#!/usr/bin/perl
use strict;

require Tk;
require Tk::Dialog;
require Tk::widgets;
require Tk::NoteBook;
require Tk::ProgressBar;
require Tk::HList;
require Tk::ItemStyle;
require Tk::DirTree;
require Tk::Pane;
require Tk::DialogBox;

use Tk;
use Tk::Dialog;
use Tk::widgets;
use Tk::NoteBook;
use Tk::ProgressBar;
use Tk::HList;
use Tk::ItemStyle;
use Tk::DirTree;
use Tk::Pane;
use Tk::DialogBox;

#
#Check for threads package
#
my $thread;
BEGIN {
	foreach my $path (@INC) {
		my $full_name = "$path/threads.pm";
		if (-f $full_name) {
			$thread = 1;
			require threads;
			use threads;
			last;
		}
	}
	if (!$thread) {
		print "Thread package NOT found, background Statistical Analysis feature disabled!\n";
	}
}

my $version = 0.48;

my $border_menu = 2;
my $color_back = "#FFFFFF";
my $color_menu_bar = "#AAAAAA";
my $color_mb_back = "#AAAAAA";
my $color_mb_aback = "#CCCCCC";
my $color_mb_fore = "#000000";
my $color_mb_dfore = "#CCCCCC";
my $color_printA = "#CCCCCC";
my $font_general = "Arial";
my $font_print = "Courier";
my $font_size_general = 10;
my $font_size_print = 10;
my $state = 0;
my $system = $^O;

if (my $arg = shift(@ARGV) eq "-kpbd") { #{{{
	my $filein = shift (@ARGV);
	my $fileout = shift (@ARGV);
	my $size = shift (@ARGV);
	my $pross = shift (@ARGV);
	my $label = shift (@ARGV);
	my $kbvar = shift (@ARGV);


	if (!(open K_FILE, ">$fileout")) {
		print "COULD OPEN $fileout!!!\n";
		exit();
	}
	if (!(open K_IFILE, "<$filein")) {
		print "COULD OPEN $filein!!!\n";
		exit();
	}

	my $data = "";

	while (my $line = <K_IFILE>) {
		$data .= $line;
	}

	my @tags = &kemp ($data, $label, $size, $pross, $kbvar);

	foreach my $tag (@tags) {
		print K_FILE "$tag";
	}
	close K_FILE;

	exit();
}

#}}}

# Main Window #{{{

my $main = MainWindow->new(-background => $color_back);
$main-> minsize("800", "600");
$main-> title ("SAGE Analysis");

my $main_font = $main->fontCreate("mfont", -family => $font_general,
	-weight => "normal",
	-size => $font_size_general);
my $print_font = $main->fontCreate("pfont", -family => $font_print,
	-size => $font_size_print);

$main->optionAdd ("*font", "mfont");
$main->optionAdd ("*borderWidth", 1);
$main->optionAdd("*tearOff", "false");

#}}}

# Menu Bar #{{{
my $menu_bar = $main-> Frame (-relief => "flat",
	-borderwidth=> $border_menu,
)-> pack ("-side"=> "top", 
	-fill=> "x");

my $file_mb = $menu_bar-> Menubutton (-text=> "File",
	-relief => "flat",
)-> pack (-side=> "left");

my $file_mb_open = $file_mb-> cascade (-label => "~Open");

my $file_mb_open_d = $file_mb_open-> command (-label => "~Concatamer",
	-command=> \&t1_load_pop);

my $file_mb_open_d = $file_mb_open-> command (-label => "~Ditag List",
	-command=> \&t2_load_pop);

my $file_mb_open_d = $file_mb_open-> command (-label => "~Statistical Analysis Configuration",

	-command=> \&t3_load_pop);

my $file_mb_save = $file_mb-> cascade (-label => "~Save");

my $file_mb_save_d = $file_mb_save-> cascade (-label => "~Ditags"); #{{{

my $file_mb_save_d1 = $file_mb_save_d-> command (-label => "Ditag ~List",
	-command=> \&save_d);

my $file_mb_save_d2 = $file_mb_save_d-> command (-label => "Ditags ~Report",
	-command=> \&save_dr);

#}}}

my $file_mb_save_t = $file_mb_save-> cascade (-label => "~Tag Counts"); #{{{

my $file_mb_save_t1 = $file_mb_save_t-> command (-label => "Tag ~Count",
	-command=> \&save_t);

my $file_mb_save_t2 = $file_mb_save_t-> command (-label => "~Trimmed Tag Count",
	-command=> \&save_tt);

my $file_mb_save_t3 = $file_mb_save_t-> command (-label => "Count ~Report",
	-command=> \&save_tr);

#}}}

my $file_mb_save_k = $file_mb_save-> cascade (-label => "~Statistical Analysis"); #{{{

my $file_mb_save_k1 = $file_mb_save_k-> command (-label => "~Analysis",
	-command=> \&save_k);

my $file_mb_save_k2 = $file_mb_save_k-> command (-label => "~Configuration",
	-command=> \&save_kr);

#}}}

$file_mb_save-> separator();

my $file_mb_save_a = $file_mb_save-> command (-label => "All ~Results",
	-command=> sub {&save_d; &save_t; &save_tt; &save_k});

my $file_mb_save_a = $file_mb_save-> command (-label => "All ~Reports",
	-command=> sub {&save_tr; &save_dr; &save_kr});

$file_mb-> separator();

$file_mb-> command (-label => "~Exit",
	-command=> sub {$main->destroy;});

my $help_mb = $menu_bar-> Menubutton (-text=> "Help",
	-tearoff=> 0,
)-> pack (-side=> "right");

my $about_dialog = $main-> Dialog (-title => "SAGE Analysis About",
	-text => "SAGE Analysis v$version\nAn integrated tool for SAGE data extraction and analysis\n(C) 2008 Samuel G. Guimaraes, Alan M. Durham & Arthur Gruber",
	-buttons => ["OK"]);

$help_mb-> command (-label => "~About",
	-command=> [$about_dialog => "Show"]);

#}}}

# Notebook Tabs #{{{

my $book = $main-> NoteBook(-background => $color_back,
	-inactivebackground=> $color_mb_aback,
)-> pack (-fill=> "both",
	-expand=> "x");

$book-> configure (-relief=> "flat");

my $tab1 = $book-> add ("ED",
	-label=> "Extract Ditags");

$tab1-> configure (-background => $color_back);

my $tab2 = $book-> add ("ET",
	-label=> "Extract Tags");

$tab2-> configure (-background => $color_back);

my $tab3 = $book-> add ("Kemp",
	-label=> "Statistical Analysis");

$tab3-> configure (-background => $color_back);

#}}}

# extract_ditags #{{{

my $t1_prob = 0;
my $t1_cutSize = 18;
my $t1_save_file = "ditags.ct";
my $t1_load_file = "concatamers.fasta";
my $t1_p = 0;
my $t1_min_di = 32;
my $t1_max_di = 34;
my $t1_punc = "catg";
my $t1_lost = 1;
my $t1_mono = 1;
my $t1_dit = 1;
my $divisor = "/";
my $t1_printAreaT1;
my $t1_printAreaT2;
my %file_hash;

my $t2_max_tag = 18;
my $t2_min_tag = 17;
my $t2_size_eq = 25;
my $t2_coesive_n = 2;

my $t1_top = $tab1-> Frame( -background => $color_back #{{{
)-> pack (-side=> "top",
	-fill => "both",
	-padx=> 5,
	-pady=> 5);


#}}}

my $t1_bottom1 = $tab1-> Frame( -background => $color_back,#{{{
)-> pack (-side=> "bottom", 
	-padx=> 10,
	-pady=> 10,
	-fill => "x");

my $t1_p_bar_s = 200;
my $t2_p;

my $t1_p_bar = $t1_bottom1->ProgressBar(
	-width => 20,
	-length => $t1_p_bar_s,
	-anchor => 'w',
	-from => 0,
	-to => $t1_p_bar_s,
	-blocks => 20,
	-colors => [0, 'green', 100, 'yellow' , 180, 'red'],
	-variable => \$t1_p
)->pack(-side=> "bottom",
	-expand=> "x",
	-fill=> "x",
	-anchor=> "e");

#}}}

my $t1_bottom2 = $tab1-> Frame (-background => $color_back#{{{
)-> pack (-side=> "bottom", 
	-padx=> 10,
	-pady=> 10,
	-expand=> "both",
	-fill => "both");

my $t1_bottom2_1 = $t1_bottom2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left", 
	-padx=> 2,
	-pady=> 2,
	-expand=> "both",
	-fill => "both",
	-anchor=> "e");

my $t1_dirTreeVar;
my $t1_dirTree;

my $t1_path_entry = $t1_bottom2_1-> Entry (-background => $color_back,
	-relief=> "sunken",
	-borderwidth=> 1,
	-justify=> "left",
	-state=> "normal",
	-textvariable=> \$t1_dirTreeVar
)-> pack (-side=> "top",
	-fill=> "x",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t1_path_entry->bind('<Return>', sub {&read_dir ($t1_dirTreeVar); $t1_dirTree->chdir ($t1_dirTreeVar);});

$t1_dirTree = $t1_bottom2_1-> Scrolled ("DirTree",  
	-background => $color_printA,
	-borderwidth=> 1, 
	-relief=> "sunken", 
	-command=> sub {&read_dir ($t1_dirTreeVar); $t1_dirTree->chdir ($t1_dirTreeVar);},
	-browsecmd=> sub {$t1_dirTreeVar = shift},
	-scrollbars=> "se", 
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "top",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "n");

$t1_dirTree->configure(-font => "pfont");
$t1_dirTreeVar = $t1_dirTree->cget ("-directory");

my $t1_bottom2_1a = $t1_bottom2_1-> Frame (-background => $color_back #{{{
)-> pack (-side=> "top", 
	-fill => "both",
	-anchor=> "n");

my $t1_opendir_button = $t1_bottom2_1a-> Button (-text=> "Open Folder",
	-command=> sub {&read_dir ($t1_dirTreeVar); $t1_dirTree->chdir ($t1_dirTreeVar);},
	-width=> 9
)-> pack (-side=> "left",
	-anchor=> "w");

my $t1_addall_button = $t1_bottom2_1a-> Button (-text=> "Add File",
	-command=> \&add_file,
	-width=> 8
)-> pack (-side=> "right",
	-anchor=> "e");

my $t1_add_button = $t1_bottom2_1a-> Button (-text=> "Select All",
	-command=> \&select_all,
	-width=> 8
)-> pack (-side=> "right",
	-anchor=> "e");

#}}}

my $t1_file_list1 = $t1_bottom2_1-> Scrolled ( "HList", #{{{
	-columns=>3, 
	-header => 1, 
	-command => \&add_file, 
	-scrollbars=> "se",
	-selectmode => "extended"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "top",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "n");

$t1_file_list1->header("create", 0,
	-itemtype => "text", 
	-text => "File");

$t1_file_list1->header("create", 1,
	-itemtype => "text", 
	-text => "Size");

$t1_file_list1->header("create", 2,
	-itemtype => "text", 
	-text => "Path");

#}}}

#}}}

my $t1_bottom2_2 = $t1_bottom2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left", 
	-padx=> 2,
	-pady=> 2,
	-expand=> "both",
	-fill => "both",
	-anchor=> "e");

