File Coverage

blib/lib/Bio/PrimerDesigner/primer3.pm
Criterion Covered Total %
statement 50 123 40.6
branch 8 82 9.7
condition 3 32 9.3
subroutine 15 17 88.2
pod 8 8 100.0
total 84 262 32.0


line stmt bran cond sub pod time code
1             package Bio::PrimerDesigner::primer3;
2              
3             # $Id: primer3.pm 9 2008-11-06 22:48:20Z kyclark $
4              
5             =head1 NAME
6              
7             Bio::PrimerDesigner::primer3 - An class for accessing primer3
8              
9             =head1 SYNOPSIS
10              
11             use Bio::PrimerDesigner::primer3;
12              
13             =head1 METHODS
14              
15             Methods are called using the simplifed alias for each primer3 result
16             or the raw primer3 BoulderIO key. Use the raw_output method to view the
17             raw output.
18              
19             =cut
20              
21 6     6   32 use strict;
  6         13  
  6         238  
22 6     6   30 use warnings;
  6         9  
  6         152  
23 6     6   5827 use File::Spec::Functions 'catfile';
  6         5149  
  6         519  
24 6     6   7235 use File::Temp 'tempfile';
  6         141070  
  6         425  
25 6     6   3445 use Bio::PrimerDesigner::Remote;
  6         22  
  6         194  
26 6     6   6407 use Bio::PrimerDesigner::Result;
  6         17  
  6         163  
27 6     6   40 use Readonly;
  6         10  
  6         590  
28              
29             Readonly our
30             $VERSION => sprintf "%s", q$Revision: 24 $ =~ /(\d+)/;
31              
32             Readonly our
33             $REMOTE_URL => 'mckay.cshl.edu/cgi-bin/primer_designer.cgi';
34              
35 6     6   30 use base 'Class::Base';
  6         9  
  6         14609  
