]> git.donarmstrong.com Git - biopieces.git/blobdiff - www/cgi-bin/index.cgi
more KISS
[biopieces.git] / www / cgi-bin / index.cgi
index f2e646098a53dddee48eaf484b821407da506065..ef28e2645828b72814b8a6ef3269cb8fd223d25b 100755 (executable)
@@ -30,465 +30,631 @@ use Data::Dumper;
 use Time::HiRes;
 use Maasha::Common;
 use Maasha::Filesys;
+use Maasha::Calc;
 use Maasha::XHTML;
-use Maasha::Biopieces;
 use Maasha::KISS::IO;
 use Maasha::KISS::Track;
 use Maasha::KISS::Draw;
 
-my ( $cgi, $database, $user, $password, $dbh, $script, @html );
+my ( $cgi, $cookie, @html );
 
-$cgi = new CGI;
-
-$database = 'S_aur_COL';
-$user     = Maasha::Biopieces::biopiecesrc( "MYSQL_USER" );
-$password = Maasha::Biopieces::biopiecesrc( "MYSQL_PASSWORD" );
-
-$dbh = Maasha::SQL::connect( $database, $user, $password );
-
-
-$script = Maasha::Common::get_scriptname();
+$cgi    = new CGI;
+$cookie = cookie_default( $cgi );;
 
 push @html, Maasha::XHTML::html_header(
     cgi_header  => 1,
     title       => "KISS Genome Browser",
-#    css_file    => "test.css",
+    css_file    => "kiss.css",
     author      => "Martin A. Hansen, mail\@maasha.dk",
     description => "Biopieces bacterial genome browser - KISS",
     keywords    => [ qw( KISS Biopieces biopiece genome browser viewer bacterium bacteria prokaryote prokaryotes ) ],
     no_cache    => 1,
 );
 
-push @html, Maasha::XHTML::h1( txt => "KISS Genome Browser", class => "center" );
-push @html, Maasha::XHTML::form_beg( action => $script, method => "get", enctype => "multipart/form-data" );
+push @html, Maasha::XHTML::h1( txt => "KISS Genome Browser", class => 'center' );
+push @html, Maasha::XHTML::form_beg( action => $cookie->{ 'SCRIPT' }, method => "get", enctype => "multipart/form-data" );
 
-push @html, sec_navigate( $cgi );
-push @html, sec_browse( $dbh, $cgi->param( 'nav_start' ), $cgi->param( 'nav_end' ) );
+push @html, page( $cookie );
 
 push @html, Maasha::XHTML::form_end;
 push @html, Maasha::XHTML::body_end;
 push @html, Maasha::XHTML::html_end;
 
+# push @html, Maasha::KISS::Draw::hdump( $cgi->param );
+# push @html, Maasha::KISS::Draw::hdump( $cookie );
+
 print "$_\n" foreach @html;
 
 
 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 
 
