]> git.donarmstrong.com Git - biopieces.git/blob - code_perl/Maasha/Biopieces.pm
more updates of c and fixes to upload_to_ucsc
[biopieces.git] / code_perl / Maasha / Biopieces.pm
1 package Maasha::Biopieces;
2
3
4 # Copyright (C) 2007-2008 Martin A. Hansen.
5
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20 # http://www.gnu.org/copyleft/gpl.html
21
22
23 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
24
25
26 # Routines for manipulation, parsing and emitting of human/machine readable biopieces records.
27
28
29 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
30
31
32 use strict;
33 use Data::Dumper;
34 use Getopt::Long qw( :config bundling );
35 use Time::HiRes qw( gettimeofday );
36 use Storable qw( dclone );
37 use Maasha::Config;
38 use Maasha::Common;
39 use Maasha::Fasta;
40 use Maasha::Align;
41 use Maasha::Matrix;
42 use Maasha::Match;
43 use Maasha::EMBL;
44 use Maasha::Stockholm;
45 use Maasha::Seq;
46 use Maasha::Patscan;
47 use Maasha::Plot;
48 use Maasha::Calc;
49 use Maasha::UCSC;
50 use Maasha::NCBI;
51 use Maasha::GFF;
52 use Maasha::TwoBit;
53 use Maasha::Solid;
54 use Maasha::Solexa;
55 use Maasha::SQL;
56 use Maasha::Gwiki;
57
58 use vars qw( @ISA @EXPORT_OK );
59
60 require Exporter;
61
62 @ISA = qw( Exporter );
63
64 @EXPORT_OK = qw(
65     read_stream
66     write_stream
67     get_record
68     put_record
69 );
70
71 use constant {
72     SEQ_NAME => 0,
73     SEQ      => 1,
74     SCORE    => 2,
75 };
76
77
78 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SIGNAL HANDLER <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
79
80
81 $SIG{ '__DIE__' } = \&sig_handler;
82 $SIG{ 'INT' }     = \&sig_handler;
83 $SIG{ 'TERM' }    = \&sig_handler;
84
85
86 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> GLOBALS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
87
88
89 my ( $script, $BP_TMP );
90
91 $script  = Maasha::Common::get_scriptname();
92 $BP_TMP  = Maasha::Common::get_tmpdir();
93
94
95 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOG <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
96
97
98 my $log_global = Maasha::Common::append_open( "$ENV{ 'BP_LOG' }/biopieces.log" );
99 my $log_local  = Maasha::Common::append_open( "$ENV{ 'HOME' }/.biopieces.log" );
100
101 $log_global->autoflush( 1 );
102 $log_local->autoflush( 1 );
103
104 &log( $log_global, $script, \@ARGV );
105 &log( $log_local, $script, \@ARGV );
106
107 close $log_global;
108 close $log_local;
109
110
111 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RUN SCRIPT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
112
113
114 my $t0 = gettimeofday();
115
116 run_script( $script );
117
118 my $t1 = gettimeofday();
119
120 print STDERR "Program: $script" . ( " " x ( 25 - length( $script ) ) ) . sprintf( "Run time: %.4f\n", ( $t1 - $t0 ) );
121
122
123 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SUBROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
124
125
126 sub log
127 {
128     # Martin A. Hansen, January 2008.
129
130     # Log messages to logfile.
131
132     my ( $fh,       # filehandle to logfile
133          $script,   # script name
134          $argv,     # reference to @ARGV
135        ) = @_;
136
137     # Returns nothing.
138
139     my ( $time_stamp, $user );
140
141     $time_stamp = Maasha::Common::time_stamp();
142
143     $user = $ENV{ 'USER' };
144
145     $script = "biopieces" if $script eq "-e";
146
147     print $fh "$time_stamp\t$user\t$script ", join( " ", @{ $argv } ), "\n";
148 }
149
150
151 sub run_script
152 {
153     # Martin A. Hansen, August 2007.
154
155     # Run a specific script.
156
157     my ( $script,   # script name
158        ) = @_;
159
160     # Returns nothing.
161
162     my ( $options, $in, $out );
163
164     $options = get_options( $script );
165
166     $options->{ "SCRIPT" } = $script;
167
168     if ( $script ne "list_biopieces" and $script ne "list_genomes" ) {
169         $script = "print_usage" if ( -t STDIN and keys %{ $options } <= 1 or $options->{ 'help' } );
170     }
171
172     $in  = read_stream( $options->{ "stream_in" } );
173     $out = write_stream( $options->{ "stream_out" } );
174
175     if    ( $script eq "print_usage" )              { script_print_usage(               $in, $out, $options ) }
176     elsif ( $script eq "list_biopieces" )           { script_list_biopieces(            $in, $out, $options ) }
177     elsif ( $script eq "list_genomes" )             { script_list_genomes(              $in, $out, $options ) }
178     elsif ( $script eq "read_fasta" )               { script_read_fasta(                $in, $out, $options ) }
179     elsif ( $script eq "read_tab" )                 { script_read_tab(                  $in, $out, $options ) }
180     elsif ( $script eq "read_psl" )                 { script_read_psl(                  $in, $out, $options ) }
181     elsif ( $script eq "read_bed" )                 { script_read_bed(                  $in, $out, $options ) }
182     elsif ( $script eq "read_fixedstep" )           { script_read_fixedstep(            $in, $out, $options ) }
183     elsif ( $script eq "read_blast_tab" )           { script_read_blast_tab(            $in, $out, $options ) }
184     elsif ( $script eq "read_embl" )                { script_read_embl(                 $in, $out, $options ) }
185     elsif ( $script eq "read_stockholm" )           { script_read_stockholm(            $in, $out, $options ) }
186     elsif ( $script eq "read_phastcons" )           { script_read_phastcons(            $in, $out, $options ) }
187     elsif ( $script eq "read_soft" )                { script_read_soft(                 $in, $out, $options ) }
188     elsif ( $script eq "read_gff" )                 { script_read_gff(                  $in, $out, $options ) }
189     elsif ( $script eq "read_2bit" )                { script_read_2bit(                 $in, $out, $options ) }
190     elsif ( $script eq "read_solexa" )              { script_read_solexa(               $in, $out, $options ) }
191     elsif ( $script eq "read_solid" )               { script_read_solid(                $in, $out, $options ) }
192     elsif ( $script eq "read_mysql" )               { script_read_mysql(                $in, $out, $options ) }
193     elsif ( $script eq "format_genome" )            { script_format_genome(             $in, $out, $options ) }
194     elsif ( $script eq "length_seq" )               { script_length_seq(                $in, $out, $options ) }
195     elsif ( $script eq "uppercase_seq" )            { script_uppercase_seq(             $in, $out, $options ) }
196     elsif ( $script eq "shuffle_seq" )              { script_shuffle_seq(               $in, $out, $options ) }
197     elsif ( $script eq "analyze_seq" )              { script_analyze_seq(               $in, $out, $options ) }
198     elsif ( $script eq "analyze_tags" )             { script_analyze_tags(              $in, $out, $options ) }
199     elsif ( $script eq "complexity_seq" )           { script_complexity_seq(            $in, $out, $options ) }
200     elsif ( $script eq "oligo_freq" )               { script_oligo_freq(                $in, $out, $options ) }
201     elsif ( $script eq "create_weight_matrix" )     { script_create_weight_matrix(      $in, $out, $options ) }
202     elsif ( $script eq "calc_bit_scores" )          { script_calc_bit_scores(           $in, $out, $options ) }
203     elsif ( $script eq "reverse_seq" )              { script_reverse_seq(               $in, $out, $options ) }
204     elsif ( $script eq "complement_seq" )           { script_complement_seq(            $in, $out, $options ) }
205     elsif ( $script eq "remove_indels" )            { script_remove_indels(             $in, $out, $options ) }
206     elsif ( $script eq "transliterate_seq" )        { script_transliterate_seq(         $in, $out, $options ) }
207     elsif ( $script eq "transliterate_vals" )       { script_transliterate_vals(        $in, $out, $options ) }
208     elsif ( $script eq "translate_seq" )            { script_translate_seq(             $in, $out, $options ) }
209     elsif ( $script eq "extract_seq" )              { script_extract_seq(               $in, $out, $options ) }
210     elsif ( $script eq "get_genome_seq" )           { script_get_genome_seq(            $in, $out, $options ) }
211     elsif ( $script eq "get_genome_align" )         { script_get_genome_align(          $in, $out, $options ) }
212     elsif ( $script eq "get_genome_phastcons" )     { script_get_genome_phastcons(      $in, $out, $options ) }
213     elsif ( $script eq "fold_seq" )                 { script_fold_seq(                  $in, $out, $options ) }
214     elsif ( $script eq "split_seq" )                { script_split_seq(                 $in, $out, $options ) }
215     elsif ( $script eq "split_bed" )                { script_split_bed(                 $in, $out, $options ) }
216     elsif ( $script eq "align_seq" )                { script_align_seq(                 $in, $out, $options ) }
217     elsif ( $script eq "tile_seq" )                 { script_tile_seq(                  $in, $out, $options ) }
218     elsif ( $script eq "invert_align" )             { script_invert_align(              $in, $out, $options ) }
219     elsif ( $script eq "patscan_seq" )              { script_patscan_seq(               $in, $out, $options ) }
220     elsif ( $script eq "create_blast_db" )          { script_create_blast_db(           $in, $out, $options ) }
221     elsif ( $script eq "blast_seq" )                { script_blast_seq(                 $in, $out, $options ) }
222     elsif ( $script eq "blat_seq" )                 { script_blat_seq(                  $in, $out, $options ) }
223     elsif ( $script eq "soap_seq" )                 { script_soap_seq(                  $in, $out, $options ) }
224     elsif ( $script eq "match_seq" )                { script_match_seq(                 $in, $out, $options ) }
225     elsif ( $script eq "create_vmatch_index" )      { script_create_vmatch_index(       $in, $out, $options ) }
226     elsif ( $script eq "vmatch_seq" )               { script_vmatch_seq(                $in, $out, $options ) }
227     elsif ( $script eq "write_fasta" )              { script_write_fasta(               $in, $out, $options ) }
228     elsif ( $script eq "write_align" )              { script_write_align(               $in, $out, $options ) }
229     elsif ( $script eq "write_blast" )              { script_write_blast(               $in, $out, $options ) }
230     elsif ( $script eq "write_tab" )                { script_write_tab(                 $in, $out, $options ) }
231     elsif ( $script eq "write_bed" )                { script_write_bed(                 $in, $out, $options ) }
232     elsif ( $script eq "write_psl" )                { script_write_psl(                 $in, $out, $options ) }
233     elsif ( $script eq "write_fixedstep" )          { script_write_fixedstep(           $in, $out, $options ) }
234     elsif ( $script eq "write_2bit" )               { script_write_2bit(                $in, $out, $options ) }
235     elsif ( $script eq "write_solid" )              { script_write_solid(               $in, $out, $options ) }
236     elsif ( $script eq "head_records" )             { script_head_records(              $in, $out, $options ) }
237     elsif ( $script eq "remove_keys" )              { script_remove_keys(               $in, $out, $options ) }
238     elsif ( $script eq "rename_keys" )              { script_rename_keys(               $in, $out, $options ) }
239     elsif ( $script eq "uniq_vals" )                { script_uniq_vals(                 $in, $out, $options ) }
240     elsif ( $script eq "merge_vals" )               { script_merge_vals(                $in, $out, $options ) }
241     elsif ( $script eq "merge_records" )            { script_merge_records(             $in, $out, $options ) }
242     elsif ( $script eq "grab" )                     { script_grab(                      $in, $out, $options ) }
243     elsif ( $script eq "compute" )                  { script_compute(                   $in, $out, $options ) }
244     elsif ( $script eq "flip_tab" )                 { script_flip_tab(                  $in, $out, $options ) }
245     elsif ( $script eq "add_ident" )                { script_add_ident(                 $in, $out, $options ) }
246     elsif ( $script eq "count_records" )            { script_count_records(             $in, $out, $options ) }
247     elsif ( $script eq "random_records" )           { script_random_records(            $in, $out, $options ) }
248     elsif ( $script eq "sort_records" )             { script_sort_records(              $in, $out, $options ) }
249     elsif ( $script eq "count_vals" )               { script_count_vals(                $in, $out, $options ) }
250     elsif ( $script eq "plot_histogram" )           { script_plot_histogram(            $in, $out, $options ) }
251     elsif ( $script eq "plot_lendist" )             { script_plot_lendist(              $in, $out, $options ) }
252     elsif ( $script eq "plot_chrdist" )             { script_plot_chrdist(              $in, $out, $options ) }
253     elsif ( $script eq "plot_karyogram" )           { script_plot_karyogram(            $in, $out, $options ) }
254     elsif ( $script eq "plot_matches" )             { script_plot_matches(              $in, $out, $options ) }
255     elsif ( $script eq "plot_seqlogo" )             { script_plot_seqlogo(              $in, $out, $options ) }
256     elsif ( $script eq "plot_phastcons_profiles" )  { script_plot_phastcons_profiles(   $in, $out, $options ) }
257     elsif ( $script eq "analyze_bed" )              { script_analyze_bed(               $in, $out, $options ) }
258     elsif ( $script eq "analyze_vals" )             { script_analyze_vals(              $in, $out, $options ) }
259     elsif ( $script eq "length_vals" )              { script_length_vals(               $in, $out, $options ) }
260     elsif ( $script eq "sum_vals" )                 { script_sum_vals(                  $in, $out, $options ) }
261     elsif ( $script eq "mean_vals" )                { script_mean_vals(                 $in, $out, $options ) }
262     elsif ( $script eq "median_vals" )              { script_median_vals(               $in, $out, $options ) }
263     elsif ( $script eq "max_vals" )                 { script_max_vals(                  $in, $out, $options ) }
264     elsif ( $script eq "min_vals" )                 { script_min_vals(                  $in, $out, $options ) }
265     elsif ( $script eq "upload_to_ucsc" )           { script_upload_to_ucsc(            $in, $out, $options ) }
266
267     close $in if defined $in;
268     close $out;
269 }
270
271
272 sub get_options
273 {
274     # Martin A. Hansen, February 2008.
275
276     # Gets options from commandline and checks these vigerously.
277
278     my ( $script,     # name of script
279        ) = @_;
280
281     # Returns hash
282
283     my ( %options, @options, $opt, @genomes );
284
285     if ( $script eq "print_usage" )
286     {
287         @options = qw(
288             data_in|i=s
289         );
290     }
291     elsif ( $script eq "read_fasta" )
292     {
293         @options = qw(
294             data_in|i=s
295             num|n=s
296         );
297     }
298     elsif ( $script eq "read_tab" )
299     {
300         @options = qw(
301             data_in|i=s
302             delimit|d=s
303             cols|c=s
304             keys|k=s
305             skip|s=s
306             num|n=s
307         );
308     }
309     elsif ( $script eq "read_psl" )
310     {
311         @options = qw(
312             data_in|i=s
313             num|n=s
314         );
315     }
316     elsif ( $script eq "read_bed" )
317     {
318         @options = qw(
319             data_in|i=s
320             num|n=s
321         );
322     }
323     elsif ( $script eq "read_fixedstep" )
324     {
325         @options = qw(
326             data_in|i=s
327             num|n=s
328         );
329     }
330     elsif ( $script eq "read_blast_tab" )
331     {
332         @options = qw(
333             data_in|i=s
334             num|n=s
335         );
336     }
337     elsif ( $script eq "read_embl" )
338     {
339         @options = qw(
340             data_in|i=s
341             num|n=s
342             keys|k=s
343             feats|f=s
344             quals|q=s
345         );
346     }
347     elsif ( $script eq "read_stockholm" )
348     {
349         @options = qw(
350             data_in|i=s
351             num|n=s
352         );
353     }
354     elsif ( $script eq "read_phastcons" )
355     {
356         @options = qw(
357             data_in|i=s
358             num|n=s
359             min|m=s
360             dist|d=s
361             threshold|t=f
362             gap|g=s
363         );
364     }
365     elsif ( $script eq "read_soft" )
366     {
367         @options = qw(
368             data_in|i=s
369             num|n=s
370         );
371     }
372     elsif ( $script eq "read_gff" )
373     {
374         @options = qw(
375             data_in|i=s
376             num|n=s
377         );
378     }
379     elsif ( $script eq "read_2bit" )
380     {
381         @options = qw(
382             data_in|i=s
383             num|n=s
384             no_mask|N
385         );
386     }
387     elsif ( $script eq "read_solexa" )
388     {
389         @options = qw(
390             data_in|i=s
391             num|n=s
392             quality|q=s
393         );
394     }
395     elsif ( $script eq "read_solid" )
396     {
397         @options = qw(
398             data_in|i=s
399             num|n=s
400             quality|q=s
401         );
402     }
403     elsif ( $script eq "read_mysql" )
404     {
405         @options = qw(
406             database|d=s
407             query|q=s
408             user|u=s
409             password|p=s
410         );
411     }
412     elsif ( $script eq "format_genome" )
413     {
414         @options = qw(
415             no_stream|x
416             dir|d=s
417             genome|g=s
418             formats|f=s
419         );
420     }
421     elsif ( $script eq "length_seq" )
422     {
423         @options = qw(
424             no_stream|x
425             data_out|o=s
426         );
427     }
428     elsif ( $script eq "oligo_freq" )
429     {
430         @options = qw(
431             word_size|w=s
432             all|a
433         );
434     }
435     elsif ( $script eq "create_weight_matrix" )
436     {
437         @options = qw(
438             percent|p
439         );
440     }
441     elsif ( $script eq "transliterate_seq" )
442     {
443         @options = qw(
444             search|s=s
445             replace|r=s
446             delete|d=s
447         );
448     }
449     elsif ( $script eq "transliterate_vals" )
450     {
451         @options = qw(
452             keys|k=s
453             search|s=s
454             replace|r=s
455             delete|d=s
456         );
457     }
458     elsif ( $script eq "translate_seq" )
459     {
460         @options = qw(
461             frames|f=s
462         );
463     }
464     elsif ( $script eq "extract_seq" )
465     {
466         @options = qw(
467             beg|b=s
468             end|e=s
469             len|l=s
470         );
471     }
472     elsif ( $script eq "get_genome_seq" )
473     {
474         @options = qw(
475             genome|g=s
476             chr|c=s
477             beg|b=s
478             end|e=s
479             len|l=s
480             flank|f=s
481             mask|m
482         );
483     }
484     elsif ( $script eq "get_genome_align" )
485     {
486         @options = qw(
487             genome|g=s
488             chr|c=s
489             beg|b=s
490             end|e=s
491             len|l=s
492             strand|s=s
493         );
494     }
495     elsif ( $script eq "get_genome_phastcons" )
496     {
497         @options = qw(
498             genome|g=s
499             chr|c=s
500             beg|b=s
501             end|e=s
502             len|l=s
503             flank|f=s
504         );
505     }
506     elsif ( $script eq "split_seq" )
507     {
508         @options = qw(
509             word_size|w=s
510             uniq|u
511         );
512     }
513     elsif ( $script eq "split_bed" )
514     {
515         @options = qw(
516             window_size|w=s
517             step_size|s=s
518         );
519     }
520     elsif ( $script eq "tile_seq" )
521     {
522         @options = qw(
523             identity|i=s
524             supress_indels|s
525         );
526     }
527     elsif ( $script eq "invert_align" )
528     {
529         @options = qw(
530             soft|s
531         );
532     }
533     elsif ( $script eq "patscan_seq" )
534     {
535         @options = qw(
536             patterns|p=s
537             patterns_in|P=s
538             comp|c
539             max_hits|h=s
540             max_misses|m=s
541             genome|g=s
542         );
543     }
544     elsif ( $script eq "create_blast_db" )
545     {
546         @options = qw(
547             no_stream|x
548             database|d=s
549         );
550     }
551     elsif ( $script eq "blast_seq" )
552     {
553         @options = qw(
554             database|d=s
555             genome|g=s
556             program|p=s
557             e_val|e=f
558             filter|f
559             cpus|c=s
560             no_filter|F
561         );
562     }
563     elsif ( $script eq "blat_seq" )
564     {
565         @options = qw(
566             genome|g=s
567             tile_size|t=s
568             step_size|s=s
569             min_identity|m=s
570             min_score|M=s
571             one_off|o=s
572             ooc|c
573         );
574     }
575     elsif ( $script eq "soap_seq" )
576     {
577         @options = qw(
578             in_file|i=s
579             genome|g=s
580             seed_size|s=s
581             mismatches|m=s
582             gap_size|G=s
583             cpus|c=s
584         );
585     }
586     elsif ( $script eq "match_seq" )
587     {
588         @options = qw(
589             word_size|w=s
590             direction|d=s
591         );
592     }
593     elsif ( $script eq "create_vmatch_index" )
594     {
595         @options = qw(
596             index_name|i=s
597             prefix_length|p=s
598             no_stream|x
599         );
600     }
601     elsif ( $script eq "vmatch_seq" )
602     {
603         @options = qw(
604             genome|g=s
605             index_name|i=s
606             count|c
607             max_hits|m=s
608             hamming_dist|h=s
609             edit_dist|e=s
610         );
611     }
612     elsif ( $script eq "write_fasta" )
613     {
614         @options = qw(
615             wrap|w=s
616             no_stream|x
617             data_out|o=s
618             compress|Z
619         );
620     }
621     elsif ( $script eq "write_align" )
622     {
623         @options = qw(
624             wrap|w=s
625             no_stream|x
626             no_ruler|R
627             no_consensus|C
628             data_out|o=s
629         );
630     }
631     elsif ( $script eq "write_blast" )
632     {
633         @options = qw(
634             no_stream|x
635             data_out|o=s
636             comment|c
637             compress|Z
638         );
639     }
640     elsif ( $script eq "write_tab" )
641     {
642         @options = qw(
643             no_stream|x
644             data_out|o=s
645             delimit|d=s
646             keys|k=s
647             no_keys|K=s
648             comment|c
649             compress|Z
650         );
651     }
652     elsif ( $script eq "write_bed" )
653     {
654         @options = qw(
655             no_stream|x
656             data_out|o=s
657             compress|Z
658         );
659     }
660     elsif ( $script eq "write_psl" )
661     {
662         @options = qw(
663             no_stream|x
664             data_out|o=s
665             compress|Z
666         );
667     }
668     elsif ( $script eq "write_fixedstep" )
669     {
670         @options = qw(
671             no_stream|x
672             data_out|o=s
673             compress|Z
674         );
675     }
676     elsif ( $script eq "write_2bit" )
677     {
678         @options = qw(
679             no_stream|x
680             data_out|o=s
681             no_mask|N
682         );
683     }
684     elsif ( $script eq "write_solid" )
685     {
686         @options = qw(
687             wrap|w=s
688             no_stream|x
689             data_out|o=s
690             compress|Z
691         );
692     }
693     elsif ( $script eq "plot_seqlogo" )
694     {
695         @options = qw(
696             no_stream|x
697             data_out|o=s
698         );
699     }
700     elsif ( $script eq "plot_phastcons_profiles" )
701     {
702         @options = qw(
703             no_stream|x
704             data_out|o=s
705             genome|g=s
706             mean|m
707             median|M
708             flank|f=s
709             terminal|t=s
710             title|T=s
711             xlabel|X=s
712             ylabel|Y=s
713         );
714     }
715     elsif ( $script eq "analyze_vals" )
716     {
717         @options = qw(
718             no_stream|x
719             keys|k=s
720         );
721     }
722     elsif ( $script eq "head_records" )
723     {
724         @options = qw(
725             num|n=s
726         );
727     }
728     elsif ( $script eq "remove_keys" )
729     {
730         @options = qw(
731             keys|k=s
732             save_keys|K=s
733         );
734     }
735     elsif ( $script eq "rename_keys" )
736     {
737         @options = qw(
738             keys|k=s
739         );
740     }
741     elsif ( $script eq "uniq_vals" )
742     {
743         @options = qw(
744             key|k=s
745             invert|i
746         );
747     }
748     elsif ( $script eq "merge_vals" )
749     {
750         @options = qw(
751             keys|k=s
752             delimit|d=s
753         );
754     }
755     elsif ( $script eq "merge_records" )
756     {
757         @options = qw(
758             keys|k=s
759             merge|m=s
760         );
761     }
762     elsif ( $script eq "grab" )
763     {
764         @options = qw(
765             patterns|p=s
766             patterns_in|P=s
767             regex|r=s
768             eval|e=s
769             exact_in|E=s
770             invert|i
771             case_insensitive|c
772             keys|k=s
773             keys_only|K
774             vals_only|V
775         );
776     }
777     elsif ( $script eq "compute" )
778     {
779         @options = qw(
780             eval|e=s
781         );
782     }
783     elsif ( $script eq "add_ident" )
784     {
785         @options = qw(
786             prefix|p=s
787             key|k=s
788         );
789     }
790     elsif ( $script eq "count_records" )
791     {
792         @options = qw(
793             no_stream|x
794             data_out|o=s
795         );
796     }
797     elsif ( $script eq "random_records" )
798     {
799         @options = qw(
800             num|n=s
801         );
802     }
803     elsif ( $script eq "sort_records" )
804     {
805         @options = qw(
806             reverse|r
807             keys|k=s
808         );
809     }
810     elsif ( $script eq "count_vals" )
811     {
812         @options = qw(
813             keys|k=s
814         );
815     }
816     elsif ( $script eq "plot_histogram" )
817     {
818         @options = qw(
819             no_stream|x
820             data_out|o=s
821             terminal|t=s
822             title|T=s
823             xlabel|X=s
824             ylabel|Y=s
825             key|k=s
826             sort|s=s
827         );
828     }
829     elsif ( $script eq "plot_lendist" )
830     {
831         @options = qw(
832             no_stream|x
833             data_out|o=s
834             terminal|t=s
835             title|T=s
836             xlabel|X=s
837             ylabel|Y=s
838             key|k=s
839         );
840     }
841     elsif ( $script eq "plot_chrdist" )
842     {
843         @options = qw(
844             no_stream|x
845             data_out|o=s
846             terminal|t=s
847             title|T=s
848             xlabel|X=s
849             ylabel|Y=s
850         );
851     }
852     elsif ( $script eq "plot_karyogram" )
853     {
854         @options = qw(
855             no_stream|x
856             data_out|o=s
857             genome|g=s
858             feat_color|f=s
859         );
860     }
861     elsif ( $script eq "plot_matches" )
862     {
863         @options = qw(
864             no_stream|x
865             data_out|o=s
866             terminal|t=s
867             title|T=s
868             xlabel|X=s
869             ylabel|Y=s
870             direction|d=s
871         );
872     }
873     elsif ( $script eq "length_vals" )
874     {
875         @options = qw(
876             keys|k=s
877         );
878     }
879     elsif ( $script eq "sum_vals" )
880     {
881         @options = qw(
882             no_stream|x
883             data_out|o=s
884             keys|k=s
885         );
886     }
887     elsif ( $script eq "mean_vals" )
888     {
889         @options = qw(
890             no_stream|x
891             data_out|o=s
892             keys|k=s
893         );
894     }
895     elsif ( $script eq "median_vals" )
896     {
897         @options = qw(
898             no_stream|x
899             data_out|o=s
900             keys|k=s
901         );
902     }
903     elsif ( $script eq "max_vals" )
904     {
905         @options = qw(
906             no_stream|x
907             data_out|o=s
908             keys|k=s
909         );
910     }
911     elsif ( $script eq "min_vals" )
912     {
913         @options = qw(
914             no_stream|x
915             data_out|o=s
916             keys|k=s
917         );
918     }
919     elsif ( $script eq "upload_to_ucsc" )
920     {
921         @options = qw(
922             no_stream|x
923             database|d=s
924             table|t=s
925             short_label|s=s
926             long_label|l=s
927             group|g=s
928             priority|p=f
929             use_score|u
930             visibility|v=s
931             wiggle|w
932             score|S
933             log10|L
934             color|c=s
935             chunk_size|C=s
936         );
937     }
938
939     push @options, qw(
940         stream_in|I=s
941         stream_out|O=s
942         verbose
943         help|?
944     );
945
946 #    print STDERR Dumper( \@options );
947     
948     GetOptions(
949         \%options,
950         @options,
951     );
952
953 #    print STDERR Dumper( \%options );
954
955     if ( -t STDIN && scalar( keys %options ) == 0 or $options{ "help" } ) {
956         return wantarray ? %options : \%options;
957     }
958
959     $options{ "cols" }      = [ split ",", $options{ "cols" } ]      if defined $options{ "cols" };
960     $options{ "keys" }      = [ split ",", $options{ "keys" } ]      if defined $options{ "keys" };
961     $options{ "no_keys" }   = [ split ",", $options{ "no_keys" } ]   if defined $options{ "no_keys" };
962     $options{ "save_keys" } = [ split ",", $options{ "save_keys" } ] if defined $options{ "save_keys" };
963     $options{ "quals" }     = [ split ",", $options{ "quals" } ]     if defined $options{ "quals" };
964     $options{ "feats" }     = [ split ",", $options{ "feats" } ]     if defined $options{ "feats" };
965     $options{ "frames" }    = [ split ",", $options{ "frames" } ]    if defined $options{ "frames" };
966     $options{ "formats" }   = [ split ",", $options{ "formats" } ]   if defined $options{ "formats" };
967     
968     # ---- check arguments ----
969
970     if ( $options{ 'data_in' } )
971     {
972         $options{ "files" } = getopt_files( $options{ 'data_in' } );
973
974         Maasha::Common::error( qq(Argument to --data_in must be a valid file or fileglob expression) ) if scalar @{ $options{ "files" } } == 0;
975     }
976
977     map { Maasha::Common::error( qq(Argument to --cols must be a whole numbers - not "$_") ) if $_ !~ /^\d+$/ } @{ $options{ "cols" } } if $options{ "cols" };
978
979 #    print STDERR Dumper( \%options );
980
981     foreach $opt ( keys %options )
982     {
983         if ( $opt =~ /stream_in|pattern_in|exact_in/ and not -f $options{ $opt } )
984         {
985             Maasha::Common::error( qq(Argument to --$opt must be a valid file or fileglob expression - not "$options{ $opt }") );
986         }
987         elsif ( $opt =~ /beg|end|word_size|wrap|chunk_size|tile_size|len|prefix_length|num|skip|cpus|window_size|step_size/ and $options{ $opt } !~ /^\d+$/ )
988         {
989             Maasha::Common::error( qq(Argument to --$opt must be a whole number - not "$options{ $opt }") );
990         }
991         elsif ( $opt =~ /max_hits|max_hits|max_misses|dist|edit_dist|flank|gap|hamming_dist|priority/ and $options{ $opt } !~ /^-?\d+$/ )
992         {
993             Maasha::Common::error( qq(Argument to --$opt must be an integer - not "$options{ $opt }") );
994         }
995         elsif ( $opt =~ /identity|threshold/ and $options{ $opt } !~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/ )
996         {
997             Maasha::Common::error( qq(Argument to --$opt must be a decimal number - not "$options{ $opt }") );
998         }
999         elsif ( $opt =~ /e_val/ and $options{ $opt } !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ )
1000         {
1001             Maasha::Common::error( qq(Argument to --$opt must be a float - not "$options{ $opt }") );
1002         }
1003         elsif ( $opt =~ /strand/ and $options{ $opt } !~ /^(\+|-)$/ )
1004         {
1005             Maasha::Common::error( qq(Argument to --$opt must be "+" or "-" - not "$options{ $opt }") );
1006         }
1007         elsif ( $opt eq "genome" and $script ne "format_genome" )
1008         {
1009             @genomes = Maasha::Common::ls_dirs( "$ENV{ 'BP_DATA' }/genomes" );
1010             map { $_ =~ s/.*\/(.+)$/$1/ } @genomes;
1011
1012             if ( not grep { $_ =~ /^$options{ $opt }$/ } @genomes ) {
1013                 Maasha::Common::error( qq(Genome $options{ $opt } not found in "$ENV{ 'BP_DATA' }/genomes/") );
1014             }
1015         }
1016         elsif ( $opt eq "terminal" and not $options{ $opt } =~ /^(svg|post|dumb)/ )
1017         {
1018             Maasha::Common::error( qq(Bad --$opt argument "$options{ $opt }") );
1019         }
1020         elsif ( $opt eq "table" and $options{ $opt } =~ /-\./ )
1021         {
1022             Maasha::Common::error( qq(Character '$options{ $opt }' is not allowed in table names) );
1023         }
1024         elsif ( $opt eq "merge" and $options{ $opt } !~ /^(AandB|AorB|BorA|AnotB|BnotA)$/ )
1025         {
1026             Maasha::Common::error( qq(Argument to --$opt must be AandB, AorB, BorA, AnotB, or BnotA - not "$options{ $opt }") );
1027         }
1028     }
1029
1030     Maasha::Common::error( qq(no --database specified) )                if $script eq "create_blast_db"     and not $options{ "database" };
1031     Maasha::Common::error( qq(no --index_name specified) )              if $script =~ /create_vmatch_index/ and not $options{ "index_name" };
1032     Maasha::Common::error( qq(no --database or --genome specified) )    if $script eq "blast_seq" and not $options{ "genome" } and not $options{ "database" };
1033     Maasha::Common::error( qq(both --database and --genome specified) ) if $script eq "blast_seq" and $options{ "genome" } and $options{ "database" };
1034     Maasha::Common::error( qq(no --index_name or --genome specified) )  if $script eq "vmatch_seq" and not $options{ "genome" } and not $options{ "index_name" };
1035     Maasha::Common::error( qq(both --index and --genome specified) )    if $script eq "vmatch_seq" and $options{ "genome" } and $options{ "index_name" };
1036     Maasha::Common::error( qq(no --in_file or --genome specified) )     if $script eq "soap_seq" and not $options{ "genome" } and not $options{ "in_file" };
1037     Maasha::Common::error( qq(both --in_file and --genome specified) )  if $script eq "soap_seq" and $options{ "genome" } and $options{ "in_file" };
1038     Maasha::Common::error( qq(no --genome specified) )                  if $script =~ /format_genome|get_genome_seq|get_genome_align|get_genome_phastcons|blat_seq|plot_phastcons_profiles|plot_karyogram/ and not $options{ "genome" };
1039     Maasha::Common::error( qq(no --key specified) )                     if $script =~ /plot_lendist|plot_histogram/ and not $options{ "key" };
1040     Maasha::Common::error( qq(no --keys speficied) )                    if $script =~ /sort_records|count_vals|sum_vals|mean_vals|median_vals|length_vals/ and not $options{ "keys" };
1041
1042     if ( $script eq "upload_to_ucsc" )
1043     {
1044         Maasha::Common::error( qq(no --database specified) ) if not $options{ "database" };
1045         Maasha::Common::error( qq(no --table specified) )    if not $options{ "table" };
1046     }
1047
1048     return wantarray ? %options : \%options;
1049 }
1050
1051
1052 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SCRIPTS  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1053
1054
1055 sub script_print_usage
1056 {
1057     # Martin A. Hansen, January 2008.
1058
1059     # Retrieves usage information from file and
1060     # prints this nicely formatted.
1061
1062     my ( $in,        # handle to in stream
1063          $out,       # handle to out stream
1064          $options,   # options hash
1065        ) = @_;
1066
1067     # Returns nothing.
1068
1069     my ( $file, $wiki, $lines );
1070
1071     if ( $options->{ 'data_in' } ) {
1072         $file = $options->{ 'data_in' };
1073     } else {
1074         $file = join "", $ENV{ 'BP_DIR' }, "/bp_usage/", $options->{ 'SCRIPT' }, ".wiki";
1075     }
1076
1077     $wiki = Maasha::Gwiki::gwiki_read( $file );
1078
1079     if ( not $options->{ "help" } ) {
1080         @{ $wiki } = grep { $_->[ 0 ]->{ 'SECTION' } =~ /Biopiece|Synopsis|Usage|Options|Help/ } @{ $wiki };
1081     }
1082
1083     $lines = Maasha::Gwiki::gwiki2ascii( $wiki );
1084
1085     print STDERR "$_\n" foreach @{ $lines };
1086
1087     exit;
1088 }
1089
1090
1091 sub script_list_biopieces
1092 {
1093     # Martin A. Hansen, January 2008.
1094
1095     # Prints the synopsis from the usage for each of the biopieces.
1096
1097     my ( $in,        # handle to in stream
1098          $out,       # handle to out stream
1099          $options,   # options hash
1100        ) = @_;
1101
1102     # Returns nothing.
1103
1104     my ( @files, $file, $wiki, $program, $synopsis );
1105
1106     @files = Maasha::Common::ls_files( "$ENV{ 'BP_DIR' }/bp_usage" );
1107
1108     foreach $file ( sort @files )
1109     {
1110         if ( $file =~ /\/([a-z0-9_]+)\.wiki$/ )
1111         {
1112             $program = $1;
1113
1114             $wiki = Maasha::Gwiki::gwiki_read( $file );
1115
1116             @{ $wiki } = grep { $_->[ 0 ]->{ 'SECTION' } =~ /Synopsis/ }  @{ $wiki };
1117             @{ $wiki } = grep { $_->[ 0 ]->{ 'FORMAT' }  =~ /paragraph/ } @{ $wiki };
1118
1119             $synopsis = $wiki->[ 0 ]->[ 0 ]->{ 'TEXT' };
1120             $synopsis =~ s/!(\w)/$1/g;
1121
1122             printf( "%-30s%s\n", $program, $synopsis );
1123         }
1124     }
1125
1126     exit;
1127 }
1128
1129
1130 sub script_list_genomes
1131 {
1132     # Martin A. Hansen, January 2008.
1133
1134     # Prints the synopsis from the usage for each of the biopieces.
1135
1136     my ( $in,        # handle to in stream
1137          $out,       # handle to out stream
1138          $options,   # options hash
1139        ) = @_;
1140
1141     # Returns nothing.
1142
1143     my ( @genomes, $genome, @formats, $format, %hash, %found, @row );
1144
1145     @genomes = Maasha::Common::ls_dirs( "$ENV{ 'BP_DATA' }/genomes" );
1146
1147     foreach $genome ( @genomes )
1148     {
1149         next if $genome =~ /\.$/;
1150
1151         @formats = Maasha::Common::ls_dirs( $genome );
1152
1153         foreach $format ( @formats )
1154         {
1155             if ( $format =~ /\/([^\/]+)\/(\w+)$/ )
1156             {
1157                 $hash{ $1 }{ $2 } = 1;
1158
1159                 $found{ $2 } = 1;
1160             }
1161         }
1162     }
1163
1164     @row = "Genome";
1165
1166     map { push @row, $_ } sort keys %found;
1167
1168     print join( "\t", @row ), "\n";
1169
1170     foreach $genome ( sort keys %hash )
1171     {
1172         @row = $genome;
1173
1174         foreach $format ( sort keys %found )
1175         {
1176             if ( exists $hash{ $genome }{ $format } ) {
1177                 push @row, "yes";
1178             } else {
1179                 push @row, "no";
1180             }
1181         }
1182
1183         print join( "\t", @row ), "\n";
1184     }
1185 }
1186
1187
1188 sub script_read_fasta
1189 {
1190     # Martin A. Hansen, August 2007.
1191
1192     # Read sequences from FASTA file.
1193
1194     my ( $in,        # handle to in stream
1195          $out,       # handle to out stream
1196          $options,   # options hash
1197        ) = @_;
1198
1199     # Returns nothing.
1200
1201     my ( $record, $file, $data_in, $entry, $num );
1202
1203     while ( $record = get_record( $in ) ) {
1204         put_record( $record, $out );
1205     }
1206
1207     $num = 1;
1208
1209     foreach $file ( @{ $options->{ "files" } } )
1210     {
1211         $data_in = Maasha::Common::read_open( $file );
1212
1213         while ( $entry = Maasha::Fasta::get_entry( $data_in ) ) 
1214         {
1215             if ( defined $entry->[ SEQ_NAME ] and $entry->[ SEQ ] )
1216             {
1217                 $record = {
1218                     SEQ_NAME => $entry->[ SEQ_NAME ],
1219                     SEQ      => $entry->[ SEQ ],
1220                     SEQ_LEN  => length $entry->[ SEQ ],
1221                 };
1222
1223                 put_record( $record, $out );
1224             }
1225
1226             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1227
1228             $num++;
1229         }
1230
1231         close $data_in;
1232     }
1233
1234     NUM:
1235
1236     close $data_in if $data_in;
1237 }
1238
1239
1240 sub script_read_tab
1241 {
1242     # Martin A. Hansen, August 2007.
1243
1244     # Read table or table columns from stream or file.
1245
1246     my ( $in,        # handle to in stream
1247          $out,       # handle to out stream
1248          $options,   # options hash
1249        ) = @_;
1250
1251     # Returns nothing.
1252
1253     my ( $file, $line, @fields, @fields2, $i, $record, $data_in, $skip, $num );
1254
1255     $options->{ 'delimit' } ||= '\s+';
1256
1257     while ( $record = get_record( $in ) ) {
1258         put_record( $record, $out );
1259     }
1260
1261     $skip = $options->{ 'skip' } ||= 0;
1262     $num = 1;
1263
1264     foreach $file ( @{ $options->{ "files" } } )
1265     {
1266         $data_in = Maasha::Common::read_open( $file );
1267
1268         while ( $line = <$data_in> ) 
1269         {
1270             if ( $skip )
1271             {
1272                 $skip--;
1273                 next;
1274             }
1275
1276             next if $line =~ /^#|^$/;
1277
1278             chomp $line;
1279
1280             undef $record;
1281             undef @fields2;
1282
1283             @fields = split /$options->{'delimit'}/, $line;
1284
1285             if ( $options->{ "cols" } ) {
1286                 map { push @fields2, $fields[ $_ ] } @{ $options->{ "cols" } };
1287             } else {
1288                 @fields2 = @fields;
1289             }
1290
1291             for ( $i = 0; $i < @fields2; $i++ )
1292             {
1293                 if ( $options->{ "keys" }->[ $i ] ) {
1294                     $record->{ $options->{ "keys" }->[ $i ] } = $fields2[ $i ];
1295                 } else {
1296                     $record->{ "V" . $i } = $fields2[ $i ];
1297                 }
1298             }
1299
1300             put_record( $record, $out );
1301
1302             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1303
1304             $num++;
1305         }
1306
1307         close $data_in;
1308     }
1309
1310     NUM:
1311
1312     close $data_in if $data_in;
1313 }
1314
1315
1316 sub script_read_psl
1317 {
1318     # Martin A. Hansen, August 2007.
1319
1320     # Read psl table from stream or file.
1321
1322     my ( $in,        # handle to in stream
1323          $out,       # handle to out stream
1324          $options,   # options hash
1325        ) = @_;
1326
1327     # Returns nothing.
1328
1329     my ( $record, @files, $file, $entries, $entry, $num );
1330
1331     while ( $record = get_record( $in ) ) {
1332         put_record( $record, $out );
1333     }
1334
1335     $num = 1;
1336
1337     foreach $file ( @{ $options->{ "files" } } )
1338     {
1339         $entries = Maasha::UCSC::psl_get_entries( $file );
1340
1341         foreach $entry ( @{ $entries } )
1342         {
1343             put_record( $entry, $out );
1344
1345             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1346
1347             $num++;
1348         }
1349     }
1350
1351     NUM:
1352 }
1353
1354
1355 sub script_read_bed
1356 {
1357     # Martin A. Hansen, August 2007.
1358
1359     # Read bed table from stream or file.
1360
1361     my ( $in,        # handle to in stream
1362          $out,       # handle to out stream
1363          $options,   # options hash
1364        ) = @_;
1365
1366     # Returns nothing.
1367
1368     my ( $file, $record, $entry, $data_in, $num );
1369
1370     while ( $record = get_record( $in ) ) {
1371         put_record( $record, $out );
1372     }
1373
1374     $num = 1;
1375
1376     foreach $file ( @{ $options->{ "files" } } )
1377     {
1378         $data_in = Maasha::Common::read_open( $file );
1379
1380         while ( $entry = Maasha::UCSC::bed_get_entry( $data_in ) )
1381         {
1382             put_record( $entry, $out );
1383
1384             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1385
1386             $num++;
1387         }
1388
1389         close $data_in;
1390     }
1391
1392     NUM:
1393
1394     close $data_in if $data_in;
1395 }
1396
1397
1398 sub script_read_fixedstep
1399 {
1400     # Martin A. Hansen, Juli 2008.
1401
1402     # Read fixedStep wiggle format from stream or file.
1403
1404     my ( $in,        # handle to in stream
1405          $out,       # handle to out stream
1406          $options,   # options hash
1407        ) = @_;
1408
1409     # Returns nothing.
1410
1411     my ( $file, $record, $entry, $head, $chr, $chr_beg, $step, $data_in, $num );
1412
1413     while ( $record = get_record( $in ) ) {
1414         put_record( $record, $out );
1415     }
1416
1417     $num = 1;
1418
1419     foreach $file ( @{ $options->{ "files" } } )
1420     {
1421         $data_in = Maasha::Common::read_open( $file );
1422
1423         while ( $entry = Maasha::UCSC::fixedstep_get_entry( $data_in ) )
1424         {
1425             $head = shift @{ $entry };
1426
1427             if ( $head =~ /^chrom=([^ ]+) start=(\d+) step=(\d+)$/ )
1428             {
1429                 $record->{ "CHR" }     = $1;
1430                 $record->{ "CHR_BEG" } = $2;
1431                 $record->{ "STEP" }    = $3;
1432                 $record->{ "VALS" }    = join ",", @{ $entry };
1433             }
1434
1435             put_record( $record, $out );
1436
1437             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1438
1439             $num++;
1440         }
1441
1442         close $data_in;
1443     }
1444
1445     NUM:
1446
1447     close $data_in if $data_in;
1448 }
1449
1450
1451 sub script_read_blast_tab
1452 {
1453     # Martin A. Hansen, September 2007.
1454
1455     # Read tabular BLAST output from NCBI blast run with -m8 or -m9.
1456
1457     my ( $in,        # handle to in stream
1458          $out,       # handle to out stream
1459          $options,   # options hash
1460        ) = @_;
1461
1462     # Returns nothing.
1463
1464     my ( $file, $line, @fields, $strand, $record, $data_in, $num );
1465
1466     while ( $record = get_record( $in ) ) {
1467         put_record( $record, $out );
1468     }
1469
1470     $num = 1;
1471
1472     foreach $file ( @{ $options->{ "files" } } )
1473     {
1474         $data_in = Maasha::Common::read_open( $file );
1475
1476         while ( $line = <$data_in> )
1477         {
1478             chomp $line;
1479
1480             next if $line =~ /^#/;
1481
1482             @fields = split /\t/, $line;
1483
1484             $record->{ "REC_TYPE" }   = "BLAST";
1485             $record->{ "Q_ID" }       = $fields[ 0 ];
1486             $record->{ "S_ID" }       = $fields[ 1 ];
1487             $record->{ "IDENT" }      = $fields[ 2 ];
1488             $record->{ "ALIGN_LEN" }  = $fields[ 3 ];
1489             $record->{ "MISMATCHES" } = $fields[ 4 ];
1490             $record->{ "GAPS" }       = $fields[ 5 ];
1491             $record->{ "Q_BEG" }      = $fields[ 6 ] - 1; # BLAST is 1-based
1492             $record->{ "Q_END" }      = $fields[ 7 ] - 1; # BLAST is 1-based
1493             $record->{ "S_BEG" }      = $fields[ 8 ] - 1; # BLAST is 1-based
1494             $record->{ "S_END" }      = $fields[ 9 ] - 1; # BLAST is 1-based
1495             $record->{ "E_VAL" }      = $fields[ 10 ];
1496             $record->{ "BIT_SCORE" }  = $fields[ 11 ];
1497
1498             if ( $record->{ "S_BEG" } > $record->{ "S_END" } )
1499             {
1500                 $record->{ "STRAND" } = '-';
1501
1502                 ( $record->{ "S_BEG" }, $record->{ "S_END" } ) = ( $record->{ "S_END" }, $record->{ "S_BEG" } );
1503             }
1504             else
1505             {
1506                 $record->{ "STRAND" } = '+';
1507             }
1508
1509             put_record( $record, $out );
1510
1511             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1512
1513             $num++;
1514         }
1515
1516         close $data_in;
1517     }
1518
1519     NUM:
1520
1521     close $data_in if $data_in;
1522 }
1523
1524
1525 sub script_read_embl
1526 {
1527     # Martin A. Hansen, August 2007.
1528
1529     # Read EMBL format.
1530
1531     my ( $in,        # handle to in stream
1532          $out,       # handle to out stream
1533          $options,   # options hash
1534        ) = @_;
1535
1536     # Returns nothing.
1537
1538     my ( %options2, $file, $data_in, $num, $entry, $record );
1539
1540     map { $options2{ "keys" }{ $_ } = 1 }  @{ $options->{ "keys" } };
1541     map { $options2{ "feats" }{ $_ } = 1 } @{ $options->{ "feats" } };
1542     map { $options2{ "quals" }{ $_ } = 1 } @{ $options->{ "quals" } };
1543
1544     while ( $record = get_record( $in ) ) {
1545         put_record( $record, $out );
1546     }
1547
1548     $num = 1;
1549
1550     foreach $file ( @{ $options->{ "files" } } )
1551     {
1552         $data_in = Maasha::Common::read_open( $file );
1553
1554         while ( $entry = Maasha::EMBL::get_embl_entry( $data_in ) ) 
1555         {
1556             $record = Maasha::EMBL::parse_embl_entry( $entry, \%options2 );
1557
1558             my ( $feat, $feat2, $qual, $qual_val, $record_copy );
1559
1560             $record_copy = dclone $record;
1561
1562             delete $record_copy->{ "FT" };
1563
1564             put_record( $record_copy, $out );
1565
1566             delete $record_copy->{ "SEQ" };
1567
1568             foreach $feat ( keys %{ $record->{ "FT" } } )
1569             {
1570                 $record_copy->{ "FEAT_TYPE" } = $feat;
1571
1572                 foreach $feat2 ( @{ $record->{ "FT" }->{ $feat } } )
1573                 {
1574                     foreach $qual ( keys %{ $feat2 } )
1575                     {
1576                         $qual_val = join "; ", @{ $feat2->{ $qual } };
1577
1578                         $qual =~ s/^_//;
1579                         $qual = uc $qual;
1580
1581                         $record_copy->{ $qual } = $qual_val;
1582                     }
1583
1584                     put_record( $record_copy, $out );
1585                 }
1586             }
1587
1588             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1589
1590             $num++;
1591         }
1592
1593         close $data_in;
1594     }
1595
1596     NUM:
1597
1598     close $data_in if $data_in;
1599 }
1600
1601
1602 sub script_read_stockholm
1603 {
1604     # Martin A. Hansen, August 2007.
1605
1606     # Read Stockholm format.
1607
1608     my ( $in,        # handle to in stream
1609          $out,       # handle to out stream
1610          $options,   # options hash
1611        ) = @_;
1612
1613     # Returns nothing.
1614
1615     my ( $data_in, $file, $num, $entry, $record, $record_anno, $record_align, $key, $seq );
1616
1617     while ( $record = get_record( $in ) ) {
1618         put_record( $record, $out );
1619     }
1620
1621     $num = 1;
1622
1623     foreach $file ( @{ $options->{ "files" } } )
1624     {
1625         $data_in = Maasha::Common::read_open( $file );
1626
1627         while ( $entry = Maasha::Stockholm::get_stockholm_entry( $data_in ) ) 
1628         {
1629             $record = Maasha::Stockholm::parse_stockholm_entry( $entry );
1630
1631             undef $record_anno;
1632
1633             foreach $key ( keys %{ $record->{ "GF" } } ) {
1634                 $record_anno->{ $key } = $record->{ "GF" }->{ $key };
1635             }
1636
1637             $record_anno->{ "ALIGN" } = $num;
1638
1639             put_record( $record_anno, $out );
1640
1641             foreach $seq ( @{ $record->{ "ALIGN" } } )
1642             {
1643                 undef $record_align;
1644             
1645                 $record_align = {
1646                     SEQ_NAME  => $seq->[ 0 ],
1647                     SEQ       => $seq->[ 1 ],
1648                 };
1649             
1650                 put_record( $record_align, $out );
1651             }
1652
1653             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1654
1655             $num++;
1656         }
1657
1658         close $data_in;
1659     }
1660
1661     NUM:
1662
1663     close $data_in if $data_in;
1664 }
1665
1666
1667 sub script_read_phastcons
1668 {
1669     # Martin A. Hansen, December 2007.
1670
1671     # Read PhastCons format.
1672
1673     my ( $in,        # handle to in stream
1674          $out,       # handle to out stream
1675          $options,   # options hash
1676        ) = @_;
1677
1678     # Returns nothing.
1679
1680     my ( $data_in, $file, $num, $entry, @records, $record );
1681
1682     $options->{ "min" }       ||= 10;
1683     $options->{ "dist" }      ||= 25;
1684     $options->{ "threshold" } ||= 0.8;
1685     $options->{ "gap" }       ||= 5;
1686
1687     while ( $record = get_record( $in ) ) {
1688         put_record( $record, $out );
1689     }
1690
1691     $num = 1;
1692
1693     foreach $file ( @{ $options->{ "files" } } )
1694     {
1695         $data_in = Maasha::Common::read_open( $file );
1696
1697         while ( $entry = Maasha::UCSC::fixedstep_get_entry( $data_in ) ) 
1698         {
1699             @records = Maasha::UCSC::phastcons_parse_entry( $entry, $options );
1700
1701             foreach $record ( @records )
1702             {
1703                 $record->{ "REC_TYPE" } = "BED";
1704                 $record->{ "BED_LEN" }  = $record->{ "CHR_END" } - $record->{ "CHR_BEG" } + 1;
1705
1706                 put_record( $record, $out );
1707
1708                 goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1709
1710                 $num++;
1711             }
1712         }
1713
1714         close $data_in;
1715     }
1716
1717     NUM:
1718
1719     close $data_in if $data_in;
1720 }
1721
1722
1723 sub script_read_soft
1724 {
1725     # Martin A. Hansen, December 2007.
1726
1727     # Read soft format.
1728     # http://www.ncbi.nlm.nih.gov/geo/info/soft2.html
1729
1730     my ( $in,        # handle to in stream
1731          $out,       # handle to out stream
1732          $options,   # options hash
1733        ) = @_;
1734
1735     # Returns nothing.
1736
1737     my ( $data_in, $file, $num, $records, $record, $soft_index, $fh, @platforms, $plat_table, @samples, $sample, $old_end );
1738
1739     while ( $record = get_record( $in ) ) {
1740         put_record( $record, $out );
1741     }
1742
1743     $num = 1;
1744
1745     foreach $file ( @{ $options->{ "files" } } )
1746     {
1747         $soft_index = Maasha::NCBI::soft_index_file( $file );
1748
1749         $fh         = Maasha::Common::read_open( $file );
1750
1751         @platforms  = grep { $_->[ 0 ] =~ /PLATFORM/ } @{ $soft_index };
1752
1753         $plat_table = Maasha::NCBI::soft_get_platform( $fh, $platforms[ 0 ]->[ 1 ], $platforms[ -1 ]->[ 2 ] );
1754
1755         @samples    = grep { $_->[ 0 ] =~ /SAMPLE/ } @{ $soft_index };
1756
1757         $old_end    = $platforms[ -1 ]->[ 2 ];
1758
1759         foreach $sample ( @samples )
1760         {
1761             $records = Maasha::NCBI::soft_get_sample( $fh, $plat_table, $sample->[ 1 ] - $old_end - 1, $sample->[ 2 ] - $old_end - 1 );
1762
1763             foreach $record ( @{ $records } )
1764             {
1765                 put_record( $record, $out );
1766
1767                 goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1768
1769                 $num++;
1770             }
1771
1772             $old_end = $sample->[ 2 ];
1773         }
1774
1775         close $fh;
1776     }
1777
1778     NUM:
1779
1780     close $data_in if $data_in;
1781     close $fh if $fh;
1782 }
1783
1784
1785 sub script_read_gff
1786 {
1787     # Martin A. Hansen, February 2008.
1788
1789     # Read soft format.
1790     # http://www.ncbi.nlm.nih.gov/geo/info/soft2.html
1791
1792     my ( $in,        # handle to in stream
1793          $out,       # handle to out stream
1794          $options,   # options hash
1795        ) = @_;
1796
1797     # Returns nothing.
1798
1799     my ( $data_in, $file, $fh, $num, $record, $entry );
1800
1801     while ( $record = get_record( $in ) ) {
1802         put_record( $record, $out );
1803     }
1804
1805     $num = 1;
1806
1807     foreach $file ( @{ $options->{ "files" } } )
1808     {
1809         $fh = Maasha::Common::read_open( $file );
1810
1811         while ( $entry = Maasha::GFF::get_entry( $fh ) )
1812         {
1813             put_record( $entry, $out );
1814
1815             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1816
1817             $num++;
1818         }
1819
1820         close $fh;
1821     }
1822
1823     NUM:
1824
1825     close $data_in if $data_in;
1826 }
1827
1828
1829 sub script_read_2bit
1830 {
1831     # Martin A. Hansen, March 2008.
1832
1833     # Read sequences from 2bit file.
1834
1835     my ( $in,        # handle to in stream
1836          $out,       # handle to out stream
1837          $options,   # options hash
1838        ) = @_;
1839
1840     # Returns nothing.
1841
1842     my ( $record, $file, $data_in, $mask, $toc, $line, $num );
1843
1844     $mask = 1 if not $options->{ "no_mask" };
1845
1846     while ( $record = get_record( $in ) ) {
1847         put_record( $record, $out );
1848     }
1849
1850     $num = 1;
1851
1852     foreach $file ( @{ $options->{ "files" } } )
1853     {
1854         $data_in = Maasha::Common::read_open( $file );
1855
1856         $toc = Maasha::TwoBit::twobit_get_TOC( $data_in );
1857
1858         foreach $line ( @{ $toc } )
1859         {
1860             $record->{ "SEQ_NAME" } = $line->[ 0 ];
1861             $record->{ "SEQ" }      = Maasha::TwoBit::twobit_get_seq( $data_in, $line->[ 1 ], undef, undef, $mask );
1862             $record->{ "SEQ_LEN" }  = length $record->{ "SEQ" };
1863
1864             put_record( $record, $out );
1865
1866             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1867
1868             $num++;
1869         }
1870
1871         close $data_in;
1872     }
1873
1874     NUM:
1875
1876     close $data_in if $data_in;
1877 }
1878
1879
1880 sub script_read_solexa
1881 {
1882     # Martin A. Hansen, March 2008.
1883
1884     # Read Solexa sequence reads from file.
1885
1886     my ( $in,        # handle to in stream
1887          $out,       # handle to out stream
1888          $options,   # options hash
1889        ) = @_;
1890
1891     # Returns nothing.
1892
1893     my ( $record, $file, $data_in, $entry, $num, @seqs, @scores, $i );
1894
1895     $options->{ "quality" } ||= 20;
1896
1897     while ( $record = get_record( $in ) ) {
1898         put_record( $record, $out );
1899     }
1900
1901     $num = 1;
1902
1903     foreach $file ( @{ $options->{ "files" } } )
1904     {
1905         $data_in = Maasha::Common::read_open( $file );
1906
1907         while ( $entry = Maasha::Solexa::solexa_get_entry( $data_in ) )
1908         {
1909             @seqs   = split //, $entry->[ SEQ ];
1910             @scores = split /:/, $entry->[ SCORE ];
1911
1912             for ( $i = 0; $i < @scores; $i++ ) {
1913                 $seqs[ $i ] = lc $seqs[ $i ] if $scores[ $i ] < $options->{ "quality" };
1914             }
1915
1916             $record->{ "SEQ_NAME" }     = $entry->[ SEQ_NAME ];
1917             $record->{ "SEQ" }          = join "", @seqs;
1918             $record->{ "SEQ_LEN" }      = scalar @seqs;
1919             $record->{ "SCORE_MEAN" }   = sprintf ( "%.2f", Maasha::Calc::mean( \@scores ) );
1920
1921             put_record( $record, $out );
1922
1923             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1924
1925             $num++;
1926         }
1927
1928         close $data_in;
1929     }
1930
1931     NUM:
1932
1933     close $data_in if $data_in;
1934 }
1935
1936
1937 sub script_read_solid
1938 {
1939     # Martin A. Hansen, April 2008.
1940
1941     # Read Solid sequence from file.
1942
1943     my ( $in,        # handle to in stream
1944          $out,       # handle to out stream
1945          $options,   # options hash
1946        ) = @_;
1947
1948     # Returns nothing.
1949
1950     my ( $record, $file, $data_in, $line, $num, $seq_name, $seq_cs, $seq_qual, @scores, @seqs, $i );
1951
1952     $options->{ "quality" } ||= 15;
1953
1954     while ( $record = get_record( $in ) ) {
1955         put_record( $record, $out );
1956     }
1957
1958     $num = 1;
1959
1960     foreach $file ( @{ $options->{ "files" } } )
1961     {
1962         $data_in = Maasha::Common::read_open( $file );
1963
1964         while ( $line = <$data_in> )
1965         {
1966             chomp $line;
1967
1968             ( $seq_name, $seq_cs, $seq_qual ) = split /\t/, $line;
1969
1970             @scores = split /,/, $seq_qual;
1971             @seqs   = split //, Maasha::Solid::color_space2seq( $seq_cs );
1972
1973             for ( $i = 0; $i < @seqs; $i++ ) {
1974                 $seqs[ $i ] = lc $seqs[ $i ] if $scores[ $i ] < $options->{ "quality" };
1975             }
1976
1977             $record = {
1978                 SEQ_NAME   => $seq_name,
1979                 SEQ_CS     => $seq_cs,
1980                 SEQ_QUAL   => $seq_qual,
1981                 SEQ_LEN    => length $seq_cs,
1982                 SEQ        => join( "", @seqs ),
1983                 SCORE_MEAN => sprintf( "%.2f", Maasha::Calc::mean( \@scores ) ),
1984             };
1985
1986             put_record( $record, $out );
1987
1988             goto NUM if $options->{ "num" } and $num == $options->{ "num" };
1989
1990             $num++;
1991         }
1992
1993         close $data_in;
1994     }
1995
1996     NUM:
1997
1998     close $data_in if $data_in;
1999 }
2000
2001
2002 sub script_read_mysql
2003 {
2004     # Martin A. Hansen, May 2008.
2005
2006     # Read a MySQL query into stream.
2007
2008     my ( $in,        # handle to in stream
2009          $out,       # handle to out stream
2010          $options,   # options hash
2011        ) = @_;
2012
2013     # Returns nothing.
2014
2015     my ( $record, $dbh, $results );
2016
2017     $options->{ "user" }     ||= Maasha::UCSC::ucsc_get_user();
2018     $options->{ "password" } ||= Maasha::UCSC::ucsc_get_password();
2019
2020     while ( $record = get_record( $in ) ) {
2021         put_record( $record, $out );
2022     }
2023
2024     $dbh = Maasha::SQL::connect( $options->{ "database" }, $options->{ "user" }, $options->{ "password" } );
2025
2026     $results = Maasha::SQL::query_hashref_list( $dbh, $options->{ "query" } );
2027
2028     Maasha::SQL::disconnect( $dbh );
2029
2030     map { put_record( $_ ) } @{ $results };
2031 }
2032
2033
2034 sub script_format_genome
2035 {
2036     # Martin A. Hansen, Juli 2008.
2037
2038     # Format a genome to speficed formats.
2039
2040     my ( $in,        # handle to in stream
2041          $out,       # handle to out stream
2042          $options,   # options hash
2043        ) = @_;
2044
2045     # Returns nothing.
2046
2047     my ( $dir, $genome, $fasta_dir, $phastcons_dir, $vals, $fh_out, $record, $format, $index, $entry );
2048
2049     $dir    = $options->{ 'dir' } || $ENV{ 'BP_DATA' };
2050     $genome = $options->{ 'genome' };
2051
2052     Maasha::Common::error( "Directory: $dir does not exist" ) if not -d $dir;
2053     Maasha::Common::dir_create_if_not_exists( "$dir/genomes" );
2054     Maasha::Common::dir_create_if_not_exists( "$dir/genomes/$genome" );
2055
2056     if ( grep { $_ =~ /fasta|blast|vmatch/i } @{ $options->{ "formats" } } )
2057     {
2058         if ( -f "$dir/genomes/$genome/fasta/$genome.fna" )
2059         {
2060             $fasta_dir = "$dir/genomes/$genome/fasta";
2061         }
2062         else
2063         {
2064             Maasha::Common::dir_create_if_not_exists( "$dir/genomes/$genome/fasta" );
2065
2066             $fasta_dir = "$dir/genomes/$genome/fasta";
2067
2068             $fh_out = Maasha::Common::write_open( "$fasta_dir/$genome.fna" );
2069         }
2070     }
2071     elsif ( grep { $_ =~ /phastcons/i } @{ $options->{ "formats" } } )
2072     {
2073         Maasha::Common::dir_create_if_not_exists( "$dir/genomes/$genome/phastcons" );
2074     
2075         $phastcons_dir = "$dir/genomes/$genome/phastcons";
2076
2077         $fh_out = Maasha::Common::write_open( "$phastcons_dir/$genome.pp" );
2078     }
2079
2080     while ( $record = get_record( $in ) ) 
2081     {
2082         if ( $fh_out and $entry = record2fasta( $record ) )
2083         {
2084             Maasha::Fasta::put_entry( $entry, $fh_out, $options->{ "wrap" } );
2085         }
2086         elsif ( $fh_out and $record->{ "CHR" } and $record->{ "CHR_BEG" } and $record->{ "STEP" } and $record->{ "VALS" } )
2087         {
2088             print $fh_out "fixedStep chrom=$record->{ 'CHR' } start=$record->{ 'CHR_BEG' } step=$record->{ 'STEP' }\n";
2089
2090             $vals = $record->{ 'VALS' };
2091
2092             $vals =~ tr/,/\n/;
2093
2094             print $fh_out "$vals\n";
2095         }
2096
2097         put_record( $record, $out ) if not $options->{ "no_stream" };
2098     }
2099
2100     foreach $format ( @{ $options->{ 'formats' } } )
2101     {
2102         if    ( $format =~ /^fasta$/i )     { Maasha::Fasta::fasta_index( "$fasta_dir/$genome.fna", "$dir/genomes/$genome/fasta/$genome.index" ) }
2103         elsif ( $format =~ /^blast$/i )     { Maasha::NCBI::blast_index( "$genome.fna", $fasta_dir, "$dir/genomes/$genome/blast", "dna", $genome ) }
2104         elsif ( $format =~ /^blat$/i )      { print STDERR "BLAT FORMAT NOT IMPLEMENTED" }
2105         elsif ( $format =~ /^vmatch$/i )    { Maasha::Match::vmatch_index( "$genome.fna", $fasta_dir, "$dir/genomes/$genome/vmatch", $BP_TMP ) }
2106         elsif ( $format =~ /^phastcons$/i ) { Maasha::UCSC::phastcons_index( "$genome.pp", $phastcons_dir ) }
2107     }
2108
2109     close $fh_out if $fh_out;
2110 }
2111
2112
2113 sub script_length_seq
2114 {
2115     # Martin A. Hansen, August 2007.
2116
2117     # Determine the length of sequences in stream.
2118
2119     my ( $in,        # handle to in stream
2120          $out,       # handle to out stream
2121          $options,   # options hash
2122        ) = @_;
2123
2124     # Returns nothing.
2125
2126     my ( $record, $total );
2127
2128     while ( $record = get_record( $in ) ) 
2129     {
2130         if ( $record->{ "SEQ" } )
2131         {
2132             $record->{ "SEQ_LEN" } = length $record->{ "SEQ" };
2133             $total += $record->{ "SEQ_LEN" };
2134         }
2135
2136         put_record( $record, $out ) if not $options->{ "no_stream" };
2137     }
2138
2139     put_record( { TOTAL_SEQ_LEN => $total }, $out );
2140 }
2141
2142
2143 sub script_uppercase_seq
2144 {
2145     # Martin A. Hansen, August 2007.
2146
2147     # Uppercases sequences in stream.
2148
2149     my ( $in,    # handle to in stream
2150          $out,   # handle to out stream
2151        ) = @_;
2152
2153     # Returns nothing.
2154
2155     my ( $record );
2156
2157     while ( $record = get_record( $in ) ) 
2158     {
2159         $record->{ "SEQ" } = uc $record->{ "SEQ" } if $record->{ "SEQ" };
2160
2161         put_record( $record, $out );
2162     }
2163 }
2164
2165
2166 sub script_shuffle_seq
2167 {
2168     # Martin A. Hansen, December 2007.
2169
2170     # Shuffle sequences in stream.
2171
2172     my ( $in,    # handle to in stream
2173          $out,   # handle to out stream
2174        ) = @_;
2175
2176     # Returns nothing.
2177
2178     my ( $record );
2179
2180     while ( $record = get_record( $in ) ) 
2181     {
2182         $record->{ "SEQ" } = Maasha::Seq::seq_shuffle( $record->{ "SEQ" } ) if $record->{ "SEQ" };
2183
2184         put_record( $record, $out );
2185     }
2186 }
2187
2188
2189 sub script_analyze_seq
2190 {
2191     # Martin A. Hansen, August 2007.
2192
2193     # Analyze sequence composition of sequences in stream.
2194
2195     my ( $in,     # handle to in stream
2196          $out,    # handle to out stream
2197        ) = @_;
2198
2199     # Returns nothing.
2200
2201     my ( $record, $analysis );
2202
2203     while ( $record = get_record( $in ) ) 
2204     {
2205         if ( $record->{ "SEQ" } )
2206         {
2207             $analysis = Maasha::Seq::seq_analyze( $record->{ "SEQ" } );
2208
2209             map { $record->{ $_ } = $analysis->{ $_ } } keys %{ $analysis };
2210         }
2211
2212         put_record( $record, $out );
2213     }
2214 }
2215
2216
2217 sub script_analyze_tags
2218 {
2219     # Martin A. Hansen, August 2008.
2220
2221     # Analyze sequence tags in stream.
2222
2223     my ( $in,     # handle to in stream
2224          $out,    # handle to out stream
2225        ) = @_;
2226
2227     # Returns nothing.
2228
2229     my ( $record, $analysis, %len_hash, %clone_hash, $clones, $key, $tag_record );
2230
2231     while ( $record = get_record( $in ) ) 
2232     {
2233         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } )
2234         {
2235             if ( $record->{ "SEQ_NAME" } =~ /_(\d+)$/ )
2236             {
2237                 $clones = $1;
2238
2239                 $len_hash{ length( $record->{ "SEQ" } ) }++;
2240                 $clone_hash{ length( $record->{ "SEQ" } ) } += $clones;
2241             }
2242         }
2243         elsif ( $record->{ "Q_ID" } and $record->{ "BED_LEN" } )
2244         {
2245             if ( $record->{ "Q_ID" } =~ /_(\d+)$/ )
2246             {
2247                 $clones = $1;
2248
2249                 $len_hash{ $record->{ "BED_LEN" } }++;
2250                 $clone_hash{ $record->{ "BED_LEN" } } += $clones;
2251             }
2252         }
2253     }
2254
2255     foreach $key ( sort { $a <=> $b } keys %len_hash )
2256     {
2257         $tag_record->{ "TAG_LEN" }    = $key;
2258         $tag_record->{ "TAG_COUNT" }  = $len_hash{ $key };
2259         $tag_record->{ "TAG_CLONES" } = $clone_hash{ $key };
2260  
2261         put_record( $tag_record, $out );
2262     }
2263 }
2264
2265
2266 sub script_complexity_seq
2267 {
2268     # Martin A. Hansen, May 2008.
2269
2270     # Generates an index calculated as the most common di-residue over
2271     # the sequence length for all sequences in stream.
2272
2273     my ( $in,     # handle to in stream
2274          $out,    # handle to out stream
2275        ) = @_;
2276
2277     # Returns nothing.
2278
2279     my ( $record, $index );
2280
2281     while ( $record = get_record( $in ) ) 
2282     {
2283         $record->{ "SEQ_COMPLEXITY" } = sprintf( "%.2f", Maasha::Seq::seq_complexity( $record->{ "SEQ" } ) ) if $record->{ "SEQ" };
2284
2285         put_record( $record, $out );
2286     }
2287 }
2288
2289
2290 sub script_oligo_freq
2291 {
2292     # Martin A. Hansen, August 2007.
2293
2294     # Determine the length of sequences in stream.
2295
2296     my ( $in,        # handle to in stream
2297          $out,       # handle to out stream
2298          $options,   # options hash
2299        ) = @_;
2300
2301     # Returns nothing.
2302
2303     my ( $record, %oligos, @freq_table );
2304
2305     $options->{ "word_size" } ||= 7;
2306
2307     while ( $record = get_record( $in ) ) 
2308     {
2309         if ( $record->{ "SEQ" } )
2310         {
2311             map { $oligos{ $_ }++ } Maasha::Seq::seq2oligos( \$record->{ "SEQ" }, $options->{ "word_size" } );
2312
2313             if ( not $options->{ "all" } )
2314             {
2315                 @freq_table = Maasha::Seq::oligo_freq( \%oligos );
2316
2317                 map { put_record( $_, $out ) } @freq_table;
2318             
2319                 undef %oligos;
2320             }
2321         }
2322
2323         put_record( $record, $out );
2324     }
2325
2326     if ( $options->{ "all" } )
2327     {
2328         @freq_table = Maasha::Seq::oligo_freq( \%oligos );
2329
2330         map { put_record( $_, $out ) } @freq_table;
2331     }
2332 }
2333
2334
2335 sub script_create_weight_matrix
2336 {
2337     # Martin A. Hansen, August 2007.
2338
2339     # Creates a weight matrix from an alignmnet.
2340
2341     my ( $in,        # handle to in stream
2342          $out,       # handle to out stream
2343          $options,   # options hash
2344        ) = @_;
2345
2346     # Returns nothing.
2347
2348     my ( $record, $count, $i, $res, %freq_hash, %res_hash, $freq );
2349
2350     $count = 0;
2351     
2352     while ( $record = get_record( $in ) ) 
2353     {
2354         if ( $record->{ "SEQ" } )
2355         {
2356             for ( $i = 0; $i < length $record->{ "SEQ" }; $i++ )
2357             {
2358                 $res = substr $record->{ "SEQ" }, $i, 1;
2359
2360                 $freq_hash{ $i }{ $res }++;
2361                 $res_hash{ $res } = 1;
2362             }
2363
2364             $count++;
2365         }
2366         else
2367         {
2368             put_record( $record, $out );
2369         }
2370     }
2371
2372     foreach $res ( sort keys %res_hash )
2373     {
2374         undef $record;
2375
2376         $record->{ "V0" } = $res;
2377
2378         for ( $i = 0; $i < keys %freq_hash; $i++ )
2379         {
2380             $freq = $freq_hash{ $i }{ $res } || 0;
2381
2382             if ( $options->{ "percent" } ) {
2383                 $freq = sprintf( "%.0f", 100 * $freq / $count ) if $freq > 0;
2384             }
2385
2386             $record->{ "V" . ( $i + 1 ) } = $freq;
2387         }
2388
2389         put_record( $record, $out );
2390     }
2391 }
2392
2393
2394 sub script_calc_bit_scores
2395 {
2396     # Martin A. Hansen, March 2007.
2397
2398     # Calculates the bit scores for each position from an alignmnet in the stream.
2399
2400     my ( $in,        # handle to in stream
2401          $out,       # handle to out stream
2402        ) = @_;
2403
2404     # Returns nothing.
2405
2406     my ( $record, $type, $count, $i, $res, %freq_hash, $bit_max, $bit_height, $bit_diff );
2407
2408     $count = 0;
2409
2410     while ( $record = get_record( $in ) ) 
2411     {
2412         if ( $record->{ "SEQ" } )
2413         {
2414             $type = Maasha::Seq::seq_guess_type( $record->{ "SEQ" } ) if not $type;
2415
2416             for ( $i = 0; $i < length $record->{ "SEQ" }; $i++ )
2417             {
2418                 $res = substr $record->{ "SEQ" }, $i, 1;
2419
2420                 next if $res =~ /-|_|~|\./;
2421
2422                 $freq_hash{ $i }{ $res }++;
2423             }
2424
2425             $count++;
2426         }
2427         else
2428         {
2429             put_record( $record, $out );
2430         }
2431     }
2432
2433     undef $record;
2434
2435     if ( $type eq "protein" ) {
2436         $bit_max = 4;
2437     } else {
2438         $bit_max = 2;
2439     }
2440
2441     for ( $i = 0; $i < keys %freq_hash; $i++ )
2442     {
2443         $bit_height = Maasha::Seq::seqlogo_calc_bit_height( $freq_hash{ $i }, $count );
2444
2445         $bit_diff = $bit_max - $bit_height;
2446
2447         $record->{ "V" . ( $i ) } = sprintf( "%.2f", $bit_diff );
2448     }
2449
2450     put_record( $record, $out );
2451 }
2452
2453
2454 sub script_reverse_seq
2455 {
2456     # Martin A. Hansen, August 2007.
2457
2458     # Reverse sequence in record.
2459
2460     my ( $in,    # handle to in stream
2461          $out,   # handle to out stream
2462        ) = @_;
2463
2464     # Returns nothing.
2465
2466     my ( $record );
2467
2468     while ( $record = get_record( $in ) ) 
2469     {
2470         if ( $record->{ "SEQ" } ) {
2471             $record->{ "SEQ" } = reverse $record->{ "SEQ" };
2472         }
2473
2474         put_record( $record, $out );
2475     }
2476 }
2477
2478
2479 sub script_complement_seq
2480 {
2481     # Martin A. Hansen, August 2007.
2482
2483     # Complement sequence in record.
2484
2485     my ( $in,     # handle to in stream
2486          $out,    # handle to out stream
2487        ) = @_;
2488
2489     # Returns nothing.
2490
2491     my ( $record, $type );
2492
2493     while ( $record = get_record( $in ) ) 
2494     {
2495         if ( $record->{ "SEQ" } )
2496         {
2497             if ( not $type ) {
2498                 $type = Maasha::Seq::seq_guess_type( $record->{ "SEQ" } );
2499             }
2500             
2501             if ( $type eq "rna" ) {
2502                 Maasha::Seq::rna_comp( \$record->{ "SEQ" } );
2503             } elsif ( $type eq "dna" ) {
2504                 Maasha::Seq::dna_comp( \$record->{ "SEQ" } );
2505             }
2506         }
2507
2508         put_record( $record, $out );
2509     }
2510 }
2511
2512
2513 sub script_remove_indels
2514 {
2515     # Martin A. Hansen, August 2007.
2516
2517     # Remove indels from sequences in stream.
2518
2519     my ( $in,     # handle to in stream
2520          $out,    # handle to out stream
2521        ) = @_;
2522
2523     # Returns nothing.
2524
2525     my ( $record );
2526
2527     while ( $record = get_record( $in ) ) 
2528     {
2529         $record->{ 'SEQ' } =~ tr/-~.//d if $record->{ "SEQ" };
2530
2531         put_record( $record, $out );
2532     }
2533 }
2534
2535
2536 sub script_transliterate_seq
2537 {
2538     # Martin A. Hansen, August 2007.
2539
2540     # Transliterate chars from sequence in record.
2541
2542     my ( $in,        # handle to in stream
2543          $out,       # handle to out stream
2544          $options,   # options hash
2545        ) = @_;
2546
2547     # Returns nothing.
2548
2549     my ( $record, $search, $replace, $delete );
2550
2551     $search  = $options->{ "search" }  || "";
2552     $replace = $options->{ "replace" } || "";
2553     $delete  = $options->{ "delete" }  || "";
2554
2555     while ( $record = get_record( $in ) ) 
2556     {
2557         if ( $record->{ "SEQ" } )
2558         {
2559             if ( $search and $replace ) {
2560                 eval "\$record->{ 'SEQ' } =~ tr/$search/$replace/";
2561             } elsif ( $delete ) {
2562                 eval "\$record->{ 'SEQ' } =~ tr/$delete//d";
2563             }
2564         }
2565
2566         put_record( $record, $out );
2567     }
2568 }
2569
2570
2571 sub script_transliterate_vals
2572 {
2573     # Martin A. Hansen, April 2008.
2574
2575     # Transliterate chars from values in record.
2576
2577     my ( $in,        # handle to in stream
2578          $out,       # handle to out stream
2579          $options,   # options hash
2580        ) = @_;
2581
2582     # Returns nothing.
2583
2584     my ( $record, $search, $replace, $delete, $key );
2585
2586     $search  = $options->{ "search" }  || "";
2587     $replace = $options->{ "replace" } || "";
2588     $delete  = $options->{ "delete" }  || "";
2589
2590     while ( $record = get_record( $in ) ) 
2591     {
2592         foreach $key ( @{ $options->{ "keys" } } )
2593         {
2594             if ( exists $record->{ $key } )
2595             {
2596                 if ( $search and $replace ) {
2597                     eval "\$record->{ $key } =~ tr/$search/$replace/";
2598                 } elsif ( $delete ) {
2599                     eval "\$record->{ $key } =~ tr/$delete//d";
2600                 }
2601             }
2602         }
2603
2604         put_record( $record, $out );
2605     }
2606 }
2607
2608
2609 sub script_translate_seq
2610 {
2611     # Martin A. Hansen, February 2008.
2612
2613     # Translate DNA sequence into protein sequence.
2614
2615     my ( $in,        # handle to in stream
2616          $out,       # handle to out stream
2617          $options,   # options hash
2618        ) = @_;
2619
2620     # Returns nothing.
2621
2622     my ( $record, $frame, %new_record );
2623
2624     $options->{ "frames" } ||= [ 1, 2, 3, -1, -2, -3 ];
2625
2626     while ( $record = get_record( $in ) ) 
2627     {
2628         if ( $record->{ "SEQ" } )
2629         {
2630             if ( Maasha::Seq::seq_guess_type( $record->{ "SEQ" } ) eq "dna" )
2631             {
2632                 foreach $frame ( @{ $options->{ "frames" } } )
2633                 {
2634                     %new_record = %{ $record };
2635
2636                     $new_record{ "SEQ" }     = Maasha::Seq::translate( $record->{ "SEQ" }, $frame );
2637                     $new_record{ "SEQ_LEN" } = length $new_record{ "SEQ" };
2638                     $new_record{ "FRAME" }   = $frame;
2639
2640                     put_record( \%new_record, $out );
2641                 }
2642             }
2643         }
2644         else
2645         {
2646             put_record( $record, $out );
2647         }
2648     }
2649 }
2650
2651
2652 sub script_extract_seq
2653 {
2654     # Martin A. Hansen, August 2007.
2655
2656     # Extract subsequences from sequences in record.
2657
2658     my ( $in,        # handle to in stream
2659          $out,       # handle to out stream
2660          $options,   # options hash
2661        ) = @_;
2662
2663     # Returns nothing.
2664
2665     my ( $beg, $end, $len, $record );
2666
2667     if ( not defined $options->{ "beg" } or $options->{ "beg" } < 0 ) {
2668         $beg = 0;
2669     } else {
2670         $beg = $options->{ "beg" } - 1;   # correcting for start offset
2671     }
2672
2673     if ( defined $options->{ "end" } and $options->{ "end" } - 1 < $beg ) {
2674         $end = $beg - 1;
2675     } elsif ( defined $options->{ "end" } ) {
2676         $end = $options->{ "end" } - 1;   # correcting for start offset
2677     }
2678
2679     $len = $options->{ "len" };
2680
2681 #    print "beg->$beg,  end->$end,  len->$len\n";
2682
2683     while ( $record = get_record( $in ) ) 
2684     {
2685         if ( $record->{ "SEQ" } )
2686         {
2687             if ( defined $beg and defined $end )
2688             {
2689                 if ( $end - $beg + 1 > length $record->{ "SEQ" } ) {
2690                     $record->{ "SEQ" } = substr $record->{ "SEQ" }, $beg;
2691                 } else {
2692                     $record->{ "SEQ" } = substr $record->{ "SEQ" }, $beg, $end - $beg + 1;
2693                 }
2694             }
2695             elsif ( defined $beg and defined $len )
2696             {
2697                 if ( $len > length $record->{ "SEQ" } ) {
2698                     $record->{ "SEQ" } = substr $record->{ "SEQ" }, $beg;
2699                 } else {
2700                     $record->{ "SEQ" } = substr $record->{ "SEQ" }, $beg, $len;
2701                 }
2702             }
2703             elsif ( defined $beg )
2704             {
2705                 $record->{ "SEQ" } = substr $record->{ "SEQ" }, $beg;
2706             }
2707         }
2708
2709         $record->{ "SEQ_LEN" } = length $record->{ "SEQ" };
2710
2711         put_record( $record, $out );
2712     }
2713 }
2714
2715
2716 sub script_get_genome_seq
2717 {
2718     # Martin A. Hansen, December 2007.
2719
2720     # Gets a subsequence from a genome.
2721
2722     my ( $in,        # handle to in stream
2723          $out,       # handle to out stream
2724          $options,   # options hash
2725        ) = @_;
2726
2727     # Returns nothing.
2728
2729     my ( $record, $genome, $genome_file, $index_file, $index, $fh, $index_head, $index_beg, $index_len, $beg, $len, %lookup_hash, @begs, @lens, $i );
2730
2731     $options->{ "flank" } ||= 0;
2732
2733     if ( $options->{ "genome" } ) 
2734     {
2735         $genome      = $options->{ "genome" };
2736
2737         $genome_file = "$ENV{ 'BP_DATA' }/genomes/$genome/fasta/$genome.fna";
2738         $index_file  = "$ENV{ 'BP_DATA' }/genomes/$genome/fasta/$genome.index";
2739
2740         $fh          = Maasha::Common::read_open( $genome_file );
2741         $index       = Maasha::Fasta::index_retrieve( $index_file );
2742
2743         shift @{ $index }; # Get rid of the file size info
2744
2745         map { $lookup_hash{ $_->[ 0 ] } = [ $_->[ 1 ], $_->[ 2 ] ] } @{ $index };
2746
2747         if ( exists $lookup_hash{ $options->{ "chr" } } and defined $options->{ "beg" } and ( defined $options->{ "end" } or defined $options->{ "len" } ) )
2748         {
2749             ( $index_beg, $index_len ) = @{ $lookup_hash{ $options->{ "chr" } } };
2750
2751             $beg = $index_beg + $options->{ "beg" } - 1;
2752
2753             if ( $options->{ "len" } ) {
2754                 $len = $options->{ "len" };
2755             } elsif ( $options->{ "end" } ) {
2756                 $len = ( $options->{ "end" } - $options->{ "beg" } + 1 );
2757             }   
2758             
2759             $beg -= $options->{ "flank" };
2760             $len += 2 * $options->{ "flank" };
2761
2762             if ( $beg <= $index_beg )
2763             {
2764                 $len -= $index_beg - $beg;
2765                 $beg = $index_beg;
2766             }
2767
2768             $len = $index_beg + $index_len - $beg if $beg + $len > $index_beg + $index_len;
2769
2770             next if $beg > $index_beg + $index_len;
2771
2772             $record->{ "CHR" }     = $options->{ "chr" };
2773             $record->{ "CHR_BEG" } = $beg - $index_beg;
2774             $record->{ "CHR_END" } = $record->{ "CHR_BEG" } + $len - 1;
2775             
2776             $record->{ "SEQ" }     = Maasha::Common::file_read( $fh, $beg, $len );
2777             $record->{ "SEQ_LEN" } = $len;
2778
2779             put_record( $record, $out );
2780         }   
2781     }
2782
2783     while ( $record = get_record( $in ) ) 
2784     {
2785         if ( $options->{ "genome" } and not $record->{ "SEQ" } )
2786         {
2787             if ( $record->{ "REC_TYPE" } eq "BED" and exists $lookup_hash{ $record->{ "CHR" } } )
2788             {
2789                 ( $index_beg, $index_len ) = @{ $lookup_hash{ $record->{ "CHR" } } };
2790             
2791                 $beg = $record->{ "CHR_BEG" } + $index_beg;
2792                 $len = $record->{ "CHR_END" } - $record->{ "CHR_BEG" } + 1;
2793             }
2794             elsif ( $record->{ "REC_TYPE" } eq "PSL" and exists $lookup_hash{ $record->{ "S_ID" } } )
2795             {
2796                 ( $index_beg, $index_len ) = @{ $lookup_hash{ $record->{ "S_ID" } } };
2797             
2798                 $beg = $record->{ "S_BEG" } + $index_beg;
2799                 $len = $record->{ "S_END" } - $record->{ "S_BEG" } + 1;
2800             }
2801             elsif ( $record->{ "REC_TYPE" } eq "BLAST" and exists $lookup_hash{ $record->{ "S_ID" } } )
2802             {
2803                 ( $index_beg, $index_len ) = @{ $lookup_hash{ $record->{ "S_ID" } } };
2804             
2805                 $beg = $record->{ "S_BEG" } + $index_beg;
2806                 $len = $record->{ "S_END" } - $record->{ "S_BEG" } + 1;
2807             }
2808
2809             $beg -= $options->{ "flank" };
2810             $len += 2 * $options->{ "flank" };
2811
2812             if ( $beg <= $index_beg )
2813             {
2814                 $len -= $index_beg - $beg;
2815                 $beg = $index_beg;
2816             }
2817
2818             $len = $index_beg + $index_len - $beg if $beg + $len > $index_beg + $index_len;
2819
2820             next if $beg > $index_beg + $index_len;
2821
2822             $record->{ "CHR_BEG" } = $beg - $index_beg;
2823             $record->{ "CHR_END" } = $record->{ "CHR_BEG" } + $len - 1;
2824
2825             $record->{ "SEQ" } = Maasha::Common::file_read( $fh, $beg, $len );
2826
2827             if ( $record->{ "STRAND" } and $record->{ "STRAND" } eq "-" )
2828             {
2829                 Maasha::Seq::dna_comp( \$record->{ "SEQ" } );
2830                 $record->{ "SEQ" } = reverse $record->{ "SEQ" };
2831             }
2832
2833             if ( $options->{ "mask" } )
2834             {
2835                 if ( $record->{ "BLOCKCOUNT" } > 1 ) # uppercase hit block segments and lowercase the rest.
2836                 {
2837                     $record->{ "SEQ" } = lc $record->{ "SEQ" };
2838                 
2839                     @begs = split ",", $record->{ "Q_BEGS" };
2840                     @lens = split ",", $record->{ "BLOCKSIZES" };
2841
2842                     for ( $i = 0; $i < @begs; $i++ ) {
2843                         substr $record->{ "SEQ" }, $begs[ $i ], $lens[ $i ], uc substr $record->{ "SEQ" }, $begs[ $i ], $lens[ $i ];
2844                     }
2845                 }
2846             }
2847         }
2848
2849         put_record( $record, $out );
2850     }
2851
2852     close $fh if $fh;                                                                                                                                          
2853 }
2854
2855
2856 sub script_get_genome_align
2857 {
2858     # Martin A. Hansen, April 2008.
2859
2860     # Gets a subalignment from a multiple genome alignment.
2861
2862     my ( $in,        # handle to in stream
2863          $out,       # handle to out stream
2864          $options,   # options hash
2865        ) = @_;
2866
2867     # Returns nothing.
2868
2869     my ( $record, $maf_track, $align, $align_num, $beg, $end, $len, $entry );
2870
2871     $options->{ "strand" } ||= "+";
2872
2873     $align_num = 1;
2874
2875     $maf_track = Maasha::Config::maf_track( $options->{ "genome" } );
2876
2877     if ( $options->{ "chr" } and $options->{ "beg" } and ( $options->{ "end" } or $options->{ "len" } ) )
2878     {
2879         $beg = $options->{ "beg" } - 1;
2880         
2881         if ( $options->{ "end" } ) {
2882             $end = $options->{ "end" };
2883         } elsif ( $options->{ "len" } ) {
2884             $end = $beg + $options->{ "len" };
2885         }
2886
2887         $align = Maasha::UCSC::maf_extract( $BP_TMP, $options->{ "genome" }, $maf_track, $options->{ "chr" }, $beg, $end, $options->{ "strand" } );
2888
2889         foreach $entry ( @{ $align } )
2890         {
2891             $entry->{ "CHR" }     = $record->{ "CHR" };
2892             $entry->{ "CHR_BEG" } = $record->{ "CHR_BEG" };
2893             $entry->{ "CHR_END" } = $record->{ "CHR_END" };
2894             $entry->{ "STRAND" }  = $record->{ "STRAND" } || '+';
2895             $entry->{ "Q_ID" }    = $record->{ "Q_ID" };
2896             $entry->{ "SCORE" }   = $record->{ "SCORE" };
2897
2898             put_record( $entry, $out );
2899         }
2900     }
2901
2902     while ( $record = get_record( $in ) ) 
2903     {
2904         if ( $record->{ "REC_TYPE" } eq "BED" )
2905         {
2906             $align = Maasha::UCSC::maf_extract( $BP_TMP, $options->{ "genome" }, $maf_track, $record->{ "CHR" }, $record->{ "CHR_BEG" }, $record->{ "CHR_END" }, $record->{ "STRAND" } );
2907         }
2908         elsif ( $record->{ "REC_TYPE" } eq "PSL" )
2909         {
2910             $align = Maasha::UCSC::maf_extract( $BP_TMP, $options->{ "genome" }, $maf_track, $record->{ "S_ID" }, $record->{ "S_BEG" }, $record->{ "S_END" }, $record->{ "STRAND" } );
2911         }
2912         elsif ( $record->{ "REC_TYPE" } eq "BLAST" )
2913         {
2914             $align = Maasha::UCSC::maf_extract( $BP_TMP, $options->{ "genome" }, $maf_track, $record->{ "S_ID" }, $record->{ "S_BEG" }, $record->{ "S_END" }, $record->{ "STRAND" } );
2915         }
2916
2917         foreach $entry ( @{ $align } )
2918         {
2919             $entry->{ "CHR" }     = $record->{ "CHR" };
2920             $entry->{ "CHR_BEG" } = $record->{ "CHR_BEG" };
2921             $entry->{ "CHR_END" } = $record->{ "CHR_END" };
2922             $entry->{ "STRAND" }  = $record->{ "STRAND" };
2923             $entry->{ "Q_ID" }    = $record->{ "Q_ID" };
2924             $entry->{ "SCORE" }   = $record->{ "SCORE" };
2925
2926             put_record( $entry, $out );
2927         }
2928
2929         $align_num++;
2930     }
2931 }
2932
2933
2934 sub script_get_genome_phastcons
2935 {
2936     # Martin A. Hansen, February 2008.
2937
2938     # Get phastcons scores from genome intervals.
2939
2940     my ( $in,        # handle to in stream
2941          $out,       # handle to out stream
2942          $options,   # options hash
2943        ) = @_;
2944
2945     # Returns nothing.
2946
2947     my ( $phastcons_file, $phastcons_index, $index, $fh_phastcons, $scores, $record );
2948
2949     $options->{ "flank" } ||= 0;
2950
2951     $phastcons_file  = Maasha::Config::genome_phastcons( $options->{ "genome" } );
2952     $phastcons_index = Maasha::Config::genome_phastcons_index( $options->{ "genome" } );
2953
2954     $index           = Maasha::UCSC::phastcons_index_retrieve( $phastcons_index );
2955     $fh_phastcons    = Maasha::Common::read_open( $phastcons_file );
2956
2957     if ( defined $options->{ "chr" } and defined $options->{ "beg" } and ( defined $options->{ "end" } or defined $options->{ "len" } ) )
2958     {
2959         $options->{ "beg" } -= 1;   # request is 1-based
2960         $options->{ "end" } -= 1;   # request is 1-based
2961
2962         if ( $options->{ "len" } ) {
2963             $options->{ "end" } = $options->{ "beg" } + $options->{ "len" } - 1;
2964         }
2965
2966         $scores = Maasha::UCSC::phastcons_index_lookup( $index, $fh_phastcons, $options->{ "chr" }, $options->{ "beg" }, $options->{ "end" }, $options->{ "flank" } );
2967
2968         $record->{ "CHR" }       = $options->{ "chr" };
2969         $record->{ "CHR_BEG" }   = $options->{ "beg" } - $options->{ "flank" };
2970         $record->{ "CHR_END" }   = $options->{ "end" } + $options->{ "flank" };
2971         
2972         $record->{ "PHASTCONS" }   = join ",", @{ $scores };
2973         $record->{ "PHAST_COUNT" } = scalar @{ $scores };  # DEBUG
2974
2975         put_record( $record, $out );
2976     }   
2977
2978     while ( $record = get_record( $in ) ) 
2979     {
2980         if ( $record->{ "REC_TYPE" } eq "BED" )
2981         {
2982             $scores = Maasha::UCSC::phastcons_index_lookup( $index, $fh_phastcons, $record->{ "CHR" }, $record->{ "CHR_BEG" }, $record->{ "CHR_END" }, $options->{ "flank" } );
2983         }
2984         elsif ( $record->{ "REC_TYPE" } eq "PSL" )
2985         {
2986             $scores = Maasha::UCSC::phastcons_index_lookup( $index, $fh_phastcons, $record->{ "S_ID" }, $record->{ "S_BEG" }, $record->{ "S_END" }, $options->{ "flank" } );
2987         }
2988         elsif ( $record->{ "REC_TYPE" } eq "BLAST" )
2989         {
2990             $scores = Maasha::UCSC::phastcons_index_lookup( $index, $fh_phastcons, $record->{ "S_ID" }, $record->{ "S_BEG" }, $record->{ "S_END" }, $options->{ "flank" } );
2991         }
2992
2993         $record->{ "PHASTCONS" } = join ",", @{ $scores } if @{ $scores };
2994 #        $record->{ "PHAST_COUNT" } = @{ $scores } if @{ $scores };  # DEBUG
2995
2996         put_record( $record, $out );
2997     }
2998
2999     close $fh_phastcons if $fh_phastcons;                                                                                                                                          
3000 }
3001
3002
3003 sub script_fold_seq
3004 {
3005     # Martin A. Hansen, December 2007.
3006
3007     # Folds sequences in stream into secondary structures.
3008
3009     my ( $in,     # handle to in stream
3010          $out,    # handle to out stream
3011        ) = @_;
3012
3013     # Returns nothing.
3014
3015     my ( $record, $type, $struct, $index );
3016
3017     while ( $record = get_record( $in ) ) 
3018     {
3019         if ( $record->{ "SEQ" } )
3020         {
3021             if ( not $type ) {
3022                 $type = Maasha::Seq::seq_guess_type( $record->{ "SEQ" } );
3023             }
3024             
3025             if ( $type ne "protein" )
3026             {
3027                 ( $struct, $index ) = Maasha::Seq::fold_struct_rnafold( $record->{ "SEQ" } );
3028                 $record->{ "SEC_STRUCT" }  = $struct;
3029                 $record->{ "FREE_ENERGY" } = $index;
3030                 $record->{ "SCORE" }       = abs int $index;
3031                 $record->{ "SIZE" }        = length $struct;
3032                 $record->{ "CONF" }        = "1," x $record->{ "SIZE" };
3033             }
3034         }
3035
3036         put_record( $record, $out );
3037     }
3038 }
3039
3040
3041 sub script_split_seq
3042 {
3043     # Martin A. Hansen, August 2007.
3044
3045     # Split a sequence in stream into words.
3046
3047     my ( $in,        # handle to in stream
3048          $out,       # handle to out stream
3049          $options,   # options hash
3050        ) = @_;
3051
3052     # Returns nothing.
3053
3054     my ( $record, $new_record, $i, $subseq, %lookup );
3055
3056     $options->{ "word_size" } ||= 7;
3057
3058     while ( $record = get_record( $in ) ) 
3059     {
3060         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } )
3061         {
3062             for ( $i = 0; $i < length( $record->{ "SEQ" } ) - $options->{ "word_size" } + 1; $i++ )
3063             {
3064                 $subseq = substr $record->{ "SEQ" }, $i, $options->{ "word_size" };
3065
3066                 if ( $options->{ "uniq" } and not $lookup{ $subseq } )
3067                 {
3068                     $new_record->{ "SEQ_NAME" } = $record->{ "SEQ_NAME" } . "[" . ( $i + 1 ) . "-" . ( $i + $options->{ "word_size" } ) . "]";
3069                     $new_record->{ "SEQ" }      = $subseq;
3070
3071                     put_record( $new_record, $out );
3072
3073                     $lookup{ $subseq } = 1;
3074                 }
3075                 else
3076                 {
3077                     $new_record->{ "SEQ_NAME" } = $record->{ "SEQ_NAME" } . "[" . ( $i + 1 ) . "-" . ( $i + $options->{ "word_size" } ) . "]";
3078                     $new_record->{ "SEQ" }      = $subseq;
3079
3080                     put_record( $new_record, $out );
3081                 }
3082             }
3083         }
3084         else
3085         {
3086             put_record( $record, $out );
3087         }
3088     }
3089 }
3090
3091
3092 sub script_split_bed
3093 {
3094     # Martin A. Hansen, June 2008.
3095
3096     # Split a BED record into overlapping windows.
3097
3098     my ( $in,        # handle to in stream
3099          $out,       # handle to out stream
3100          $options,   # options hash
3101        ) = @_;
3102
3103     # Returns nothing.
3104
3105     my ( $record, $new_record, $i );
3106
3107     $options->{ "window_size" } ||= 20;
3108     $options->{ "step_size" }   ||= 1;
3109
3110     while ( $record = get_record( $in ) ) 
3111     {
3112         if ( $record->{ "CHR" } and $record->{ "CHR_BEG" } and $record->{ "CHR_END" } )
3113         {
3114             $record->{ "BED_LEN" } = $record->{ "CHR_END" } - $record->{ "CHR_BEG" } + 1;
3115
3116             for ( $i = 0; $i < $record->{ "BED_LEN" } - $options->{ "window_size" }; $i += $options->{ "step_size" } )
3117             {
3118                 $new_record->{ "REC_TYPE" } = "BED";
3119                 $new_record->{ "CHR" }      = $record->{ "CHR" };
3120                 $new_record->{ "CHR_BEG" }  = $record->{ "CHR_BEG" } + $i;
3121                 $new_record->{ "CHR_END" }  = $record->{ "CHR_BEG" } + $i + $options->{ "window_size" };
3122                 $new_record->{ "BED_LEN" }  = $options->{ "window_size" };
3123                 $new_record->{ "Q_ID" }     = $record->{ "Q_ID" } . "_$i";
3124                 $new_record->{ "SCORE" }    = $record->{ "SCORE" };
3125                 $new_record->{ "STRAND" }   = $record->{ "STRAND" };
3126
3127                 put_record( $new_record, $out );
3128             }
3129         }
3130         else
3131         {
3132             put_record( $record, $out );
3133         }
3134     }
3135 }
3136
3137
3138 sub script_align_seq
3139 {
3140     # Martin A. Hansen, August 2007.
3141
3142     # Align sequences in stream.
3143
3144     my ( $in,    # handle to in stream
3145          $out,   # handle to out stream
3146        ) = @_;
3147
3148     # Returns nothing.
3149
3150     my ( $record, @entries, $entry );
3151
3152     while ( $record = get_record( $in ) ) 
3153     {
3154         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } ) {
3155             push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3156         } elsif ( $record->{ "Q_ID" } and $record->{ "SEQ" } ) {
3157             push @entries, [ $record->{ "Q_ID" }, $record->{ "SEQ" } ];
3158         } else {
3159             put_record( $record, $out );
3160         }
3161     }
3162
3163     @entries = Maasha::Align::align( \@entries );
3164
3165     foreach $entry ( @entries )
3166     {
3167         if ( $entry->[ SEQ_NAME ] and $entry->[ SEQ ] )
3168         {
3169             $record = {
3170                 SEQ_NAME => $entry->[ SEQ_NAME ],
3171                 SEQ      => $entry->[ SEQ ],
3172             };
3173
3174             put_record( $record, $out );
3175         }
3176     }
3177 }
3178
3179
3180 sub script_tile_seq
3181 {
3182     # Martin A. Hansen, February 2008.
3183
3184     # Using the first sequence in stream as reference, tile
3185     # all subsequent sequences based on pairwise alignments.
3186
3187     my ( $in,        # handle to in stream
3188          $out,       # handle to out stream
3189          $options,   # options hash
3190        ) = @_;
3191
3192     # Returns nothing.
3193
3194     my ( $record, $first, $ref_entry, @entries );
3195
3196     $first = 1;
3197
3198     while ( $record = get_record( $in ) ) 
3199     {
3200         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } )
3201         {
3202             if ( $first )
3203             {
3204                 $ref_entry = [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3205
3206                 $first = 0;
3207             }
3208             else
3209             {
3210                 push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3211             }
3212         }
3213         else
3214         {
3215             put_record( $record, $out );
3216         }
3217     }
3218
3219     @entries = Maasha::Align::align_tile( $ref_entry, \@entries, $options );
3220
3221     map { put_record( { SEQ_NAME => $_->[ SEQ_NAME ], SEQ => $_->[ SEQ ] }, $out ) } @entries;
3222 }
3223
3224
3225 sub script_invert_align
3226 {
3227     # Martin A. Hansen, February 2008.
3228
3229     # Inverts an alignment showing only non-mathing residues
3230     # using the first sequence as reference.
3231
3232     my ( $in,        # handle to in stream
3233          $out,       # handle to out stream
3234          $options,   # options hash
3235        ) = @_;
3236
3237     # Returns nothing.
3238
3239     my ( $record, @entries );
3240
3241     while ( $record = get_record( $in ) ) 
3242     {
3243         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } )
3244         {
3245             push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3246         }
3247         else
3248         {
3249             put_record( $record, $out );
3250         }
3251     }
3252
3253     Maasha::Align::align_invert( \@entries, $options->{ "soft" } );
3254
3255     map { put_record( { SEQ_NAME => $_->[ SEQ_NAME ], SEQ => $_->[ SEQ ] }, $out ) } @entries;
3256 }
3257
3258
3259 sub script_patscan_seq
3260 {
3261     # Martin A. Hansen, August 2007.
3262
3263     # Locates patterns in sequences using scan_for_matches.
3264
3265     my ( $in,        # handle to in stream
3266          $out,       # handle to out stream
3267          $options,   # options hash
3268        ) = @_;
3269
3270     # Returns nothing.
3271
3272     my ( $genome_file, @args, $arg, $type, $seq_file, $pat_file, $out_file, $fh_in, $fh_out, $record, $patterns, $pattern, $entry, $result, %head_hash, $i );
3273
3274     if ( $options->{ "patterns" } ) {
3275         $patterns = Maasha::Patscan::parse_patterns( $options->{ "patterns" } );
3276     } elsif ( -f $options->{ "patterns_in" } ) {
3277         $patterns = Maasha::Patscan::read_patterns( $options->{ "patterns_in" } );
3278     }
3279
3280     $genome_file = "$ENV{ 'BP_DATA' }/genomes/$options->{ 'genome' }/fasta/$options->{ 'genome' }.fna" if $options->{ 'genome' };
3281
3282     push @args, "-c"                            if $options->{ "comp" };
3283     push @args, "-m $options->{ 'max_hits' }"   if $options->{ 'max_hits' };
3284     push @args, "-n $options->{ 'max_misses' }" if $options->{ 'max_hits' };
3285
3286     $seq_file = "$BP_TMP/patscan.seq";
3287     $pat_file = "$BP_TMP/patscan.pat";
3288     $out_file = "$BP_TMP/patscan.out";
3289
3290     $fh_out = Maasha::Common::write_open( $seq_file );
3291
3292     $i = 0;
3293
3294     while ( $record = get_record( $in ) ) 
3295     {
3296         if ( $record->{ "SEQ" } and $record->{ "SEQ_NAME" } )
3297         {
3298             $type = Maasha::Seq::seq_guess_type( $record->{ "SEQ" } ) if not $type;
3299
3300             Maasha::Fasta::put_entry( [ $i, $record->{ "SEQ" } ], $fh_out );
3301
3302             $head_hash{ $i } = $record->{ "SEQ_NAME" };
3303
3304             $i++;
3305         }
3306     }
3307
3308     close $fh_out;
3309
3310     $arg  = join " ", @args;
3311     $arg .= " -p" if $type eq "protein";
3312
3313     foreach $pattern ( @{ $patterns } )
3314     {
3315         $fh_out = Maasha::Common::write_open( $pat_file );
3316
3317         print $fh_out "$pattern\n";
3318
3319         close $fh_out;
3320
3321         if ( $options->{ 'genome' } ) {
3322             `scan_for_matches $arg $pat_file < $genome_file > $out_file`;
3323             # Maasha::Common::run( "scan_for_matches", "$arg $pat_file < $genome_file > $out_file" );
3324         } else {
3325             `scan_for_matches $arg $pat_file < $seq_file > $out_file`;
3326             # Maasha::Common::run( "scan_for_matches", "$arg $pat_file < $seq_file > $out_file" );
3327         }
3328
3329         $fh_in = Maasha::Common::read_open( $out_file );
3330
3331         while ( $entry = Maasha::Fasta::get_entry( $fh_in ) )
3332         {
3333             $result = Maasha::Patscan::parse_scan_result( $entry, $pattern );
3334
3335             if ( $options->{ 'genome' } )
3336             {
3337                 $result->{ "CHR" }     = $result->{ "S_ID" };
3338                 $result->{ "CHR_BEG" } = $result->{ "S_BEG" }; 
3339                 $result->{ "CHR_END" } = $result->{ "S_END" }; 
3340
3341                 delete $result->{ "S_ID" };
3342                 delete $result->{ "S_BEG" };
3343                 delete $result->{ "S_END" };
3344             }
3345             else
3346             {
3347                 $result->{ "S_ID" } = $head_hash{ $result->{ "S_ID" } };
3348             }
3349
3350             put_record( $result, $out );
3351         }
3352
3353         close $fh_in;
3354     }
3355
3356     unlink $pat_file;
3357     unlink $seq_file;
3358     unlink $out_file;
3359 }
3360
3361
3362 sub script_create_blast_db
3363 {
3364     # Martin A. Hansen, September 2007.
3365
3366     # Creates a NCBI BLAST database with formatdb
3367
3368     my ( $in,        # handle to in stream
3369          $out,       # handle to out stream
3370          $options,   # options hash
3371        ) = @_;
3372
3373     # Returns nothing.
3374
3375     my ( $fh, $seq_type, $path, $record, $entry );
3376
3377     $path = $options->{ "database" };
3378
3379     $fh = Maasha::Common::write_open( $path );
3380
3381     while ( $record = get_record( $in ) ) 
3382     {
3383         put_record( $record, $out ) if not $options->{ "no_stream" };
3384
3385         if ( $entry = record2fasta( $record ) )
3386         {
3387             $seq_type = Maasha::Seq::seq_guess_type( $entry->[ SEQ ] ) if not $seq_type;
3388
3389             Maasha::Fasta::put_entry( $entry, $fh );
3390         }
3391     }
3392
3393     close $fh;
3394
3395     if ( $seq_type eq "protein" ) {
3396         Maasha::Common::run( "formatdb", "-p T -i $path -t $options->{ 'database' }" );
3397     } else {
3398         Maasha::Common::run( "formatdb", "-p F -i $path -t $options->{ 'database' }" );
3399     }
3400
3401     unlink $path;
3402 }
3403
3404
3405 sub script_blast_seq
3406 {
3407     # Martin A. Hansen, September 2007.
3408
3409     # BLASTs sequences in stream against a given database.
3410
3411     my ( $in,        # handle to in stream
3412          $out,       # handle to out stream
3413          $options,   # options hash
3414        ) = @_;
3415
3416     # Returns nothing.
3417
3418     my ( $genome, $q_type, $s_type, $tmp_in, $tmp_out, $fh_in, $fh_out, $record, $line, @fields, $entry );
3419
3420     $options->{ "e_val" }  = 10 if not defined $options->{ "e_val" };
3421     $options->{ "filter" } = "F";
3422     $options->{ "filter" } = "T" if $options->{ "filter" };
3423     $options->{ "cpus" } ||= 1;
3424
3425     $options->{ "database" } = "$ENV{ 'BP_DATA' }/genomes/$options->{ 'genome' }/blast/$options->{ 'genome' }.fna" if $options->{ 'genome' };
3426
3427     $tmp_in  = "$BP_TMP/blast_query.seq";
3428     $tmp_out = "$BP_TMP/blast.result";
3429
3430     $fh_out = Maasha::Common::write_open( $tmp_in );
3431
3432     while ( $record = get_record( $in ) ) 
3433     {
3434         if ( $entry = record2fasta( $record ) )
3435         {
3436             $q_type = Maasha::Seq::seq_guess_type( $entry->[ SEQ ] ) if not $q_type;
3437
3438             Maasha::Fasta::put_entry( $entry, $fh_out );
3439         }
3440
3441         put_record( $record, $out );
3442     }
3443
3444     close $fh_out;
3445
3446     if ( -f $options->{ 'database' } . ".phr" ) {
3447         $s_type = "protein";
3448     } else {
3449         $s_type = "nucleotide";
3450     }
3451
3452     if ( not $options->{ 'program' } )
3453     {
3454         if ( $q_type ne "protein" and $s_type ne "protein" ) {
3455             $options->{ 'program' } = "blastn";
3456         } elsif ( $q_type eq "protein" and $s_type eq "protein" ) {
3457             $options->{ 'program' } = "blastp";
3458         } elsif ( $q_type ne "protein" and $s_type eq "protein" ) {
3459             $options->{ 'program' } = "blastx";
3460         } elsif ( $q_type eq "protein" and $s_type ne "protein" ) {
3461             $options->{ 'program' } = "tblastn";
3462         }
3463     }
3464
3465     Maasha::Common::run( "blastall", "-p $options->{ 'program' } -e $options->{ 'e_val' } -a $options->{ 'cpus' } -m 8 -i $tmp_in -d $options->{ 'database' } -F $options->{ 'filter' } -o $tmp_out > /dev/null 2>&1", 1 );
3466
3467     unlink $tmp_in;
3468
3469     $fh_out = Maasha::Common::read_open( $tmp_out );
3470
3471     undef $record;
3472
3473     while ( $line = <$fh_out> )
3474     {
3475         chomp $line;
3476
3477         next if $line =~ /^#/;
3478
3479         @fields = split /\s+/, $line;
3480
3481         $record->{ "REC_TYPE" }   = "BLAST";
3482         $record->{ "Q_ID" }       = $fields[ 0 ];
3483         $record->{ "S_ID" }       = $fields[ 1 ];
3484         $record->{ "IDENT" }      = $fields[ 2 ];
3485         $record->{ "ALIGN_LEN" }  = $fields[ 3 ];
3486         $record->{ "MISMATCHES" } = $fields[ 4 ];
3487         $record->{ "GAPS" }       = $fields[ 5 ];
3488         $record->{ "Q_BEG" }      = $fields[ 6 ] - 1; # BLAST is 1-based
3489         $record->{ "Q_END" }      = $fields[ 7 ] - 1; # BLAST is 1-based
3490         $record->{ "S_BEG" }      = $fields[ 8 ] - 1; # BLAST is 1-based
3491         $record->{ "S_END" }      = $fields[ 9 ] - 1; # BLAST is 1-based
3492         $record->{ "E_VAL" }      = $fields[ 10 ];
3493         $record->{ "BIT_SCORE" }  = $fields[ 11 ];
3494
3495         if ( $record->{ "S_BEG" } > $record->{ "S_END" } )
3496         {
3497             $record->{ "STRAND" } = '-';
3498
3499             ( $record->{ "S_BEG" }, $record->{ "S_END" } ) = ( $record->{ "S_END" }, $record->{ "S_BEG" } );
3500         }
3501         else
3502         {
3503             $record->{ "STRAND" } = '+';
3504         }
3505
3506         put_record( $record, $out );
3507     }
3508
3509     close $fh_out;
3510
3511     unlink $tmp_out;
3512 }
3513
3514
3515 sub script_blat_seq
3516 {
3517     # Martin A. Hansen, August 2007.
3518
3519     # BLATs sequences in stream against a given genome.
3520
3521     my ( $in,        # handle to in stream
3522          $out,       # handle to out stream
3523          $options,   # options hash
3524        ) = @_;
3525
3526     # Returns nothing.
3527
3528     my ( $blat_args, $genome_file, $query_file, $fh_in, $fh_out, $type, $record, $result_file, $entries, $entry );
3529
3530     $genome_file = "$ENV{ 'BP_DATA' }/genomes/$options->{ 'genome' }/fasta/$options->{ 'genome' }.fna";
3531
3532     $options->{ 'tile_size' }    ||= 11;
3533     $options->{ 'one_off' }      ||= 0;
3534     $options->{ 'min_identity' } ||= 90;
3535     $options->{ 'min_score' }    ||= 0;
3536     $options->{ 'step_size' }    ||= $options->{ 'tile_size' };
3537
3538     $blat_args .= " -tileSize=$options->{ 'tile_size' }";
3539     $blat_args .= " -oneOff=$options->{ 'one_off' }";
3540     $blat_args .= " -minIdentity=$options->{ 'min_identity' }";
3541     $blat_args .= " -minScore=$options->{ 'min_score' }";
3542     $blat_args .= " -stepSize=$options->{ 'step_size' }";
3543 #    $blat_args .= " -ooc=" . Maasha::Config::genome_blat_ooc( $options->{ "genome" }, 11 ) if $options->{ 'ooc' };
3544
3545     $query_file = "$BP_TMP/blat.seq";
3546
3547     $fh_out = Maasha::Common::write_open( $query_file );
3548
3549     while ( $record = get_record( $in ) ) 
3550     {
3551         if ( $entry = record2fasta( $record ) )
3552         {
3553             $type = Maasha::Seq::seq_guess_type( $entry->[ SEQ ] ) if not $type;
3554             Maasha::Fasta::put_entry( $entry, $fh_out, 80 );
3555         }
3556
3557         put_record( $record, $out );
3558     }
3559
3560     close $fh_out;
3561
3562     $blat_args .= " -t=dnax" if $type eq "protein";
3563     $blat_args .= " -q=$type";
3564
3565     $result_file = "$BP_TMP/blat.psl";
3566
3567     Maasha::Common::run( "blat", "$genome_file $query_file $blat_args $result_file > /dev/null 2>&1" );
3568
3569     unlink $query_file;
3570
3571     $entries = Maasha::UCSC::psl_get_entries( $result_file );
3572
3573     map { put_record( $_, $out ) } @{ $entries };
3574
3575     unlink $result_file;
3576 }
3577
3578
3579 sub script_soap_seq
3580 {
3581     # Martin A. Hansen, July 2008.
3582
3583     # soap sequences in stream against a given file or genome.
3584
3585     my ( $in,        # handle to in stream
3586          $out,       # handle to out stream
3587          $options,   # options hash
3588        ) = @_;
3589
3590     # Returns nothing.
3591
3592     my ( $genome, $tmp_in, $tmp_out, $fh_in, $fh_out, $record, $line, @fields, $entry, $count, $args );
3593
3594     $options->{ "seed_size" }  ||= 10;
3595     $options->{ "mismatches" } ||= 2;
3596     $options->{ "gap_size" }   ||= 0;
3597     $options->{ "cpus" }       ||= 1;
3598
3599     if ( $options->{ "genome" } ) {
3600         $options->{ "in_file" } = "$ENV{ 'BP_DATA' }/genomes/$options->{ 'genome' }/fasta/$options->{ 'genome' }.fna";
3601     }
3602
3603     $tmp_in  = "$BP_TMP/soap_query.seq";
3604     $tmp_out = "$BP_TMP/soap.result";
3605
3606     $fh_out = Maasha::Common::write_open( $tmp_in );
3607  
3608     $count = 0;
3609
3610     while ( $record = get_record( $in ) ) 
3611     {
3612         if ( $entry = record2fasta( $record ) )
3613         {
3614             Maasha::Fasta::put_entry( $entry, $fh_out );
3615
3616             $count++;
3617         }
3618
3619         put_record( $record, $out );
3620     }
3621
3622     close $fh_out;
3623
3624     if ( $count > 0 )
3625     {
3626         $args = join( " ",
3627             "-s $options->{ 'seed_size' }",
3628             "-r 2",
3629             "-a $tmp_in",
3630             "-v $options->{ 'mismatches' }",
3631             "-g $options->{ 'gap_size' }",
3632             "-p $options->{ 'cpus' }",
3633             "-d $options->{ 'in_file' }",
3634             "-o $tmp_out",
3635         );
3636
3637         $args .= " > /dev/null 2>&1" if not $options->{ 'verbose' };
3638
3639         Maasha::Common::run( "soap", $args, 1 );
3640
3641         unlink $tmp_in;
3642
3643         $fh_out = Maasha::Common::read_open( $tmp_out );
3644
3645         undef $record;
3646
3647         while ( $line = <$fh_out> )
3648         {
3649             chomp $line;
3650
3651             @fields = split /\t/, $line;
3652
3653             $record->{ "REC_TYPE" }   = "SOAP";
3654             $record->{ "Q_ID" }       = $fields[ 0 ];
3655             $record->{ "SCORE" }      = $fields[ 3 ];
3656             $record->{ "STRAND" }     = $fields[ 6 ];
3657             $record->{ "S_ID" }       = $fields[ 7 ];
3658             $record->{ "S_BEG" }      = $fields[ 8 ] - 1; # soap is 1-based
3659             $record->{ "S_END" }      = $fields[ 8 ] + $fields[ 5 ] - 2;
3660
3661             put_record( $record, $out );
3662         }
3663
3664         close $fh_out;
3665     }
3666
3667     unlink $tmp_out;
3668 }
3669
3670
3671 sub script_match_seq
3672 {
3673     # Martin A. Hansen, August 2007.
3674
3675     # BLATs sequences in stream against a given genome.
3676
3677     my ( $in,        # handle to in stream
3678          $out,       # handle to out stream
3679          $options,   # options hash
3680        ) = @_;
3681
3682     # Returns nothing.
3683
3684     my ( $record, @entries, $results );
3685
3686     $options->{ "word_size" } ||= 20;
3687     $options->{ "direction" } ||= "both";
3688
3689     while ( $record = get_record( $in ) ) 
3690     {
3691         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } ) {
3692             push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3693         }
3694
3695         put_record( $record, $out );
3696     }
3697
3698     if ( @entries == 1 )
3699     {
3700         $results = Maasha::Match::match_mummer( [ $entries[ 0 ] ], [ $entries[ 0 ] ], $options, $BP_TMP );
3701
3702         map { put_record( $_, $out ) } @{ $results };
3703     }
3704     elsif ( @entries == 2 )
3705     {
3706         $results = Maasha::Match::match_mummer( [ $entries[ 0 ] ], [ $entries[ 1 ] ], $options, $BP_TMP );
3707
3708         map { put_record( $_, $out ) } @{ $results };
3709     }
3710 }
3711
3712
3713 sub script_create_vmatch_index
3714 {
3715     # Martin A. Hansen, January 2008.
3716
3717     # Create a vmatch index from sequences in the stream.
3718
3719     my ( $in,        # handle to in stream
3720          $out,       # handle to out stream
3721          $options,   # options hash
3722        ) = @_;
3723
3724     # Returns nothing.
3725
3726     my ( $record, $file_tmp, $fh_tmp, $type, $entry );
3727
3728     if ( $options->{ "index_name" } )
3729     {
3730         $file_tmp = $options->{ 'index_name' };
3731         $fh_tmp   = Maasha::Common::write_open( $file_tmp );
3732     }
3733
3734     while ( $record = get_record( $in ) ) 
3735     {
3736         if ( $options->{ "index_name" } and $entry = record2fasta( $record ) )
3737         {
3738             Maasha::Fasta::put_entry( $entry, $fh_tmp );
3739
3740             $type = Maasha::Seq::seq_guess_type( $entry->[ SEQ ] ) if not defined $type;
3741         }
3742
3743         put_record( $record, $out ) if not $options->{ "no_stream" };
3744     }
3745
3746     if ( $options->{ "index_name" } )
3747     {
3748         close $fh_tmp;
3749     
3750         if ( $type eq "protein" ) {
3751             Maasha::Common::run( "mkvtree", "-db $file_tmp -protein -pl $options->{ 'prefix_length' } -allout -indexname $file_tmp > /dev/null 2>&1" );
3752         } else {
3753             Maasha::Common::run( "mkvtree", "-db $file_tmp -dna -pl $options->{ 'prefix_length' } -allout -indexname $file_tmp > /dev/null 2>&1" );
3754         }
3755
3756         unlink $file_tmp;
3757     }
3758 }
3759
3760
3761 sub script_vmatch_seq
3762 {
3763     # Martin A. Hansen, August 2007.
3764
3765     # Vmatches sequences in stream against a given genome.
3766
3767     my ( $in,        # handle to in stream
3768          $out,       # handle to out stream
3769          $options,   # options hash
3770        ) = @_;
3771
3772     # Returns nothing.
3773
3774     my ( @index_files, @records, $result_file, $fh_in, $record, %hash );
3775
3776     $options->{ 'count' } = 1 if $options->{ 'max_hits' };
3777
3778     if ( $options->{ "index_name" } )
3779     {
3780         @index_files = $options->{ "index_name" };
3781     }
3782     else
3783     {
3784         @index_files = Maasha::Common::ls_files( "$ENV{ 'BP_DATA' }/genomes/$options->{ 'genome' }/vmatch" );
3785
3786         map { $_ =~ /^(.+)\.[a-z1]{3,4}$/; $hash{ $1 } = 1 } @index_files;
3787
3788         @index_files = sort keys %hash;
3789     }
3790
3791     while ( $record = get_record( $in ) ) 
3792     {
3793         push @records, $record;
3794
3795         put_record( $record, $out );
3796     }
3797
3798     $result_file = Maasha::Match::match_vmatch( $BP_TMP, \@records, \@index_files, $options );
3799
3800     undef @records;
3801
3802     $fh_in = Maasha::Common::read_open( $result_file );
3803
3804     while ( $record = Maasha::Match::vmatch_get_entry( $fh_in ) ) {
3805         put_record( $record, $out );
3806     }
3807
3808     close $fh_in;
3809
3810     unlink $result_file;
3811 }
3812
3813
3814 sub script_write_fasta
3815 {
3816     # Martin A. Hansen, August 2007.
3817
3818     # Write FASTA entries from sequences in stream.
3819
3820     my ( $in,        # handle to in stream
3821          $out,       # handle to out stream
3822          $options,   # options hash
3823        ) = @_;
3824
3825     # Returns nothing.
3826
3827     my ( $record, $fh, $entry );
3828
3829     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
3830
3831     while ( $record = get_record( $in ) ) 
3832     {
3833         if ( $entry = record2fasta( $record ) ) {
3834             Maasha::Fasta::put_entry( $entry, $fh, $options->{ "wrap" } );
3835         }
3836
3837         put_record( $record, $out ) if not $options->{ "no_stream" };
3838     }
3839
3840     close $fh;
3841 }
3842
3843
3844 sub script_write_align
3845 {
3846     # Martin A. Hansen, August 2007.
3847
3848     # Write pretty alignments aligned sequences in stream.
3849
3850     my ( $in,        # handle to in stream
3851          $out,       # handle to out stream
3852          $options,   # options hash
3853        ) = @_;
3854
3855     # Returns nothing.
3856
3857     my ( $fh, $record, @entries );
3858
3859     $fh = write_stream( $options->{ "data_out" } ) ;
3860
3861     while ( $record = get_record( $in ) ) 
3862     {
3863         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } ) {
3864             push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
3865         }
3866
3867         put_record( $record, $out ) if not $options->{ "no_stream" };
3868     }
3869
3870     if ( scalar( @entries ) == 2 ) {
3871         Maasha::Align::align_print_pairwise( $entries[ 0 ], $entries[ 1 ], $fh, $options->{ "wrap" } );
3872     } elsif ( scalar ( @entries ) > 2 ) {
3873         Maasha::Align::align_print_multi( \@entries, $fh, $options->{ "wrap" }, $options->{ "no_ruler" }, $options->{ "no_consensus" } );
3874     }
3875
3876     close $fh if $fh;
3877 }
3878
3879
3880 sub script_write_blast
3881 {
3882     # Martin A. Hansen, November 2007.
3883
3884     # Write data in blast table format (-m8 and 9).
3885
3886     my ( $in,        # handle to in stream
3887          $out,       # handle to out stream
3888          $options,   # options hash
3889        ) = @_;
3890
3891     # Returns nothing.
3892
3893     my ( $fh, $record, $first );
3894
3895     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } ) ;
3896
3897     $first = 1;
3898
3899     while ( $record = get_record( $in ) ) 
3900     {
3901         if ( $record->{ "REC_TYPE" } eq "BLAST" )
3902         {
3903             if ( $options->{ "comment" } and $first )
3904             {
3905                 print "# Fields: Query id, Subject id, % identity, alignment length, mismatches, gap openings, q. start, q. end, s. start, s. end, e-value, bit score\n";
3906
3907                 $first = 0;
3908             }
3909
3910             if ( $record->{ "STRAND" } eq "-" ) {
3911                 ( $record->{ "S_BEG" }, $record->{ "S_END" } ) = ( $record->{ "S_END" }, $record->{ "S_BEG" } );
3912             }
3913
3914             print $fh join( "\t",
3915                 $record->{ "Q_ID" },
3916                 $record->{ "S_ID" },
3917                 $record->{ "IDENT" },
3918                 $record->{ "ALIGN_LEN" },
3919                 $record->{ "MISMATCHES" },
3920                 $record->{ "GAPS" },
3921                 $record->{ "Q_BEG" } + 1,
3922                 $record->{ "Q_END" } + 1,
3923                 $record->{ "S_BEG" } + 1,
3924                 $record->{ "S_END" } + 1,
3925                 $record->{ "E_VAL" },
3926                 $record->{ "BIT_SCORE" }
3927             ), "\n";
3928         }
3929
3930         put_record( $record, $out ) if not $options->{ "no_stream" };
3931     }
3932
3933     close $fh;
3934 }
3935
3936
3937 sub script_write_tab
3938 {
3939     # Martin A. Hansen, August 2007.
3940
3941     # Write data as table.
3942
3943     my ( $in,        # handle to in stream
3944          $out,       # handle to out stream
3945          $options,   # options hash
3946        ) = @_;
3947
3948     # Returns nothing.
3949
3950     my ( $fh, $record, $key, @keys, @vals, $ok, %no_keys, $A, $B );
3951
3952     $options->{ "delimit" } ||= "\t";
3953
3954     map { $no_keys{ $_ } = 1 } @{ $options->{ "no_keys" } };
3955
3956     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
3957
3958     while ( $record = get_record( $in ) ) 
3959     {
3960         undef @vals;
3961         $ok = 1;
3962         
3963         if ( $options->{ "keys" } )
3964         {
3965             map { $ok = 0 if not exists $record->{ $_ } } @{ $options->{ "keys" } };
3966
3967             if ( $ok )
3968             {
3969                 foreach $key ( @{ $options->{ "keys" }  } )
3970                 {
3971                     if ( exists $record->{ $key } )
3972                     {
3973                         push @keys, $key if $options->{ "comment" };
3974                         push @vals, $record->{ $key };
3975                     }
3976                 }
3977              }
3978         }
3979         else
3980         {
3981             foreach $key ( sort { $A = $a; $B = $b; $A =~ s/^V(\d+)$/$1/; $B =~ s/^V(\d+)$/$1/; $A <=> $B } keys %{ $record } )
3982             {
3983                 next if exists $no_keys{ $key };
3984
3985                 push @keys, $key if $options->{ "comment" };
3986                 push @vals, $record->{ $key };
3987             }
3988         }
3989
3990         if ( @keys and $options->{ "comment" } )
3991         {
3992             print $fh "#", join( $options->{ "delimit" }, @keys ), "\n";
3993
3994             delete $options->{ "comment" };
3995         }
3996
3997         print $fh join( $options->{ "delimit" }, @vals ), "\n" if @vals;
3998
3999         put_record( $record, $out ) if not $options->{ "no_stream" };
4000     }
4001
4002     close $fh;
4003 }
4004
4005
4006 sub script_write_bed
4007 {
4008     # Martin A. Hansen, August 2007.
4009
4010     # Write BED format for the UCSC genome browser using records in stream.
4011
4012     my ( $in,        # handle to in stream
4013          $out,       # handle to out stream
4014          $options,   # options hash
4015        ) = @_;
4016
4017     # Returns nothing.
4018
4019     my ( $fh, $record, $new_record );
4020
4021     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
4022
4023     while ( $record = get_record( $in ) ) 
4024     {
4025         if ( $record->{ "REC_TYPE" } eq "BED" )                                             # ---- Hits from BED ----
4026         {
4027             Maasha::UCSC::bed_put_entry( $record, $fh, $record->{ "BED_COLS" } );
4028         }
4029         elsif ( $record->{ "REC_TYPE" } eq "PSL" and $record->{ "S_ID" } =~ /^chr/i )       # ---- Hits from BLAT (PSL) ----
4030         {
4031             $new_record->{ "CHR" }     = $record->{ "S_ID" };
4032             $new_record->{ "CHR_BEG" } = $record->{ "S_BEG" };
4033             $new_record->{ "CHR_END" } = $record->{ "S_END" };
4034             $new_record->{ "Q_ID" }    = $record->{ "Q_ID" };
4035             $new_record->{ "SCORE" }   = $record->{ "SCORE" } || 999;
4036             $new_record->{ "STRAND" }  = $record->{ "STRAND" };
4037
4038             Maasha::UCSC::bed_put_entry( $new_record, $fh, 6 );
4039         }
4040         elsif ( $record->{ "REC_TYPE" } eq "PATSCAN" and $record->{ "CHR" } )               # ---- Hits from patscan_seq ----
4041         {
4042             Maasha::UCSC::bed_put_entry( $record, $fh, 6 );
4043         }
4044         elsif ( $record->{ "REC_TYPE" } eq "BLAST" and $record->{ "S_ID" } =~ /^chr/i )     # ---- Hits from BLAST ----
4045         {
4046             $new_record->{ "CHR" }     = $record->{ "S_ID" };
4047             $new_record->{ "CHR_BEG" } = $record->{ "S_BEG" };
4048             $new_record->{ "CHR_END" } = $record->{ "S_END" };
4049             $new_record->{ "Q_ID" }    = $record->{ "Q_ID" };
4050             $new_record->{ "SCORE" }   = $record->{ "SCORE" } || 999; # or use E_VAL somehow
4051             $new_record->{ "STRAND" }  = $record->{ "STRAND" };
4052
4053             Maasha::UCSC::bed_put_entry( $new_record, $fh, 6 );
4054         }
4055         elsif ( $record->{ "REC_TYPE" } eq "VMATCH" and $record->{ "S_ID" } =~ /^chr/i )    # ---- Hits from Vmatch ----
4056         {
4057             $new_record->{ "CHR" }     = $record->{ "S_ID" };
4058             $new_record->{ "CHR_BEG" } = $record->{ "S_BEG" };
4059             $new_record->{ "CHR_END" } = $record->{ "S_END" };
4060             $new_record->{ "Q_ID" }    = $record->{ "Q_ID" };
4061             $new_record->{ "SCORE" }   = $record->{ "SCORE" } || 999; # or use E_VAL somehow
4062             $new_record->{ "STRAND" }  = $record->{ "STRAND" };
4063
4064             Maasha::UCSC::bed_put_entry( $new_record, $fh, 6 );
4065         }
4066         elsif ( $record->{ "REC_TYPE" } eq "SOAP" and $record->{ "S_ID" } =~ /^chr/i )    # ---- Hits from Vmatch ----
4067         {
4068             $new_record->{ "CHR" }     = $record->{ "S_ID" };
4069             $new_record->{ "CHR_BEG" } = $record->{ "S_BEG" };
4070             $new_record->{ "CHR_END" } = $record->{ "S_END" };
4071             $new_record->{ "Q_ID" }    = $record->{ "Q_ID" };
4072             $new_record->{ "SCORE" }   = $record->{ "SCORE" } || 999;
4073             $new_record->{ "STRAND" }  = $record->{ "STRAND" };
4074
4075             Maasha::UCSC::bed_put_entry( $new_record, $fh, 6 );
4076         }
4077         elsif ( $record->{ "CHR" } and defined $record->{ "CHR_BEG" } and $record->{ "CHR_END" } )  # ---- Generic data from tables ----
4078         {
4079             Maasha::UCSC::bed_put_entry( $record, $fh );
4080         }
4081
4082         put_record( $record, $out ) if not $options->{ "no_stream" };
4083     }
4084
4085     close $fh;
4086 }
4087
4088
4089 sub script_write_psl
4090 {
4091     # Martin A. Hansen, August 2007.
4092
4093     # Write PSL output from stream.
4094
4095     my ( $in,        # handle to in stream
4096          $out,       # handle to out stream
4097          $options,   # options hash
4098        ) = @_;
4099
4100     # Returns nothing.
4101
4102     my ( $fh, $record, @output, $first );
4103
4104     $first = 1;
4105
4106     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
4107
4108     while ( $record = get_record( $in ) ) 
4109     {
4110         put_record( $record, $out ) if not $options->{ "no_stream" };
4111
4112         if ( $record->{ "REC_TYPE" } and $record->{ "REC_TYPE" } eq "PSL" )
4113         {
4114             Maasha::UCSC::psl_put_header( $fh ) if $first;
4115             Maasha::UCSC::psl_put_entry( $record, $fh );
4116             $first = 0;
4117         }
4118     }
4119
4120     close $fh;
4121 }
4122
4123
4124 sub script_write_fixedstep
4125 {
4126     # Martin A. Hansen, Juli 2008.
4127
4128     # Write fixedStep entries from recrods in the stream.
4129
4130     my ( $in,        # handle to in stream
4131          $out,       # handle to out stream
4132          $options,   # options hash
4133        ) = @_;
4134
4135     # Returns nothing.
4136
4137     my ( $fh, $record, $vals );
4138
4139     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
4140
4141     while ( $record = get_record( $in ) ) 
4142     {
4143         if ( $record->{ "CHR" } and $record->{ "CHR_BEG" } and $record->{ "STEP" } and $record->{ "VALS" } )
4144         {
4145             print $fh "fixedStep chrom=$record->{ 'CHR' } start=$record->{ 'CHR_BEG' } step=$record->{ 'STEP' }\n";
4146
4147             $vals = $record->{ 'VALS' };
4148
4149             $vals =~ tr/,/\n/;
4150
4151             print $fh "$vals\n";
4152         }
4153
4154         put_record( $record, $out ) if not $options->{ "no_stream" };
4155     }
4156
4157     close $fh;
4158 }
4159
4160
4161 sub script_write_2bit
4162 {
4163     # Martin A. Hansen, March 2008.
4164
4165     # Write sequence entries from stream in 2bit format.
4166
4167     my ( $in,        # handle to in stream
4168          $out,       # handle to out stream
4169          $options,   # options hash
4170        ) = @_;
4171
4172     # Returns nothing.
4173
4174     my ( $record, $mask, $tmp_file, $fh_tmp, $fh_in, $fh_out, $entry );
4175
4176     $mask = 1 if not $options->{ "no_mask" };
4177
4178     $tmp_file = "$BP_TMP/write_2bit.fna";
4179     $fh_tmp   = Maasha::Common::write_open( $tmp_file );
4180
4181     $fh_out = write_stream( $options->{ "data_out" } );
4182
4183     while ( $record = get_record( $in ) ) 
4184     {
4185         if ( $entry = record2fasta( $record ) ) {
4186             Maasha::Fasta::put_entry( $entry, $fh_tmp );
4187         }
4188
4189         put_record( $record, $out ) if not $options->{ "no_stream" };
4190     }
4191
4192     close $fh_tmp;
4193
4194     $fh_in = Maasha::Common::read_open( $tmp_file );
4195
4196     Maasha::TwoBit::fasta2twobit( $fh_in, $fh_out, $mask );
4197
4198     close $fh_in;
4199     close $fh_out;
4200
4201     unlink $tmp_file;
4202 }
4203
4204
4205 sub script_write_solid
4206 {
4207     # Martin A. Hansen, April 2008.
4208
4209     # Write di-base encoded Solid sequence from entries in stream.
4210
4211     my ( $in,        # handle to in stream
4212          $out,       # handle to out stream
4213          $options,   # options hash
4214        ) = @_;
4215
4216     # Returns nothing.
4217
4218     my ( $record, $fh, $entry );
4219
4220     $fh = write_stream( $options->{ "data_out" }, $options->{ "compress" } );
4221
4222     while ( $record = get_record( $in ) ) 
4223     {
4224         if ( $entry = record2fasta( $record ) )
4225         {
4226             $entry->[ SEQ ] = Maasha::Solid::seq2color_space( uc $entry->[ SEQ ] );
4227
4228             Maasha::Fasta::put_entry( $entry, $fh, $options->{ "wrap" } );
4229         }
4230
4231         put_record( $record, $out ) if not $options->{ "no_stream" };
4232     }
4233
4234     close $fh;
4235 }
4236
4237
4238 sub script_plot_seqlogo
4239 {
4240     # Martin A. Hansen, August 2007.
4241
4242     # Calculates and writes a sequence logo for alignments.
4243
4244     my ( $in,        # handle to in stream
4245          $out,       # handle to out stream
4246          $options,   # options hash
4247        ) = @_;
4248
4249     # Returns nothing.
4250
4251     my ( $record, @entries, $logo, $fh );
4252
4253     while ( $record = get_record( $in ) ) 
4254     {
4255         if ( $record->{ "SEQ_NAME" } and $record->{ "SEQ" } ) {
4256             push @entries, [ $record->{ "SEQ_NAME" }, $record->{ "SEQ" } ];
4257         }
4258
4259         put_record( $record, $out ) if not $options->{ "no_stream" };
4260     }
4261
4262     $logo = Maasha::Plot::seq_logo( \@entries );
4263
4264     $fh = write_stream( $options->{ "data_out" } );
4265
4266     print $fh $logo;
4267
4268     close $fh;
4269 }
4270
4271
4272 sub script_plot_phastcons_profiles
4273 {
4274     # Martin A. Hansen, January 2008.
4275
4276     # Plots PhastCons profiles.
4277
4278     my ( $in,        # handle to in stream
4279          $out,       # handle to out stream
4280          $options,   # options hash
4281        ) = @_;
4282
4283     # Returns nothing.
4284
4285     my ( $phastcons_file, $phastcons_index, $index, $fh_phastcons, $record, $scores, $AoA, $plot, $fh );
4286
4287     $options->{ "title" } ||= "PhastCons Profiles";
4288
4289     $phastcons_file  = Maasha::Config::genome_phastcons( $options->{ "genome" } );
4290     $phastcons_index = Maasha::Config::genome_phastcons_index( $options->{ "genome" } );
4291
4292     $index           = Maasha::UCSC::phastcons_index_retrieve( $phastcons_index );
4293     $fh_phastcons    = Maasha::Common::read_open( $phastcons_file );
4294
4295     while ( $record = get_record( $in ) ) 
4296     {
4297         if ( $record->{ "CHR" } and $record->{ "CHR_BEG" } and $record->{ "CHR_END" } )
4298         {
4299             $scores = Maasha::UCSC::phastcons_index_lookup( $index, $fh_phastcons, $record->{ "CHR" }, $record->{ "CHR_BEG" }, $record->{ "CHR_END" }, $options->{ "flank" } );
4300
4301             push @{ $AoA }, [ @{ $scores } ];
4302         }
4303
4304         put_record( $record, $out ) if not $options->{ "no_stream" };
4305     }
4306
4307     Maasha::UCSC::phastcons_normalize( $AoA );
4308
4309     $AoA = [ [ Maasha::UCSC::phastcons_mean( $AoA ) ] ] if $options->{ "mean" };
4310     $AoA = [ [ Maasha::UCSC::phastcons_median( $AoA ) ] ] if $options->{ "median" };
4311
4312     $AoA = Maasha::Matrix::matrix_flip( $AoA );
4313
4314     $plot = Maasha::Plot::lineplot_simple( $AoA, $options, $BP_TMP );
4315
4316     $fh = write_stream( $options->{ "data_out" } );
4317
4318     print $fh "$_\n" foreach @{ $plot };
4319
4320     close $fh;
4321 }
4322
4323
4324 sub script_analyze_bed
4325 {
4326     # Martin A. Hansen, March 2008.
4327
4328     # Analyze BED entries in stream.
4329
4330     my ( $in,        # handle to in stream
4331          $out,       # handle to out stream
4332          $options,   # options hash
4333        ) = @_;
4334
4335     # Returns nothing.
4336
4337     my ( $record );
4338
4339     while ( $record = get_record( $in ) ) 
4340     {
4341         $record = Maasha::UCSC::bed_analyze( $record ) if $record->{ "REC_TYPE" } eq "BED";
4342
4343         put_record( $record, $out );
4344     }
4345 }
4346
4347
4348 sub script_analyze_vals
4349 {
4350     # Martin A. Hansen, August 2007.
4351
4352     # Analyze values for given keys in stream.
4353
4354     my ( $in,        # handle to in stream
4355          $out,       # handle to out stream
4356          $options,   # options hash
4357        ) = @_;
4358
4359     # Returns nothing.
4360
4361     my ( $record, $key, @keys, %key_hash, $analysis, $len );
4362
4363     map { $key_hash{ $_ } = 1 } @{ $options->{ "keys" } };
4364
4365     while ( $record = get_record( $in ) ) 
4366     {
4367         foreach $key ( keys %{ $record } )
4368         {
4369             next if $options->{ "keys" } and not exists $key_hash{ $key };
4370
4371             $analysis->{ $key }->{ "COUNT" }++;
4372
4373             if ( Maasha::Calc::is_a_number( $record->{ $key } ) )
4374             {
4375                 $analysis->{ $key }->{ "TYPE" } = "num";
4376                 $analysis->{ $key }->{ "SUM" } += $record->{ $key };
4377                 $analysis->{ $key }->{ "MAX" } = $record->{ $key } if $record->{ $key } > $analysis->{ $key }->{ "MAX" } or not $analysis->{ $key }->{ "MAX" };
4378                 $analysis->{ $key }->{ "MIN" } = $record->{ $key } if $record->{ $key } < $analysis->{ $key }->{ "MIN" } or not $analysis->{ $key }->{ "MIN" };
4379             }
4380             else
4381             {
4382                 $len = length $record->{ $key };
4383
4384                 $analysis->{ $key }->{ "TYPE" } = "alph";
4385                 $analysis->{ $key }->{ "SUM" } += $len;
4386                 $analysis->{ $key }->{ "MAX" } = $len if $len > $analysis->{ $key }->{ "MAX" } or not $analysis->{ $key }->{ "MAX" };
4387                 $analysis->{ $key }->{ "MIN" } = $len if $len < $analysis->{ $key }->{ "MIM" } or not $analysis->{ $key }->{ "MIN" };
4388             }
4389         }
4390
4391         put_record( $record, $out ) if not $options->{ "no_stream" };
4392     }
4393
4394     foreach $key ( keys %{ $analysis } )
4395     {
4396         $analysis->{ $key }->{ "MEAN" } = sprintf "%.2f", $analysis->{ $key }->{ "SUM" } / $analysis->{ $key }->{ "COUNT" };
4397         $analysis->{ $key }->{ "SUM" }  = sprintf "%.2f", $analysis->{ $key }->{ "SUM" };
4398     }
4399
4400     my ( $keys, $types, $counts, $mins, $maxs, $sums, $means );
4401
4402     $keys   = "KEY  ";
4403     $types  = "TYPE ";
4404     $counts = "COUNT";
4405     $mins   = "MIN  ";
4406     $maxs   = "MAX  ";
4407     $sums   = "SUM  ";
4408     $means  = "MEAN ";
4409
4410     if ( $options->{ "keys" } ) {
4411         @keys = @{ $options->{ "keys" } };
4412     } else {
4413         @keys = keys %{ $analysis };
4414     }
4415
4416     foreach $key ( @keys )
4417     {
4418         $keys   .= sprintf "% 15s", $key;
4419         $types  .= sprintf "% 15s", $analysis->{ $key }->{ "TYPE" };
4420         $counts .= sprintf "% 15s", $analysis->{ $key }->{ "COUNT" };
4421         $mins   .= sprintf "% 15s", $analysis->{ $key }->{ "MIN" };
4422         $maxs   .= sprintf "% 15s", $analysis->{ $key }->{ "MAX" };
4423         $sums   .= sprintf "% 15s", $analysis->{ $key }->{ "SUM" };
4424         $means  .= sprintf "% 15s", $analysis->{ $key }->{ "MEAN" };
4425     }
4426
4427     print $out "$keys\n";
4428     print $out "$types\n";
4429     print $out "$counts\n";
4430     print $out "$mins\n";
4431     print $out "$maxs\n";
4432     print $out "$sums\n";
4433     print $out "$means\n";
4434 }
4435
4436
4437 sub script_head_records
4438 {
4439     # Martin A. Hansen, August 2007.
4440
4441     # Display the first sequences in stream.
4442
4443     my ( $in,        # handle to in stream
4444          $out,       # handle to out stream
4445          $options,   # options hash
4446        ) = @_;
4447
4448     # Returns nothing.
4449
4450     my ( $record, $count );
4451
4452     $options->{ "num" } ||= 10;
4453
4454     $count = 0;
4455
4456     while ( $record = get_record( $in ) ) 
4457     {
4458         $count++;
4459
4460         put_record( $record, $out );
4461
4462         last if $count == $options->{ "num" };
4463     }
4464 }
4465
4466
4467 sub script_remove_keys
4468 {
4469     # Martin A. Hansen, August 2007.
4470
4471     # Remove keys from stream.
4472
4473     my ( $in,        # handle to in stream
4474          $out,       # handle to out stream
4475          $options,   # options hash
4476        ) = @_;
4477
4478     # Returns nothing.
4479
4480     my ( $record, $new_record );
4481
4482     while ( $record = get_record( $in ) ) 
4483     {
4484         if ( $options->{ "keys" } )
4485         {
4486             map { delete $record->{ $_ } } @{ $options->{ "keys" } };
4487         }
4488         elsif ( $options->{ "save_keys" } )
4489         {
4490             map { $new_record->{ $_ } = $record->{ $_ } if exists $record->{ $_ } } @{ $options->{ "save_keys" } };
4491
4492             $record = $new_record;
4493         }
4494
4495         put_record( $record, $out ) if keys %{ $record };
4496     }
4497 }
4498
4499
4500 sub script_rename_keys
4501 {
4502     # Martin A. Hansen, August 2007.
4503
4504     # Rename keys in stream.
4505
4506     my ( $in,        # handle to in stream
4507          $out,       # handle to out stream
4508          $options,   # options hash
4509        ) = @_;
4510
4511     # Returns nothing.
4512
4513     my ( $record );
4514
4515     while ( $record = get_record( $in ) ) 
4516     {
4517         if ( exists $record->{ $options->{ "keys" }->[ 0 ] } )
4518         {
4519             $record->{ $options->{ "keys" }->[ 1 ] } = $record->{ $options->{ "keys" }->[ 0 ] };
4520
4521             delete $record->{ $options->{ "keys" }->[ 0 ] };
4522         }
4523
4524         put_record( $record, $out );
4525     }
4526 }
4527
4528
4529 sub script_uniq_vals
4530 {
4531     # Martin A. Hansen, August 2007.
4532
4533     # Find unique values in stream.
4534
4535     my ( $in,        # handle to in stream
4536          $out,       # handle to out stream
4537          $options,   # options hash
4538        ) = @_;
4539
4540     # Returns nothing.
4541
4542     my ( %hash, $record );
4543
4544     while ( $record = get_record( $in ) ) 
4545     {
4546         if ( $record->{ $options->{ "key" } } )
4547         {
4548             if ( not $hash{ $record->{ $options->{ "key" } } } and not $options->{ "invert" } )
4549             {
4550                 put_record( $record, $out );
4551
4552                 $hash{ $record->{ $options->{ "key" } } } = 1;
4553             }
4554             elsif ( $hash{ $record->{ $options->{ "key" } } } and $options->{ "invert" } )
4555             {
4556                 put_record( $record, $out );
4557             }
4558             else
4559             {
4560                 $hash{ $record->{ $options->{ "key" } } } = 1;
4561             }
4562         }
4563         else
4564         {
4565             put_record( $record, $out );
4566         }
4567     }
4568 }
4569
4570
4571 sub script_merge_vals
4572 {
4573     # Martin A. Hansen, August 2007.
4574
4575     # Rename keys in stream.
4576
4577     my ( $in,        # handle to in stream
4578          $out,       # handle to out stream
4579          $options,   # options hash
4580        ) = @_;
4581
4582     # Returns nothing.
4583
4584     my ( $record, @join, $i );
4585
4586     $options->{ "delimit" } ||= '_';
4587
4588     while ( $record = get_record( $in ) ) 
4589     {
4590         if ( exists $record->{ $options->{ "keys" }->[ 0 ] } )
4591         {
4592             @join = $record->{ $options->{ "keys" }->[ 0 ] };
4593             
4594             for ( $i = 1; $i < @{ $options->{ "keys" } }; $i++ ) {
4595                 push @join, $record->{ $options->{ "keys" }->[ $i ] } if exists $record->{ $options->{ "keys" }->[ $i ] };
4596             }
4597
4598             $record->{ $options->{ "keys" }->[ 0 ] } = join $options->{ "delimit" }, @join;
4599         }
4600
4601         put_record( $record, $out );
4602     }
4603 }
4604
4605
4606 sub script_merge_records
4607 {
4608     # Martin A. Hansen, July 2008.
4609
4610     # Merges records in the stream based on identical values of two given keys.
4611
4612     my ( $in,        # handle to in stream
4613          $out,       # handle to out stream
4614          $options,   # options hash
4615        ) = @_;
4616
4617     # Returns nothing.
4618
4619     my ( $merge, $record, $file1, $file2, $fh1, $fh2, $key1, $key2, @keys1, @keys2, @vals1, @vals2,
4620          $num1, $num2, $num, $cmp, $i );
4621
4622     $merge = $options->{ "merge" } || "AandB";
4623
4624     $file1 = "$BP_TMP/merge_records1.tmp";
4625     $file2 = "$BP_TMP/merge_records2.tmp";
4626
4627     $fh1   = Maasha::Common::write_open( $file1 );
4628     $fh2   = Maasha::Common::write_open( $file2 );
4629
4630     $key1  = $options->{ "keys" }->[ 0 ];
4631     $key2  = $options->{ "keys" }->[ 1 ];
4632
4633     $num   = $key2 =~ s/n$//;
4634     $num1  = 0;
4635     $num2  = 0;
4636
4637     while ( $record = get_record( $in ) ) 
4638     {
4639         if ( exists $record->{ $key1 } )
4640         {
4641             @keys1 = $key1;
4642             @vals1 = $record->{ $key1 };
4643
4644             delete $record->{ $key1 };
4645
4646             map { push @keys1, $_; push @vals1, $record->{ $_ } } keys %{ $record };
4647
4648             print $fh1 join( "\t", @vals1 ), "\n";
4649
4650             $num1++;
4651         }
4652         elsif ( exists $record->{ $key2 } )
4653         {
4654             @keys2 = $key2;
4655             @vals2 = $record->{ $key2 };
4656
4657             delete $record->{ $key2 };
4658
4659             map { push @keys2, $_; push @vals2, $record->{ $_ } } keys %{ $record };
4660
4661             print $fh2 join( "\t", @vals2 ), "\n";
4662
4663             $num2++;
4664         }
4665     }
4666
4667     close $fh1;
4668     close $fh2;
4669
4670     if ( $num )
4671     {
4672         Maasha::Common::run( "sort", "-k 1,1n $file1 > $file1.sort" ) and rename "$file1.sort", $file1;
4673         Maasha::Common::run( "sort", "-k 1,1n $file2 > $file2.sort" ) and rename "$file2.sort", $file2;
4674     }
4675     else
4676     {
4677         Maasha::Common::run( "sort", "-k 1,1 $file1 > $file1.sort" ) and rename "$file1.sort", $file1;
4678         Maasha::Common::run( "sort", "-k 1,1 $file2 > $file2.sort" ) and rename "$file2.sort", $file2;
4679     }
4680
4681     $fh1 = Maasha::Common::read_open( $file1 );
4682     $fh2 = Maasha::Common::read_open( $file2 );
4683
4684     @vals1 = Maasha::Common::get_fields( $fh1 );
4685     @vals2 = Maasha::Common::get_fields( $fh2 );
4686
4687     while ( $num1 > 0 and $num2 > 0 )
4688     {
4689         undef $record;
4690
4691         if ( $num ) {
4692             $cmp = $vals1[ 0 ] <=> $vals2[ 0 ];
4693         } else {
4694             $cmp = $vals1[ 0 ] cmp $vals2[ 0 ];
4695         }
4696
4697         if ( $cmp < 0 )
4698         {
4699             if ( $merge =~ /^(AorB|AnotB)$/ )
4700             {
4701                 for ( $i = 0; $i < @keys1; $i++ ) {
4702                     $record->{ $keys1[ $i ] } = $vals1[ $i ];
4703                 }
4704
4705                 put_record( $record, $out );
4706             }
4707
4708             @vals1 = Maasha::Common::get_fields( $fh1 );
4709             $num1--;
4710         }
4711         elsif ( $cmp > 0 )
4712         {
4713             if ( $merge =~ /^(BorA|BnotA)$/ )
4714             {
4715                 for ( $i = 0; $i < @keys2; $i++ ) {
4716                     $record->{ $keys2[ $i ] } = $vals2[ $i ];
4717                 }
4718
4719                 put_record( $record, $out );
4720             }
4721
4722             @vals2 = Maasha::Common::get_fields( $fh2 );
4723             $num2--;
4724         }
4725         else
4726         {
4727             if ( $merge =~ /^(AandB|AorB|BorA)$/ )
4728             {
4729                 for ( $i = 0; $i < @keys1; $i++ ) {
4730                     $record->{ $keys1[ $i ] } = $vals1[ $i ];
4731                 }
4732
4733                 for ( $i = 1; $i < @keys2; $i++ ) {
4734                     $record->{ $keys2[ $i ] } = $vals2[ $i ];
4735                 }
4736             
4737                 put_record( $record, $out );
4738             }
4739
4740             @vals1 = Maasha::Common::get_fields( $fh1 );
4741             @vals2 = Maasha::Common::get_fields( $fh2 );
4742             $num1--;
4743             $num2--;
4744         }
4745     }
4746
4747     close $fh1;
4748     close $fh2;
4749
4750     unlink $file1;
4751     unlink $file2;
4752
4753     if ( $num1 > 0 and $merge =~ /^(AorB|AnotB)$/ )
4754     {
4755         undef $record;
4756
4757         for ( $i = 0; $i < @keys1; $i++ ) {
4758             $record->{ $keys1[ $i ] } = $vals1[ $i ];
4759         }
4760
4761         put_record( $record, $out );
4762     }
4763
4764     if ( $num2 > 0 and $merge =~ /^(BorA|BnotA)$/ )
4765     {
4766         undef $record;
4767
4768         for ( $i = 0; $i < @keys2; $i++ ) {
4769             $record->{ $keys2[ $i ] } = $vals2[ $i ];
4770         }
4771
4772         put_record( $record, $out );
4773     }
4774 }
4775
4776
4777 sub script_grab
4778 {
4779     # Martin A. Hansen, August 2007.
4780
4781     # Grab for records in stream.
4782
4783     my ( $in,        # handle to in stream
4784          $out,       # handle to out stream
4785          $options,   # options hash
4786        ) = @_;
4787
4788     # Returns nothing.
4789
4790     my ( $patterns, $pattern, $record, $key, $pos, $op, $val, %lookup_hash );
4791
4792     if ( $options->{ "patterns" } )
4793     {
4794         $patterns = [ split ",", $options->{ "patterns" } ];
4795     }
4796     elsif ( -f $options->{ "patterns_in" } )
4797     {
4798         $patterns = Maasha::Patscan::read_patterns( $options->{ "patterns_in" } );
4799     }
4800     elsif ( -f $options->{ "exact_in" } )
4801     {
4802         $patterns = Maasha::Patscan::read_patterns( $options->{ "exact_in" } );
4803
4804         map { $lookup_hash{ $_ } = 1 } @{ $patterns };
4805
4806         undef $patterns;
4807     }
4808
4809     if ( $options->{ "eval" } )
4810     {
4811         if ( $options->{ "eval" } =~ /^([^><=! ]+)\s*(>=|<=|>|<|=|!=|eq|ne)\s*(.+)$/ )
4812         {
4813             $key = $1;
4814             $op  = $2;
4815             $val = $3;
4816         }
4817     } 
4818
4819     while ( $record = get_record( $in ) ) 
4820     {
4821         $pos = -1;
4822         
4823         if ( %lookup_hash )
4824         {
4825             if ( $options->{ "keys" } )
4826             {
4827                 foreach $key ( @{ $options->{ "keys" } } )
4828                 {
4829                     if ( exists $lookup_hash{ $record->{ $key } } )
4830                     {
4831                         $pos = 1;
4832                         goto FOUND;
4833                     }
4834                 }
4835             }
4836             else
4837             {
4838                 foreach $key ( keys %{ $record } )
4839                 {
4840                     if ( not $options->{ "vals_only" } )
4841                     {
4842                         if ( exists $lookup_hash{ $key } )
4843                         {
4844                             $pos = 1;
4845                             goto FOUND;
4846                         }
4847                     }
4848
4849                     if ( not $options->{ "keys_only" } )
4850                     {
4851                         if ( exists $lookup_hash{ $record->{ $key } } )
4852                         {
4853                             $pos = 1;
4854                             goto FOUND;
4855                         }
4856                     }
4857                 }
4858             }
4859         }
4860         elsif ( $patterns )
4861         {
4862             foreach $pattern ( @{ $patterns } )
4863             {
4864                 if ( $options->{ "keys" } )
4865                 {
4866                     foreach $key ( @{ $options->{ "keys" } } )
4867                     {
4868                         $pos = index $record->{ $key }, $pattern;
4869
4870                         goto FOUND if $pos >= 0;
4871                     }
4872                 }
4873                 else
4874                 {
4875                     foreach $key ( keys %{ $record } )
4876                     {
4877                         if ( not $options->{ "vals_only" } )
4878                         {
4879                             $pos = index $key, $pattern;
4880
4881                             goto FOUND if $pos >= 0;
4882                         }
4883
4884                         if ( not $options->{ "keys_only" } )
4885                         {
4886                             $pos = index $record->{ $key }, $pattern;
4887
4888                             goto FOUND if $pos >= 0;
4889                         }
4890                     }
4891                 }
4892             }
4893         }
4894         elsif ( $options->{ "regex" } )
4895         {
4896             if ( $options->{ "keys" } )
4897             {
4898                 foreach $key ( @{ $options->{ "keys" } } )
4899                 {
4900                     if ( $options->{ "case_insensitive" } ) {
4901                         $pos = 1 if $record->{ $key } =~ /$options->{'regex'}/i;
4902                     } else {
4903                         $pos = 1 if $record->{ $key } =~ /$options->{'regex'}/;
4904                     }
4905
4906                     goto FOUND if $pos >= 0;
4907                 }
4908             }
4909             else
4910             {
4911                 foreach $key ( keys %{ $record } )
4912                 {
4913                     if ( not $options->{ "vals_only" } )
4914                     {
4915                         if ( $options->{ "case_insensitive" } ) {
4916                             $pos = 1 if $key =~ /$options->{'regex'}/i;
4917                         } else {
4918                             $pos = 1 if $key =~ /$options->{'regex'}/;
4919                         }
4920
4921                         goto FOUND if $pos >= 0;
4922                     }
4923
4924                     if ( not $options->{ "keys_only" } )
4925                     {
4926                         if ( $options->{ "case_insensitive" } ) {
4927                             $pos = 1 if $record->{ $key } =~ /$options->{'regex'}/i;
4928                         } else {
4929                             $pos = 1 if $record->{ $key } =~ /$options->{'regex'}/;
4930                         }
4931
4932                         goto FOUND if $pos >= 0;
4933                     }
4934                 }
4935             }
4936         }
4937         elsif ( $options->{ "eval" } )
4938         {
4939             if ( defined $record->{ $key } ) 
4940             {
4941                 if ( $op eq "<" and $record->{ $key } < $val ) {
4942                     $pos = 1 and goto FOUND;
4943                 } elsif ( $op eq ">" and $record->{ $key } > $val ) {
4944                     $pos = 1 and goto FOUND;
4945                 } elsif ( $op eq ">=" and $record->{ $key } >= $val ) {
4946                     $pos = 1 and goto FOUND;
4947                 } elsif ( $op eq "<=" and $record->{ $key } <= $val ) {
4948                     $pos = 1 and goto FOUND;
4949                 } elsif ( $op eq "=" and $record->{ $key } == $val ) {
4950                     $pos = 1 and goto FOUND;
4951                 } elsif ( $op eq "!=" and $record->{ $key } != $val ) {
4952                     $pos = 1 and goto FOUND;
4953                 } elsif ( $op eq "eq" and $record->{ $key } eq $val ) {
4954                     $pos = 1 and goto FOUND;
4955                 } elsif ( $op eq "ne" and $record->{ $key } ne $val ) {
4956                     $pos = 1 and goto FOUND;
4957                 }
4958             }
4959         }
4960
4961         FOUND:
4962
4963         if ( $pos >= 0 and not $options->{ "invert" } ) {
4964             put_record( $record, $out );
4965         } elsif ( $pos < 0 and $options->{ "invert" } ) {
4966             put_record( $record, $out );
4967         }
4968     }
4969 }
4970
4971
4972 sub script_compute
4973 {
4974     # Martin A. Hansen, August 2007.
4975
4976     # Evaluate extression for records in stream.
4977
4978     my ( $in,        # handle to in stream
4979          $out,       # handle to out stream
4980          $options,   # options hash
4981        ) = @_;
4982
4983     # Returns nothing.
4984
4985     my ( $record, $eval_key, $eval_val, $check, @keys );
4986
4987     while ( $record = get_record( $in ) ) 
4988     {
4989         if ( $options->{ "eval" } )
4990         {
4991             if ( $options->{ "eval" } =~ /^(.+)\s*=\s*(.+)$/ )
4992             {
4993                 $eval_key = $1;
4994                 $eval_val = $2;
4995             }
4996
4997             if ( not $check )
4998             {
4999                 @keys = split /\W+/, $eval_val;
5000                 @keys = grep { ! /^\d+$/ } @keys;
5001
5002                 $check = 1;
5003             }
5004
5005             map { $eval_val =~ s/$_/$record->{ $_ }/g } @keys;
5006
5007             $record->{ $eval_key } = eval "$eval_val" or Maasha::Common::error( "eval failed -> $@" );
5008         } 
5009
5010         put_record( $record, $out );
5011     }
5012 }
5013
5014
5015 sub script_flip_tab
5016 {
5017     # Martin A. Hansen, June 2008.
5018
5019     # Flip a table.
5020
5021     my ( $in,        # handle to in stream
5022          $out,       # handle to out stream
5023          $options,   # options hash
5024        ) = @_;
5025
5026     # Returns nothing.
5027
5028     my ( $record, $key, $A, $B, @rows, @matrix, $row, $i );
5029
5030     while ( $record = get_record( $in ) ) 
5031     {
5032         undef @rows;
5033
5034         foreach $key ( sort { $A = $a; $B = $b; $A =~ s/^V(\d+)$/$1/; $B =~ s/^V(\d+)$/$1/; $A <=> $B } keys %{ $record } )
5035         {
5036             push @rows, $record->{ $key };
5037
5038         }
5039
5040         push @matrix, [ @rows ];
5041     }
5042
5043     undef $record;
5044
5045     @matrix = Maasha::Matrix::matrix_flip( \@matrix );
5046
5047     foreach $row ( @matrix )
5048     {
5049         for ( $i = 0; $i < @{ $row }; $i++ ) {
5050             $record->{ "V$i" } = $row->[ $i ];
5051         }
5052
5053         put_record( $record, $out );
5054     }
5055 }
5056
5057
5058 sub script_add_ident
5059 {
5060     # Martin A. Hansen, May 2008.
5061
5062     # Add a unique identifier to each record in stream.
5063
5064     my ( $in,        # handle to in stream
5065          $out,       # handle to out stream
5066          $options,   # options hash
5067        ) = @_;
5068
5069     # Returns nothing.
5070
5071     my ( $record, $key, $prefix, $i );
5072
5073     $key    = $options->{ "key" }    || "ID";
5074     $prefix = $options->{ "prefix" } || "ID";
5075
5076     $i = 0;
5077
5078     while ( $record = get_record( $in ) ) 
5079     {
5080         $record->{ $key } = sprintf( "$prefix%08d", $i );
5081
5082         put_record( $record, $out );
5083
5084         $i++;
5085     }
5086 }
5087
5088
5089 sub script_count_records
5090 {
5091     # Martin A. Hansen, August 2007.
5092
5093     # Count records in stream.
5094
5095     my ( $in,        # handle to in stream
5096          $out,       # handle to out stream
5097          $options,   # options hash
5098        ) = @_;
5099
5100     # Returns nothing.
5101
5102     my ( $record, $count, $result, $fh, $line );
5103
5104     $count = 0;
5105
5106     if ( $options->{ "no_stream" } )
5107     {
5108         while ( $line = <$in> )
5109         {
5110             chomp $line;
5111
5112             $count++ if $line eq "---";
5113         }
5114     }
5115     else
5116     {
5117         while ( $record = get_record( $in ) ) 
5118         {
5119             put_record( $record, $out );
5120
5121             $count++;
5122         }
5123     }
5124
5125     $result = { "RECORDS_COUNT" => $count };
5126
5127     $fh = write_stream( $options->{ "data_out" } );
5128
5129     put_record( $result, $fh );
5130
5131     close $fh;
5132 }
5133
5134
5135 sub script_random_records
5136 {
5137     # Martin A. Hansen, August 2007.
5138
5139     # Pick a number or random records from stream.
5140
5141     my ( $in,        # handle to in stream
5142          $out,       # handle to out stream
5143          $options,   # options hash
5144        ) = @_;
5145
5146     # Returns nothing.
5147
5148     my ( $record, $tmp_file, $fh_out, $fh_in, $count, $i, %rand_hash, $rand, $max );
5149
5150     $options->{ "num" } ||= 10;
5151
5152     $tmp_file = "$BP_TMP/random_records.tmp";
5153
5154     $fh_out = Maasha::Common::write_open( $tmp_file );
5155
5156     $count = 0;
5157
5158     while ( $record = get_record( $in ) ) 
5159     {
5160         put_record( $record, $fh_out );
5161
5162         $count++;
5163     }
5164
5165     close $fh_out;
5166
5167     $max = 0;
5168     $i   = 0;
5169
5170     Maasha::Common::error( qq(Requested random records > records in stream) ) if $options->{ "num" } > $count;
5171
5172     while ( $i < $options->{ "num" } )
5173     {
5174         $rand = int( rand( $count ) );
5175     
5176         if ( not exists $rand_hash{ $rand } )
5177         {
5178             $rand_hash{ $rand } = 1;
5179
5180             $max = $rand if $rand > $max;
5181
5182             $i++;
5183         }
5184     }
5185
5186     $fh_in = Maasha::Common::read_open( $tmp_file );
5187
5188     $count = 0;
5189
5190     while ( $record = get_record( $fh_in ) ) 
5191     {
5192         put_record( $record, $out ) if exists $rand_hash{ $count };
5193
5194         last if $count == $max;
5195
5196         $count++;
5197     }
5198
5199     close $fh_in;
5200
5201     unlink $tmp_file;
5202 }
5203
5204
5205 sub script_sort_records
5206 {
5207     # Martin A. Hansen, August 2007.
5208
5209     # Sort to sort records according to keys.
5210
5211     my ( $in,        # handle to in stream
5212          $out,       # handle to out stream
5213          $options,   # options hash
5214        ) = @_;
5215
5216     # Returns nothing.
5217
5218     my ( @keys, $key, @sort_cmd, $sort_str, $sort_sub, @records, $record, $i );
5219
5220     foreach $key ( @{ $options->{ "keys" } } )
5221     {
5222         if ( $key =~ s/n$// ) {
5223             push @sort_cmd, qq(\$a->{ "$key" } <=> \$b->{ "$key" });
5224         } else {
5225             push @sort_cmd, qq(\$a->{ "$key" } cmp \$b->{ "$key" });
5226         }
5227     }
5228
5229     $sort_str = join " or ", @sort_cmd;
5230     $sort_sub = eval "sub { $sort_str }";   # NB security issue!
5231
5232     while ( $record = get_record( $in ) ) {
5233         push @records, $record;
5234     }
5235
5236     @records = sort $sort_sub @records;
5237
5238     if ( $options->{ "reverse" } )
5239     {
5240         for ( $i = scalar @records - 1; $i >= 0; $i-- ) {
5241             put_record( $records[ $i ], $out );
5242         }
5243     }
5244     else
5245     {
5246         for ( $i = 0; $i < scalar @records; $i++ ) {
5247             put_record( $records[ $i ], $out );
5248         }
5249     }
5250 }
5251
5252
5253 sub script_count_vals
5254 {
5255     # Martin A. Hansen, August 2007.
5256
5257     # Count records in stream.
5258
5259     my ( $in,        # handle to in stream
5260          $out,       # handle to out stream
5261          $options,   # options hash
5262        ) = @_;
5263
5264     # Returns nothing.
5265
5266     my ( $num, $record, %count_hash, @records, $tmp_file, $fh_out, $fh_in, $cache );
5267
5268     $tmp_file = "$BP_TMP/count_cache.tmp";
5269
5270     $fh_out   = Maasha::Common::write_open( $tmp_file );
5271
5272     $cache    = 0;
5273     $num      = 0;
5274
5275     while ( $record = get_record( $in ) ) 
5276     {
5277         map { $count_hash{ $_ }{ $record->{ $_ } }++ if exists $record->{ $_ } } @{ $options->{ "keys" } };
5278
5279         push @records, $record;
5280
5281         if ( scalar @records > 5_000_000 )   # too many records to hold in memory - use disk cache
5282         {
5283             map { put_record( $_, $fh_out ) } @records;
5284
5285             undef @records;
5286
5287             $cache = 1;
5288         }
5289
5290         print STDERR "verbose: records read $num\n" if ( $options->{ 'verbose' } and ( $num % 1_000_000 ) == 0 );
5291
5292         $num++;
5293     }
5294
5295     close $fh_out;
5296
5297     if ( $cache )
5298     {
5299         $num   = 0;
5300
5301         $fh_in = Maasha::Common::read_open( $tmp_file );
5302
5303         while ( $record = get_record( $fh_in ) )
5304         {
5305             map { $record->{ $_ . "_COUNT" } = $count_hash{ $_ }{ $record->{ $_ } } if exists $record->{ $_ } } @{ $options->{ "keys" } };
5306
5307             put_record( $record, $out );
5308
5309             print STDERR "verbose: cache read $num\n" if ( $options->{ 'verbose' } and ( $num % 1_000_000 ) == 0 );
5310
5311             $num++;
5312         }
5313     
5314         close $fh_in;
5315     }
5316
5317     foreach $record ( @records )
5318     {
5319         map { $record->{ $_ . "_COUNT" } = $count_hash{ $_ }{ $record->{ $_ } } if exists $record->{ $_ } } @{ $options->{ "keys" } };
5320
5321         put_record( $record, $out );
5322     }
5323
5324     unlink $tmp_file;
5325 }
5326
5327
5328 sub script_plot_histogram
5329 {
5330     # Martin A. Hansen, September 2007.
5331
5332     # Plot a simple histogram for a given key using GNU plot.
5333
5334     my ( $in,        # handle to in stream
5335          $out,       # handle to out stream
5336          $options,   # options hash
5337        ) = @_;
5338
5339     # Returns nothing.
5340
5341     my ( $record, %data_hash, $max, @data_list, $i, $result, $fh );
5342
5343     $options->{ "title" } ||= "Histogram";
5344     $options->{ "sort" }  ||= "num";
5345
5346     while ( $record = get_record( $in ) ) 
5347     {
5348         $data_hash{ $record->{ $options->{ "key" } } }++ if $record->{ $options->{ "key" } };
5349
5350         put_record( $record, $out ) if not $options->{ "no_stream" };
5351     }
5352
5353     if ( $options->{ "sort" } eq "num" ) {
5354         map { push @data_list, [ $_, $data_hash{ $_ } ] } sort { $a <=> $b } keys %data_hash;
5355     } else {
5356         map { push @data_list, [ $_, $data_hash{ $_ } ] } sort keys %data_hash;
5357     }
5358
5359     $result = Maasha::Plot::histogram_simple( \@data_list, $options );
5360
5361     $fh = write_stream( $options->{ "data_out" } );
5362
5363     print $fh "$_\n" foreach @{ $result };
5364
5365     close $fh;
5366 }
5367
5368
5369 sub script_plot_lendist
5370 {
5371     # Martin A. Hansen, August 2007.
5372
5373     # Plot length distribution using GNU plot.
5374
5375     my ( $in,        # handle to in stream
5376          $out,       # handle to out stream
5377          $options,   # options hash
5378        ) = @_;
5379
5380     # Returns nothing.
5381
5382     my ( $record, %data_hash, $max, @data_list, $i, $result, $fh );
5383
5384     $options->{ "title" } ||= "Length Distribution";
5385
5386     while ( $record = get_record( $in ) ) 
5387     {
5388         $data_hash{ $record->{ $options->{ "key" } } }++ if $record->{ $options->{ "key" } };
5389
5390         put_record( $record, $out ) if not $options->{ "no_stream" };
5391     }
5392
5393     $max = Maasha::Calc::list_max( [ keys %data_hash ] );
5394
5395     for ( $i = 0; $i < $max; $i++ ) {
5396         push @data_list, [ $i, $data_hash{ $i } || 0 ];
5397     }
5398
5399     $result = Maasha::Plot::histogram_lendist( \@data_list, $options );
5400
5401     $fh = write_stream( $options->{ "data_out" } );
5402
5403     print $fh "$_\n" foreach @{ $result };
5404
5405     close $fh;
5406 }
5407
5408
5409 sub script_plot_chrdist
5410 {
5411     # Martin A. Hansen, August 2007.
5412
5413     # Plot chromosome distribution using GNU plot.
5414
5415     my ( $in,        # handle to in stream
5416          $out,       # handle to out stream
5417          $options,   # options hash
5418        ) = @_;
5419
5420     # Returns nothing.
5421
5422     my ( $record, %data_hash, @data_list, $elem, $sort_key, $count, $result, $fh );
5423
5424     $options->{ "title" } ||= "Chromosome Distribution";
5425
5426     while ( $record = get_record( $in ) ) 
5427     {
5428         if ( $record->{ "CHR" } ) {                                                             # generic
5429             $data_hash{ $record->{ "CHR" } }++;
5430         } elsif ( $record->{ "REC_TYPE" } eq "PATSCAN" and $record->{ "S_ID" } =~ /^chr/i ) {   # patscan
5431             $data_hash{ $record->{ "S_ID" } }++;
5432         } elsif ( $record->{ "REC_TYPE" } eq "PSL" and $record->{ "S_ID" } =~ /^chr/i ) {       # BLAT / PSL
5433             $data_hash{ $record->{ "S_ID" } }++;
5434         } elsif ( $record->{ "REC_TYPE" } eq "BLAST" and $record->{ "S_ID" } =~ /^chr/i ) {     # BLAST
5435             $data_hash{ $record->{ "S_ID" } }++;
5436         }
5437
5438         put_record( $record, $out ) if not $options->{ "no_stream" };
5439     }
5440
5441     foreach $elem ( keys %data_hash )
5442     {
5443         $sort_key = $elem;
5444
5445         $sort_key =~ s/chr//i;
5446     
5447         $sort_key =~ s/^X(.*)/99$1/;
5448         $sort_key =~ s/^Y(.*)/99$1/;
5449         $sort_key =~ s/^Z(.*)/999$1/;
5450         $sort_key =~ s/^M(.*)/9999$1/;
5451         $sort_key =~ s/^U(.*)/99999$1/;
5452
5453         $count = $sort_key =~ tr/_//;
5454
5455         $sort_key =~ s/_.*/"999999" x $count/ex;
5456
5457         push @data_list, [ $elem, $data_hash{ $elem }, $sort_key ];
5458     }
5459
5460     @data_list = sort { $a->[ 2 ] <=> $b->[ 2 ] } @data_list;
5461
5462     $result = Maasha::Plot::histogram_chrdist( \@data_list, $options );
5463
5464     $fh = write_stream( $options->{ "data_out" } );
5465
5466     print $fh "$_\n" foreach @{ $result };
5467
5468     close $fh;
5469 }
5470
5471
5472 sub script_plot_karyogram
5473 {
5474     # Martin A. Hansen, August 2007.
5475
5476     # Plot hits on karyogram.
5477
5478     my ( $in,        # handle to in stream
5479          $out,       # handle to out stream
5480          $options,   # options hash
5481        ) = @_;
5482
5483     # Returns nothing.
5484
5485     my ( %options, $record, @data, $fh, $result, %data_hash );
5486
5487     $options->{ "genome" }     ||= "human";
5488     $options->{ "feat_color" } ||= "black";
5489
5490     while ( $record = get_record( $in ) ) 
5491     {
5492         if ( $record->{ "CHR" } and $record->{ "CHR_BEG" } and $record->{ "CHR_END" } )
5493         {
5494             push @{ $data_hash{ $record->{ "CHR" } } }, [ $record->{ "CHR_BEG" }, $record->{ "CHR_END" }, $options->{ "feat_color" } ];
5495         }
5496
5497         put_record( $record, $out ) if not $options->{ "no_stream" };
5498     }
5499
5500     $result = Maasha::Plot::karyogram( \%data_hash, \%options );
5501
5502     $fh = write_stream( $options->{ "data_out" } );
5503
5504     print $fh $result;
5505
5506     close $fh;
5507 }
5508
5509
5510 sub script_plot_matches
5511 {
5512     # Martin A. Hansen, August 2007.
5513
5514     # Plot matches in 2D generating a dotplot.
5515
5516     my ( $in,        # handle to in stream
5517          $out,       # handle to out stream
5518          $options,   # options hash
5519        ) = @_;
5520
5521     # Returns nothing.
5522
5523     my ( $record, @data, $fh, $result, %data_hash );
5524
5525     $options->{ "direction" } ||= "both";
5526
5527     while ( $record = get_record( $in ) ) 
5528     {
5529         if ( defined $record->{ "Q_BEG" } and defined $record->{ "S_BEG" } and $record->{ "Q_END" } and $record->{ "S_END" } ) {
5530             push @data, $record;
5531         }
5532
5533         put_record( $record, $out ) if not $options->{ "no_stream" };
5534     }
5535
5536     $options->{ "title" }  ||= "plot_matches";
5537     $options->{ "xlabel" } ||= $data[ 0 ]->{ "Q_ID" };
5538     $options->{ "ylabel" } ||= $data[ 0 ]->{ "S_ID" };
5539
5540     $result = Maasha::Plot::dotplot_matches( \@data, $options, $BP_TMP );
5541
5542     $fh = write_stream( $options->{ "data_out" } );
5543
5544     print $fh "$_\n" foreach @{ $result };
5545
5546     close $fh;
5547 }
5548
5549
5550 sub script_length_vals
5551 {
5552     # Martin A. Hansen, August 2007.
5553
5554     # Determine the length of the value for given keys.
5555
5556     my ( $in,        # handle to in stream
5557          $out,       # handle to out stream
5558          $options,   # options hash
5559        ) = @_;
5560
5561     # Returns nothing.
5562
5563     my ( $record, $key );
5564
5565     while ( $record = get_record( $in ) ) 
5566     {
5567         foreach $key ( @{ $options->{ "keys" } } )
5568         {
5569             if ( $record->{ $key } ) {
5570                 $record->{ $key . "_LEN" } = length $record->{ $key };
5571             }
5572         }
5573
5574         put_record( $record, $out );
5575     }
5576 }
5577
5578
5579 sub script_sum_vals
5580 {
5581     # Martin A. Hansen, August 2007.
5582
5583     # Calculates the sums for values of given keys.
5584
5585     my ( $in,        # handle to in stream
5586          $out,       # handle to out stream
5587          $options,   # options hash
5588        ) = @_;
5589
5590     # Returns nothing.
5591
5592     my ( $record, $key, %sum_hash, $fh );
5593
5594     while ( $record = get_record( $in ) ) 
5595     {
5596         foreach $key ( @{ $options->{ "keys" } } )
5597         {
5598             if ( $record->{ $key } ) {
5599                 $sum_hash{ $key } += $record->{ $key };
5600             }
5601         }
5602
5603         put_record( $record, $out ) if not $options->{ "no_stream" };
5604     }
5605
5606     $fh = write_stream( $options->{ "data_out" } );
5607
5608     foreach $key ( @{ $options->{ "keys" } } ) {
5609         put_record( { $key . "_SUM" => $sum_hash{ $key } || 0 } , $fh );
5610     }
5611
5612     close $fh;
5613 }
5614
5615
5616 sub script_mean_vals
5617 {
5618     # Martin A. Hansen, August 2007.
5619
5620     # Calculate the mean of values of given keys.
5621
5622     my ( $in,        # handle to in stream
5623          $out,       # handle to out stream
5624          $options,   # options hash
5625        ) = @_;
5626
5627     # Returns nothing.
5628
5629     my ( $record, $key, %sum_hash, %count_hash, $mean, $fh );
5630
5631     while ( $record = get_record( $in ) ) 
5632     {
5633         foreach $key ( @{ $options->{ "keys" } } )
5634         {
5635             if ( $record->{ $key } )
5636             {
5637                 $sum_hash{ $key } += $record->{ $key };
5638                 $count_hash{ $key }++;
5639             }
5640         }
5641
5642         put_record( $record, $out ) if not $options->{ "no_stream" };
5643     }
5644
5645     $fh = write_stream( $options->{ "data_out" } );
5646
5647     foreach $key ( @{ $options->{ "keys" } } )
5648     {
5649         if ( $count_hash{ $key } ) {
5650             $mean = sprintf( "%.2f", ( $sum_hash{ $key } / $count_hash{ $key } ) );
5651         } else {
5652             $mean = "N/A";
5653         }
5654
5655         put_record( { $key . "_MEAN" => $mean } , $fh );
5656     }
5657
5658     close $fh;
5659 }
5660
5661
5662 sub script_median_vals
5663 {
5664     # Martin A. Hansen, March 2008.
5665
5666     # Calculate the median values of given keys.
5667
5668     my ( $in,        # handle to in stream
5669          $out,       # handle to out stream
5670          $options,   # options hash
5671        ) = @_;
5672
5673     # Returns nothing.
5674
5675     my ( $record, $key, %median_hash, $median, $fh );
5676
5677     while ( $record = get_record( $in ) ) 
5678     {
5679         foreach $key ( @{ $options->{ "keys" } } ) {
5680             push @{ $median_hash{ $key } }, $record->{ $key } if defined $record->{ $key };
5681         }
5682
5683         put_record( $record, $out ) if not $options->{ "no_stream" };
5684     }
5685
5686     $fh = write_stream( $options->{ "data_out" } );
5687
5688     foreach $key ( @{ $options->{ "keys" } } )
5689     {
5690         if ( $median_hash{ $key } ) {
5691             $median = Maasha::Calc::median( $median_hash{ $key } );
5692         } else {
5693             $median = "N/A";
5694         }
5695
5696         put_record( { $key . "_MEDIAN" => $median } , $fh );
5697     }
5698
5699     close $fh;
5700 }
5701
5702
5703 sub script_max_vals
5704 {
5705     # Martin A. Hansen, February 2008.
5706
5707     # Determine the maximum values of given keys.
5708
5709     my ( $in,        # handle to in stream
5710          $out,       # handle to out stream
5711          $options,   # options hash
5712        ) = @_;
5713
5714     # Returns nothing.
5715
5716     my ( $record, $key, $fh, %max_hash, $max_record );
5717
5718     while ( $record = get_record( $in ) ) 
5719     {
5720         foreach $key ( @{ $options->{ "keys" } } )
5721         {
5722             if ( $record->{ $key } )
5723             {
5724                 $max_hash{ $key } = $record->{ $key } if $record->{ $key } > $max_hash{ $key };
5725             }
5726         }
5727
5728         put_record( $record, $out ) if not $options->{ "no_stream" };
5729     }
5730
5731     $fh = write_stream( $options->{ "data_out" } );
5732
5733     foreach $key ( @{ $options->{ "keys" } } )
5734     {
5735         $max_record->{ $key . "_MAX" } = $max_hash{ $key };
5736     }
5737
5738     put_record( $max_record, $fh );
5739
5740     close $fh;
5741 }
5742
5743
5744 sub script_min_vals
5745 {
5746     # Martin A. Hansen, February 2008.
5747
5748     # Determine the minimum values of given keys.
5749
5750     my ( $in,        # handle to in stream
5751          $out,       # handle to out stream
5752          $options,   # options hash
5753        ) = @_;
5754
5755     # Returns nothing.
5756
5757     my ( $record, $key, $fh, %min_hash, $min_record );
5758
5759     while ( $record = get_record( $in ) ) 
5760     {
5761         foreach $key ( @{ $options->{ "keys" } } )
5762         {
5763             if ( defined $record->{ $key } )
5764             {
5765                 if ( exists $min_hash{ $key } ) {
5766                     $min_hash{ $key } = $record->{ $key } if $record->{ $key } < $min_hash{ $key };
5767                 } else {
5768                     $min_hash{ $key } = $record->{ $key }; 
5769                 }
5770             }
5771         }
5772
5773         put_record( $record, $out ) if not $options->{ "no_stream" };
5774     }
5775
5776     $fh = write_stream( $options->{ "data_out" } );
5777
5778     foreach $key ( @{ $options->{ "keys" } } )
5779     {
5780         $min_record->{ $key . "_MIN" } = $min_hash{ $key };
5781     }
5782
5783     put_record( $min_record, $fh );
5784
5785     close $fh;
5786 }
5787
5788
5789 sub script_upload_to_ucsc
5790 {
5791     # Martin A. Hansen, August 2007.
5792
5793     # Calculate the mean of values of given keys.
5794
5795     my ( $in,        # handle to in stream
5796          $out,       # handle to out stream
5797          $options,   # options hash
5798        ) = @_;
5799
5800     # Returns nothing.
5801
5802     my ( $record, $file, $wib_file, $wig_file, $wib_dir, $fh_in, $fh_out, $i, $first, $format, $args, $type, $columns, $append, %fh_hash,
5803          $chr, $beg, $end, $block, $line, $max, $beg_block, $entry, $q_id, $clones );
5804
5805     $options->{ "short_label" } ||= $options->{ 'table' };
5806     $options->{ "long_label" }  ||= $options->{ 'table' };
5807     $options->{ "group" }       ||= $ENV{ "LOGNAME" };
5808     $options->{ "priority" }    ||= 1;
5809     $options->{ "visibility" }  ||= "pack";
5810     $options->{ "color" }       ||= join( ",", int( rand( 255 ) ), int( rand( 255 ) ), int( rand( 255 ) ) );
5811     $options->{ "chunk_size" }  ||= 10_000_000_000;    # Due to 32-bit UCSC compilation really large tables cannot be loaded in one go.
5812
5813     $file = "$BP_TMP/ucsc_upload.tmp";
5814
5815     $append = 0;
5816
5817     $first = 1;
5818
5819     $i = 0;
5820
5821     if ( $options->{ 'wiggle' } )
5822     {
5823         $options->{ "visibility" } = "full";
5824
5825         while ( $record = get_record( $in ) )
5826         {
5827             put_record( $record, $out ) if not $options->{ "no_stream" };
5828
5829             $record->{ "CHR" }     = $record->{ "S_ID" }  if not defined $record->{ "CHR" };
5830             $record->{ "CHR_BEG" } = $record->{ "S_BEG" } if not defined $record->{ "CHR_BEG" };
5831             $record->{ "CHR_END" } = $record->{ "S_END" } if not defined $record->{ "CHR_END" };
5832
5833             $fh_hash{ $record->{ "CHR" } } = Maasha::Common::write_open( "$BP_TMP/$record->{ 'CHR' }" ) if not exists $fh_hash{ $record->{ "CHR" } };
5834
5835             $fh_out = $fh_hash{ $record->{ "CHR" } };
5836             
5837             Maasha::UCSC::bed_put_entry( $record, $fh_out, 5 );
5838         }
5839
5840         map { close $_ } keys %fh_hash;
5841
5842         $fh_out = Maasha::Common::write_open( $file );
5843
5844         foreach $chr ( sort keys %fh_hash )
5845         {
5846             Maasha::Common::run( "bedSort", "$BP_TMP/$chr $BP_TMP/$chr" );
5847
5848             $fh_in = Maasha::Common::read_open( "$BP_TMP/$chr" );
5849
5850             undef $block;
5851
5852             while ( $entry = Maasha::UCSC::bed_get_entry( $fh_in, 5 ) )
5853             {
5854                 $chr  = $entry->{ 'CHR' };
5855                 $beg  = $entry->{ 'CHR_BEG' };
5856                 $end  = $entry->{ 'CHR_END' };
5857                 $q_id = $entry->{ 'Q_ID' };
5858                 
5859                 if ( $options->{ "score" } ) {
5860                     $clones = $entry->{ 'SCORE' };
5861                 } if ( $q_id =~ /_(\d+)$/ ) {
5862                     $clones = $1;
5863                 } else {
5864                     $clones = 1;
5865                 }
5866
5867                 if ( $block )
5868                 {
5869                     if ( $beg > $max )
5870                     {
5871                         Maasha::UCSC::fixedstep_put_entry( $chr, $beg_block, $block, $fh_out );
5872                         undef $block;
5873                     }
5874                     else
5875                     {
5876                         for ( $i = $beg - $beg_block; $i < ( $beg - $beg_block ) + ( $end - $beg ); $i++ ) {
5877                             $block->[ $i ] += $clones;
5878                         }
5879
5880                         $max = Maasha::Calc::max( $max, $end );
5881                     }
5882                 }
5883
5884                 if ( not $block )
5885                 {
5886                     $beg_block = $beg;
5887                     $max       = $end;
5888
5889                     for ( $i = 0; $i < ( $end - $beg ); $i++ ) {
5890                         $block->[ $i ] += $clones;
5891                     }
5892                 }
5893             }
5894
5895             close $fh_in;
5896
5897             Maasha::UCSC::fixedstep_put_entry( $chr, $beg_block, $block, $fh_out, $options->{ "log10" } );
5898
5899             unlink "$BP_TMP/$chr";
5900         }
5901
5902         close $fh_out;
5903
5904         $wig_file = "$options->{ 'table' }.wig";
5905         $wib_file = "$options->{ 'table' }.wib";
5906
5907         $wib_dir  = "$ENV{ 'HOME' }/ucsc/wib";
5908
5909         Maasha::Common::dir_create_if_not_exists( $wib_dir );
5910
5911         # Maasha::Common::run( "wigEncode", "$file $wig_file $wib_file > /dev/null 2>&1" );
5912
5913         `cd $BP_TMP && wigEncode $file $wig_file $wib_file > /dev/null 2>&1`;
5914         Maasha::Common::run( "mv", "$BP_TMP/$wib_file $wib_dir" );
5915
5916         unlink $file;
5917
5918         $file = $wig_file;
5919
5920         $format = "WIGGLE";
5921     }
5922     else
5923     {
5924         $fh_out = Maasha::Common::write_open( $file );
5925     
5926         while ( $record = get_record( $in ) ) 
5927         {
5928             put_record( $record, $out ) if not $options->{ "no_stream" };
5929
5930             if ( $record->{ "REC_TYPE" } eq "PSL" )
5931             {
5932                 Maasha::UCSC::psl_put_header( $fh_out ) if $first;
5933                 Maasha::UCSC::psl_put_entry( $record, $fh_out );
5934                 
5935                 $first = 0;
5936
5937                 $format = "PSL" if not $format;
5938             }
5939             elsif ( $record->{ "REC_TYPE" } eq "BED" and $record->{ "SEC_STRUCT" } )
5940             {
5941                 # chrom chromStart  chromEnd    name    score   strand  size    secStr  conf 
5942
5943                 print $fh_out join ( "\t",
5944                     $record->{ "CHR" },
5945                     $record->{ "CHR_BEG" },
5946                     $record->{ "CHR_END" } + 1,
5947                     $record->{ "Q_ID" },
5948                     $record->{ "SCORE" },
5949                     $record->{ "STRAND" },
5950                     $record->{ "SIZE" },
5951                     $record->{ "SEC_STRUCT" },
5952                     $record->{ "CONF" },
5953                 ), "\n";
5954
5955                 $format  = "BED_SS" if not $format;
5956             }
5957             elsif ( $record->{ "REC_TYPE" } eq "BED" )
5958             {
5959                 Maasha::UCSC::bed_put_entry( $record, $fh_out, $record->{ "BED_COLS" } );
5960
5961                 $format  = "BED"                   if not $format;
5962                 $columns = $record->{ "BED_COLS" } if not $columns;
5963             }
5964             elsif ( $record->{ "REC_TYPE" } eq "PATSCAN" and $record->{ "CHR" } )
5965             {
5966                 Maasha::UCSC::bed_put_entry( $record, $fh_out, 6 );
5967
5968                 $format  = "BED" if not $format;
5969                 $columns = 6     if not $columns;
5970             }
5971             elsif ( $record->{ "REC_TYPE" } eq "BLAST" and $record->{ "S_ID" } =~ /^chr/ )
5972             {
5973                 $record->{ "CHR" }     = $record->{ "S_ID" };
5974                 $record->{ "CHR_BEG" } = $record->{ "S_BEG" };
5975                 $record->{ "CHR_END" } = $record->{ "S_END" };
5976                 $record->{ "SCORE" }   = $record->{ "BIT_SCORE" } * 1000;
5977
5978                 $format  = "BED" if not $format;
5979                 $columns = 6     if not $columns;
5980
5981                 Maasha::UCSC::bed_put_entry( $record, $fh_out );
5982             }
5983             elsif ( $record->{ "REC_TYPE" } eq "VMATCH" and $record->{ "S_ID" } =~ /^chr/i )
5984             {
5985                 $record->{ "CHR" }     = $record->{ "S_ID" };
5986                 $record->{ "CHR_BEG" } = $record->{ "S_BEG" };
5987                 $record->{ "CHR_END" } = $record->{ "S_END" };
5988                 $record->{ "SCORE" }   = $record->{ "SCORE" } || 999;
5989                 $record->{ "SCORE" }   = int( $record->{ "SCORE" } );
5990
5991                 $format  = "BED" if not $format;
5992                 $columns = 6     if not $columns;
5993
5994                 Maasha::UCSC::bed_put_entry( $record, $fh_out, 6 );
5995             }
5996
5997             if ( $i == $options->{ "chunk_size" } )
5998             {
5999                 close $fh_out;
6000
6001                 if ( $format eq "BED" ) {
6002                     Maasha::UCSC::bed_upload_to_ucsc( $BP_TMP, $file, $options, $append );
6003                 } elsif ( $format eq "PSL" ) {
6004                     Maasha::UCSC::psl_upload_to_ucsc( $file, $options, $append ); 
6005                 }
6006
6007                 unlink $file;
6008
6009                 $first = 1;
6010
6011                 $append = 1;
6012
6013                 $fh_out = Maasha::Common::write_open( $file );
6014             }
6015
6016             $i++;
6017         }
6018     }
6019
6020     close $fh_out;
6021
6022     if ( exists $options->{ "database" } and $options->{ "table" } )
6023     {
6024         if ( $format eq "BED" )
6025         {
6026             $type = "bed $columns";
6027
6028             Maasha::UCSC::bed_upload_to_ucsc( $BP_TMP, $file, $options, $append );
6029         }
6030         elsif ( $format eq "BED_SS" )
6031         {
6032             $options->{ "sec_struct" } = 1; 
6033
6034             $type = "sec_struct";
6035         
6036             Maasha::UCSC::bed_upload_to_ucsc( $BP_TMP, $file, $options, $append );
6037         }
6038         elsif ( $format eq "PSL" )
6039         {
6040             $type = "psl";
6041
6042             Maasha::UCSC::psl_upload_to_ucsc( $file, $options, $append ); 
6043         }
6044         elsif ( $format eq "WIGGLE" )
6045         {
6046             $type = "wig 0";
6047
6048             Maasha::UCSC::wiggle_upload_to_ucsc( $BP_TMP, $wib_dir, $file, $options );
6049         }
6050
6051         unlink $file;
6052
6053         Maasha::UCSC::update_my_tracks( $options, $type );
6054     }
6055 }
6056
6057
6058 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6059
6060
6061 sub record2fasta
6062 {
6063     # Martin A. Hansen, July 2008.
6064
6065     # Given a biopiece record converts it to a FASTA record.
6066     # If no generic SEQ or SEQ_NAME is found, the Q_* and S_* are
6067     # tried in that order.
6068
6069     my ( $record,    # record
6070        ) = @_;
6071
6072     # Returns a tuple.
6073
6074     my ( $seq_name, $seq );
6075
6076     $seq_name = $record->{ "SEQ_NAME" } || $record->{ "Q_ID" }  || $record->{ "S_ID" };
6077     $seq      = $record->{ "SEQ" }      || $record->{ "Q_SEQ" } || $record->{ "S_SEQ" };
6078
6079     if ( defined $seq_name and defined $seq ) {
6080         return wantarray ? ( $seq_name, $seq ) : [ $seq_name, $seq ];
6081     } else {
6082         return;
6083     }
6084 }
6085
6086
6087 sub read_stream
6088 {
6089     # Martin A. Hansen, July 2007.
6090
6091     # Opens a stream to STDIN or a file,
6092
6093     my ( $path,   # path - OPTIONAL
6094        ) = @_;
6095
6096     # Returns filehandle.
6097
6098     my ( $fh );
6099
6100     if ( not -t STDIN ) {
6101         $fh = Maasha::Common::read_stdin();
6102     } elsif ( not $path ) {
6103 #        Maasha::Common::error( qq(no data stream) );
6104     } else {
6105         $fh = Maasha::Common::read_open( $path );
6106     }
6107     
6108 #    $fh->autoflush(1) if $fh;  # Disable file buffer for debugging.
6109
6110     return $fh;
6111 }
6112
6113
6114 sub write_stream
6115 {
6116     # Martin A. Hansen, August 2007.
6117
6118     # Opens a stream to STDOUT or a file.
6119
6120     my ( $path,   # path          - OPTIONAL
6121          $gzip,   # compress data - OPTIONAL
6122        ) = @_;
6123
6124     # Returns filehandle.
6125
6126     my ( $fh );
6127
6128     if ( $path ) {
6129         $fh = Maasha::Common::write_open( $path, $gzip );
6130     } else {
6131         $fh = Maasha::Common::write_stdout();
6132     }
6133
6134     return $fh;
6135 }
6136
6137
6138 sub get_record
6139 {
6140     # Martin A. Hansen, July 2007.
6141
6142     # Reads one record at a time and converts that record
6143     # to a Perl data structure (a hash) which is returned.
6144
6145     my ( $fh,   # handle to stream
6146        ) = @_;
6147
6148     # Returns a hash. 
6149
6150     my ( $block, @lines, $line, $key, $value, %record );
6151
6152     local $/ = "\n---\n";
6153
6154     $block = <$fh>;
6155
6156     chomp $block;
6157
6158     return if not defined $block;
6159
6160     @lines = split "\n", $block;
6161
6162     foreach $line ( @lines )
6163     {
6164         ( $key, $value ) = split ": ", $line, 2;
6165
6166         $record{ $key } = $value;
6167     }
6168
6169     return wantarray ? %record : \%record;
6170 }
6171
6172
6173 sub put_record
6174 {
6175     # Martin A. Hansen, July 2007.
6176
6177     # Given a Perl datastructure (a hash ref) emits this to STDOUT or a filehandle.
6178
6179     my ( $data,   # data structure
6180          $fh,     # file handle - OPTIONAL
6181        ) = @_;
6182
6183     # Returns nothing.
6184
6185     if ( scalar keys %{ $data } )
6186     {
6187         if ( $fh )
6188         {
6189             map { print $fh "$_: $data->{ $_ }\n" } keys %{ $data };
6190             print $fh "---\n";
6191         }
6192         else
6193         {
6194             map { print "$_: $data->{ $_ }\n" } keys %{ $data };
6195             print "---\n";
6196         }
6197     }
6198
6199     undef $data;
6200 }
6201
6202
6203 sub getopt_files
6204 {
6205     # Martin A. Hansen, November 2007.
6206
6207     # Extracts files from an explicit GetOpt::Long argument
6208     # allowing for the use of glob. E.g.
6209     # --data_in=test.fna
6210     # --data_in=test.fna,test2.fna
6211     # --data_in=*.fna
6212     # --data_in=test.fna,/dir/*.fna
6213
6214     my ( $option,   # option from GetOpt::Long
6215        ) = @_;
6216
6217     # Returns a list.
6218
6219     my ( $elem, @files );
6220
6221     foreach $elem ( split ",", $option )
6222     {
6223         if ( -f $elem ) {
6224             push @files, $elem;
6225         } elsif ( $elem =~ /\*/ ) {
6226             push @files, glob( $elem );
6227         }
6228     }
6229
6230     return wantarray ? @files : \@files;
6231 }
6232
6233
6234 sub sig_handler
6235 {
6236     # Martin A. Hansen, April 2008.
6237
6238     # Removes temporary directory and exits gracefully.
6239     # This subroutine is meant to be run always as the last
6240     # thing even if a script is dies or is interrupted
6241     # or killed. 
6242
6243     my ( $sig,   # signal from the %SIG
6244        ) = @_;
6245
6246     # print STDERR "signal->$sig<-\n";
6247
6248     chomp $sig;
6249
6250     sleep 1;
6251
6252     if ( -d $BP_TMP )
6253     {
6254         if ( $sig =~ /MAASHA_ERROR/ ) {
6255             print STDERR "\nProgram '$script' had an error"                     . "  -  Please wait for temporary data to be removed\n";
6256         } elsif ( $sig eq "INT" ) {
6257             print STDERR "\nProgram '$script' interrupted (ctrl-c was pressed)" . "  -  Please wait for temporary data to be removed\n";
6258         } elsif ( $sig eq "TERM" ) {
6259             print STDERR "\nProgram '$script' terminated (someone used kill?)"  . "  -  Please wait for temporary data to be removed\n";
6260         } else {
6261             print STDERR "\nProgram '$script' died->$sig"                       . "  -  Please wait for temporary data to be removed\n";
6262         }
6263
6264         clean_tmp();
6265     }
6266
6267     exit( 0 );
6268 }
6269
6270
6271 sub clean_tmp
6272 {
6273     # Martin A. Hansen, July 2008.
6274
6275     # Cleans out any unused temporary files and direcotries in BP_TMP.
6276
6277     # Returns nothing.
6278
6279     my ( $tmpdir, @dirs, $curr_pid, $dir, $user, $sid, $pid );
6280
6281     $tmpdir = $ENV{ 'BP_TMP' } || Maasha::Common::error( 'No BP_TMP variable in environment.' );
6282
6283     $curr_pid = Maasha::Common::get_processid();
6284
6285     @dirs = Maasha::Common::ls_dirs( $tmpdir );
6286
6287     foreach $dir ( @dirs )
6288     {
6289         if ( $dir =~ /^$tmpdir\/(.+)_(\d+)_(\d+)_bp_tmp$/ )
6290         {
6291             $user = $1;
6292             $sid  = $2;
6293             $pid  = $3;
6294
6295             if ( $user eq Maasha::Common::get_user() )
6296             {
6297                 if ( not Maasha::Common::process_running( $pid ) )
6298                 {
6299                     # print STDERR "Removing stale dir: $dir\n";
6300                     Maasha::Common::dir_remove( $dir );
6301                 }
6302                 elsif ( $pid == $curr_pid )
6303                 {
6304                     # print STDERR "Removing current dir: $dir\n";
6305                     Maasha::Common::dir_remove( $dir );
6306                 }
6307             }
6308         }
6309     }
6310 }
6311
6312
6313 END
6314 {
6315     clean_tmp();
6316 }
6317
6318
6319 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
6320
6321 1;
6322
6323 __END__