line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Bio::Polloc::LocusIO::gff3 - A LocusIO for Gff3 |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 DESCRIPTION |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
A repeatitive locus. |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 IMPLEMENTS OR EXTENDS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=over |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=item * |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
L<Bio::Polloc::LocusIO> |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=back |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 AUTHOR - Luis M. Rodriguez-R |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Email lmrodriguezr at gmail dot com |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=cut |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
package Bio::Polloc::LocusIO::gff3; |
26
|
2
|
|
|
2
|
|
10
|
use base qw(Bio::Polloc::LocusIO); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
199
|
|
27
|
2
|
|
|
2
|
|
14
|
use strict; |
|
2
|
|
|
|
|
70
|
|
|
2
|
|
|
|
|
80
|
|
28
|
2
|
|
|
2
|
|
1702
|
use Bio::Polloc::LociGroup; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
72
|
|
29
|
2
|
|
|
2
|
|
750
|
use Bio::Polloc::LocusI; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
4197
|
|
30
|
|
|
|
|
|
|
our $VERSION = 1.0503; # [a-version] from Bio::Polloc::Polloc::Version |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 APPENDIX |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Methods provided by the package |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 new |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Creates a B<Bio::Polloc::LocusIO::gff3> object. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head3 Returns |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
A L<Bio::Polloc::LocusIO::gff3> object. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub new { |
48
|
0
|
|
|
0
|
1
|
0
|
my($caller,@args) = @_; |
49
|
0
|
|
|
|
|
0
|
my $self = $caller->SUPER::new(@args); |
50
|
0
|
|
|
|
|
0
|
$self->_initialize(@args); |
51
|
0
|
|
|
|
|
0
|
return $self; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head2 gff3_line |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
Formats the locus as a GFF3 line and returns it. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head3 Arguments |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=over |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item -force |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Boolean (1 or 0) |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=back |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head3 Returns |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
The GFF3-formatted line (str) |
71
|
|
|
|
|
|
|
=head3 Note |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
This function stores the line in cache. If it is called twice, the second |
74
|
|
|
|
|
|
|
time will return the cached line unless the C<-force=>1> flag is passed. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub gff3_line { |
79
|
3
|
|
|
3
|
1
|
6
|
my($self,@args) = @_; |
80
|
3
|
|
|
|
|
14
|
my($locus, $force) = $self->_rearrange([qw(LOCUS FORCE)], @args); |
81
|
3
|
50
|
33
|
|
|
37
|
defined $locus and UNIVERSAL::can($locus, 'isa') and $locus->isa('Bio::Polloc::LocusI') |
|
|
|
33
|
|
|
|
|
82
|
|
|
|
|
|
|
or $self->throw("Undefined locus or bad type", $locus); |
83
|
3
|
50
|
33
|
|
|
15
|
return $locus->{'_gff3_line'} if defined $locus->{'_gff3_line'} and not $force; |
84
|
3
|
|
|
|
|
4
|
my @out; |
85
|
3
|
50
|
|
|
|
11
|
push @out, defined $locus->seq_name ? $locus->seq_name : "."; |
86
|
3
|
|
|
|
|
8
|
$out[0] =~ s/^>/{{%}}3E/; |
87
|
3
|
|
|
|
|
13
|
push @out, $locus->source; #defined $locus->rule ? $locus->rule->source : 'bme'; |
88
|
3
|
|
|
|
|
10
|
push @out, $locus->family; |
89
|
3
|
|
|
|
|
22
|
push @out, $locus->from , $locus->to; |
90
|
3
|
50
|
|
|
|
11
|
push @out, defined $locus->score ? $locus->score : "."; |
91
|
3
|
|
|
|
|
9
|
push @out, $locus->strand, "0"; |
92
|
3
|
|
|
|
|
6
|
my %atts; |
93
|
3
|
50
|
|
|
|
8
|
$atts{'ID'} = $locus->id if defined $locus->id; |
94
|
3
|
50
|
|
|
|
11
|
$atts{'Name'} = $locus->name if defined $locus->name; |
95
|
3
|
50
|
|
|
|
17
|
$atts{'Alias'} = $locus->aliases if defined $locus->aliases; |
96
|
3
|
50
|
|
|
|
14
|
$atts{'Parent'} = $locus->parents if defined $locus->parents; |
97
|
3
|
50
|
33
|
|
|
10
|
$atts{'organism_name'} = $locus->genome->name |
98
|
|
|
|
|
|
|
if defined $locus->genome and defined $locus->genome->name; |
99
|
3
|
50
|
|
|
|
12
|
if(defined $locus->target){ |
100
|
0
|
|
|
|
|
0
|
my $tid = $locus->target->{'id'}; |
101
|
0
|
|
|
|
|
0
|
$tid =~ s/\s/{{%}}20/g; |
102
|
0
|
|
|
|
|
0
|
$atts{'Target'} = $tid . " " . $locus->target->{'from'} . " " . $locus->target->{'to'}; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
# TODO Gap |
105
|
3
|
50
|
|
|
|
10
|
$atts{'Note'} = [split /[\n\r]+/, $locus->comments] if defined $locus->comments; |
106
|
3
|
50
|
|
|
|
15
|
$atts{'Dbxref'} = $locus->xrefs if defined $locus->xrefs; |
107
|
3
|
50
|
|
|
|
12
|
$atts{'Ontology_term'} = $locus->ontology_terms_str if defined $locus->ontology_terms_str; |
108
|
3
|
|
|
|
|
17
|
my $o = ""; |
109
|
3
|
|
|
|
|
6
|
for my $v (@out){ |
110
|
24
|
|
|
|
|
44
|
$o.= $self->_gff3_value($v)."\t"; |
111
|
|
|
|
|
|
|
} |
112
|
3
|
|
|
|
|
5
|
$a = ""; |
113
|
3
|
|
|
|
|
8
|
for my $k (keys %atts){ |
114
|
9
|
|
|
|
|
25
|
$a .= "$k=" . $self->_gff3_attribute($atts{$k}).";"; |
115
|
|
|
|
|
|
|
} |
116
|
3
|
50
|
|
|
|
12
|
$a = substr($a,0,-1) if $a; |
117
|
3
|
|
|
|
|
13
|
$locus->{'_gff3_line'} = $o . $a . "\n"; |
118
|
3
|
|
|
|
|
18
|
return $locus->{'_gff3_line'}; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head1 INTERNAL METHODS |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Methods intended to be used only within the scope of Bio::Polloc::* |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head2 _next_locus_impl |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=cut |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub _next_locus_impl { |
131
|
90
|
|
|
90
|
|
121
|
my ($self, @args) = @_; |
132
|
90
|
|
|
|
|
304
|
my($genomes) = $self->_rearrange([qw(GENOMES)], @args); |
133
|
90
|
|
|
|
|
150
|
my $ln; |
134
|
90
|
|
|
|
|
306
|
while($ln = $self->_readline){ |
135
|
94
|
100
|
100
|
|
|
577
|
last unless $ln =~ /^\s*#/ or $ln =~ /^\s*$/; |
136
|
|
|
|
|
|
|
} |
137
|
90
|
100
|
|
|
|
166
|
return unless $ln; |
138
|
87
|
|
|
|
|
325
|
$self->debug("Parsing: $ln"); |
139
|
87
|
|
|
|
|
443
|
my @row = split /\t/, $ln; |
140
|
87
|
|
|
|
|
217
|
my $seqid = $self->_gff3_decode($row[0]); |
141
|
87
|
|
|
|
|
172
|
my $source = $self->_gff3_decode($row[1]); |
142
|
87
|
|
|
|
|
178
|
my $family = $self->_gff3_decode($row[2]); |
143
|
87
|
|
|
|
|
176
|
my $from = $self->_gff3_decode($row[3]); |
144
|
87
|
|
|
|
|
175
|
my $to = $self->_gff3_decode($row[4]); |
145
|
87
|
|
|
|
|
168
|
my $score= $self->_gff3_decode($row[5]); |
146
|
87
|
|
|
|
|
180
|
my $strand = $self->_gff3_decode($row[6]); |
147
|
87
|
|
|
|
|
155
|
my $frame = $self->_gff3_decode($row[7]); |
148
|
87
|
|
|
|
|
257
|
my @compl = split /;/, $row[8]; |
149
|
87
|
|
|
|
|
127
|
my %atts = (); |
150
|
87
|
|
|
|
|
124
|
for my $c (@compl){ |
151
|
229
|
50
|
|
|
|
947
|
$c =~ /(.+?)=(.*)/ or next; |
152
|
229
|
|
|
|
|
488
|
my ($k,$v) = ($1, $2); |
153
|
229
|
|
|
|
|
406
|
$atts{lc $k} = $self->_gff3_decode($v); |
154
|
|
|
|
|
|
|
} |
155
|
87
|
|
|
|
|
140
|
my $id = $atts{'id'}; |
156
|
87
|
|
|
|
|
112
|
my $name = $atts{'name'}; |
157
|
87
|
|
|
|
|
116
|
my $genome_name = $atts{'organism_name'}; |
158
|
87
|
|
|
|
|
115
|
my @comments = (); |
159
|
87
|
50
|
|
|
|
361
|
@comments = split /,/, $atts{'note'} if defined $atts{'note'}; |
160
|
87
|
|
|
|
|
317
|
my $f = Bio::Polloc::LocusI->_qualify_type($family); |
161
|
87
|
50
|
33
|
|
|
1138
|
my $type = ($f eq 'amplicon' or $f eq 'amplification') ? 'amplicon' : |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
162
|
|
|
|
|
|
|
($f eq 'composition') ? 'composition' : |
163
|
|
|
|
|
|
|
($f eq 'crispr') ? 'crispr' : |
164
|
|
|
|
|
|
|
($f eq 'pattern' or $f eq 'domain') ? 'pattern' : |
165
|
|
|
|
|
|
|
($f eq 'repeat' or $f eq 'vntr' or $f =~ /tandem.?repeat/ |
166
|
|
|
|
|
|
|
or lc $source eq 'trf' or lc $source eq 'mreps') ? 'repeat' : |
167
|
|
|
|
|
|
|
'generic'; |
168
|
87
|
100
|
|
|
|
139
|
$type = "extend" if grep{ /Extended feature/ } @comments; |
|
298
|
|
|
|
|
615
|
|
169
|
87
|
|
|
|
|
583
|
my $locus = Bio::Polloc::LocusI->new( |
170
|
|
|
|
|
|
|
-id=>$id, -name=>$name, |
171
|
|
|
|
|
|
|
-type=>$type, |
172
|
|
|
|
|
|
|
-from=>$from, -to=>$to, -strand=>$strand, |
173
|
|
|
|
|
|
|
-source=>$source, -family=>$family, |
174
|
|
|
|
|
|
|
-score=>$score, |
175
|
|
|
|
|
|
|
-seqname=>$seqid); |
176
|
|
|
|
|
|
|
# Parse comments |
177
|
87
|
|
|
|
|
201
|
for my $comm (@comments){ |
178
|
298
|
100
|
66
|
|
|
1289
|
if($comm =~ m/^(.+?)=(.+)$/){ |
|
|
100
|
|
|
|
|
|
179
|
215
|
|
|
|
|
450
|
my ($k, $v) = (lc $1, $2); |
180
|
215
|
100
|
66
|
|
|
1367
|
if($k and $v and $locus->can($k)){ |
|
|
|
66
|
|
|
|
|
181
|
207
|
|
|
|
|
710
|
$self->debug("Setting $k to $v"); |
182
|
207
|
|
|
|
|
559
|
$locus->$k($v); |
183
|
207
|
|
|
|
|
353
|
next; |
184
|
|
|
|
|
|
|
} |
185
|
8
|
50
|
33
|
|
|
82
|
$genome_name = $v if not defined $genome_name and |
|
|
|
33
|
|
|
|
|
186
|
|
|
|
|
|
|
($k =~ /^organism(?:_name)?$/ or $k =~ /^genome(?:_name)?$/); |
187
|
|
|
|
|
|
|
}elsif($type eq 'extend' and $comm =~ m/Based on group [^:]+: (.*)/){ |
188
|
34
|
|
|
|
|
120
|
for my $b (split /\s/, $1){ |
189
|
34
|
50
|
|
|
|
103
|
$locus->basefeature($self->_locus_by_id($b)) if defined $self->_locus_by_id($b); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
} |
193
|
87
|
100
|
|
|
|
176
|
if(defined $genomes){ |
194
|
2
|
|
|
|
|
3
|
my $genome; |
195
|
|
|
|
|
|
|
# Search the genome by name: |
196
|
2
|
50
|
|
|
|
6
|
if(defined $genome_name){ |
197
|
2
|
|
|
|
|
4
|
for my $g (@$genomes){ |
198
|
2
|
50
|
|
|
|
8
|
$genome = $g if $g->name eq $genome_name; |
199
|
2
|
50
|
|
|
|
6
|
last if defined $genome; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
# Search the genome by sequence name (prone to errors, but it's a guess): |
203
|
2
|
50
|
|
|
|
11
|
unless(defined $genome){ |
204
|
0
|
|
|
|
|
0
|
for my $g (@$genomes){ |
205
|
0
|
0
|
|
|
|
0
|
$genome = $g if defined $g->search_sequence($seqid); |
206
|
0
|
0
|
|
|
|
0
|
last if defined $genome; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
} |
209
|
2
|
|
|
|
|
7
|
$locus->genome($genome); |
210
|
|
|
|
|
|
|
} |
211
|
87
|
|
|
|
|
239
|
$locus->comments(@comments); |
212
|
87
|
|
|
|
|
271
|
return $self->_save_locus($locus); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head2 _write_locus_impl |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=cut |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _write_locus_impl { |
220
|
3
|
|
|
3
|
|
5
|
my $self = shift; |
221
|
3
|
|
|
|
|
10
|
my $line = $self->gff3_line(@_); |
222
|
3
|
100
|
|
|
|
9
|
unless($self->{'_header'}){ |
223
|
1
|
|
|
|
|
30
|
$self->_print("##gff-version 3\n\n"); |
224
|
1
|
|
|
|
|
3
|
$self->{'_header'} = 1; |
225
|
|
|
|
|
|
|
} |
226
|
3
|
|
|
|
|
11
|
$self->_print($line); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 _gff3_attribute |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Properly escapes an attribute for GFF3 (an attribute the value of one of |
232
|
|
|
|
|
|
|
the colon-separated entries in the ninth column) |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head3 Purpose |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
To simplify the code of L<Bio::Polloc::LocusI::gff3_line> |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head3 Arguments |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
The value to escape |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=head3 Returns |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
The escaped value |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=cut |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _gff3_attribute { |
249
|
9
|
|
|
9
|
|
13
|
my($self,$value) = @_; |
250
|
9
|
50
|
|
|
|
19
|
return unless defined $value; |
251
|
9
|
100
|
66
|
|
|
39
|
if(ref($value) && ref($value) =~ m/array/i){ |
252
|
3
|
|
|
|
|
5
|
my $out = ""; |
253
|
3
|
|
|
|
|
4
|
for my $att (@{$value}){ |
|
3
|
|
|
|
|
7
|
|
254
|
15
|
|
|
|
|
29
|
$out.= "," . $self->_gff3_value($att); |
255
|
|
|
|
|
|
|
} |
256
|
3
|
50
|
|
|
|
12
|
$out = substr($out, 1) if $out; |
257
|
3
|
|
|
|
|
14
|
return $out; |
258
|
|
|
|
|
|
|
} |
259
|
6
|
|
|
|
|
13
|
return $self->_gff3_value($value); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head2 _gff3_value |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Properly escapes a value on the GFF3 line. I.e., the content of one column. |
265
|
|
|
|
|
|
|
Not to be used with the ninth column, because scapes the colon. the comma and |
266
|
|
|
|
|
|
|
the equals signs. Use instead the L<_gff3_attribute> function attribute by |
267
|
|
|
|
|
|
|
attribute |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head3 Purpose |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
To simplify the code of L<gff3_line> |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head3 Arguments |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
The value to escape |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head3 Returns |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
The escaped value |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=cut |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub _gff3_value { |
284
|
45
|
|
|
45
|
|
55
|
my ($self,$value) = @_; |
285
|
45
|
50
|
|
|
|
77
|
return unless defined $value; |
286
|
45
|
|
|
|
|
61
|
$value =~ s/%/%25/g; |
287
|
45
|
|
|
|
|
45
|
$value =~ s/\{\{%25\}\}/%/g; |
288
|
45
|
|
|
|
|
43
|
$value =~ s/\t/%9/g; |
289
|
45
|
|
|
|
|
48
|
$value =~ s/\n/\%D/g; |
290
|
45
|
|
|
|
|
43
|
$value =~ s/\r/\%A/g; |
291
|
45
|
|
|
|
|
46
|
$value =~ s/;/%3B/g; |
292
|
45
|
|
|
|
|
106
|
$value =~ s/=/%3D/g; |
293
|
45
|
|
|
|
|
47
|
$value =~ s/&/%26/g; |
294
|
45
|
|
|
|
|
51
|
$value =~ s/,/%2C/g; |
295
|
45
|
|
|
|
|
49
|
$value =~ s/ /%20/g; |
296
|
45
|
|
|
|
|
135
|
return $value; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head2 _gff_decode |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
Decodes the URI-fashioned values on GFF3 |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head3 Arguments |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
The value to decode (str) |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head3 Returns |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
The decoded value (str) |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=cut |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub _gff3_decode { |
314
|
925
|
|
|
925
|
|
1088
|
my($self,$value) = @_; |
315
|
925
|
50
|
|
|
|
1426
|
return unless defined $value; |
316
|
925
|
|
|
|
|
1014
|
$value =~ s/%25/%/g; |
317
|
925
|
|
|
|
|
917
|
$value =~ s/%9/\t/g; |
318
|
925
|
|
|
|
|
875
|
$value =~ s/\%D/\n/g; |
319
|
925
|
|
|
|
|
931
|
$value =~ s/\%A/\r/g; |
320
|
925
|
|
|
|
|
885
|
$value =~ s/%3B/;/g; |
321
|
925
|
|
|
|
|
1062
|
$value =~ s/%3D/=/g; |
322
|
925
|
|
|
|
|
892
|
$value =~ s/%26/&/g; |
323
|
925
|
|
|
|
|
862
|
$value =~ s/%2C/,/g; |
324
|
925
|
|
|
|
|
1019
|
$value =~ s/%20/ /g; |
325
|
925
|
|
|
|
|
1970
|
return $value; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
1; |