-sub sec_navigate
+sub cookie_default
 {
     my ( $cgi,   # CGI object
        ) = @_;
 
-    # Returns a list.
+    # Returns a hash
 
-    my ( $list_clade, $list_genome, $list_assembly, $list_contig, $def_clade, $def_genome, $def_assembly, $def_contig, $def_start, $def_end, @html );
+    my ( $cookie, $path );
 
-    $list_clade    = nav_list_clade();
-    $list_genome   = nav_list_genome();
-    $list_assembly = nav_list_assembly();
-    $list_contig   = nav_list_contig();
+    $cookie = {};
 
-    nav_zoom( $cgi );
-    nav_move( $cgi, 2_800_000 ); # FIXME
+    $cookie->{ 'SCRIPT' }      = Maasha::Common::get_scriptname();
+    $cookie->{ 'DATA_DIR' }    = "Data";
+    $cookie->{ 'LIST_PAGES' }  = [ qw( user clade genome assembly contig browse ) ];
+    $cookie->{ 'PAGE' }        = $cgi->param( 'page' )     || 'user';
+    $cookie->{ 'USER' }        = $cgi->param( 'user' )     || '';
+    $cookie->{ 'CLADE' }       = $cgi->param( 'clade' )    || '';
+    $cookie->{ 'GENOME' }      = $cgi->param( 'genome' )   || '';
+    $cookie->{ 'ASSEMBLY' }    = $cgi->param( 'assembly' ) || '';
+    $cookie->{ 'CONTIG' }      = $cgi->param( 'contig' )   || '';
+    $cookie->{ 'NAV_START' }   = $cgi->param( 'nav_start' );
+    $cookie->{ 'NAV_END' }     = $cgi->param( 'nav_end' );
+    $cookie->{ 'ZOOM_IN1' }    = $cgi->param( 'zoom_in1' );
+    $cookie->{ 'ZOOM_IN2' }    = $cgi->param( 'zoom_in2' );
+    $cookie->{ 'ZOOM_IN3' }    = $cgi->param( 'zoom_in3' );
+    $cookie->{ 'ZOOM_OUT1' }   = $cgi->param( 'zoom_out1' );
+    $cookie->{ 'ZOOM_OUT2' }   = $cgi->param( 'zoom_out2' );
+    $cookie->{ 'ZOOM_OUT3' }   = $cgi->param( 'zoom_out3' );
+    $cookie->{ 'MOVE_LEFT1' }  = $cgi->param( 'move_left1' );
+    $cookie->{ 'MOVE_LEFT2' }  = $cgi->param( 'move_left2' );
+    $cookie->{ 'MOVE_LEFT3' }  = $cgi->param( 'move_left3' );
+    $cookie->{ 'MOVE_RIGHT1' } = $cgi->param( 'move_right1' );
+    $cookie->{ 'MOVE_RIGHT2' } = $cgi->param( 'move_right2' );
+    $cookie->{ 'MOVE_RIGHT3' } = $cgi->param( 'move_right3' );
 
-    $def_clade     = nav_def_clade( $cgi );
-    $def_genome    = nav_def_genome( $cgi );
-    $def_assembly  = nav_def_assembly( $cgi );
-    $def_contig    = nav_def_contig( $cgi );
-    $def_start     = nav_def_start( $cgi );
-    $def_end       = nav_def_end( $cgi );
+    $path = "$cookie->{ 'DATA_DIR' }/Users";
 
-    Maasha::Calc::commify( \$def_start );
-    Maasha::Calc::commify( \$def_end );
+    $cookie->{ 'LIST_USER' }     = ls_dir_base( $path ) if -d $path;
 
-    push @html, Maasha::XHTML::table_beg( summary => "Navigation table" );
-    push @html, Maasha::XHTML::table_row_simple( tr => [ qw( Clade Genome Assembly Contig Start End ) ], align => 'center' );
-    push @html, Maasha::XHTML::table_row_simple( tr => [
-        Maasha::XHTML::menu( name => "nav_clade",    options => $list_clade,    selected => $def_clade ),
-        Maasha::XHTML::menu( name => "nav_genome",   options => $list_genome,   selected => $def_genome ),
-        Maasha::XHTML::menu( name => "nav_assembly", options => $list_assembly, selected => $def_assembly ),
-        Maasha::XHTML::menu( name => "nav_contig",   options => $list_contig,   selected => $def_contig ),
-        Maasha::XHTML::text( name => "nav_start", value => $def_start, size => 20 ),
-        Maasha::XHTML::text( name => "nav_end",   value => $def_end,   size => 20 ), 
-        Maasha::XHTML::submit( name => "nav_submit", value => "Submit" ),
-    ] );
-    push @html, Maasha::XHTML::table_end;
+    $path .= "/$cookie->{ 'USER' }";
 
-    push @html, Maasha::XHTML::table_beg( summary => "Zoom table" );
-    push @html, Maasha::XHTML::table_row_simple( tr => [
-        Maasha::XHTML::p( txt => 'Move:' ),
-        Maasha::XHTML::submit( name => "move_left3",  value => "<<<", title => "move 95% to the left" ),
-        Maasha::XHTML::submit( name => "move_left2",  value => "<<",  title => "move 47.5% to the left" ),
-        Maasha::XHTML::submit( name => "move_left1",  value => "<",   title => "move 10% to the left" ),
-        Maasha::XHTML::submit( name => "move_right1", value => ">",   title => "move 10% to the rigth" ),
-        Maasha::XHTML::submit( name => "move_right2", value => ">>",  title => "move 47.5% to the rigth" ),
-        Maasha::XHTML::submit( name => "move_right3", value => ">>>", title => "move 95% to the right" ),
-        Maasha::XHTML::p( txt => 'Zoom in:' ),
-        Maasha::XHTML::submit( name => "zoom_in1", value => "1.5x" ),
-        Maasha::XHTML::submit( name => "zoom_in2", value => "3x" ),
-        Maasha::XHTML::submit( name => "zoom_in3", value => "10x" ),
-        Maasha::XHTML::p( txt => 'Zoom out:' ),
-        Maasha::XHTML::submit( name => "zoom_out1", value => "1.5x" ),
-        Maasha::XHTML::submit( name => "zoom_out2", value => "3x" ),
-        Maasha::XHTML::submit( name => "zoom_out3", value => "10x" ),
-    ] );
-    push @html, Maasha::XHTML::table_end;
+    $cookie->{ 'LIST_CLADE' }    = ls_dir_base( $path ) if -d $path;
 
-    return wantarray ? @html : \@html;
+    $path .= "/$cookie->{ 'CLADE' }";
+
+    $cookie->{ 'LIST_GENOME' }   = ls_dir_base( $path ) if -d $path;
+
+    $path .= "/$cookie->{ 'GENOME' }";
+
+    $cookie->{ 'LIST_ASSEMBLY' } = ls_dir_base( $path ) if -d $path;
+
+    $path .= "/$cookie->{ 'ASSEMBLY' }";
+
+    $cookie->{ 'LIST_CONTIG' }   = ls_dir_base( $path ) if -d $path;
+
+    if ( $cookie->{ 'CONTIG' } )
+    {
+        cookie_start( $cookie );
+        cookie_end( $cookie );
+        cookie_zoom( $cookie );
+        cookie_move( $cookie );
+    }
+
+    return wantarray ? %{ $cookie } : $cookie;
 }
 
 