my $t1_bottom2_2t1 = $t1_bottom2_2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "top", 
	-fill => "both",
	-anchor=> "n");

my $t1_bottom2_2t1t = $t1_bottom2_2t1-> Frame (-background => $color_back
)-> pack (-side=> "left", 
	-fill => "both",
	-anchor=> "w");

my $t1_bottom2_2t11 = $t1_bottom2_2t1t-> Frame (-background => $color_back
)-> pack (-side=> "top",
    -fill => "both",
    -anchor=> "n");

my $t1_miseq_size = $t1_bottom2_2t11 -> Label ( -justify=>"left",
	-text=>"Minimum ditag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_miseq_size = $t1_bottom2_2t11 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_min_di,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_size_bp = $t1_bottom2_2t11 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_2_2space = $t1_bottom2_2t11 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-width=> 5,
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_maseq_size = $t1_bottom2_2t11 -> Label ( -justify=>"left",
	-text=>"Maximum ditag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_maseq_size = $t1_bottom2_2t11 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_max_di,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_size_bp = $t1_bottom2_2t11 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_bottom2_2t12 = $t1_bottom2_2t1t-> Frame (-background => $color_back
)-> pack (-side=> "top",
    -fill => "both",
	-pady => 3,
    -anchor=> "n");

my $t1_punc_p = $t1_bottom2_2t12 -> Label ( -justify=>"left",
	-text=>"Punctuation Sequence:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_punc_p = $t1_bottom2_2t12 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_punc,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_2_2space = $t1_bottom2_2t12 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-width=> 5,
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_lost_p = $t1_bottom2_2t12 -> Checkbutton ( -justify=>"left",
	-text=> "Recover degenerate punctuation sites",
	-relief=> "flat",
	-variable=> \$t1_lost,
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");


#}}}

my $t1_bottom2_2t2 = $t1_bottom2_2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "top", 
	-fill => "both",
	-anchor=> "n");

my $t1_bottom2_2t2rr;

my $t1_bottom2_2t2l = $t1_bottom2_2t2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left",
	-padx=> 3,
	-anchor=> "w");

my $t1_mono_l = $t1_bottom2_2t2l-> Label (-text=> "Extract Monotags:",
	-background=> $color_back,
)-> pack (-anchor=> "w");

my @t1_mono;

$t1_mono[0] = $t1_bottom2_2t2l-> Radiobutton (-text=> "Never",
	-background=> $color_back,
	-value=> 0,
	-variable=> \$t1_mono
)-> pack (-anchor=> "w");
$t1_mono[1] = $t1_bottom2_2t2l-> Radiobutton (-text=> "Evaluate Size",
	-background=> $color_back,
	-value=> 1,
	-variable=> \$t1_mono
)-> pack (-anchor=> "w");
$t1_mono[2] = $t1_bottom2_2t2l-> Radiobutton (-text=> "Always",
	-background=> $color_back,
	-value=> 2,
	-variable=> \$t1_mono
)-> pack (-anchor=> "w");

#}}}

my $t1_bottom2_2t2r = $t1_bottom2_2t2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left",
	-padx=> 3,
	-anchor=> "w");

my $t1_mono_l = $t1_bottom2_2t2r-> Label (-text=> "Duplicated Ditags:",
	-background=> $color_back,
)-> pack (-anchor=> "w");

my @t1_dit;

$t1_dit[0] = $t1_bottom2_2t2r-> Radiobutton (-text=> "Keep All",
	-background=> $color_back,
	-value=> 0,
	-command=> sub {$t1_bottom2_2t2rr->packForget();},
	-variable=> \$t1_dit
)-> pack (-anchor=> "w");
$t1_dit[1] = $t1_bottom2_2t2r-> Radiobutton (-text=> "Evaluate Ocurrence",
	-background=> $color_back,
	-value=> 1,
	-command=> sub {$t1_bottom2_2t2rr->pack (-side=> "left",
			-padx=> 0,
			-anchor=> "w");
		;},
	-variable=> \$t1_dit
)-> pack (-anchor=> "w");
$t1_dit[2] = $t1_bottom2_2t2r-> Radiobutton (-text=> "Remove all",
	-background=> $color_back,
	-value=> 2,
	-command=> sub {$t1_bottom2_2t2rr->packForget();},
	-variable=> \$t1_dit
)-> pack (-anchor=> "w");

#}}}

$t1_bottom2_2t2rr = $t1_bottom2_2t2-> Frame (-background => $color_back,#{{{
)-> pack (-side=> "left",
	-padx=> 0,
	-anchor=> "w");

my $t1_left1t1 = $t1_bottom2_2t2rr -> Frame (-background => $color_back,#{{{
	-width=> $t2_size_eq
)-> pack (-side=> "top",
	-anchor=> "w",
	-pady=> 1,
	-padx=> 0);

