[Bio] / FigKernelPackages / gjoalignandtree.pm Repository:
ViewVC logotype

Diff of /FigKernelPackages/gjoalignandtree.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.7, Thu Nov 18 22:39:56 2010 UTC revision 1.8, Mon Dec 6 19:55:51 2010 UTC
# Line 23  Line 23 
23  #    \@trimmed_seq             = extract_with_psiblast( $db, $profile, \%opts )  #    \@trimmed_seq             = extract_with_psiblast( $db, $profile, \%opts )
24  #  ( \@trimmed_seq, \%report ) = extract_with_psiblast( $db, $profile, \%opts )  #  ( \@trimmed_seq, \%report ) = extract_with_psiblast( $db, $profile, \%opts )
25  #  #
26    #  Profile blast against protein database:
27    #
28  #   $structured_blast = blastpgp(  $dbfile,  $profilefile, \%options )  #   $structured_blast = blastpgp(  $dbfile,  $profilefile, \%options )
29  #   $structured_blast = blastpgp( \@dbseq,   $profilefile, \%options )  #   $structured_blast = blastpgp( \@dbseq,   $profilefile, \%options )
30  #   $structured_blast = blastpgp(  $dbfile, \@profileseq,  \%options )  #   $structured_blast = blastpgp(  $dbfile, \@profileseq,  \%options )
31  #   $structured_blast = blastpgp( \@dbseq,  \@profileseq,  \%options )  #   $structured_blast = blastpgp( \@dbseq,  \@profileseq,  \%options )
32  #  #
33    #  Profile blast against DNA database (PSI-tblastn):
34    #
35    #   $structured_blast = blastpgpn(  $dbfile,  $profilefile, \%options )
36    #   $structured_blast = blastpgpn( \@dbseq,   $profilefile, \%options )
37    #   $structured_blast = blastpgpn(  $dbfile, \@profileseq,  \%options )
38    #   $structured_blast = blastpgpn( \@dbseq,  \@profileseq,  \%options )
39    #
40  #   print_blast_as_records(  $file, \@queries )  #   print_blast_as_records(  $file, \@queries )
41  #   print_blast_as_records( \*FH,   \@queries )  #   print_blast_as_records( \*FH,   \@queries )
42  #   print_blast_as_records(         \@queries )     # STDOUT  #   print_blast_as_records(         \@queries )     # STDOUT
# Line 328  Line 337 
337  #  Options:  #  Options:
338  #  #
339  #     e_value       =>  $max_e_value    #  maximum blastpgp E-value (D = 0.01)  #     e_value       =>  $max_e_value    #  maximum blastpgp E-value (D = 0.01)
340  #     max_e_val     =>  $max_e_value    #  maximum blastpgp E-value (D = 0.01)  #     max_e_value   =>  $max_e_value    #  maximum blastpgp E-value (D = 0.01)
341  #     max_q_uncov   =>  $aa_per_end     #  maximum unmatched query (D = 20)  #     max_q_uncov   =>  $aa_per_end     #  maximum unmatched query (D = 20)
342  #     max_q_uncov_c =>  $aa_per_end     #  maximum unmatched query, c-term (D = 20)  #     max_q_uncov_c =>  $aa_per_end     #  maximum unmatched query, c-term (D = 20)
343  #     max_q_uncov_n =>  $aa_per_end     #  maximum unmatched query, n-term (D = 20)  #     max_q_uncov_n =>  $aa_per_end     #  maximum unmatched query, n-term (D = 20)
344  #     min_ident     =>  $frac_ident     #  minimum fraction identity (D =  0.15)  #     min_ident     =>  $frac_ident     #  minimum fraction identity (D =  0.15)
345  #     min_positive  =>  $frac_positive  #  minimum fraction positive scoring (D = 0.20)  #     min_positive  =>  $frac_positive  #  minimum fraction positive scoring (D = 0.20)
346  #     nresult       =>  $max_seq        #  maximim matching sequences (D = 5000)  #     n_result      =>  $max_results    #  maxiumn restuls returned (D = 1000)
347    #     n_thread      =>  $n_thread       #  number of blastpgp threads (D = 2)
348  #     query         =>  $q_file_name    #  query sequence file (D = most complete)  #     query         =>  $q_file_name    #  query sequence file (D = most complete)
349  #     query         => \@q_seq_entry    #  query sequence (D = most complete)  #     query         => \@q_seq_entry    #  query sequence (D = most complete)
350  #     stderr        =>  $file           #  blastpgp stderr (D = /dev/stderr)  #     stderr        =>  $file           #  blastpgp stderr (D = /dev/stderr)
# Line 349  Line 359 
359    
360      $opts && ref $opts eq 'HASH' or $opts = {};      $opts && ref $opts eq 'HASH' or $opts = {};
361    
362      $opts->{ e_value } ||= $opts->{ max_e_val } ||= 0.01;      $opts->{ e_value }  ||= $opts->{ max_e_val } || $opts->{ max_e_value } || 0.01;
363      $opts->{ nresult } ||= 5000;      $opts->{ n_result } ||= 1000;
364        $opts->{ n_thread } ||=    2;
365      my $max_q_uncov_c = $opts->{ max_q_uncov_c } || $opts->{ max_q_uncov } || 20;      my $max_q_uncov_c = $opts->{ max_q_uncov_c } || $opts->{ max_q_uncov } || 20;
366      my $max_q_uncov_n = $opts->{ max_q_uncov_n } || $opts->{ max_q_uncov } || 20;      my $max_q_uncov_n = $opts->{ max_q_uncov_n } || $opts->{ max_q_uncov } || 20;
367      my $min_ident     = $opts->{ min_ident }    ||  0.15;      my $min_ident     = $opts->{ min_ident }    ||  0.15;
# Line 422  Line 433 
433    
434  #-------------------------------------------------------------------------------  #-------------------------------------------------------------------------------
435  #  #
436  #   $structured_blast = blastpgp( $db, $profile, $options )  #   $structured_blast = blastpgp(  $dbfile,  $profilefile, \%options )
437    #   $structured_blast = blastpgp( \@dbseq,   $profilefile, \%options )
438    #   $structured_blast = blastpgp(  $dbfile, \@profileseq,  \%options )
439    #   $structured_blast = blastpgp( \@dbseq,  \@profileseq,  \%options )
440  #  #
441  #  Required:  #  Required:
442  #  #
# Line 431  Line 445 
445  #  #
446  #  Options:  #  Options:
447  #  #
448  #     e_value   =>  $max_e_value   # D = 0.01  #     e_value     =>  $max_e_value   # maximum E-value of matches (D = 0.01)
449  #     max_e_val =>  $max_e_value   # D = 0.01  #     max_e_value =>  $max_e_value   # maximum E-value of matches (D = 0.01)
450  #     nresult   =>  $max_seq       # D = 5000  #     n_result    =>  $max_results   # maximum matches returned (D = 1000)
451    #     n_thread    =>  $n_thread      # number of blastpgp threads (D = 2)
452    #     stderr      =>  $file          # place to send blast stderr (D = /dev/null)
453  #     query     =>  $q_file_name   # most complete  #     query     =>  $q_file_name   # most complete
454  #     query     => \@q_seq_entry   # most complete  #     query     => \@q_seq_entry   # most complete
455  #  #
# Line 443  Line 459 
459  {  {
460      my ( $db, $profile, $opts ) = @_;      my ( $db, $profile, $opts ) = @_;
461      $opts ||= {};      $opts ||= {};
462      my $tmp = SeedAware::location_of_tmp();      my $tmp = SeedAware::location_of_tmp( $opts );
463    
464      my ( $dbfile, $rm_db );      my ( $dbfile, $rm_db );
465      if ( defined $db && ref $db )      if ( defined $db && ref $db )
# Line 452  Line 468 
468              && @$db              && @$db
469              || print STDERR "blastpgp requires one or more database sequences.\n"              || print STDERR "blastpgp requires one or more database sequences.\n"
470                 && return undef;                 && return undef;
471          $dbfile = "$tmp/blastpgp_db_$$";          $dbfile = SeedAware::new_file_name( "$tmp/blastpgp_db" );
472          gjoseqlib::print_alignment_as_fasta( $dbfile, $db );          gjoseqlib::print_alignment_as_fasta( $dbfile, $db );
473          $rm_db = 1;          $rm_db = 1;
474      }      }
# Line 473  Line 489 
489              && @$profile              && @$profile
490              || print STDERR "blastpgp requires one or more profile sequences.\n"              || print STDERR "blastpgp requires one or more profile sequences.\n"
491                 && return undef;                 && return undef;
492          $proffile = "$tmp/blastpgp_profile_$$";          $proffile = SeedAware::new_file_name( "$tmp/blastpgp_profile" );
493          &print_alignment_as_pseudoclustal( $profile,  { file => $proffile, upper => 1 } );          &print_alignment_as_pseudoclustal( $profile,  { file => $proffile, upper => 1 } );
494          $rm_profile = 1;          $rm_profile = 1;
495      }      }
# Line 494  Line 510 
510              or print STDERR "blastpgp invalid query sequence.\n"              or print STDERR "blastpgp invalid query sequence.\n"
511                 and return undef;                 and return undef;
512    
513          $qfile = "$tmp/blastpgp_query_$$";          $qfile = SeedAware::new_file_name( "$tmp/blastpgp_query" );
514          gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );          gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );
515          $rm_query = 1;          $rm_query = 1;
516      }      }
# Line 505  Line 521 
521      elsif ( $profile )    #  Build it from profile      elsif ( $profile )    #  Build it from profile
522      {      {
523          $query = &representative_for_profile( $profile );          $query = &representative_for_profile( $profile );
524          $qfile = "$tmp/blastpgp_query_$$";          $qfile = SeedAware::new_file_name( "$tmp/blastpgp_query" );
525          gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );          gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );
526          $rm_query = 1;          $rm_query = 1;
527      }      }
# Line 514  Line 530 
530          die "blastpgp requires database.";          die "blastpgp requires database.";
531      }      }
532    
533      my $nkeep = $opts->{ nresult } || $opts->{ n_result }  || 5000;      my $e_val = $opts->{ e_value }  || $opts->{ max_e_val } || $opts->{ max_e_value }            ||    0.01;
534      my $e_val = $opts->{ e_value } || $opts->{ max_e_val } ||    0.01;      my $n_cpu = $opts->{ n_thread } || $opts->{ nthread } || $opts->{ n_cpu } || $opts->{ ncpu } ||    2;
535        my $nkeep = $opts->{ n_result } || $opts->{ nresult }                                        || 1000;
536    
537      my @cmd = ( SeedAware::executable_for( 'blastpgp' ),      my @cmd = ( SeedAware::executable_for( 'blastpgp' ),
538                  '-B', $proffile,                  '-j', 1,          #  function is profile alignment
539                  '-j', 1,                  '-B', $proffile,  #  location of profile
540                  '-d', $dbfile,                  '-d', $dbfile,
541                    '-i', $qfile,
542                    '-e', $e_val,
543                  '-b', $nkeep,                  '-b', $nkeep,
544                  '-v', $nkeep,                  '-v', $nkeep,
545                  '-i', $qfile,                  '-t', 1           #  issues warning if not set
                 '-e', $e_val  
546                );                );
547        push @cmd, ( '-a', $n_cpu ) if $n_cpu;
548    
549      my $blastfh = SeedAware::read_from_pipe_with_redirect( @cmd, $opts->{stderr} ? { stderr => $opts->{stderr} } : () )      my $opts2 = { stderr => ( $opts->{stderr} || '/dev/null' ) };
550        my $blastfh = SeedAware::read_from_pipe_with_redirect( @cmd, $opts2 )
551             or print STDERR "Failed to open: '" . join( ' ', @cmd ), "'.\n"             or print STDERR "Failed to open: '" . join( ' ', @cmd ), "'.\n"
552                and return undef;                and return undef;
553      my $out = &gjoparseblast::structured_blast_output( $blastfh, 1 );  # selfmatches okay      my $out = &gjoparseblast::structured_blast_output( $blastfh, 1 );  # selfmatches okay
# Line 545  Line 566 
566    
567    
568  #-------------------------------------------------------------------------------  #-------------------------------------------------------------------------------
569    #  Do psiblast against tranlated genomic DNA
570    #
571    #   $structured_blast = blastpgpn(  $dbfile,  $profilefile, \%options )
572    #   $structured_blast = blastpgpn( \@dbseq,   $profilefile, \%options )
573    #   $structured_blast = blastpgpn(  $dbfile, \@profileseq,  \%options )
574    #   $structured_blast = blastpgpn( \@dbseq,  \@profileseq,  \%options )
575    #
576    #  Required:
577    #
578    #     $db_file      or \@db_seq
579    #     $profile_file or \@profile_seq
580    #
581    #  Options:
582    #
583    #     aa_db_file =>  $trans_file    # put translation db here
584    #     e_value    =>  $max_e_value   # D = 0.01
585    #     max_e_val  =>  $max_e_value   # D = 0.01
586    #     n_cpu      =>  $n_cpu         # synonym of n_thread
587    #     n_result   =>  $max_seq       # D = 1000
588    #     n_thread   =>  $n_cpu         # D = 1
589    #     query      =>  $q_file_name   # most complete
590    #     query      => \@q_seq_entry   # most complete
591    #     stderr     =>  $file          # place to send blast stderr (D = /dev/null)
592    #     tmp        =>  $temp_dir      # location for temp files
593    #
594    #  depricated alternatives:
595    #
596    #     prot_file  =>  $trans_file    # put translation db here
597    #-------------------------------------------------------------------------------
598    
599    sub blastpgpn
600    {
601        my ( $ndb, $profile, $opts ) = @_;
602        $opts ||= {};
603        my $tmp = SeedAware::location_of_tmp( $opts );
604    
605        $opts->{ aa_db_file } ||= $opts->{ prot_file } if defined $opts->{ prot_file };
606        my $dbfile =   $opts->{ aa_db_file } || SeedAware::new_file_name( "$tmp/blastpgpn_db" );
607        my $rm_db  = ! $opts->{ aa_db_file };
608        if ( defined $dbfile && -f $dbfile && -s $dbfile )
609        {
610            #  The tranaslated sequence database exists
611        }
612        elsif ( defined $ndb )
613        {
614            if ( ref $ndb eq 'ARRAY' && @$ndb )
615            {
616                ref $ndb eq 'ARRAY'
617                    && @$ndb
618                    || print STDERR "Bad sequence reference passed to blastpgpn.\n"
619                       && return undef;
620                my @pdb = map { six_translations( $_ ) } @$ndb;
621                gjoseqlib::print_alignment_as_fasta( $dbfile, \@pdb );
622            }
623            elsif ( -f $ndb && -s $ndb )
624            {
625                open( PDB, ">$dbfile" )
626                    or print STDERR "Could not open protein database file '$dbfile'.\n"
627                        and return undef;
628                my $entry;
629                while ( $entry = gjoseqlib::next_fasta_entry( $ndb ) )
630                {
631                    gjoseqlib::write_alignment_as_fasta( \*PDB, six_translations( $entry ) );
632                }
633                close PDB;
634            }
635            else
636            {
637                die "blastpgpn requires a sequence database.";
638            }
639        }
640        verify_db( $dbfile, 'P' );  # protein
641    
642        my ( $proffile, $rm_profile );
643        if ( defined $profile && ref $profile )
644        {
645            ref $profile eq 'ARRAY'
646                && @$profile
647                || print STDERR "blastpgpn requires one or more profile sequences.\n"
648                   && return undef;
649            $proffile = SeedAware::new_file_name( "$tmp/blastpgpn_profile" );
650            &print_alignment_as_pseudoclustal( $profile,  { file => $proffile, upper => 1 } );
651            $rm_profile = 1;
652        }
653        elsif ( defined $profile && -f $profile )
654        {
655            $proffile = $profile;
656        }
657        else
658        {
659            die "blastpgpn requires profile.";
660        }
661    
662        my ( $qfile, $rm_query );
663        my $query = $opts->{ query };
664        if ( defined $query && ref $query )
665        {
666            ref $query eq 'ARRAY' && @$query == 3
667                or print STDERR "blastpgpn invalid query sequence.\n"
668                   and return undef;
669    
670            $qfile = SeedAware::new_file_name( "$tmp/blastpgpn_query" );
671            gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );
672            $rm_query = 1;
673        }
674        elsif ( defined $query && -f $query )
675        {
676            $qfile = $query;
677        }
678        elsif ( $profile )    #  Build it from profile
679        {
680            $query = &representative_for_profile( $profile );
681            $qfile = SeedAware::new_file_name( "$tmp/blastpgpn_query" );
682            gjoseqlib::print_alignment_as_fasta( $qfile, [$query] );
683            $rm_query = 1;
684        }
685        else
686        {
687            die "blastpgpn requires database.";
688        }
689    
690        my $e_val = $opts->{ e_value }  || $opts->{ max_e_val } || $opts->{ max_e_value }            ||    0.01;
691        my $n_cpu = $opts->{ n_thread } || $opts->{ nthread } || $opts->{ n_cpu } || $opts->{ ncpu } ||    2;
692        my $nkeep = $opts->{ n_result } || $opts->{ nresult }                                        || 1000;
693    
694        my @cmd = ( SeedAware::executable_for( 'blastpgp' ),
695                    '-j', 1,          #  function is profile alignment
696                    '-B', $proffile,  #  location of protein profile
697                    '-d', $dbfile,    #  protein database
698                    '-i', $qfile,     #  one protein from the profile
699                    '-e', $e_val,
700                    '-b', $nkeep,
701                    '-v', $nkeep,
702                    '-t', 1,          #  issues warning if not set
703                  );
704        push @cmd, ( '-a', $n_cpu ) if $n_cpu;
705    
706        my $opts2 = { stderr => ( $opts->{stderr} || '/dev/null' ) };
707        my $blastfh = SeedAware::read_from_pipe_with_redirect( @cmd, $opts2 )
708               or print STDERR "Failed to open: '" . join( ' ', @cmd ), "'.\n"
709                  and return undef;
710        my $out = &gjoparseblast::structured_blast_output( $blastfh );
711        close $blastfh;
712    
713        if ( $rm_db )
714        {
715            my @files = grep { -f $_ } map { ( $_, "$_.psq", "$_.pin", "$_.phr" ) } $dbfile;
716            unlink @files if @files;
717        }
718        unlink $proffile if $rm_profile;
719        unlink $qfile    if $rm_query;
720    
721        #  Fix the blastp output to look like tblastn output
722    
723        foreach my $qdata ( @$out )
724        {
725            my %sdata;     #  There are now multiple sequences per subject DNA
726            foreach my $sdata ( @{ $qdata->[3] } )
727            {
728                my ( $sid, $sdef, undef, $hsps ) = @$sdata;
729                my $fr;
730                ( $sid, $fr ) = $sid =~ m/^(.*)\.([-+]\d)$/;
731                my ( $b, $e, $slen ) = $sdef =~ m/(\d+)-(\d+)\/(\d+)$/;
732                $sdef =~ s/ ?\S+$//;
733                my $sd2 = $sdata{ $sid } ||= [ $sid, $sdef, $slen, [] ];
734                foreach ( @$hsps ) { adjust_hsp( $_, $fr, $b ); push @{$sd2->[3]}, $_ }
735            }
736    
737            #  Order the hsps for each subject
738    
739            foreach my $sid ( keys %sdata )
740            {
741                my $hsps = $sdata{ $sid }->[3];
742                @$hsps = sort { $b->[0] <=> $a->[0] } @$hsps;
743            }
744    
745            #  Order the subjects for the query
746    
747            @{$qdata->[3]} = map  { $_->[0] }                    # remove score
748                             sort { $b->[1] <=> $a->[1] }        # sort by score
749                             map  { [ $_, $_->[3]->[0]->[0] ] }  # tag with top score
750                             map  { $sdata{ $_ } }               # subject data
751                             keys %sdata;                        # subject ids
752        }
753    
754        return $out;
755    }
756    
757    
758    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
759    #  When search is versus six frame translation, there is a need to adjust
760    #  the frame and location information in the hsp back to the DNA coordinates.
761    #
762    #     adjust_hsp( $hsp, $frame, $begin )
763    #
764    #   0   1    2    3    4   5    6    7   8  9 10   11  12 13  14
765    #  scr Eval nseg Eval naln nid npos ngap fr q1 q2 qseq s1 s2 sseq
766    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
767    sub adjust_hsp
768    {
769        my ( $hsp, $fr, $b ) = @_;
770        $hsp->[8] = $fr;
771        if ( $fr > 0 )
772        {
773            $hsp->[12] = $b + 3 * ( $hsp->[12] - 1 );
774            $hsp->[13] = $b + 3 * ( $hsp->[13] - 1 ) + 2;
775        }
776        else
777        {
778            $hsp->[12] = $b - 3 * ( $hsp->[12] - 1 );
779            $hsp->[13] = $b - 3 * ( $hsp->[13] - 1 ) - 2;
780        }
781    }
782    
783    
784    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
785    #  Do a six frame translation for use by blastpgpn.  This modifications of
786    #  the identifiers and definitions are essential to the interpretation of
787    #  the blast results.  The program 'translate_fasta_6' produces the same
788    #  output format, and is much faster.
789    #
790    #   @translations = six_translations( $nucleotide_entry )
791    #
792    #  The ids are modified by adding ".frame" (+1, +2, +3, -1, -2, -3).
793    #  The definition is mofidified by adding " begin-end/of_length".
794    #  NCBI frame numbers reverse strand translation frames from the end of the
795    #  sequence (i.e., the beginning of the complement of the strand).
796    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
797    
798    sub six_translations
799    {
800        my ( $id, $def, $seq ) = map { defined($_) ? $_ : '' } @{ $_[0] };
801        my $l = length( $seq );
802    
803        return () if $l < 15;
804    
805        #                    fr   beg    end
806        my @intervals = ( [ '+1',  1,   $l - (  $l    % 3 ) ],
807                          [ '+2',  2,   $l - ( ($l-1) % 3 ) ],
808                          [ '+3',  3,   $l - ( ($l-2) % 3 ) ],
809                          [ '-1', $l,    1 + (  $l    % 3 ) ],
810                          [ '-2', $l-1,  1 + ( ($l-1) % 3 ) ],
811                          [ '-3', $l-2,  1 + ( ($l-2) % 3 ) ]
812                        );
813        my ( $fr, $b, $e );
814    
815        map { ( $fr, $b, $e ) = @$_;
816              [ "$id.$fr", "$def $b-$e/$l", gjoseqlib::translate_seq( gjoseqlib::DNA_subseq( \$seq, $b, $e ) ) ]
817            } @intervals;
818    }
819    
820    
821    #-------------------------------------------------------------------------------
822  #  Get an input file handle, and boolean on whether to close or not:  #  Get an input file handle, and boolean on whether to close or not:
823  #  #
824  #  ( \*FH, $close ) = input_file_handle(  $filename );  #  ( \*FH, $close ) = input_file_handle(  $filename );
# Line 743  Line 1017 
1017      my ( $db, $type ) = @_;      my ( $db, $type ) = @_;
1018    
1019      my @args;      my @args;
1020      if ($type =~ /^p/i && ((! -s "$db.psq") || (-M "$db.psq" > -M $db)))      if ( $type =~ m/^p/i )
     {  
         @args = ( "-p", "T", "-i", $db );  
     }  
     elsif ($type !~ /^p/i && ((! -s "$db.nsq") || (-M "$db.nsq" > -M $db)))  
1021      {      {
1022          @args = ( "-p", "F", "-i", $db );          @args = ( "-p", "T", "-i", $db ) if ((! -s "$db.psq") || (-M "$db.psq" > -M $db));
1023      }      }
1024      else      else
1025      {      {
1026          return 1;          @args = ( "-p", "F", "-i", $db ) if ((! -s "$db.nsq") || (-M "$db.nsq" > -M $db));
1027      }      }
1028        @args or return ( -s $db ? 1 : 0 );
1029    
1030      #      #
1031      # Find formatdb; if we're operating in a SEED environment      #  Find formatdb appropriate for the excecution environemnt.
     # use it from there.  
1032      #      #
1033    
1034      my $prog = SeedAware::executable_for( 'formatdb' );      my $prog = SeedAware::executable_for( 'formatdb' );

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3