-sub sec_browse
+sub ls_dir_base
 {
-    my ( $dbh,     # Database handle
-         $start,   # Browse start position
-         $end,     # Browse end position
+    my ( $path,
        ) = @_;
 
     # Returns a list.
+    
+    my ( @dirs, $dir, @list );
 
-    my ( $t0, $t1, $table, $entries, $features, $svg, $file, $fh, @html );
+    @dirs = Maasha::Filesys::ls_dirs( $path );
 
-    $table = 'Solexa';
+    foreach $dir ( @dirs )
+    {
+        next if $dir =~ /\/\.\.?$/;
 
-    $t0 = Time::HiRes::gettimeofday();
-    $entries = Maasha::KISS::IO::kiss_sql_get( $dbh, $table, $start, $end );
-    $t1 = Time::HiRes::gettimeofday();
+        push @list, ( split "/", $dir )[ -1 ];
+    }
 
-    push @html, Maasha::XHTML::p( txt => "Feature count: " . scalar @$entries );
+    return wantarray ? @list : \@list;
+}
 
-    push @html, Maasha::XHTML::p( txt => "Time SQL: " . ( $t1 - $t0 ) );
 
-    $t0 = Time::HiRes::gettimeofday();
-    Maasha::KISS::Track::entries_sort( $entries );
-    $t1 = Time::HiRes::gettimeofday();
+sub cookie_clade
+{
+    my ( $cookie,
+       ) = @_;
 
-    push @html, Maasha::XHTML::p( txt => "Time sort: " . ( $t1 - $t0 ) );
+    # Returns nothing.
+    
+    my ( $user, @dirs, $dir );
 
-    $t0 = Time::HiRes::gettimeofday();
+    $user = $cookie->{ 'USER' };
+
+    @dirs = Maasha::Filesys::ls_dirs( "$cookie->{ 'DATA_DIR' }/Users/$user" );
 
-    my $MAX = 4000;  # FIXME should depend on hieght of track as well
+    foreach $dir ( @dirs )
+    {
+        next if $dir =~ /\/\.\.?$/;
 
-    if ( @$entries > $MAX ) {
-        $features = Maasha::KISS::Track::track_histogram( 1200, 50, $start, $end, $entries );
-    } else {
-        $features = Maasha::KISS::Track::track_feature( 1200, 50, $start, $end, $entries );
+        push @{ $cookie->{ 'LIST_CLADE' } }, ( split "/", $dir )[ -1 ];
     }
+}
 
-    $t1 = Time::HiRes::gettimeofday();
 
-    # push @html, Maasha::KISS::Draw::hdump( $entries );
-    # push @html, Maasha::KISS::Draw::hdump( $features );
+sub cookie_genome
+{
+    my ( $cookie,
+       ) = @_;
 
-    push @html, Maasha::XHTML::p( txt => "Time Track: " . ( $t1 - $t0 ) );
+    # Returns nothing.
+    
+    my ( $user, $clade, @dirs, $dir );
 
-    $file = "fisk.svg";
+    $user  = $cookie->{ 'USER' };
+    $clade = $cookie->{ 'CLADE' };
 
-    $fh = Maasha::Filesys::file_write_open( $file );
+    @dirs = Maasha::Filesys::ls_dirs( "$cookie->{ 'DATA_DIR' }/Users/$user/$clade" );
 
-    $svg = Maasha::KISS::Draw::svg_init( 800, 1200 );
+    foreach $dir ( @dirs )
+    {
+        next if $dir =~ /\/\.\.?$/;
 
-    $t0 = Time::HiRes::gettimeofday();
-    Maasha::KISS::Draw::svg_frame( 800, 1200, $svg );
+        push @{ $cookie->{ 'LIST_GENOME' } }, ( split "/", $dir )[ -1 ];
+    }
+}
 
-    Maasha::KISS::Draw::svg_track_dna( 1200, $svg, 'dna', 'ATCG' );
 
-    if ( @$entries > $MAX ) {
-        Maasha::KISS::Draw::svg_track_histogram( $svg, $features, 'track id', 'green' ) if $features;
-    } else {
-        Maasha::KISS::Draw::svg_track_feature( 800, 1200, $svg, $features, 'track id2', 'green' ) if $features;
-    }
+sub cookie_assembly
+{
+    my ( $cookie,
+       ) = @_;
 
-    Maasha::KISS::Draw::svg_print( $svg, $fh );
-    $t1 = Time::HiRes::gettimeofday();
+    # Returns nothing.
+    
+    my ( $user, $clade, $genome, @dirs, $dir );
 
-    push @html, Maasha::XHTML::p( txt => "Time Draw: " . ( $t1 - $t0 ) );
+    $user   = $cookie->{ 'USER' };
+    $clade  = $cookie->{ 'CLADE' };
+    $genome = $cookie->{ 'GENOME' };
 
-    close $fh;
+    @dirs = Maasha::Filesys::ls_dirs( "$cookie->{ 'DATA_DIR' }/Users/$user/$clade/$genome" );
 
-    push @html, Maasha::XHTML::object( type   => "image/svg+xml",
-                                       # data   => "/Users/maasha/test.svg",
-                                       data   => $file,
-                                       name   => "owMain",
-                                       width  => "1200",
-                                       height => "800" );
+    foreach $dir ( @dirs )
+    {
+        next if $dir =~ /\/\.\.?$/;
 
-    return wantarray ? @html : \@html;
+        push @{ $cookie->{ 'LIST_ASSEMBLY' } }, ( split "/", $dir )[ -1 ];
+    }
 }
 
 
-sub nav_list_clade
+sub cookie_contig
 {
-    my ( $list_clade );
-
-    $list_clade = [ qw( Eukaryote Bacillus Fish ) ];
+    my ( $cookie,
+       ) = @_;
 
-    return wantarray ? @{ $list_clade } : $list_clade;
-}
+    # Returns nothing.
+    
+    my ( $user, $clade, $genome, $assembly, @dirs, $dir );
 
+    $user     = $cookie->{ 'USER' };
+    $clade    = $cookie->{ 'CLADE' };
+    $genome   = $cookie->{ 'GENOME' };
+    $assembly = $cookie->{ 'ASSEMBLY' };
 
-sub nav_list_genome
-{
-    my ( $list_genome );
+    @dirs = Maasha::Filesys::ls_dirs( "$cookie->{ 'DATA_DIR' }/Users/$user/$clade/$genome/$assembly" );
 
-    $list_genome = [ qw( S.aur_COL E.col B.sub ) ];
+    foreach $dir ( @dirs )
+    {
+        next if $dir =~ /\/\.\.?$/;
 
-    return wantarray ? @{ $list_genome } : $list_genome;
+        push @{ $cookie->{ 'LIST_CONTIG' } }, ( split "/", $dir )[ -1 ];
+    }
 }
 
 
-sub nav_list_assembly
+sub cookie_start
 {
-    my ( $list_assembly );
+    my ( $cookie,
+       ) = @_;
 
-    $list_assembly = [ qw( 2008-02-21 2009-01-23 ) ];
+    # Returns nothing.
 
-    return wantarray ? @{ $list_assembly } : $list_assembly;
+    if ( defined $cookie->{ 'NAV_START' } )
+    {
+        $cookie->{ 'NAV_START' } =~ tr/,//d;
+        $cookie->{ 'NAV_START' } = 1 if $cookie->{ 'NAV_START' } <= 0;
+    }
+    else
+    {
+        $cookie->{ 'NAV_START' } = 1;
+    }
 }
 
 
-sub nav_list_contig
+sub cookie_end
 {
-    my ( $list_contig );
+    my ( $cookie,
+       ) = @_;
 
-    $list_contig = [ qw( chr1 chr2 ) ];
+    # Returns nothing.
 
-    return wantarray ? @{ $list_contig } : $list_contig;
+    my ( $max );
+    
+    $max = Maasha::Filesys::file_size( Maasha::KISS::Track::path_seq( $cookie ) );
+
+    if ( defined $cookie->{ 'NAV_END' } )
+    {
+        $cookie->{ 'NAV_END' } =~ tr/,//d;
+        $cookie->{ 'NAV_END' } = $max if $cookie->{ 'NAV_END' } > $max;
+    }
+    else
+    {
+        $cookie->{ 'NAV_END' } = $max;
+    }
 }
 
 
-sub nav_zoom
+sub cookie_zoom
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $start, $end, $dist, $new_dist, $dist_diff, $new_start, $new_end );
+    # Returns nothing.
+
+    my ( $max, $dist, $new_dist, $dist_diff );
+
+    $max = Maasha::Filesys::file_size( Maasha::KISS::Track::path_seq( $cookie ) );
+
+    $dist = $cookie->{ 'NAV_END' } - $cookie->{ 'NAV_START' };
 
-    if ( defined $cgi->param( 'nav_start' ) and $cgi->param( 'nav_end' ) )
+    if ( defined $cookie->{ 'ZOOM_IN1' } ) {
+        $new_dist = $dist / 1.5;
+    } elsif ( defined $cookie->{ 'ZOOM_IN2' } ) {
+        $new_dist = $dist / 3;
+    } elsif ( defined $cookie->{ 'ZOOM_IN3' } ) {
+        $new_dist = $dist / 10;
+    } elsif ( defined $cookie->{ 'ZOOM_OUT1' } ) {
+        $new_dist = $dist * 1.5;
+    } elsif ( defined $cookie->{ 'ZOOM_OUT2' } ) {
+        $new_dist = $dist * 3;
+    } elsif ( defined $cookie->{ 'ZOOM_OUT3' } ) {
+        $new_dist = $dist * 10;
+    }
+
+    if ( $new_dist )
     {
-        $start = $cgi->param( 'nav_start' );
-        $end   = $cgi->param( 'nav_end' );
-
-        $start =~ tr/,//d;
-        $end   =~ tr/,//d;
-
-        $dist = $end - $start;
-
-        if ( defined $cgi->param( 'zoom_in1' ) ) {
-            $new_dist = $dist / 1.5;
-        } elsif ( defined $cgi->param( 'zoom_in2' ) ) {
-            $new_dist = $dist / 3;
-        } elsif ( defined $cgi->param( 'zoom_in3' ) ) {
-            $new_dist = $dist / 10;
-        } elsif ( defined $cgi->param( 'zoom_out1' ) ) {
-            $new_dist = $dist * 1.5;
-        } elsif ( defined $cgi->param( 'zoom_out2' ) ) {
-            $new_dist = $dist * 3;
-        } elsif ( defined $cgi->param( 'zoom_out3' ) ) {
-            $new_dist = $dist * 10;
-        }
+        $dist_diff = $dist - $new_dist;
 
-        if ( $new_dist )
-        {
-            $dist_diff = $dist - $new_dist;
-            $new_start = int( $start + ( $dist_diff / 2 ) );
-            $new_end   = int( $end   - ( $dist_diff / 2 ) );
+        $cookie->{ 'NAV_START' } = int( $cookie->{ 'NAV_START' } + ( $dist_diff / 2 ) );
+        $cookie->{ 'NAV_END' }   = int( $cookie->{ 'NAV_END' }   - ( $dist_diff / 2 ) );
 
-            $cgi->param( 'nav_start', $new_start );
-            $cgi->param( 'nav_end',  $new_end );
-        }
+        $cookie->{ 'NAV_START' } = 1     if $cookie->{ 'NAV_START' } <= 0;
+        $cookie->{ 'NAV_END' }   = $max if $cookie->{ 'NAV_END' } > $max;
     }
 }
 
 
