line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Bio::Das::Request::Features; |
2
|
|
|
|
|
|
|
# $Id: Features.pm,v 1.16 2010/06/16 21:28:41 lstein Exp $ |
3
|
|
|
|
|
|
|
# this module issues and parses the types command, with arguments -dsn, -segment, -categories, -enumerate |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
6
|
1
|
|
|
1
|
|
5
|
use Bio::Das::Type; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
17
|
|
7
|
1
|
|
|
1
|
|
546
|
use Bio::Das::Feature; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
40
|
|
8
|
1
|
|
|
1
|
|
14
|
use Bio::Das::Segment; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
9
|
1
|
|
|
1
|
|
5
|
use Bio::Das::Request; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
10
|
1
|
|
|
1
|
|
6
|
use Bio::Das::Util 'rearrange'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
60
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
5
|
use vars '@ISA'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2131
|
|
13
|
|
|
|
|
|
|
@ISA = 'Bio::Das::Request'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
16
|
2
|
|
|
2
|
1
|
3
|
my $pack = shift; |
17
|
2
|
|
|
|
|
18
|
my ($dsn,$segments,$types,$categories,$feature_id,$group_id,$das,$fcallback,$scallback) |
18
|
|
|
|
|
|
|
= rearrange([ |
19
|
|
|
|
|
|
|
['dsn','dsns'], |
20
|
|
|
|
|
|
|
['segment','segments'], |
21
|
|
|
|
|
|
|
['type','types'], |
22
|
|
|
|
|
|
|
['category','categories'], |
23
|
|
|
|
|
|
|
'feature_id', |
24
|
|
|
|
|
|
|
'group_id', |
25
|
|
|
|
|
|
|
'das', |
26
|
|
|
|
|
|
|
['callback','feature_callback'], |
27
|
|
|
|
|
|
|
'segment_callback', |
28
|
|
|
|
|
|
|
],@_); |
29
|
2
|
|
|
|
|
30
|
my $self = $pack->SUPER::new( |
30
|
|
|
|
|
|
|
-dsn => $dsn, |
31
|
|
|
|
|
|
|
-callback => $fcallback, |
32
|
|
|
|
|
|
|
-args => { |
33
|
|
|
|
|
|
|
segment => $segments, |
34
|
|
|
|
|
|
|
category => $categories, |
35
|
|
|
|
|
|
|
type => $types, |
36
|
|
|
|
|
|
|
feature_id => $feature_id, |
37
|
|
|
|
|
|
|
group_id => $group_id, |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
); |
40
|
2
|
50
|
|
|
|
9
|
$self->{segment_callback} = $scallback if $scallback; |
41
|
2
|
50
|
|
|
|
10
|
$self->das($das) if defined $das; |
42
|
2
|
|
|
|
|
9
|
$self; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
61
|
|
|
61
|
1
|
133
|
sub command { 'features' } |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub das { |
48
|
5
|
|
|
5
|
0
|
12
|
my $self = shift; |
49
|
5
|
|
|
|
|
99
|
my $d = $self->{das}; |
50
|
5
|
100
|
|
|
|
15
|
$self->{das} = shift if @_; |
51
|
5
|
|
|
|
|
21
|
$d; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
3
|
|
|
3
|
0
|
12
|
sub segment_callback { shift->{segment_callback} } |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub t_DASGFF { |
57
|
4
|
|
|
4
|
0
|
8
|
my $self = shift; |
58
|
4
|
|
|
|
|
9
|
my $attrs = shift; |
59
|
4
|
100
|
|
|
|
15
|
if ($attrs) { |
60
|
2
|
|
|
|
|
14
|
$self->clear_results; |
61
|
|
|
|
|
|
|
} |
62
|
4
|
|
|
|
|
48
|
delete $self->{tmp}; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
4
|
|
|
4
|
0
|
25
|
sub t_GFF { |
66
|
|
|
|
|
|
|
# nothing to do here -- probably should check version |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub t_SEGMENT { |
70
|
6
|
|
|
6
|
0
|
12
|
my $self = shift; |
71
|
6
|
|
|
|
|
10
|
my $attrs = shift; |
72
|
6
|
100
|
|
|
|
18
|
if ($attrs) { # segment section is starting |
73
|
3
|
|
|
|
|
58
|
$self->{tmp}{current_segment} = Bio::Das::Segment->new($attrs->{id},$attrs->{start}, |
74
|
|
|
|
|
|
|
$attrs->{stop},$attrs->{version}, |
75
|
|
|
|
|
|
|
$self->das,$self->dsn |
76
|
|
|
|
|
|
|
); |
77
|
3
|
|
|
|
|
12
|
$self->{tmp}{current_feature} = undef; |
78
|
3
|
|
|
|
|
30
|
$self->{tmp}{features} = []; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
else { # reached the end of the segment, so push result |
82
|
3
|
|
|
|
|
13
|
$self->finish_segment(); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub finish_segment { |
88
|
3
|
|
|
3
|
0
|
4
|
my $self = shift; |
89
|
|
|
|
|
|
|
|
90
|
3
|
|
|
|
|
13
|
$self->infer_parents_from_groups($self->{tmp}{features}); |
91
|
3
|
|
|
|
|
17
|
my $features = $self->build_object_hierarchy($self->{tmp}{features}); |
92
|
|
|
|
|
|
|
|
93
|
3
|
50
|
|
|
|
15
|
if ($self->segment_callback) { |
94
|
0
|
|
|
|
|
0
|
eval {$self->segment_callback->($self->{tmp}{current_segment}=>$features)}; |
|
0
|
|
|
|
|
0
|
|
95
|
0
|
0
|
|
|
|
0
|
warn $@ if $@; |
96
|
|
|
|
|
|
|
} else { |
97
|
3
|
|
|
|
|
17
|
$self->add_object($self->{tmp}{current_segment},$features); |
98
|
|
|
|
|
|
|
} |
99
|
3
|
|
|
|
|
11
|
delete $self->{tmp}{current_segment}; |
100
|
3
|
|
|
|
|
64
|
delete $self->{tmp}{features}; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# for features that have a <group> but no parent or parts, |
104
|
|
|
|
|
|
|
# create inferred parents |
105
|
|
|
|
|
|
|
sub infer_parents_from_groups { |
106
|
3
|
|
|
3
|
0
|
4
|
my $self = shift; |
107
|
3
|
|
|
|
|
4
|
my $f = shift; |
108
|
|
|
|
|
|
|
|
109
|
3
|
|
|
|
|
4
|
my (%inferred_parents,%group_types); |
110
|
3
|
|
|
|
|
8
|
for my $feature (@$f) { |
111
|
|
|
|
|
|
|
|
112
|
204
|
50
|
|
|
|
411
|
my $group = $feature->group or next; |
113
|
204
|
50
|
|
|
|
428
|
next if $feature->parent_id; |
114
|
204
|
50
|
|
|
|
392
|
next if $feature->child_ids > 0; |
115
|
|
|
|
|
|
|
|
116
|
204
|
|
|
|
|
333
|
$group = "group_$group"; # avoid collisions |
117
|
|
|
|
|
|
|
|
118
|
204
|
100
|
|
|
|
541
|
unless ($inferred_parents{$group}) { |
119
|
63
|
|
|
|
|
167
|
my $p = $inferred_parents{$group} = Bio::Das::Feature->new( |
120
|
|
|
|
|
|
|
-segment => $feature->segment, |
121
|
|
|
|
|
|
|
-id => $group, |
122
|
|
|
|
|
|
|
-start => $feature->start, |
123
|
|
|
|
|
|
|
-stop => $feature->stop |
124
|
|
|
|
|
|
|
); |
125
|
63
|
|
|
|
|
205
|
$p->orientation($feature->orientation); |
126
|
63
|
|
|
|
|
179
|
$p->category('group'); |
127
|
63
|
|
33
|
|
|
127
|
my $gt = $feature->group_type || $feature->type; |
128
|
63
|
|
66
|
|
|
195
|
my $type = $group_types{$gt} |
129
|
|
|
|
|
|
|
||= Bio::Das::Type->new($gt,$gt,'group'); |
130
|
63
|
|
|
|
|
155
|
$p->type($type); |
131
|
63
|
|
|
|
|
133
|
$p->link($feature->link); |
132
|
63
|
|
|
|
|
142
|
$p->label($feature->label); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
204
|
|
|
|
|
347
|
my $p = $inferred_parents{$group}; |
136
|
204
|
50
|
|
|
|
442
|
$p->start($feature->start) if $feature->start < $p->start; |
137
|
204
|
100
|
|
|
|
482
|
$p->stop($feature->stop) if $feature->stop > $p->stop; |
138
|
204
|
|
|
|
|
491
|
$feature->parent_id($group); |
139
|
204
|
|
|
|
|
394
|
$p->add_child_id($feature->id); |
140
|
|
|
|
|
|
|
} |
141
|
3
|
|
|
|
|
51
|
push @$f,values %inferred_parents; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# this builds up hierarchical objects using their parent/child relationships |
146
|
|
|
|
|
|
|
sub build_object_hierarchy { |
147
|
3
|
|
|
3
|
0
|
6
|
my $self = shift; |
148
|
3
|
|
|
|
|
4
|
my $f = shift; |
149
|
3
|
|
|
|
|
9
|
my %id_to_feature = map {$_->id => $_} @$f; |
|
267
|
|
|
|
|
550
|
|
150
|
|
|
|
|
|
|
|
151
|
3
|
|
|
|
|
22
|
my @top_level; |
152
|
3
|
|
|
|
|
10
|
for my $feature (@$f) { |
153
|
267
|
|
|
|
|
666
|
my $parent_id = $feature->parent_id; |
154
|
267
|
100
|
66
|
|
|
984
|
if (defined $parent_id |
155
|
|
|
|
|
|
|
&& (my $parent = $id_to_feature{$parent_id})) { |
156
|
204
|
|
|
|
|
441
|
$parent->add_subfeature($feature); |
157
|
|
|
|
|
|
|
} else { |
158
|
63
|
|
|
|
|
354
|
push @top_level,$feature; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
3
|
|
|
|
|
108
|
return \@top_level; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub cleanup { |
165
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
166
|
|
|
|
|
|
|
# this fixes a problem in the UCSC server |
167
|
2
|
50
|
|
|
|
11
|
$self->finish_segment if $self->{tmp}{current_segment}; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub add_object { |
171
|
3
|
|
|
3
|
0
|
6
|
my $self = shift; |
172
|
3
|
|
|
|
|
4
|
push @{$self->{results}},@_; |
|
3
|
|
|
|
|
11
|
|
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# do nothing |
177
|
0
|
|
|
0
|
0
|
0
|
sub t_UNKNOWNSEGMENT { } |
178
|
0
|
|
|
0
|
0
|
0
|
sub t_ERRORSEGMENT { } |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub t_FEATURE { |
181
|
408
|
|
|
408
|
0
|
475
|
my $self = shift; |
182
|
408
|
|
|
|
|
439
|
my $attrs = shift; |
183
|
|
|
|
|
|
|
|
184
|
408
|
100
|
|
|
|
614
|
if ($attrs) { # start of tag |
185
|
204
|
|
|
|
|
827
|
my $feature = $self->{tmp}{current_feature} = Bio::Das::Feature->new($self->{tmp}{current_segment}, |
186
|
|
|
|
|
|
|
$attrs->{id} |
187
|
|
|
|
|
|
|
); |
188
|
204
|
50
|
|
|
|
501
|
$feature->label($attrs->{label}) if exists $attrs->{label}; |
189
|
204
|
|
|
|
|
1679
|
$self->{tmp}{type} = undef; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
else { |
193
|
|
|
|
|
|
|
# feature is ending. This would be the place to do group aggregation |
194
|
204
|
|
|
|
|
355
|
my $feature = $self->{tmp}{current_feature}; |
195
|
204
|
|
|
|
|
503
|
my $cft = $feature->type; |
196
|
|
|
|
|
|
|
|
197
|
204
|
50
|
|
|
|
606
|
if (!$cft->complete) { |
198
|
|
|
|
|
|
|
# fix up broken das servers that don't set a method |
199
|
|
|
|
|
|
|
# the id and method will be set to the same value |
200
|
0
|
0
|
0
|
|
|
0
|
$cft->id($cft->method) if $cft->method && !$cft->id; |
201
|
0
|
0
|
0
|
|
|
0
|
$cft->method($cft->id) if $cft->id && !$cft->method; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
204
|
50
|
|
|
|
548
|
if (my $callback = $self->callback) { |
205
|
0
|
|
|
|
|
0
|
$callback->($feature); |
206
|
|
|
|
|
|
|
} else { |
207
|
204
|
|
|
|
|
200
|
push @{$self->{tmp}{features}},$feature; |
|
204
|
|
|
|
|
1232
|
|
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub t_TYPE { |
213
|
408
|
|
|
408
|
0
|
493
|
my $self = shift; |
214
|
408
|
|
|
|
|
439
|
my $attrs = shift; |
215
|
408
|
50
|
|
|
|
1545
|
my $feature = $self->{tmp}{current_feature} or return; |
216
|
|
|
|
|
|
|
|
217
|
408
|
|
66
|
|
|
1702
|
my $cft = $self->{tmp}{type} ||= Bio::Das::Type->new(); |
218
|
|
|
|
|
|
|
|
219
|
408
|
100
|
|
|
|
853
|
if ($attrs) { # tag starts |
220
|
204
|
|
|
|
|
568
|
$cft->id($attrs->{id}); |
221
|
204
|
50
|
|
|
|
776
|
$cft->category($attrs->{category}) if $attrs->{category}; |
222
|
204
|
50
|
33
|
|
|
620
|
$cft->reference(1) if $attrs->{reference} && $attrs->{reference} eq 'yes'; |
223
|
204
|
50
|
33
|
|
|
521
|
$cft->has_subparts(1) if $attrs->{subparts} && $attrs->{subparts} eq 'yes'; |
224
|
204
|
50
|
33
|
|
|
1595
|
$cft->has_superparts(1) if $attrs->{superparts} && $attrs->{superparts} eq 'yes'; |
225
|
|
|
|
|
|
|
} else { |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# possibly add a label |
228
|
204
|
50
|
|
|
|
466
|
if (my $label = $self->char_data) { |
229
|
0
|
|
|
|
|
0
|
$cft->label($label); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
204
|
|
|
|
|
440
|
my $type = $self->_cache_types($cft); |
233
|
204
|
|
|
|
|
655
|
$feature->type($type); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub t_METHOD { |
238
|
408
|
|
|
408
|
0
|
516
|
my $self = shift; |
239
|
408
|
|
|
|
|
460
|
my $attrs = shift; |
240
|
408
|
50
|
|
|
|
1234
|
my $feature = $self->{tmp}{current_feature} or return; |
241
|
408
|
|
33
|
|
|
1260
|
my $cft = $self->{tmp}{type} ||= Bio::Das::Type->new(); |
242
|
|
|
|
|
|
|
|
243
|
408
|
100
|
|
|
|
754
|
if ($attrs) { # tag starts |
244
|
204
|
|
|
|
|
575
|
$cft->method($attrs->{id}); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
else { # tag ends |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# possibly add a label |
250
|
204
|
50
|
|
|
|
477
|
if (my $label = $self->char_data) { |
251
|
204
|
|
|
|
|
557
|
$cft->method_label($label); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
204
|
50
|
|
|
|
474
|
if ($cft->complete) { |
255
|
204
|
|
|
|
|
409
|
my $type = $self->_cache_types($cft); |
256
|
204
|
|
|
|
|
616
|
$feature->type($type); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub t_PARENT { |
263
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
264
|
0
|
|
|
|
|
0
|
my $attrs = shift; |
265
|
0
|
0
|
|
|
|
0
|
my $feature = $self->{tmp}{current_feature} or return; |
266
|
0
|
0
|
|
|
|
0
|
$feature->parent_id($attrs->{id}) if $attrs; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub t_PART { |
270
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
271
|
0
|
|
|
|
|
0
|
my $attrs = shift; |
272
|
0
|
0
|
|
|
|
0
|
my $feature = $self->{tmp}{current_feature} or return; |
273
|
0
|
0
|
|
|
|
0
|
$feature->add_child_id($attrs->{id}) if $attrs; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub t_START { |
277
|
408
|
|
|
408
|
0
|
472
|
my $self = shift; |
278
|
408
|
|
|
|
|
451
|
my $attrs = shift; |
279
|
408
|
50
|
|
|
|
2190
|
my $feature = $self->{tmp}{current_feature} or return; |
280
|
408
|
100
|
|
|
|
2161
|
$feature->start($self->char_data) unless $attrs; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub t_END { |
284
|
408
|
|
|
408
|
0
|
525
|
my $self = shift; |
285
|
408
|
|
|
|
|
440
|
my $attrs = shift; |
286
|
408
|
50
|
|
|
|
1227
|
my $feature = $self->{tmp}{current_feature} or return; |
287
|
408
|
100
|
|
|
|
1964
|
$feature->stop($self->char_data) unless $attrs; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub t_SCORE { |
291
|
408
|
|
|
408
|
0
|
476
|
my $self = shift; |
292
|
408
|
|
|
|
|
410
|
my $attrs = shift; |
293
|
408
|
50
|
|
|
|
1177
|
my $feature = $self->{tmp}{current_feature} or return; |
294
|
408
|
100
|
|
|
|
1991
|
$feature->score($self->char_data) unless $attrs; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub t_ORIENTATION { |
298
|
408
|
|
|
408
|
0
|
513
|
my $self = shift; |
299
|
408
|
|
|
|
|
454
|
my $attrs = shift; |
300
|
408
|
50
|
|
|
|
1171
|
my $feature = $self->{tmp}{current_feature} or return; |
301
|
408
|
100
|
|
|
|
2197
|
$feature->orientation($self->char_data) unless $attrs; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub t_PHASE { |
305
|
408
|
|
|
408
|
0
|
472
|
my $self = shift; |
306
|
408
|
|
|
|
|
429
|
my $attrs = shift; |
307
|
408
|
50
|
|
|
|
1188
|
my $feature = $self->{tmp}{current_feature} or return; |
308
|
408
|
100
|
|
|
|
1972
|
$feature->phase($self->char_data) unless $attrs; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub t_GROUP { |
312
|
408
|
|
|
408
|
0
|
461
|
my $self = shift; |
313
|
408
|
|
|
|
|
401
|
my $attrs = shift; |
314
|
408
|
50
|
|
|
|
1125
|
my $feature = $self->{tmp}{current_feature} or return; |
315
|
408
|
100
|
|
|
|
1643
|
if($attrs) { |
316
|
204
|
|
|
|
|
566
|
$feature->group_label( $attrs->{label} ); |
317
|
204
|
|
|
|
|
573
|
$feature->group_type( $attrs->{type} ); |
318
|
204
|
|
|
|
|
492
|
$feature->group( $attrs->{id} ); |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub t_LINK { |
323
|
408
|
|
|
408
|
0
|
515
|
my $self = shift; |
324
|
408
|
|
|
|
|
408
|
my $attrs = shift; |
325
|
408
|
50
|
|
|
|
1194
|
my $feature = $self->{tmp}{current_feature} or return; |
326
|
408
|
100
|
|
|
|
816
|
if($attrs) { |
327
|
204
|
|
|
|
|
591
|
$feature->link( $attrs->{href} ); |
328
|
|
|
|
|
|
|
} else { |
329
|
204
|
|
|
|
|
518
|
$feature->link_label( $self->char_data ); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub t_NOTE { |
334
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
335
|
0
|
|
|
|
|
0
|
my $attrs = shift; |
336
|
0
|
0
|
|
|
|
0
|
my $feature = $self->{tmp}{current_feature} or return; |
337
|
0
|
0
|
|
|
|
0
|
if ($attrs) { |
338
|
0
|
0
|
|
|
|
0
|
$self->{tmp}{note_tag} = $attrs->{tag} if exists $attrs->{tag}; |
339
|
|
|
|
|
|
|
} else { |
340
|
0
|
|
|
|
|
0
|
$feature->add_note($self->{tmp}{note_tag},$self->char_data); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub t_TARGET { |
345
|
340
|
|
|
340
|
0
|
397
|
my $self = shift; |
346
|
340
|
|
|
|
|
368
|
my $attrs = shift; |
347
|
340
|
50
|
|
|
|
966
|
my $feature = $self->{tmp}{current_feature} or return; |
348
|
340
|
100
|
|
|
|
676
|
if($attrs){ |
349
|
170
|
|
|
|
|
630
|
$feature->target($attrs->{id},$attrs->{start},$attrs->{stop}); |
350
|
|
|
|
|
|
|
} else { |
351
|
170
|
|
|
|
|
405
|
$feature->target_label($self->char_data()); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
sub _cache_types { |
356
|
408
|
|
|
408
|
|
452
|
my $self = shift; |
357
|
408
|
|
|
|
|
454
|
my $type = shift; |
358
|
408
|
|
|
|
|
883
|
my $key = $type->_key; |
359
|
408
|
|
66
|
|
|
1603
|
return $self->{cached_types}{$key} ||= $type; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# override for segmentation behavior |
363
|
|
|
|
|
|
|
sub results { |
364
|
3
|
|
|
3
|
1
|
6
|
my $self = shift; |
365
|
3
|
50
|
|
|
|
17
|
my %r = $self->SUPER::results or return; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# in array context, return the list of types |
368
|
3
|
100
|
|
|
|
12
|
return map { @{$_} } values %r if wantarray; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
9
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# otherwise return ref to a hash |
371
|
2
|
|
|
|
|
6
|
return \%r; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
1; |