36              
37              
38             # -------------------------------------------------------------------
39             sub binary_name {
40              
41             =pod
42              
43             =head2 binary_name
44              
45             Defines the binary's name on the system.
46              
47             =cut
48              
49 2     2 1 412 my $self = shift;
50 2         18 return 'primer3';
51             }
52              
53             # -------------------------------------------------------------------
54             sub check_params {
55              
56             =pod
57              
58             =head2 check_params
59              
60             Make sure we have required primer3 arguments.
61              
62             =cut
63              
64 2     2 1 5 my ( $self, $args ) = @_;
65              
66 2 50 33     15 if (
67             defined $args->{'PRIMER_LEFT_INPUT'} &&
68             defined $args->{'PRIMER_RIGHT_INPUT'}
69             ) {
70 0 0       0 return $self->error(
71             "Number of sets must be set to 1 for defined primers"
72             ) if $args->{'PRIMER_NUM_RETURN'} > 1;
73              
74 0 0       0 return $self->error("Sequence input is missing")
75             unless defined $args->{'SEQUENCE'};
76             }
77             else {
78 2 0 33     33 return $self->error("Required design paramaters are missing") unless
      33        
79             defined $args->{'PRIMER_SEQUENCE_ID'} &&
80             defined $args->{'SEQUENCE'} &&
81             defined $args->{'PRIMER_PRODUCT_SIZE_RANGE'};
82             }
83              
84 0         0 return 1;
85             }
86              
87             # -------------------------------------------------------------------
88             sub design {
89              
90             =pod
91              
92             =head2 design
93              
94             Build the primer3 config file, run primer3, then parse the results.
95             Expects to be passed a hash of primer3 input options. Returns an object
96             that can be used to call result methods.
97              
98             =cut
99              
100 3     3 1 13 my ( $self, $method, $loc, $args ) = @_;
101              
102 3 100       29 return $self->error('No arguments for design method' ) unless $args;
103            
104             #
105             # Unalias incoming parameters if required.
106             #
107 2         9 my %aliases = $self->list_aliases;
108 2         183 my %lookup = reverse %aliases;
109 2         19 while ( my ( $k, $v ) = each %$args ) {
110 13 100       51 next if exists $aliases{ $k };
111 8 50       24 my $alias = $lookup{ $k } or return $self->error("No alias for '$k'");
112 8         17 delete $args->{ $k };
113 8         471 $args->{ $alias } = $v;
114             }
115              
116             #
117             # Check that everything required is present.
118             #
119 2 50       13 $self->check_params( $args ) or return $self->error;
120              
121             #
122             # Send request to designer.
123             #
124 0         0 my @data = $self->request( $method, $loc, $args );
125            
126             #
127             # abort on empty or undefined data array
128             #
129 0 0 0     0 return '' unless @data && @data > 1;
130              
131 0         0 my $output = '';
132 0         0 my $count = 1;
133 0         0 my $result = Bio::PrimerDesigner::Result->new;
134              
135 0         0 for ( @data ) {
136 0         0 $output .= $_;# unless /^SEQUENCE=/;
137              
138             # save raw output into the results hash
139 0         0 my ($key, $value) = /(.+)=(.+)/;
140 0 0 0     0 $result->{$count}->{$key} = $value if $key && $value;
141              
142             # save aliased output
143 0 0 0     0 $result->{$count}->{'qual'} = $1
144             if /R_PAIR_PENALT\S+=(\S+)/ || /R_PAIR_QUAL\S+=(\S+)/;
145 0 0       0 $result->{$count}->{'left'} = $1
146             if /R_LEFT\S+SEQUENC\S+=(\S+)/;
147 0 0       0 $result->{$count}->{'right'} = $1
148             if /R_RIGHT\S+SEQUENC\S+=(\S+)/;
149 0 0       0 $result->{$count}->{'startleft'} = $1
150             if /R_LEFT_?\d*=(\d+),\d+/;
151 0 0       0 $result->{$count}->{'startright'} = $1
152             if /R_RIGHT_?\d*=(\d+),\d+/;
153 0 0 0     0 $result->{$count}->{'lqual'} = $1
154             if /R_LEFT\S*_PENALT\S+=(\S+)/ || /R_LEFT\S*_QUAL\S+=(\S+)/;
155 0 0 0     0 $result->{$count}->{'rqual'} = $1
156             if /R_RIGHT\S*_PENALT\S+=(\S+)/ || /R_RIGHT\S*_QUAL\S+=(\S+)/;
157 0 0       0 $result->{$count}->{'leftgc'} = int $1
158             if /R_LEFT\S+GC_PERCEN\S+=(\S+)/;
159 0 0       0 $result->{$count}->{'rightgc'} = int $1
160             if /R_RIGHT\S+GC_PERCEN\S+=(\S+)/;
161 0 0       0 $result->{$count}->{'lselfany'} = int $1
162             if /R_LEFT\S+SELF_AN\S+=(\S+)/;
163 0 0       0 $result->{$count}->{'rselfany'} = int $1
164             if /R_RIGHT\S+SELF_AN\S+=(\S+)/;
165 0 0       0 $result->{$count}->{'lselfend'} = int $1
166             if /R_LEFT\S+SELF_EN\S+=(\S+)/;
167 0 0       0 $result->{$count}->{'rselfend'} = int $1
168             if /R_RIGHT\S+SELF_EN\S+=(\S+)/;
169 0 0       0 $result->{$count}->{'lendstab'} = int $1
170             if /R_LEFT\S+END_STABILIT\S+=(\S+)/;
171 0 0       0 $result->{$count}->{'rendstab'} = int $1
172             if /R_RIGHT\S+END_STABILIT\S+=(\S+)/;
173 0 0       0 $result->{$count}->{'pairendcomp'}= int $1
174             if /R_PAIR\S+COMPL_EN\S+=(\S+)/;
175 0 0       0 $result->{$count}->{'pairanycomp'}= int $1
176             if /R_PAIR\S+COMPL_AN\S+=(\S+)/;
177 0 0       0 $result->{$count}->{'hyb_oligo'}= lc $1
178             if /PRIMER_INTERNAL_OLIGO_SEQUENC\S+=(\S+)/;
179            
180             #
181             # round up Primer Tm's
182             #
183 0 0       0 $result->{$count}->{'hyb_tm'}= int (0.5 + $1)
184             if /PRIMER_INTERNAL_OLIGO\S+TM=(\d+)/;
185              
186 0 0       0 $result->{$count}->{'tmleft'} = int (0.5 + $1)
187             if (/^PRIMER_LEFT.*_TM=(\S+)/);
188              
189 0 0       0 $result->{$count}->{'tmright'} = int (0.5 + $1)
190             if (/^PRIMER_RIGHT.*_TM=(\S+)/);
191              
192             #
193             # product size key means that we are at the end of each primer set
194             #
195 0 0 0     0 $result->{$count}->{'prod'} = $1 and $count++
      0        
196             if /^PRIMER_PRODUCT_SIZ\S+=(\S+)/ && !/RANGE/;
197            
198             #
199             # abort if we encounter a primer3 error message
200             #
201 0 0       0 if (/PRIMER_ERROR/) {
202 0         0 $self->error("Some sort of primer3 error:\n$output");
203 0         0 return '';
204             }
205             }
206              
207             #
208             # save the raw primer3 output (except for input sequence -- too big)
209             #
210 0         0 $result->{1}->{'raw_output'} = $output;
211            
212 0         0 return $result;
213             }
214              
215              
216             # -------------------------------------------------------------------
217             sub request {
218              
219             =pod
220              
221             =head2 request
222              
223             Figures out where the primer3 binary resides and accesses it with a
224             list of parameters for designing primers.
225              
226             =cut
227              
228 0     0 1 0 my ( $self, $method, $loc, $args ) = @_;
229 0   0     0 $method ||= 'remote';
230              
231 0         0 my $config = '';
232 0         0 while ( my ( $key, $value ) = each %$args ) {
233 0         0 $config .= "$key=$value\n";
234             }
235              
236 0         0 my @data = ();
237              
238 0 0       0 if ( $method eq 'remote' ) {
239 0 0       0 my $cgi = Bio::PrimerDesigner::Remote->new
240             or return $self->error('could not make remote object');
241 0         0 my $url = $loc;
242 0         0 $args->{'program'} = $self->binary_name;
243 0         0 @data = $cgi->CGI_request( $url, $args );
244             }
245             else { # "local"
246 0         0 my $path = $loc;
247 0 0       0 my $binary_name = $self->binary_name or return;
248 0         0 my $binary_path = catfile( $path, $binary_name );
249 0 0       0 return $self->error("Can't execute local binary '$binary_path'")
250             unless -x $binary_path;
251              
252 0         0 my ( $tmp_fh, $tmp_file ) = tempfile;
253 0         0 print $tmp_fh $config, "=\n";
254 0         0 close $tmp_fh;
255            
256             #
257             # send the instructions to primer3 and get results
258             #
259 0         0 open RESULT_FILE, "$binary_path < $tmp_file |";
260 0         0 @data = ;
261 0         0 close RESULT_FILE;
262 0         0 unlink $tmp_file;
263             }
264            
265 0 0       0 if ( $self->check_results( $method, @data ) ) {
266 0         0 return @data;
267             }
268             else {
269 0         0 return '';
270             }
271             }
272              
273             # -------------------------------------------------------------------
274             sub check_results {
275              
276             =pod
277              
278             =head2 check_results
279              
280             Verify the validity of the design results.
281              
282             =cut
283              
284 0     0 1 0 my $self = shift;
285 0         0 my $method = shift;
286 0         0 my $results = join '', grep {defined} @_;
  0         0  
287              
288 0 0       0 my $thing = $method eq 'remote' ? 'URL' : 'binary';
289 0         0 my $problem = "Possible problem with the primer3 $thing";
290            
291 0 0       0 if ( $results =~ /SEQUENCE=/m ) {
292 0         0 return 1;
293             }
294             else {
295 0         0 return $self->error("Primer design failure:\n", $problem);
296             }
297             }
298              
299             # -------------------------------------------------------------------
300             sub list_aliases {
301              
302             =pod
303              
304             =head2 list_aliases
305              
306             Prints a list of shorthand aliases for the primer3 BoulderIO
307             input format. The full input/ouput options and the aliases can be
308             used interchangeably.
309              
310             =cut
311              
312 3     3 1 6 my $self = shift;
313            
314             return (
315 3         186 PRIMER_SEQUENCE_ID => 'id',
316             SEQUENCE => 'seq',
317             INCLUDED_REGION => 'inc',
318             TARGET => 'target',
319             EXCLUDED_REGION => 'excluded',
320             PRIMER_COMMENT => 'comment',
321             PRIMER_SEQUENCE_QUALITY => 'quality',
322             PRIMER_LEFT_INPUT => 'leftin',
323             PRIMER_RIGHT_INPUT => 'rightin',
324             PRIMER_START_CODON_POSITION => 'start_cod_pos',
325             PRIMER_PICK_ANYWAY => 'pickanyway',
326             PRIMER_MISPRIMING_LIBRARY => 'misprimelib',
327             PRIMER_MAX_MISPRIMING => 'maxmisprime',
328             PRIMER_PAIR_MAX_MISPRIMING => 'pairmaxmisprime',
329             PRIMER_PRODUCT_MAX_TM => 'prodmaxtm',
330             PRIMER_PRODUCT_MIN_TM => 'prodmintm',
331             PRIMER_EXPLAIN_FLAG => 'explain',
332             PRIMER_PRODUCT_SIZE_RANGE => 'sizerange',
333             PRIMER_GC_CLAMP => 'gcclamp',
334             PRIMER_OPT_SIZE => 'optpsize',
335             PRIMER_INTERNAL_OLIGO_OPT_SIZE => 'hyb_opt_size',
336             PRIMER_MIN_SIZE => 'minpsize',
337             PRIMER_MAX_SIZE => 'maxpsize',
338             PRIMER_OPT_TM => 'opttm',
339             PRIMER_MIN_TM => 'mintm',
340             PRIMER_MAX_TM => 'maxtm',
341             PRIMER_MAX_DIFF_TM => 'maxtmdiff',
342             PRIMER_MIN_GC => 'mingc',
343             PRIMER_OPT_GC_PERCENT => 'optgc',
344             PRIMER_MAX_GC => 'maxgc',
345             PRIMER_SALT_CONC => 'saltconc',
346             PRIMER_DNA_CONC => 'dnaconc',
347             PRIMER_NUM_NS_ACCEPTED => 'maxN',
348             PRIMER_SELF_ANY => 'selfany',
349             PRIMER_SELF_END => 'selfend',
350             PRIMER_DEFAULT_PRODUCT => 'sizerangelist',
351             PRIMER_MAX_POLY_X => 'maxpolyX',
352             PRIMER_LIBERAL_BASE => 'liberal',
353             PRIMER_NUM_RETURN => 'num',
354             PRIMER_FIRST_BASE_INDEX => '1stbaseindex',
355             PRIMER_MAX_END_STABILITY => 'maxendstab',
356             PRIMER_PRODUCT_OPT_TM => 'optprodtm',
357             PRIMER_PRODUCT_OPT_SIZE => 'optprodsize',
358             PRIMER_WT_TM_GT => 'wt_tm_gt',
359             PRIMER_WT_TM_LT => 'wt_tm_lt',
360             PRIMER_WT_SIZE_LT => 'wt_size_lt',
361             PRIMER_WT_SIZE_GT => 'wt_size_gt',
362             PRIMER_WT_GC_PERCENT_LT => 'wt_gc_lt',
363             PRIMER_WT_GC_PERCENT_GT => 'wt_gc_gt',
364             PRIMER_WT_COMPL_ANY => 'wt_comp_any',
365             PRIMER_WT_COMPL_END => 'wt_comp_end',
366             PRIMER_WT_NUM_NS => 'wt_numN',
367             PRIMER_WT_REP_SIM => 'wt_rep_sim',
368             PRIMER_WT_SEQ_QUAL => 'wt_seq_qual',
369             PRIMER_WT_END_QUAL => 'wt_end_qual',
370             PRIMER_WT_END_STABILITY => 'wt_end_stab',
371             PRIMER_PAIR_WT_PR_PENALTY => 'wt_pr_penalty',
372             PRIMER_PAIR_WT_DIFF_TM => 'wt_pr_tmdiff',
373             PRIMER_PAIR_WT_COMPL_ANY => 'wt_pr_comp_any',
374             PRIMER_PAIR_WT_COMPL_END => 'wt_pr_comp_end',
375             PRIMER_PAIR_WT_PRODUCT_TM_LT => 'wt_prodtm_lt',
376             PRIMER_PAIR_WT_PRODUCT_TM_GT => 'wt_prodtm_gt',
377             PRIMER_PAIR_WT_PRODUCT_SIZE_GT => 'wt_prodsize_gt',
378             PRIMER_PAIR_WT_PRODUCT_SIZE_LT => 'wt_prodsize_lt',
379             PRIMER_PAIR_WT_REP_SIM => 'wt_repsim',
380             PRIMER_PICK_INTERNAL_OLIGO => 'hyb_oligo',
381             PRIMER_LEFT_EXPLAIN => 'left_explain',
382             PRIMER_RIGHT_EXPLAIN => 'right_explain',
383             PRIMER_PAIR_EXPLAIN => 'pair_explain',
384             PRIMER_INTERNAL_OLIGO_EXPLAIN => 'hyb_explain',
385             PRIMER_INTERNAL_OLIGO_MIN_SIZE => 'hyb_min_size',
386             PRIMER_INTERNAL_OLIGO_MAX_SIZE => 'hyb_max_size',
387             );
388             }
389              
390             # -------------------------------------------------------------------
391             sub list_params {
392              
393             =pod
394              
395             =head2 list_params
396              
397             Returns a list of primer3 configuration options. primer3 will use
398             reasonable default options for most parameters.
399              
400             =cut
401              
402              
403 1     1 1 2 my $self = shift;
404              
405             return (
406 1         9 'PRIMER_SEQUENCE_ID (string, optional)',
407             'SEQUENCE (nucleotide sequence, REQUIRED)',
408             'INCLUDED_REGION (interval, optional)',
409             'TARGET (interval list, default empty)',
410             'EXCLUDED_REGION (interval list, default empty)',
411             'PRIMER_COMMENT (string, optional)',
412             'PRIMER_SEQUENCE_QUALITY (quality list, default empty)',
413             'PRIMER_LEFT_INPUT (nucleotide sequence, default empty)',
414             'PRIMER_RIGHT_INPUT (nucleotide sequence, default empty)',
415             'PRIMER_START_CODON_POSITION (int, default -1000000)',
416             'PRIMER_PICK_ANYWAY (boolean, default 0)',
417             'PRIMER_MISPRIMING_LIBRARY (string, optional)',
418             'PRIMER_MAX_MISPRIMING (decimal,9999.99, default 12.00)',
419             'PRIMER_PAIR_MAX_MISPRIMING (decimal,9999.99, default 24.00)',
420             'PRIMER_PRODUCT_MAX_TM (float, default 1000000.0)',
421             'PRIMER_PRODUCT_MIN_TM (float, default -1000000.0)',
422             'PRIMER_EXPLAIN_FLAG (boolean, default 0)',
423             'PRIMER_PRODUCT_SIZE_RANGE (size range list, default 100-300)',
424             'PRIMER_GC_CLAMP (int, default 0)',
425             'PRIMER_OPT_SIZE (int, default 20)',
426             'PRIMER_MIN_SIZE (int, default 18)',
427             'PRIMER_MAX_SIZE (int, default 27)',
428             'PRIMER_OPT_TM (float, default 60.0C)',
429             'PRIMER_MIN_TM (float, default 57.0C)',
430             'PRIMER_MAX_TM (float, default 63.0C)',
431             'PRIMER_MAX_DIFF_TM (float, default 100.0C)',
432             'PRIMER_MIN_GC (float, default 20.0%)',
433             'PRIMER_OPT_GC_PERCENT (float, default 50.0%)',
434             'PRIMER_MAX_GC (float, default 80.0%)',
435             'PRIMER_SALT_CONC (float, default 50.0 mM)',
436             'PRIMER_DNA_CONC (float, default 50.0 nM)',
437             'PRIMER_NUM_NS_ACCEPTED (int, default 0)',
438             'PRIMER_SELF_ANY (decimal,9999.99, default 8.00)',
439             'PRIMER_SELF_END (decimal 9999.99, default 3.00)',
440             'PRIMER_DEFAULT_PRODUCT (size range list, default 100-300)',
441             'PRIMER_MAX_POLY_X (int, default 5)',
442             'PRIMER_LIBERAL_BASE (boolean, default 0)',
443             'PRIMER_NUM_RETURN (int, default 5)',
444             'PRIMER_FIRST_BASE_INDEX (int, default 0)',
445             'PRIMER_MAX_END_STABILITY (float 999.9999, default 100.0)',
446             'PRIMER_PRODUCT_OPT_TM (float, default 0.0)',
447             'PRIMER_PRODUCT_OPT_SIZE (int, default 0)',
448             '',
449             '** PENALTY WEIGHTS **',
450             '',
451             'PRIMER_WT_TM_GT (float, default 1.0)',
452             'PRIMER_WT_TM_LT (float, default 1.0)',
453             'PRIMER_WT_SIZE_LT (float, default 1.0)',
454             'PRIMER_WT_SIZE_GT (float, default 1.0)',
455             'PRIMER_WT_GC_PERCENT_LT (float, default 1.0)',
456             'PRIMER_WT_GC_PERCENT_GT (float, default 1.0)',
457             'PRIMER_WT_COMPL_ANY (float, default 0.0)',
458             'PRIMER_WT_COMPL_END (float, default 0.0)',
459             'PRIMER_WT_NUM_NS (float, default 0.0)',
460             'PRIMER_WT_REP_SIM (float, default 0.0)',
461             'PRIMER_WT_SEQ_QUAL (float, default 0.0)',
462             'PRIMER_WT_END_QUAL (float, default 0.0)',
463             'PRIMER_WT_END_STABILITY (float, default 0.0)',
464             'PRIMER_PAIR_WT_PR_PENALTY (float, default 1.0)',
465             'PRIMER_PAIR_WT_DIFF_TM (float, default 0.0)',
466             'PRIMER_PAIR_WT_COMPL_ANY (float, default 0.0)',
467             'PRIMER_PAIR_WT_COMPL_END (float, default 0.0)',
468             'PRIMER_PAIR_WT_PRODUCT_TM_LT (float, default 0.0)',
469             'PRIMER_PAIR_WT_PRODUCT_TM_GT (float, default 0.0)',
470             'PRIMER_PAIR_WT_PRODUCT_SIZE_GT (float, default 0.0)',
471             'PRIMER_PAIR_WT_PRODUCT_SIZE_LT (float, default 0.0)',
472             'PRIMER_PAIR_WT_REP_SIM (float, default 0.0)',
473             );
474             }
475              
476             # -------------------------------------------------------------------
477             sub example {
478              
479             =pod
480              
481             =head2 example
482              
483             Runs a sample remote primer design job. Returns an
484             Bio::PrimerDesigner::Result object.
485              
486             =cut
487              
488 2     2 1 3 my $self = shift;
489 2         9 my $dna = $self->_example_dna;
490 2         5 my $length = length $dna;
491 2 50       25 my $result = $self->design(
492             'remote',
493             $REMOTE_URL,
494             {
495             num => 1,
496             seq => $dna,
497             sizerange => '100-200',
498             target => '150,10',
499             excluded => '1,30 400,' . ($length - 401),
500             id => 'test_seq'
501             }
502             ) or return $self->error("Can't get remote server call to work");
503            
504 2         182 return $result;
505             }
506              
507             # -------------------------------------------------------------------
508             sub _example_dna {
509              
510             =pod
511              
512             =head2 _example_dna
513              
514             Returns an example DNA sequence.
515              
516             =cut
517              
518 2     2   4 my $self = shift;
519 2         7 return 'cagagttaaagagaaaactgataattttttttccatctttctcctcacttgtgaataaac' .
520             'taaacgcatttctgtggacgttccaagtgtaatatgagagttgttttcatttggaaatgc' .
521             'gggaatatattgaatcttccattagatgttcaggaatatataaatacgttgtctgctctg' .
522             'aaaattcacacggaaaatctaaaaattgtcaaattatagatttcattctcaaatgactat' .
523             'ataacattttatttttgcaatttcttttcaattaggaaacatttcaaaaagctacgttgt' .
524             'ttttcacattcaaaatgattactgtcggtgcgttcattttccgagtttttccaatttcac' .
525             'gcttgctcttcttcgtaaaaaactcgtaatttagaaattgtgtctagatcaaaaaaaaaa' .
526             'ttttctgagcaatcctgaatcaggcatgctctctaaacaactctcagatatctgagatat' .
527             'gggaagcaaattttgagaccttactagttataaaaatcattaaaaatcaacgccgacagt' .
528             'ttctcacagaaacttaaaccgaaaaatcccaacgaagacttcagctcttttttctttgaa';
529             }
530              
531             1;
532              
533             # -------------------------------------------------------------------
534              
535             =pod
536              
537             =head1 AUTHOR
538              
539             Copyright (C) 2003-2009 Sheldon McKay Emckays@cshl.eduE,
540             Ken Youens-Clark Ekclark@cpan.orgE.
541              
542             =head1 LICENSE
543              
544             This program is free software; you can redistribute it and/or modify
545             it under the terms of the GNU General Public License as published by
546             the Free Software Foundation; version 3 or any later version.
547              
548             This program is distributed in the hope that it will be useful, but
549             WITHOUT ANY WARRANTY; without even the implied warranty of
550             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
551             General Public License for more details.
552              
553             You should have received a copy of the GNU General Public License
554             along with this program; if not, write to the Free Software
555             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
556             USA.
557              
558             =head1 SEE ALSO
559              
560             Bio::PrimerDesigner::epcr.
561              
562             =cut