-sub nav_move
+sub cookie_move
 {
-    my ( $cgi,   # CGI object
-         $max,   # Max end position
+    my ( $cookie,
        ) = @_;
 
-    my ( $start, $end, $dist, $shift, $new_start, $new_end );
+    my ( $max, $dist, $shift, $new_start, $new_end );
 
-    if ( defined $cgi->param( 'nav_start' ) and $cgi->param( 'nav_end' ) )
-    {
-        $start = $cgi->param( 'nav_start' );
-        $end   = $cgi->param( 'nav_end' );
-
-        $start =~ tr/,//d;
-        $end   =~ tr/,//d;
-
-        $dist = $end - $start;
-
-        if ( defined $cgi->param( 'move_left1' ) ) {
-            $shift = -1 * $dist * 0.10;
-        } elsif ( defined $cgi->param( 'move_left2' ) ) {
-            $shift = -1 * $dist * 0.475;
-        } elsif ( defined $cgi->param( 'move_left3' ) ) {
-            $shift = -1 * $dist * 0.95;
-        } elsif ( defined $cgi->param( 'move_right1' ) ) {
-            $shift = $dist * 0.10;
-        } elsif ( defined $cgi->param( 'move_right2' ) ) {
-            $shift = $dist * 0.475;
-        } elsif ( defined $cgi->param( 'move_right3' ) ) {
-            $shift = $dist * 0.95;
-        }
+    $max = Maasha::Filesys::file_size( Maasha::KISS::Track::path_seq( $cookie ) );
 
-        if ( $shift )
-        {
-            $new_start = int( $start + $shift );
-            $new_end   = int( $end   + $shift );
+    $dist = $cookie->{ 'NAV_END' } - $cookie->{ 'NAV_START' };
 
-            print "HERRRR: shift: $shift    start: $new_start    end: $new_end\n";
+    if ( defined $cookie->{ 'MOVE_LEFT1' } ) {
+        $shift = -1 * $dist * 0.10;
+    } elsif ( defined $cookie->{ 'MOVE_LEFT2' } ) {
+        $shift = -1 * $dist * 0.475;
+    } elsif ( defined $cookie->{ 'MOVE_LEFT3' } ) {
+        $shift = -1 * $dist * 0.95;
+    } elsif ( defined $cookie->{ 'MOVE_RIGHT1' } ) {
+        $shift = $dist * 0.10;
+    } elsif ( defined $cookie->{ 'MOVE_RIGHT2' } ) {
+        $shift = $dist * 0.475;
+    } elsif ( defined $cookie->{ 'MOVE_RIGHT3' } ) {
+        $shift = $dist * 0.95;
+    }
+
+    if ( $shift )
+    {
+        $new_start = int( $cookie->{ 'NAV_START' } + $shift );
+        $new_end   = int( $cookie->{ 'NAV_END' }   + $shift );
 
-            if ( $new_start > 0 and $new_end < $max )
-            {
-                $cgi->param( 'nav_start', $new_start );
-                $cgi->param( 'nav_end',  $new_end );
-            }
+        if ( $new_start > 0 and $new_end < $max )
+        {
+            $cookie->{ 'NAV_START' } = $new_start;
+            $cookie->{ 'NAV_END' }   = $new_end;
         }
     }
 }
 
 
-sub nav_def_clade
+sub page
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $def_clade );
+    # Returns a list.
+
+    my ( @html, $list, $item, $href );
 
-    if ( defined $cgi->param( 'nav_clade' ) )
+    push @html, breadcrumb( $cookie );
+
+    $list = "LIST_" . uc $cookie->{ 'PAGE' };
+
+    if ( $cookie->{ 'PAGE' } eq 'export' )
     {
-        $def_clade = $cgi->param( 'nav_clade' );
+        push @html, Maasha::XHTML::h2( txt => "Export", class => 'center' );
+    }
+    elsif ( $cookie->{ 'PAGE' } ne 'browse' )
+    {
+        push @html, Maasha::XHTML::h2( txt => "Select $cookie->{ 'PAGE' }", class => 'center' );
+
+        push @html, Maasha::XHTML::table_beg( summary => "Select table", align => 'center', cellpadding => '5px' );
+
+        foreach $item ( @{ $cookie->{ $list } } )
+        {
+            $cookie->{ uc $cookie->{ 'PAGE' } } = $item;
+
+            $href = page_href( $cookie, page_next( $cookie ) );
+
+            push @html, Maasha::XHTML::table_row_simple( tr => [ Maasha::XHTML::ln( txt => $item, href => $href ) ] );
+        }
+
+        push @html, Maasha::XHTML::table_end;
     }
     else
     {
-        $def_clade = "Bacteria";
+        push @html, sec_navigate( $cookie );
+        push @html, sec_browse( $cookie );
     }
 
-    return $def_clade;
+    return wantarray ? @html : \@html;
 }
 
 
-sub nav_def_genome
+sub page_next
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $def_genome );
+    my ( $i );
 
