| 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; |