my $t1_seq_size = $t1_left1t1 -> Label ( -justify=>"left",
	-text=>"Cohesive end size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_seq_size = $t1_left1t1 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_coesive_n,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_seq_size_p = $t1_left1t1 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

my $t1_left1t2 = $t1_bottom2_2t2rr -> Frame (-background => $color_back#{{{
)-> pack (-side=> "bottom",
	-anchor=>"w",
	-pady=> 1,
	-padx=> 0);

my $t1_miseq_size = $t1_left1t2 -> Label ( -justify=>"left",
	-text=>"Minimum tag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_miseq_size = $t1_left1t2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_min_tag,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_miseq_size = $t1_left1t2 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

my $t1_left1t3 = $t1_bottom2_2t2rr -> Frame (-background => $color_back#{{{
)-> pack (-side=> "bottom",
	-anchor=>"w",
	-pady=> 1,
	-padx=> 0);

my $t1_maseq_size = $t1_left1t3 -> Label ( -justify=>"left",
	-text=>"Maximum tag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t1_p_maseq_size = $t1_left1t3 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_max_tag,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t1_maseq_size = $t1_left1t3 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

#}}}

#}}}

my $t1_file_list2 = $t1_bottom2_2-> Scrolled ( "HList", #{{{
	-columns=>3, 
	-header => 1, 
	-scrollbars=> "se",
	-selectmode => "extended"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "top",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "n");

$t1_file_list2->header("create", 0,
	-itemtype => "text", 
	-text => "File") ;

$t1_file_list2->header("create", 1,
	-itemtype => "text", 
	-text => "Size");

$t1_file_list2->header("create", 2,
	-itemtype => "text", 
	-text => "Path");

$t1_file_list2->bind('<Delete>', \&remove);

#}}}

my $t1_bottom2_2b = $t1_bottom2_2-> Frame (-background => $color_back #{{{
)-> pack (-side=> "top", 
	-fill => "both",
	-anchor=> "n");

my $t1_remove_button = $t1_bottom2_2b-> Button (-text=> "Remove",
	-command=> \&remove,
	-width=> 8
)-> pack (-side=> "left",
	-anchor=> "w");

my $t1_extract_button = $t1_bottom2_2b-> Button (-text=> "Extract",
	-command=> \&t1_extract,
	-width=> 8
)-> pack (-side=> "right",
	-anchor=> "e");

my $t1_selectall_button = $t1_bottom2_2b-> Button (-text=> "Select All",
	-command=> \&select_all2,
	-width=> 8
)-> pack (-side=> "right",
	-padx=>10,
	-anchor=> "e");

#}}}

#}}}

#}}}

sub read_dir { #{{{
	my $src = shift;

	opendir (DIR, $src);
	my @files = sort (readdir (DIR));
	closedir (DIR);


	$t1_file_list1->delete ("all");

	foreach my $file (@files) {
		if (-f "$src/$file") {
			my $el = $t1_file_list1->addchild("");
			$t1_file_list1->itemCreate($el, 0, -itemtype=>"text", -text=>$file);
			my $size = -s $src."/".$file;
			$t1_file_list1->itemCreate($el, 1, -itemtype=>"text", -text=>$size);
			$t1_file_list1->itemCreate($el, 2, -itemtype=>"text", -text=>$src);
		}
	}
}

#}}}

sub add_file { #{{{
	my @files = $t1_file_list1->infoSelection();

	foreach my $file (@files) {
		my $name = $t1_file_list1->itemCget($file, 0, "-text");
		my $size = $t1_file_list1->itemCget($file, 1, "-text");
		my $path = $t1_file_list1->itemCget($file, 2, "-text");
		my $full_name = $path.$divisor.$name;
		if (defined $file_hash{$full_name}) {
			if ($file_hash{$full_name} == 1) {
				return;
			}
		}
		my $el = $t1_file_list2->addchild("");
		$t1_file_list2->itemCreate($el, 0, -text=>$name);
		$t1_file_list2->itemCreate($el, 1, -text=> $size);
		$t1_file_list2->itemCreate($el, 2, -text=> $path);
		$file_hash{$full_name} = 1;
	}
}

#}}}

sub select_all { #{{{
	my @files = $t1_file_list1->info("child");
	my $size = @files;

	if ($size) {
		$t1_file_list1->selectionSet($files[0], $files[$size - 1]);
	}
}

#}}}

sub select_all2 { #{{{
	my @files = $t1_file_list2->info("child");
	my $size = @files;

	if ($size) {
		$t1_file_list2->selectionSet($files[0], $files[$size - 1]);
	}
}

#}}}

sub remove { #{{{
	my @files = $t1_file_list2->infoSelection();

	foreach my $entry (@files) {
		my $full_name = $t1_file_list2->itemCget($entry, 2, "-text").$divisor.$t1_file_list2->itemCget($entry, 0, "-text");
		$file_hash{$full_name} = 0;
		$t1_file_list2->delete("entry", $entry);
	}
}

#}}}

sub t1_extract { #{{{
	my @files = $t1_file_list2->infoSelection();

	if (int (@files) == 0) {
		&select_all2;
	}

	@files = $t1_file_list2->infoSelection();

	if (int (@files) == 0) {
		return;
	}

	$t1_p = 0;

	$main-> configure(-cursor=>"watch");
	$main-> update();

	my @final = ();
	&t2_clearAll();

	foreach my $entry (@files) {
		my $name = $t1_file_list2->itemCget($entry, 2, "-text"). $divisor. $t1_file_list2->itemCget($entry, 0, "-text");
		push (@final, $name);
	}

	my @ditags = &extract_ditags (\@final, $t1_min_di, $t1_max_di, $t1_mono, $t1_punc, $t1_lost);

	my @data = ();
	foreach my $ditag (@ditags) {
		if ($ditag) {
			if ($ditag =~ "#") {
				(my $junk, my $clear) = split (/#/, $ditag);
				$t1_printAreaT2-> insert ("end", "$clear\n");
			}
			else {
				if ($t1_dit) {
					push (@data, $ditag);
				}
				else {
					$t1_printAreaT1-> insert ("end", "$ditag\n");
				}
			}
		}
	}

	my @cleanditags;

	if ($t1_dit == 1) {
		@cleanditags = &dupDitag (\@data, $t1_min_di, $t1_max_di, $t1_mono);
	}
	elsif ($t1_dit == 2) {
		@cleanditags = &uniDitag (\@data);
	}

	if ($t1_dit) {
		$t1_printAreaT2-> insert ("end", "\nDitag (Occurences) Limit\n\n");
	}

	foreach my $ditag (@cleanditags) {
		if ($ditag =~ "#") {
			(my $junk, my $clear) = split (/#/, $ditag);
			$t1_printAreaT2-> insert ("end", "$clear\n");
		}
		else {
			$t1_printAreaT1-> insert ("end", "$ditag\n");
		}
	}

	$t1_p = $t1_p_bar_s;
	$t2_p = 0;

	$main-> configure(-cursor=>"arrow");

	$book-> raise("ET");
}

#}}}

sub t1_load_pop { #{{{
	my $ret = $main->getOpenFile (-filetypes => [["FASTA", ".fasta"], ["Text file", ".txt"], ["All", "*"]],
		-defaultextension => ".fasta",
		-initialfile      => "concatamer.fasta",
		-title            => "Load Concatamer File",
	);

	if (!$ret) {
		return;
	}

	print "[$ret]\n";

	if (defined $file_hash{$ret}) {
		if ($file_hash{$ret} == 1) {
			return;
		}
	}
	
	my @split = split (/($divisor)/, $ret);

	my $name = pop (@split);
	my $size = -s $ret;
	my $path = substr ($ret, 0, -(length($name) + 1));
	my $full_name = $ret;

	my $el = $t1_file_list2->addchild("");
	$t1_file_list2->itemCreate($el, 0, -text=>$name);
	$t1_file_list2->itemCreate($el, 1, -text=> $size);
	$t1_file_list2->itemCreate($el, 2, -text=> $path);
	$file_hash{$full_name} = 1;
	print "{$full_name}\n";

	$book-> raise("ED");
}

#}}}

#}}}

# extract_tags #{{{

my $t2_save_state = 0;
my $t2_rep_n = 0;
my $t2_size_eq_v = "";
my $t2_file_l = "ditags.txt";
my $t2_file_s = "tags.txt";
my $t2_save_file_ct = "tag_report.txt";
my $t2_save_file_rp = "ditags_report.txt";


my $t2_top = $tab2-> Frame( -background => $color_back #{{{
)-> pack (-side=> "top",
	-fill => "both",
	-padx=> 5,
	-pady=> 5);

my $t2_left1t = $t2_top-> Frame (-background => $color_back,#{{{
	-width=> 150
)-> pack (-side=> "left",
	-pady=> 2,
	-padx=> 5);


my $t2_left1t1 = $t2_left1t-> Frame (-background => $color_back,#{{{
	-width=> $t2_size_eq
)-> pack (-side=> "top",
	-anchor=> "w",
	-pady=> 2,
	-padx=> 5);

my $t2_seq_size = $t2_left1t1 -> Label ( -justify=>"left",
	-text=>"Cohesive end size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_p_seq_size = $t2_left1t1 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_coesive_n,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t2_seq_size_p = $t2_left1t1 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

my $t2_left1t2 = $t2_left1t-> Frame (-background => $color_back#{{{
)-> pack (-side=> "bottom",
	-anchor=>"w",
	-pady=> 2,
	-padx=> 5);

my $t2_miseq_size = $t2_left1t2 -> Label ( -justify=>"left",
	-text=>"Minimum tag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_p_miseq_size = $t2_left1t2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_min_tag,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t2_miseq_size = $t2_left1t2 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_maseq_size = $t2_left1t2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-width=> 5,
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_maseq_size = $t2_left1t2 -> Label ( -justify=>"left",
	-text=>"Maximum tag size:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_p_maseq_size = $t2_left1t2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_max_tag,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t2_maseq_size = $t2_left1t2 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

#}}}

my $t2_right1t = $t2_top-> Frame (-background => $color_back,#{{{
	-width=> 150
)-> pack (-side=> "right",
	-pady=> 10,
	-padx=> 15);

my $t2_right1t1 = $t2_right1t-> Frame (-background => $color_back,#{{{
	-width=> 150
)-> pack (-side=> "top",
	-pady=> 2,
	-padx=> 5);

my $t2_size_eq = $t2_right1t1 -> Label ( -justify=>"left",
	-text=>"Trim tag size to:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

my $t2_size_eq_e = $t2_right1t1 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t2_size_eq_v,
	-width=> 5,
	-state=> "normal" 
) -> pack(-side=>"left",
	-anchor=>"w");

my $t2_seq_size_p = $t2_right1t1 -> Label ( -justify=>"left",
	-text=>"bp",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "left",
	-anchor=>"w");

#}}}

my $t2_right1t2 = $t2_right1t-> Frame (-background => $color_back,#{{{
	-width=> 150
)-> pack (-side=> "top",
	-anchor=> "e",
	-pady=> 2,
	-padx=> 5);

my $t2_trim_b = $t2_right1t2 -> Button (-text=> "Trim Tags",
	-command=> \&t2_trim
)-> pack (-side=> "right",
	-anchor=>"e");

#}}}

#}}}

#}}}

my $t2_bottom1 = $tab2-> Frame( -background => $color_back, #{{{
)-> pack (-side=> "bottom", 
	-padx=> 10,
	-pady=> 10,
	-fill => "x");

$t2_p = 0;

my $t2_p_bar_s = 200;

my $t2_p_bar = $t2_bottom1->ProgressBar(
	-width => 20,
	-length => $t2_p_bar_s,
	-anchor => 'w',
	-from => 0,
	-to => $t2_p_bar_s,
	-blocks => 20,
	-colors => [0, 'green', 100, 'yellow' , 180, 'red'],
	-variable => \$t2_p
)->pack(-side=> "bottom",
	-expand=> "x",
	-fill=> "x",
	-anchor=> "e");

#}}}

my $t2_bottom2 = $tab2-> Frame (-background => $color_back#{{{
)-> pack (-side=> "bottom", 
	-padx=> 10,
	-pady=> 10,
	-expand=> "both",
	-fill => "both");


my $t2_book1 = $t2_bottom2-> NoteBook(-inactivebackground=> $color_menu_bar, #{{{
	-relief=> "flat",
	-background => $color_printA,
	-backpagecolor=> $color_back
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "left",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

my $t2_book11 = $t2_book1-> add ("t2_book11",  #{{{
	-label=> "Ditag List");

$t2_book11-> configure (-background => $color_printA);

my $t2_printArea11 = $t2_book11 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t2_printArea11->configure(-font => "pfont");

$t1_printAreaT1 = $t2_printArea11;

#}}}

my $t2_book12 = $t2_book1-> add ("t2_book12", #{{{
	-label=> "Report");

$t2_book12-> configure (-background => $color_printA);

my $t2_printArea12 = $t2_book12 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t2_printArea12->configure(-font => "pfont");

$t1_printAreaT2 = $t2_printArea12;

#}}}

#}}}

my $t2_2ditags_button = $t2_bottom2-> Button (-text=> "Extract\nTags",
	-command=> \&t2_extract,
	-width=> 5
)-> pack (-side=> "left",
	-anchor=> "e");

my $t2_book2 = $t2_bottom2-> NoteBook(-inactivebackground=> $color_menu_bar, #{{{
	-relief=> "flat",
	-background => $color_printA,
	-backpagecolor=> $color_back
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "left",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

my $t2_book21 = $t2_book2-> add ("t2_book21",  #{{{
	-label=> "Tags");

$t2_book21-> configure (-background => $color_printA);

my $t2_printArea21 = $t2_book21 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t2_printArea21->configure(-font => "pfont");

#}}}

my $t2_book22 = $t2_book2-> add ("t2_book22", #{{{
	-label=> "Report");

$t2_book22-> configure (-background => $color_printA);

my $t2_printArea22 = $t2_book22 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t2_printArea22->configure(-font => "pfont");

#}}}

my $t2_book23 = $t2_book2-> add ("t2_book23", #{{{
	-label=> "Trimmed");

$t2_book23-> configure (-background => $color_printA);

my $t2_printArea23 = $t2_book23 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t2_printArea23->configure(-font => "pfont");

#}}}

#}}}

#}}}

sub t2_extract { #{{{
	$t2_p = 0;
	$t2_p_bar->update();

	$main-> configure(-cursor=>"watch");

	$main-> update();

	my $data = $t2_printArea11-> get ("0.0", "end - 1 chars");

	$t2_printArea21-> delete ("0.0", "end");
	my @tags = &extract_tags ($data, $t2_min_tag, $t2_max_tag, $t2_coesive_n);

	$t2_printArea21-> delete ("0.0", "end");
	$t2_printArea22-> delete ("0.0", "end");
	foreach my $tag (@tags) {
		if ($tag =~ "%") {
			(my $junk, my $clear) = split (/%/, $tag);
			$t2_printArea22-> insert ("end", $clear, "\n");
		}
		else  {
			$t2_printArea21-> insert ("end", $tag, "\n");
		}
	}

	$t2_p = $t2_p_bar_s;

	&t2_trim;

	$main-> configure(-cursor=>"arrow");

	$t2_book2-> raise ("t2_book21");
}

#}}}

sub t2_trim { #{{{
	$main-> configure(-cursor=>"watch");

	$main-> update();

	my $data = $t2_printArea21-> get ("0.0", "end - 1 chars");

	$t2_printArea23-> delete ("0.0", "end");

	my %tags = &trim_tags ($data, $t2_size_eq_v);

	foreach my $key (keys %tags) {
		$t2_printArea23-> insert ("end", "$key=$tags{$key}\n");
	}

	$main-> configure(-cursor=>"arrow");

	$t2_book2-> raise ("t2_book23");
}

#}}}

sub t2_load_pop { #{{{
	my $ret = $main->getOpenFile (-filetypes => [["Text File", ".txt"], ["Ditags List", ".dt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => $t2_file_l,
		-title            => "Load Ditag List",
	);

	if ($ret) {
		$t2_file_l = $ret;
		&load_ditag;
		$book-> raise("ET");
		$t2_book1-> raise ("t2_book11");
	}
}

#}}}

sub load_ditag { #{{{
	if (!open (IN, "<$t2_file_l")) {
		print "Could not open $t2_file_l, $!\n";
		return;
	}   

	$t2_printArea11-> delete ("0.0", "end");
	$t2_printArea12-> delete ("0.0", "end");
	$t2_printArea21-> delete ("0.0", "end");
	$t2_printArea22-> delete ("0.0", "end");
	while (<IN>) {
		$t2_printArea11-> insert ("end", $_);
	}

	close IN;
}

#}}}

sub t2_clearAll { #{{{
	$t2_printArea11-> delete ("0.0", "end");
	$t2_printArea12-> delete ("0.0", "end");
	$t2_printArea21-> delete ("0.0", "end");
	$t2_printArea22-> delete ("0.0", "end");
	$t2_printArea23-> delete ("0.0", "end");
}

#}}}

#}}}

# kemp #{{{

my $t3_label = "Tag_";
my $t3_size = 3;
my $t3_pross = 2;
my $t3_file_l = "kemp_configuration.txt";
my $t3_lib = "count.txt";
my $t3_lib_count = 1;
my $t3_sent_count = 1;
my $t3_lib_name = "Library 1";
my %t3_lib_hash;
my @files;
my %t3_hash;
my %t3_sent_hash;
my $t3_kbvar = "kemp";
my $t3_kstate = 0;
my $t3_fbvar = "fg";
my $t3_savePath = "analysis.csv";
my %t3_anOrder;

my $t3_top = $tab3-> Frame( -background => $color_back #{{{
)-> pack (-side=> "top",
	-fill => "both",
	-padx=> 5,
	-pady=> 5);

#}}}

my $t3_bottom = $tab3-> Frame (-background => $color_back #{{{
)-> pack (-side=> "bottom", 
	-expand=> "both",
	-fill => "both");

my $t3_kemp_e2 = $main-> Dialog (-title => "Warning!",
	-text => "Select at least two libraries for the test. Press CTRL key and select the libraries in the upper window by clicking with the mouse button.",
	-buttons => ["Ok"]);

my $t3_kemp_e1 = $main-> Dialog (-title => "Warning!",
	-text => "Select at least two libraries to merge. Press CTRL key and select the libraries in the upper window by clicking with the mouse button.",
	-buttons => ["Ok"]);


my $t3_bottom_1 = $t3_bottom-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left", 
	-padx=> 5,
	-pady=> 5,
	-expand=> "both",
	-fill => "both");

my $t3_book = $t3_bottom_1-> NoteBook(-inactivebackground=> $color_menu_bar,
	-relief=> "flat",
	-background => $color_printA,
	-backpagecolor=> $color_back
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "left",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

my $t3_book1 = $t3_book-> add ("t3_book1",  #{{{
	-raisecmd=> sub {$t3_kstate = 0;},
	-label=> "Configuration");

$t3_book1-> configure (-background => $color_printA);

my $t3_b1e = $t3_book1-> Frame (-background => $color_printA
)-> pack (-expand=> 1,
	-side=> "left",
	-fill=> "both",
	-padx=> 0,
	-pady=> 0);

my $t3_libs_lab = $t3_b1e -> Label ( -justify=>"left", #{{{
	-text=>"Libraries",
	-relief=>"flat", 
	-background => $color_printA
)-> pack(-side=> "top",
	-anchor=>"w",
	-padx=> 10,
	-pady=> 5);

my $t3_lib_list = $t3_b1e-> Scrolled ( "HList", 
	-columns=>2, 
	-header => 1, 
#	-command => \&hl_command, 
#	-browsecmd => \&hl_browse, 
	-scrollbars=> "se",
	-selectmode => "extended"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "top",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t3_lib_list->header("create", 0,
	-itemtype => "text", 
	-text => "Name") ;

$t3_lib_list->header("create", 1,
	-itemtype => "text", 
	-text => "Path");

my $t3_sent_lab = $t3_b1e -> Label ( -justify=>"left",
	-text=>"Tests",
	-relief=>"flat", 
	-background => $color_printA
)-> pack(-side=> "top",
	-anchor=>"w",
	-padx=> 10,
	-pady=> 5);

my $t3_sent_list = $t3_b1e-> Scrolled ( "HList", 
	-columns=>2, 
	-header => 1, 
#	-command => \&hl_command, 
#	-browsecmd => \&hl_browse, 
	-scrollbars=> "se",
	-selectmode => "extended"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "top",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t3_sent_list->header("create", 0,
	-itemtype => "text", 
	-text => "Name") ;

$t3_sent_list->header("create", 1,
	-itemtype => "text", 
	-text => "Sentense");

#}}}

my $t3_b1d = $t3_book1-> Frame (-background => $color_printA #{{{
)-> pack (-side=> "left",
	-fill=> "both",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

my $t3_b1dt = $t3_b1d-> Frame (-background => $color_printA 
)-> pack (-side=> "top",
	-fill=> "both",
	-expand=> "both",
	-anchor=> "n");

$t3_b1dt-> Frame ()-> pack (-side=> "top", -pady=> 10);

my $t3_addLib = $t3_b1dt-> Button (-text=> "Add Library",
	-command=> \&t3_add_lib
)-> pack (-side=> "top",
	-fill=> "x",
	-anchor=> "n",
	-pady=> 10);

my $t3_selAll = $t3_b1dt-> Button (-text=> "Select All",
	-command=> \&t3_select_all
)-> pack (-side=> "top",
	-fill=> "x",
	-anchor=> "n",
	-pady=> 10);

my $t3_addLib = $t3_b1dt-> Button (-text=> "Remove Library",
	-command=> \&t3_rem_lib
)-> pack (-side=> "top",
	-anchor=> "n",
	-fill=> "x",
	-pady=> 10);

my $t3_addLib = $t3_b1dt-> Button (-text=> "Merge Libraries",
	-command=> \&t3_merge
)-> pack (-side=> "top",
	-anchor=> "n",
	-fill=> "x",
	-pady=> 10);

my $t3_b1db = $t3_b1d-> Frame (-background => $color_printA 
)-> pack (-side=> "top",
	-fill=> "both",
	-expand=> "both",
	-anchor=> "n");

my $t3_addLib = $t3_b1db-> Button (-text=> "Add Test",
	-command=> \&t3_add_sent
)-> pack (-side=> "top",
	-fill=> "x",
	-anchor=> "n",
	-pady=> 10);

my $t3_selAll = $t3_b1db-> Button (-text=> "Select All",
	-command=> \&t3_select_all_s
)-> pack (-side=> "top",
	-fill=> "x",
	-anchor=> "n",
	-pady=> 10);

my $t3_addLib = $t3_b1db-> Button (-text=> "Remove Test",
	-command=> \&t3_rem_sent
)-> pack (-side=> "top",
	-anchor=> "n",
	-fill=> "x",
	-pady=> 10);

#}}}

#}}}

my $t3_book2 = $t3_book-> add ("t3_book2",  #{{{
	-raisecmd=> sub {$t3_kstate = 1;},
	-label=> "Manual Entry");

$t3_book2-> configure (-background => $color_printA);

my $t3_printArea1 = $t3_book2 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t3_printArea1->configure(-font => "pfont");

#}}}

my $t3_book3 = $t3_book-> add ("t3_book3",  #{{{
	-label=> "Analysis Results");

$t3_book3-> configure (-background => $color_printA);

my $t3_printArea2 = $t3_book3 -> Scrolled ( "Text", 
	-background => $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)-> pack (-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t3_printArea2->configure(-font => "pfont");

#}}}

#}}}

my $t3_bottom_2 = $t3_bottom-> Frame (-background => $color_back #{{{
)-> pack (-side=> "left", 
	-padx=> 10,
	-pady=> 10,
	-fill => "both");

my $t3_tag_label = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"Tag Label:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-anchor=>"w");

my $t3_p_tag_label = $t3_bottom_2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t3_label,
	-width=> 15,
	-state=> "normal" 
) -> pack(-side=>"top",
	-anchor=>"w");

my $t3_space = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-pady=> 5,
	-anchor=>"w");

my $t3_digisize = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"Digits on label:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-anchor=>"w");

my $t3_p_digisize = $t3_bottom_2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t3_size,
	-width=> 4,
	-state=> "normal" 
) -> pack(-side=>"top",
	-anchor=>"w");

my $t3_space2 = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-pady=> 5,
	-anchor=>"w");

my $t3_npross = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"Number of processors:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-anchor=>"w");

my $t3_p_npross = $t3_bottom_2 -> Entry (-borderwidth=>1,
	-background => $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t3_pross,
	-width=> 4,
	-state=> "normal" 
) -> pack(-side=>"top",
	-anchor=>"w");

my $t3_space3 = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-pady=> 5,
	-anchor=>"w");

my $t3_kempbasu = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=> "Run statistical analysis with:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-padx=> 5,
	-pady=> 2,
	-anchor=>"w");

my $t3_sel_kemp = $t3_bottom_2-> Radiobutton (-text=> "Kemp - frequentist test",
	-background => $color_back,
	-value=> "kemp",
	-variable=> \$t3_kbvar
)-> pack (-side => "top",
	-anchor => "w");

my $t3_sel_back = $t3_bottom_2-> Radiobutton (-text=> "Basu - Bayesian test (Slower)",
	-background => $color_back,
	-value=> "basu",
	-variable=> \$t3_kbvar
)-> pack (-side => "top",
	-anchor => "w");

my $t3_space3 = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-pady=> 5,
	-anchor=>"w");

my $t3_runback = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=> "Run analysis in:",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-padx=> 5,
	-pady=> 2,
	-anchor=>"w");

my $t3_sel_fore = $t3_bottom_2-> Radiobutton (-text=> "Foreground",
	-background => $color_back,
	-value=> "fg",
	-variable=> \$t3_fbvar,
	-justify=> "left"
)-> pack (-side => "top",
	-anchor => "w");

my $t3_sync_state = "normal";

if (!$thread) {
	$t3_sync_state = "disabled";
}

my $t3_sel_back = $t3_bottom_2-> Radiobutton (-text=> "Background",
	-background => $color_back,
	-value=> "bg",
	-state=> $t3_sync_state,
	-command=> \&t3_set_save,
	-variable=> \$t3_fbvar
)-> pack (-side => "top",
	-anchor => "w");

my $t3_nohup = "normal";

if ($system ne "linux") {
	$t3_nohup = "disabled";
}

my $t3_sel_back = $t3_bottom_2-> Radiobutton (-text=> "Nohup",
	-background => $color_back,
	-value=> "nh",
	-state=> $t3_sync_state,
	-command=> \&t3_set_save,
	-variable=> \$t3_fbvar
)-> pack (-side => "top",
	-anchor => "w");

my $t3_space3 = $t3_bottom_2 -> Label ( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)-> pack(-side=> "top",
	-pady=> 5,
	-anchor=>"w");

my $t3_runButton = $t3_bottom_2-> Button (-text=> "Run analysis",
	-command=> \&t3_kemp
)-> pack (-side => "top",
	-padx=> 5,
	-pady=> 2,
	-anchor => "w");

#}}}

my $t3_name = $main->DialogBox(-title => "Name", #{{{
	-buttons => ["OK", "Cancel"]);
my $t3_name_lab = $t3_name->add("Entry", 
	-textvariable=> \$t3_lib_name
)->pack;

#}}}


#}}}

sub t3_kemp { #{{{
	$main-> configure(-cursor=>"watch");

	$main-> update();

	if ($t3_kstate == 0) {
		my $fsent = "";

		foreach my $lib (keys (%t3_lib_hash)) {
			if ($t3_lib_hash{$lib} == 1) {
				$fsent .= "$lib = $t3_hash{$lib}\n";
			}
		}

		$fsent .= "\n";

		my @sents = keys (%t3_sent_hash);
		my @ssents = sort {$t3_anOrder{$a} <=> $t3_anOrder{$b}} (@sents);
		foreach my $sent (@ssents) {
			$fsent .= "$sent := $t3_sent_hash{$sent}\n";
		}

		$t3_printArea1-> delete ("0.0", "end");
		$t3_printArea1-> insert ("end", $fsent);
	}

	$t3_printArea2-> delete ("0.0", "end");

	my $data = $t3_printArea1-> get ("0.0", "end - 1 chars");

	my $t3_kemp_bg_dial = $main-> Dialog (-title => "Running statistical analysis",
		-text    => "Your job will now be processed.\nYou may follow the progress on the terminal.\nThe results files will be stored in:\n$t3_savePath",
		-buttons => ["Start"]);

	my $t3_kemp_fg_dial = $main-> Dialog (-title => "Running statistical analysis",
		-text    => "Your job will now be processed.\nYou may follow the progress on the terminal.\nPlease wait...\n(It may take a while)",
		-buttons => ["Start"]);

	my $t3_kemp_fg_fdial = $main-> Dialog (-title => "Statistical analysis",
		-text    => "Your job is done.\nYou may save it on the file menu",
		-buttons => ["Ok"]);

	if ($t3_fbvar eq "bg") {
		$t3_kemp_bg_dial-> Show();
		async{
			print "Starting to run asynchronous process\n";
			if (!(open K_FILE, ">$t3_savePath")) {
				print "COULD OPEN $t3_savePath!!!\n";
				exit();
			}

			my @tags = &kemp ($data, $t3_label, $t3_size, $t3_pross, $t3_kbvar);

			foreach my $tag (@tags) {
				print K_FILE "$tag";
			}
			close K_FILE;
			print "\nProcessing done.\nResults saved in $t3_savePath\n";
		};

		$main-> configure(-cursor=>"arrow");
	}
	elsif ($t3_fbvar eq "nh") {
		$t3_kemp_bg_dial-> Show();

		my $print = $t3_printArea1-> get ("0.0", "end - 1 chars");

		if (!(open K_FILE, ">kemp-conf")) {
			print "COULD OPEN kemp-conf!!!\n";
			exit();
		}

		print K_FILE $print;

		system ("nohup ./analysis.pl -kpbd kemp-conf $t3_savePath $t3_size $t3_pross $t3_label $t3_kbvar &");
		$main-> configure(-cursor=>"arrow");
	}

	else {
		$t3_kemp_fg_dial-> Show();
		my @tags = &kemp ($data, $t3_label, $t3_size, $t3_pross, $t3_kbvar);

		foreach my $tag (@tags) {
			$t3_printArea2-> insert ("end", $tag);
		}

		$main-> configure(-cursor=>"arrow");
		$t3_kemp_fg_fdial-> Show();

		$t3_book-> raise("t3_book3");
	}
}

#}}}

sub t3_load_pop { #{{{
	my $ret = $main->getOpenFile (-filetypes => [["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => $t3_file_l,
		-title            => "Load Statistical Analysis Configuration File",
	);

	if ($ret) {
		$t3_file_l = $ret;
		&load_kemp;
		$book-> raise("Kemp");
		$t3_book-> raise ("t3_book2");
	}
}

#}}}

sub t3_add_lib { #{{{
	$t3_lib = $main->getOpenFile (-filetypes => [["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "count.txt",
		-title            => "Add Library",
	);

	if (!$t3_lib) {
		return;
	}


	$t3_lib_name = "Library $t3_lib_count";
	my $back = $t3_name->Show();
	if ($back ne "OK") 	{
		return;
	}


	if ($t3_lib && $t3_lib_name) {
		if (defined $t3_lib_hash{$t3_lib_name}) {
			if ($t3_lib_hash{$t3_lib_name} != 0) {
				print "Redundant Name: [$t3_lib_name]!";
				return;
			}
		}

		my $el = $t3_lib_list->addchild("");
		$t3_lib_list->itemCreate($el, 0, -text=>$t3_lib_name);
		$t3_lib_list->itemCreate($el, 1, -text=> $t3_lib);
		$t3_lib_hash{$t3_lib_name} = 1;
		$t3_hash{$t3_lib_name} = $t3_lib;
	}

	$t3_lib_count++;
}

#}}}

sub t3_rem_lib { #{{{
	my @files = $t3_lib_list->infoSelection();

	foreach my $entry (@files) {
		my $name = $t3_lib_list->itemCget($entry, 0, "-text");
		$t3_lib_hash{$name} = 0;
		$t3_lib_list->delete("entry", $entry);
	}
}

#}}}

sub t3_select_all { #{{{
	my @files = $t3_lib_list->info("child");
	my $size = @files;

	if ($size) {
		$t3_lib_list->selectionSet($files[0], $files[$size - 1]);
	}
}

#}}}

sub t3_merge { #{{{
	my @files = $t3_lib_list->infoSelection();


	if (int(@files) <= 1) {
		$t3_kemp_e2->Show();
		return;
	}

	$t3_lib_name = "Library $t3_lib_count";
	my $back = $t3_name->Show();
	if ($back ne "OK" || !$t3_lib_name) 	{
		return;
	}

	if (defined $t3_lib_hash{$t3_lib_name}) {
		if ($t3_lib_hash{$t3_lib_name} != 0) {
			print "Redundant Name: [$t3_lib_name]!\n";
			return;
		}
	}

	my $hash = "";
	my $merge = "";
	foreach my $entry (@files) {
		my $name = $t3_lib_list->itemCget($entry, 0, "-text");
		$merge .= " + $name";
		if ($t3_lib_hash{$name} == 2) {
			$hash .= " + $t3_hash{$name}";
		}
		else {
			$hash .= " + $name";
		}
	}

	$hash = substr ($hash, 3);

	my $el = $t3_lib_list->addchild("");
	$t3_lib_list->itemCreate($el, 0, -text=>$t3_lib_name);
	$t3_lib_list->itemCreate($el, 1, -text=> substr ($merge, 3));
	$t3_lib_hash{$t3_lib_name} = 2;
	$t3_hash{$t3_lib_name} = $hash;

	$t3_lib_count++;
}

#}}}

sub t3_add_sent { #{{{
	my @files = $t3_lib_list->infoSelection();

	my $sent = "";
	my $ha_sent = "";
	if (int (@files) < 2) {
		$t3_kemp_e1->Show();
		return;
	}

	foreach my $entry (@files) {
		my $name = $t3_lib_list->itemCget($entry, 0, "-text");
		if ($t3_lib_hash{$name} == 1) {
			$ha_sent .= " * $name";
		}
		elsif ($t3_lib_hash{$name} == 2) {
			$ha_sent .= " * $t3_hash{$name}";
		}
		$sent .= " | $name";
	}

	$t3_lib_name = "Analysis_$t3_sent_count";
	my $back = $t3_name->Show();
	if ($back ne "OK" || !$t3_lib_name) 	{
		return;
	}


	$sent = "[" . substr ($sent, 3) . "]";
	my $el = $t3_sent_list->addchild("");
	$t3_sent_list->itemCreate($el, 0, -text=>$t3_lib_name);
	$t3_sent_list->itemCreate($el, 1, -text=> $sent);

	$t3_sent_hash{$t3_lib_name} = substr ($ha_sent, 3);
	$t3_anOrder{$t3_lib_name} = $t3_sent_count;

	$t3_sent_count++;
}

#}}}

sub t3_select_all_s { #{{{
	my @files = $t3_sent_list->info("child");
	my $size = @files;

	if ($size) {
		$t3_sent_list->selectionSet($files[0], $files[$size - 1]);
	}
}

#}}}

sub t3_rem_sent { #{{{
	my @files = $t3_sent_list->infoSelection();

	foreach my $entry (@files) {
		my $name = $t3_sent_list->itemCget($entry, 0, "-text");
		if ($t3_sent_hash{$name}) {
			delete $t3_sent_hash{$name};
		}
		$t3_sent_list->delete("entry", $entry);
	}
}

#}}}

sub t3_set_save { #{{{
	my $file = $main->getSaveFile (-filetypes => [["Comma Separated Values", ".csv"], ["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".csv",
		-initialfile      => "kemp_analysis.csv",
		-title            => "Statistical Analysis Save Path",
	);

	if ($file) {
		$t3_savePath = $file;
		return;
	}

	$t3_fbvar = "fg";
}

#}}}

sub load_kemp { #{{{
	if (!open (IN, "<$t3_file_l")) {
		print "Could not open $t3_file_l, $!\n";
		return;
	}   

	$t3_printArea1-> delete ("0.0", "end");
	$t3_printArea2-> delete ("0.0", "end");
	while (<IN>) {
		$t3_printArea1-> insert ("end", $_);
	}

	close IN;
}

#}}}

#}}}

MainLoop();

sub save_d { #{{{

	my $print = $t2_printArea11-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No ditags to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["Ditag List", ".dt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "ditags.txt",
		-title            => "Save Ditag List",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving ditag list to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_dr { #{{{

	my $print = $t2_printArea12-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No ditag report to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "ditags_extract_report.txt",
		-title            => "Save Ditag Extraction Report",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving ditags extraction report to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_t { #{{{

	my $print = $t2_printArea21-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No tag count to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["Tag Count", ".ct"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "count.txt",
		-title            => "Save Tag Count",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving tag count to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_tt { #{{{

	my $print = $t2_printArea23-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No trimmed tags to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["Tag Count", ".ct"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "trimmed_count.txt",
		-title            => "Save Trimmed Tag Count",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving tag count to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_tr { #{{{

	my $print = $t2_printArea22-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No tag report to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "tag_extract_report.txt",
		-title            => "Save Tags Extraction Report",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving tags extraction report to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_k { #{{{

	my $print = $t3_printArea2-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No kemp analysis to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Comma Separated Values", ".csv"], ["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".csv",
		-initialfile      => "kemp_analysis.csv",
		-title            => "Save Statistical Analysis",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving tag count to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_kr { #{{{

	my $print = $t3_printArea1-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		print "Warning :: No kemp report to save\n";
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".txt",
		-initialfile      => "kemp_configuration.txt",
		-title            => "Save Statistical Configuration File",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving tags extraction report to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub save_kp { #{{{

	my $print = $t3_printArea2-> get ("0.0", "end - 1 chars");
	$print = &clean ($print);

	if (!$print) {
		return;
	}

	my $file = $main->getSaveFile (-filetypes => [["Comma Separated Values", ".csv"], ["Text File", ".txt"], ["All", "*"]],
		-defaultextension => ".csv",
		-initialfile      => "kemp_analysis.csv",
		-title            => "Save Statistical Analysis",
	);

	if (!$file) {
		return;
	}

	if (!open (OUT, ">$file")) {
		print "Could not open $file, $!\n";
		return;
	}	

	print STDERR "Saving kemp analysis to file [$file]...\n";
	print OUT $print;

	close OUT;

}

#}}}

sub extract_ditags { #{{{
	my $file_ref = shift;
	my @sizes;
	my $minimum_size = shift;
	my $maximum_size = shift;
	my $mono = shift;
	my $punc = shift;
	my $lost = shift;
	my @t_ditags = ();

	my @files = @$file_ref;

	my @file_sizes = ();
	my $total_size = 1;

	foreach my $file (@files) {
		my $size = -s $file;
		push (@file_sizes, $size);
		$total_size += $size;
	}

	@t_ditags = ();
	while (@files) {
		my $file =  shift (@files);

		my $file_size = shift (@file_sizes);
		my $size_prop = $file_size / $total_size;

		if (!open (IN, $file)) {
			print STDERR "ERROR! : Could not open file : $file\n\n";
			next;
		}

		push (@t_ditags, "#$file");

		my @content = <IN>;
		close (IN);
		my $concatamer = "";

		while (@content){
			my $entry = shift (@content);
			chomp $entry;
			$entry = &clean ($entry);
			if (!$entry) {
				next;
			}
			elsif ($entry =~ ">") {
				if ($concatamer eq "") {
					#First concatamer
					next;
				}
			}
			else { 
				#mount the concatamer, in case of it being separated in many lines
				$concatamer .= $entry;
				next;
			}
			#use only lower case letters to make it simple
			$concatamer =~ tr/ATCG/atcg/;

			my @ditags = &process_concatamer($minimum_size,$maximum_size,$concatamer, $mono, $punc, $lost);
			foreach my $dtg (@ditags) {
				push (@t_ditags, $dtg);
			}
			$concatamer = "";
		}
		my @ditags = &process_concatamer($minimum_size,$maximum_size,$concatamer, $mono, $punc, $lost);
		foreach my $dtg (@ditags) {
			push (@t_ditags, $dtg);
		}

		$t1_p += $t1_p_bar_s * $size_prop;
		$t1_p_bar-> update();
	}

	return @t_ditags;

	sub process_concatamer {
		my $minimum_size = shift;
		my $maximum_size = shift;
		my $concatamer = shift;
		my $mono = shift;
		my $punc = shift;
		my $lost = shift;
		my @ditags = ();
		push (@ditags, "#===CONCATAMER:\n$concatamer");
		#to control the last entry
		$concatamer .= "X";
		my @all_ditags = split($punc,$concatamer);
		my $size = @all_ditags - 2;
		my $current = 0;
		my $ditag = shift (@all_ditags);
		my $separator = $punc;
		my $comment = $ditag;


		#
		#Processing the first ditag, may be a monotag
		#   
		if (length ($ditag) != 0) {
			if ($mono) {
				my @ret = &process_monotag ($minimum_size, $maximum_size, $ditag, $mono, 0);
				foreach my $dtg (@ret) {
					push (@ditags, $dtg);
				}
			}
			else {
				push (@ditags, "#\tHEAD:$ditag");
			}
		}
		$ditag = shift (@all_ditags);

		while ($current < $size){
			my $size_ditag = length($ditag);
			if ( ($minimum_size <= $size_ditag) &&
				($size_ditag <= $maximum_size)){
				push (@ditags, "#\tGOOD DITAG:$ditag");
				push (@ditags, $ditag);
				$sizes[$size_ditag] += 1;
				$current += 1;
				$ditag = shift(@all_ditags);
				$comment = $ditag
			}
			elsif ($size_ditag > $maximum_size){
				if ($lost) {
					(my $last, my $shorted_ditags) = &process_long_ditags($minimum_size,$maximum_size,$ditag, $punc);
					my @shorted_ditags = @$shorted_ditags;
					foreach my $dtg (@shorted_ditags) {
						push (@ditags, $dtg);
					}
				}
				else {
					push (@ditags, "#\tBAD DITAG(Large:$size_ditag):$ditag\n");
				}

				$current += 1;
				$ditag = shift(@all_ditags);
				$comment = $ditag
			}	 
			else {

				#
				#ditag is too small
				#
				my $next_ditag = shift(@all_ditags);
				my $size_next_ditag = length($next_ditag);
				my $combined_size = $size_ditag + 4 + $size_next_ditag;
				if ((($minimum_size/2) <= ($size_ditag+3)) && 
					(($size_ditag+1) <= ($maximum_size/2)) &&
					(($minimum_size/2) <= ($size_next_ditag+3)) && 
					(($size_next_ditag+1) <= ($maximum_size/2)) &&
					($minimum_size <= $combined_size) && 
					($combined_size <= $maximum_size)){
					#
					#seems that we have catg in the middle of a ditag
					#
					$ditag .= "$separator"."$next_ditag";
					$comment .= "[$punc]$next_ditag";
					$sizes[$combined_size] += 1;
					push (@ditags, "#\tJOINED DITAG:$ditag($comment)");
					push (@ditags, $ditag);
					#
					#get next ditag
					#
					$ditag = shift(@all_ditags);
					$current += 2;
					$comment = $ditag;

				}
				else {
					#
					#we can not accept catg in the middle otherwise
					# discard ditag
					push (@ditags, "#\tBAD DITAG(Small:$size_ditag,$size_next_ditag):$ditag($comment)");
					$sizes[$size_ditag] += 1;
					$ditag = $next_ditag;
					$current += 1;
					$comment = $ditag;
				}
			}
		}
		my $last_size = length ($ditag);
		if ($last_size <= 1) {
			return @ditags;
		}
		$ditag = substr ($ditag, 0, $last_size - 1);

		if (length ($ditag) == 0) {
			return;
		}
		my $rest;
		if ($lost && length ($ditag) > $maximum_size) {
			(my $result, my $ditags_rec) = &process_long_ditags ($minimum_size,$maximum_size,$ditag, $punc);
			my @ditags_rec = @$ditags_rec;
			foreach my $dtg (@ditags_rec) {
				push (@ditags, $dtg);
			}
			$rest = substr ($ditag, $result);
		}
		else {
			$rest = $ditag;
		}
		if ($mono) {
			my @ret = &process_monotag ($minimum_size, $maximum_size, $rest, $mono, 1);
			foreach my $dtg (@ret) {
				push (@ditags, $dtg);
			}
		}
		else {
			push (@ditags, "#\tTAIL:$ditag");
		}
		return @ditags;
	}



	sub process_long_ditags {
		my $minimum_size = shift;
		my $maximum_size = shift;
		my $large_ditag = shift;
		my $punc = shift;
		my @ditags = ();
		my @spunc = split (//, $punc);
		my %ref = ("a", "[ctg]",
			"c", "[atg]",
			"t", "[acg]",
			"g", "[act]");

		my $variations = "(";
		my $punc_size = int (@spunc);
		$variations .= $ref{$spunc[0]} . substr ($punc, 1);
		for (my $i = 1; $i < $punc_size; $i++) {
			$variations .= "|" . substr ($punc, 0, $i) . $ref{$spunc[$i]} . substr ($punc, $i + 1);
		}
		$variations .= ")";
		my @all_fields = split(/$variations/,$large_ditag);
		my $size = @all_fields;
		my $current = 0;

		my $size = length ($large_ditag);
		my $intro = "#\tLARGE DITAG($size):";
		my $sep = 0;
		foreach my $part (@all_fields) {
			if ($sep) {
				$intro .= "[$part]";
				$sep = 0;
			}
			else {
				$intro .= "$part";
				$sep = 1
			}
		}
		push (@ditags, "$intro");

		my $ditag = shift(@all_fields);
		my $separator = shift(@all_fields);
		my $comment = $ditag;
		my $last_good = 0;

		LOOP:
		while ($current < $size){
			my $size_ditag = length($ditag);
			if (($minimum_size <= $size_ditag) && ($size_ditag <= $maximum_size)){
				push (@ditags, "#\t\tRECOVERED DITAG:$ditag($comment)");
				push (@ditags, $ditag);
				$sizes[$size_ditag] += 1;
				$current += 2;
				$ditag = shift(@all_fields);
				$separator = shift(@all_fields);
				$comment = $ditag;
				$last_good += $size_ditag + length ($punc);
			}
			elsif ($size_ditag > $maximum_size){
				#something is REALLY wrong!!
				push (@ditags, "#\t\tBAD DITAG(Large:$size_ditag):$ditag($comment)");
				$sizes[$size_ditag] += 1;
				$current += 2;
				$ditag = shift(@all_fields);
				$separator = shift(@all_fields);
				$comment = $ditag;
			}	 
			else {

				#
				#ditag is too small
				#
				my $next_ditag = shift(@all_fields);
				my $next_separator = shift(@all_fields);
				my $size_next_ditag = length($next_ditag);
				#
				#separator is NOT "catg"
				#   in this case we keep joining ditags until correct size
				#
				$ditag .= $separator.$next_ditag;
				$comment .= "[$separator]$next_ditag";
				$separator = $next_separator;
				$current += 2;
			}

		}
		return ($last_good, \@ditags);

	}

	sub process_monotag {
		my $minimum_size = shift;
		my $maximum_size = shift;
		my $entry = shift;
		my $mono = shift;
		my $side = shift;
		my @ret = ();
		#0 for reverse, 1 to normal
		#
		#see if a ditag may be cutted of at the start
		#
		my $size_ditag = length ($entry);
		if ($size_ditag <= $maximum_size || $mono == 2) {
			#
			#check the size
			#
			my $monotag;
			if ($side) {
				$monotag = substr ($entry, 0, $maximum_size/2);
			}   
			else {
				$monotag = substr ($entry, -$maximum_size/2);
			}   
			if (length ($monotag) >= $minimum_size/2) {
				my $mask = "";
				for (my $i = 0; $i < $maximum_size/2; $i++) {
					$mask .= "X";
				}
				#
				#put it on
				#
				push (@ret, "#\tMONOTAG:$monotag($entry)");
				if ($side) {
					push (@ret, "$monotag$mask");
				}
				else {
					push (@ret, "$mask$monotag");
				}
			}
			else {
				push (@ret, "#\tTOO SHORT MONOTAG:$entry");
			}
		}
		else {
			push (@ret, "#\tTOO LONG MONOTAG:$entry");
		}
		return @ret;
	}

}

#}}}

sub dupDitag { #{{{

	my $data_ref = shift;
	my $minimum_size = shift;
	my $maximum_size = shift;
	my $coesive = shift;
	my $ditag_size;
	my $tcount = 0;
	my $rejected = 0;
	my @mono = ();
	my %hash;
	my %count;
	my %ditag_count = ();
	my %tag_count = ();
	my @out = ();

	my @data = @$data_ref;

	while (my $ditag = pop(@data)) {

		&clean ($ditag);
		#
		#get the ditag size
		#
		if ($ditag =~ "X") {
			push (@out, $ditag);
			next;
		}
		my $dt_size = length ($ditag);
		my $tag1;
		my $tag2;

		my $cut_th = &max ($dt_size + $coesive - $maximum_size, $minimum_size);
		$tag1 = substr ($ditag, 0, $cut_th);
		$tag1 = &cleanX ($tag1);
		$tag2 = &reverseComplement (substr ($ditag, -$cut_th));
		$tag2 = &cleanX ($tag2);

		if (!$tag1 && $tag2) {
			push (@mono, $tag2);
			next;
		}
		elsif ($tag1 && !$tag2) {
			push (@mono, $tag1);
			next;
		}
		elsif (!$tag1 && !$tag2) {
			next;
		}

		$hash{$ditag} = "$tag1#$tag2";

		my $tail1 = &getTail ($tag1);
		my $tail2 = &getTail ($tag2);

		if (defined $count{$tail1}) {
			$count{$tail1}++;
		}
		else {
			$count{$tail1} = 1;
		}

		if (defined $count{$tail2}) {
			$count{$tail2}++;
		}
		else {
			$count{$tail2} = 1;
		}
		$tcount += 2;

		if (exists($ditag_count{$ditag})) {
			$ditag_count{$ditag}++;
		}
		else {
			$ditag_count{$ditag} = 1;
		}

		if (exists($tag_count{$tag1})) {
			$tag_count{$tag1} += 1;
		}
		else {
			$tag_count{$tag1} = 1;
		}

		if (exists($tag_count{$tag2})) {
			$tag_count{$tag2} += 1;
		}
		else {
			$tag_count{$tag2} = 1;
		}
	}


	my $uniq = 0;
	foreach my $ditag (keys(%ditag_count)) {

		$uniq++;

		(my $tag1, my $tag2) = split (/#/, $hash{$ditag});

		my $tail1 = &getTail ($tag1);
		my $tail2 = &getTail ($tag2);

		my $freq_tag1 = $tag_count{$tag1}/$count{$tail1};
		my $freq_tag2 = $tag_count{$tag2}/$count{$tail2}; 

		my $p = ($tag_count{$tag1} / $count{$tail1}) * ($tag_count{$tag2} / $count{$tail2});

		my $var = $tcount * $p * (1 - $p);

		#
		#expect = prob of selecting 2 tags  times the numer of ditags in the bins
		#
		my $expect = $p * ($count{$tail1} + $count{$tail2}) / 2;


		if ($tag1 eq $tag2) {
			$expect /= 2;
		}

		#if ($tail1  eq $tail2){
		#	$expect /= 2;
		#}


		my $xc = (1.96 * $var) / sqrt ($count{$tail1} + $count{$tail2}) + $expect; 

		my $margin = $xc - $ditag_count{$ditag};

		print ("$xc | $ditag_count{$ditag} | $margin\n\t$tag_count{$tag1} | $tag_count{$tag2}\n\t$count{$tail1} | $count{$tail2} | $expect\n");

		push (@out, "#$ditag ($ditag_count{$ditag})$xc");

		my $extra = int (&max (0, -$margin));
		for (my $i = 0; $i < $ditag_count{$ditag} - $extra; $i++) {
			push (@out, $ditag); 
		}
	}

	return @out;

	sub getTail {
		my $tag = shift();
		my $tail = 'X';
		if ($coesive) {
			$tail = substr ($tag, -$coesive);
		}
		return $tail;
	}
	#
	#return the reverse complement of the DNA sequence
	#
	sub reverseComplement {
		my $string = shift();
		my $base;
		my @split;
		@split = split (//, $string);
		$string = "";
		while (@split) {
			$base = pop (@split);
			if ($base eq "a") {
				$string .= "t";
			}
			elsif ($base eq "t") {
				$string .= "a";
			}
			elsif ($base eq "c") {
				$string .= "g";
			}
			else {
				$string .= "c";
			}
		}

		return $string;
	}


	
}

#}}}

sub uniDitag { #{{{
	my $data_ref = shift;

	my %hash;
	my @out = ();
	my @data = @$data_ref;

	foreach my $ditag (@data) {
		if ($ditag =~ "X") {
			push (@out, $ditag);
		}
		elsif (!defined $hash{$ditag}) {
			$hash{$ditag} = 1;
		}
		else {
			$hash{$ditag} += 1;
		}
	}

	push (@out, keys (%hash));
	foreach my $key (keys %hash) {
		push (@out, "#$key=$hash{$key}");
	}

	return @out;
}

#}}}

sub extract_tags { #{{{

	#
	#IMPORTANT: mininum_size and maximum_size at the
	#moment can differ by only 1
	#
	my $data = shift;
	my $minimum_size = shift;
	my $maximum_size = shift;
	my $coesive = shift;
	my %hash = ();
	my %count = ();
	#
	#fist separate individual tags from ditags
	#

	my @tags_ret = ();

	my @data = split (/\n/, $data);

	my $data_size = @data;
	if (!$data_size) {
		return;
	}
	my $done = 0;
	my $prop = $t2_p_bar_s / $data_size;

	foreach my $ditag  (@data) {
		chomp ($ditag);
		$ditag = &clean ($ditag);
		($ditag) = split (/#/, $ditag);
		$ditag = &clean ($ditag);
		if (!$ditag) {
			next;
		}
		$done++;
		#
		#get the ditag size
		#
		my $dt_size = length ($ditag);
		my $tag1;
		my $tag2;

		my $cut_th = &max ($dt_size + $coesive - $maximum_size, $minimum_size);
		$tag1 = substr ($ditag, 0, $cut_th);
		$tag1 = &cleanX ($tag1);
		$tag2 = &revcomp (substr ($ditag, -$cut_th));
		$tag2 = &cleanX ($tag2);

		my $size1 = length ($tag1);
		my $size2 = length ($tag2);

		if ($size1 <= $maximum_size && $size1 >= $minimum_size) {
			$count{$tag1}++;

			my $key = substr ($tag1, 0, $minimum_size);

			if (exists ($hash{$key})){
				if ($hash{$key} !~ m/\#$tag1\#/){
					$hash{$key} .= "$tag1#";
				}
			}
			else {
				$hash{$key} = "#$tag1#";
			}
			$t2_p += $prop;
			$done++;
		}

		if ($size2 <= $maximum_size && $size2 >= $minimum_size) {
			$count{$tag2}++;

			my $key = substr ($tag2, 0, $minimum_size);

			if (exists ($hash{$key})){
				if ($hash{$key} !~ m/\#$tag2\#/) {
					$hash{$key} .= "$tag2#";
				}
			}
			else {
				$hash{$key} = "#$tag2#";
			}

			$t2_p += $prop;
			$done++;
		}
		if ($done >= 1000) {
			$done = 0;
			$t1_p_bar->update();
		}
	}
	my $total = 0;
	#
#first print individual tag count
	#
#print "INDIVIDUAL TAG COUNTS:\n";
	foreach my $key (keys (%count)){
		push (@tags_ret, "$key=$count{$key}\n");
		$total += $count{$key};
	}


	#
	#now we try to make sense of tags with different sizes
	#as of now, when tags of different sizes are compatible, we
	#compute all counts to the tag with minimum size
	#
	push (@tags_ret, "\%PROCESSED TAG COUNTS:\n");
	my $unique = (keys (%hash));
	push (@tags_ret, "\%total different tags(may be redundant)=$unique\nConflicts:\n");
	my $numberOfTagsInConflict = 0;
	my $numberOfKeysInConflict = 0;
	my $totalUniqueTags = 0;
	foreach my $key (keys (%hash)){
		my $string = $hash{$key};
		#
		#need to remove first and last "#"
		#
		$string =~ s/^\#//;
		$string =~ s/\#$//;
		my @tags = split ("#",$string);
		push (@tags_ret, "%DEBUG:$key=>$string<=\n");
		my $num_tags = @tags;
		@tags = sort {$b cmp $a} (@tags);
		my $partial_count = 0;
		my $non_redundant_tags = shift (@tags);
		$partial_count = $count{$non_redundant_tags};
		my $has_subtags;
		foreach my $tag (@tags) {
			#$totalGoodTags += $count{$tag};
			if ($non_redundant_tags !~ m/$tag/){
				$non_redundant_tags .= " $tag";
			}
			else {
				$has_subtags = 1;
			}
			$partial_count += $count{$tag};
		}
		my @final_tags = split (" ",$non_redundant_tags);
		my $num_tags = @final_tags;
		if ($num_tags > 1) {
			if ($has_subtags) {
				$numberOfKeysInConflict += 1;
				push (@tags_ret, "%\t BAD, conflicts:$key$count{$key})==>");
				foreach my $tag (@final_tags){
					push (@tags_ret, "%$tag($count{$tag}) ");
				}
				push (@tags_ret, "%\n");
				$numberOfTagsInConflict += $partial_count;
			}
			else {
				push (@tags_ret, "%=>OK, no conflict\n");
				foreach my $tag (@final_tags){
					my $count = $count{$tag};
					push (@tags_ret, "%$tag=$count\n");
					$totalUniqueTags +=$count;
				}
			}


		}
		else {
			$totalUniqueTags += $partial_count;
			my $the_tag = shift(@final_tags);
			push (@tags_ret, "%$the_tag=$partial_count \n");
		}
	}
	push (@tags_ret, "%(REDUNDANT KEYS, TAGS IN CONFLICT, TOTAL TAGS, TOTAL GOOD TAGS)= $numberOfKeysInConflict, $numberOfTagsInConflict, $total, $totalUniqueTags\n");
	push (@tags_ret, "%====\n");


	return @tags_ret;

	sub revcomp {
		my $original = shift;
		$original =~ tr/acgtACGT/tgcaTGCA/;
		my @chars = split (//,$original);
		my @reversed;
		while (my $char = shift (@chars)){
			unshift (@reversed, $char);
		}
		my $result = join ("",@reversed);
		return $result;
	}
}

#}}}

sub trim_tags { #{{{

	my $raw_data = shift;
	my $size = shift;

	if ($size <= 0) {
		return;
	}

	my %new_counts = ();

	my @data = split ("\n", $raw_data);

	my $total = 0;
	my %counts;

	foreach my $entry (@data) {
		chomp ($entry);
		if (!$entry) {
			next;
		}
		(my $tag, my $count) = split (/=/, $entry);

		$total += $count;

		if (defined $counts{$tag}) {
			$counts{$tag} += $count;
		}
		else {
			$counts{$tag} = $count;
		}
	}

	if ($total == 0) {
		return;
	}

	foreach my $tag (%counts) {
		my $count = $counts{$tag};

		for(my $i = 1; $i <= $count; $i++) {
			my $new_tag;
			$new_tag = substr ($tag, 0, $size);
			if (exists ($new_counts{$new_tag} )) {
				$new_counts{$new_tag} += 1;
			}
			else{
				$new_counts{$new_tag} = 1;
			}
		}
	}

	return %new_counts;
}

#}}}

sub kemp { #{{{
	my %count = ();
	my %ref = ();
	my %hash_lib = ();
	my %l_count = ();
	my @soma = ();
	my @sentences = ();
	my $data = shift;
	my $pref_name = shift;
	my $digit = shift;
	my $p = shift;
	my $type = shift;

	my %tags = ();

	my $k = 0;

	my @ret = ();

	my @data = split (/\n/, $data);

	foreach my $in (@data) {
		&clean ($in);
		if (!$in) {
			next;
		}

		#
		#Indentify sentence by the ':=' ponctuation adter the reference name
		#
		if ($in =~ m/:=/) {
			(my $name, my $sent) = split (/:=/, $in);
			$name = &clean ($name);
			$sent = &clean ($sent);

			my @sentence;
			if ($sent=~ m/\*/) {
				@sentence = split (/\s*\*\s*/, $sent);
			}
			else {
				print "\n";
				print STDERR "WARNING: Invalid sentence!: [$sent]\n";
				next;
			}

			%count = ();
			@soma = ();

			my $n = 0;
			$k++;

			if (!$name) {
				$name = "sentence".$k;
			}

			foreach my $case (@sentence) {
				my @splitted = split (/\s*\+\s*/, $case);
				my $end = shift (@splitted);

				if (!defined $hash_lib{$end}) {
					print "ERROR: $end library not defined!\n";
					return;
				}

				$n++;

				while (@splitted) {
					my $next = shift (@splitted);

					if (!defined $hash_lib{$end.$next}) {
						my $href = &join_hash($end, $next, \%hash_lib);
						%hash_lib = %$href;
					}
					$end .= $next;
				}
				%l_count = %{$hash_lib{$end}};
				(my $href, my $soma) = &addCount ($n, \%count, \%l_count);
				%count = %$href;
				push (@soma, $soma);
			}

			my $lines = keys (%count);

			open TEMP, ">$name" or die "Could not open $name: $!\n";

			print TEMP ($lines + 1, " $n\n");
			print TEMP ("@soma \n");

			my @keys = sort (keys (%count));

			foreach my $key (@keys) {
				print TEMP ("@{$count{$key}}\n");
			}

			close TEMP;

			$tags{$name} = \@keys;

			push (@sentences, $name);

			print ("Processing sequence: [$name]...\n$type.bin -n $p $name\n\n");
			my $err = system ("$type.bin -n $p $name");
			if ($err != 0) {
				print ("Warning! An error has ocurred while running \"$type.bin -n $p $name\"\n");
			}

			print ($a, "\n");

		}

		#
		#Add reference to the hash
		#
		else {
			(my $name, my $ref) = split (/\s+=\s+/, $in);
			if (!$ref) {
				($name, $ref) = split (/\s*=\s*/, $in);
				if (!$ref) {
					($name, $ref) = split (/\s+/, $in);
					if (!$ref) {
						print STDERR "WARNING: Invalid reference!: [$in]\n";
						next;
					}
				}
			}

			$name = &clean ($name);
			$ref = &clean ($ref);

			if (exists $ref{$name}) {
				print STDERR "WARNING: $name already defined [$name:=$ref{$name}]. Substituting...\n"; 
			}
			$ref{$name} = $ref;
			my $hasho = &read_lib ($ref, $name, \%hash_lib);
			%hash_lib = %$hasho;
		}
	}

	close INPUT;


	%count = ();
	my $n = 0;


	foreach my $sentence (@sentences) {
		if (!open KFILE, "<$sentence"."-$type") {
			print "COULD NOT FIND $sentence"."-$type!\n$!\n";
			return;
		}

		$n++;

		my @tags = @{$tags{$sentence}};

		my %pvhash;

		<KFILE>;
		while (defined (my $line = <KFILE>) && defined (my $tag = shift (@tags))) {
			chomp $line;
			my @scores = split (/\t/, $line);
			my $score = "$scores[0],$scores[1],$scores[2]";
			$pvhash{$tag} = $score;
		}

		%l_count = %pvhash;
		(my $href, my $soma) = &addCount ($n, \%count, \%l_count);
		%count = %$href;
		push (@soma, $soma);

		close KFILE;
		close TFILE;
	}

	my @sortRef = sort (keys (%ref));

	push (@ret, "tag name,sequence");
	foreach my $lib (@sortRef) {
		push (@ret, ",$lib");
	}
	foreach my $sentence (@sentences) {
		push (@ret, ",$sentence:pvalue,score,category");
	}
	push (@ret, "\n");

	my $name_c = 1;

	foreach my $key (sort (keys (%count))) {
		my $pr = sprintf ("%0$digit"."d", $name_c++);
		push (@ret, "$pref_name$pr,$key");
		foreach my $lib (@sortRef) {
			if (defined $hash_lib{$lib}{$key}) {
				push (@ret, ",$hash_lib{$lib}{$key}");
			}
			else {
				push (@ret, ",0");
			}
		}
		foreach my $count (@{$count{$key}}) {
			push (@ret, ",$count");
		}
		push (@ret, "\n");
	}

	return @ret;


	sub addCount {
		my $readed = shift;
		my $href = shift;
		my $lref = shift;

		my %count = %$href;
		my %l_count = %$lref;

		my @ckeys = sort (keys (%count));
		my @rkeys = sort (keys (%l_count));

		my $soma = 0;

		my $i = 0;
		my $j = 0;

		my $ii = @rkeys;
		my $jj = @ckeys;

		while ($i < $ii && $j < $jj) {
			my $rkey = $rkeys[$i];
			my $ckey = $ckeys[$j];

			if ($rkey gt $ckey) {
				push (@{$count{$ckey}}, 0);
				$j++;
			}
			elsif ($rkey lt $ckey) {
				for (my $k = 1; $k < $readed; $k++) {
					push (@{$count{$rkey}}, 0);
				}
				push (@{$count{$rkey}}, $l_count{$rkey});
				$soma += $l_count{$rkey};
				$i++;
			}
			else {
				push (@{$count{$rkey}}, $l_count{$rkey});
				$soma += $l_count{$rkey};
				$i++;
				$j++;
			}
		}
		while ($i < $ii) {
			for (my $k = 1; $k < $readed; $k++) {
				push (@{$count{$rkeys[$i]}}, 0);
			}
			push (@{$count{$rkeys[$i]}}, $l_count{$rkeys[$i]});
			$soma += $l_count{$rkeys[$i]};
			$i++;
		}
		while ($j < $jj) {
			push (@{$count{$ckeys[$j]}}, 0);
			$j++;
		}

		return (\%count, $soma);
	}

	sub read_lib {
		my $file = shift;
		my $ref = shift;
		my $href = shift;
		my %hash = %$href;

		open OUT, "<$file" or die "COULD NOT OPEN $file!\n$!\n";

		while (my $in = <OUT>) {
			chomp $in;
			(my $tag, my $count) = split (/\s*=\s*/, $in);
			&clean ($tag);
			&clean ($in);

			$hash{$ref}{$tag} = $count;
		}

		return \%hash;
	}

	sub join_hash {
		my $hash1 = shift;
		my $hash2 = shift;
		my $ref = shift;
		my %hash_lib = %$ref;

		my $mhash = $hash1.$hash2;

		foreach my $key (keys (%{$hash_lib{$hash1}})) {
			$hash_lib{$mhash}{$key} = $hash_lib{$hash1}{$key};
		}
		foreach my $key (keys (%{$hash_lib{$hash2}})) {
			if (defined $hash_lib{$hash1}{$key}) {
				$hash_lib{$mhash}{$key} += $hash_lib{$hash2}{$key};
			}
			else {
				$hash_lib{$mhash}{$key} = $hash_lib{$hash2}{$key};
			}
		}

		return \%hash_lib;
	}

}

#}}}

sub clean { #{{{
	my $string = shift;

	if ($string) {
		$string =~ s/^\s+//;
		$string =~ s/\s+$//;
	}

	return $string;
}

#}}}

sub cleanX { #{{{
	my $string = shift;

	$string =~ s/^X+//;
	$string =~ s/X+$//;

	return $string;
}

#}}}

sub max { #{{{
	my $a = shift;
	my $b = shift;
	if ($a > $b) {
		return $a;
	}
	else {
		return $b;
	}
}

#}}}