-    if ( defined $cgi->param( 'nav_genome' ) )
-    {
-        $def_genome = $cgi->param( 'nav_genome' );
-    }
-    else
-    {
-        $def_genome = "S.aur_COL";
+    for ( $i = 0; $i < @{ $cookie->{ 'LIST_PAGES' } }; $i++ ) {
+        last if $cookie->{ 'PAGE' } eq $cookie->{ 'LIST_PAGES' }->[ $i ];
     }
 
-    return $def_genome;
+    return $cookie->{ 'LIST_PAGES' }->[ $i + 1 ];
 }
 
 
-sub nav_def_assembly
+sub breadcrumb
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $def_assembly );
+    # Returns a list.
 
-    if ( defined $cgi->param( 'nav_assembly' ) )
-    {
-        $def_assembly = $cgi->param( 'nav_assembly' );
-    }
-    else
+    my ( @pages, $page, @row1, @row2, @html, $href, $txt );
+    
+    @pages = @{ $cookie->{ 'LIST_PAGES' } };
+
+    pop @pages;   # remove 'browse'
+
+    foreach $page ( @pages )
     {
-        $def_assembly = "2009-01-23";
+        $href = page_href( $cookie, $page );
+
+        $txt = $cookie->{ uc $page } || "";
+
+        push @row1, Maasha::XHTML::ln( txt => $page, href => $href, class => 'inline' );
+        push @row2, Maasha::XHTML::p( txt => $txt, class => 'inline' );
+
+        last if $page eq $cookie->{ 'PAGE' };
     }
 
-    return $def_assembly;
+    push @html, Maasha::XHTML::table_beg( summary => "Taxonomy table", align => 'center', cellpadding => '5px' );
+    push @html, Maasha::XHTML::table_row_simple( tr => \@row1, align => 'center' );
+    push @html, Maasha::XHTML::table_row_simple( tr => \@row2, align => 'center' );
+    push @html, Maasha::XHTML::table_end;
+
+    return wantarray ? @html : \@html;
 }
 
 
-sub nav_def_contig
+sub page_href
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
+         $page,
        ) = @_;
 
-    my ( $def_contig );
+    # Returns a string.
 
-    if ( defined $cgi->param( 'nav_contig' ) )
-    {
-        $def_contig = $cgi->param( 'nav_contig' );
-    }
-    else
+    my ( @href );
+
+    while ( 1 )
     {
-        $def_contig = "chr1";
+        push @href, "$cookie->{ 'SCRIPT' }?page=$page";
+        push @href, "user=$cookie->{ 'USER' }"         if $cookie->{ 'USER' };
+        last if $page eq 'user';
+        push @href, "clade=$cookie->{ 'CLADE' }"       if $cookie->{ 'CLADE' };
+        last if $page eq 'clade';
+        push @href, "genome=$cookie->{ 'GENOME' }"     if $cookie->{ 'GENOME' };
+        last if $page eq 'genome';
+        push @href, "assembly=$cookie->{ 'ASSEMBLY' }" if $cookie->{ 'ASSEMBLY' };
+        last if $page eq 'assembly';
+        push @href, "contig=$cookie->{ 'CONTIG' }"     if $cookie->{ 'CONTIG' };
+        last if $page eq 'contig';
+        last;
     }
 
-    return $def_contig;
+    return join "&", @href;
 }
 
 
-sub nav_def_start
+sub sec_navigate
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $def_start );
+    # Returns a list.
 
-    if ( defined $cgi->param( 'nav_start' ) ) {
-        $def_start = $cgi->param( 'nav_start' );
-    } else {
-        $def_start = 1;
-    }
+    my ( @html );
 
-    $def_start =~ tr/,//d;
+    push @html, Maasha::XHTML::table_beg( summary => "Navigation table", align => 'center' );
+    push @html, Maasha::XHTML::table_row_simple( tr => [ qw( Start End ) ], align => 'center' );
+    push @html, Maasha::XHTML::table_row_simple( tr => [
+        Maasha::XHTML::text( name => "nav_start", value => Maasha::Calc::commify( $cookie->{ 'NAV_START' } ), size => 20 ),
+        Maasha::XHTML::text( name => "nav_end",   value => Maasha::Calc::commify( $cookie->{ 'NAV_END' } ),   size => 20 ), 
+        Maasha::XHTML::submit( name => "nav_submit", value => "Submit" ),
+    ] );
+    push @html, Maasha::XHTML::table_end;
 
-    if ( $def_start <= 0 ) {
-        $def_start = 1;
-    }
+    push @html, Maasha::XHTML::table_beg( summary => "Zoom table", align => 'center' );
+    push @html, Maasha::XHTML::table_row_simple( tr => [
+        Maasha::XHTML::p( txt => 'Move:' ),
+        Maasha::XHTML::submit( name => "move_left3",  value => "<<<", title => "move 95% to the left" ),
+        Maasha::XHTML::submit( name => "move_left2",  value => "<<",  title => "move 47.5% to the left" ),
+        Maasha::XHTML::submit( name => "move_left1",  value => "<",   title => "move 10% to the left" ),
+        Maasha::XHTML::submit( name => "move_right1", value => ">",   title => "move 10% to the rigth" ),
+        Maasha::XHTML::submit( name => "move_right2", value => ">>",  title => "move 47.5% to the rigth" ),
+        Maasha::XHTML::submit( name => "move_right3", value => ">>>", title => "move 95% to the right" ),
+        Maasha::XHTML::p( txt => 'Zoom in:' ),
+        Maasha::XHTML::submit( name => "zoom_in1", value => "1.5x" ),
+        Maasha::XHTML::submit( name => "zoom_in2", value => "3x" ),
+        Maasha::XHTML::submit( name => "zoom_in3", value => "10x" ),
+        Maasha::XHTML::p( txt => 'Zoom out:' ),
+        Maasha::XHTML::submit( name => "zoom_out1", value => "1.5x" ),
+        Maasha::XHTML::submit( name => "zoom_out2", value => "3x" ),
+        Maasha::XHTML::submit( name => "zoom_out3", value => "10x" ),
+    ] );
+    push @html, Maasha::XHTML::table_end;
 
-    $cgi->param( 'nav_start', $def_start );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "page",     value => "browse" ) );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "user",     value => "$cookie->{ 'USER' }" ) );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "clade",    value => "$cookie->{ 'CLADE' }" ) );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "genome",   value => "$cookie->{ 'GENOME' }" ) );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "assembly", value => "$cookie->{ 'ASSEMBLY' }" ) );
+    push @html, Maasha::XHTML::p( txt => Maasha::XHTML::hidden( name => "contig",   value => "$cookie->{ 'CONTIG' }" ) );
 
-    return $def_start;
+    return wantarray ? @html : \@html;
 }
 
 
-sub nav_def_end
+sub sec_browse
 {
-    my ( $cgi,   # CGI object
+    my ( $cookie,
        ) = @_;
 
-    my ( $def_end );
+    # Returns a list.
+
+    my ( $draw_metrics, @tracks, $i, @features, $feat, $elem, $file, $surface, $cr, @html, @img );
+
+    $draw_metrics = {
+        IMG_WIDTH       => 1200,
+        IMG_HEIGHT      => 800,
+        TRACK_OFFSET    => 20,
+        TRACK_SPACE     => 20,
+        RULER_FONT_SIZE => 10,
+        RULER_COLOR     => [ 0, 0, 0 ],
+        SEQ_FONT_SIZE   => 10,
+        SEQ_COLOR       => [ 0, 0, 0, ],
+        FEAT_WIDTH      => 5,
+        FEAT_COLOR      => [ 0, 1, 0 ],
+    };
     
-    if ( defined $cgi->param( 'nav_end' ) ) {
-        $def_end = $cgi->param( 'nav_end' );
-    } else {
-        $def_end = 2809422;
-        $def_end = 2000;
+    push @features, [ Maasha::KISS::Track::track_ruler( $draw_metrics, $cookie ) ];
+    push @features, [ Maasha::KISS::Track::track_seq( $draw_metrics, $cookie ) ];
+
+    @tracks = Maasha::KISS::Track::path_tracks( $cookie );
+
+    for ( $i = 0; $i < @tracks; $i++ )
+    {
+        $draw_metrics->{ 'FEAT_COLOR' } = palette( $i );
+
+        push @features, [ Maasha::KISS::Track::track_feature( $tracks[ $i ], $draw_metrics, $cookie ) ];
     }
 
-    $def_end =~ tr/,//d;
+    $file = "fisk.png";
+
+    $surface = Cairo::ImageSurface->create( 'argb32', $draw_metrics->{ 'IMG_WIDTH' }, $draw_metrics->{ 'TRACK_OFFSET' } );
+    $cr      = Cairo::Context->create( $surface );
 
-    if ( $def_end > 2809422 ) {
-        $def_end = 2809422;
+    foreach $feat ( @features ) {
+        Maasha::KISS::Draw::draw_feature( $cr, $feat ) if $feat;
     }
 
-    $cgi->param( 'nav_end', $def_end );
+    Maasha::KISS::Draw::file_png( $surface, $file );
 
-    return $def_end;
-}
+    push @img, Maasha::XHTML::img(
+        src    => $file,
+        alt    => "Browser Tracks",
+        height => $draw_metrics->{ 'TRACK_OFFSET' },
+        width  => $draw_metrics->{ 'IMG_WIDTH' },
+        id     => "browser_map",
+        usemap => "#browser_map"
+    );
 
+    push @img, Maasha::XHTML::map_beg( name => "browser_map", id => "browser_map" );
 
-# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+    foreach $feat ( @features )
+    {
+        foreach $elem ( @{ $feat } )
+        {
+            next if $elem->{ 'type' } eq 'text';
+
+            push @img, Maasha::XHTML::area(
+                href   => page_href( $cookie, "export" ) . "&Q_ID=$elem->{ 'id' }",
+                shape  => "rect",
+                coords => "$elem->{ x1 }, $elem->{ y1 }, $elem->{ x2 }, $elem->{ y2 }", title => "$elem->{ 'title' }",
+            );
+        }
+    }
+
+    push @img, Maasha::XHTML::map_end();
+
+    push @html, Maasha::XHTML::p( txt => join( "\n", @img ) );
+
+    @html = Maasha::XHTML::div( txt => join( "\n", @html ), class => 'browse' );
+
+    return wantarray ? @html : \@html;
+}
 
 
-END
+sub palette
 {
-    Maasha::SQL::disconnect( $dbh ) if $dbh;
+    my ( $i,
+       ) = @_;
+
+    my ( $palette, $color );
+
+    $palette = [
+        [ 30, 130, 130 ],
+        [ 30, 50, 150 ],
+        [ 130, 130, 50 ],
+        [ 130, 90, 130 ],
+        [ 130, 70, 70 ],
+        [ 70, 170, 130 ],
+        [ 130, 170, 50 ],
+    ];
+
+    $color = $palette->[ $i ];
+
+    map { $_ /= 255 } @{ $color };
+
+    return $color;
 }
 
+# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
 
 __END__
+
+    # push @html, Maasha::KISS::Draw::hdump( $features );
+
+    $t0 = Time::HiRes::gettimeofday();
+    $t1 = Time::HiRes::gettimeofday();