pax_global_header00006660000000000000000000000064131225720720014513gustar00rootroot0000000000000052 comment=ea913cec0a7305ecc089eb1c19e6437edc34fcae cdhit-4.6.8/000077500000000000000000000000001312257207200126255ustar00rootroot00000000000000cdhit-4.6.8/ChangeLog000066400000000000000000000044511312257207200144030ustar00rootroot00000000000000 CD-HIT ChangeLog CD-HIT-V4.6.1 (2012-08-27): Fix: a minor bug in handling masking letters; Add: a few minor changes and fixings to conform to debian packaging rules. CD-HIT-V4.6 (2012-04-25): Add: better auto tuning (for -M 0) of word table size for both single and multiple threaded execution; Fix: a minor bug for very long input sequences; Add: compiling option to change MAX_SEQ. CD-HIT-V4.5.8 (2012-03-24): Add: handling of asterisk at the end of sequences; Add: a few minor improvements in the parallelization; Add: new options -mask and -bak. CD-HIT-V4.5.7 (2011-12-16): Add: minor improvements to the word table size handling; Add: updated documentation file. CD-HIT-V4.5.6 (2011-09-02): Fix: -M for cd-hit-2d and cd-hit-est-2d; Fix: handling of invalid input sequences. CD-HIT-V4.5.5: Fix: a minor bug in option handling for score setting (-match, -mismatch); Fix: a minor bug in printing logs to stdout for cd-hit-2d and cd-hit-2d-est. CD-HIT-V4.5.4: Add: support for FASTQ file as input; Add: improvement to sequence partition for parallelization; Change: default identity threshold from 0.9 to 0.95 for EST. CD-HIT-V4.5.3: Add: cd-hit-454 program to the main package (cdhit-454.c++); Add: options to change the scoring settings; Add: options to control the length of unmatched region. CD-HIT-V4.5.2: MinorChange: default value of "-n" for DNA sequence from 8 to 10; MinorFix: alignment locations and length; CD-HIT-V4.5.1: MinorChange: default value of "-r" from 0 to 1; MinorFix: alignment length for "-G 0". CD-HIT-V4.5: Remove: multi-level counting; Fix: support for "-F" option. CD-HIT-V4.5-Beta3: Change: default word table size for "-M 0"; Fix: global identity computation. CD-HIT-V4.5-Beta2: Fix: alignment position and identity. CD-HIT-V4.5-Beta: Change: local band alignment; Change: filter threshold calculation; Fix: best alignment band searching; CD-HIT-V4.3: Fix: a few bugs related to multi-level counting; Change: implementation for -M option. CD-HIT-V4.2.x: Some bug fixings. CD-HIT-V4.2: Add: multi-level counting array to improve the speed. CD-HIT-V4.1.1: Change: improve estimating alignment band for sequences with low complexity. CD-HIT-V4.1: Fix: a bug in searching best alignment band; Fix: a bug in handling 'N' for EST; CD-HIT-V4.0: New implementation with parallelization using OpenMP. cdhit-4.6.8/FET.pl000077500000000000000000000061201312257207200136020ustar00rootroot00000000000000#!/usr/bin/perl use Storable; use strict; use Text::NSP::Measures::2D::Fisher::right; my $clstr_file = shift; my $anno_file = shift; my $store_file = shift; my @cls_list = (); my @fun_list = (); my $cur_cls = ""; my %cls2rep = (); my @cur_anno = (); open(TMP, $clstr_file) || die; while(my $ll = ) { # read .clstr files if ($ll =~ /^>/) { # the begin of a cluster $cur_cls = $ll; $cur_cls =~ s/^>(.*?)\s$/$1/; # print "$cur_cls|\n"; } else{ chop($ll); if ($ll =~ /^(\d+)\s+(\d+)(aa|nt),\s+>(.+)\.\.\./) { my @tmp = split(/\|\|/,$4); if ($#tmp == 0){ @cur_anno = (); } else{ @cur_anno = split(/,/, pop(@tmp)); } # print $cur_cls.$cur_anno[0]."|\n"; push(@cls_list, $cur_cls); push(@fun_list, [@cur_anno]); if ($ll =~ /^(\d+)\s+(\d+)(aa|nt),\s+>(.+)\.\.\.(.*)\*$/){ # print "$4\n"; $cls2rep{$cur_cls} = $4; # print "$cur_cls\t$4\n"; } } } } #print join("\n", @cls_list[0..10]); @cls_list = map {$cls2rep{$_}} @cls_list; #print join("\n", @cls_list[0..10]); #print "\n"; #foreach my $i (0..10){ # print join("\t",@{$fun_list[$i]}); # print "\n"; #} #print join("\n", @fun_list[0..10]); #exit(1); my %cls_size = (); my %cls_anno = (); my %anno_size = (); my $M = $#fun_list+1; #print $#fun_list."\t".$M."\n"; #print $#cls_list."\t".$M."\n"; foreach my $i (0..$#fun_list){ $cls_size{$cls_list[$i]}++; if ($#{$fun_list[$i]} >= 0) { # have annotation foreach my $anno (@{$fun_list[$i]}){ # print "$i\t$cls_list[$i]\t$anno\n"; $anno_size{$anno}++; $cls_anno{$cls_list[$i]}{$anno}++; } } } #while (my ($a,$b) = each %anno_size){ # print "$a\t$b\n"; #} #print "COG0171\t".$anno_ my %resu = (); while(my ($cls, $cls_s) = each %cls_size){ my @tmp = (); # $resu{$cls} = []; while (my ($anno,$anno_s) = each %{$cls_anno{$cls}}){ # print "$cls\t$cls_s\t$anno\t$anno_s\t$anno_size{$anno}"; # print "\n"; my $pvalue = calculateStatistic(n11=>$anno_s, n1p=>$cls_s, np1=>$anno_size{$anno}, npp=>$M); # anno_term, anno_size, clsper, anno_total, backper, enrichment, pvalue push @tmp, [$anno, $anno_s, $anno_s/$cls_s, $anno_size{$anno}, $anno_size{$anno}/$M, $anno_s*$M/($cls_s*$anno_size{$anno}), $pvalue]; # push $resu{$cls}, [sort{$a[0] <=> $b[0]} @tmp]; } @tmp = sort {$$a[6] <=> $$b[6]} @tmp; $resu{$cls} = [@tmp]; } store \%resu, $store_file; open(TMP, "> $anno_file") || die; print TMP "ClsName\tClsSize\tAnno_term\tAnno_size\tClsPer\tAnno_total\tSeq_total\tBackPer\tEnrichment\tPvalue\n"; while(my ($cls, $info) = each %resu){ foreach my $a (@{$info}){ #[$pvalue, $enrichment, $anno_s, $anno] print TMP join("\t",($cls, $cls_size{$cls}, $a->[0], $a->[1], $a->[2], $a->[3], $M, $a->[4], $a->[5], $a->[6]))."\n"; # print "$cls\t".join("\t",@{$a})."\n"; } # print "$cls\t$#{$info}\n"; } close(TMP) cdhit-4.6.8/Makefile000066400000000000000000000043561312257207200142750ustar00rootroot00000000000000 CC = g++ -Wall -ggdb CC = g++ -pg CC = g++ # without OpenMP # with OpenMP # in command line: # make openmp=yes ifeq ($(openmp),no) CCFLAGS = -DNO_OPENMP else CCFLAGS = -fopenmp endif # support debugging # in command line: # make debug=yes # make openmp=yes debug=yes ifeq ($(debug),yes) CCFLAGS += -ggdb else CCFLAGS += -O2 endif ifdef MAX_SEQ CCFLAGS += -DMAX_SEQ=$(MAX_SEQ) endif #LDFLAGS = -static -o LDFLAGS += -o PROGS = cd-hit cd-hit-est cd-hit-2d cd-hit-est-2d cd-hit-div cd-hit-454 # Propagate hardening flags CCFLAGS := $(CPPFLAGS) $(CCFLAGS) $(CXXFLAGS) .c++.o: $(CC) $(CCFLAGS) -c $< all: $(PROGS) clean: rm -f *.o $(PROGS) # programs cd-hit: cdhit-common.o cdhit-utility.o cdhit.o $(CC) $(CCFLAGS) cdhit.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit cd-hit-2d: cdhit-common.o cdhit-utility.o cdhit-2d.o $(CC) $(CCFLAGS) cdhit-2d.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit-2d cd-hit-est: cdhit-common.o cdhit-utility.o cdhit-est.o $(CC) $(CCFLAGS) cdhit-est.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit-est cd-hit-est-2d: cdhit-common.o cdhit-utility.o cdhit-est-2d.o $(CC) $(CCFLAGS) cdhit-est-2d.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit-est-2d cd-hit-div: cdhit-common.o cdhit-utility.o cdhit-div.o $(CC) $(CCFLAGS) cdhit-div.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit-div cd-hit-454: cdhit-common.o cdhit-utility.o cdhit-454.o $(CC) $(CCFLAGS) cdhit-454.o cdhit-common.o cdhit-utility.o $(LDFLAGS) cd-hit-454 # objects cdhit-common.o: cdhit-common.c++ cdhit-common.h $(CC) $(CCFLAGS) cdhit-common.c++ -c cdhit-utility.o: cdhit-utility.c++ cdhit-utility.h $(CC) $(CCFLAGS) cdhit-utility.c++ -c cdhit.o: cdhit.c++ cdhit-utility.h $(CC) $(CCFLAGS) cdhit.c++ -c cdhit-2d.o: cdhit-2d.c++ cdhit-utility.h $(CC) $(CCFLAGS) cdhit-2d.c++ -c cdhit-est.o: cdhit-est.c++ cdhit-utility.h $(CC) $(CCFLAGS) cdhit-est.c++ -c cdhit-est-2d.o: cdhit-est-2d.c++ cdhit-utility.h $(CC) $(CCFLAGS) cdhit-est-2d.c++ -c cdhit-div.o: cdhit-div.c++ cdhit-common.h $(CC) $(CCFLAGS) cdhit-div.c++ -c cdhit-454.o: cdhit-454.c++ cdhit-common.h $(CC) $(CCFLAGS) cdhit-454.c++ -c PREFIX ?= /usr/local/bin install: for prog in $(PROGS); do \ install -m 0755 $$prog $(PREFIX); \ done install -m 0755 *.pl $(PREFIX); cdhit-4.6.8/README000066400000000000000000000010621312257207200135040ustar00rootroot00000000000000For cd-hit How to compile? 1. Compile with multi-threading support (default): make 2. Compile without multi-threading support (if you are on very old systems): make openmp=no For cd-hit-auxtools cd cd-hit-auxtools make For psi-cd-hit please download legacy BLAST (not BLAST+) and install the executables in your $PATH For more information, please visit http://cd-hit.org Most up-to-date documents are available at https://github.com/weizhongli/cdhit/wiki cd-hit is also available as web server, visit http://cd-hit.org for web server address. cdhit-4.6.8/cd-hit-2d-para.pl000077500000000000000000000304251312257207200155650ustar00rootroot00000000000000#!/usr/bin/perl -w # ============================================================================= # CD-HIT # http://cd-hit.org/ # http://bioinformatics.burnham.org/cd-hi # # program written by # Weizhong Li # UCSD, San Diego Supercomputer Center # La Jolla, CA, 92093 # Email liwz@sdsc.edu # ============================================================================= use strict; no strict "refs"; my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; $script_dir = "./" unless ($script_dir); chop($script_dir); my $arg; my $in; my $indb2; my $out; my $arg_pass = ""; my $para = ""; my $host_no = 0; my @hosts = (); my $cd_hit_div_exe = "$script_dir/cd-hit-div"; my $cd_hit_div_pl = "$script_dir/cd-hit-div.pl"; my $cd_hit_2d_exe = "$script_dir/cd-hit-2d"; my $cd_hit_est_2d_exe = "$script_dir/cd-hit-est-2d"; my $clstr_merge_exe = "$script_dir/clstr_merge.pl"; my $seg_no = 2; my $seg_no2 = 8; my $restart_in = ""; my $queue = 0; my $local_cpu = 0; my $queue_type = "PBS"; my $prog = "cd-hit-2d"; my %stable_files = (); while ($arg=shift) { if ($arg eq "-h" ) { print_usage();} elsif ($arg eq "-i" ) { $in = shift; } elsif ($arg eq "-i2") { $indb2 = shift; } elsif ($arg eq "-o" ) { $out = shift; } elsif ($arg eq "--B") { $para = shift; } elsif ($arg eq "--L") { $local_cpu = shift; } elsif ($arg eq "--P") { $prog = shift; } elsif ($arg eq "--S") { $seg_no = shift; } elsif ($arg eq "--S2") { $seg_no2 = shift; } elsif ($arg eq "--Q" ) { $queue = shift; } elsif ($arg eq "--T" ) { $queue_type = shift; } elsif ($arg eq "--R" ) { $restart_in = shift; } else {$arg_pass .= " $arg "; } } ($in and $out) || print_usage(); if (not ($seg_no2 >1)) { die "You are not dividing 2nd input db, parallel mode won't help"; } if ($prog eq "cd-hit-est") { $cd_hit_2d_exe = $cd_hit_est_2d_exe; } my $pwd = `pwd`; chop($pwd); my $work_dir = "$out.cd-hit-para-tmp"; my $restart_file = "$out.restart"; my $indiv = "$work_dir/$in.div"; my $indiv2 = "$work_dir/$indb2.div"; my @commands = (); my @command_status = (); my $command_no = 0; my $cmd; my ($i, $j, $k, $i1, $j1, $k1); # readin a list of hosts if ($para) { open(PARA, "$para") || die "can not open $para"; while(my $ll= ){ chop($ll); $ll =~ s/\s//g; next unless ($ll); push(@hosts, $ll); $host_no++; } close(PARA); } if ($queue) { for ($i=0; $i<$queue; $i++) { push(@hosts, "queue_host.$i"); } $host_no = $queue; } if ($local_cpu) { for ($i=0; $i<$local_cpu; $i++) { push(@hosts, "localhost.$i"); } $host_no = $local_cpu; } die "no host" unless $host_no; if ($host_no > $seg_no2) { print "$indb2 was divided into $seg_no2 pieces, "; print "Your number of hosts ($host_no) is more than $seg_no, "; print "So, not all of hosts will be used\n"; } if (-e $restart_in) { read_restart(); } else { $cmd = `mkdir $work_dir`; assign_commands(); write_restart(); } #dbdiv run on master node? if ($command_status[0] eq "wait") { $cmd = `$commands[0]`; $command_status[0] = "done"; write_restart(); for ($i=0; $i<$seg_no; $i++) { my $idb = "$indiv-$i"; $stable_files{$idb} = 1; } } if ($command_status[1] eq "wait") { $cmd = `$commands[1]`; $command_status[1] = "done"; write_restart(); for ($i=0; $i<$seg_no2; $i++) { my $idb = "$indiv2-$i"; $stable_files{$idb} = 1; } } #main runing loop my $sleep_time = 1; while(1) { #refresh job status by checking output files #check whether all jobs are done or not my $finish_flag = 1; my $status_change = 0; for ($i=2; $i<$command_no; $i++) { next if ($command_status[$i] eq "done"); $finish_flag = 0; my $tcmd = $commands[$i]; my $output = ""; if ($tcmd =~ / -o\s+(\S+)/) { $output = $1; if ((-s $output) or (-s "$output.clstr")) { $command_status[$i] = "done"; $status_change = 1; } } } if ($status_change) { write_restart(); } else { sleep($sleep_time); print "."; } last if $finish_flag; my $job_sent = 0; for ($i=2; $i<$command_no; $i++) { next if ($command_status[$i] eq "done"); next if ($command_status[$i] eq "run"); my $tcmd = $commands[$i]; my $in1 = ""; my $in2 = ""; my $out_done = ""; if ($tcmd =~ / -i\s+(\S+)/ ) {$in1 = $1;} if ($tcmd =~ / -i2\s+(\S+)/) {$in2 = $1;} if ($tcmd =~ / -o\s+(\S+)/ ) {$out_done = "$1.done";} my $input_flag = 0; if (($in1 =~ /\S/) and ($in2 =~ /\S/)) { $input_flag = 1 if ((-s $in1) and (-s $in2)); } elsif ($in1 =~ /\S/) { $input_flag = 1 if (-s $in1); } else { die "Error at $tcmd\n"; } next unless $input_flag; #now input files are ready, wait wait_stable_file($in1); wait_stable_file($in2); my $thost_idx = wait_for_available_host(); my $thost = $hosts[$thost_idx]; my $tsh = "$work_dir/$out.$$.$thost_idx.sh"; my $tlock = "$work_dir/$out.$$.$thost_idx.lock"; my $trm = ""; $trm = "rm -f $in2" if ($in2 =~ /\S/); open(TSH, "> $tsh") || die; $cmd = `date > $tlock`; print TSH < $tlock $tcmd $trm rm -f $tlock date > $out_done EOD close(TSH); if ($local_cpu) { $cmd = `sh $tsh >/dev/null 2>&1 &`; $command_status[$i] = "run"; print "run at $thost $tcmd\n"; } elsif ($queue and ($queue_type eq "PBS")) { my $t = "para-$thost_idx"; open(QUEUE,"| qsub -N $t -o $t.log -e $t.err"); print QUEUE "cd $pwd; sh $tsh"; close(QUEUE); $command_status[$i] = "run"; } elsif ($queue and ($queue_type eq "SGE")) { my $t = "para-$thost_idx"; open(QUEUE,"| qsub -N $t"); print QUEUE </dev/null 2>&1 &'`; $command_status[$i] = "run"; print "run at $thost $tcmd\n"; } $sleep_time = 1; $job_sent = 1; last; } if ((not $job_sent) and ($sleep_time < 60)) { $sleep_time +=5; } } ############ main run loop ######## merge all .clstr file my $out_clstr = "$out.clstr"; if (not -s $out_clstr) { my @indb2_left = (); for ($i=0; $i<$seg_no; $i++) { my @t_clstr = (); for ($j=0; $j<$seg_no2; $j++) { my $tclstr = "$indiv2-$j.vs.$i.clstr"; if (-s $tclstr) {push(@t_clstr,$tclstr); } else {die "No file $tclstr\n";} if ($i==($seg_no-1)) { push(@indb2_left, "$indiv2-$j.vs.$i"); } } #merge my $tclstrs = join(" ", @t_clstr); if (@t_clstr > 1) { print "$clstr_merge_exe $tclstrs >> $out_clstr\n"; $cmd = `$clstr_merge_exe $tclstrs >> $out_clstr`; } else { print "cat $tclstrs >> $out_clstr"; $cmd = `cat $tclstrs >> $out_clstr`; } } my $out_clstr_ren = "$out.clstr.$$"; open(TMP, $out_clstr) || die; open(OTMP, "> $out_clstr_ren") || die; my $no = 0; my $cno; my $ll; while($ll=){ if ($ll =~ /^>Cluster (\d+)/) { print OTMP ">Cluster $no\n"; $no++; $cno = 0; } else { $ll =~ s/^\d+/$cno/; print OTMP $ll; $cno++; } } close(TMP); close(OTMP); sleep(10); $cmd = `mv $out_clstr_ren $out_clstr`; my $reps = join(" ", @indb2_left); $cmd = `cat $reps > $out`; } if (1) { $cmd = `grep CPU $work_dir/*log`; my @lls = split(/\n/, $cmd); my $cpu = 0; my $ll; foreach $ll (@lls) { if ($ll =~ /CPU\s+time\s+(\d+)/) { $cpu += $1; } } print "Total CPU time: $cpu\n"; } sub wait_for_available_host { my ($i, $j, $k); my $sleep = 30; while(1) { for ($i=0; $i<$host_no; $i++) { my $thost = $hosts[$i]; my $tlock = "$work_dir/$out.$$.$i.lock"; next if (-e $tlock); return $i; } sleep($sleep); $sleep +=30; if ($sleep >= 300) { $sleep = 30; } } } ########## END wait_for_available_host sub wait_stable_file { my ($i, $j, $k); my $f = shift; return if ($stable_files{$f}); return unless (-e $f); if (-e "$f.done") { $stable_files{$f} = 1; return; } my $size0 = -s $f; while(1) { sleep(10); my $size1 = -s $f; if ($size0 == $size1) { $stable_files{$f} = 1; last; } else {$size0 = $size1; } } } ########## END wait_stable_file sub write_restart { my ($i, $j, $k); open(RES, "> $restart_file") || die; for ($i=0; $i<$command_no; $i++) { print RES "$commands[$i]\n$command_status[$i]\n"; } close(RES); } ########## END write_restart sub assign_commands { my ($i, $j, $k); my $cmd; my ($idb, $idbo, $jdb, $jdbo, $idbout, $idblog, $jdblog); $command_no = 0; if ($seg_no >1) {$cmd = "$cd_hit_div_exe -i $in -o $indiv -div $seg_no";} elsif ($seg_no==1) {$cmd = "ln -s ../$in $indiv-0";} else {die "Wrong --S option";} push(@commands, $cmd); push(@command_status, "wait"); $command_no++; if ($seg_no2 >1){$cmd = "$cd_hit_div_pl $indb2 $indiv2 $seg_no2";} elsif ($seg_no2==1){$cmd = "ln -s ../$indb2 $indiv2-0"; } push(@commands, $cmd); push(@command_status, "wait"); $command_no++; for ($j=0; $j<$seg_no2; $j++) { #j for db2 $jdb = "$indiv2-$j"; $jdblog = "$jdb.log"; for ($i=0; $i<$seg_no; $i++) { $idb = "$indiv-$i"; $jdbo = "$indiv2-$j.vs.$i"; $cmd = "$cd_hit_2d_exe -i $idb -i2 $jdb -o $jdbo $arg_pass >> $jdblog"; push(@commands, $cmd); push(@command_status, "wait"); $command_no++; $jdb = $jdbo; } } } #### END assign_commands sub read_restart { $command_no = 0; open(RRRR, "$restart_in") || die; my $ll; while ($ll = ) { chop($ll); push(@commands, $ll); $ll = ; chop($ll); push(@command_status, $ll); $command_no++; } close(RRRR); } ########## END read_restart sub print_usage { print < #include "bioSequence.hxx" using namespace Min; using namespace Bio; Min::String Bio::Sequence::GetDescription( int deslen ) { String des = Description(); int i = 0; if( des[i] == '>' || des[i] == '@' || des[i] == '+' ) i += 1; if( des[i] == ' ' || des[i] == '\t' ) i += 1; if( deslen == 0 || deslen > des.Size() ) deslen = des.Size(); while( i < deslen and ! isspace( des[i] ) ) i += 1; des.Resize( i ); return des; } const char *dna_reverse_complimentary = "TBGDEFCHIJKLMNOPQRSAAVWXYZ"; void Bio::Sequence::ToReverseComplimentary() { int i, j; int n = seq.Size(); int m = (n/2) + (n%2); for(i=0, j=n-1; i%s\n", des.Data() ); }else{ fprintf( fout, ">%i\n", id ); } fprintf( fout, "%s\n", seq.Data() ); } } #define BUFSIZE 1024 int Bio::SequenceCache::Update( int max, bool idonly ) { char buf[ BUFSIZE+1 ]; char *res = NULL; FILE *fin = inputFile; String & ds = buffer.Description(); String & ss = buffer.SequenceData(); String & qs = buffer.QualityScore(); Clear(); if( fin == NULL ) return 0; while( feof( fin ) == 0 ){ if( (res=fgets( buf, BUFSIZE, fin )) == NULL ) break; if( getdes && (buf[0] == '>' || buf[0] == '@' || buf[0] == '+') ){ getdes = 0; if( buf[0] == '+' ){ current = & qs; }else{ if( ss.Size() ){ ss.ToUpper(); sequences.Append( new Sequence( buffer ) ); buffer.Reset(); if( sequences.Size() % 100000 == 0 ) printf( "Read %9i sequences ...\n", (int)sequences.Size() ); } current = & ss; ds = buf + 1; while( ds[ds.Size()-1] != '\n' ){ if( (res=fgets( buf, BUFSIZE, fin )) == NULL ) break; ds += buf; } ds.Chop(); if( idonly ){ int d = 0; while( d < ds.Size() && isspace( ds[d] ) ==0 ) d += 1; ds.Resize( d ); } //printf( "%s\n", ds->Data() ); if( max > 0 && (int)sequences.Size() >= max ) return sequences.Size(); } }else{ assert( current != NULL ); *current += buf; while( current->Size() && isspace( (*current)[current->Size()-1] ) ) current->Chop(); getdes = current == & ss || (current == & qs && qs.Size() == ss.Size()); } } if( ss.Size() ){ sequences.Append( new Sequence( buffer ) ); buffer.Reset(); } return sequences.Size(); } bool Bio::SequenceList::ReadFastAQ( const Min::String & file, bool idonly, FILE *fout_log ) { char buf[ BUFSIZE+1 ]; FILE *fin = fopen( file.Data(), "r" ); bool wasEmpty = sequences.Size() == 0; char *res = NULL; int max = 0, min = 0x7fffffff; int getdes = 1; Sequence one; String & ds = one.Description(); String & ss = one.SequenceData(); String & qs = one.QualityScore(); String *data=NULL; if( fin == NULL ) return 0; while( feof( fin ) == 0 ){ if( (res=fgets( buf, BUFSIZE, fin )) == NULL ) break; if( getdes && (buf[0] == '>' || buf[0] == '@' || buf[0] == '+') ){ getdes = 0; if( buf[0] == '+' ){ data = & qs; }else{ if( ss.Size() ){ ss.ToUpper(); if( ss.Size() > max ) max = ss.Size(); if( ss.Size() < min ) min = ss.Size(); sequences.Append( new Sequence( one ) ); one.Reset(); if( sequences.Size() % 100000 == 0 ) fprintf( fout_log, "Read %9i sequences ...\n", (int)sequences.Size() ); } data = & ss; ds = buf + 1; while( ds[ds.Size()-1] != '\n' ){ if( (res=fgets( buf, BUFSIZE, fin )) == NULL ) break; ds += buf; } ds.Chop(); if( idonly ){ int d = 0; while( d < ds.Size() && isspace( ds[d] ) ==0 ) d += 1; ds.Resize( d ); } //printf( "%s\n", ds->Data() ); } }else{ *data += buf; while( data->Size() && isspace( (*data)[data->Size()-1] ) ) data->Chop(); getdes = data == & ss || (data == & qs && qs.Size() == ss.Size()); } } fclose( fin ); if( ss.Size() ){ if( ss.Size() > max ) max = ss.Size(); if( ss.Size() < min ) min = ss.Size(); sequences.Append( new Sequence( one ) ); } if( wasEmpty ){ max_length = max; min_length = min; }else{ if( max > max_length ) max_length = max; if( min < min_length ) min_length = min; } return true; } void Bio::SequenceList::SortByLength() { if( max_length == min_length ) return; int i; int N = sequences.Size(); int M = max_length - min_length + 1; Min::Array count( M, 0 ); // count for each size = max_len - i Min::Array accum( M, 0 ); // count for all size > max_len - i Min::Array offset( M, 0 ); // offset from accum[i] when filling sorting Min::Array sorting( N ); for (i=0; iLength() ] ++; for (i=1; iLength(); int id = accum[len] + offset[len]; //sequences[i].index = id; sorting[id] = sequences[i]; offset[len] ++; } sequences.Swap( sorting ); } int Bio::SequenceList::RemoveEmptySequences() { int i, M=0, N = sequences.Size(); for(i=0; iLength() == 0 ){ delete sequences[i]; continue; } sequences[M++] = sequences[i]; } sequences.Resize( M ); } void Bio::SequenceList::Shuffle() { int i, N = sequences.Size(); if( N <= 1 ) return; for(i=N-1; i>=0; i--){ int rnd = (int)(i * (rand() / (1.0 + RAND_MAX))); Sequence *seq = sequences[i]; sequences[i] = sequences[rnd]; sequences[rnd] = seq; } } cdhit-4.6.8/cd-hit-auxtools/bioSequence.hxx000066400000000000000000000053301312257207200206450ustar00rootroot00000000000000//================================================================= // This file is a part of cdhit-dup. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) //================================================================= #include #include #include "minArray.hxx" #include "minString.hxx" #define BEGIN_NS_BIO namespace Bio { #define END_NS_BIO } BEGIN_NS_BIO class Sequence { uint32_t id; Min::String des; Min::String seq; Min::String qs; public: Sequence(){ id = 0; } #if 0 Sequence( const Sequence & other ){ id = other.id; des = other.des; seq = other.seq; qs = other.qs; } #endif void Copy( const Sequence & other ){ des = other.des; seq = other.seq; qs = other.qs; } int Length()const{ return seq.Size(); } Min::String& Description(){ return des; } Min::String& SequenceData(){ return seq; } Min::String& QualityScore(){ return qs; } Min::String GetDescription( int deslen = 0 ); void Reset(){ des.Reset(); seq.Reset(); qs.Reset(); } void ToReverseComplimentary(); void Print( FILE *fout = stdout, int width = 0 ); }; class SequenceCache { Min::Array sequences; FILE *inputFile; bool getdes; Sequence buffer; Min::String *current; public: SequenceCache( const Min::String & file ){ inputFile = fopen( file.Data(), "r" ); current = NULL; getdes = true; } ~SequenceCache(){ if( inputFile ) fclose( inputFile ); Clear(); } void Clear(){ for(int i=0,n=sequences.Size(); i sequences; int max_length; int min_length; public: SequenceList(){ max_length = min_length = 0; } ~SequenceList(){ Clear(); } void Clear(){ for(int i=0,n=sequences.Size(); iLength(); iLength() > max_length ) max_length = sequences[i]->Length(); } return max_length; } int MinLength(){ int i, N = sequences.Size(); if( N == 0 ) return 0; for(i=1, min_length = sequences[0]->Length(); iLength() < min_length ) min_length = sequences[i]->Length(); } return min_length; } int RemoveEmptySequences(); void Shuffle(); Sequence* operator[]( int i )const{ return sequences[i]; } }; END_NS_BIO cdhit-4.6.8/cd-hit-auxtools/cd-hit-dup-PE-out.pl000077500000000000000000000055131312257207200212620ustar00rootroot00000000000000#!/usr/bin/perl my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; chop($script_dir); $script_dir = "./" unless ($script_dir); use Getopt::Std; getopts("i:j:o:p:c:",\%opts); die usage() unless ($opts{i} and $opts{j} and $opts{o} and $opts{p} and $opts{c} ); my ($i, $j, $k, $cmd); my ($ll, $lla, $llb, $id, $ida, $idb, $seq, $seqa, $seqb, $qua, $quaa, $quab); my ($len, $lena, $lenb); my %FHZ=(); my $fastq1 = $opts{i}; my $fastq2 = $opts{j}; my $clstr_file = $opts{c}; my $outfile1 = $opts{o}; my $outfile2 = $opts{p}; my $format = input_test($fastq1); #fasta or fastq my %rep_ids = (); open(TMP, $clstr_file) || die "can not open $clstr_file"; while($ll = ){ if ($ll =~ /^>/) { next; } else { chop($ll); if ($ll =~ /\*$/) { if ($ll =~ /\s(\d+)(aa|nt), >(.+)\.\.\./) { my $id = $3; $rep_ids{$id} = 1; } } } } close(TMP); open(INPUTa, $fastq1) || die "can not open $fastq1"; open(OUTa, "> $outfile1") || die "can not write to $outfile1"; open(INPUTb, $fastq2) || die "can not open $fastq2"; open(OUTb, "> $outfile2") || die "can not write to $outfile2"; if ($format eq "fasta") { my $flag; while($lla = and $llb=) { if ( ($lla =~ /^>/) and ($llb =~ /^>/) ) { my $ida = substr($lla,1); chop($ida); $ida =~ s/\s.+$//; my $idb = substr($llb,1); chop($idb); $idb =~ s/\s.+$//; $flag = (($rep_ids{$ida}) or ($rep_ids{$idb})) ? 1 : 0; } if ($flag) { print OUTa $lla; print OUTb $llb; } } } else { my $flag; while($lla = and $llb=) { if ( ($lla =~ /^@/) and ($llb =~ /^@/) ) { my $ida = substr($lla,1); chop($ida); $ida =~ s/\s.+$//; my $idb = substr($llb,1); chop($idb); $idb =~ s/\s.+$//; $flag = (($rep_ids{$ida}) or ($rep_ids{$idb})) ? 1 : 0; if ($flag) { print OUTa $lla; print OUTb $llb; $lla = ; print OUTa $lla; $lla = ; print OUTa $lla; $lla = ; print OUTa $lla; $llb = ; print OUTb $llb; $llb = ; print OUTb $llb; $llb = ; print OUTb $llb; } } } } close(INPUTa); close(OUTa); close(INPUTb); close(OUTb); sub usage { <; close(TTT); my $c = substr($ll,0,1); if ($c eq ">") {return "fasta";} else {return "fastq";} } cdhit-4.6.8/cd-hit-auxtools/cdhit-dup.cxx000066400000000000000000000766751312257207200203030ustar00rootroot00000000000000//================================================================= // This file is a part of cdhit-dup. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) //================================================================= #include #include #include "minString.hxx" #include "minArray.hxx" #include "minMap.hxx" #include "bioSequence.hxx" using namespace Min; using namespace Bio; class SequenceCluster : public Array { int id; int abundance; int chiHead; int chiTail; public: SequenceCluster( Sequence *rep = NULL ){ id = 0; abundance = 0; chiHead = chiTail = 0; if( rep ) Append( rep ); } String GetDescription( Sequence *seq, int deslen=0 ); int GetID()const{ return id; } void SetID( int i ){ id = i; } int GetAbundance()const{ return abundance; } void SetAbundance( int ab ){ abundance = ab; } int GetChimericParent1()const{ return chiHead; } int GetChimericParent2()const{ return chiTail; } void SetChimericParent( int head, int tail ){ chiHead = head; chiTail = tail; } void Write( FILE *fout = stdout, int id = 0, int deslen=0, const char *des=NULL ); bool operator<( const SequenceCluster & other ){ assert( Size() && other.Size() ); return (*this)[0]->Length() < other[0]->Length(); } }; String SequenceCluster::GetDescription( Sequence *seq, int deslen ) { String des = seq->Description(); int i = 0; if( des[i] == '>' || des[i] == '@' || des[i] == '+' ) i += 1; if( des[i] == ' ' || des[i] == '\t' ) i += 1; if( deslen == 0 || deslen > des.Size() ) deslen = des.Size(); while( i < deslen and ! isspace( des[i] ) ) i += 1; des.Resize( i ); return des; } void SequenceCluster::Write( FILE *fout, int id, int deslen, const char *cdes ) { //Array & seqs = *this; SequenceCluster & seqs = *this; String des = GetDescription( seqs[0], deslen ); int i = 0, n = Size(); fprintf( fout, ">Cluster %i%s\n", id, cdes ? cdes : "" ); fprintf( fout, "%i\t%int, >%s... *\n", 0, seqs[0]->Length(), des.Data() ); for(i=1; iLength(); int mm = CountMismatch( seqs[0]->SequenceData(), seqs[i]->SequenceData() ); fprintf( fout, "%i\t%int, >%s... at 1:%i:1:%i/+/%.2f%%\n", i, len, des.Data(), len, len, 100*(len-mm)/(float)len ); } } void WriteClusters( Array & clusters, const String & name = "temp.txt", int deslen = 0 ) { String cfile = name + ".clstr"; String cfile2 = name + "2.clstr"; FILE *fout1 = fopen( name.Data(), "w" ); FILE *fout2 = fopen( cfile.Data(), "w" ); FILE *fout3 = fopen( cfile2.Data(), "w" ); char cdes[200]; int i, n = clusters.Size(); int k1 = 0, k2 = 0; for(i=0; iPrint( fout1 ); cluster.SetID( k1 ); cluster.Write( fout2, k1++, deslen ); }else{ head = clusters[head].GetID(); tail = clusters[tail].GetID(); sprintf( cdes, " chimeric_parent1=%i,chimeric_parent2=%i", head, tail ); cluster.Write( fout3, k2++, deslen, cdes ); } } fclose( fout1 ); fclose( fout2 ); fclose( fout3 ); } //liwz //skip fout1 since R1 being modified due to padding void WriteClusters_clstronly( Array & clusters, const String & name = "temp.txt", int deslen = 0 ) { String cfile = name + ".clstr"; String cfile2 = name + "2.clstr"; // FILE *fout1 = fopen( name.Data(), "w" ); FILE *fout2 = fopen( cfile.Data(), "w" ); FILE *fout3 = fopen( cfile2.Data(), "w" ); char cdes[200]; int i, n = clusters.Size(); int k1 = 0, k2 = 0; for(i=0; iPrint( fout1 ); cluster.SetID( k1 ); cluster.Write( fout2, k1++, deslen ); }else{ head = clusters[head].GetID(); tail = clusters[tail].GetID(); sprintf( cdes, " chimeric_parent1=%i,chimeric_parent2=%i", head, tail ); cluster.Write( fout3, k2++, deslen, cdes ); } } // fclose( fout1 ); fclose( fout2 ); fclose( fout3 ); } void WriteClusters_seqonly( Array & clusters, const String & name = "temp.txt", int deslen = 0 ) { FILE *fout1 = fopen( name.Data(), "w" ); int i, n = clusters.Size(); for(i=0; iPrint( fout1 ); } } fclose( fout1 ); } void SortByAbundance( Array & clusters ) { int i, max = 0, min = 0; int N = clusters.Size(); if( N <= 1 ) return; max = min = clusters[0].GetAbundance(); for(i=1; i max ) max = ab; if( ab < min ) min = ab; } int M = max - min + 1; Min::Array count( M, 0 ); // count for each size = max_len - i Min::Array accum( M, 0 ); // count for all size > max_len - i Min::Array offset( M, 0 ); // offset from accum[i] when filling sorting Array sorted( N ); for (i=0; i= min ); return (int)sqrt( (len - min) / 10); } int HashingLength( int dep, int min ) { return min + 10 * dep * dep; } struct ChimericSource { int index; int head; int tail; ChimericSource( int i=0, int h=0, int t=0 ){ index = i; head = h; tail = t; } }; struct HashHit { int index; int offset; HashHit( int i = 0, int o = 0 ){ index = i; offset = o; } }; #define MAX_OFFSETS 5 struct HashHit3 { int index; int size; int offsets[MAX_OFFSETS]; int counts[MAX_OFFSETS]; // number of word hits with the corresponding offsets; HashHit3( int i = 0, int o = 0 ){ memset( offsets, 0, MAX_OFFSETS*sizeof(int) ); memset( counts, 0, MAX_OFFSETS*sizeof(int) ); index = i; size = 1; offsets[0] = o; counts[0] = 1; } void Update( int o ){ int imin = 0, min = counts[0]; for(int i=0; i max ){ max = counts[i]; imax = i; } } //printf( "BestOffset: %i %i %i %i\n", max, imax, size, offsets[imax] ); return offsets[imax]; } }; typedef Hash > HashHitTable; void UpdateHashTables( Array > & middles, String & seq, int id, int shared, int min, int primer ) { unsigned int hash = MakeHash( seq, shared ); int j, k; for(j=primer; (j+shared)<=seq.Size(); j+=shared){ int dep = j ? 0 : HashingDepth( seq.Size()-j, min ); for(k=0; k<=dep; k++){ hash = MakeHash( seq, j, HashingLength( k, min ) ); middles[j][k][hash].Append( id ); } } } void ClusterDuplicate( SequenceList & seqlist, Array & clusters, bool mlen, int errors = 0, float errors2 = 0.0 ) { int primer = 0; int maxmm = errors; unsigned int hash; int i, j, k, K, K2, M, N = seqlist.Count(); int shared, min, count = 0; int max = seqlist.MaxLength(); Hash > wholes; Array > > > middles; Node > *node; String & first = seqlist[0]->SequenceData(); primer = first.Size(); for(i=1; iSequenceData(), 0, primer, 0 ); if( primer < 15 ){ primer = 0; break; } } if( errors == 0 ) maxmm = max * errors2; printf( "primer = %i\n", primer ); shared = (seqlist.MinLength() - primer) / (maxmm + 1); if( shared < 30 ) shared = 30; min = shared; middles.Resize( max ); for(i=0; (i+shared)<=max; i++) middles[i].Resize( HashingDepth( max - i, min ) + 1 ); for(i=0; iSequenceData(); int qlen = seq.Size(); bool clustered = false; maxmm = errors; if( errors == 0 ) maxmm = qlen * errors2; if( i && (i%10000 == 0) ) printf( "Clustered %9i sequences with %9i clusters ...\n", i, (int)clusters.Size() ); hash = MakeHash( seq ); node = wholes.Find( hash ); if( node != NULL ){ Array & hits = node->value; for(j=0, M=hits.Size(); jSequenceData(); if( qlen == rep.Size() && Compare( seq, rep ) == 0 ){ clust.Append( seqlist[i] ); clustered = true; break; } } if( clustered ) continue; for(j=0, M=hits.Size(); jSequenceData(); if( mlen && rep.Size() != qlen ) continue; K = ComparePrefix( seq, rep, maxmm ); if( K == qlen ){ clust.Append( seqlist[i] ); clustered = true; break; } } if( clustered ) continue; } int dep = HashingDepth( qlen - primer, min ); int hashlen = HashingLength( dep, min ); hash = MakeHash( seq, primer, hashlen ); node = middles[primer][ dep ].Find( hash ); if( node ){ Array & hits = node->value; for(j=0, M=hits.Size(); jSequenceData(); if( mlen && rep.Size() != qlen ) continue; K = ComparePrefix( seq, rep, maxmm ); if( K == qlen ){ clustered = true; clust.Append( seqlist[i] ); break; } } } //seqlists[i]->Print(); int start = primer; dep = 0;//HashingDepth( shared, min ); while( maxmm == 0 && clustered == false && (start+2*shared) <= qlen && start <= primer + (maxmm+1) * shared ){ hash = MakeHash( seq, start, shared ); node = middles[start][ dep ].Find( hash ); start += shared; if( node == NULL ) continue; Array & hits = node->value; for(j=0, M=hits.Size(); jSequenceData(); if( mlen && rep.Size() != qlen ) continue; K = ComparePrefix( seq, rep, maxmm ); if( K == qlen ){ clustered = true; clust.Append( seqlist[i] ); break; } } } if( clustered == false ){ hash = MakeHash( seq ); UpdateHashTables( middles, seq, clusters.Size(), shared, min, primer ); wholes[ hash ].Append( clusters.Size() ); clusters.Append( SequenceCluster( seqlist[i] ) ); } } } void PrintChimeric( FILE *fout, Sequence *SQ, Sequence *SA, Sequence *SB, int IX, int GAP = 0 ) { String A( SA->SequenceData() ), B( SB->SequenceData() ), Q( SQ->SequenceData() ); fprintf( fout, "\nQuery = %s\n", SQ->Description().Data() ); fprintf( fout, "Parent A = %s\n", SA->Description().Data() ); fprintf( fout, "Parent B = %s\n", SB->Description().Data() ); fprintf( fout, "Crossover = %i\n", IX ); //if( offset != 0 ) fprintf( fout, "Offset = %i\n", offset ); //fprintf( fout, "LQA = %i\n", LQA ); //fprintf( fout, "LQB = %i\n", LQB ); //fprintf( fout, "RQA = %i\n", RQA ); //fprintf( fout, "RQB = %i\n", RQB ); if( GAP > 0 ){ while( GAP-- > 0 ) B.Insert( '-', IX ); }else if( GAP < 0 ){ while( GAP++ < 0 ){ A.Insert( '-', IX ); Q.Insert( '-', IX ); } } A.Insert( "|X|", IX ); Q.Insert( "|X|", IX ); B.Insert( "|X|", IX ); int I, J, W = 80; int LA = A.Size(); int LB = B.Size(); int LQ = Q.Size(); int L = LA; if( L < LB ) L = LB; if( L < LQ ) L = LQ; for(I=0; ISequenceData() ), B( SB->SequenceData() ), Q( SQ->SequenceData() ); fprintf( fout, "\nQuery = %s\n", SQ->Description().Data() ); fprintf( fout, "Parent A = %s\n", SA->Description().Data() ); fprintf( fout, "Parent B = %s\n", SB->Description().Data() ); fprintf( fout, "Crossover = %i\n", IX ); //if( offset != 0 ) fprintf( fout, "Offset = %i\n", offset ); //fprintf( fout, "LQA = %i\n", LQA ); //fprintf( fout, "LQB = %i\n", LQB ); //fprintf( fout, "RQA = %i\n", RQA ); //fprintf( fout, "RQB = %i\n", RQB ); if( offset > 0 ){ while( offset-- > 0 ){ A.Insert( '-', 0 ); Q.Insert( '-', 0 ); } }else if( offset < 0 ){ while( offset++ < 0 ) B.Insert( '-', 0 ); } A.Insert( "|X|", IX ); Q.Insert( "|X|", IX ); B.Insert( "|X|", IX ); int I, J, W = 80; int LA = A.Size(); int LB = B.Size(); int LQ = Q.Size(); int L = LA; if( L < LB ) L = LB; if( L < LQ ) L = LQ; for(I=0; Ioffset = offset; this->count = count; } bool operator<( const OffsetCount & other )const{ if( count != other.count ) return count > other.count; return offset < other.offset; } }; void DetectChimeric( Array & clusters, Array & chistat, int max, int shared, float percent, float abratio = 1, int minabu = 2 ) { int primer = 20; unsigned int hash; int i, j, k, K, K2, M, N = clusters.Size(); int min, count = 0, maxmm = 2, maxmm2 = maxmm + maxmm; Hash > hashTable; Node > *node; Hash chimap; Array hitMapping; Array hashes; Array hitList; Array parentAList; Array parentBList; Array offsetCounts; FILE *debug = NULL; if( N <= 2 ) return; if( shared < 20 ) shared = 20; min = shared; //debug = fopen( "debug.txt", "w+" ); hitList.Resize( N ); hitMapping.Resize( N ); String & first = clusters[0][0]->SequenceData(); primer = first.Size(); for(i=1; iSequenceData(), 0, primer, 0 ); if( primer < 15 ){ primer = 0; break; } } printf( "primer = %i\n", primer ); printf( "Searching for chimeric clusters ...\n" ); for(i=0; iSequenceData(); int qlen = seq.Size(); int qn = clusters[i].GetAbundance(); int maxmm = (int)(0.01*qlen*percent); int maxmm2 = (int)(0.015*qlen*percent); if( i && i % 1000 ==0 ) printf( "Checked %9i clusters, detected %9i chimeric clusters\n", i, (int)chistat.Size() ); if( qn < minabu ) break; hashes.ResetSize( primer ); for(j=primer; j<=qlen-shared; j++) hashes.Append( MakeHash( seq, j, shared ) ); if( qlen < (2*shared + primer) ){ for(j=primer,k=hashes.Size(); jPrint(); HashHit3 *hit = & hitList[0]; for(j=0,M=hitList.Size(); jindex] = 0; hitList.ResetSize( 0 ); bool detected = false; bool duplicate = false; int start = primer; int dep = 0; int proto = -1; int protomm = max; while( (start + shared) <= qlen ){ hash = hashes[start]; node = hashTable.Find( hash ); start += 1; if( node == NULL ) continue; Array & hits = node->value; for(j=0, M=hits.Size(); j & hits = hitList; for(j=0, M=hits.Size(); jSequenceData(); if( clusters[hit].GetAbundance() < qn*abratio ) continue; offsetCounts.ResetSize( 0 ); for(k=0; k= (primer + shared) ) parentAList.Append( ParentInfo( hit, 0, head, 0 ) ); int best = offsetCounts[0].offset; for(k=0; k<2; k++){ // check the best two offsets: best = offsetCounts[k].offset; if( qlen + best < rep.Size() ){ tail = CompareSuffix( seq, qlen-1, rep, qlen+best-1, 0, maxmm ); if( tail >= shared ){ parentBList.Append( ParentInfo( hit, qlen - tail + best, tail, best ) ); break; } }else{ tail = CompareSuffix( seq, rep.Size()-best-1, rep, rep.Size()-1, 0, maxmm ); if( tail >= shared ){ parentBList.Append( ParentInfo( hit, rep.Size() - tail, tail, best ) ); break; } } tail = 0; } if( (head + tail) >= qlen ){ int X = (head + qlen - tail) / 2; int mm = CountMismatch2( seq, rep, 0, X, maxmm2 ); mm += CountMismatch3( seq, X, rep, X+best, qlen, maxmm2 ); //printf( "\noffset = %5i; mm = %5i\n", best, mm ); //PrintChimeric2( stdout, clusters[i][0], clusters[hit][0], clusters[hit][0], X, best ); if( mm <= maxmm2 /*&& rep.Size() >= qlen*/ ){ if( mm < protomm ){ protomm = mm; proto = hit; } } }else{ int mm = CountMismatch2( seq, rep, 0, qlen, maxmm2 ); if( mm <= maxmm2 /*&& rep.Size() >= qlen*/ ){ if( mm < protomm ){ protomm = mm; proto = hit; } } } } if( protomm <= maxmm ){ if( chimap.Find( proto ) ){ ChimericSource cs = chistat[chimap[proto]]; chimap[i] = chistat.Size(); chistat.Append( ChimericSource( i, cs.head, cs.tail ) ); } continue; } //printf( "debug: %9i %9i %9i\n", (int)hitList.Size(), (int)parentAList.Size(), (int)parentBList.Size() ); parentBList.QuickSort(); for(j=0, M=parentAList.Size(); jSequenceData(); for(k=0; kSequenceData(); if( infoA.index == infoB.index ) continue; if( (infoB.start - infoB.offset) > infoA.len ) break; int XA = (infoA.len + infoB.start - infoB.offset) / 2; int XB = XA + infoB.offset; int LQA = CountMismatch( seq, repA, 0, XA ); int RQA = CountMismatch( seq, repA, XA, qlen ); int LQB = CountMismatch3( seq, 0, repB, 0, XA, qlen ); int RQB = CountMismatch3( seq, XA, repB, XB, qlen - XA, qlen ); if( proto < 0 ) protomm = maxmm2; if( LQB > (protomm + maxmm) && RQA > (protomm + maxmm) && (LQA + RQB) <= protomm ) { //PrintChimeric2( stdout, clusters[i][0], clusters[infoA.index][0], clusters[infoB.index][0], XA, infoB.offset ); detected = true; chimap[i] = chistat.Size(); chistat.Append( ChimericSource( i, infoA.index, infoB.index ) ); count += 1; break; } } if( detected ) break; } //if( (i+1) % 1000 ==0 ) printf( "Checked %9i clusters, detected %9i chimeric clusters\n", i+1, chistat.Size() ); //if( detected == false && duplicate == false ){ if( detected == false ){ for(j=primer; j max2 ? max1 : max2; if( uselen <= 0 ) uselen = max; if( uselen > max ) uselen = max; N = seqlist.Count(); for(k=0; kQualityScore().Size(); String & s1 = first->SequenceData(); String & s2 = second->SequenceData(); String & qs1 = first->QualityScore(); String & qs2 = second->QualityScore(); int n1 = s1.Size(); int n2 = s2.Size(); int i, j, m = 1; if( n1 < uselen ){ s1.Resize( uselen, 'N' ); qs1.Resize( uselen, 0 ); } if( n2 < uselen ){ s2.Resize( uselen, 'N' ); qs2.Resize( uselen, 0 ); seqlist2_modified = 1; } seqlist[k]->SequenceData().Chop( n1 - uselen ); seqlist[k]->SequenceData() += s2.Data(); seqlist[k]->SequenceData().Chop( n2 - uselen ); if( qs ){ seqlist[k]->QualityScore().Chop( n1 - uselen ); seqlist[k]->QualityScore() += qs2.Data(); seqlist[k]->QualityScore().Chop( n2 - uselen ); } } seqlist_modified = 1; }else if( uselen > 0 ){ N = seqlist.Count(); for(k=0; kQualityScore().Size(); String & s1 = first->SequenceData(); String & qs1 = first->QualityScore(); int n1 = s1.Size(); int i, j, m = 1; if( n1 < uselen ) continue; seqlist_modified = 1; seqlist[k]->SequenceData().Chop( n1 - uselen ); if( qs ) seqlist[k]->QualityScore().Chop( n1 - uselen ); } } if( seqlist.Count() == 0 ){ printf( "Abort: no sequence available for the analysis!\n" ); return 1; } if( seqlist.MaxLength() != seqlist.MinLength() ){ seqlist.SortByLength(); printf( "Sorted by length ...\n" ); } Array clusters; Array chistat; printf( "Start clustering duplicated sequences ...\n" ); ClusterDuplicate( seqlist, clusters, matchLength, errors, errors2 ); printf( "Number of reads: %i\n", seqlist.Count() ); printf( "Number of clusters found: %i\n", clusters.Size() ); for(i=0, m=clusters.Size(); iDescription(); int ab = 1; int pos = des.Find( "_abundance_" ); if( pos ) ab = strtol( des.Data() + pos + 10, NULL, 10 ); clusters[i].SetAbundance( ab ); } } SortByAbundance( clusters ); DetectChimeric( clusters, chistat, seqlist.MaxLength(), shared, percent, abratio, abundance ); for(i=0, m=0; i seqlist N = seqlist.Count(); for(k=0; kQualityScore().Size(); seqlist[k]->SequenceData().Reset(); seqlist[k]->SequenceData() += seqlist2[k]->SequenceData(); seqlist[k]->Description().Reset(); seqlist[k]->Description() += seqlist2[k]->Description(); if( qs ){ seqlist[k]->QualityScore().Reset(); seqlist[k]->QualityScore() += seqlist2[k]->QualityScore(); } seqlist_modified = 1; } // write R2 printf( "Write R2 reads\n" ); WriteClusters_seqonly( clusters, output2, deslen ); } if (seqlist_modified){ // since seqlist was nodified, re-read from file, this time use seqlist2 as storage seqlist2.Clear(); if( not seqlist2.ReadFastAQ( input ) ){ printf( "File openning failed: %s\n", input.Data() ); return 1; } // copy seqlist2 => seqlist N = seqlist.Count(); for(k=0; kQualityScore().Size(); seqlist[k]->SequenceData().Reset(); seqlist[k]->SequenceData() += seqlist2[k]->SequenceData(); seqlist[k]->Description().Reset(); seqlist[k]->Description() += seqlist2[k]->Description(); if( qs ){ seqlist[k]->QualityScore().Reset(); seqlist[k]->QualityScore() += seqlist2[k]->QualityScore(); } } // overwrite R1 if R1 was modified printf( "Write R1 reads\n" ); WriteClusters_seqonly( clusters, output, deslen ); } printf( "Done!\n" ); return 0; } cdhit-4.6.8/cd-hit-auxtools/cdhit-lap.cxx000066400000000000000000000263551312257207200202550ustar00rootroot00000000000000//================================================================= // This file is a part of cdhit-dup. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) //================================================================= #include #include #include "minString.hxx" #include "minArray.hxx" #include "minMap.hxx" #include "bioSequence.hxx" using namespace Min; using namespace Bio; char base_mapping[128] = {0}; char rev_comp_mapping[128] = {0}; uint64_t base_powers[33]; FILE *fout_log = stdout; FILE *fout_rep = NULL; FILE *fout_clstr = NULL; uint64_t EncodeWord( const char *word, unsigned char W ) { unsigned char i; uint64_t *power = base_powers; uint64_t code = 0; for(i=0; i { int id; int abundance; int chiHead; int chiTail; public: SequenceCluster( Sequence *rep = NULL ){ id = 0; abundance = 0; chiHead = chiTail = 0; if( rep ) Append( ClusterMember( rep ) ); } String GetDescription( Sequence *seq, int deslen=0 ); int GetID()const{ return id; } void SetID( int i ){ id = i; } int GetAbundance()const{ return abundance; } void SetAbundance( int ab ){ abundance = ab; } int GetChimericParent1()const{ return chiHead; } int GetChimericParent2()const{ return chiTail; } void SetChimericParent( int head, int tail ){ chiHead = head; chiTail = tail; } void Write( FILE *fout = stdout, int id = 0, int deslen=0, const char *des=NULL ); bool operator<( const SequenceCluster & other ){ assert( Size() && other.Size() ); return (*this)[0].seq->Length() < other[0].seq->Length(); } }; String SequenceCluster::GetDescription( Sequence *seq, int deslen ) { String des = seq->Description(); int i = 0; if( des[i] == '>' || des[i] == '@' || des[i] == '+' ) i += 1; if( des[i] == ' ' || des[i] == '\t' ) i += 1; if( deslen == 0 || deslen > des.Size() ) deslen = des.Size(); while( i < deslen and ! isspace( des[i] ) ) i += 1; des.Resize( i ); return des; } void SequenceCluster::Write( FILE *fout, int id, int deslen, const char *cdes ) { //Array & seqs = *this; SequenceCluster & seqs = *this; String des = GetDescription( seqs[0].seq, deslen ); String & rep = seqs[0].seq->SequenceData(); int len2 = seqs[0].seq->Length(); int i = 0, n = Size(); fprintf( fout, ">Cluster %i%s\n", id, cdes ? cdes : "" ); fprintf( fout, "%i\t%int, >%s... *\n", 0, seqs[0].seq->Length(), des.Data() ); for(i=1; iSequenceData(); String des = GetDescription( seqs[i].seq, deslen ); int len = seqs[i].seq->Length(); int startQ = seqs[i].offset + 1; int startR = seqs[i].offset2 + 1; int endQ = len; int endR = len2; int mm = 0; if( (endQ - startQ) < (endR - startR) ){ endR = startR + endQ - startQ; }else{ endQ = startQ + endR - startR; } if( seqs[i].revcomp ){ startQ = len - startQ + 1; endQ = len - endQ + 1; } fprintf( fout, "%i\t%int, >%s... at %i:%i:%i:%i/%c/%.2f%%\n", i, len, des.Data(), startQ, endQ, startR, endR, seqs[i].revcomp ? '-' : '+', 100*(len-mm)/(float)len ); } } void WriteClusters( Array & clusters, const String & name = "temp.txt", int deslen = 0 ) { char cdes[200]; int i, n = clusters.Size(); int k1 = 0, k2 = 0; for(i=0; iPrint( fout_rep ); cluster.SetID( k1 ); cluster.Write( fout_clstr, k1++, deslen ); } } int HashingDepth( int len, int min ) { assert( len >= min ); return (int)sqrt( (len - min) / 10); } int HashingLength( int dep, int min ) { return min + 10 * dep * dep; } #define USE_WORD void ClusterOverlap( SequenceList & seqlist, Array & clusters, int min, float minper ) { String reverse; Array clusters2; #ifdef USE_WORD Hash > headHashes; Hash > tailHashes; Node > *node; #else Hash > headHashes; Hash > tailHashes; Node > *node; #endif int i, i2, j, k, m, N = seqlist.Count(); int WORD = min; #ifndef USE_WORD if( WORD > 30 ) WORD = 30; #endif for(i=0; iLength(); int min2 = len * minper; bool clustered = false; if( min2 < min ) min2 = min; String *ss = & seq->SequenceData(); reverse.ResetSize( len ); for(j=0; jData()[len - j - 1] ]; for(j=(len-WORD-1); j>=min2-WORD; j--){ for(i2=0; i2<2; i2++){ String *ss = & seq->SequenceData(); if( i2 ) ss = & reverse; //if( i2 ) break; #ifdef USE_WORD uint64_t hash = EncodeWord( ss->Data() + j, WORD ); #else unsigned int hash = MakeHash( *ss, j, WORD ); #endif node = tailHashes.Find( hash ); if( node == NULL ) continue; Array & clusts = node->value; for(int j2=0, m=clusts.Size(); j2SequenceData(); if( rep.Size() < (j + WORD) ) continue; const char *r = rep.Data() + (rep.Size() - j - WORD); const char *q = ss->Data(); int M = j + WORD; for(k=0; kSequenceData(); if( i2 ) ss = & reverse; //if( i2 ) break; #ifdef USE_WORD uint64_t hash = EncodeWord( ss->Data() + j, WORD ); #else unsigned int hash = MakeHash( *ss, j, WORD ); #endif node = headHashes.Find( hash ); if( node == NULL ) continue; Array & clusts = node->value; for(int j2=0, m=clusts.Size(); j2SequenceData(); if( rep.Size() < (len - j) ) continue; const char *r = rep.Data(); const char *q = ss->Data() + j; int M = len - j; for(k=0; kSequenceData().Data(), WORD ); uint64_t tail = EncodeWord( seq->SequenceData().Data() + (len - WORD), WORD ); #else unsigned int head = MakeHash( seq->SequenceData(), WORD ); unsigned int tail = MakeHash( seq->SequenceData(), (len - WORD), WORD ); #endif clusters2.Append( new SequenceCluster( seq ) ); headHashes[head].Append( clusters2.Back() ); tailHashes[tail].Append( clusters2.Back() ); } if( (i+1)%100000 == 0 ) fprintf( fout_log, "Clustered %9i sequences with %9i clusters ...\n", i+1, clusters2.Size() ); } for(i=0, m=clusters2.Size(); i clusters; fprintf( fout_log, "Start clustering duplicated sequences ...\n" ); ClusterOverlap( seqlist, clusters, minlen, minper ); fprintf( fout_log, "Number of clusters found: %i\n", clusters.Size() ); WriteClusters( clusters, output, deslen ); fprintf( fout_log, "Done!\n" ); fclose( fout_log ); fclose( fout_rep ); fclose( fout_clstr ); return 0; } cdhit-4.6.8/cd-hit-auxtools/mintlib/000077500000000000000000000000001312257207200173075ustar00rootroot00000000000000cdhit-4.6.8/cd-hit-auxtools/mintlib/minArray.hxx000066400000000000000000000137161312257207200216320ustar00rootroot00000000000000//================================================================= // This file is a part of the Minimum Template Library. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) // Released under the MIT license. //================================================================= #ifndef __MIN_ARRAY_HXX__ #define __MIN_ARRAY_HXX__ #include #include #include #include #include #include"minBase.hxx" BEGIN_NS_MIN template class Array { item_t *items; item_t *buf; size_t size; size_t bufsize; public: Array( size_t n=0, item_t it=item_t() ){ items = buf = NULL; size = bufsize = 0; Resize( n, it ); } Array( const Array & other ){ items = buf = NULL; size = bufsize = 0; this->operator=( other ); } ~Array(){ Clear(); } size_t Size()const{ return size; } item_t* Data(){ return items; } item_t& operator[]( size_t i ){ return items[i]; } item_t operator[]( size_t i )const{ return items[i]; } Array& operator=( const Array & other ){ size_t i; Clear(); size = other.size; bufsize = other.bufsize; items = buf = (item_t*) calloc( bufsize, sizeof(item_t) ); for(i=0; i bufsize ) Resize( n ); else size = n; } void ResetBuffer(){ // remove buffer from front: if( items == buf ) return; memmove( buf, items, size*sizeof(item_t) ); items = buf; } void Reserve( size_t n, bool extra=false ){ size_t front = (intptr_t) (items - buf); if( bufsize >= (n + front) ) return; // enough space at back if( bufsize >= n ){ // front > 0 ResetBuffer(); return; } void *old = buf; if( extra ) n += n/5; buf = (item_t*) malloc( n*sizeof(item_t) ); memmove( buf, items, size*sizeof(item_t) ); items = buf; bufsize = n; free( old ); } void Resize( size_t n, item_t it=item_t() ){ size_t i; ResetBuffer(); if( bufsize != n ){ items = buf = (item_t*) realloc( buf, n*sizeof(item_t) ); bufsize = n; } for(i=size; i= size ) return; if( n < 0 ) n = size - start; n += start; if( n > size ) n = size; size_t i; for(i=start; i items[i] ){ item_t tmp = items[i-1]; items[i-1] = items[i]; items[i] = tmp; swap = i; } } sorted = swap; } } void QuickSort( size_t partial=0, size_t sub=0 ){ if( size <= 1 ) return; if( partial ==0 ) partial = size; if( sub ==0 ) sub = size; PartialQuickSort( items, 0, sub-1, partial ); } /* Quick Sort. * Adam Drozdek: Data Structures and Algorithms in C++, 2nd Edition. */ void PartialQuickSort( item_t *data, size_t first, size_t last, size_t partial ) { size_t lower=first+1, upper=last; item_t pivot; item_t val; if( first >= last ) return; val = data[first]; data[first] = data[ (first+last)/2 ]; data[ (first+last)/2 ] = val; pivot = data[ first ]; while( lower <= upper ){ while( lower <= last && data[lower] < pivot ) lower ++; while( pivot < data[upper] ) upper --; if( lower < upper ){ val = data[lower]; data[lower] = data[upper]; data[upper] = val; upper --; } lower ++; } val = data[first]; data[first] = data[upper]; data[upper] = val; if( upper && first < upper-1 ) PartialQuickSort( data, first, upper-1, partial ); if( upper >= partial ) return; if( upper+1 < last ) PartialQuickSort( data, upper+1, last, partial ); } item_t QuickXth( item_t *data, size_t first, size_t last, size_t X ) { size_t lower=first+1, upper=last; item_t pivot; item_t val; if( first >= last ) return data[last]; val = data[first]; data[first] = data[ (first+last)/2 ]; data[ (first+last)/2 ] = val; pivot = data[ first ]; while( lower <= upper ){ while( lower <= last && data[lower] < pivot ) lower ++; while( pivot < data[upper] ) upper --; if( lower < upper ){ val = data[lower]; data[lower] = data[upper]; data[upper] = val; upper --; } lower ++; } val = data[first]; data[first] = data[upper]; data[upper] = val; if( first < upper-1 and upper > X ) return QuickXth( data, first, upper-1, X ); if( upper+1 < last and upper < X ) return QuickXth( data, upper+1, last, X ); return val; } item_t QuickMedian(){ Array tmp( *this ); return QuickXth( tmp.items, 0, size-1, size/2 ); } item_t QuickXth( size_t xth ){ Array tmp( *this ); return QuickXth( tmp.items, 0, size-1, xth ); } }; END_NS_MIN #endif cdhit-4.6.8/cd-hit-auxtools/mintlib/minBase.hxx000066400000000000000000000006161312257207200214210ustar00rootroot00000000000000//================================================================= // This file is a part of the Minimum Template Library. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) // Released under the MIT license. //================================================================= #ifndef __MIN_BASE_HXX__ #define __MIN_BASE_HXX__ #define BEGIN_NS_MIN namespace Min { #define END_NS_MIN } #endif cdhit-4.6.8/cd-hit-auxtools/mintlib/minMap.cxx000066400000000000000000000312331312257207200212560ustar00rootroot00000000000000//================================================================= // This file is a part of the Minimum Template Library. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) // Note: Adapted from Dao Virtual Machine source codes (daovm.net). // Released under the MIT license. //================================================================= #include"minMap.hxx" BEGIN_NS_MIN DNode* DNode::First()const { DNode *p = (DNode*) this; if( p ) while( p->left ) p = p->left; return p; } DNode* DNode::Next()const { DNode* p = (DNode*) this->right; if( this->right ){ while( p->left ) p = p->left; }else if( this->parent ){ if( this == this->parent->left ){ p = this->parent; }else{ p = this->parent; while( p->parent && p==p->parent->right ) p = p->parent; p = p->parent; } } return p; } DTree::DTree( bool hs ) { root = NULL; table = NULL; size = 0; tsize = 0; hashing = hs; if( hashing ){ tsize = 4; table = (DNode**) calloc( tsize, sizeof(DNode*) ); } } DTree::~DTree() { Clear(); if( table ) free( table ); } void DTree::Clear() { int i; if( hashing ){ for(i=0; iHashKey( this->tsize ); id = node->hash; this->root = this->table[id]; if( this->root ==NULL ){ this->size += 1; this->table[id] = node; node->color = RB_BLACK; return node; } } p = SimpleInsert( node ); if( p == node ){ /* key not exist: */ InsertNode( node ); if( hashing ){ this->table[id] = this->root; if( this->size >= this->tsize ) ResetTable(); } }else{ p->CopyValue( node ); delete node; } return p; } DNode* DTree::First() { const DTree *tree = this; return (DNode*) tree->First(); } DNode* DTree::Next( const DNode *node ) { const DTree *tree = this; return (DNode*) tree->Next( node ); } const DNode* DTree::First()const { const DNode *node = NULL; int i = 0; if( hashing ){ while( i < this->tsize && this->table[i] == NULL ) i += 1; if( i < this->tsize ) node = this->table[i]->First(); } if( node == NULL && this->root ) node = this->root->First(); return node; } const DNode* DTree::Next( const DNode *node )const { const DNode *next; if( node == NULL ) return NULL; next = node->Next(); if( next == NULL && hashing ){ int i = node->hash + 1; while( i < this->tsize && this->table[i] == NULL ) i += 1; if( i < this->tsize ) next = this->table[i]->First(); } return next; } #define HASH_SEED 0xda0 void DTree::DeleteTree( DNode *node ) { if( node == NULL ) return; DeleteTree( node->left ); DeleteTree( node->right ); delete node; } void DTree::RotateLeft( DNode *child ) { DNode *grandpa = child->parent; DNode *parent = child->right; if( grandpa ){ if( child == grandpa->right ) grandpa->right = parent; else grandpa->left = parent; }else{ this->root = parent; } parent->parent = grandpa; child->right = parent->left; if( child->right ) child->right->parent = child; parent->left = child; child->parent = parent; } void DTree::RotateRight( DNode *parent ) { DNode *grandpa = parent->parent; DNode *child = parent->left; if( grandpa ){ if( parent == grandpa->right ) grandpa->right = child; else grandpa->left = child; }else{ this->root = child; } child->parent = grandpa; parent->left = child->right; if( parent->left ) parent->left->parent = parent; child->right = parent; parent->parent = child; } void DTree::InsertNode( DNode *node ) { DNode *grandpa, *parent, *uncle; node->color = RB_RED; this->size ++; while( node->parent != NULL ){ parent = node->parent; grandpa = parent->parent; if( parent->color == RB_RED ){ /* insert_case2() */ /* grandpa can't be NULL, since parent is RED and can't be root. */ uncle = ( parent == grandpa->left ? grandpa->right : grandpa->left ); if( uncle != NULL && uncle->color == RB_RED ){ /* insert_case3(): */ parent->color = RB_BLACK; uncle->color = RB_BLACK; grandpa->color = RB_RED; node = grandpa; continue; /* insert_case1() */ }else{ if( node == parent->right && parent == grandpa->left ){ RotateLeft( parent ); node = node->left; }else if( node == parent->left && parent == grandpa->right ){ /* rotate right around parent: */ RotateRight( parent ); node = node->right; } /* node changed, update parent and grandpa. */ parent = node->parent; grandpa = parent->parent; /* insert_case5() */ parent->color = RB_BLACK; grandpa->color = RB_RED; if( node == parent->left && parent == grandpa->left ) RotateRight( grandpa ); else RotateLeft( grandpa ); } } break; } /* insert_case1() as in Wikipedia term: Red-black tree. */ if( node->parent == NULL){ this->root = node; node->color = RB_BLACK; } } void DTree::EraseChild( DNode *node ) { DNode *extreme = node; DNode *child = 0; if( node == NULL ) return; this->size --; /* deletion by coping */ if( node->left ){ extreme = node->left; while( extreme->right ) extreme = extreme->right; child = extreme->left; }else if( node->right ){ extreme = node->right; while( extreme->left ) extreme = extreme->left; child = extreme->right; } SwapNode( node, extreme ); if( child ){ /* replace node */ child->parent = extreme->parent; if( extreme->parent ){ if( extreme == extreme->parent->left ) extreme->parent->left = child; else extreme->parent->right = child; } if( extreme->color == RB_BLACK ){ if( child->color == RB_RED ) child->color = RB_BLACK; else{ node = child; while( node->parent ){ /* delete_case1() */ DNode *parent = node->parent; DNode *sibling = ( node == parent->left ? parent->right : parent->left ); if( sibling && sibling->color == RB_RED ){ /* delete_case2() */ parent->color = RB_RED; sibling->color = RB_BLACK; if( node == parent->left ) RotateLeft( parent ); else RotateRight( parent ); } /* node relationship changed, update parent and sibling: */ parent = node->parent; sibling = ( node == parent->left ? parent->right : parent->left ); if( ! sibling ) break; /* delete_case3() */ if( parent->color == RB_BLACK && sibling->color == RB_BLACK && ( ! sibling->left || sibling->left->color == RB_BLACK ) && ( ! sibling->right|| sibling->right->color == RB_BLACK)){ sibling->color = RB_RED; node = node->parent; continue; /* delete_case1() */ }else{ /* delete_case4() */ if( parent->color == RB_RED && sibling->color == RB_BLACK && ( ! sibling->left || sibling->left->color == RB_BLACK ) && ( ! sibling->right|| sibling->right->color == RB_BLACK)){ sibling->color = RB_RED; parent->color = RB_BLACK; }else{ /* delete_case5() */ if( node == parent->left && sibling->color == RB_BLACK &&( sibling->left && sibling->left->color == RB_RED ) &&( !sibling->right|| sibling->right->color == RB_BLACK)){ sibling->color = RB_RED; sibling->left->color = RB_BLACK; RotateRight( sibling ); }else if( node == parent->right && sibling->color == RB_BLACK &&( sibling->right && sibling->right->color == RB_RED ) &&( !sibling->left || sibling->left->color == RB_BLACK)){ sibling->color = RB_RED; sibling->right->color = RB_BLACK; RotateLeft( sibling ); } /* node relationship changed, update parent and sibling: */ parent = node->parent; sibling = ( node==parent->left ? parent->right:parent->left ); /* delete_case6() */ sibling->color = parent->color; parent->color = RB_BLACK; if( node == parent->left ){ sibling->right->color = RB_BLACK; RotateLeft( parent ); }else{ sibling->left->color = RB_BLACK; RotateRight( parent ); } } /* end if */ } /* end if */ } /* end while */ } } }else if( extreme->parent ){ if( extreme == extreme->parent->left ) extreme->parent->left = NULL; else extreme->parent->right = NULL; }else{ this->root = NULL; } delete extreme; } void DTree::EraseNode( DNode *node ) { if( node == NULL ) return; if( this->hashing ){ unsigned int hash = node->hash; this->root = this->table[ node->hash ]; if( this->root == NULL ) return; EraseChild( node ); this->table[ hash ] = this->root; if( this->size < 0.25*this->tsize ) ResetTable(); }else{ EraseChild( node ); } } void DTree::InsertTree( DNode *node ) { DNode *left = node->left; DNode *right = node->right; node->HashKey( this->tsize ); node->parent = node->left = node->right = NULL; this->root = this->table[ node->hash ]; if( this->root == NULL ){ node->color = RB_BLACK; this->table[ node->hash ] = node; this->size += 1; }else{ SimpleInsert( node ); InsertNode( node ); this->table[ node->hash ] = this->root; } if( left ) InsertTree( left ); if( right ) InsertTree( right ); } void DTree::ResetTable() { DNode **nodes = this->table; int i, tsize = this->tsize; if( hashing ==0 ) return; this->tsize = 2 * this->size + 1; this->table = (DNode**)calloc( this->tsize, sizeof(DNode*) ); this->size = 0; for(i=0; iroot; int compare; node->color = RB_RED; if( this->root == NULL ) return node; for(;;){ compare = CompareNode( node, p ); if( compare == 0 ){ return p; }else if( compare < 0 ){ if( p->left ){ p = p->left; }else{ p->left = node; node->parent = p; break; } }else{ if( p->right ){ p = p->right; }else{ p->right = node; node->parent = p; break; } } } return node; } static unsigned int MurmurHash2_Int32( unsigned int k ) { /* 'm' and 'r' are mixing constants generated offline. They're not really 'magic', they just happen to work well. */ const unsigned int m = 0x5bd1e995; const int r = 24; /* Initialize the hash to a 'random' value */ unsigned int h = HASH_SEED ^ 4; /* Mix 4 bytes into the hash */ k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; /* Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. */ h ^= h >> 13; h *= m; h ^= h >> 15; return h; } unsigned int MurmurHash2( const void *key, int len, unsigned int seed ); unsigned int MakeHash( unsigned int k ) { return MurmurHash2_Int32( k ); } unsigned int MakeHash( int k ) { return MurmurHash2_Int32( (unsigned int) k ); } unsigned int MakeHash( void *p ) { return MurmurHash2( & p, sizeof(void*), HASH_SEED ); } unsigned int MakeHash( uint64_t k ) { return MurmurHash2( & k, sizeof(uint64_t), HASH_SEED ); } int Compare( int left, int right ) { return left == right ? 0 : (left < right ? -1 : 1); } int Compare( unsigned int left, unsigned int right ) { return left == right ? 0 : (left < right ? -1 : 1); } int Compare( void *left, void *right ) { if( left == right ) return 0; if( left < right ) return -1; return 1; } int Compare( uint64_t left, uint64_t right ) { return left == right ? 0 : (left < right ? -1 : 1); } /* PUBLIC DOMAIN CODES http://sites.google.com/site/murmurhash/ http://www.burtleburtle.net/bob/hash/doobs.html */ /* ----------------------------------------------------------------------------- MurmurHash2, by Austin Appleby Note - This code makes a few assumptions about how your machine behaves - 1. We can read a 4-byte value from any address without crashing 2. sizeof(int) == 4 And it has a few limitations - 1. It will not work incrementally. 2. It will not produce the same results on little-endian and big-endian machines. */ unsigned int MurmurHash2( const void *key, int len, unsigned int seed ) { /* 'm' and 'r' are mixing constants generated offline. They're not really 'magic', they just happen to work well. */ const unsigned int m = 0x5bd1e995; const int r = 24; /* Initialize the hash to a 'random' value */ unsigned int h = seed ^ len; /* Mix 4 bytes at a time into the hash */ const unsigned char * data = (const unsigned char *)key; while(len >= 4) { unsigned int k = *(unsigned int *)data; k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } /* Handle the last few bytes of the input array */ switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; /* Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. */ h ^= h >> 13; h *= m; h ^= h >> 15; return h; } END_NS_MIN cdhit-4.6.8/cd-hit-auxtools/mintlib/minMap.hxx000066400000000000000000000126661312257207200212740ustar00rootroot00000000000000//================================================================= // This file is a part of the Minimum Template Library. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) // Note: Adapted from Dao Virtual Machine source codes (daovm.net). // Released under the MIT license. //================================================================= #ifndef __MIN_MAP_HXX__ #define __MIN_MAP_HXX__ #include #include #include #include"minBase.hxx" BEGIN_NS_MIN #define RB_RED 0 #define RB_BLACK 1 typedef enum{ KEY_EQ=0, KEY_ML/*Max Less*/, KEY_MG/*Min Great*/ } KeySearchType; struct DNode { unsigned int color : 1; unsigned int hash : 31; DNode *parent; DNode *left; DNode *right; DNode *next; DNode(){ parent = left = right = NULL; } virtual ~DNode(){} DNode* First()const; DNode* Next()const; virtual void HashKey( int T ){} virtual void CopyValue( DNode *other ){} }; struct DTree { DNode **table; DNode *root; DNode *first; DNode *last; int size; int tsize; bool hashing; DTree( bool hashing = false ); virtual ~DTree(); void Clear(); int Size()const{ return size; } protected: virtual int CompareNode( DNode *left, DNode *right )=0; virtual void SwapNode( DNode *node, DNode *extreme ){} DNode* First(); DNode* Next( const DNode *node ); const DNode* First()const; const DNode* Next( const DNode *node )const; DNode* Insert( DNode *node ); DNode* SimpleInsert( DNode *node ); void DeleteTree( DNode *node ); void RotateLeft( DNode *child ); void RotateRight( DNode *parent ); void InsertNode( DNode *node ); void EraseChild( DNode *node ); void EraseNode( DNode *node ); void InsertTree( DNode *node ); void ResetTable(); }; unsigned int MakeHash( unsigned int k ); unsigned int MakeHash( int k ); unsigned int MakeHash( void *p ); unsigned int MakeHash( uint64_t k ); int Compare( int left, int right ); int Compare( unsigned int left, unsigned int right ); int Compare( void *left, void *right ); int Compare( uint64_t left, uint64_t right ); template struct DKeyValue : public DNode { KeyType key; ValueType value; DKeyValue( const KeyType & k, const ValueType & v ){ key = k; value = v; parent = left = right = next = NULL; } void HashKey( int T ){ hash = MakeHash( key ) % T; } void CopyValue( DNode *other ){ value = ((DKeyValue*)other)->value; } }; template struct DMap : public DTree { typedef Min::DKeyValue DKeyValue; DMap(){} DMap( const DMap & other ) : DTree( other.hashing ){ this->operator=( other ); } DMap& operator=(const DMap & other){ const DKeyValue *node; Clear(); hashing = other.hashing; for(node=other.First(); node; node=other.Next(node)) Insert( node->key, node->value ); return *this; } void Erase( const KeyType & key ){ EraseNode( FindNode( key, KEY_EQ ) ); } DKeyValue* Insert( const KeyType & key, const ValueType & value ){ DKeyValue *node = new DKeyValue( key, value ); return (DKeyValue*) this->DTree::Insert( (DNode*) node ); } DKeyValue* Find( const KeyType & key ){ return FindNode( key, KEY_EQ ); } DKeyValue* FindML( const KeyType & key ){ return FindNode( key, KEY_ML ); } DKeyValue* FindMG( const KeyType & key ){ return FindNode( key, KEY_MG ); } DKeyValue* First(){ return (DKeyValue*) DTree::First(); } DKeyValue* Next( const DKeyValue *node ){ return (DKeyValue*) DTree::Next( node ); } const DKeyValue* First()const{ return (DKeyValue*) DTree::First(); } const DKeyValue* Next( const DKeyValue *node )const{ return (DKeyValue*) DTree::Next( node ); } ValueType& operator[]( KeyType key ){ DKeyValue *node = Find( key ); if( node ) return node->value; node = Insert( key, ValueType() ); return node->value; } protected: DMap( bool hashing ) : DTree( hashing ){} virtual int CompareNode( DNode *left0, DNode *right0 ){ DKeyValue *left = (DKeyValue*) left0; DKeyValue *right = (DKeyValue*) right0; return Compare( left->key, right->key ); } void SwapNode( DNode *node0, DNode *extreme0 ) { DKeyValue *node = (DKeyValue*) node0; DKeyValue *extreme = (DKeyValue*) extreme0; KeyType key = extreme->key; ValueType value = extreme->value; int hash = extreme->hash; extreme->hash = node->hash; extreme->key = node->key; extreme->value = node->value; node->hash = hash; node->key = key; node->value = value; } DKeyValue* FindChild( DKeyValue *root, KeyType key, KeySearchType type ) { DKeyValue *p = root; DKeyValue *m = 0; int compare; if( root == NULL ) return NULL; for(;;){ compare = Compare( key, p->key ); if( compare == 0 ) return p; if( compare < 0 ){ if( type == KEY_MG ) m = p; if( p->left ) p = (DKeyValue*) p->left; else break; }else{ if( type == KEY_ML ) m = p; if( p->right ) p = (DKeyValue*) p->right; else break; } } return m; } DKeyValue* FindNode( KeyType key, KeySearchType type ) { DKeyValue *root = (DKeyValue*) this->root; int id; if( hashing ){ id = MakeHash( key ) % this->tsize; root = (DKeyValue*) this->table[id]; if( root == NULL ) return NULL; } return FindChild( root, key, type ); } }; template struct DHash : public DMap { DHash() : DMap( true ){} DHash( const DHash & other ) : DMap( other ){} }; #define Map DMap #define Hash DHash #define Node DKeyValue END_NS_MIN #endif cdhit-4.6.8/cd-hit-auxtools/mintlib/minString.cxx000066400000000000000000000271341312257207200220140ustar00rootroot00000000000000//================================================================= // This file is a part of the Minimum Template Library. // By Limin Fu (phoolimin@gmail.com, lmfu@ucsd.edu) //================================================================= #include #include #include #include #include #include"minString.hxx" BEGIN_NS_MIN String::String( char ch ) { data = NULL; size = bufsize = 0; SetBytes( & ch, 1 ); } String::String( const char *s ) { data = NULL; size = bufsize = 0; *this = s; } String::String( const char *s, int n ) { data = NULL; size = bufsize = 0; SetBytes( s, n ); } String::String( const String & other ) { data = NULL; size = bufsize = 0; SetBytes( other.data, other.size ); } void String::Clear() { if( data ) free( data ); data = NULL; size = bufsize = 0; } void String::Reset() { if( size == 0 ) return; size = 0; data[0] = 0; } void String::Reserve( int n ) { if( bufsize >= n ) return; data = (char*) realloc( data, (n+1)*sizeof(char) ); bufsize = n; } void String::ResetSize( int n ) { if( size < n ) Resize( n, 0 ); size = n; data[size] = 0; } void String::Resize( int n, char ch ) { int i; if( bufsize != n ){ data = (char*) realloc( data, (n+1)*sizeof(char) ); bufsize = n; } for(i=size; i size ) return; Reserve( size + 1 ); if( at < size ) memmove( data + at + 1, data + at, (size - at) * sizeof(char) ); data[at] = ch; data[++size] = '\0'; } void String::Insert( char *chs, int at ) { if( chs == NULL ) return; if( at < 0 || at > size ) return; int i, N = strlen( chs ); Reserve( size + N ); if( at < size ) memmove( data + at + N, data + at, (size - at) * sizeof(char) ); for(i=0; i= size ) return; if( start + count > size ) count = size - start; rest = size - (start + count); if( rest ) memmove( data + start, data + start + count, rest * sizeof(char) ); size -= count; if( data ) data[size] = 0; } void String::Chop( int count ) { if( size ){ if( count > size ) count = size; Erase( size-count, count ); } } void String::ToUpper() { for(int i=0; i> 4 ]; shex += hex[ data[i] & 0xf ]; } return shex; } static void MD5_Append( String & md5, uint32_t h ) { const char *hex = "0123456789abcdef"; uint32_t k; k = (h >> 0) & 0xff; md5 += hex[k>>4]; md5 += hex[k&0xf]; k = (h >> 8) & 0xff; md5 += hex[k>>4]; md5 += hex[k&0xf]; k = (h >>16) & 0xff; md5 += hex[k>>4]; md5 += hex[k&0xf]; k = (h >>24) & 0xff; md5 += hex[k>>4]; md5 += hex[k&0xf]; } static void MD5_Update( uint32_t H[4], uint32_t W[16], uint32_t K[64] ) { static uint32_t R[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 }; uint32_t A = H[0]; uint32_t B = H[1]; uint32_t C = H[2]; uint32_t D = H[3]; uint32_t k; for(k=0; k<16; k++){ uint32_t f = (B & C) | ((~B) & D); uint32_t g = k; uint32_t t = D; uint32_t x = A + f + K[k] + W[g]; D = C; C = B; B = B + ((x << R[k]) | (x >> (32-R[k]))); A = t; } for(k=16; k<32; k++){ uint32_t f = (D & B) | ((~D) & C); uint32_t g = (k*5 + 1) % 16; uint32_t t = D; uint32_t x = A + f + K[k] + W[g]; D = C; C = B; B = B + ((x << R[k]) | (x >> (32-R[k]))); A = t; } for(k=32; k<48; k++){ uint32_t f = B ^ C ^ D; uint32_t g = (k*3 + 5) % 16; uint32_t t = D; uint32_t x = A + f + K[k] + W[g]; D = C; C = B; B = B + ((x << R[k]) | (x >> (32-R[k]))); A = t; } for(k=48; k<64; k++){ uint32_t f = C ^ (B | (~D)); uint32_t g = (k*7) % 16; uint32_t t = D; uint32_t x = A + f + K[k] + W[g]; D = C; C = B; B = B + ((x << R[k]) | (x >> (32-R[k]))); A = t; } H[0] += A; H[1] += B; H[2] += C; H[3] += D; } String String::MD5()const { String padding; uint64_t n, twop32 = ((uint64_t)1)<<32; uint32_t H[4] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 }; uint32_t K[64], W[16]; int32_t i, k, m, chunks = size / 64; uint8_t *data = (uint8_t*) this->data; for(i=0; i<64; i++) K[i] = (uint32_t) floor( fabs( sin(i+1) ) * twop32 ); for(i=0; idata + chunks*64, m*sizeof(char) ); if( m + 8 > 64 ) padding.size = 128; chunks = padding.size / 64; data[m] = 1<<7; // first bit 1 followed by bit 0s; for(i=m+1; i> 8) & 0xff; data[i+2] = (n >> 16) & 0xff; data[i+3] = (n >> 24) & 0xff; data[i+4] = (n >> 32) & 0xff; data[i+5] = (n >> 40) & 0xff; data[i+6] = (n >> 48) & 0xff; data[i+7] = (n >> 56) & 0xff; for(i=0; i s.Size() ) length = s.Size(); return MurmurHash2( s.Data(), length, HASH_SEED ); } unsigned int MakeHash( const String & s, int offset, int length ) { if( offset < 0 ) offset = 0; if( length <= 0 ) length = s.Size() - offset; if( (length + offset) > s.Size() ) length = s.Size() - offset; return MurmurHash2( s.Data() + offset, length, HASH_SEED ); } int Compare( const String & left, const String & right ) { const char *L = left.Data(); const char *R = right.Data(); int M = left.Size(); int N = right.Size(); int I = 0; for(; I=0 ) M = lstart + 1 - max; if( rstart + 1 - max >=0 ) N = rstart + 1 - max; } for(; I>=M and J>=N and (mm+=(*L!=*R))<=maxmm; I--, J--, L--, R--); return lstart - I; } int CountMismatch( const String & left, const String & right, int from, int to ) { const char *L = left.Data() + from; const char *R = right.Data() + from; int M = left.Size(); int N = right.Size(); int i, mm = 0; if( to < 0 ) to = M; if( to > M ) to = M; if( to > N ) to = N; for(i=from; i M ) to = M; if( to > N ) to = N; for(i=from; i #include"minBase.hxx" BEGIN_NS_MIN class String { char *data; int size; int bufsize; public: String( char ch ); String( const char *s = NULL ); String( const char *s, int n ); String( const String & other ); ~String(){ Clear(); } const char* Data()const{ return data; } int Size()const{ return size; } int BufferSize()const{ return bufsize; } void Clear(); void Reset(); void Reserve( int n ); void ResetSize( int n ); void Resize( int n, char ch=0 ); void SetBytes( const char *s, int n ); void AppendBytes( const char *s, int n ); void Insert( char ch, int at ); void Insert( char *chs, int at ); void Erase( int start, int count ); void Chop( int count = 1 ); void ToUpper(); void ToLower(); int Find( char ch )const; int Find( const String & s )const; String& operator=( const char ch ); String& operator=( const char *s ); String& operator=( const String & s ); void operator+=( const char ch ); void operator+=( const char *s ); void operator+=( const String &s ); char& operator[]( int i ){ return data[i]; } char operator[]( int i )const{ return data[i]; } String FromHex()const; String ToHex()const; String MD5()const; static String FromNumber( int i ); }; String operator+( const String & left, const String & right ); bool operator==( const String & left, const String & right ); bool operator!=( const String & left, const String & right ); unsigned int MakeHash( const String & s, int length=0 ); unsigned int MakeHash( const String & s, int offset, int length ); int Compare( const String & left, const String & right ); int ComparePrefix( const String & left, const String & right, int maxmm = 0 ); int ComparePrefix( const String & left, int lstart, const String & right, int rstart, int max=0, int maxmm = 0 ); int CompareSuffix( const String & left, int lstart, const String & right, int rstart, int max=0, int maxmm = 0 ); int CountMismatch( const String & left, const String & right, int from = 0, int to = -1 ); int CountMismatch2( const String & left, const String & right, int from = 0, int to = -1, int maxmm=0 ); int CountMismatch3( const String & left, int lstart, const String & right, int rstart, int max, int maxmm ); END_NS_MIN #endif cdhit-4.6.8/cd-hit-auxtools/mintlib/minUtility.hxx000066400000000000000000000003441312257207200222100ustar00rootroot00000000000000 #include"minString.hxx" #include"minArray.hxx" int BurrowsWheelerTrans( const String & input, String & output, Array & idbuf ); int ReverseBurrowsWheelerTrans( const String & input, String & output, Array & idbuf ); cdhit-4.6.8/cd-hit-auxtools/read-linker.cxx000066400000000000000000000164771312257207200206110ustar00rootroot00000000000000#include "bioSequence.hxx" using namespace Min; using namespace Bio; class SequenceLinker { int minOverlap; int tolerance; int maxlen; int overlap; int error; int count; Array sequences; public: SequenceLinker( int minOverlap = 10, int tolerance = 1 ){ this->minOverlap = minOverlap; this->tolerance = tolerance; maxlen = 0; error = 0; count = 0; overlap = 0; } void SetMaxLen( int max ){ maxlen = max; } int Overlap()const{ return overlap; } int Error()const{ return error; } int Count()const{ return count; } int Check( const String & first, const String & second ); int Link( Sequence *first, Sequence *second ); int Link2( Sequence *first, Sequence *second ); void Reset(){ count = 0; sequences.Clear(); } void Write( FILE *fout ){ for(int i=0,n=sequences.Size(); i%d\t%s\n", i, sequences[i].Description().Data()); sequences[i].Print( fout ); } } }; int SequenceLinker::Check( const String & first, const String & second ) { int n1 = first.Size(); int n2 = second.Size(); int m = n1 < n2 ? n1 : n2; int i, j, k; for(k=m; k>=minOverlap; k--){ error = 0; for(i=n1-k, j=0; j tolerance ) break; } overlap = k; if( error <= tolerance ) return k; } overlap = 0; return 0; } int SequenceLinker::Link( Sequence *first, Sequence *second ) { int qs = first->QualityScore().Size(); const String & s1 = first->SequenceData(); const String & s2 = second->SequenceData(); const String & qs1 = first->QualityScore(); const String & qs2 = second->QualityScore(); int n1 = s1.Size(); int n2 = s2.Size(); int i, j, m = 1, O = Check( s1, s2 ); int error2 = 0; if( O == 0 ) return 0; String locs; for(i=n1-O, j=0; j (int)sequences.Size() ) sequences.Append( Sequence() ); for(i=0; iGetDescription(); seq.Description() += tag; if( locs.Size() ) seq.Description() += " mismatch_pos=" + locs; seq.SequenceData() += s1; seq.SequenceData() += s2.Data() + O; if( qs ){ seq.QualityScore() += qs1; seq.QualityScore() += qs2.Data() + O; } } int step = m; for(i=n1-O, j=0; j> 1; for(int k=0; kQualityScore().Size(); const String & s1 = first->SequenceData(); const String & s2 = second->SequenceData(); const String & qs1 = first->QualityScore(); const String & qs2 = second->QualityScore(); int n1 = s1.Size(); int n2 = s2.Size(); int i, j, m = 1; if( n1 < minOverlap || n2 < minOverlap ) return 0; if( n2 < maxlen ) return 0; Sequence joint = Sequence(); joint.Description() = first->GetDescription(); joint.SequenceData() += s1; joint.SequenceData().Chop( n1 - minOverlap ); joint.SequenceData() += s2.Data() + (maxlen - minOverlap); joint.SequenceData().Chop( n2 - maxlen ); if( qs ){ joint.QualityScore() = first->QualityScore(); joint.QualityScore().Chop( n1 - minOverlap ); joint.QualityScore() += qs2.Data() + (maxlen - minOverlap); joint.QualityScore().Chop( n2 - maxlen ); } sequences.Append( joint ); return 1; } const char *help = "Options:\n" " -1 file Input file, first end;\n" " -2 file Input file, second end;\n" " -o file Output file;\n" " -l number Minimum overlapping length (default 10);\n" //" Or the selection length, if \"number\" is negative,\n" //" to simply join the two ends;\n" " -e number Maximum number of errors (mismatches, default 1);\n" //" -m number Cutoff length when \"-l\" is negative;\n" ; int main( int argc, char *argv[] ) { String first; String second; String output; int min = 10; int error = 1; int maxlen = 0; int i; if( argc < 7 ){ printf( "%s\n", help ); return 1; } for(i=1; i countPairs( error+1, 0 ); Array countContigs( error+1, 0 ); linker.SetMaxLen( maxlen ); while(1){ //cache1.Clear(); //cache2.Clear(); int n1 = cache1.Update(); int n2 = cache2.Update(); int n = n1 < n2 ? n1 : n2; if( n1 != n2 ){ printf( "Warning: the pair end files contain different number of reads!\n" ); } if( n == 0 ) break; //printf("==>%d\t%d\n", n1, n2); if( min < 0 && maxlen == 0 ){ maxlen = cache2[0]->Length(); linker.SetMaxLen( maxlen ); } //Array sequences( n ); for(int i=0; iToReverseComplimentary(); int c = 0; if( min > 0 ){ c = linker.Link( cache1[i], cache2[i] ); int o = linker.Overlap(); if( o > omax ) omax = o; if( o && o < omin ) omin = o; }else{ c = linker.Link2( cache1[i], cache2[i] ); } countUsedPairs += c != 0; countPairs[ linker.Error() ] += c != 0; countContigs[ linker.Error() ] += c; } countInputPairs += n; countAllContig += linker.Count();; linker.Write( fout ); linker.Reset(); count += n; printf( "handled: %9i\n", count ); } printf( "Total input pairs of read: %i\n", countInputPairs ); printf( "Total pairs of read used: %i\n", countUsedPairs ); printf( "Total contigs: %i\n", countAllContig ); if( min > 0 ){ for(i=0; i<=error; i++) printf( "%2i mismatch: %9i pairs of reads => %9i contigs\n", i, countPairs[i], countContigs[i] ); printf( "Overlap range %i-%i\n", omin, omax ); } fclose( fout ); return 0; } cdhit-4.6.8/cd-hit-div.pl000077500000000000000000000015551312257207200151230ustar00rootroot00000000000000#!/usr/bin/perl #not like cd-hit-div, this script do not sort input #or throw away seq $in = shift; $in or die "no input file"; $out = shift; $out or die "no output file"; $div = shift; $div or die "no div number"; @fhs = (); for ($i=0; $i<$div; $i++) { my $tf = "$out-$i"; $tfh = "FH". $i; open($tfh, "> $tf") || die "can not open output files for write"; push(@fhs, $tfh); } open(TMP, $in) || die "can not open input file"; my $seq; my $des; my $no = 0; while($ll = ) { if ($ll =~ /^>/) { if ($seq) { $i = $no % $div; $tfh = $fhs[$i]; $no++; print $tfh $des, $seq; } $des = $ll; $seq = ""; } else { $seq .= $ll; } } if ($seq) { $i = $no % $div; $tfh = $fhs[$i]; $no++; print $tfh $des, $seq; } close(TMP); for ($i=0; $i<$div; $i++) { $tfh = $fhs[$i]; close($tfh); } cdhit-4.6.8/cd-hit-para.pl000077500000000000000000000270621312257207200152650ustar00rootroot00000000000000#!/usr/bin/perl -w # ============================================================================= # CD-HIT # http://cd-hit.org/ # http://bioinformatics.burnham.org/cd-hi # # program written by # Weizhong Li # UCSD, San Diego Supercomputer Center # La Jolla, CA, 92093 # Email liwz@sdsc.edu # ============================================================================= use strict; no strict "refs"; my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; $script_dir = "./" unless ($script_dir); chop($script_dir); my $arg; my $in; my $out; my $arg_pass = ""; my $para = ""; my $host_no = 0; my @hosts = (); my $cd_hit_div_exe = "$script_dir/cd-hit-div"; my $cd_hit_exe = "$script_dir/cd-hit"; my $cd_hit_est_exe = "$script_dir/cd-hit-est"; my $cd_hit_2d_exe = "$script_dir/cd-hit-2d"; my $cd_hit_est_2d_exe = "$script_dir/cd-hit-est-2d"; my $clstr_merge_exe = "$script_dir/clstr_merge.pl"; my $seg_no = 64; my $restart_in = ""; my $queue = 0; my $local_cpu = 0; my $queue_type = "PBS"; my $prog = "cd-hit"; my %stable_files = (); while ($arg=shift) { if ($arg eq "-h" ) { print_usage();} elsif ($arg eq "-i" ) { $in = shift; } elsif ($arg eq "-o" ) { $out = shift; } elsif ($arg eq "--B") { $para = shift; } elsif ($arg eq "--L") { $local_cpu = shift; } elsif ($arg eq "--P") { $prog = shift; } elsif ($arg eq "--S") { $seg_no = shift; } elsif ($arg eq "--Q") { $queue = shift; } elsif ($arg eq "--T") { $queue_type = shift; } elsif ($arg eq "--R") { $restart_in = shift; } else {$arg_pass .= " $arg "; } } ($in and $out) || print_usage(); if ($prog eq "cd-hit-est") { $cd_hit_exe = $cd_hit_est_exe; $cd_hit_2d_exe = $cd_hit_est_2d_exe; } my $pwd = `pwd`; chop($pwd); my $work_dir = "$out.cd-hit-para-tmp"; my $restart_file = "$out.restart"; my $indiv = "$work_dir/$in.div"; my @commands = (); my @command_status = (); my $command_no = 0; my $cmd; my ($i, $j, $k, $i1, $j1, $k1); # readin a list of hosts if ($para) { open(PARA, "$para") || die "can not open $para"; while(my $ll= ){ chop($ll); $ll =~ s/\s//g; next unless ($ll); push(@hosts, $ll); $host_no++; } close(PARA); } if ($queue) { for ($i=0; $i<$queue; $i++) { push(@hosts, "queue_host.$i"); } $host_no = $queue; } if ($local_cpu) { for ($i=0; $i<$local_cpu; $i++) { push(@hosts, "localhost.$i"); } $host_no = $local_cpu; } die "no host" unless $host_no; if (-e $restart_in) { read_restart(); } else { $cmd = `mkdir $work_dir`; assign_commands(); write_restart(); } #dbdiv run on master node? if ($command_status[0] eq "wait") { $cmd = `$commands[0]`; $command_status[0] = "done"; write_restart(); for ($i=0; $i<$seg_no; $i++) { my $idb = "$indiv-$i"; $stable_files{$idb} = 1; } } #main runing loop my $sleep_time = 1; while(1) { #refresh job status by checking output files #check whether all jobs are done or not my $finish_flag = 1; my $status_change = 0; for ($i=1; $i<$command_no; $i++) { next if ($command_status[$i] eq "done"); $finish_flag = 0; my $tcmd = $commands[$i]; my $output = ""; if ($tcmd =~ / -o\s+(\S+)/) { $output = $1; if ((-s $output) or (-s "$output.clstr")) { $command_status[$i] = "done"; $status_change = 1; } } } if ($status_change) { write_restart(); } else { sleep($sleep_time); print "."; } last if $finish_flag; my $job_sent = 0; for ($i=1; $i<$command_no; $i++) { next if ($command_status[$i] eq "done"); next if ($command_status[$i] eq "run"); my $tcmd = $commands[$i]; my $in1 = ""; my $in2 = ""; my $out_done = ""; if ($tcmd =~ / -i\s+(\S+)/ ) {$in1 = $1;} if ($tcmd =~ / -i2\s+(\S+)/) {$in2 = $1;} if ($tcmd =~ / -o\s+(\S+)/ ) {$out_done = "$1.done";} my $input_flag = 0; if (($in1 =~ /\S/) and ($in2 =~ /\S/)) { $input_flag = 1 if ((-s $in1) and (-s $in2)); } elsif ($in1 =~ /\S/) { $input_flag = 1 if (-s $in1); } else { die "Error at $tcmd\n"; } next unless $input_flag; #now input files are ready, wait wait_stable_file($in1); wait_stable_file($in2) if ($in2 =~ /\S/); my $thost_idx = wait_for_available_host(); my $thost = $hosts[$thost_idx]; my $tsh = "$work_dir/$out.$$.$thost_idx.sh"; my $tlock = "$work_dir/$out.$$.$thost_idx.lock"; my $trm = ""; $trm = "rm -f $in2" if ($in2 =~ /\S/); open(TSH, "> $tsh") || die; $cmd = `date > $tlock`; print TSH < $tlock $tcmd $trm rm -f $tlock date > $out_done EOD close(TSH); if ($local_cpu) { $cmd = `sh $tsh >/dev/null 2>&1 &`; $command_status[$i] = "run"; print "run at $thost $tcmd\n"; } elsif ($queue and ($queue_type eq "PBS")) { my $t = "para-$thost_idx"; open(QUEUE,"| qsub -N $t -o $t.log -e $t.err"); print QUEUE "cd $pwd; sh $tsh"; close(QUEUE); $command_status[$i] = "run"; } elsif ($queue and ($queue_type eq "SGE")) { my $t = "para-$thost_idx"; open(QUEUE,"| qsub -N $t"); print QUEUE </dev/null 2>&1 &'`; $command_status[$i] = "run"; print "run at $thost $tcmd\n"; } $sleep_time = 1; $job_sent = 1; last; } if ((not $job_sent) and ($sleep_time < 60)) { $sleep_time +=5; } } ############ main run loop ######## merge all .clstr file my $out_clstr = "$out.clstr"; if (not -s $out_clstr) { my @reps = (); for ($i=0; $i<$seg_no; $i++) { my $master_clstr = "$indiv-$i-o.clstr"; die "No file $master_clstr\n" unless (-s $master_clstr); my $this_rep = "$indiv-$i-o"; die "No rep $this_rep\n" unless (-e $this_rep); push(@reps, $this_rep); my @slave_clstr = (); for ($j=$i+1; $j<$seg_no; $j++) { my $tclstr = "$indiv-$j.vs.$i.clstr"; if (-s $tclstr) {push(@slave_clstr,$tclstr); } else {die "No file $tclstr\n";} } if (@slave_clstr) { my $tclstrs = join(" ", @slave_clstr); print "$clstr_merge_exe $master_clstr $tclstrs >> $out_clstr\n"; $cmd = `$clstr_merge_exe $master_clstr $tclstrs >> $out_clstr`; } else { #this is the last piece print "cat $master_clstr >> $out_clstr"; $cmd = `cat $master_clstr >> $out_clstr`; } } my $out_clstr_ren = "$out.clstr.$$"; open(TMP, $out_clstr) || die; open(OTMP, "> $out_clstr_ren") || die; my $no = 0; my $cno; my $ll; while($ll=){ if ($ll =~ /^>Cluster (\d+)/) { print OTMP ">Cluster $no\n"; $no++; $cno = 0; } else { $ll =~ s/^\d+/$cno/; print OTMP $ll; $cno++; } } close(TMP); close(OTMP); sleep(10); $cmd = `mv $out_clstr_ren $out_clstr`; my $reps = join(" ", @reps); $cmd = `cat $reps > $out`; } if (1) { $cmd = `grep CPU $work_dir/*log`; my @lls = split(/\n/, $cmd); my $cpu = 0; my $ll; foreach $ll (@lls) { if ($ll =~ /CPU\s+time\s+(\d+)/) { $cpu += $1; } } print "Total CPU time: $cpu\n"; } sub wait_for_available_host { my ($i, $j, $k); my $sleep = 30; while(1) { for ($i=0; $i<$host_no; $i++) { my $thost = $hosts[$i]; my $tlock = "$work_dir/$out.$$.$i.lock"; next if (-e $tlock); return $i; } sleep($sleep); $sleep +=30; if ($sleep >= 300) { $sleep = 30; } } } ########## END wait_for_available_host sub wait_stable_file { my ($i, $j, $k); my $f = shift; return if ($stable_files{$f}); return unless (-e $f); if (-e "$f.done") { $stable_files{$f} = 1; return; } my $size0 = -s $f; while(1) { sleep(10); my $size1 = -s $f; if ($size0 == $size1) { $stable_files{$f} = 1; last; } else {$size0 = $size1; } } } ########## END wait_stable_file sub write_restart { my ($i, $j, $k); open(RES, "> $restart_file") || die; for ($i=0; $i<$command_no; $i++) { print RES "$commands[$i]\n$command_status[$i]\n"; } close(RES); } ########## END write_restart sub assign_commands { my ($i, $j, $k); my $cmd; my ($idb, $idbo, $jdb, $idbout, $idblog); $command_no = 0; $cmd = "$cd_hit_div_exe -i $in -o $indiv -div $seg_no"; push(@commands, $cmd); push(@command_status, "wait"); $command_no++; for ($i=0; $i<$seg_no; $i++) { $idb = "$indiv-$i"; $idblog = "$indiv-$i.log"; #compare to previous segs for ($j=0; $j<$i; $j++) { $jdb = "$indiv-$j-o"; $idbo = "$indiv-$i.vs.$j"; $cmd = "$cd_hit_2d_exe -i $jdb -i2 $idb -o $idbo $arg_pass >> $idblog"; push(@commands, $cmd); push(@command_status, "wait"); $command_no++; $idb = $idbo; } #self comparing $cmd = "$cd_hit_exe -i $idb -o $indiv-$i-o $arg_pass >> $idblog"; push(@commands, $cmd); push(@command_status, "wait"); $command_no++; } } sub read_restart { $command_no = 0; open(RRRR, "$restart_in") || die; my $ll; while ($ll = ) { chop($ll); push(@commands, $ll); $ll = ; chop($ll); push(@command_status, $ll); $command_no++; } close(RRRR); } ########## END read_restart sub print_usage { print <), seq_db.NAAN, sizeof(NVector) * seq_db.NAAN ); seq_db.Read( db_in.c_str(), options ); cout << "total seq: " << seq_db.sequences.size() << endl; seq_db.SortDivide( options ); seq_db.DoClustering( options ); printf( "writing new database\n" ); seq_db.WriteClusters( db_in.c_str(), db_out.c_str(), options ); // write a backup clstr file in case next step crashes seq_db.WriteExtra1D( options ); cout << "program completed !" << endl << endl; end_time = current_time(); printf( "Total CPU time %.2f\n", end_time - begin_time ); return 0; } // END int main cdhit-4.6.8/cdhit-common.c++000066400000000000000000003745661312257207200155250ustar00rootroot00000000000000// ============================================================================= // CD-HI/CD-HIT // // Cluster Database at High Identity // // CD-HIT clusters protein sequences at high identity threshold. // This program can remove the high sequence redundance efficiently. // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include "cdhit-common.h" #include #include #include #include #ifndef NO_OPENMP #include #define WITH_OPENMP " (+OpenMP)" #else #define WITH_OPENMP "" #define omp_set_num_threads(T) (T = T) #define omp_get_thread_num() 0 #endif //class function definition const char aa[] = {"ARNDCQEGHILKMFPSTWYVBZX"}; //{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,2,6,20}; int aa2idx[] = {0, 2, 4, 3, 6, 13,7, 8, 9,20,11,10,12, 2,20,14, 5, 1,15,16,20,19,17,20,18, 6}; // idx for A B C D E F G H I J K L M N O P // Q R S T U V W X Y Z // so aa2idx[ X - 'A'] => idx_of_X, eg aa2idx['A' - 'A'] => 0, // and aa2idx['M'-'A'] => 12 int BLOSUM62[] = { 4, // A -1, 5, // R -2, 0, 6, // N -2,-2, 1, 6, // D 0,-3,-3,-3, 9, // C -1, 1, 0, 0,-3, 5, // Q -1, 0, 0, 2,-4, 2, 5, // E 0,-2, 0,-1,-3,-2,-2, 6, // G -2, 0, 1,-1,-3, 0, 0,-2, 8, // H -1,-3,-3,-3,-1,-3,-3,-4,-3, 4, // I -1,-2,-3,-4,-1,-2,-3,-4,-3, 2, 4, // L -1, 2, 0,-1,-3, 1, 1,-2,-1,-3,-2, 5, // K -1,-1,-2,-3,-1, 0,-2,-3,-2, 1, 2,-1, 5, // M -2,-3,-3,-3,-2,-3,-3,-3,-1, 0, 0,-3, 0, 6, // F -1,-2,-2,-1,-3,-1,-1,-2,-2,-3,-3,-1,-2,-4, 7, // P 1,-1, 1, 0,-1, 0, 0, 0,-1,-2,-2, 0,-1,-2,-1, 4, // S 0,-1, 0,-1,-1,-1,-1,-2,-2,-1,-1,-1,-1,-2,-1, 1, 5, // T -3,-3,-4,-4,-2,-2,-3,-2,-2,-3,-2,-3,-1, 1,-4,-3,-2,11, // W -2,-2,-2,-3,-2,-1,-2,-3, 2,-1,-1,-2,-1, 3,-3,-2,-2, 2, 7, // Y 0,-3,-3,-3,-1,-2,-2,-3,-3, 3, 1,-2, 1,-1,-2,-2, 0,-3,-1, 4, // V -2,-1, 3, 4,-3, 0, 1,-1, 0,-3,-4, 0,-3,-3,-2, 0,-1,-4,-3,-3, 4, // B -1, 0, 0, 1,-3, 3, 4,-2, 0,-3,-3, 1,-1,-3,-1, 0,-1,-3,-2,-2, 1, 4, // Z 0,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2, 0, 0,-2,-1,-1,-1,-1,-1 // X //A R N D C Q E G H I L K M F P S T W Y V B Z X //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 6 20 }; int na2idx[] = {0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 4, 4, 4, 4, 4}; // idx for A B C D E F G H I J K L M N O P // Q R S T U V W X Y Z // so aa2idx[ X - 'A'] => idx_of_X, eg aa2idx['A' - 'A'] => 0, // and aa2idx['M'-'A'] => 4 int BLOSUM62_na[] = { 2, // A -2, 2, // C -2,-2, 2, // G -2,-2,-2, 2, // T -2,-2,-2, 1, 2, // U -2,-2,-2,-2,-2, 1, // N 0, 0, 0, 0, 0, 0, 1 // X //A C G T U N X //0 1 2 3 3 4 5 }; void setaa_to_na(); struct TempFile { FILE *file; char buf[512]; TempFile( const char *dir = NULL ){ int len = dir ? strlen( dir ) : 0; assert( len < 400 ); buf[0] = 0; if( len ){ strcat( buf, dir ); if( buf[len-1] != '/' && buf[len-1] != '\\' ){ buf[len] = '/'; len += 1; } } strcat( buf, "cdhit.temp." ); len += 11; sprintf( buf + len, "%p", this ); file = fopen( buf, "w+" ); } ~TempFile(){ if( file ){ fclose( file ); remove( buf ); } } }; struct TempFiles { NVector files; ~TempFiles(){ Clear(); } void Clear(){ int i; #pragma omp critical { for(i=0; ifile; } static void CleanUpTempFiles() { if( temp_files.files.Size() ) printf( "Clean up temporary files ...\n" ); temp_files.Clear(); } int NAA1 ; int NAA2 ; int NAA3 ; int NAA4 ; int NAA5 ; int NAA6 ; int NAA7 ; int NAA8 ; int NAA9 ; int NAA10; int NAA11; int NAA12; int NAAN_array[13] = { 1 }; void InitNAA( int max ) { NAA1 = NAAN_array[1] = max; NAA2 = NAAN_array[2] = NAA1 * NAA1; NAA3 = NAAN_array[3] = NAA1 * NAA2; NAA4 = NAAN_array[4] = NAA2 * NAA2; NAA5 = NAAN_array[5] = NAA2 * NAA3; NAA6 = NAAN_array[6] = NAA3 * NAA3; NAA7 = NAAN_array[7] = NAA3 * NAA4; NAA8 = NAAN_array[8] = NAA4 * NAA4; NAA9 = NAAN_array[9] = NAA4 * NAA5; NAA10 = NAAN_array[10] = NAA5 * NAA5; NAA11 = NAAN_array[11] = NAA5 * NAA6; NAA12 = NAAN_array[12] = NAA6 * NAA6; } extern Options options; ScoreMatrix mat; Vector Comp_AAN_idx; void make_comp_iseq(int len, char *iseq_comp, char *iseq) { int i, c[6] = {3,2,1,0,4,5}; for (i=0; i cpu ){ threads = cpu; printf( "Warning: total number of CPUs in the system is %i\n", cpu ); }else if( threads < 0 ){ threads += cpu; if( threads < 0 ) threads = 0; } if( threads == 0 ){ threads = cpu; printf( "total number of CPUs in the system is %i\n", cpu ); } if( threads != intval ) printf( "Actual number of CPUs to be used: %i\n\n", threads ); #else printf( "Option -T is ignored: multi-threading with OpenMP is NOT enabled!\n" ); #endif }else return false; return true; } bool Options::SetOption( const char *flag, const char *value ) { if( is454 ){ if( strcmp(flag, "-s") == 0 ) return false; else if( strcmp(flag, "-S") == 0 ) return false; else if( strcmp(flag, "-G") == 0 ) return false; else if( strcmp(flag, "-A") == 0 ) return false; else if( strcmp(flag, "-r") == 0 ) return false; else if( strcmp(flag, "-D") == 0 ){ max_indel = atoi(value); return true; } } if( SetOptionCommon( flag, value ) ) return true; if (strcmp(flag, "-t" ) == 0) tolerance = atoi(value); else if (strcmp(flag, "-F" ) == 0) frag_size = atoi(value); else if (has2D && SetOption2D( flag, value ) ) return true; else if (isEST && SetOptionEST( flag, value ) ) return true; else return false; return true; } bool Options::SetOption2D( const char *flag, const char *value ) { if( SetOptionCommon( flag, value ) ) return true; if (strcmp(flag, "-i2" ) == 0) input2 = value; else if (strcmp(flag, "-j2" ) == 0) input2_pe = value; else if (strcmp(flag, "-s2") == 0) diff_cutoff2 = atof(value); else if (strcmp(flag, "-S2") == 0) diff_cutoff_aa2 = atoi(value); else return false; return true; } bool Options::SetOptionEST( const char *flag, const char *value ) { NAA_top_limit = 12; if( SetOptionCommon( flag, value ) ) return true; if (strcmp(flag, "-r" ) == 0) option_r = atoi(value); else if (strcmp(flag, "-gap") == 0) mat.gap = MAX_SEQ * atoi(value); else if (strcmp(flag, "-gap-ext") == 0) mat.ext_gap = MAX_SEQ * atoi(value); else if (strcmp(flag, "-match") == 0) mat.set_match( atoi(value) ); else if (strcmp(flag, "-mismatch") == 0) mat.set_mismatch( atoi(value) ); else if (strcmp(flag, "-mask") == 0){ string letters = value; int i, n = letters.size(); for(i=0; i 'Z' ) continue; na2idx[ ch - 'A' ] = 5; } setaa_to_na(); }else return false; return true; } bool Options::SetOptions( int argc, char *argv[], bool twod, bool est ) { int i, n; char date[100]; strcpy( date, __DATE__ ); n = strlen( date ); for(i=1; i= 64 ){ printf( "\n %s", argv[i] ); n = strlen( argv[i] ) + 9; }else{ printf( " %s", argv[i] ); } } printf( "\n\n" ); time_t tm = time(NULL); printf( "Started: %s", ctime(&tm) ); printf( "================================================================\n" ); printf( " Output \n" ); printf( "----------------------------------------------------------------\n" ); has2D = twod; isEST = est; for (i=1; i+1 1.0) || (distance_thd < 0.0)) bomb_error("invalid distance threshold"); }else if( isEST ){ if ((cluster_thd > 1.0) || (cluster_thd < 0.8)) bomb_error("invalid clstr threshold, should >=0.8"); }else{ if ((cluster_thd > 1.0) || (cluster_thd < 0.4)) bomb_error("invalid clstr"); } if (input.size() == 0) bomb_error("no input file"); if (output.size() == 0) bomb_error("no output file"); if (PE_mode) { if (input_pe.size() == 0) bomb_error("no input file for R2 sequences in PE mode"); if (output_pe.size() == 0) bomb_error("no output file for R2 sequences in PE mode"); } if (isEST && (align_pos==1)) option_r = 0; if (band_width < 1 ) bomb_error("invalid band width"); if (NAA < 2 || NAA > NAA_top_limit) bomb_error("invalid word length"); if (des_len < 0 ) bomb_error("too short description, not enough to identify sequences"); if (not isEST && (tolerance < 0 || tolerance > 5) ) bomb_error("invalid tolerance"); if ((diff_cutoff<0) || (diff_cutoff>1)) bomb_error("invalid value for -s"); if (diff_cutoff_aa<0) bomb_error("invalid value for -S"); if( has2D ){ if ((diff_cutoff2<0) || (diff_cutoff2>1)) bomb_error("invalid value for -s2"); if (diff_cutoff_aa2<0) bomb_error("invalid value for -S2"); if (PE_mode) { if (input2_pe.size() == 0) bomb_error("no input file for R2 sequences for 2nd db in PE mode"); } } if (global_identity == 0) print = 1; if (short_coverage < long_coverage) short_coverage = long_coverage; if (short_control > long_control) short_control = long_control; if ((global_identity == 0) && (short_coverage == 0.0) && (min_control == 0)) bomb_error("You are using local identity, but no -aS -aL -A option"); if (frag_size < 0) bomb_error("invalid fragment size"); #if 0 if( useDistance ){ /* when required_aan becomes zero */ if( distance_thd * NAA >= 1 ) bomb_warning( "word length is too long for the distance cutoff" ); }else{ /* when required_aan becomes zero */ if( cluster_thd <= 1.0 - 1.0 / NAA ) bomb_warning( "word length is too long for the identity cutoff" ); } #endif const char *message = "Your word length is %i, using %i may be faster!\n"; if ( not isEST && tolerance ) { int i, clstr_idx = (int) (cluster_thd * 100) - naa_stat_start_percent; int tcutoff = naa_stat[tolerance-1][clstr_idx][5-NAA]; if (tcutoff < 5 ) bomb_error("Too low cluster threshold for the word length.\n" "Increase the threshold or the tolerance, or decrease the word length."); for ( i=5; i>NAA; i--) { if ( naa_stat[tolerance-1][clstr_idx][5-i] > 10 ) { printf( message, NAA, i ); break; } } } else if( isEST ) { if ( cluster_thd > 0.9 && NAA < 8 ) printf( message, NAA, 8 ); else if ( cluster_thd > 0.87 && NAA < 5 ) printf( message, NAA, 5 ); else if ( cluster_thd > 0.80 && NAA < 4 ) printf( message, NAA, 4 ); else if ( cluster_thd > 0.75 && NAA < 3 ) printf( message, NAA, 3 ); } else { if ( cluster_thd > 0.85 && NAA < 5 ) printf( message, NAA, 5 ); else if ( cluster_thd > 0.80 && NAA < 4 ) printf( message, NAA, 4 ); else if ( cluster_thd > 0.75 && NAA < 3 ) printf( message, NAA, 3 ); } if ( (min_length + 1) < NAA ) bomb_error("Too short -l, redefine it"); } void Options::Print() { printf( "isEST = %i\n", isEST ); printf( "has2D = %i\n", has2D ); printf( "NAA = %i\n", NAA ); printf( "NAA_top_limit = %i\n", NAA_top_limit ); printf( "min_length = %i\n", min_length ); printf( "cluster_best = %i\n", cluster_best ); printf( "global_identity = %i\n", global_identity ); printf( "cluster_thd = %g\n", cluster_thd ); printf( "diff_cutoff = %g\n", diff_cutoff ); printf( "diff_cutoff_aa = %i\n", diff_cutoff_aa ); printf( "tolerance = %i\n", tolerance ); printf( "long_coverage = %g\n", long_coverage ); printf( "long_control = %i\n", long_control ); printf( "short_coverage = %g\n", short_coverage ); printf( "short_control = %i\n", short_control ); printf( "frag_size = %i\n", frag_size ); printf( "option_r = %i\n", option_r ); printf( "print = %i\n", print ); } void bomb_error(const char *message) { fprintf( stderr, "\nFatal Error:\n%s\nProgram halted !!\n\n", message ); temp_files.Clear(); exit (1); } // END void bomb_error void bomb_error(const char *message, const char *message2) { fprintf( stderr, "\nFatal Error:\n%s %s\nProgram halted !!\n\n", message, message2 ); temp_files.Clear(); exit (1); } // END void bomb_error void bomb_warning(const char *message) { fprintf( stderr, "\nWarning:\n%s\nNot fatal, but may affect results !!\n\n", message ); } // END void bomb_warning void bomb_warning(const char *message, const char *message2) { fprintf( stderr, "\nWarning:\n%s %s\nNot fatal, but may affect results !!\n\n", message, message2 ); } // END void bomb_warning void format_seq(char *seq) { int i, j; char c1; int len = strlen(seq); for (i=0,j=0; i & taap = buffer.taap; Vector & aap_begin = buffer.aap_begin; Vector & aap_list = buffer.aap_list; Vector & diag_score = buffer.diag_score; Vector & diag_score2 = buffer.diag_score2; if (nall > MAX_DIAG) bomb_error("in diag_test_aapn, MAX_DIAG reached"); for (pp=&diag_score[0], i=nall; i; i--, pp++) *pp=0; for (pp=&diag_score2[0], i=nall; i; i--, pp++) *pp=0; int c22, cpx; INTs *bip; int len11 = len1-1; int len22 = len2-1; i1 = len11; for (i=0; i= 0 ? required_aa1-1:0; // on dec 21 2001 int band_e = nall - band_b; int band_m = ( band_b+band_width-1 < band_e ) ? band_b+band_width-1 : band_e; int best_score=0; int best_score2=0; int max_diag = 0; int max_diag2 = 0; int imax_diag = 0; for (i=band_b; i<=band_m; i++){ best_score += diag_score[i]; best_score2 += diag_score2[i]; if( diag_score2[i] > max_diag2 ){ max_diag2 = diag_score2[i]; max_diag = diag_score[i]; imax_diag = i; } } int from=band_b; int end =band_m; int score = best_score; int score2 = best_score2; for (k=from, j=band_m+1; j best_score2 ) { from = k + 1; end = j; best_score = score; best_score2 = score2; if( diag_score2[j] > max_diag2 ){ max_diag2 = diag_score2[j]; max_diag = diag_score[j]; imax_diag = j; } } } int mlen = imax_diag; if( imax_diag > len1 ) mlen = nall - imax_diag; int emax = int((1.0 - options.cluster_thd) * mlen) + 1; for (j=from; j emax || diag_score[j] < 1 ) { best_score -= diag_score[j]; from++; } else break; } for (j=end; j>imax_diag; j--) { // if aap pairs fail to open gap if ( (j - imax_diag) > emax || diag_score[j] < 1 ) { best_score -= diag_score[j]; end--; } else break; } // delete [] diag_score; band_left = from - len1 + 1; band_right= end - len1 + 1; band_center = imax_diag - len1 + 1; best_sum = best_score; return OK_FUNC; } // END diag_test_aapn int diag_test_aapn_est(int NAA1, char iseq2[], int len1, int len2, WorkingBuffer & buffer, int &best_sum, int band_width, int &band_left, int &band_center, int &band_right, int required_aa1) { int i, i1, j, k; int *pp, *pp2; int nall = len1+len2-1; int NAA2 = NAA1 * NAA1; int NAA3 = NAA2 * NAA1; Vector & taap = buffer.taap; Vector & aap_begin = buffer.aap_begin; Vector & aap_list = buffer.aap_list; Vector & diag_score = buffer.diag_score; Vector & diag_score2 = buffer.diag_score2; if (nall > MAX_DIAG) bomb_error("in diag_test_aapn_est, MAX_DIAG reached"); pp = & diag_score[0]; pp2 = & diag_score2[0]; for (i=nall; i; i--, pp++, pp2++) *pp = *pp2 =0; INTs *bip; int c22, cpx; int len22 = len2-3; i1 = len1-1; for (i=0; i=4) || (c1>=4) || (c2>=4) || (c3>=4)) continue; //skip N c22 = c0*NAA3+ c1*NAA2 + c2*NAA1 + c3; if ( (j=taap[c22]) == 0) continue; cpx = 1 + (c0 != c1) + (c1 != c2) + (c2 != c3); bip = & aap_list[ aap_begin[c22] ]; // bi = aap_begin[c22]; for (; j; j--, bip++) { diag_score[i1 - *bip]++; diag_score2[i1 - *bip] += cpx; } } #if 0 int mmax = 0; int immax = 0; for(i=0; i<=nall; i++){ if( i%len2 ==0 or i == nall ) printf( "\n" ); printf( "%3i ", diag_score[i] ); if( diag_score[i] > mmax ){ mmax = diag_score[i]; immax = i; } } #endif //find the best band range // int band_b = required_aa1; int band_b = required_aa1-1 >= 0 ? required_aa1-1:0; // on dec 21 2001 int band_e = nall - band_b; if( options.is454 ){ band_b = len1 - band_width; band_e = len1 + band_width; if( band_b < 0 ) band_b = 0; if( band_e > nall ) band_e = nall; } int band_m = ( band_b+band_width-1 < band_e ) ? band_b+band_width-1 : band_e; int best_score=0; int best_score2=0; int max_diag = 0; int max_diag2 = 0; int imax_diag = 0; for (i=band_b; i<=band_m; i++){ best_score += diag_score[i]; best_score2 += diag_score2[i]; if( diag_score2[i] > max_diag2 ){ max_diag2 = diag_score2[i]; max_diag = diag_score[i]; imax_diag = i; } } int from=band_b; int end =band_m; int score = best_score; int score2 = best_score2; for (k=from, j=band_m+1; j best_score2 ) { from = k + 1; end = j; best_score = score; best_score2 = score2; if( diag_score2[j] > max_diag2 ){ max_diag2 = diag_score2[j]; max_diag = diag_score[j]; imax_diag = j; } } } #if 0 printf( "%i %i\n", required_aa1, from ); printf( "max=%3i imax=%3i; band: %3i %3i %i\n", max_diag, imax_diag, band_b, band_e, band_m ); printf( "best: %i\n", best_score ); printf( "from: %i, end: %i, best: %i\n", from, end, best_score ); #endif int mlen = imax_diag; if( imax_diag > len1 ) mlen = nall - imax_diag; int emax = int((1.0 - options.cluster_thd) * mlen) + 1; for (j=from; j emax || diag_score[j] < 1 ) { best_score -= diag_score[j]; from++; } else break; } for (j=end; j>imax_diag; j--) { // if aap pairs fail to open gap if ( (j - imax_diag) > emax || diag_score[j] < 1 ) { best_score -= diag_score[j]; end--; } else break; } band_left = from-len1+1; band_right= end-len1+1; band_center = imax_diag - len1 + 1; best_sum = best_score; if( options.is454 ){ if( band_left > 0 ) best_sum = 0; if( band_right < 0 ) best_sum = 0; } #if 0 printf( "%3i: best: %i, %i %i %i\n", required_aa1, best_score, band_left, band_right, band_width ); printf( "max=%3i imax=%3i; band: %3i %3i %i\n", mmax, immax, band_b, band_e, band_m ); #endif return OK_FUNC; } // END diag_test_aapn_est /* local alignment of two sequence within a diag band for band 0 means direction (0,0) -> (1,1) 1 means direction (0,1) -> (1,2) -1 means direction (1,0) -> (2,1) added on 2006 11 13 band 0 XXXXXXXXXXXXXXXXXX seq2, rep seq XXXXXXXXXXXXXXX seq1 band 1 XXXXXXXXXXXXXXXXXX seq2, rep seq XXXXXXXXXXXXXXX seq1 extreme right (+) XXXXXXXXXXXXXXXXXX seq2, rep seq band = len2-1 XXXXXXXXXXXXXXX seq1 band-1 XXXXXXXXXXXXXXXXXX seq2, rep seq XXXXXXXXXXXXXXX seq1 extreme left (-) XXXXXXXXXXXXXXXXXX seq2, rep seq XXXXXXXXXXXXXXX band = -(len1-1) seq1 iseq len are integer sequence and its length, mat is matrix, return ALN_PAIR class band: -101 seq2 len2 = 17 \\\1234567890123456 0 \xxxxxxxxxxxxxxxxx 1 xxxxxxxxxxxxxxxxx\ most right band = len2-1 2 xxxxxxxxxxxxxxxxx seq1 3 xxxxxxxxxxxxxxxxx len1 = 11 4 xxxxxxxxxxxxxxxxx 5 xxxxxxxxxxxxxxxxx 6 xxxxxxxxxxxxxxxxx 7 xxxxxxxxxxxxxxxxx 8 xxxxxxxxxxxxxxxxx 9 xxxxxxxxxxxxxxxxx 0 xxxxxxxxxxxxxxxxx \ most left band = -(len1-1) */ int local_band_align( char iseq1[], char iseq2[], int len1, int len2, ScoreMatrix &mat, int &best_score, int &iden_no, int &alnln, float &dist, int *alninfo, int band_left, int band_center, int band_right, WorkingBuffer & buffer) { int i, j, k, j1; int jj, kk; int iden_no1; int64_t best_score1; iden_no = 0; if ( (band_right >= len2 ) || (band_left <= -len1) || (band_left > band_right) ) return FAILED_FUNC; // allocate mem for score_mat[len1][len2] etc int band_width = band_right - band_left + 1; int band_width1 = band_width + 1; MatrixInt64 & score_mat = buffer.score_mat; MatrixInt & back_mat = buffer.back_mat; //printf( "%i %i\n", band_right, band_left ); if( score_mat.size() <= len1 ){ VectorInt row( band_width1, 0 ); VectorInt64 row2( band_width1, 0 ); while( score_mat.size() <= len1 ){ score_mat.Append( row2 ); back_mat.Append( row ); } } for(i=0; i<=len1; i++){ if( score_mat[i].Size() < band_width1 ) score_mat[i].Resize( band_width1 ); if( back_mat[i].Size() < band_width1 ) back_mat[i].Resize( band_width1 ); } best_score = 0; /* seq2 len2 = 17 seq2 len2 = 17 seq2 len2 = 17 01234567890123456 01234567890123456 01234567890123456 0 xxxxxxxxxxxxxxxxx \\\\\\XXXxxxxxxxxxxxxxx xXXXXXXXxxxxxxxxx 1\\\\\Xxxxxxxxxxxxxxxxx \\\\\Xxx\xxxxxxxxxxxxx xx\xxxxx\xxxxxxxx 2 \\\\X\xxxxxxxxxxxxxxx \\\\Xxxx\xxxxxxxxxxxx xxx\xxxxx\xxxxxxx seq1 3 \\\Xx\xxxxxxxxxxxxxx \\\Xxxxx\xxxxxxxxxxx xxxx\xxxxx\xxxxxx len1 4 \\Xxx\xxxxxxxxxxxxx \\Xxxxxx\xxxxxxxxxx xxxxx\xxxxx\xxxxx = 11 5 \Xxxx\xxxxxxxxxxxx \Xxxxxxx\xxxxxxxxx xxxxxx\xxxxx\xxxx 6 Xxxxx\xxxxxxxxxxx Xxxxxxxx\xxxxxxxx xxxxxxx\xxxxx\xxx 7 x\xxxx\xxxxxxxxxx x\xxxxxxx\xxxxxxx xxxxxxxx\xxxxx\xx 8 xx\xxxx\xxxxxxxxx xx\xxxxxxx\xxxxxx xxxxxxxxx\xxxxx\x 9 xxx\xxxx\xxxxxxxx xxx\xxxxxxx\xxxxx xxxxxxxxxx\xxxxx\ 0 xxxx\xxxx\xxxxxxx xxxx\xxxxxxx\xxxx xxxxxxxxxxx\xxxxx band_left < 0 band_left < 0 band_left >=0 band_right < 0 band_right >=0 band_right >=0 init score_mat, and iden_mat (place with upper 'X') */ if (band_left < 0) { //set score to left border of the matrix within band int tband = (band_right < 0) ? band_right : 0; //for (k=band_left; k=0) { //set score to top border of the matrix within band int tband = (band_left > 0) ? band_left : 0; for (j=tband; j<=band_right; j++) { j1 = j-band_left; score_mat[0][j1] = mat.ext_gap * j; back_mat[0][j1] = DP_BACK_LEFT; } back_mat[0][tband-band_left] = DP_BACK_NONE; } int gap_open[2] = { mat.gap, mat.ext_gap }; int max_diag = band_center - band_left; int extra_score[4] = { 4, 3, 2, 1 }; for (i=1; i<=len1; i++) { int J0 = 1 - band_left - i; int J1 = len2 - band_left - i; if( J0 < 0 ) J0 = 0; if( J1 >= band_width ) J1 = band_width; for (j1=J0; j1<=J1; j1++){ j = j1+i+band_left; int ci = iseq1[i-1]; int cj = iseq2[j-1]; int sij = mat.matrix[ci][cj]; //int iden_ij = (ci == cj); int s1, k0, back; /* extra score according to the distance to the best diagonal */ int extra = extra_score[ abs(j1 - max_diag) & 3 ]; // max distance 3 sij += extra * (sij>0); back = DP_BACK_LEFT_TOP; best_score1 = score_mat[i-1][j1] + sij; int gap0 = gap_open[ (i == len1) | (j == len2) ]; int gap = 0; int64_t score; if( j1 > 0 ){ gap = gap0; if( back_mat[i][j1-1] == DP_BACK_LEFT ) gap = mat.ext_gap; if( (score = score_mat[i][j1-1] + gap) > best_score1 ){ back = DP_BACK_LEFT; best_score1 = score; } } if(j1+1 best_score1 ){ back = DP_BACK_TOP; best_score1 = score; } } score_mat[i][j1] = best_score1; back_mat[i][j1] = back; //printf( "%2i(%2i) ", best_score1, iden_no1 ); } //printf( "\n" ); } i = j = 0; if( len2 - band_left < len1 ){ i = len2 - band_left; j = len2; }else if( len1 + band_right < len2 ){ i = len1; j = len1 + band_right; }else{ i = len1; j = len2; } j1 = j - i - band_left; best_score = score_mat[i][j1]; best_score1 = score_mat[i][j1]; #if 1 const char *letters = "acgtnx"; const char *letters2 = "ACGTNX"; #else const char *letters = "arndcqeghilkmfpstwyvbzx"; const char *letters2 = "ARNDCQEGHILKMFPSTWYVBZX"; #endif int back = back_mat[i][j1]; int last = back; int count = 0, count2 = 0, count3 = 0; int match, begin1, begin2, end1, end2; int gbegin1=0, gbegin2=0, gend1=0, gend2=0; int64_t score, smin = best_score1, smax = best_score1 - 1; int posmin, posmax, pos = 0; int bl, dlen = 0, dcount = 0; posmin = posmax = 0; begin1 = begin2 = end1 = end2 = 0; #ifdef PRINT #define PRINT printf( "%i %i\n", best_score, score_mat[i][j1] ); printf( "%i %i %i\n", band_left, band_center, band_right ); printf( "%i %i %i %i\n", i, j, j1, len2 ); #endif #ifdef MAKEALIGN #define MAKEALIGN char AA[ MAX_SEQ ], BB[ MAX_SEQ ]; int NN = 0; int IA, IB; for(IA=len1;IA>i;IA--){ AA[NN] = letters[ iseq1[IA-1] ]; BB[NN++] = '-'; } for(IB=len2;IB>j;IB--){ AA[NN] = '-'; BB[NN++] = letters[ iseq2[IB-1] ]; } #endif int masked = 0; int indels = 0; int max_indels = 0; while( back != DP_BACK_NONE ){ switch( back ){ case DP_BACK_TOP : #ifdef PRINT printf( "%5i: %c %c %9i\n", pos, letters[ iseq1[i-1] ], '|', score_mat[i][j1] ); #endif #ifdef MAKEALIGN AA[NN] = letters[ iseq1[i-1] ]; BB[NN++] = '-'; #endif bl = (last != back) & (j != 1) & (j != len2); dlen += bl; dcount += bl; score = score_mat[i][j1]; if( score < smin ){ count2 = 0; smin = score; posmin = pos - 1; begin1 = i; begin2 = j; } i -= 1; j1 += 1; break; case DP_BACK_LEFT : #ifdef PRINT printf( "%5i: %c %c %9i\n", pos, '|', letters[ iseq2[j-1] ], score_mat[i][j1] ); #endif #ifdef MAKEALIGN AA[NN] = '-'; BB[NN++] = letters[ iseq2[j-1] ]; #endif bl = (last != back) & (i != 1) & (i != len1); dlen += bl; dcount += bl; score = score_mat[i][j1]; if( score < smin ){ count2 = 0; smin = score; posmin = pos - 1; begin1 = i; begin2 = j; } j1 -= 1; j -= 1; break; case DP_BACK_LEFT_TOP : #ifdef PRINT if( iseq1[i-1] == iseq2[j-1] ){ printf( "%5i: %c %c %9i\n", pos, letters2[ iseq1[i-1] ], letters2[ iseq2[j-1] ], score_mat[i][j1] ); }else{ printf( "%5i: %c %c %9i\n", pos, letters[ iseq1[i-1] ], letters[ iseq2[j-1] ], score_mat[i][j1] ); } #endif #ifdef MAKEALIGN if( iseq1[i-1] == iseq2[j-1] ){ AA[NN] = letters2[ iseq1[i-1] ]; BB[NN++] = letters2[ iseq2[j-1] ]; }else{ AA[NN] = letters[ iseq1[i-1] ]; BB[NN++] = letters[ iseq2[j-1] ]; } #endif if( alninfo && options.global_identity ){ if( i == 1 || j == 1 ){ gbegin1 = i-1; gbegin2 = j-1; }else if( i == len1 || j == len2 ){ gend1 = i-1; gend2 = j-1; } } score = score_mat[i][j1]; i -= 1; j -= 1; match = iseq1[i] == iseq2[j]; if( score > smax ){ count = 0; smax = score; posmax = pos; end1 = i; end2 = j; } if( options.isEST && (iseq1[i] > 4 || iseq2[j] > 4) ){ masked += 1; }else{ dlen += 1; dcount += ! match; count += match; count2 += match; count3 += match; } if( score < smin ){ int mm = match == 0; count2 = 0; smin = score; posmin = pos - mm; begin1 = i + mm; begin2 = j + mm; } break; default : printf( "%i\n", back ); break; } if( options.is454 ){ if( back == DP_BACK_LEFT_TOP ){ if( indels > max_indels ) max_indels = indels; indels = 0; }else{ if( last == DP_BACK_LEFT_TOP ){ indels = 1; }else if( indels ){ indels += 1; } } } pos += 1; last = back; back = back_mat[i][j1]; } if( options.is454 and max_indels > options.max_indel ) return FAILED_FUNC; iden_no = options.global_identity ? count3 : count - count2; alnln = posmin - posmax + 1 - masked; dist = dcount/(float)dlen; //dist = - 0.75 * log( 1.0 - dist * 4.0 / 3.0 ); int umtail1 = len1 - 1 - end1; int umtail2 = len2 - 1 - end2; int umhead = begin1 < begin2 ? begin1 : begin2; int umtail = umtail1 < umtail2 ? umtail1 : umtail2; int umlen = umhead + umtail; if( umlen > options.unmatch_len ) return FAILED_FUNC; if( umlen > len1 * options.short_unmatch_per ) return FAILED_FUNC; if( umlen > len2 * options.long_unmatch_per ) return FAILED_FUNC; if( alninfo ){ alninfo[0] = begin1; alninfo[1] = end1; alninfo[2] = begin2; alninfo[3] = end2; alninfo[4] = masked; if( options.global_identity ){ alninfo[0] = gbegin1; alninfo[1] = gend1; alninfo[2] = gbegin2; alninfo[3] = gend2; } } #ifdef PRINT printf( "%6i %6i: %4i %4i %4i %4i\n", alnln, iden_no, begin1, end1, begin2, end2 ); printf( "%6i %6i: %4i %4i\n", posmin, posmax, posmin - posmax, count - count2 ); printf( "smin = %9i, smax = %9i\n", smin, smax ); printf( "dlen = %5i, dcount = %5i, dist = %.3f\n", dlen, dcount, dcount/(float)dlen ); #endif #ifdef MAKEALIGN float identity = iden_no / (float)( options.global_identity ? (len1 - masked) : alnln); if( identity < options.cluster_thd ) return OK_FUNC; while(i--){ AA[NN] = letters[ iseq1[i-1] ]; BB[NN++] = '-'; } while(j--){ AA[NN] = '-'; BB[NN++] = letters[ iseq2[j-1] ]; } AA[NN] = '\0'; BB[NN] = '\0'; for(i=0; iindex, AA ); fprintf( fout, "%i %s\n", seq2->index, BB ); #else bool printaa = true; IB = IA = 0; fprintf( fout, "\n\nX " ); while( IA < NN ){ if( printaa ){ fprintf( fout, "%c", BB[IB] ); IB += 1; if( IB % 75 ==0 or IB == NN ) printaa = false, fprintf( fout, "\nY " ); }else{ fprintf( fout, "%c", AA[IA] ); IA += 1; if( IA % 75 ==0 ) printaa = true, fprintf( fout, "\n\nX " ); } } #endif fclose( fout ); #endif return OK_FUNC; } // END int local_band_align void setaa_to_na() { int i; for (i=0; i<26; i++) aa2idx[i] = na2idx[i]; } // END void setaa_to_na ///////////////// ScoreMatrix::ScoreMatrix() { init(); } void ScoreMatrix::init() { set_gap( -11, -1 ); set_matrix( BLOSUM62 ); } void ScoreMatrix::set_gap(int gap1, int ext_gap1) { int i; gap = MAX_SEQ * gap1; ext_gap = MAX_SEQ * ext_gap1; } void ScoreMatrix::set_matrix(int *mat1) { int i, j, k; k = 0; for ( i=0; i & ics = indexCounts[i]; for(int j=0; j= 4; } } printf( "%9i %9i %9i %9i\n", n1, n2, n3, ns ); #endif size = 0; frag_count = 0; sequences.clear(); for (i=0; i & counts, Sequence *seq, bool skipN) { int aan_no = counts.Size(); int i, j, k, idx = sequences.size(); for (i=0; i & row = indexCounts[j]; ic.index = idx; row.Append( ic ); size += 1; } } sequences.Append( seq ); return OK_FUNC; } int WordTable::AddWordCountsFrag( NVector & counts, int frag, int frag_size, int repfrag ) { return 0; } int WordTable::AddWordCounts(int aan_no, Vector & word_encodes, Vector & word_encodes_no, int idx, bool skipN) { int i, j, k; //printf( "seq %6i: ", idx ); for (i=0; i & row = indexCounts[j]; row.Append( IndexCount( idx, k ) ); size += 1; //if( k >1 ) printf( " %3i", k ); } } //printf( "\n" ); return OK_FUNC; } int WordTable::AddWordCountsFrag( int aan_no, Vector & word_encodes, Vector & word_encodes_no, int frag, int frag_size ) { int i, j, k, i1, k1, fra; for (i=0; i & row = indexCounts[j]; row.Append( IndexCount( frag_count + fra, k1 ) ); size += 1; } } } frag_count += frag; return 0; } void WordTable::PrintAll() { int i, j, k; int cols = 0; long long total_words = 0; k = 0; for (i=0; i= last ) return; val = data[first]; data[first] = data[ (first+last)/2 ]; data[ (first+last)/2 ] = val; pivot = data[ first ]; while( lower <= upper ){ while( lower <= last && data[lower].count < pivot.count ) lower ++; while( pivot.count < data[upper].count ) upper --; if( lower < upper ){ val = data[lower]; data[lower] = data[upper]; data[upper] = val; upper --; } lower ++; } val = data[first]; data[first] = data[upper]; data[upper] = val; if( first < upper-1 ) PartialQuickSort( data, first, upper-1, partial ); if( upper >= partial ) return; if( upper+1 < last ) PartialQuickSort( data, upper+1, last, partial ); } int WordTable::CountWords(int aan_no, Vector & word_encodes, Vector & word_encodes_no, NVector &lookCounts, NVector & indexMapping, bool est, int min) { int S = frag_count ? frag_count : sequences.size(); int j, k, j0, j1, k1, m; int ix1, ix2, ix3, ix4; IndexCount tmp; IndexCount *ic = lookCounts.items; for(j=0; jindex ] = 0; lookCounts.size = 0; int *we = & word_encodes[0]; j0 = 0; if( est ) while( *we <0 ) j0++, we++; // if met short word has 'N' INTs *wen = & word_encodes_no[j0]; //printf( "\nquery : " ); for (; j01 ) printf( " %3i", j1 ); if( j1==0 ) continue; NVector & one = indexCounts[j]; k1 = one.Size(); IndexCount *ic = one.items; int rest = aan_no - j0 + 1; for (k=0; kcount < j1 ? ic->count : j1; uint32_t *idm = indexMapping.items + ic->index; if( *idm ==0 ){ if( rest < min ) continue; IndexCount *ic2 = lookCounts.items + lookCounts.size; lookCounts.size += 1; *idm = lookCounts.size; ic2->index = ic->index; ic2->count = c; }else{ lookCounts[ *idm - 1 ].count += c; } } } //printf( "%6i %6i\n", S, lookCounts.size ); lookCounts[ lookCounts.size ].count = 0; //printf( "\n\n" ); return OK_FUNC; } Sequence::Sequence() { memset( this, 0, sizeof( Sequence ) ); distance = 2.0; } Sequence::Sequence( const Sequence & other ) { int i; //printf( "new: %p %p\n", this, & other ); memcpy( this, & other, sizeof( Sequence ) ); distance = 2.0; if( other.data ){ size = bufsize = other.size; size_R2 = 0; data = new char[size+1]; //printf( "data: %p %p\n", data, other.data ); data[size] = 0; memcpy( data, other.data, size ); //for (i=0; i XXXXXXABC ------------------- NMLYYYYYY <--R2 // >R1 >R2 // XXXXXXABC YYYYYYLMN =====> Merge into // >R12 // NMLYYYYYYXXXXXXABC Sequence::Sequence( const Sequence & other, const Sequence & other2, int mode ) { int i; if (mode != 1) bomb_error("unknown mode"); //printf( "new: %p %p\n", this, & other ); memcpy( this, & other, sizeof( Sequence ) ); distance = 2.0; if( other.data && other2.data ){ size = bufsize = (other.size + other2.size); size_R2 = other2.size; data = new char[size+1]; //printf( "data: %p %p\n", data, other.data ); data[size] = 0; data[size_R2] = 0; memcpy( data, other2.data, size_R2); // copy R2 first strrev( data ); // reverse R2 on data memcpy( data+size_R2, other.data, size-size_R2 ); // copy R1 to end of R2 //for (i=0; i bufsize ){ char *old = data; bufsize = size + size/5 + 1; data = new char[ bufsize + 1 ]; if ( data == NULL ) bomb_error( "Memory" ); if ( old ){ memcpy( data, old, m ); delete []old; } } if( size ) data[size] = 0; } void Sequence::trim(int trim_len) { if (trim_len >= size) return; size = trim_len; if (size) data[size]=0; } void Sequence::ConvertBases() { int i; for(i=0; i%s...", id, size, tag, identifier+1 ); if( identity ){ int *c = coverage; fprintf( fout, " at " ); if (print) fprintf( fout, "%i:%i:%i:%i/", c[0], c[1], c[2], c[3] ); if (strand) fprintf( fout, "%c/", (state & IS_MINUS_STRAND) ? '-' : '+' ); fprintf( fout, "%.2f%%", identity*100 ); if( options.useDistance ) fprintf( fout, "/%.2f%%", distance*100 ); fprintf( fout, "\n" ); }else{ fprintf( fout, " *\n" ); } } // by liwz // disable swap option // change des_begin, des_length, des_length2, dat_length => des_begin, tot_length // where des_begin is the FILE pointer of sequence record start // tot_length is the total bytes of sequence record void SequenceDB::Read( const char *file, const Options & options ) { Sequence one; Sequence des; FILE *fin = fopen( file, "rb" ); char *buffer = NULL; char *res = NULL; int option_l = options.min_length; if( fin == NULL ) bomb_error( "Failed to open the database file" ); Clear(); buffer = new char[ MAX_LINE_SIZE+1 ]; while (not feof( fin ) || one.size) { /* do not break when the last sequence is not handled */ buffer[0] = '>'; if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL && one.size == 0) break; if( buffer[0] == '+' ){ int len = strlen( buffer ); int len2 = len; while( len2 && buffer[len2-1] != '\n' ){ if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; len2 = strlen( buffer ); len += len2; } one.tot_length += len; // read next line quality score if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) bomb_error("can not read quality score after"); len = strlen( buffer ); len2 = len; while( len2 && buffer[len2-1] != '\n' ){ if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; len2 = strlen( buffer ); len += len2; } one.tot_length += len; }else if (buffer[0] == '>' || buffer[0] == '@' || (res==NULL && one.size)) { if ( one.size ) { // write previous record if( one.identifier == NULL || one.Format() ){ printf( "Warning: from file \"%s\",\n", file ); printf( "Discarding invalid sequence or sequence without identifier and description!\n\n" ); if( one.identifier ) printf( "%s\n", one.identifier ); printf( "%s\n", one.data ); one.size = 0; } one.index = sequences.size(); if( one.size > option_l ) { if (options.trim_len > 0) one.trim(options.trim_len); sequences.Append( new Sequence( one ) ); } } one.size = 0; one.tot_length = 0; int len = strlen( buffer ); int len2 = len; des.size = 0; des += buffer; while( len2 && buffer[len2-1] != '\n' ){ if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; des += buffer; len2 = strlen( buffer ); len += len2; } size_t offset = ftell( fin ); one.des_begin = offset - len; one.tot_length += len; // count first line int i = 0; if( des.data[i] == '>' || des.data[i] == '@' || des.data[i] == '+' ) i += 1; if( des.data[i] == ' ' or des.data[i] == '\t' ) i += 1; if( options.des_len and options.des_len < des.size ) des.size = options.des_len; while( i < des.size and ! isspace( des.data[i] ) ) i += 1; des.data[i] = 0; one.identifier = des.data; } else { one.tot_length += strlen(buffer); one += buffer; } } #if 0 int i, n = 0; for(i=0; i 0)) bomb_error( "Paired input files have different number sequences" ); if ( (one.size > 0 ) && (two.size == 0)) bomb_error( "Paired input files have different number sequences" ); if ( (res == NULL) && (one.size == 0)) break; if( buffer[0] == '+' ){ // fastq 3rd line // file 1 int len = strlen( buffer ); int len2 = len; while( len2 && buffer[len2-1] != '\n' ){ // read until the end of the line if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; len2 = strlen( buffer ); len += len2; } one.tot_length += len; // read next line quality score if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) bomb_error("can not read quality score after"); len = strlen( buffer ); len2 = len; while( len2 && buffer[len2-1] != '\n' ){ if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; len2 = strlen( buffer ); len += len2; } one.tot_length += len; // file 2 len = strlen( buffer2 ); len2 = len; while( len2 && buffer2[len2-1] != '\n' ){ // read until the end of the line if ( (res2=fgets( buffer2, MAX_LINE_SIZE, fin2 )) == NULL ) break; len2 = strlen( buffer2 ); len += len2; } two.tot_length += len; // read next line quality score if ( (res2=fgets( buffer2, MAX_LINE_SIZE, fin2 )) == NULL ) bomb_error("can not read quality score after"); len = strlen( buffer2 ); len2 = len; while( len2 && buffer2[len2-1] != '\n' ){ if ( (res2=fgets( buffer2, MAX_LINE_SIZE, fin2 )) == NULL ) break; len2 = strlen( buffer2 ); len += len2; } two.tot_length += len; }else if (buffer[0] == '>' || buffer[0] == '@' || (res==NULL && one.size)) { if ( one.size && two.size ) { // write previous record if( one.identifier == NULL || one.Format() ){ printf( "Warning: from file \"%s\",\n", file ); printf( "Discarding invalid sequence or sequence without identifier and description!\n\n" ); if( one.identifier ) printf( "%s\n", one.identifier ); printf( "%s\n", one.data ); one.size=0; two.size=0; } if( two.identifier == NULL || two.Format() ){ printf( "Warning: from file \"%s\",\n", file2 ); printf( "Discarding invalid sequence or sequence without identifier and description!\n\n" ); if( two.identifier ) printf( "%s\n", two.identifier ); printf( "%s\n", two.data ); one.size=0; two.size = 0; } one.index = sequences.size(); if( (one.size + two.size)> option_l ) { if (options.trim_len > 0) one.trim(options.trim_len); if (options.trim_len_R2 > 0) two.trim(options.trim_len_R2); sequences.Append( new Sequence( one, two, 1 ) ); } } // R1 one.size = 0; one.tot_length = 0; int len = strlen( buffer ); int len2 = len; des.size = 0; des += buffer; while( len2 && buffer[len2-1] != '\n' ){ if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break; des += buffer; len2 = strlen( buffer ); len += len2; } size_t offset = ftell( fin ); one.des_begin = offset - len; // offset of ">" or "@" one.tot_length += len; // count first line int i = 0; if( des.data[i] == '>' || des.data[i] == '@' || des.data[i] == '+' ) i += 1; if( des.data[i] == ' ' or des.data[i] == '\t' ) i += 1; if( options.des_len and options.des_len < des.size ) des.size = options.des_len; while( i < des.size and ! isspace( des.data[i] ) ) i += 1; des.data[i] = 0; // find first non-space letter one.identifier = des.data; // R2 two.size = 0; two.tot_length = 0; len = strlen( buffer2 ); len2 = len; while( len2 && buffer2[len2-1] != '\n' ){ if ( (res=fgets( buffer2, MAX_LINE_SIZE, fin2 )) == NULL ) break; len2 = strlen( buffer2 ); len += len2; } offset = ftell( fin2 ); two.des_begin = offset - len; two.tot_length += len; // count first line two.identifier = des.data; } else { one.tot_length += strlen(buffer); one += buffer; two.tot_length+= strlen(buffer2); two+= buffer2; } } #if 0 int i, n = 0; for(i=0; i= last ) return; val = sequences[first]; sequences[first] = sequences[ (first+last)/2 ]; sequences[ (first+last)/2 ] = val; pivot = sequences[ first ]; while( lower <= upper ){ while( lower <= last && sequences[lower]->stats < pivot->stats ) lower ++; while( pivot->stats < sequences[upper]->stats ) upper --; if( lower < upper ){ val = sequences[lower]; sequences[lower] = sequences[upper]; sequences[upper] = val; upper --; } lower ++; } val = sequences[first]; sequences[first] = sequences[upper]; sequences[upper] = val; if( first < upper-1 ) Sort( first, upper-1 ); if( upper+1 < last ) Sort( upper+1, last ); } #endif void SequenceDB::SortDivide( Options & options, bool sort ) { int i, j, k, len; int N = sequences.size(); total_letter=0; total_desc=0; max_len = 0; min_len = (size_t)-1; for (i=0; isize; total_letter += len; if (len > max_len) max_len = len; if (len < min_len) min_len = len; if (seq->swap == NULL) seq->ConvertBases(); if( seq->identifier ) total_desc += strlen( seq->identifier ); } options.max_entries = max_len * MAX_TABLE_SEQ; if (max_len >= 65536 and sizeof(INTs) <=2) bomb_warning("Some seqs longer than 65536, you may define LONG_SEQ"); if (max_len > MAX_SEQ ) bomb_warning("Some seqs are too long, please rebuild the program with make parameter " "MAX_SEQ=new-maximum-length (e.g. make MAX_SEQ=10000000)"); cout << "longest and shortest : " << max_len << " and " << min_len << endl; cout << "Total letters: " << total_letter << endl; // END change all the NR_seq to iseq len_n50 = (max_len + min_len) / 2; // will be properly set, if sort is true; if( sort ){ // **************************** Form NR_idx[], Sort them from Long to short long long sum = 0; int M = max_len - min_len + 1; Vector count( M, 0 ); // count for each size = max_len - i Vector accum( M, 0 ); // count for all size > max_len - i Vector offset( M, 0 ); // offset from accum[i] when filling sorting Vector sorting( N ); // TODO: use a smaller class if this consumes to much memory! for (i=0; isize ] ++; for (i=1; i= (total_letter>>1) ){ len_n50 = max_len - i; break; } } for (i=0; isize; int id = accum[len] + offset[len]; //sequences[i].index = id; sorting[id] = sequences[i]; offset[len] ++; } options.max_entries = 0; for (i=0; isize; } #if 0 if( options.isEST ){ int start = 0; for (i=0; isize; if( max_seg >= MAX_BIN_SWAP ) max_seg = (size_t) MAX_BIN_SWAP; FILE *fin = fopen( db, "rb" ); char *buf = new char[MAX_LINE_SIZE+1]; char outfile[512]; size_t seg_size = 0; int i, j, count, rest, seg = 0; sprintf( outfile, "%s-%i", newdb, 0 ); FILE *fout = fopen( outfile, "w+" ); n = sequences.size(); for (i=0; ides_begin, SEEK_SET ); seg_size += seq->size; if( seg_size >= max_seg ){ seg += 1; sprintf( outfile, "%s-%i", newdb, seg ); fclose( fout ); fout = fopen( outfile, "w+" ); seg_size = seq->size; } count = seq->tot_length / MAX_LINE_SIZE; rest = seq->tot_length % MAX_LINE_SIZE; //printf( "count = %6i, rest = %6i\n", count, rest ); for (j=0; j sorting( n ); if( fin == NULL || fout == NULL ) bomb_error( "file opening failed" ); for (i=0; iindex << 32) | rep_seqs[i]; std::sort( sorting.begin(), sorting.end() ); for (i=0; ides_begin, SEEK_SET ); count = seq->tot_length / MAX_LINE_SIZE; rest = seq->tot_length % MAX_LINE_SIZE; //printf( "count = %6i, rest = %6i\n", count, rest ); for (j=0; j sorting( n ); if( fin == NULL || fout == NULL ) bomb_error( "file opening failed" ); if( fin_pe == NULL || fout_pe == NULL ) bomb_error( "file opening failed" ); for (i=0; iindex << 32) | rep_seqs[i]; std::sort( sorting.begin(), sorting.end() ); //sort fasta / fastq int *clstr_size; int *clstr_idx1; if (options.sort_outputf) { clstr_size = new int[n]; clstr_idx1 = new int[n]; for (i=0; icluster_id; if (id < 0) continue; if (id >=n) continue; clstr_size[id]++; } quick_sort_idxr(clstr_size, clstr_idx1, 0, n-1); } for (i=0; ides_begin, SEEK_SET ); count = seq->tot_length / MAX_LINE_SIZE; rest = seq->tot_length % MAX_LINE_SIZE; //printf( "count = %6i, rest = %6i\n", count, rest ); for (j=0; jdes_begin2, SEEK_SET ); count = seq->tot_length2 / MAX_LINE_SIZE; rest = seq->tot_length2 % MAX_LINE_SIZE; //printf( "count = %6i, rest = %6i\n", count, rest ); for (j=0; j sorting( N ); for (i=0; iindex << 32) | i; std::sort( sorting.begin(), sorting.end() ); FILE *fout; char *buf = new char[ MAX_DES + 1 ]; if( options.backupFile ){ fout = fopen( db_clstr_bak.c_str(), "w+" ); for (i=0; iPrintInfo( seq->cluster_id, fout, options, buf ); } fclose( fout ); } cout << "writing clustering information" << endl; int M = rep_seqs.size(); Vector > clusters( M ); for (i=0; icluster_id; clusters[id].Append( k ); } fout = fopen( db_clstr.c_str(), "w+" ); if (options.sort_output) { int *clstr_size = new int[M]; int *clstr_idx1 = new int[M]; for (i=0; iCluster %i\n", i ); for (k=0; k<(int)clusters[i0].size(); k++) sequences[ clusters[i0][k] ]->PrintInfo( k, fout, options, buf ); } } else { for (i=0; iCluster %i\n", i ); for (k=0; k<(int)clusters[i].size(); k++) sequences[ clusters[i][k] ]->PrintInfo( k, fout, options, buf ); } } delete []buf; } void SequenceDB::WriteExtra2D( SequenceDB & other, const Options & options ) { string db_clstr = options.output + ".clstr"; string db_clstr_bak = options.output + ".bak.clstr"; int i, k, N = other.sequences.size(); int N2 = sequences.size(); vector sorting( N ); for (i=0; iindex << 32) | i; std::sort( sorting.begin(), sorting.end() ); FILE *fout; char *buf = new char[ MAX_DES + 1 ]; if( options.backupFile ){ fout = fopen( db_clstr_bak.c_str(), "w+" ); for (i=0; iPrintInfo( seq->cluster_id, fout, options, buf ); } for (i=0; istate & IS_REDUNDANT ) seq->PrintInfo( seq->cluster_id, fout, options, buf ); } fclose( fout ); } cout << "writing clustering information" << endl; Vector > clusters( N ); for (i=0; icluster_id; if( sequences[i]->state & IS_REDUNDANT ) clusters[id].Append( i ); } fout = fopen( db_clstr.c_str(), "w+" ); for (i=0; iCluster %i\n", i ); seq->PrintInfo( 0, fout, options, buf ); for (k=0; k<(int)clusters[i].size(); k++) sequences[ clusters[i][k] ]->PrintInfo( k+1, fout, options, buf ); } delete []buf; } void WorkingParam::ControlShortCoverage( int len, const Options & options ) { len_eff = len; aln_cover_flag = 0; if ((options.short_coverage > 0.0) || (options.min_control>0) ) { // has alignment coverage control aln_cover_flag = 1; min_aln_lenS = (int) (double(len) * options.short_coverage); if ( len-options.short_control > min_aln_lenS) min_aln_lenS = len-options.short_control; if ( options.min_control > min_aln_lenS) min_aln_lenS = options.min_control; } if (options.global_identity == 0) len_eff = min_aln_lenS; //global_identity==0 } void WorkingParam::ControlLongCoverage( int len2, const Options & options ) { if (aln_cover_flag) { min_aln_lenL = (int) (double(len2) * options.long_coverage); if ( len2-options.long_control > min_aln_lenL) min_aln_lenL = len2-options.long_control; if ( options.min_control > min_aln_lenL) min_aln_lenL = options.min_control; } } // when alignment coverage such as -aL is specified // if a existing rep is too long, it won't be qulified int upper_bound_length_rep(int len, double opt_s, int opt_S, double opt_aL, int opt_AL ) { int len_upper_bound = 99999999; double r1 = (opt_s > opt_aL) ? opt_s : opt_aL; int a2 = (opt_S < opt_AL) ? opt_S : opt_AL; if (r1 > 0.0) len_upper_bound = (int) ( ((float) len) / r1); if ((len+a2) < len_upper_bound) len_upper_bound = len+a2; return len_upper_bound; } // END upper_bound_length_rep int upper_bound_length_rep(int len, const Options & options ) { double opt_s = options.diff_cutoff; int opt_S = options.diff_cutoff_aa; double opt_aL = options.long_coverage; int opt_AL = options.long_control; return upper_bound_length_rep( len, opt_s, opt_S, opt_aL, opt_AL ); } void cal_aax_cutoff(double &aa1_cutoff, double &aa2_cutoff, double &aan_cutoff, double cluster_thd, int tolerance, int naa_stat_start_percent, int naa_stat[5][61][4], int NAA) { aa1_cutoff = cluster_thd; aa2_cutoff = 1 - (1-cluster_thd)*2; aan_cutoff = 1 - (1-cluster_thd)*NAA; if (tolerance==0) return; int clstr_idx = (int) (cluster_thd * 100) - naa_stat_start_percent; if (clstr_idx <0) clstr_idx = 0; double d2 = ((double) (naa_stat[tolerance-1][clstr_idx][3] )) / 100; double dn = ((double) (naa_stat[tolerance-1][clstr_idx][5-NAA] )) / 100; aa2_cutoff = d2 > aa2_cutoff ? d2 : aa2_cutoff; aan_cutoff = dn > aan_cutoff ? dn : aan_cutoff; return; } // END cal_aax_cutoff void update_aax_cutoff(double &aa1_cutoff, double &aa2_cutoff, double &aan_cutoff, int tolerance, int naa_stat_start_percent, int naa_stat[5][61][4], int NAA, double cluster_thd) { if (cluster_thd > 1.0) cluster_thd = 1.00; double aa1_t, aa2_t, aan_t; cal_aax_cutoff(aa1_t, aa2_t, aan_t, cluster_thd, tolerance, naa_stat_start_percent, naa_stat, NAA); if (aa1_t > aa1_cutoff) aa1_cutoff = aa1_t; if (aa2_t > aa2_cutoff) aa2_cutoff = aa2_t; if (aan_t > aan_cutoff) aan_cutoff = aan_t; return; } // END update_aax_cutoff void WorkingParam::ComputeRequiredBases( int NAA, int ss, const Options & option ) { // d: distance, fraction of errors; // e: number of errors; // g: length of the maximum gap; // m: word length; // n: sequence length; // alignment length = n - g + 1; // d = e / (n - g + 1); // e >= 1, so that, g <= n + 1 - 1/d // word count = (n - g - m + 1) - (e - 1)*m; // = (n - g - m + 1) - (d*(n - g + 1) - 1)*m // = (n - g + 1) - d*m*(n - g + 1) // = (n - g + 1)*(1 - d*m) // minimum word count is reached when g == n + 1 - 1/d // so, minimum word count = 1/d - m. // if g == band_width: word count = (n - band + 1)*(1 - d*m); if( options.useDistance ){ int band = options.band_width + 1; int invd = int( 1.0 / (options.distance_thd + 1E-9) ); int k = len_eff < invd ? len_eff : invd; int ks = len_eff - ss + 1; int kn = len_eff - NAA + 1; int ks2 = invd - ss; int kn2= invd - NAA; int ks3 = int((len_eff - band + 1.0)*(1.0 - options.distance_thd * ss)); int kn3 = int((len_eff - band + 1.0)*(1.0 - options.distance_thd * NAA)); //if( ks3 > ks2 ) ks2 = ks3; //if( kn3 > kn2 ) kn2 = kn3; required_aa1 = required_aas = (ks2 < ks ? ks2 : ks); required_aan = kn2 < kn ? kn2 : kn; if( required_aa1 <=0 ) required_aa1 = required_aas = 1; if( required_aan <=0 ) required_aan = 1; //required_aa1 = required_aas = required_aan = 0; return; } // (N-K)-K*(1-C)*N = C*K*N-(K-1)*N-K = (C*K-K+1)*N-K required_aa1 = (len_eff - ss) - int(ss * ceil( (1.0 - aa1_cutoff) * len_eff )); if( required_aa1 < 0 ) required_aa1 = 0; required_aas = required_aa1; required_aan = (len_eff - NAA) - int(NAA * ceil( (1.0 - aa1_cutoff) * len_eff )); //printf( "%i %i\n", required_aa1, required_aan ); if( required_aan < 0 ) required_aan = 0; int aa1_old = int (aa1_cutoff* (double) len_eff) - ss + 1; int aas_old = int (aas_cutoff* (double) len_eff); int aan_old = int (aan_cutoff* (double) len_eff); double thd = option.cluster_thd; //double rest = (len_eff - ss) / double(len_eff * ss); double rest = (len_eff - NAA) / double(len_eff * NAA); double thd0 = 1.0 - rest; double fnew = 0; double fold = 1; if( thd > thd0 ){ fnew = (thd - thd0) / rest; fold = 1.0 - fnew; } //printf( "%g %g %g\n", thd, thd0, fnew ); required_aa1 = (int)(fnew*required_aa1 + fold*aa1_old); required_aas = (int)(fnew*required_aas + fold*aas_old); required_aan = (int)(fnew*required_aan + fold*aan_old); } int WorkingBuffer::EncodeWords( Sequence *seq, int NAA, bool est ) { char *seqi = seq->data; int len = seq->size; // check_word_encodes int aan_no = len - NAA + 1; int i, j, i0, i1; int skip = 0; unsigned char k, k1; for (j=0; j= 4 ) { // here N is 4 i0 = (j-NAA+1 > 0) ? j-NAA+1 : 0; i1 = j < aan_no ? j : aan_no - 1; for (i=i0; i<=i1; i++) word_encodes[i]=-1; } } for (j=0; j=4) || (seqi[j1+1]>=4) || (seqi[j1+2]>=4) || (seqi[j1+3]>=4)) continue; //skip N c22 = seqi[j1]*NAA3 + seqi[j1+1]*NAA2 + seqi[j1+2]*NAA1 + seqi[j1+3]; taap[c22]++; } for (sk=0,mm=0; sk=4) || (seqi[j1+1]>=4) || (seqi[j1+2]>=4) || (seqi[j1+3]>=4)) continue; //skip N c22 = seqi[j1]*NAA3 + seqi[j1+1]*NAA2 + seqi[j1+2]*NAA1 + seqi[j1+3]; aap_list[aap_begin[c22]+taap[c22]++] =j1; } } void SequenceDB::ClusterOne( Sequence *seq, int id, WordTable & table, WorkingParam & param, WorkingBuffer & buffer, const Options & options ) { if (seq->state & IS_REDUNDANT) return; int frag_size = options.frag_size; int NAA = options.NAA; int len = seq->size; int len_bound = upper_bound_length_rep(len, options); param.len_upper_bound = len_bound; int flag = CheckOne( seq, table, param, buffer, options ); if( flag == 0 ){ if ((seq->identity>0) && (options.cluster_best)) { // because of the -g option, this seq is similar to seqs in old SEGs seq->state |= IS_REDUNDANT ; seq->Clear(); } else { // else add to NR90 db int aan_no = len - NAA + 1; int size = rep_seqs.size(); rep_seqs.Append( id ); seq->cluster_id = size; seq->identity = 0; seq->state |= IS_REP; if (frag_size){ /* not used for EST */ int frg1 = (len - NAA ) / frag_size + 1; table.AddWordCountsFrag( aan_no, buffer.word_encodes_backup, buffer.word_encodes_no, frg1, frag_size ); }else{ table.AddWordCounts(aan_no, buffer.word_encodes, buffer.word_encodes_no, table.sequences.size(), options.isEST); } table.sequences.Append( seq ); if( frag_size ){ while( table.sequences.size() < table.frag_count ) table.sequences.Append( seq ); } } } if ( (id+1) % 1000 == 0 ) { int size = rep_seqs.size(); printf( "." ); fflush( stdout ); if ( (id+1) % 10000 == 0 ) printf( "\r..........%9i finished %9i clusters\n", id+1, size ); } } #include size_t SequenceDB::MinimalMemory( int frag_no, int bsize, int T, const Options & options, size_t extra ) { int N = sequences.size(); int F = frag_no < MAX_TABLE_SEQ ? frag_no : MAX_TABLE_SEQ; size_t mem_need = 0; size_t mem, mega = 1000000; int table = T > 1 ? 2 : 1; printf( "\nApproximated minimal memory consumption:\n" ); mem = N*sizeof(Sequence) + total_desc + N + extra; if( options.store_disk == false ) mem += total_letter + N; printf( "%-16s: %zuM\n", "Sequence", mem/mega ); mem_need += mem; mem = bsize; printf( "%-16s: %i X %zuM = %zuM\n", "Buffer", T, mem/mega, T*mem/mega ); mem_need += T*mem; mem = F*(sizeof(Sequence*) + sizeof(IndexCount)) + NAAN*sizeof(NVector); printf( "%-16s: %i X %zuM = %zuM\n", "Table", table, mem/mega, table*mem/mega ); mem_need += table*mem; mem = sequences.capacity()*sizeof(Sequence*) + N*sizeof(int); mem += Comp_AAN_idx.size()*sizeof(int); printf( "%-16s: %zuM\n", "Miscellaneous", mem/mega ); mem_need += mem; printf( "%-16s: %zuM\n\n", "Total", mem_need/mega ); if(options.max_memory and options.max_memory < mem_need + 50*table ){ char msg[200]; sprintf( msg, "not enough memory, please set -M option greater than %zu\n", 50*table + mem_need/mega ); bomb_error(msg); } return mem_need; } size_t MemoryLimit( size_t mem_need, const Options & options ) { size_t mem_limit = (options.max_memory - mem_need) / sizeof(IndexCount); //printf( "Table limit with the given memory limit:\n" ); if( options.max_memory == 0 ){ mem_limit = options.max_entries; if( mem_limit > MAX_TABLE_SIZE ) mem_limit = MAX_TABLE_SIZE; } //printf( "Max number of representatives: %zu\n", mem_limit ); //printf( "Max number of word counting entries: %zu\n\n", mem_limit ); return mem_limit; } void Options::ComputeTableLimits( int min_len, int max_len, int typical_len, size_t mem_need ) { //liwz Fri Jan 15 15:44:47 PST 2016 //T=1 scale=1 //T=2 scale=0.6035 //T=4 scale=0.375 //T=8 scale=0.2392 //T=16 scale=0.1562 //T=32 scale=0.104 //T=64 scale=0.0703 double scale = 0.5/threads + 0.5/sqrt(threads); max_sequences = (size_t)(scale * MAX_TABLE_SEQ); max_entries = (size_t)(scale * (500*max_len + 500000*typical_len + 50000000)); if( max_memory ){ double frac = max_sequences / (double) max_entries; max_entries = (options.max_memory - mem_need) / sizeof(IndexCount); max_sequences = (size_t)(max_entries * frac); if( max_sequences < MAX_TABLE_SEQ / 100 ) max_sequences = MAX_TABLE_SEQ / 100; if( max_sequences > MAX_TABLE_SEQ ) max_sequences = MAX_TABLE_SEQ; } printf( "Table limit with the given memory limit:\n" ); printf( "Max number of representatives: %zu\n", max_sequences ); printf( "Max number of word counting entries: %zu\n\n", max_entries ); } void SequenceDB::DoClustering( int T, const Options & options ) { int i, j, k; int NAA = options.NAA; double aa1_cutoff = options.cluster_thd; double aas_cutoff = 1 - (1-options.cluster_thd)*4; double aan_cutoff = 1 - (1-options.cluster_thd)*options.NAA; int seq_no = sequences.size(); int frag_no = seq_no; int frag_size = options.frag_size; int len, len_bound; int flag; valarray letters(T); //printf( "%li\n", options.mem_limit ); if (frag_size){ frag_no = 0; for (i=0; isize - NAA) / frag_size + 1; } if( not options.isEST ) cal_aax_cutoff(aa1_cutoff, aas_cutoff, aan_cutoff, options.cluster_thd, options.tolerance, naa_stat_start_percent, naa_stat, NAA); Vector params(T); Vector buffers(T); for(i=0; i 1000 ){ // first SCB with small size max_items /= 8; max_seqs /= 8; } while( m < N && (sum*redundancy) < max_seqs && items < max_items ){ Sequence *seq = sequences[m]; if( ! (seq->state & IS_REDUNDANT) ){ if ( options.store_disk ) seq->SwapIn(); //items += seq->size; items += (size_t)(seq->size * redundancy); sum += 1; } m ++; } if( (m > i + 1E4) && (m > i + (N - i) / (2+T)) ) m = i + (N - i) / (2+T); if( m == i || m >= N ){ m = N; if( m > i + 1E3 ) m = i + (N - i) / (2+T); } //printf( "m = %i %i, %i\n", i, m, m-i ); printf( "\r# comparing sequences from %9i to %9i\n", i, m ); if( last_table.size ){ int print = (m-i)/20 + 1; #pragma omp parallel for schedule( dynamic, 1 ) for(int j=i; jstate & IS_REDUNDANT) continue; int tid = omp_get_thread_num(); CheckOne( seq, last_table, params[tid], buffers[tid], options ); if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); if( j%print==0 ){ printf( "." ); fflush( stdout ); } } int may_stop = 0; int self_stop = 0; float p0 = 0; int min = last_table.sequences[ last_table.sequences.size()-1 ]->size; int m0 = m; bool stop = false; #pragma omp parallel for schedule( dynamic, 1 ) for(int j=m-1; jstate & IS_REDUNDANT) continue; ClusterOne( seq, ks, word_table, params[tid], buffers[tid], options ); if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); if( may_stop and word_table.sequences.size() >= 100 ) break; if( word_table.size >= max_items ) break; int tmax = max_seqs - (frag_size ? seq->size / frag_size + 1 : 0); if( word_table.sequences.size() >= tmax ) break; } self_stop = 1; }else{ Sequence *seq = sequences[j]; if (seq->state & IS_REDUNDANT) continue; if ( options.store_disk ){ #pragma omp critical seq->SwapIn(); } int tid = omp_get_thread_num(); CheckOne( seq, last_table, params[tid], buffers[tid], options ); if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); if( min > params[tid].len_upper_bound ){ may_stop = 1; stop = true; #pragma omp flush (stop) } if( self_stop && tid ==1 ){ float p = (100.0*j)/N; if( p > p0+1E-1 ){ // print only if the percentage changed printf( "\r%4.1f%%", p ); fflush( stdout ); p0 = p; } } } } } } if( i == start || m == N ){ //printf( "comparing the first or last or very small group ...\n" ); fflush( stdout ); for(k=i; kstate & IS_REDUNDANT) ) sum += sequences[mm]->size; mm += 1; } if( mm < k + 1000 ) mm = k + 1000; if( mm > m ) mm = m; #pragma omp parallel for schedule( dynamic, 1 ) for(kk=k; kkstate & IS_REDUNDANT) continue; int tid = omp_get_thread_num(); CheckOne( seq, word_table, params[tid], buffers[tid], options ); if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); } bool bk = false; for(int ks=k; ksstate & IS_REDUNDANT) continue; ClusterOne( seq, ks, word_table, params[0], buffers[0], options ); bk = true; if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); if( word_table.size >= max_items ) break; int tmax = max_seqs - (frag_size ? seq->size / frag_size + 1 : 0); if( word_table.sequences.size() >= tmax ) break; bk = false; } if( bk ) break; } }else if( i < m ){ remaining = remaining/2 + (m - i); printf( "\r---------- %6i remaining sequences to the next cycle\n", m-i ); } printf( "---------- new table with %8i representatives\n", word_table.sequences.size() ); if( (last_table.size + word_table.size) > tabsize ) tabsize = last_table.size + word_table.size; last_table.Clear(); last_table.sequences.swap( word_table.sequences ); last_table.indexCounts.swap( word_table.indexCounts ); last_table.size = word_table.size; word_table.size = 0; } printf( "\n%9i finished %9i clusters\n", sequences.size(), rep_seqs.size() ); mem = (mem_need + tabsize*sizeof(IndexCount))/mega; printf( "\nApprixmated maximum memory consumption: %zuM\n", mem ); last_table.Clear(); word_table.Clear(); } int SequenceDB::CheckOne( Sequence *seq, WordTable & table, WorkingParam & param, WorkingBuffer & buf, const Options & options ) { int len = seq->size; param.len_upper_bound = upper_bound_length_rep(len, options); if( options.isEST ) return CheckOneEST( seq, table, param, buf, options ); return CheckOneAA( seq, table, param, buf, options ); } int SequenceDB::CheckOneAA( Sequence *seq, WordTable & table, WorkingParam & param, WorkingBuffer & buf, const Options & options ) { NVector & lookCounts = buf.lookCounts; NVector & indexMapping = buf.indexMapping; Vector & word_encodes_no = buf.word_encodes_no; Vector & aap_list = buf.aap_list; Vector & aap_begin = buf.aap_begin; Vector & word_encodes = buf.word_encodes; Vector & taap = buf.taap; double aa1_cutoff = param.aa1_cutoff; double aa2_cutoff = param.aas_cutoff; double aan_cutoff = param.aan_cutoff; char *seqi = seq->data; int j, k, j1, len = seq->size; int flag = 0; int frag_size = options.frag_size; int & aln_cover_flag = param.aln_cover_flag; int & required_aa1 = param.required_aa1; int & required_aa2 = param.required_aas; int & required_aan = param.required_aan; int & min_aln_lenS = param.min_aln_lenS; int & min_aln_lenL = param.min_aln_lenL; int NAA = options.NAA; int S = table.sequences.size(); int len_eff = len; if( S ){ int min = table.sequences[S-1]->size; if( min < len ){ if( len * options.diff_cutoff2 > min ) min = (int)(len * options.diff_cutoff2); if( (len - options.diff_cutoff_aa2) > min ) min = len - options.diff_cutoff_aa2; len_eff = min; } } //liwz 2016 01, seq is too short for the shortest (longer) seq in word_table to satisfy -aL option //longer seqeunce * -aL -band_width if ( S ) { int min = table.sequences[S-1]->size; int min_red = min * options.long_coverage - options.band_width; if (len < min_red) return 0; // return flag=0 } param.ControlShortCoverage( len_eff, options ); param.ComputeRequiredBases( options.NAA, 2, options ); buf.EncodeWords( seq, options.NAA, false ); // if minimal alignment length > len, return // I can not return earlier, because I need to calc the word_encodes etc if (options.min_control>len) return 0; // return flag=0 // lookup_aan int aan_no = len - options.NAA + 1; int M = frag_size ? table.frag_count : S; table.CountWords(aan_no, word_encodes, word_encodes_no, lookCounts, indexMapping, false, required_aan); // contained_in_old_lib() int len_upper_bound = param.len_upper_bound; int len_lower_bound = param.len_lower_bound; int band_left, band_right, best_score, band_width1, best_sum, len2, alnln, len_eff1; int tiden_no, band_center; float tiden_pc, distance=0; int talign_info[5]; int best1, sum; INTs *lookptr; char *seqj; int frg2 = frag_size ? (len - NAA + options.band_width ) / frag_size + 1 + 1 : 0; int lens; int has_aa2 = 0; IndexCount *ic = lookCounts.items; ic = lookCounts.items; for(; ic->count; ic++){ if( ! frag_size ){ indexMapping[ ic->index ] = 0; if ( ic->count < required_aan ) continue; } Sequence *rep = table.sequences[ ic->index ]; len2 = rep->size; if (len2 > len_upper_bound ) continue; if (options.has2D && len2 < len_lower_bound ) continue; if( frag_size ){ uint32_t *ims = & indexMapping[ ic->index ]; int count = ic->count; k = (len2 - NAA) / frag_size + 1; sum = 0; for (j1=0; j1 count) count = sum; } if ( count < required_aan ) continue; } param.ControlLongCoverage( len2, options ); if ( has_aa2 == 0 ) { // calculate AAP array buf.ComputeAAP( seqi, seq->size ); has_aa2 = 1; } seqj = rep->data; //NR_seq[NR90_idx[j]]; band_width1 = (options.band_width < len+len2-2 ) ? options.band_width : len+len2-2; diag_test_aapn(NAA1, seqj, len, len2, buf, best_sum, band_width1, band_left, band_center, band_right, required_aa1); if ( best_sum < required_aa2 ) continue; int rc = FAILED_FUNC; if (options.print || aln_cover_flag) //return overlap region rc = local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); else rc = local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); if ( rc == FAILED_FUNC ) continue; if ( tiden_no < required_aa1 ) continue; lens = len; if( options.has2D && len > len2 ) lens = len2; len_eff1 = (options.global_identity == 0) ? alnln : (lens - talign_info[4]); tiden_pc = tiden_no / (float) len_eff1; if( options.useDistance ){ if (distance > options.distance_thd ) continue; if (distance >= seq->distance) continue; // existing distance }else{ if (tiden_pc < options.cluster_thd) continue; if (tiden_pc <= seq->identity) continue; // existing iden_no } if (aln_cover_flag) { if ( talign_info[3]-talign_info[2]+1 < min_aln_lenL) continue; if ( talign_info[1]-talign_info[0]+1 < min_aln_lenS) continue; } if( options.has2D ) seq->state |= IS_REDUNDANT ; flag = 1; seq->identity = tiden_pc; seq->cluster_id = rep->cluster_id; seq->distance = distance; seq->coverage[0] = talign_info[0] +1; seq->coverage[1] = talign_info[1] +1; seq->coverage[2] = talign_info[2] +1; seq->coverage[3] = talign_info[3] +1; if (not options.cluster_best) break; update_aax_cutoff(aa1_cutoff, aa2_cutoff, aan_cutoff, options.tolerance, naa_stat_start_percent, naa_stat, NAA, tiden_pc); param.ComputeRequiredBases( options.NAA, 2, options ); } if( frag_size ) ic = lookCounts.items; while( ic->count ){ indexMapping[ ic->index ] = 0; ic += 1; } lookCounts.size = 0; if (flag == 1) { // if similar to old one delete it if (! options.cluster_best) { seq->Clear(); seq->state |= IS_REDUNDANT ; } } return flag; } int SequenceDB::CheckOneEST( Sequence *seq, WordTable & table, WorkingParam & param, WorkingBuffer & buf, const Options & options ) { NVector & lookCounts = buf.lookCounts; NVector & indexMapping = buf.indexMapping; Vector & word_encodes_no = buf.word_encodes_no; Vector & aap_list = buf.aap_list; Vector & aap_begin = buf.aap_begin; Vector & word_encodes = buf.word_encodes; Vector & taap = buf.taap; Vector & aan_list_comp = buf.aan_list_comp; char *seqi_comp = & buf.seqi_comp[0]; int & aln_cover_flag = param.aln_cover_flag; int & required_aa1 = param.required_aa1; int & required_aas = param.required_aas; int & required_aan = param.required_aan; int & min_aln_lenS = param.min_aln_lenS; int & min_aln_lenL = param.min_aln_lenL; char *seqi = seq->data; int j, len = seq->size; int flag = 0; int S = table.sequences.size(); int len_eff = len; if( S ){ int min = table.sequences[S-1]->size; if( min < len ){ if( len * options.diff_cutoff2 > min ) min = (int)(len * options.diff_cutoff2); if( (len - options.diff_cutoff_aa2) > min ) min = len - options.diff_cutoff_aa2; len_eff = min; } } //liwz 2016 01, seq is too short for the shortest (longer) seq in word_table to satisfy -aL option //longer seqeunce * -aL -band_width if ( S ) { int min = table.sequences[S-1]->size; int min_red = min * options.long_coverage - options.band_width; if (len < min_red) return 0; // return flag=0 } param.ControlShortCoverage( len_eff, options ); param.ComputeRequiredBases( options.NAA, 4, options ); int skip = buf.EncodeWords( seq, options.NAA, true ); required_aan -= skip; required_aas -= skip; required_aa1 -= skip; if( required_aan <= 0 ) required_aan = 1; if( required_aas <= 0 ) required_aas = 1; if( required_aa1 <= 0 ) required_aa1 = 1; // if minimal alignment length > len, return // I can not return earlier, because I need to calc the word_encodes etc if (options.min_control>len) return 0; // return flag=0 int aan_no = len - options.NAA + 1; // contained_in_old_lib() int len_upper_bound = param.len_upper_bound; int len_lower_bound = param.len_lower_bound; int band_left, band_right, best_score, band_width1, best_sum, len2, alnln, len_eff1; int tiden_no, band_center; float tiden_pc, distance=0; int talign_info[5]; int j0, comp, lens; char *seqj; for(comp=0; comp<2; comp++){ if( comp ){ for (j0=0; j0count; ic++){ indexMapping[ ic->index ] = 0; if ( ic->count < required_aan ) continue; Sequence *rep = table.sequences[ic->index]; len2 = rep->size; if (len2 > len_upper_bound ) continue; if (options.has2D && len2 < len_lower_bound ) continue; seqj = rep->data; param.ControlLongCoverage( len2, options ); if ( has_aas == 0 ) { // calculate AAP array buf.ComputeAAP2( seqi, seq->size ); has_aas = 1; } band_width1 = (options.band_width < len+len2-2 ) ? options.band_width : len+len2-2; diag_test_aapn_est(NAA1, seqj, len, len2, buf, best_sum, band_width1, band_left, band_center, band_right, required_aa1); if ( best_sum < required_aas ) continue; //if( comp and flag and (not options.cluster_best) and j > rep->cluster_id ) goto Break; int rc = FAILED_FUNC; if (options.print || aln_cover_flag){ //return overlap region rc = local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); if( comp ){ talign_info[0] = len - talign_info[0] - 1; talign_info[1] = len - talign_info[1] - 1; } }else{ //printf( "%5i %5i %5i %5i\n", band_width1, band_right-band_left, band_left, band_right ); rc = local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); } if ( rc == FAILED_FUNC ) continue; //printf( "%i %i %i\n", best_score, tiden_no, required_aa1 ); if ( tiden_no < required_aa1 ) continue; if ( options.is454 ){ if (talign_info[2] != talign_info[0]) continue; // same start if (talign_info[0] > 1) continue; // one mismatch allowed at beginning if ((len-talign_info[1]) > 2) continue; // one mismatch allowed at end } lens = len; if( options.has2D && len > len2 ) lens = len2; len_eff1 = (options.global_identity == 0) ? alnln : (lens - talign_info[4]); tiden_pc = tiden_no / (float)len_eff1; //printf( "%i %f\n", tiden_no, tiden_pc ); if( options.useDistance ){ if (distance > options.distance_thd ) continue; if (options.cluster_best and distance >= seq->distance) continue; // existing distance }else{ if (tiden_pc < options.cluster_thd) continue; if (options.cluster_best and tiden_pc < seq->identity) continue; // existing iden_no } if (aln_cover_flag) { if ( talign_info[3]-talign_info[2]+1 < min_aln_lenL) continue; if( comp ){ if ( talign_info[0]-talign_info[1]+1 < min_aln_lenS) continue; }else{ if ( talign_info[1]-talign_info[0]+1 < min_aln_lenS) continue; } } if( options.cluster_best and fabs(tiden_pc - seq->identity) < 1E-9 and rep->cluster_id >= seq->cluster_id ) continue; if( (not options.cluster_best) and flag !=0 and rep->cluster_id >= seq->cluster_id ) continue; flag = comp ? -1 : 1; seq->identity = tiden_pc; seq->distance = distance; seq->cluster_id = rep->cluster_id; seq->coverage[0] = talign_info[0] +1; seq->coverage[1] = talign_info[1] +1; seq->coverage[2] = talign_info[2] +1; seq->coverage[3] = talign_info[3] +1; if (not options.cluster_best) break; } while( ic->count ){ indexMapping[ ic->index ] = 0; ic += 1; } lookCounts.size = 0; if (not options.option_r ) break; } if ((flag == 1) || (flag == -1)) { // if similar to old one delete it if (! options.cluster_best) { seq->Clear(); seq->state |= IS_REDUNDANT ; } if( flag == -1 ) seq->state |= IS_MINUS_STRAND; else seq->state &= ~IS_MINUS_STRAND; } return flag; } void SequenceDB::ComputeDistance( const Options & options ) { int i, j, N = sequences.size(); int best_score, best_sum; int band_width1, band_left, band_center, band_right, required_aa1; int tiden_no, alnln; int talign_info[5]; float distance; WorkingBuffer buf( N, max_len, options ); Vector > dists( N, NVector(N) ); Sequence comseq( *sequences[0] ); for(i=0; idata; int len = seq->size; buf.EncodeWords( seq, options.NAA, false ); buf.ComputeAAP2( seqi, seq->size ); dists[i][i] = 0.0; if((i+1)%1000 ==0) printf( "%9i\n", (i+1) ); for(j=0; jdata; int len2 = rep->size; band_width1 = (options.band_width < len+len2-2 ) ? options.band_width : len+len2-2; diag_test_aapn_est(NAA1, seqj, len, len2, buf, best_sum, band_width1, band_left, band_center, band_right, 0); local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); dists[seq->index][rep->index] = dists[rep->index][seq->index] = distance; } if (not options.option_r ) break; comseq.index = seq->index; comseq.size = len; for(j=0; jdata[len-i-1]; seqi = comseq.data; buf.EncodeWords( &comseq, options.NAA, false ); buf.ComputeAAP2( seqi, seq->size ); for(j=0; jdata; int len2 = rep->size; band_width1 = (options.band_width < len+len2-2 ) ? options.band_width : len+len2-2; diag_test_aapn_est(NAA1, seqj, len, len2, buf, best_sum, band_width1, band_left, band_center, band_right, 0); local_band_align(seqi, seqj, len, len2, mat, best_score, tiden_no, alnln, distance, talign_info, band_left, band_center, band_right, buf); if( distance < dists[seq->index][rep->index] ) dists[seq->index][rep->index] = dists[rep->index][seq->index] = distance; } } std::string output = options.output + ".dist"; FILE *fout = fopen( output.c_str(), "w+" ); fprintf( fout, "1" ); for(i=1; i 1 ){ DoClustering( options.threads, options ); temp_files.Clear(); return; } if (frag_size){ frag_no = 0; for (i=0; isize - NAA) / frag_size + 1; } if( not options.isEST ) cal_aax_cutoff(aa1_cutoff, aas_cutoff, aan_cutoff, options.cluster_thd, options.tolerance, naa_stat_start_percent, naa_stat, NAA); WorkingParam param( aa1_cutoff, aas_cutoff, aan_cutoff ); WorkingBuffer buffer( frag_no, max_len, options ); WordTable word_table( options.NAA, NAAN ); size_t mem_need = MinimalMemory( frag_no, buffer.total_bytes, 1, options ); size_t mem_limit = MemoryLimit( mem_need, options ); size_t mem, mega = 1000000; int N = sequences.size(); size_t total_letters = total_letter; size_t tabsize = 0; Options opts( options ); opts.ComputeTableLimits( min_len, max_len, len_n50, mem_need ); for(i=0; istate & IS_REDUNDANT) ){ if ( options.store_disk ) seq->SwapIn(); items += (size_t)(seq->size * redundancy); sum += 1; } m ++; } if( m > N ) m = N; printf( "\rcomparing sequences from %9i to %9i\n", i, m ); fflush( stdout ); for(int ks=i; ksstate & IS_REDUNDANT) continue; ClusterOne( seq, ks, word_table, param, buffer, options ); total_letters -= seq->size; if( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); if( word_table.size >= max_items ) break; int tmax = max_seqs - (frag_size ? seq->size / frag_size + 1 : 0); if( word_table.sequences.size() >= tmax ) break; } m = i; if( word_table.size == 0 ) continue; float p0 = 0; for(int j=m; jstate & IS_REDUNDANT) continue; if ( options.store_disk ) seq->SwapIn(); CheckOne( seq, word_table, param, buffer, options ); total_letters -= seq->size; if ( options.store_disk && (seq->state & IS_REDUNDANT) ) seq->SwapOut(); int len_bound = param.len_upper_bound; if( word_table.sequences[ word_table.sequences.size()-1 ]->size > len_bound ){ break; } float p = (100.0*j)/N; if( p > p0+1E-1 ){ // print only if the percentage changed printf( "\r%4.1f%%", p ); fflush( stdout ); p0 = p; } } if( word_table.size > tabsize ) tabsize = word_table.size; //if( i && i < m ) printf( "\r---------- %6i remaining sequences to the next cycle\n", m-i ); word_table.Clear(); } printf( "\n%9i finished %9i clusters\n", sequences.size(), rep_seqs.size() ); mem = (mem_need + tabsize*sizeof(IndexCount))/mega; printf( "\nApprixmated maximum memory consumption: %liM\n", mem ); temp_files.Clear(); word_table.Clear(); #if 0 int zeros = 0; for(i=0; i word_encodes( MAX_SEQ ); Vector word_encodes_no( MAX_SEQ ); if( not options.isEST ){ cal_aax_cutoff(aa1_cutoff, aas_cutoff, aan_cutoff, options.cluster_thd, options.tolerance, naa_stat_start_percent, naa_stat, NAA); } int N = other.sequences.size(); int M = sequences.size(); int T = options.threads; valarray counts(T); Vector params(T); Vector buffers(T); WorkingParam & param = params[0]; WorkingBuffer & buffer = buffers[0]; for(i=0; i1 ) omp_set_num_threads(T); size_t mem_need = MinimalMemory( N, buffer.total_bytes, T, options, other.total_letter+other.total_desc ); size_t mem_limit = MemoryLimit( mem_need, options ); Options opts( options ); opts.ComputeTableLimits( min_len, max_len, len_n50, mem_need ); WordTable word_table( options.NAA, NAAN ); size_t max_items = opts.max_entries; size_t max_seqs = opts.max_sequences; for(i=0; istate & IS_REDUNDANT) ){ if ( options.store_disk ) seq->SwapIn(); items += seq->size; sum += 1; } m ++; } if( m > N ) m = N; //printf( "m = %i %i, %i\n", i, m, m-i ); for(int ks=i; kssize; seqi = seq->data; calc_ann_list(len, seqi, NAA, aan_no, word_encodes, word_encodes_no, options.isEST); word_table.AddWordCounts(aan_no, word_encodes, word_encodes_no, ks-i, options.isEST); word_table.sequences.Append( seq ); seq->cluster_id = ks; seq->state |= IS_REP; if ( (ks+1) % 1000 == 0 ) { printf( "." ); fflush( stdout ); if ( (ks+1) % 10000 == 0 ) printf( "%9i finished\n", ks+1 ); } } float p0 = 0; if( T > 1 ){ int JM = M; counts = 0; #pragma omp parallel for schedule( dynamic, 1 ) for(int j=0; jstate & IS_REDUNDANT ) continue; int len = seq->size; char *seqi = seq->data; int len_upper_bound = upper_bound_length_rep(len,options); int len_lower_bound = len - options.diff_cutoff_aa2; int len_tmp = (int) ( ((double)len) * options.diff_cutoff2); if (len_tmp < len_lower_bound) len_lower_bound = len_tmp; int tid = omp_get_thread_num(); params[tid].len_upper_bound = len_upper_bound; params[tid].len_lower_bound = len_lower_bound; if( word_table.sequences[ word_table.sequences.size()-1 ]->size > len_upper_bound ){ JM = 0; continue; } int flag = other.CheckOne( seq, word_table, params[tid], buffers[tid], options ); if ((flag == 1) || (flag == -1)) { // if similar to old one delete it if (! options.cluster_best) { seq->Clear(); seq->state |= IS_REDUNDANT ; counts[tid] ++; } if( flag == -1 ) seq->state |= IS_MINUS_STRAND; // for EST only } float p = (100.0*j)/M; if( p > p0+1E-1 ){ // print only if the percentage changed printf( "\r%4.1f%%", p ); fflush( stdout ); p0 = p; } } for(int j=0; jstate & IS_REDUNDANT ) continue; len = seq->size; seqi = seq->data; len_upper_bound = upper_bound_length_rep(len,options); len_lower_bound = len - options.diff_cutoff_aa2; len_tmp = (int) ( ((double)len) * options.diff_cutoff2); if (len_tmp < len_lower_bound) len_lower_bound = len_tmp; param.len_upper_bound = len_upper_bound; param.len_lower_bound = len_lower_bound; if( word_table.sequences[ word_table.sequences.size()-1 ]->size > len_upper_bound ){ break; } flag = other.CheckOne( seq, word_table, param, buffer, options ); if ((flag == 1) || (flag == -1)) { // if similar to old one delete it if (! options.cluster_best) { seq->Clear(); seq->state |= IS_REDUNDANT ; NR2_red_no ++; } if( flag == -1 ) seq->state |= IS_MINUS_STRAND; // for EST only } float p = (100.0*j)/M; if( p > p0+1E-1 ){ // print only if the percentage changed printf( "\r%4.1f%%", p ); fflush( stdout ); p0 = p; } } } printf( "\r..........%9i compared %9i clusters\n", i, NR2_red_no ); word_table.Clear(); word_table.size = 0; i = m; } if (options.cluster_best) {//delete redundant sequences in options.cluster_best mode for (i=0; i<(int)sequences.size(); i++){ Sequence *seq = sequences[i]; if (seq->identity > 0 ){ seq->state |= IS_REDUNDANT; NR2_red_no ++; } } } for (i=0; i<(int)sequences.size(); i++){ Sequence *seq = sequences[i]; if( seq->identity <0 ) seq->identity *= -1; if( not(seq->state & IS_REDUNDANT) ) rep_seqs.Append( i ); } cout << endl; cout << sequences.size() << " compared\t" << NR2_red_no << " clustered" << endl; temp_files.Clear(); } int calc_ann_list(int len, char *seqi, int NAA, int& aan_no, Vector & aan_list, Vector & aan_list_no, bool est) { int i, j, k, i0, i1, k1; // check_aan_list aan_no = len - NAA + 1; for (j=0; j= 4 ) { // here N is 4 i0 = (j-NAA+1 > 0) ? j-NAA+1 : 0; i1 = j < aan_no ? j : aan_no - 1; for (i=i0; i<=i1; i++) aan_list[i]=-1; } } } std::sort(aan_list.begin(), aan_list.begin() + aan_no); for(j=0; j &Comp_AAN_idx) { int i, j, k, icomp, k1; int c[4] = {3,2,1,0}; unsigned char short_word[32]; //short_word[12] is enough int NAA1 = NAAN_array[1]; int NAAN = NAAN_array[NAA]; for (i=0; i lo0) { mid = a[ ( lo0 + hi0 ) / 2 ]; while( lo <= hi ) { while( ( lo < hi0 ) && ( a[lo] < mid ) ) lo++; while( ( hi > lo0 ) && ( a[hi] > mid ) ) hi--; if( lo <= hi ) { tmp=a[lo]; a[lo]=a[hi]; a[hi]=tmp; tmp=idx[lo]; idx[lo]=idx[hi]; idx[hi]=tmp; lo++; hi--; } } // while if( lo0 < hi ) quick_sort_idx(a, idx, lo0, hi ); if( lo < hi0 ) quick_sort_idx(a, idx, lo, hi0 ); } // if ( hi0 > lo0) return 0; } // quick_sort_idx //decreasing can not use reverse of quick_sort_idx due to tie //quick_sort_idxr calling (a, idx, 0, no-1) //sort a with another array idx //so that idx rearranged int quick_sort_idxr (int *a, int *idx, int lo0, int hi0 ) { int lo = lo0; int hi = hi0; int mid; int tmp; if ( hi0 > lo0) { mid = a[ ( lo0 + hi0 ) / 2 ]; while( lo <= hi ) { while( ( lo < hi0 ) && ( a[lo] > mid ) ) lo++; while( ( hi > lo0 ) && ( a[hi] < mid ) ) hi--; if( lo <= hi ) { tmp=a[lo]; a[lo]=a[hi]; a[hi]=tmp; tmp=idx[lo]; idx[lo]=idx[hi]; idx[hi]=tmp; lo++; hi--; } } // while if( lo0 < hi ) quick_sort_idxr(a, idx, lo0, hi ); if( lo < hi0 ) quick_sort_idxr(a, idx, lo, hi0 ); } // if ( hi0 > lo0) return 0; } // quick_sort_idxr /////////////////////////// END ALL //////////////////////// int naa_stat_start_percent = 40; int naa_stat[5][61][4] = { // cover 0.99 { // N=5 N=4 N=3 N=2 { 0, 0, 0, 7, }, // 40% { 0, 0, 0, 8, }, // 41% { 0, 0, 0, 9, }, // 42% { 0, 0, 0, 9, }, // 43% { 0, 0, 1, 10, }, // 44% { 0, 0, 1, 11, }, // 45% { 0, 0, 1, 12, }, // 46% { 0, 0, 2, 13, }, // 47% { 0, 0, 2, 14, }, // 48% { 0, 0, 4, 16, }, // 49% { 0, 0, 4, 16, }, // 50% { 0, 0, 5, 17, }, // 51% { 0, 0, 5, 18, }, // 52% { 0, 0, 7, 20, }, // 53% { 0, 1, 7, 21, }, // 54% { 0, 1, 7, 21, }, // 55% { 0, 2, 8, 23, }, // 56% { 0, 2, 8, 25, }, // 57% { 0, 2, 10, 25, }, // 58% { 0, 3, 10, 26, }, // 59% { 0, 4, 13, 28, }, // 60% { 0, 5, 13, 30, }, // 61% { 0, 5, 14, 30, }, // 62% { 1, 6, 15, 33, }, // 63% { 2, 7, 17, 34, }, // 64% { 2, 7, 17, 35, }, // 65% { 2, 9, 20, 37, }, // 66% { 4, 10, 20, 37, }, // 67% { 4, 11, 22, 40, }, // 68% { 5, 12, 24, 41, }, // 69% { 5, 12, 25, 42, }, // 70% { 6, 16, 27, 43, }, // 71% { 8, 16, 27, 45, }, // 72% { 9, 17, 29, 47, }, // 73% { 10, 18, 31, 47, }, // 74% { 10, 20, 32, 50, }, // 75% { 12, 20, 32, 51, }, // 76% { 14, 22, 36, 54, }, // 77% { 15, 24, 37, 55, }, // 78% { 17, 26, 41, 58, }, // 79% { 18, 29, 41, 59, }, // 80% { 20, 30, 45, 60, }, // 81% { 24, 35, 48, 62, }, // 82% { 26, 36, 48, 64, }, // 83% { 27, 38, 51, 65, }, // 84% { 31, 43, 54, 68, }, // 85% { 35, 43, 55, 70, }, // 86% { 36, 48, 60, 71, }, // 87% { 36, 50, 61, 73, }, // 88% { 40, 50, 61, 75, }, // 89% { 45, 54, 65, 75, }, // 90% { 52, 60, 70, 79, }, // 91% { 53, 62, 71, 81, }, // 92% { 57, 66, 75, 84, }, // 93% { 57, 66, 76, 85, }, // 94% { 64, 71, 78, 85, }, // 95% { 70, 75, 82, 89, }, // 96% { 77, 81, 86, 92, }, // 97% { 82, 86, 90, 94, }, // 98% { 83, 87, 91, 95, }, // 99% { 91, 93, 95, 97, }, // 100% }, // cover 0.95 { // N=5 N=4 N=3 N=2 { 0, 0, 1, 9, }, // 40% { 0, 0, 2, 10, }, // 41% { 0, 0, 2, 11, }, // 42% { 0, 0, 3, 12, }, // 43% { 0, 0, 3, 12, }, // 44% { 0, 0, 4, 14, }, // 45% { 0, 0, 4, 14, }, // 46% { 0, 1, 5, 16, }, // 47% { 0, 1, 6, 17, }, // 48% { 0, 2, 7, 19, }, // 49% { 0, 2, 8, 19, }, // 50% { 0, 2, 8, 20, }, // 51% { 0, 2, 9, 21, }, // 52% { 0, 4, 10, 23, }, // 53% { 1, 4, 11, 24, }, // 54% { 1, 4, 11, 24, }, // 55% { 1, 5, 13, 26, }, // 56% { 2, 5, 13, 27, }, // 57% { 2, 6, 15, 29, }, // 58% { 2, 7, 15, 30, }, // 59% { 3, 8, 16, 31, }, // 60% { 4, 8, 18, 32, }, // 61% { 4, 9, 18, 33, }, // 62% { 5, 11, 20, 36, }, // 63% { 6, 12, 22, 37, }, // 64% { 6, 12, 22, 38, }, // 65% { 8, 14, 24, 40, }, // 66% { 8, 15, 25, 41, }, // 67% { 10, 16, 27, 42, }, // 68% { 10, 18, 28, 45, }, // 69% { 11, 18, 29, 45, }, // 70% { 14, 21, 31, 47, }, // 71% { 14, 22, 32, 48, }, // 72% { 14, 22, 33, 50, }, // 73% { 17, 24, 36, 52, }, // 74% { 17, 25, 36, 52, }, // 75% { 18, 27, 39, 54, }, // 76% { 20, 29, 41, 56, }, // 77% { 21, 31, 42, 58, }, // 78% { 21, 31, 46, 60, }, // 79% { 27, 35, 46, 60, }, // 80% { 28, 37, 50, 63, }, // 81% { 31, 38, 50, 64, }, // 82% { 34, 43, 53, 66, }, // 83% { 36, 45, 54, 67, }, // 84% { 41, 50, 60, 70, }, // 85% { 43, 51, 60, 71, }, // 86% { 45, 54, 63, 74, }, // 87% { 48, 55, 64, 75, }, // 88% { 54, 60, 68, 78, }, // 89% { 55, 62, 71, 80, }, // 90% { 56, 63, 71, 80, }, // 91% { 64, 70, 76, 84, }, // 92% { 69, 74, 80, 86, }, // 93% { 73, 78, 83, 88, }, // 94% { 74, 78, 84, 89, }, // 95% { 80, 84, 87, 91, }, // 96% { 83, 86, 90, 93, }, // 97% { 86, 89, 92, 95, }, // 98% { 91, 93, 95, 97, }, // 99% { 92, 93, 95, 97, }, // 100% }, // cover 0.9 { // N=5 N=4 N=3 N=2 { 0, 0, 2, 11, }, // 40% { 0, 0, 3, 12, }, // 41% { 0, 0, 3, 12, }, // 42% { 0, 1, 4, 13, }, // 43% { 0, 1, 5, 14, }, // 44% { 0, 1, 5, 15, }, // 45% { 0, 1, 6, 16, }, // 46% { 0, 2, 7, 18, }, // 47% { 0, 2, 7, 18, }, // 48% { 0, 3, 9, 20, }, // 49% { 1, 4, 9, 20, }, // 50% { 1, 4, 10, 21, }, // 51% { 1, 4, 11, 23, }, // 52% { 2, 5, 12, 24, }, // 53% { 2, 5, 12, 25, }, // 54% { 2, 6, 13, 26, }, // 55% { 3, 7, 14, 28, }, // 56% { 3, 7, 15, 28, }, // 57% { 4, 8, 16, 30, }, // 58% { 5, 9, 17, 31, }, // 59% { 5, 10, 18, 32, }, // 60% { 6, 11, 20, 35, }, // 61% { 6, 11, 20, 35, }, // 62% { 7, 13, 22, 38, }, // 63% { 8, 14, 23, 39, }, // 64% { 8, 15, 24, 39, }, // 65% { 10, 16, 26, 42, }, // 66% { 10, 17, 27, 42, }, // 67% { 12, 19, 29, 44, }, // 68% { 13, 20, 30, 46, }, // 69% { 13, 21, 31, 47, }, // 70% { 16, 23, 33, 48, }, // 71% { 18, 25, 34, 50, }, // 72% { 18, 26, 36, 51, }, // 73% { 19, 28, 38, 53, }, // 74% { 20, 29, 38, 53, }, // 75% { 23, 30, 41, 56, }, // 76% { 24, 33, 43, 57, }, // 77% { 26, 34, 45, 59, }, // 78% { 28, 37, 48, 61, }, // 79% { 30, 37, 48, 62, }, // 80% { 33, 42, 52, 64, }, // 81% { 35, 43, 53, 65, }, // 82% { 38, 47, 56, 68, }, // 83% { 40, 47, 56, 68, }, // 84% { 44, 53, 61, 71, }, // 85% { 45, 53, 62, 73, }, // 86% { 50, 58, 66, 75, }, // 87% { 51, 58, 66, 76, }, // 88% { 57, 63, 71, 79, }, // 89% { 60, 66, 72, 81, }, // 90% { 62, 68, 75, 83, }, // 91% { 70, 74, 80, 85, }, // 92% { 74, 78, 82, 88, }, // 93% { 85, 87, 90, 92, }, // 94% { 86, 88, 90, 92, }, // 95% { 87, 89, 91, 93, }, // 96% { 87, 89, 92, 94, }, // 97% { 89, 91, 93, 96, }, // 98% { 93, 94, 96, 97, }, // 99% { 94, 95, 97, 98, }, // 100% }, // cover 0.8 { // N=5 N=4 N=3 N=2 { 0, 1, 4, 13, }, // 40% { 0, 1, 5, 13, }, // 41% { 0, 1, 5, 14, }, // 42% { 0, 2, 6, 15, }, // 43% { 0, 2, 6, 16, }, // 44% { 0, 2, 7, 17, }, // 45% { 1, 3, 8, 18, }, // 46% { 1, 4, 9, 20, }, // 47% { 1, 4, 9, 20, }, // 48% { 2, 5, 11, 22, }, // 49% { 2, 5, 11, 22, }, // 50% { 2, 6, 12, 24, }, // 51% { 3, 6, 13, 25, }, // 52% { 3, 7, 14, 26, }, // 53% { 4, 8, 14, 27, }, // 54% { 4, 8, 15, 28, }, // 55% { 5, 9, 17, 30, }, // 56% { 5, 9, 17, 30, }, // 57% { 6, 11, 19, 32, }, // 58% { 7, 12, 20, 34, }, // 59% { 8, 12, 20, 34, }, // 60% { 9, 14, 22, 37, }, // 61% { 9, 14, 23, 37, }, // 62% { 10, 16, 25, 39, }, // 63% { 11, 17, 26, 41, }, // 64% { 12, 18, 27, 41, }, // 65% { 13, 20, 28, 43, }, // 66% { 14, 21, 30, 45, }, // 67% { 15, 22, 31, 46, }, // 68% { 17, 24, 33, 48, }, // 69% { 17, 24, 34, 48, }, // 70% { 19, 26, 36, 50, }, // 71% { 20, 27, 37, 51, }, // 72% { 21, 29, 39, 53, }, // 73% { 23, 31, 41, 55, }, // 74% { 23, 31, 41, 55, }, // 75% { 26, 34, 44, 58, }, // 76% { 28, 36, 46, 59, }, // 77% { 29, 37, 47, 60, }, // 78% { 34, 41, 50, 62, }, // 79% { 34, 42, 51, 63, }, // 80% { 38, 45, 55, 66, }, // 81% { 39, 46, 55, 67, }, // 82% { 44, 51, 60, 70, }, // 83% { 44, 51, 60, 70, }, // 84% { 49, 56, 64, 73, }, // 85% { 50, 57, 64, 74, }, // 86% { 57, 63, 69, 77, }, // 87% { 58, 64, 70, 78, }, // 88% { 68, 71, 76, 82, }, // 89% { 68, 72, 77, 83, }, // 90% { 75, 79, 81, 85, }, // 91% { 86, 87, 89, 90, }, // 92% { 88, 89, 90, 92, }, // 93% { 90, 91, 92, 93, }, // 94% { 91, 92, 93, 94, }, // 95% { 92, 94, 94, 95, }, // 96% { 93, 94, 95, 96, }, // 97% { 94, 95, 95, 96, }, // 98% { 94, 95, 96, 98, }, // 99% { 95, 96, 97, 98, }, // 100% }, // cover 0.6 { // N=5 N=4 N=3 N=2 { 1, 2, 6, 15, }, // 40% { 1, 3, 7, 16, }, // 41% { 1, 3, 8, 17, }, // 42% { 2, 4, 9, 18, }, // 43% { 2, 4, 9, 19, }, // 44% { 2, 5, 10, 20, }, // 45% { 3, 5, 10, 21, }, // 46% { 3, 6, 12, 22, }, // 47% { 3, 6, 12, 23, }, // 48% { 4, 8, 14, 25, }, // 49% { 4, 8, 14, 25, }, // 50% { 5, 8, 15, 26, }, // 51% { 5, 9, 16, 27, }, // 52% { 6, 10, 17, 29, }, // 53% { 6, 11, 18, 30, }, // 54% { 7, 11, 18, 31, }, // 55% { 8, 12, 20, 32, }, // 56% { 8, 13, 20, 33, }, // 57% { 10, 14, 22, 35, }, // 58% { 10, 15, 23, 37, }, // 59% { 11, 16, 24, 37, }, // 60% { 12, 18, 26, 39, }, // 61% { 13, 18, 26, 40, }, // 62% { 14, 20, 28, 42, }, // 63% { 16, 22, 30, 43, }, // 64% { 16, 22, 31, 44, }, // 65% { 17, 23, 32, 45, }, // 66% { 18, 25, 33, 47, }, // 67% { 19, 26, 35, 48, }, // 68% { 21, 27, 36, 50, }, // 69% { 22, 29, 37, 51, }, // 70% { 24, 30, 39, 52, }, // 71% { 25, 32, 41, 53, }, // 72% { 26, 33, 42, 55, }, // 73% { 29, 35, 44, 57, }, // 74% { 29, 36, 45, 57, }, // 75% { 32, 39, 48, 60, }, // 76% { 34, 41, 50, 61, }, // 77% { 36, 43, 51, 62, }, // 78% { 40, 46, 54, 65, }, // 79% { 40, 46, 54, 65, }, // 80% { 46, 52, 59, 68, }, // 81% { 46, 52, 60, 69, }, // 82% { 53, 59, 65, 73, }, // 83% { 54, 60, 66, 73, }, // 84% { 63, 67, 73, 78, }, // 85% { 68, 71, 75, 79, }, // 86% { 78, 80, 82, 85, }, // 87% { 79, 81, 83, 85, }, // 88% { 83, 85, 86, 87, }, // 89% { 85, 86, 87, 89, }, // 90% { 86, 88, 89, 90, }, // 91% { 88, 89, 90, 91, }, // 92% { 90, 90, 91, 92, }, // 93% { 91, 92, 92, 93, }, // 94% { 92, 93, 94, 94, }, // 95% { 94, 94, 95, 95, }, // 96% { 95, 95, 96, 96, }, // 97% { 95, 96, 97, 97, }, // 98% { 96, 96, 97, 98, }, // 99% { 97, 98, 98, 99, }, // 100% }, }; cdhit-4.6.8/cdhit-common.h000066400000000000000000000425511312257207200153660ustar00rootroot00000000000000// ============================================================================= // CD-HI/CD-HIT // // Cluster Database at High Identity Threshold // // CD-HIT clusters protein sequence database at high sequence identity threshold. // This program can remove the high sequence redundance efficiently. // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include #include #include #include #include #include #include #include #include #include #include #include #define CDHIT_VERSION "4.7" #ifndef MAX_SEQ #define MAX_SEQ 655360 #endif #define MAX_AA 23 #define MAX_NA 6 #define MAX_UAA 21 #define MAX_DIAG (MAX_SEQ<<1) // MAX_DIAG be twice of MAX_SEQ #define MAX_GAP MAX_SEQ // MAX_GAP <= MAX_SEQ #define MAX_DES 300000 #define MAX_LINE_SIZE 300000 #define MAX_FILE_NAME 1280 #define MAX_SEG 50 #define MAX_BIN_SWAP 2E9 #define MAX_TABLE_SIZE 50000000 #define CLOCK_TICKS 100 #define FAILED_FUNC 1 #define OK_FUNC 0 #define IS_REP 1 #define IS_REDUNDANT 2 #define IS_PROCESSED 16 #define IS_MINUS_STRAND 32 #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b)) typedef unsigned int UINT4; typedef unsigned short UINT2; #define LONG_SEQ //if the longset sequence is longer than 65535, I use INT4 #ifdef LONG_SEQ #define INTs UINT4 #else #define INTs UINT2 #endif using namespace std; // the parent containter must guarantee continuous memory allocation. // std::valarray could be used instead of std::vector. template class Vector : public vector { public: Vector() : vector(){} Vector( size_t size ) : vector( size ){} Vector( size_t size, const TYPE & deft ) : vector( size, deft ){} void Append( const TYPE & item ){ size_t n = this->size(); if( n + 1 >= this->capacity() ) this->reserve( n + n/5 + 1 ); this->push_back( item ); } int size()const{ return (int)vector::size(); } }; // for primitive types only template class NVector { public: TYPE *items; int size; int capacity; NVector(){ size = capacity = 0; items = NULL; } NVector( int n, const TYPE & v=TYPE() ){ size = capacity = 0; items = NULL; Resize( n, v ); } NVector( const NVector & other ){ size = capacity = 0; items = NULL; if( other.items ){ Resize( other.size ); memcpy( items, other.items, other.size * sizeof(TYPE) ); } } ~NVector(){ if( items ) free( items ); } int Size()const{ return size; } void Clear(){ if( items ) free( items ); size = capacity = 0; items = NULL; } void Resize( int n, const TYPE & value=TYPE() ){ if( n == size && capacity > 0 ) return; int i; // When resize() is called, probably this is the intended size, // and will not be changed frequently. if( n != capacity ){ capacity = n; items = (TYPE*)realloc( items, capacity*sizeof(TYPE) ); } for(i=size; i= capacity ){ capacity = size + size/5 + 1; items = (TYPE*)realloc( items, capacity*sizeof(TYPE) ); } items[size] = item; size ++; } TYPE& operator[]( const int i ){ //if( i <0 or i >= size ) printf( "out of range\n" ); return items[i]; } TYPE& operator[]( const int i )const{ //if( i <0 or i >= size ) printf( "out of range\n" ); return items[i]; } }; typedef NVector VectorInt; typedef Vector MatrixInt; typedef NVector VectorInt64; typedef Vector MatrixInt64; ////////// Class definition ////////// class ScoreMatrix { //Matrix private: public: int matrix[MAX_AA][MAX_AA]; int gap, ext_gap; ScoreMatrix(); void init(); void set_gap(int gap1, int ext_gap1); void set_matrix(int *mat1); void set_to_na(); void set_match( int score ); void set_mismatch( int score ); }; // END class ScoreMatrix typedef NVector VectorIntX; typedef Vector MatrixIntX; extern int NAA1 ; extern int NAA2 ; extern int NAA3 ; extern int NAA4 ; extern int NAA5 ; extern int NAA6 ; extern int NAA7 ; extern int NAA8 ; extern int NAA9 ; extern int NAA10; extern int NAA11; extern int NAA12; extern int NAAN_array[13]; void InitNAA( int max ); extern int naa_stat_start_percent; extern int naa_stat[5][61][4]; struct IndexCount { int index; int count; IndexCount( int i=0, int c=0 ){ index = i, count = c; } }; struct Sequence; class WordTable { private: public: Vector > indexCounts; // hold index and word counts of seqs Vector sequences; int NAA; // length of word int NAAN; // rows of table char is_aa; // aa is for prot size_t size; int frag_count; public: WordTable( int naa=0, int naan=0 ); void Init(int, int); void Clear(); void SetDNA(); int AddWordCounts( NVector & counts, Sequence *seq, bool skipN=false); int AddWordCountsFrag( NVector & counts, int frag, int frag_size, int repfrag ); int AddWordCounts(int aan_no, Vector & word_encodes, Vector & word_encodes_no, int idx, bool skipN=false); int AddWordCountsFrag( int aan_no, Vector & word_encodes, Vector & word_encodes_no, int frag, int frag_size ); int CountWords(int aan_no, Vector & aan_list, Vector & aan_list_no, NVector & lookCounts, NVector & indexMapping, bool est=false, int min=0); void PrintAll(); }; // END class INDEX_TBL struct Options { int NAA; int NAAN; int NAA_top_limit; size_t max_memory; // -M: 400,000,000 in bytes int min_length; // -l: 10 bases bool cluster_best; // -g: 0, the first; 1, the best bool global_identity; // -G: bool store_disk; // -B: int band_width; // -b: 20 double cluster_thd; // -c double distance_thd; // -D double diff_cutoff; // -s: 0.0 double diff_cutoff2; // -s2: 1.0 int diff_cutoff_aa; // -S: 999999 int diff_cutoff_aa2; // -S2: 0 int tolerance; // -t: 2 double long_coverage; // -aL: int long_control; // -AL: double short_coverage; // -aS: int short_control; // -AS: int min_control; // -A: double long_unmatch_per; // -uL double short_unmatch_per; // -uS int unmatch_len; // -U int max_indel; // -D int print; int des_len; int frag_size; int option_r; int threads; int PE_mode; // -P int trim_len; // -cx int trim_len_R2; // -cy int align_pos; // -ap for alignment position size_t max_entries; size_t max_sequences; size_t mem_limit; bool has2D; bool isEST; bool is454; bool useIdentity; bool useDistance; bool backupFile; string input; string input_pe; string input2; string input2_pe; string output; string output_pe; int sort_output; // -sc int sort_outputf; // -sf Options(){ backupFile = false; useIdentity = false; useDistance = false; has2D = false; isEST = false; is454 = false; NAA = 5; NAA_top_limit = 5; cluster_thd = 0.9; distance_thd = 0.0; max_memory = 800000000; min_length = 10; cluster_best = false; global_identity = true; store_disk = false; band_width = 20; diff_cutoff = 0.0; diff_cutoff2 = 1.0; diff_cutoff_aa = 99999999; diff_cutoff_aa2 = 0; tolerance = 2; long_coverage = 0.0; long_control = 99999999; short_coverage = 0.0; short_control = 99999999; long_unmatch_per = 1.0; short_unmatch_per = 1.0; unmatch_len = 99999999; min_control = 0; max_indel = 1; print = 0; option_r = 1; frag_size = 0; des_len = 20; threads = 1; PE_mode = 0; trim_len = 0; trim_len_R2 = 0; align_pos = 0; sort_output = 0; sort_outputf = 0; max_entries = 0; max_sequences = 1<<20; mem_limit = 100000000; }; bool SetOptionCommon( const char *flag, const char *value ); bool SetOption( const char *flag, const char *value ); bool SetOption2D( const char *flag, const char *value ); bool SetOptionEST( const char *flag, const char *value ); bool SetOptions( int argc, char *argv[], bool twodata=false, bool est=false ); void Validate(); void ComputeTableLimits( int min_len, int max_len, int typical_len, size_t mem_need ); void Print(); }; void bomb_error(const char *message); struct Sequence { // real sequence, if it is not stored swap file: char *data; // length of the sequence: int size; int bufsize; int size_R2; // size = size.R1 + size.R2 for back-to-back merged seq //uint32_t stats; // if swap != NULL, the sequence is stored in file. // swap is opened as temporary file, which will be deleted automatically // after the program is finished: FILE *swap; // stream offset of the sequence: int offset; // stream offset of the description string in the database: size_t des_begin, des_begin2; // total record length int tot_length, tot_length2; char *identifier; // index of the sequence in the original database: int index; short state; int cluster_id; float identity; float distance; int coverage[4]; Sequence(); Sequence( const Sequence & other ); Sequence( const Sequence & other, const Sequence & other2, int mode ); ~Sequence(); void Clear(); void operator=( const char *s ); void operator+=( const char *s ); void Resize( int n ); void Reserve( int n ); void Swap( Sequence & other ); int Format(); void ConvertBases(); void trim(int trim_len); void SwapIn(); void SwapOut(); void PrintInfo( int id, FILE *fout, const Options & options, char *buf ); }; struct WorkingParam { double aa1_cutoff; double aas_cutoff; /* or aa2 */ double aan_cutoff; int len_upper_bound; int len_lower_bound; WorkingParam( double a1=0, double a2=0, double an=0 ){ Set( a1, a2, an ); } void Set( double a1=0, double a2=0, double an=0 ){ aa1_cutoff = a1; aas_cutoff = a2; aan_cutoff = an; len_upper_bound = 0; len_lower_bound = 0; } int len_eff; int aln_cover_flag; int min_aln_lenS; int min_aln_lenL; int required_aa1; int required_aas; /* or aa2 */ int required_aan; void ControlShortCoverage( int len, const Options & option ); void ControlLongCoverage( int len, const Options & option ); void ComputeRequiredBases( int NAA, int ss, const Options & option ); }; //#define MAX_TABLE_SEQ (1<<22) #define MAX_TABLE_SEQ 4000000 enum { DP_BACK_NONE=0, DP_BACK_LEFT_TOP=1, DP_BACK_LEFT=2, DP_BACK_TOP=3 }; struct WorkingBuffer { Vector taap; Vector word_encodes; Vector word_encodes_backup; Vector word_encodes_no; Vector aap_list; Vector aap_begin; //Vector indexCounts; NVector lookCounts; NVector indexMapping; MatrixInt64 score_mat; MatrixInt back_mat; Vector diag_score; Vector diag_score2; Vector aan_list_comp; Vector seqi_comp; int total_bytes; WorkingBuffer( size_t frag=0, size_t maxlen=0, const Options & options=Options() ){ Set( frag, maxlen, options ); seqi_comp.resize( MAX_SEQ ); } void Set( size_t frag, size_t maxlen, const Options & options ){ bool est = options.isEST; size_t m = MAX_UAA*MAX_UAA; size_t max_len = maxlen; size_t band = max_len*max_len; if( est ) m = m * m; if( band > options.band_width ) band = options.band_width; taap.resize( m ); aap_list.resize( max_len ); aap_begin.resize( m ); //indexCounts.resize( max_len ); word_encodes.resize( max_len ); word_encodes_no.resize( max_len ); word_encodes_backup.resize( max_len ); /* each table can not contain more than MAX_TABLE_SEQ representatives or fragments! */ if( frag > MAX_TABLE_SEQ ) frag = MAX_TABLE_SEQ; lookCounts.Resize( frag + 2 ); indexMapping.Resize( frag + 2 ); diag_score.resize( MAX_DIAG ); diag_score2.resize( MAX_DIAG ); aan_list_comp.resize( max_len ); total_bytes = max_len; total_bytes += taap.size()*sizeof(int); total_bytes += word_encodes.size()*sizeof(int); total_bytes += word_encodes_backup.size()*sizeof(int); total_bytes += diag_score.size()*sizeof(int); total_bytes += diag_score2.size()*sizeof(int); total_bytes += aan_list_comp.size()*sizeof(int); total_bytes += word_encodes_no.size()*sizeof(INTs); total_bytes += aap_list.size()*sizeof(INTs); total_bytes += aap_begin.size()*sizeof(INTs); total_bytes += indexMapping.Size()*sizeof(uint32_t); //total_bytes += indexCounts.size()*sizeof(IndexCount); total_bytes += lookCounts.Size()*sizeof(IndexCount); total_bytes += max_len*(band*sizeof(int)+sizeof(VectorInt)); total_bytes += max_len*(band*sizeof(int)+sizeof(VectorInt64)); } int EncodeWords( Sequence *seq, int NA, bool est = false ); void ComputeAAP( const char *seqi, int size ); void ComputeAAP2( const char *seqi, int size ); }; extern Vector Comp_AAN_idx; extern ScoreMatrix mat; class SequenceDB { public: int NAAN; Vector sequences; Vector rep_seqs; long long total_letter; long long total_desc; size_t max_len; size_t min_len; size_t len_n50; void Clear(){ for(int i=0; i & aan_list, Vector & aan_list_no, bool est=false); float current_time(); //some functions from very old cd-hit int quick_sort_idx(int *a, int *idx, int lo0, int hi0 ); int quick_sort_idxr(int *a, int *idx, int lo0, int hi0 ); cdhit-4.6.8/cdhit-div.c++000066400000000000000000000046221312257207200147760ustar00rootroot00000000000000// ============================================================================= // CD-HIT // http://cd-hit.org/ // http://bioinformatics.burnham-inst.org/cd-hi // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // Modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include "cdhit-common.h" Options options; SequenceDB seq_db; //////////////////////////////////// MAIN ///////////////////////////////////// int main(int argc, char *argv[]) { string db_in; string db_out; int i, div = 1; float begin_time = current_time(); float end_time; // *********************************** parse command line and open file if (argc < 5) print_usage_div(argv[0]); for (i=1; i), seq_db.NAAN, sizeof(NVector) * seq_db.NAAN ); seq_db.Read( db_in.c_str(), options ); cout << "total seq: " << seq_db.sequences.size() << endl; seq_db.SortDivide( options ); printf( "writing new databases\n" ); seq_db.DivideSave( db_in.c_str(), db_out.c_str(), div, options ); end_time = current_time(); printf( "Total CPU time %.2f\n", end_time - begin_time ); cout << "program completed !" << endl << endl; return 0; } // END int main cdhit-4.6.8/cdhit-est-2d.c++000066400000000000000000000074561312257207200153220ustar00rootroot00000000000000// ============================================================================= // CD-HI-EST // http://cd-hit.org/ // Cluster Database at High Identity (EST version) // modified from CD-HI // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // Modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include "cdhit-common.h" #include "cdhit-utility.h" //over-write some defs in cd-hi.h for est version #undef MAX_UAA #define MAX_UAA 4 //over-write some defs in cd-hi-init.h for est version void setaa_to_na(); void make_comp_iseq(int len, char *iseq_comp, char *iseq); void make_comp_short_word_index(int NAA, int *NAAN_array, Vector & Comp_AAN_idx); Options options; SequenceDB seq_db; SequenceDB seq_db2; // next two control how if seqs in db2 is longer than reps in db1 // by deault, only seqs in db2 that are shorter than rep in db1 // are clustered to the rep in db1 //////////////////////////////////// MAIN ///////////////////////////////////// int main(int argc, char **argv) { string db_in; string db_in2; string db_out; string db_in_pe; string db_in2_pe; string db_out_pe; options.cluster_thd = 0.95; options.NAA = 10; options.NAAN = NAA8; seq_db.NAAN = NAA8; options.NAA_top_limit = 12; setaa_to_na(); mat.set_to_na(); //mat.set_gap(-6,-1); float begin_time = current_time(); float end_time; // *********************************** parse command line and open file if (argc < 7) print_usage_est_2d(argv[0]); if (options.SetOptions( argc, argv, true, true ) == 0) print_usage_est_2d(argv[0]); options.Validate(); db_in = options.input; db_in_pe = options.input_pe; db_in2 = options.input2; db_in2_pe = options.input2_pe; db_out = options.output; db_out_pe = options.output_pe; InitNAA( MAX_UAA ); options.NAAN = NAAN_array[options.NAA]; seq_db.NAAN = NAAN_array[options.NAA]; seq_db2.NAAN = NAAN_array[options.NAA]; if ( options.option_r ) { Comp_AAN_idx.resize( seq_db.NAAN ); make_comp_short_word_index(options.NAA, NAAN_array, Comp_AAN_idx); } if ( options.PE_mode ) {seq_db.Read( db_in.c_str(), db_in_pe.c_str(), options );} else {seq_db.Read( db_in.c_str(), options );} cout << "total seq in db1: " << seq_db.sequences.size() << endl; if ( options.PE_mode ) { seq_db2.Read( db_in2.c_str(), db_in2_pe.c_str(), options );} else { seq_db2.Read( db_in2.c_str(), options );} cout << "total seq in db2: " << seq_db2.sequences.size() << endl; seq_db.SortDivide( options ); seq_db2.SortDivide( options, false ); seq_db2.ClusterTo( seq_db, options ); cout << "writing non-redundant sequences from db2" << endl; seq_db2.WriteClusters( db_in2.c_str(), db_out.c_str(), options ); if ( options.PE_mode ) { seq_db2.WriteClusters( db_in2.c_str(), db_in2_pe.c_str(), db_out.c_str(), db_out_pe.c_str(), options ); } else { seq_db2.WriteClusters( db_in2.c_str(), db_out.c_str(), options ); } seq_db2.WriteExtra2D( seq_db, options ); cout << "program completed !" << endl << endl; end_time = current_time(); printf( "Total CPU time %.2f\n", end_time - begin_time ); return 0; } // END int main cdhit-4.6.8/cdhit-est.c++000066400000000000000000000060451312257207200150100ustar00rootroot00000000000000// ============================================================================= // CD-HI-EST // http://cd-hit.org/ // Cluster Database at High Identity (EST version) // modified from CD-HI // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // Modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include "cdhit-common.h" #include "cdhit-utility.h" //over-write some defs in cd-hi.h for est version #undef MAX_UAA #define MAX_UAA 4 //over-write some defs in cd-hi-init.h for est version void setaa_to_na(); void make_comp_short_word_index(int NAA, int *NAAN_array, Vector & Comp_AAN_idx); void make_comp_iseq(int len, char *iseq_comp, char *iseq); Options options; SequenceDB seq_db; //////////////////////////////////// MAIN ///////////////////////////////////// int main(int argc, char **argv) { string db_in; string db_out; string db_in_pe; string db_out_pe; options.cluster_thd = 0.95; options.NAA = 10; options.NAAN = NAA8; seq_db.NAAN = NAA8; options.NAA_top_limit = 12; setaa_to_na(); mat.set_to_na(); //mat.set_gap(-6,-1); float begin_time = current_time(); float end_time; // *********************************** parse command line and open file if (argc < 5) print_usage_est(argv[0]); if (options.SetOptions( argc, argv, false, true ) == 0) print_usage_est(argv[0]); options.Validate(); db_in = options.input; db_in_pe = options.input_pe; db_out = options.output; db_out_pe = options.output_pe; InitNAA( MAX_UAA ); seq_db.NAAN = NAAN_array[options.NAA]; if ( options.option_r ) { Comp_AAN_idx.resize( seq_db.NAAN ); make_comp_short_word_index(options.NAA, NAAN_array, Comp_AAN_idx); } if ( options.PE_mode ) {seq_db.Read( db_in.c_str(), db_in_pe.c_str(), options );} else {seq_db.Read( db_in.c_str(), options );} cout << "total seq: " << seq_db.sequences.size() << endl; seq_db.SortDivide( options ); seq_db.DoClustering( options ); printf( "writing new database\n" ); if ( options.PE_mode ) { seq_db.WriteClusters( db_in.c_str(), db_in_pe.c_str(), db_out.c_str(), db_out_pe.c_str(), options ); } else { seq_db.WriteClusters( db_in.c_str(), db_out.c_str(), options ); } // write a backup clstr file in case next step crashes seq_db.WriteExtra1D( options ); cout << "program completed !" << endl << endl; end_time = current_time(); printf( "Total CPU time %.2f\n", end_time - begin_time ); return 0; } cdhit-4.6.8/cdhit-utility.c++000066400000000000000000000401321312257207200157130ustar00rootroot00000000000000 #include #include #include"cdhit-common.h" using namespace std; // information char cd_hit_ver[] = "\t\t====== CD-HIT version " CDHIT_VERSION " (built on " __DATE__ ") ======"; char cd_hit_ref1[] = "\"CD-HIT: a fast program for clustering and comparing large sets of protein or nucleotide sequences\", Weizhong Li & Adam Godzik. Bioinformatics, (2006) 22:1658-1659"; char cd_hit_ref2[] = "\"CD-HIT: accelerated for clustering the next generation sequencing data\", Limin Fu, Beifang Niu, Zhengwei Zhu, Sitao Wu & Weizhong Li. Bioinformatics, (2012) 28:3150-3152"; char cd_hit_ref3[] = "\"Beifang Niu, Limin Fu, Shulei Sun and Weizhong Li. Artificial and natural duplicates in pyrosequencing reads of metagenomic data. BMC Bioinformatics (2010) 11:187"; // char contacts[] = " Questions, bugs, contact Limin Fu at l2fu@ucsd.edu, or Weizhong Li at liwz@sdsc.edu\n" " For updated versions and information, please visit: http://cd-hit.org\n\n" " cd-hit web server is also available from http://cd-hit.org\n\n" " If you find cd-hit useful, please kindly cite:\n\n"; char txt_option_i[] = "\tinput filename in fasta format, required\n"; char txt_option_j[] = "\tinput filename in fasta/fastq format for R2 reads if input are paired end (PE) files\n \ \t -i R1.fq -j R2.fq -o output_R1 -op output_R2 or\n \ \t -i R1.fa -j R2.fa -o output_R1 -op output_R2 \n"; char txt_option_i_2d[] = "\tinput filename for db1 in fasta format, required\n"; char txt_option_i2[] = "\tinput filename for db2 in fasta format, required\n"; char txt_option_j2[] = "\tinput filename in fasta/fastq format for R2 reads if input are paired end (PE) files\n \ \t -i db1-R1.fq -j db1-R2.fq -i2 db2-R1.fq -j2 db2-R2.fq -o output_R1 -op output_R2 or\n \ \t -i db1-R1.fa -j db1-R2.fa -i2 db2-R1.fq -j2 db2-R2.fq -o output_R1 -op output_R2 \n"; char txt_option_o[] = "\toutput filename, required\n"; char txt_option_op[] = "\toutput filename for R2 reads if input are paired end (PE) files\n"; char txt_option_c[] = "\tsequence identity threshold, default 0.9\n \ \tthis is the default cd-hit's \"global sequence identity\" calculated as:\n \ \tnumber of identical amino acids in alignment\n \ \tdivided by the full length of the shorter sequence\n"; char txt_option_G[] = "\tuse global sequence identity, default 1\n \ \tif set to 0, then use local sequence identity, calculated as :\n \ \tnumber of identical amino acids in alignment\n \ \tdivided by the length of the alignment\n \ \tNOTE!!! don't use -G 0 unless you use alignment coverage controls\n \ \tsee options -aL, -AL, -aS, -AS\n"; char txt_option_g[] = "\t1 or 0, default 0\n \ \tby cd-hit's default algorithm, a sequence is clustered to the first \n \ \tcluster that meet the threshold (fast cluster). If set to 1, the program\n \ \twill cluster it into the most similar cluster that meet the threshold\n \ \t(accurate but slow mode)\n \ \tbut either 1 or 0 won't change the representatives of final clusters\n"; char txt_option_b[] = "\tband_width of alignment, default 20\n"; char txt_option_M[] = "\tmemory limit (in MB) for the program, default 800; 0 for unlimitted;\n"; char txt_option_n[] = "\tword_length, default 5, see user's guide for choosing it\n"; char txt_option_n_est[] = "\tword_length, default 10, see user's guide for choosing it\n"; char txt_option_l[] = "\tlength of throw_away_sequences, default 10\n"; char txt_option_t[] = "\ttolerance for redundance, default 2\n"; char txt_option_T[] = "\tnumber of threads, default 1; with 0, all CPUs will be used\n"; char txt_option_d[] = "\tlength of description in .clstr file, default 20\n \ \tif set to 0, it takes the fasta defline and stops at first space\n"; char txt_option_s[] = "\tlength difference cutoff, default 0.0\n \ \tif set to 0.9, the shorter sequences need to be\n \ \tat least 90% length of the representative of the cluster\n"; char txt_option_S[] = "\tlength difference cutoff in amino acid, default 999999\n \ \tif set to 60, the length difference between the shorter sequences\n \ \tand the representative of the cluster can not be bigger than 60\n"; char txt_option_s2[] = "\tlength difference cutoff for db1, default 1.0\n \ \tby default, seqs in db1 >= seqs in db2 in a same cluster\n \ \tif set to 0.9, seqs in db1 may just >= 90% seqs in db2\n"; char txt_option_S2[] = "\tlength difference cutoff, default 0\n \ \tby default, seqs in db1 >= seqs in db2 in a same cluster\n \ \tif set to 60, seqs in db2 may 60aa longer than seqs in db1\n"; char txt_option_aL[] = "\talignment coverage for the longer sequence, default 0.0\n \ \tif set to 0.9, the alignment must covers 90% of the sequence\n"; char txt_option_AL[] = "\talignment coverage control for the longer sequence, default 99999999\n \ \tif set to 60, and the length of the sequence is 400,\n \ \tthen the alignment must be >= 340 (400-60) residues\n"; char txt_option_aS[] = "\talignment coverage for the shorter sequence, default 0.0\n \ \tif set to 0.9, the alignment must covers 90% of the sequence\n"; char txt_option_AS[] = "\talignment coverage control for the shorter sequence, default 99999999\n \ \tif set to 60, and the length of the sequence is 400,\n \ \tthen the alignment must be >= 340 (400-60) residues\n"; char txt_option_A[] = "\tminimal alignment coverage control for the both sequences, default 0\n \ \talignment must cover >= this value for both sequences \n"; char txt_option_B[] = "\t1 or 0, default 0, by default, sequences are stored in RAM\n \ \tif set to 1, sequence are stored on hard drive\n \ \t!! No longer supported !!\n"; char txt_option_P[] = "\tinput paired end (PE) reads, default 0, single file\n \ \tif set to 1, please use -i R1 -j R2 to input both PE files\n"; char txt_option_cx[] = "\tlength to keep after trimming the tail of sequence, default 0, not trimming\n \ \tif set to 50, the program only uses the first 50 letters of input sequence\n"; char txt_option_cy[] = "\tlength to keep after trimming the tail of R2 sequence, default 0, not trimming\n \ \tif set to 50, the program only uses the first 50 letters of input R2 sequence\n \ \te.g. -cx 100 -cy 80 for paired end reads\n"; char txt_option_ap[] = "\talignment position constrains, default 0, no constrain\n \ \tif set to 1, the program will force sequences to align at beginings\n \ \twhen set to 1, the program only does +/+ alignment\n"; char txt_option_uL[] = "\tmaximum unmatched percentage for the longer sequence, default 1.0\n \ \tif set to 0.1, the unmatched region (excluding leading and tailing gaps)\n \ \tmust not be more than 10% of the sequence\n"; char txt_option_uS[] = "\tmaximum unmatched percentage for the shorter sequence, default 1.0\n \ \tif set to 0.1, the unmatched region (excluding leading and tailing gaps)\n \ \tmust not be more than 10% of the sequence\n"; char txt_option_U[] = "\tmaximum unmatched length, default 99999999\n \ \tif set to 10, the unmatched region (excluding leading and tailing gaps)\n \ \tmust not be more than 10 bases\n"; char txt_option_p[] = "\t1 or 0, default 0\n \tif set to 1, print alignment overlap in .clstr file\n"; char txt_option_r[] = "\t1 or 0, default 1, by default do both +/+ & +/- alignments\n \ \tif set to 0, only +/+ strand alignment\n"; char txt_option_bak[] = "\twrite backup cluster file (1 or 0, default 0)\n"; char txt_option_sc[] = "\tsort clusters by size (number of sequences), default 0, output clusters by decreasing length\n \ \tif set to 1, output clusters by decreasing size\n"; char txt_option_sf[] = "\tsort fasta/fastq by cluster size (number of sequences), default 0, no sorting\n \ \tif set to 1, output sequences by decreasing cluster size\n"; char txt_option_mask[] = "\tmasking letters (e.g. -mask NX, to mask out both 'N' and 'X')\n"; char txt_option_match[] = "\tmatching score, default 2 (1 for T-U and N-N)\n"; char txt_option_match2[] = "\tmatching score, default 2\n"; char txt_option_mismatch[] = "\tmismatching score, default -2\n"; char txt_option_mismatch2[] = "\tmismatching score, default -1\n"; char txt_option_gap[] = "\tgap opening score, default -6\n"; char txt_option_gap2[] = "\tgap opening score, default -3\n"; char txt_option_gap_ext[] = "\tgap extension score, default -1\n"; int print_usage (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << " -i" << txt_option_i; cout << " -o" << txt_option_o; cout << " -c" << txt_option_c; cout << " -G" << txt_option_G; cout << " -b" << txt_option_b; cout << " -M" << txt_option_M; cout << " -T" << txt_option_T; cout << " -n" << txt_option_n; cout << " -l" << txt_option_l; cout << " -t" << txt_option_t; cout << " -d" << txt_option_d; cout << " -s" << txt_option_s; cout << " -S" << txt_option_S; cout << " -aL" << txt_option_aL; cout << " -AL" << txt_option_AL; cout << " -aS" << txt_option_aS; cout << " -AS" << txt_option_AS; cout << " -A" << txt_option_A; cout << " -uL" << txt_option_uL; cout << " -uS" << txt_option_uS; cout << " -U" << txt_option_U; cout << " -B" << txt_option_B; cout << " -p" << txt_option_p; cout << " -g" << txt_option_g; cout << " -sc"<< txt_option_sc; cout << " -sf"<< txt_option_sf; cout << " -bak" << txt_option_bak; cout << " -h\tprint this help\n\n"; cout << contacts; cout << " " << cd_hit_ref1 << "\n"; cout << " " << cd_hit_ref2 << "\n\n\n"; exit(1); } // END print_usage int print_usage_2d (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << " -i" << txt_option_i_2d; cout << " -i2"<< txt_option_i2; cout << " -o" << txt_option_o; cout << " -c" << txt_option_c; cout << " -G" << txt_option_G; cout << " -b" << txt_option_b; cout << " -M" << txt_option_M; cout << " -T" << txt_option_T; cout << " -n" << txt_option_n; cout << " -l" << txt_option_l; cout << " -t" << txt_option_t; cout << " -d" << txt_option_d; cout << " -s" << txt_option_s; cout << " -S" << txt_option_S; cout << " -s2" << txt_option_s2; cout << " -S2" << txt_option_S2; cout << " -aL" << txt_option_aL; cout << " -AL" << txt_option_AL; cout << " -aS" << txt_option_aS; cout << " -AS" << txt_option_AS; cout << " -A" << txt_option_A; cout << " -uL" << txt_option_uL; cout << " -uS" << txt_option_uS; cout << " -U" << txt_option_U; cout << " -B" << txt_option_B; cout << " -p" << txt_option_p; cout << " -g" << txt_option_g; cout << " -bak" << txt_option_bak; cout << " -h\tprint this help\n\n"; cout << " Questions, bugs, contact Weizhong Li at liwz@sdsc.edu\n\n"; cout << " If you find cd-hit useful, please kindly cite:\n\n"; cout << " " << cd_hit_ref1 << "\n"; cout << " " << cd_hit_ref2 << "\n\n\n"; exit(1); } // END print_usage_2d int print_usage_est (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << " -i" << txt_option_i; cout << " -j" << txt_option_j; cout << " -o" << txt_option_o; cout << " -op" << txt_option_op; cout << " -c" << txt_option_c; cout << " -G" << txt_option_G; cout << " -b" << txt_option_b; cout << " -M" << txt_option_M; cout << " -T" << txt_option_T; cout << " -n" << txt_option_n_est; cout << " -l" << txt_option_l; cout << " -d" << txt_option_d; cout << " -s" << txt_option_s; cout << " -S" << txt_option_S; cout << " -aL" << txt_option_aL; cout << " -AL" << txt_option_AL; cout << " -aS" << txt_option_aS; cout << " -AS" << txt_option_AS; cout << " -A" << txt_option_A; cout << " -uL" << txt_option_uL; cout << " -uS" << txt_option_uS; cout << " -U" << txt_option_U; cout << " -B" << txt_option_B; cout << " -P" << txt_option_P; cout << " -cx"<< txt_option_cx; cout << " -cy"<< txt_option_cy; cout << " -ap"<< txt_option_ap; cout << " -p" << txt_option_p; cout << " -g" << txt_option_g; cout << " -r" << txt_option_r; cout << " -mask" << txt_option_mask; cout << " -match" << txt_option_match; cout << " -mismatch" << txt_option_mismatch; cout << " -gap" << txt_option_gap; cout << " -gap-ext" << txt_option_gap_ext; cout << " -bak" << txt_option_bak; cout << " -sc"<< txt_option_sc; cout << " -sf"<< txt_option_sf; cout << " -h\tprint this help\n\n"; cout << contacts; cout << " " << cd_hit_ref1 << "\n"; cout << " " << cd_hit_ref2 << "\n\n\n"; exit(1); } // END print_usage_est int print_usage_est_2d (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << " -i" << txt_option_i_2d; cout << " -i2"<< txt_option_i2; cout << " -j, -j2"<< txt_option_j2; cout << " -o" << txt_option_o; cout << " -op" << txt_option_op; cout << " -c" << txt_option_c; cout << " -G" << txt_option_G; cout << " -b" << txt_option_b; cout << " -M" << txt_option_M; cout << " -T" << txt_option_T; cout << " -n" << txt_option_n_est; cout << " -l" << txt_option_l; cout << " -d" << txt_option_d; cout << " -s" << txt_option_s; cout << " -S" << txt_option_S; cout << " -s2" << txt_option_s2; cout << " -S2" << txt_option_S2; cout << " -aL" << txt_option_aL; cout << " -AL" << txt_option_AL; cout << " -aS" << txt_option_aS; cout << " -AS" << txt_option_AS; cout << " -A" << txt_option_A; cout << " -uL" << txt_option_uL; cout << " -uS" << txt_option_uS; cout << " -U" << txt_option_U; cout << " -B" << txt_option_B; cout << " -P" << txt_option_P; cout << " -cx"<< txt_option_cx; cout << " -cy"<< txt_option_cy; cout << " -p" << txt_option_p; cout << " -g" << txt_option_g; cout << " -r" << txt_option_r; cout << " -mask" << txt_option_mask; cout << " -match" << txt_option_match; cout << " -mismatch" << txt_option_mismatch; cout << " -gap" << txt_option_gap; cout << " -gap-ext" << txt_option_gap_ext; cout << " -bak" << txt_option_bak; cout << " -h\tprint this help\n\n"; cout << contacts; cout << " " << cd_hit_ref1 << "\n"; cout << " " << cd_hit_ref2 << "\n\n\n"; exit(1); } // END print_usage_est_2d int print_usage_div (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << "Options " << endl << endl; cout << " -i in_dbname, required" << endl; cout << " -o out_dbname, required" << endl; cout << " -div number of divide, required " << endl; // cout << " -dbmax max size of your db\n\n\n"; exit(1); } // END print_usage_div char mytxt_option_c[] = "\tsequence identity threshold, default 0.98\n \ \tthis is a \"global sequence identity\" calculated as :\n \ \tnumber of identical amino acids in alignment\n \ \tdivided by the full length of the shorter sequence + gaps\n"; char mytxt_option_b[] = "\tband_width of alignment, default 10\n"; char mytxt_option_n_est[] = "\tword_length, default 10, see user's guide for choosing it\n"; char mytxt_option_D[] = "\tmax size per indel, default 1\n"; int print_usage_454 (char *arg) { cout << cd_hit_ver << "\n\n" ; cout << "Usage: "<< arg << " [Options] \n\nOptions\n\n"; cout << " -i" << txt_option_i; cout << " -o" << txt_option_o; cout << " -c" << mytxt_option_c; cout << " -b" << mytxt_option_b; cout << " -M" << txt_option_M; cout << " -T" << txt_option_T; cout << " -n" << mytxt_option_n_est; cout << " -aL" << txt_option_aL; cout << " -AL" << txt_option_AL; cout << " -aS" << txt_option_aS; cout << " -AS" << txt_option_AS; cout << " -B" << txt_option_B; cout << " -g" << txt_option_g; cout << " -D" << mytxt_option_D; cout << " -match" << txt_option_match2; cout << " -mismatch" << txt_option_mismatch2; cout << " -gap" << txt_option_gap2; cout << " -gap-ext" << txt_option_gap_ext; cout << " -bak" << txt_option_bak; cout << " -h\tprint this help\n\n"; cout << " Questions, bugs, contact Weizhong Li at liwz@sdsc.edu\n\n"; cout << " If you find cd-hit useful, please kindly cite:\n\n"; cout << " " << cd_hit_ref1 << "\n"; cout << " " << cd_hit_ref2 << "\n"; cout << " " << cd_hit_ref3 << "\n\n\n"; exit(1); } float current_time() { return ((float)clock())/CLOCKS_PER_SEC; } cdhit-4.6.8/cdhit-utility.h000066400000000000000000000003051312257207200155700ustar00rootroot00000000000000 int print_usage (char *arg); int print_usage_2d (char *arg); int print_usage_est (char *arg); int print_usage_div (char *arg); int print_usage_est_2d (char *arg); int print_usage_454 (char *arg); cdhit-4.6.8/cdhit.c++000066400000000000000000000041171312257207200142150ustar00rootroot00000000000000// ============================================================================= // CD-HIT // http://cd-hit.org/ // http://bioinformatics.burnham-inst.org/cd-hi // // program written by // Weizhong Li // UCSD, San Diego Supercomputer Center // La Jolla, CA, 92093 // Email liwz@sdsc.edu // at // Adam Godzik's lab // The Burnham Institute // La Jolla, CA, 92037 // Email adam@burnham-inst.org // // Modified by: // Limin Fu // Center for Research in Biological Systems (CRBS), UCSD // La Jolla, CA, 92093 // Email: l2fu@ucsd.edu, fu@daovm.net // ============================================================================= #include "cdhit-common.h" Options options; SequenceDB seq_db; //////////////////////////////////// MAIN ///////////////////////////////////// int main(int argc, char *argv[]) { string db_in; string db_out; float begin_time = current_time(); float end_time; // *********************************** parse command line and open file if (argc < 5) print_usage(argv[0]); if (options.SetOptions( argc, argv ) == 0) print_usage(argv[0]); options.Validate(); db_in = options.input; db_out = options.output; InitNAA( MAX_UAA ); options.NAAN = NAAN_array[options.NAA]; seq_db.NAAN = NAAN_array[options.NAA]; //printf( "%i %i %i\n", sizeof(NVector), seq_db.NAAN, sizeof(NVector) * seq_db.NAAN ); seq_db.Read( db_in.c_str(), options ); cout << "total seq: " << seq_db.sequences.size() << endl; seq_db.SortDivide( options ); seq_db.DoClustering( options ); printf( "writing new database\n" ); seq_db.WriteClusters( db_in.c_str(), db_out.c_str(), options ); // write a backup clstr file in case next step crashes seq_db.WriteExtra1D( options ); cout << "program completed !" << endl << endl; end_time = current_time(); printf( "Total CPU time %.2f\n", end_time - begin_time ); return 0; } // END int main cdhit-4.6.8/clstr2tree.pl000077500000000000000000000016701312257207200152620ustar00rootroot00000000000000#!/usr/bin/perl $clstr = shift; $fr = shift; # for nr80.clstr $fr = 0.8 $fra = 1 - $fr; print "(\n"; open(TMP, $clstr) || die; my $ll; my $no = 0; my @ids = (); my $rep = ""; while($ll=) { if ($ll =~ /^>/) { if ($no) { if ($no ==1 ) { print "$rep:1.0,\n";} else { my @mms = (); foreach my $tid (@ids) { push(@mms, "$tid:$fra"); } my $mm = join(",\n", @mms); print "(\n$mm\n):$fr,\n"; } } $no = 0; @ids = (); $rep = ""; } else { my $tid= ""; if ($ll =~ /(aa|nt), >(.+)\.\.\./) { $tid=$2;} push(@ids,$tid); if ($ll =~ /\*/) {$rep = $tid;} $no++; } } if ($no) { if ($no ==1 ) { print "$rep:1.0\n";} else { my @mms = (); foreach my $tid (@ids) { push(@mms, "$tid:$fra"); } my $mm = join(",\n", @mms); print "(\n$mm\n):$fr\n"; } } close(TMP); print ");\n"; cdhit-4.6.8/clstr2txt.pl000077500000000000000000000022711312257207200151400ustar00rootroot00000000000000#!/usr/bin/perl my $no = 0; my $clstr_no = ""; my @this_cluster = (); print "id clstr clstr_size length clstr_rep clstr_iden clstr_cov\n"; while($ll = <>) { if ($ll =~ /^>/) { if ($no>0) { process_this_cluster(); } if ($ll =~ /^>Cluster (\d+)/) { $clstr_no = $1; } $no = 0; @this_cluster = (); } else { my ($id, $len, $rep, $iden); if ($ll =~ /\d+\t(\d+)[a-z]{2}, >(.+)\.\.\. \*/) { $len = $1; $id = $2; $rep = 1; $iden = 100; } elsif ($ll =~ /\d+\t(\d+)[a-z]{2}, >(.+)\.\.\./) { $len = $1; $id = $2; $rep = 0; $ll=~/(\d+%|\d+\.\d+%)$/; $iden = $1; } else { print STDERR "***********\n"; } push(@this_cluster, [($id, $len, $rep, $iden)]); $no++; } } if ($no>0) { process_this_cluster(); } sub process_this_cluster { my ($i, $j, $k); my @t = sort { ($b->[2] <=> $a->[2]) or ( $b->[1] <=> $a->[1]) } @this_cluster; my $longest = 0; foreach $i (@t) { $longest = $i->[1] if ($i->[2]); } foreach $i (@t) { my $cov = int ( $i->[1]/$longest * 100); print "$i->[0]\t$clstr_no\t$no\t$i->[1]\t$i->[2]\t$i->[3]\t$cov\%\n"; } } cdhit-4.6.8/clstr2xml.pl000077500000000000000000000106271312257207200151250ustar00rootroot00000000000000#!/usr/bin/perl #usage: clstr_xml.pl [-len|-size] level1.clstr [level2.clstr level3.clstr ...] #purpose: to create xml file from cd-hit or hierarchical cd-hit(h-cd-hit) results #example: # if nr90 from nr100 and nr80 from nr90, with nr90.clstr and nr80.clstr # use # clstr_xml.pl -len nr90.clstr nr80.clstr # to create an xml file my $n=@ARGV; my $option="-len"; if($n==0||($n==1&&$ARGV[0]=~/^-/)){print "Usage:\n\tclstr2xml.pl [-len|-size] input1.clstr [input2.clstr input3.clstr ...]\n";exit(0);} if($ARGV[0]=~/^-/){ $option=$ARGV[0];shift @ARGV; $n--; } my $topsize=0; my $totalsequence=0; for($ilevel=$n;$ilevel>0;$ilevel--){ open(TMP, $ARGV[$ilevel-1]) || die "Can not open file"; $readin = 0; my $gi = ""; my $clstr = ""; my $this_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { if ($readin and $key and $this_no>0 ) { $nextlevel=$ilevel-1; $childofgi{"$key##$ilevel"}=[$this_no,$key,@members]; if($ilevel>1){ foreach $k (@members){$parent{"$k##$nextlevel"}=$key;} $parent{"$key##$nextlevel"}=$key; } $size{"$key##$ilevel"}=$this_no; $totalsequence+=$this_no; if($ilevel<$n){ $totalsequence--; my $j=$ilevel; while(exists($parent{"$key##$j"})){ $key=$parent{"$key##$j"};$j++; $size{"$key##$j"}+=($this_no-1); } } } $key=""; $clstr=""; $this_no=0; @members=(); if($ilevel==$n){$topsize++;} } #>Cluster 10 #0 187aa, >BPHE_BURCE\1-187... at 1:187:9:195/96.79% #1 188aa, >Q7B113_9PSED\1-188... at 1:188:8:195/96.81% #2 195aa, >Q9AEY4_9PSED\19-213... * else { $readin = 1; #$clstr .= $ll; if ($ll =~ /\*/ and $ll =~ /\d+\t(\d+)[a-z]{2}, >(.+)\.\.\./ ) { $key = $2; $len{$key}=$1;} else{$ll =~ /\d+\t(\d+)[a-z]{2}, >(.+)\.\.\./; $gi=$2;push(@members,$gi);$len{$gi}=$1; $ll=~/(\d+%|\d+\.\d+%)$/;$identity{"$gi##$ilevel"}=$1; } $this_no++; } } close(TMP); #last group if ($readin and $key and $this_no>0 ) { $nextlevel=$ilevel-1; $childofgi{"$key##$ilevel"}=[$this_no,$key,@members]; if($ilevel>1){ foreach $k (@members){$parent{"$k##$nextlevel"}=$key;} $parent{"$key##$nextlevel"}=$key; } $size{"$key##$ilevel"}=$this_no; $totalsequence+=$this_no; if($ilevel<$n){ $totalsequence--; my $j=$ilevel; while(exists($parent{"$key##$j"})){ $key=$parent{"$key##$j"};$j++; $size{"$key##$j"}+=($this_no-1); } } }#end of last group } print < head my @allkeys; if($option eq "-len"){ @allkeys=sort {$len{substr($b,0,rindex($b,"##"))} <=> $len{substr($a,0,rindex($a,"##"))}} keys %childofgi; } elsif($option eq "-size"){ @allkeys=sort {$size{$b} <=> $size{$a}} keys %childofgi; } foreach $k (@allkeys){ printnode($k,$n); } print "\n"; exit(0); sub printnode{ my $ckey=shift; my $level=shift; my ($key,$keylevel)=split(/##/,$ckey); if($keylevel != $level){return;} my $space=" "x(3*($n-$level)); my $mspace="$space "; print "$space1){print "GroupNo=\"$childofgi{$ckey}->[0]\" ";} print "SequenceNo=\"$size{$ckey}\" Length=\"$len{$key}\""; my $nextlevel=$level-1; my $upperlevel=$level+1; my $identitykey="$key##$upperlevel"; if(exists($identity{$identitykey})){print " Identity=\"$identity{$identitykey}\"";} else{if($keylevel<$n){print " Identity=\"100%\"";}} print ">$key\n"; my @ids=@{$childofgi{$ckey}};shift @ids; if($option eq "-len"||$nextlevel==0){ @ids=sort {$len{$b} <=> $len{$a}} @ids; } elsif($option eq "-size"){ @ids=sort {$size{"$b##$nextlevel"} <=> $size{"$a##$nextlevel"}} @ids; } for(my $i=0;$i<$childofgi{$ckey}->[0];$i++){ if(!exists($childofgi{"$ids[$i]##$nextlevel"})) { print "$mspace$ids[$i]\n"; } else{ $newkey="$ids[$i]##$nextlevel"; printnode($newkey,$nextlevel); } } print "$space\n"; } cdhit-4.6.8/clstr_cut.pl000077500000000000000000000007201312257207200151660ustar00rootroot00000000000000#!/usr/bin/perl #keep only top $no proteins in cluster my $no_cutoff = shift; $no_cutoff or die "no number\n"; my $clstr= ""; my $no = 0; my $repout=1; while($ll=<>){ if ($ll =~ /^>/) { if ($no) { print $clstr; } $clstr = $ll; $no = 0; $repout=1; } else { if ($no < $no_cutoff-$repout or $ll =~ /\*$/) { if($ll=~/\*$/){$repout=0;} $clstr .= $ll; $no++; } } } if ($no) { print $clstr; } cdhit-4.6.8/clstr_list.pl000077500000000000000000000062721312257207200153560ustar00rootroot00000000000000#!/usr/bin/perl use Storable; use strict; #my $sort_by_what = shift; # $sort_by_what = "no" unless $sort_by_what; my $clstr_file = shift; my $store_file = shift; my %clstr = (); # an array of hashes for all the cluster my $rep_len = 0; my $rep_acc = ""; my @cur_sequences = (); # array of hashes for all sequences in a cluster my $ll = ""; my @record = (); open(TMP, $clstr_file) || die; while($ll = ) { # read .clstr files if ($ll =~ /^>/) { # the begin of a cluster if (scalar(@cur_sequences)) { # not the first cluster, therefore collect the information of last clstr #@cur_sequences = sort {$$b{"seq_len"} <=> $$a{"seq_len"}} @cur_sequences; @cur_sequences = sort {$$b[1] <=> $$a[1]} @cur_sequences; @record = ($rep_acc, $rep_len, 1, [@cur_sequences], ""); $clstr{$rep_acc} = [@record]; } @cur_sequences=(); } else { # the sequence line chop($ll); if ($ll =~ /^(\d+)\s+(\d+)(aa|nt),\s+>(.+)\.\.\./) { @record = ($4, $2, 0, [], ""); if ($ll =~ /\*$/) { # representative sequence or not $rep_acc = $record[0]; $rep_len = $record[1]; $record[4] = "100%"; } # elsif ($ll =~ / at (\d.+)$/ ) { elsif ($ll =~ / at (.+\d.+)$/ ) {# because cd-hit-est have strand info $record[4] = $1; } } push(@cur_sequences, [@record]); } } if (scalar(@cur_sequences)) { #@cur_sequences = sort {$$b{"seq_len"} <=> $$a{"seq_len"}} @cur_sequences; @cur_sequences = sort {$$b[1] <=> $$a[1]} @cur_sequences; @record = ($rep_acc, $rep_len, 1, [@cur_sequences], ""); $clstr{$rep_acc} = [@record]; } close(TMP); if (-e $store_file){ # already have a cluster file my %old_clstr = %{retrieve($store_file)}; foreach my $rep_acc (keys %clstr){ my $seqs = $clstr{$rep_acc}[3]; # $seqs a reference to the sequences; my $tmp_size = scalar(@{$seqs}); # how many sequences in a top level cluster, each sequence should be a representative sequence for lower level cluster #print "$rep_acc, $tmp_size\n"; my $i; for $i (0..($tmp_size-1)){ my $seq = $$seqs[$i]; if ($old_clstr{$$seq[0]}){ $clstr{$rep_acc}[3][$i][3] = [@{$old_clstr{$$seq[0]}[3]}]; $clstr{$rep_acc}[3][$i][2] = 1; } } } } store \%clstr, $store_file; #~ my $size = scalar(keys %clstr); #~ print "$size\n"; #~ my $acc = 'D8F4YGO02FSTQP|range|2:370|frame|2|len|123'; #~ my $temp = $clstr{$acc}[1]; #~ print "$temp\n"; #~ my $temp = scalar(@{$clstr{$acc}[3]}); #~ print "$temp\n"; #~ my $x; #~ for $x (@{$clstr{$acc}[3]} ){ #~ my $tmp_1 = scalar(@{$x->[3]}); #~ print "$x->[2], $x->[4], $x->[0], $x->[1], $tmp_1\n"; #~ } cdhit-4.6.8/clstr_list_sort.pl000077500000000000000000000021511312257207200164150ustar00rootroot00000000000000#!/usr/bin/perl use Storable; use strict; my $input_file = shift; my $output_file = shift; my $sort_by_what = shift; $sort_by_what = "no" unless $sort_by_what; my @clstr = values %{retrieve($input_file)}; if ($sort_by_what eq "no") { ### Added by liwz sort by No. sequences instead of No. nodes my %rep2size = (); my $clstr_no = scalar(@clstr); my ($i); for ($i=0; $i<$clstr_no; $i++){ my $node_size = 0; foreach my $seq1 (@{$clstr[$i][3]}) { if ($$seq1[2]) { # can be futher expanded foreach my $seq2(@{$$seq1[3]}) { if ($$seq2[2]) { $node_size += scalar(@{$$seq2[3]}); } else { $node_size++; } } } else { $node_size++; } } $rep2size{ $clstr[$i][0] } = $node_size; } ### END #@clstr = sort {scalar(@{$b->[3]}) <=> scalar(@{$a->[3]})} @clstr; @clstr = sort {$rep2size{$b->[0]} <=> $rep2size{$a->[0]}} @clstr; } elsif ($sort_by_what eq "len") { @clstr = sort {$b->[1] <=> $a->[1]} @clstr; } elsif ($sort_by_what eq "des") { @clstr = sort {$a->[0] cmp $b->[0]} @clstr; } store \@clstr, $output_file; cdhit-4.6.8/clstr_merge.pl000077500000000000000000000061771312257207200155060ustar00rootroot00000000000000#!/usr/bin/perl # the order of clusters need to be identical my ($master_clstr, @clstr) = @ARGV; my $clstr_file_no = $#clstr+1; my @fhs = (); my @div_reps = (); my @div_seqs = (); my @div_rep_no = (); for ($i=0; $i<$clstr_file_no; $i++) { $fh = "FH" . $i; open($fh, $clstr[$i]) || die "can not open $clstr[$i]"; $div_reps[$i] = ""; $div_seqs[$i] = ""; $div_rep_no[$i] = 0; } my $master_rep = ""; my $master_seq = ""; my $rep_no = 0; open(TMP, $master_clstr) || die "can not open $master_clstr"; while($ll = ) { if ($ll =~ /^>/) { if ($master_rep) { print $master_seq; foreach ($i=0; $i<$clstr_file_no; $i++) { $this_no = process_this($i, $master_rep, $rep_no); $rep_no += $this_no; } } $master_rep = ""; $master_seq = $ll; $rep_no = 0; } else { $master_seq .= $ll; $rep_no++; chop($ll); if ($ll =~ /\*$/) { $rep = ""; if ($ll =~ /(aa|nt), >(.+)\.\.\./) { $rep = $2; $master_rep = $rep; } else { die "format error $ll"; } } } } if ($master_rep) { print $master_seq; foreach ($i=0; $i<$clstr_file_no; $i++) { $this_no = process_this($i, $master_rep, $rep_no); $rep_no += $this_no; } } close(TMP); for ($i=0; $i<$clstr_file_no; $i++) { $fh = "FH" . $i; close($fh); } sub process_this { my ($i, $master_rep, $rep_no) = @_; my $ll; my ($j, $k); $fh = "FH" . $i; while($ll = <$fh>) { if ($ll =~ /^>/) { if ($div_reps[$i] eq $master_rep) { if ($div_rep_no[$i] > 1) { $j = $rep_no; my @lls = split(/\n/,$div_seqs[$i]); foreach $k (@lls) { next if ($k =~ /\*$/); $k =~ s/^\d+/$j/; print $k, "\n"; $j++; } } $div_reps[$i] = ""; $div_seqs[$i] = ""; my $t1 = $div_rep_no[$i]; $div_rep_no[$i] = 0; return ($t1-1); #return ($div_rep_no[$i]-1); } else { $div_reps[$i] = ""; $div_seqs[$i] = ""; $div_rep_no[$i] = 0; } } else { $div_seqs[$i] .= $ll; $div_rep_no[$i]++; chop($ll); if ($ll =~ /\*$/) { my $rep = ""; if ($ll =~ /(aa|nt), >(.+)\.\.\./) { $rep = $2; $div_reps[$i] = $rep; } else { die "format error $ll"; } } } } if ($div_reps[$i] eq $master_rep) { if ($div_rep_no[$i] > 1) { $j = $rep_no; my @lls = split(/\n/,$div_seqs[$i]); foreach $k (@lls) { next if ($k =~ /\*$/); $k =~ s/^\d+/$j/; print $k, "\n"; $j++; } } $div_reps[$i] = ""; $div_seqs[$i] = ""; my $t1 = $div_rep_no[$i]; $div_rep_no[$i] = 0; return ($t1-1); #return ($div_rep_no[$i]-1); } } cdhit-4.6.8/clstr_merge_noorder.pl000077500000000000000000000041621312257207200172260ustar00rootroot00000000000000#!/usr/bin/perl # order of clusters don't need to be the same # but then I have to read everything into memory my ($master_clstr, @clstr) = @ARGV; my $clstr_file_no = $#clstr+1; my %slave_clstr = (); foreach $file (@clstr) { my $rep = ""; my $no = ""; my @members = (); open(TC, $file) || die; while($ll=){ if ($ll =~ /^>/) { if ($no) { die "format error, no rep before cluster $ll" unless ($rep); if (not defined($slave_clstr{$rep})) { $slave_clstr{$rep}=[]; } push(@{$slave_clstr{$rep}}, @members); } $rep = ""; $no = ""; @members = (); } else { my $id = ""; if ($ll =~ /(aa|nt), >(.+)\.\.\./) { $id = $2; } else { die "format error at $ll\n"; } chop($ll); if ($ll =~ /\*$/) { $rep = $id; } else { push(@members, $ll); $no++; } } } if ($no) { die "format error, no rep before cluster $ll" unless ($rep); if (not defined($slave_clstr{$rep})) { $slave_clstr{$rep}=[]; } push(@{$slave_clstr{$rep}}, @members); } close(TC); } ########## my $master_rep = ""; my $master_seq = ""; my $rep_no = 0; open(TMP, $master_clstr) || die "can not open $master_clstr"; while($ll = ) { if ($ll =~ /^>/) { if ($master_rep) { print $master_seq; if (defined( $slave_clstr{$master_rep} )) { foreach $i (@{$slave_clstr{$master_rep}}) { $i =~ s/^\d+/$rep_no/; print $i, "\n"; $rep_no++; } } } $master_rep = ""; $master_seq = $ll; $rep_no = 0; } else { $master_seq .= $ll; $rep_no++; chop($ll); if ($ll =~ /\*$/) { if ($ll =~ /(aa|nt), >(.+)\.\.\./) { $master_rep = $2; } else { die "format error $ll"; } } } } if ($master_rep) { print $master_seq; if (defined( $slave_clstr{$master_rep} )) { foreach $i (@{$slave_clstr{$master_rep}}) { $i =~ s/^\d+/$rep_no/; print $i, "\n"; $rep_no++; } } } close(TMP); cdhit-4.6.8/clstr_quality_eval.pl000077500000000000000000000066111312257207200170770ustar00rootroot00000000000000#!/usr/bin/perl ## calculate the sensitivity and specificity of clusters ## if the input fasta file has pre-defined classification term ## such as COG, pfam, TAXID etc. ## these terms can be used as benchmark to calcuate ## the sensitivity and specificity of clustering ## sensitivity is the ratio of number of correct pairs in cd-hit to number of pairs in benchmark ## specificity is the ratio of number of correct pairs in cd-hit to number of all cd-hit pairs ## here a pair is a pair of seqs that in same cluster ## the fasta file defline should be ">id||term" ## for example: ">id1||COG00001"; my %pair_status = (); my %bench_clusters = (); my %cdhit_clusters = (); my %seqs = (); my $seq_idx = 0; my @clstr = (); my $readin = 0; my $i = 0; while($ll=<>) { if ($ll =~ /^>/) { if ($readin) { if (@clstr > 1) { #skip singleton $cdhit_clusters{$i} = [@clstr]; $i++; } } @clstr = (); } else { $readin=1; chop($ll); if ($ll =~ /(\d+)(aa|nt), >(.+)\.\.\./) { $id = $3; my ($seq_id, $ben_id) = split(/\|\|/, $id); if ($ben_id) { if (not defined($bench_clusters{$ben_id})) { $bench_clusters{$ben_id} = []; } push(@{$bench_clusters{$ben_id}},$seq_idx); } push(@clstr, $seq_idx); push(@seqs,$seq_id); $seq_idx++; } } } if ($readin) { if (@clstr > 1) { #skip singleton $cdhit_clusters{$i} = [@clstr]; $i++; } } #process pairs in cdhit my $total_cdhit_pairs=0; foreach my $family (keys %cdhit_clusters) { my @seqs = @{$cdhit_clusters{$family}}; @seqs = sort {$a <=> $b} @seqs; my $N = $#seqs+1; for ($i=0; $i<$N-1; $i++) { my $idi = $seqs[$i]; for ($j=$i+1; $j<$N; $j++){ my $idj = $seqs[$j]; $pair_status{"$idi|$idj"} = "C"; #cdhit pairs $total_cdhit_pairs++; } } } #process pairs in benchmark my $total_bench_pairs = 0; my $correct_pairs=0; foreach my $family (keys %bench_clusters) { my @seqs = @{$bench_clusters{$family}}; next unless (@seqs > 1); #skip singleton @seqs = sort {$a <=> $b} @seqs; my $N = $#seqs+1; for ($i=0; $i<$N-1; $i++) { my $idi = $seqs[$i]; for ($j=$i+1; $j<$N; $j++){ my $idj = $seqs[$j]; if (defined( $pair_status{"$idi|$idj"} )) { $correct_pairs++; $pair_status{"$idi|$idj"} = "T"; #True pair } else { $pair_status{"$idi|$idj"} = "B"; #bench pairs } $total_bench_pairs++; } } } my $sen = $correct_pairs / $total_bench_pairs; my $spe = $correct_pairs / $total_cdhit_pairs; print "Total benchmark pairs\t$total_bench_pairs\n"; print "Total cd-hit pairs\t$total_cdhit_pairs\n"; print "Total correct pairs\t$correct_pairs\n"; print "Sensitivity\t$sen\n"; print "Specificity\t $spe\n"; print "\n\nPairs in benchmark but not in cd-hit\n"; foreach $pair (keys %pair_status) { next unless ($pair_status{$pair} eq "B"); my ($idx1, $idx2) = split(/\|/,$pair); print "$seqs[$idx1]\t$seqs[$idx2]\n"; } print "\n\nPairs in cd-hit but not in benchmark\n"; foreach $pair (keys %pair_status) { next unless ($pair_status{$pair} eq "C"); my ($idx1, $idx2) = split(/\|/,$pair); print "$seqs[$idx1]\t$seqs[$idx2]\n"; } print "\n\nPairs in both cd-hit and benchmark\n"; foreach $pair (keys %pair_status) { next unless ($pair_status{$pair} eq "T"); my ($idx1, $idx2) = split(/\|/,$pair); print "$seqs[$idx1]\t$seqs[$idx2]\n"; } cdhit-4.6.8/clstr_quality_eval_by_link.pl000077500000000000000000000044371312257207200206120ustar00rootroot00000000000000#!/usr/bin/perl ## calculate the sensitivity and specificity of clusters ## if the input fasta file has pre-defined classification term ## such as COG, pfam, TAXID etc. ## these terms can be used as benchmark to calcuate ## the sensitivity and specificity of clustering ## sensitivity is the ratio of number of correct pairs in cd-hit to number of pairs in benchmark ## specificity is the ratio of number of correct pairs in cd-hit to number of all cd-hit pairs ## here a pair is a pair of seqs that in same cluster ## the fasta file defline should be ">id||term" ## such as ">id1||COG00001"; ## NOTE !!!!!!!!!! ## this script use independant link instead of pair ## for example ## if a cluster has 8 sequences, it has 28 pairs, but only 7 pairs are independant ## these 7 pairs are independ links my %bench_clusters = (); my $total_bench_links = 0; my $total_cdhit_links = 0; my $correct_links = 0; my %clstr_by_ben = (); my $t_no = 0; my $readin = 0; while($ll=<>) { if ($ll =~ /^>/) { if ($readin) { if ($t_no > 1) { foreach my $ben_id (keys %clstr_by_ben) { $correct_links += $clstr_by_ben{$ben_id}-1; } $total_cdhit_links += $t_no-1; } } $t_no = 0; %clstr_by_ben = (); } else { $readin=1; chop($ll); if ($ll =~ /(\d+)(aa|nt), >(.+)\.\.\./) { $id = $3; my ($seq_id, $ben_id) = split(/\|\|/, $id); if ($ben_id) { if (not defined($bench_clusters{$ben_id})) { $bench_clusters{$ben_id} = []; } push(@{$bench_clusters{$ben_id}},$seq_id); $clstr_by_ben{$ben_id}++; $t_no++ ; } } } } if ($t_no > 1) { foreach my $ben_id (keys %clstr_by_ben) { $correct_links += $clstr_by_ben{$ben_id}-1; } $total_cdhit_links += $t_no-1; } #process links in benchmark foreach my $family (keys %bench_clusters) { my @seqs = @{$bench_clusters{$family}}; my $N = $#seqs+1; $total_bench_links += $N-1; #print "$family $N\n"; } my $sen = $correct_links / $total_bench_links; my $spe = $correct_links / $total_cdhit_links; print "Total benchmark links\t$total_bench_links\n"; print "Total cd-hit links\t$total_cdhit_links\n"; print "Total correct links\t$correct_links\n"; print "Sensitivity\t$sen\n"; print "Specificity\t $spe\n"; cdhit-4.6.8/clstr_reduce.pl000077500000000000000000000017501312257207200156460ustar00rootroot00000000000000#!/usr/bin/perl $file90 = shift; $segs = shift; $reduce_rate = shift; @clstr_nos = (); @segs = split(/,/, $segs); @segs_no = (); @no2seg_idx = (); for ($i=0; $i<@segs; $i++) { $seg = $segs[$i]; if ($seg =~ /-/) { ($b, $e) = split(/-/, $seg); } else { $b= $e = $seg; } for($j=$b; $j<=$e; $j++) { $no2seg_idx[$j]=$i; } $segs_no[$i] = 0; } open(TMP, $file90) || die "Can not open file"; $readin = 0; $this_no = 0; $this_clstr = ""; $ll; while($ll=) { if ($ll =~ /^>/ ) { if ($readin) { $this_seg = $no2seg_idx[$this_no]; if (($segs_no[$this_seg] % $reduce_rate) == 0) { print $this_clstr; } $segs_no[$this_seg]++; } $this_no=0; $this_clstr = $ll; } else { $this_clstr .= $ll; $readin = 1; $this_no++; } } close(TMP); if ($readin) { $this_seg = $no2seg_idx[$this_no]; if (($segs_no[$this_seg] % $reduce_rate) == 0) { print $this_clstr; } $segs_no[$this_seg]++; } cdhit-4.6.8/clstr_renumber.pl000077500000000000000000000003041312257207200162100ustar00rootroot00000000000000#!/usr/bin/perl $no = 0; while($ll=<>){ if ($ll =~ /^>Cluster (\d+)/) { print ">Cluster $no\n"; $no++; $cno = 0; } else { $ll =~ s/^\d+/$cno/; print $ll; $cno++; } } cdhit-4.6.8/clstr_rep.pl000077500000000000000000000010521312257207200151600ustar00rootroot00000000000000#!/usr/bin/perl $rep = ""; $no = 0; while($ll=<>){ if ($ll =~ /^>/) { if ($no) { print "$cid\t$rep\t$no\n"; } $cid = ""; if ($ll =~ /^>Cluster (\d+)/) {$cid = $1;} elsif ($ll =~ /^>Clstr (\d+)/) {$cid = $1;} else {die "format error $ll"} $rep = ""; $no = 0; } else { if ($ll =~ /\*$/) { $rep = ""; if ($ll =~ /aa, >(.+)\.\.\./) { $rep = $1; } else { die "format error $ll"; } } $no++; } } if ($no) { print "$cid\t$rep\t$no\n"; } cdhit-4.6.8/clstr_reps_faa_rev.pl000077500000000000000000000022101312257207200170230ustar00rootroot00000000000000#!/usr/bin/perl # output single fasta file # for each cluster output at least $cutoff seqs $clstr_file = shift; $fasta_file = shift; $cutoff = shift; die "" unless ((-e $clstr_file) and (-e $fasta_file) and ($cutoff>0)); my ($i, $j, $k, $cmd); my %rep_ids = (); #rep_ids to be skipped open(TMP, $clstr_file) || die "Can not open file"; my @gis = (); my $clstr_id = ""; while(my $ll=) { if ($ll =~ /^>/ ) { if (@gis) { my $no = $#gis+1; for ($i=$cutoff; $i<$no; $i++) { $rep_ids{$gis[$i]}=1; } } @gis = (); } else { chop($ll); if ($ll =~ />(.+)\.\.\./ ) { my $id = $1; if ($ll =~ /\*$/) { unshift(@gis, $id);} else { push(@gis, $id);} } } } if (@gis) { my $no = $#gis+1; for ($i=$cutoff; $i<$no; $i++) { $rep_ids{$gis[$i]}=1; } } close(TMP); ######################################################### my $flag = 0; open(TMP, $fasta_file) || die; while($ll = ) { chomp($ll);$ll=~s/\r$//; if ($ll =~ /^>/) { $gi = substr($ll,1); $gi =~ s/\s.+$//; $flag = ($rep_ids{$gi}) ? 0 : 1; } if ($flag) {print "$ll\n";} } close(TMP); cdhit-4.6.8/clstr_rev.pl000077500000000000000000000031241312257207200151700ustar00rootroot00000000000000#!/usr/bin/perl # if nr90 from nr100 and # nr80 from nr90, so I have nr90.clstr and nr80.clstr # but, in nr80.clstr, some gi numbers whose from nr100 are there # use this script, I create a new nr80new.clstr, as it is clustered from nr100 $file90 = shift; $file80 = shift; my %gi2clstr = (); open(TMP, $file90) || die "Can not open file"; $readin = 0; my $gi = ""; my $clstr = ""; my $this_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { if ($readin and $gi and $this_no>1 ) { $gi2clstr{$gi} = $clstr; } $gi=""; $clstr=""; $this_no=0; } else { $readin = 1; $clstr .= $ll; if ($ll =~ /\*/ and $ll =~ />(.+)\.\.\./ ) { $gi = $1; } $this_no++; } } close(TMP); if ($readin and $gi and $this_no>1 ) { $gi2clstr{$gi} = $clstr; } my $no = 0; open(TMP, $file80) || die "Can not open file"; while( $ll = ) { if ($ll =~ /^>/ ) { print $ll; $no = 0; } elsif ($ll =~ />(.+)\.\.\./ ) { $gi = $1; chop($ll); $rep = ( $ll =~ /\*$/) ? 1 : 0; $iden = ""; if ($ll =~ / at (.+)$/) { $iden = $1; } else { $iden = "100%"; } if ( $gi2clstr{$gi} ) { $aa = $gi2clstr{$gi}; @aa = split(/\n/, $aa); foreach $a (@aa) { $a =~ s/^\d+/$no/; if (not $rep) { if ($a =~ /\*$/) { $a =~ s/\*/at $iden/; } else { $a =~ s/at (.+)$/at $iden,$1/; } } print "$a\n"; $no++; } } else { $ll =~ s/^\d+/$no/; print "$ll\n"; $no++; } } else { print $ll; } } close(TMP); cdhit-4.6.8/clstr_select.pl000077500000000000000000000006031312257207200156520ustar00rootroot00000000000000#!/usr/bin/perl #my $by = shift; my $min; my $max; #if ($by eq "size") { $min = shift; $max = shift; #} $no = 0; $clstr = ""; while($ll=<>){ if ($ll =~ /^>/) { if (($no >= $min) and ($no <= $max)) { print $clstr; } $clstr = $ll; $no = 0; } else { $clstr .= $ll; $no++; } } if (($no >= $min) and ($no <= $max)) { print $clstr; } cdhit-4.6.8/clstr_select_rep.pl000077500000000000000000000010531312257207200165200ustar00rootroot00000000000000#!/usr/bin/perl #my $by = shift; my $min; my $max; #if ($by eq "size") { $min = shift; $max = shift; #} $rep = ""; $no = 0; while($ll=<>){ if ($ll =~ /^>/) { if (($no >= $min) and ($no <= $max)) { print "$rep\n"; } $rep = ""; $no = 0; } else { chop($ll); if ($ll =~ /\*$/) { $rep = ""; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $rep = $2; } else { die "format error $ll"; } } $no++; } } if (($no >= $min) and ($no <= $max)) { print "$rep\n"; } cdhit-4.6.8/clstr_size_histogram.pl000077500000000000000000000014131312257207200174220ustar00rootroot00000000000000#!/usr/bin/perl if(@ARGV==0){ print "Usage:\n\tclstr_size_histogram.pl [-bin N] clstr_file\n"; exit(1); } #$file90 = shift; $step = 100; if($ARGV[0] eq "-bin"){$step=$ARGV[1];$file90=$ARGV[2];} else{$file90=$ARGV[0];} my @clstr_nos = (); open(TMP, $file90) || die "Can not open file"; $readin = 0; my $this_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { $this_no = int ( ($this_no-1) / $step); if ($readin) { $clstr_nos[$this_no]++; } $this_no=0; } else { $readin = 1; $this_no++; } } close(TMP); $this_no = int ( ($this_no-1) / $step); $clstr_nos[$this_no]++; print "bin_size\tNo_of_clusters\n"; for ($i=0; $i<@clstr_nos; $i++) { if(!$clstr_nos[$i]){$clstr_nos[$i]=0;} print $i*$step+1, "-", $i*$step+$step,"\t$clstr_nos[$i]\n"; } cdhit-4.6.8/clstr_size_stat.pl000077500000000000000000000013251312257207200164020ustar00rootroot00000000000000#!/usr/bin/perl if(@ARGV==0){ print "Usage:\n\tclstr_size_stat.pl clstr_file\n"; exit(1); } $file90 = shift; my @clstr_nos = (); my $max_size = 0; open(TMP, $file90) || die "Can not open file"; $readin = 0; my $this_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { if ($readin) { $clstr_nos[$this_no]++; if ($this_no > $max_size) {$max_size=$this_no;} } $this_no=0; } else { $readin = 1; $this_no++; } } close(TMP); $clstr_nos[$this_no]++; if ($this_no > $max_size) {$max_size=$this_no;} print "size No.clstr No.seq\n"; for ($i=1; $i<=$max_size; $i++) { $noc = $clstr_nos[$i] ? $clstr_nos[$i] : 0; next unless $noc; $nos = $noc * $i; print "$i $noc $nos\n"; } cdhit-4.6.8/clstr_sort_by.pl000077500000000000000000000014461312257207200160620ustar00rootroot00000000000000#!/usr/bin/perl my $sort_by_what = shift; $sort_by_what = "no" unless $sort_by_what; my @clstr = (); my $no = 0; my $len = 0; my $clstr = ""; while($ll = <>) { if ($ll =~ /^>/) { if ($clstr) { push(@clstr, [$len, $no, $clstr]); } $no = 0; $len = 0; $clstr = ""; } else { $clstr .= $ll; $no++; chop($ll); if ($ll =~ /(\d+)(aa|nt),/) { my $this_len = $1; if ($this_len > $len) {$len = $this_len;} } } } if ($clstr) { push(@clstr, [$len, $no, $clstr]); } if ($sort_by_what eq "no") { @clstr = sort {$b->[1] <=> $a->[1]} @clstr; } elsif ($sort_by_what eq "len") { @clstr = sort {$b->[0] <=> $a->[0]} @clstr; } my $clstr_no = 0; foreach $c (@clstr) { print ">Cluster $clstr_no\n"; print $c->[-1]; $clstr_no++; } cdhit-4.6.8/clstr_sort_prot_by.pl000077500000000000000000000024131312257207200171210ustar00rootroot00000000000000#!/usr/bin/perl my $sort_by = shift; $sort_by = "len" unless ($sort_by); my @clstr = (); my $readin = 0; my $head = ""; while($ll=<>) { if ($ll =~ /^>/) { if ($readin) { print $head; if ($sort_by eq "len") { @clstr = sort { $b->[1]<=>$a->[1] } @clstr; } elsif ($sort_by eq "id") { @clstr = sort {$a->[2] cmp $b->[2] or $b->[1]<=>$a->[1]} @clstr; } else { @clstr = sort {$b->[1]<=>$a->[1] or $a->[2] cmp $b->[2]} @clstr; } for ($i=0; $i<@clstr; $i++) { print "$i\t$clstr[$i]->[0]\n"; } } @clstr = (); $head = $ll; } else { $readin=1; chop($ll); if ($ll =~ /(\d+)(aa|nt), >(.+)\.\.\./) { $len = $1; $id = $3; $len = 99999999 if ($ll =~ /\*/); $ll =~ s/^\d+\t//; push(@clstr, [$ll, $len, $id]); } } } if ($readin) { print $head; if ($sort_by eq "len") { @clstr = sort { $b->[1]<=>$a->[1] } @clstr; } elsif ($sort_by eq "id") { @clstr = sort {$a->[2] cmp $b->[2] or $b->[1]<=>$a->[1]} @clstr; } else { @clstr = sort {$b->[1]<=>$a->[1] or $a->[2] cmp $b->[2]} @clstr; } for ($i=0; $i<@clstr; $i++) { print "$i\t$clstr[$i]->[0]\n"; } } cdhit-4.6.8/clstr_sql_tbl.pl000077500000000000000000000055601312257207200160420ustar00rootroot00000000000000#!/usr/bin/perl if(@ARGV==0){ print "Usage:\n\tclstr_sql_tbl.pl clstr_file tbl_file\n"; exit(1); } #usage clstr_sql_tbl.pl clstr_file tbl_file # 1 if tbl_file does not exist # create a new tbl_file # 2 if tbl_file exists # add 2 new columns to it #format prot_id prot_len cid_level1 rep_level1 cid_level2 rep_level2 ... cid_leveln rep_leveln # if I have db90.clstr db60.clstr then db30.clstr # # run clstr_sql_tbl.pl db90.clstr db_sql.txt #create first 4 columns # clstr_sql_tbl.pl db60.clstr db_sql.txt #adding next 2 columns # clstr_sql_tbl.pl db30.clstr db_sql.txt #adding next 2 columns my $clstr_file = shift; my $tbl_file = shift; my $tbl_file_tmp = shift; $tbl_file_tmp = "$tbl_file.$$" unless ($tbl_file_tmp); my ($i, $j, $k, $ll); if (not (-e $tbl_file)) { open(TMP, $clstr_file) || die; open(OUT, "> $tbl_file") || die; my $cid = -1; while($ll=){ if ($ll =~ /^>/) { $cid++; } else { chop($ll); if ($ll =~ /\s(\d+)(aa|nt), >(.+)\.\.\./) { my $len = $1; my $id = $3; my $rep = 0; if ($ll =~ /\*$/) { $rep = 1; } print OUT "$id\t$len\t$cid\t$rep\n"; } else { die "format error $ll"; } } } close(OUT); close(TMP); } else { add_info_to_tbl(); } sub add_info_to_tbl { my ($i, $j, $k, $ll); my %id2cid = (); my %idisrep = (); open(TMP, $clstr_file) || die; my $cid = -1; while($ll=){ if ($ll =~ /^>/) { $cid++; } else { chop($ll); if ($ll =~ /\s(\d+)(aa|nt), >(.+)\.\.\./) { my $id = $3; if ($ll =~ /\*$/) { $idisrep{$id} = 1;} $id2cid{$id} = $cid; } else { die "format error $ll"; } } } close(TMP); print STDERR "done reading $clstr_file\n"; my @last_cid_2_id = (); open(TMP0, $tbl_file) || die; while($ll=) { chop($ll); my @lls = split(/\t/, $ll); my $id = $lls[0]; my $last_level_cid = $lls[-2]; my $last_level_rep = $lls[-1]; next unless ($last_level_rep == 1); $last_cid_2_id[$last_level_cid] = $id; } close(TMP0); open(TMP2, $tbl_file) || die; open(OUT, "> $tbl_file_tmp") || die; while($ll=) { chop($ll); my @lls = split(/\t/, $ll); my $id = $lls[0]; my $last_level_cid = $lls[-2]; my $last_level_rep = $lls[-1]; my $this_level_cid = "-1"; my $this_level_rep = 0; if (defined($idisrep{$id})) { $this_level_rep = $idisrep{$id} ;} if (defined($id2cid{$id})) { $this_level_cid = $id2cid{$id}; } else { my $rep1 = $last_cid_2_id[$last_level_cid]; if (defined($id2cid{$rep1})) { $this_level_cid = $id2cid{$rep1}; } else { die "at $ll";} } print OUT "$ll\t$this_level_cid\t$this_level_rep\n"; } close(OUT); close(TMP2); if(-e $tbl_file_tmp){ system("cp $tbl_file_tmp $tbl_file"); system("rm -f $tbl_file_tmp"); } } cdhit-4.6.8/clstr_sql_tbl_sort.pl000077500000000000000000000021171312257207200171040ustar00rootroot00000000000000#!/usr/bin/perl if(@ARGV==0){ print "Usage:\n\tclstr_sql_tbl_sort.pl table_file level\n"; exit(1); } my $clstr_file = shift; my $level = shift; my ($i, $j, $k, $ll); my @lls = (); open(TMP, $clstr_file) || die; while($ll=){ chop($ll); push(@lls, $ll); } close(TMP); print STDERR "done reading $clstr_file\n"; @sp=split(/\t/,$lls[0]); if(@sp < $level*2+2){ print "error level\n"; exit(1); } if ($level == 1) { @lls = sort {@a=split(/\t/,$a); @b=split(/\t/,$b); $a[-2] <=> $b[-2] or $b[-1] <=> $a[-1] } @lls; } elsif ($level == 2) { @lls = sort {@a=split(/\t/,$a); @b=split(/\t/,$b); $a[-2] <=> $b[-2] or $b[-1] <=> $a[-1] or $a[-4] <=> $b[-4] or $b[-3] <=> $a[-3]} @lls; } elsif ($level == 3) { @lls = sort {@a=split(/\t/,$a); @b=split(/\t/,$b); $a[-2] <=> $b[-2] or $b[-1] <=> $a[-1] or $a[-4] <=> $b[-4] or $b[-3] <=> $a[-3] or $a[-6] <=> $b[-6] or $b[-5] <=> $a[-5]} @lls; } foreach $ll (@lls) { print $ll , "\n"; } cdhit-4.6.8/doc/000077500000000000000000000000001312257207200133725ustar00rootroot00000000000000cdhit-4.6.8/doc/Figure1.png000066400000000000000000001254171312257207200154140ustar00rootroot00000000000000PNG  IHDRQ sRGBbKGD pHYs  tIME 8B-"tEXtCommentCreated with GIMP on a MacwC IDATx}TT׹2"/j%^%̀Jļh$4I!-k+銬ؤ&Q1 fŘ_TКR͋X &&bA^aeFsΜs / 5Ks9{?mAAAAAćT@AAA@   $AAAAI   AAA $   AAA $   HAAA4$   h IAAA|?Ox7qA1ĉ߰X, dss3b A1q8Ƶkz-/ JA i1fg?߁k`0j*2A1ƍq^ӟo6l) HA!8p) `v   $AAAҥKp8n7  `g ƦF]A~p:p 88AAARv]uPZtwttn8`4a2AFvi쐐:ЃX 2 :hiiLXNu !cB`3BIkV>rkYb744nܟn! L[lV{SSSn$va jNyb˖-: l6d/Owvvfو @HMMv`2l=:RAٲe W-|S+ɖ-[zz%.wʇ f,k??}e{ϰcRSS%eIAClQ2#sNdddG:t# >>odɒ!1ЎfŲe0|@BBjkk6m`Æ _b޼yO2:tF#҂,?b޽ҿo?b3?/_V}'lKgDD>(BP`LǕݲN=z4S]v{Ų?YjUq$$$(hl>q yYu4|̙3ol2-++ ))): %Kl7j0bٲeHOO:(..,K[=:xG t˗͉NBB0k,ʎ}'n ͛sι}8x<?҂Dlݺ_W^۷111+W& %%% Vzlygyɏ$#D%&&=ҢYJY?IMzRAN\noЫObuo> L&ϟ>VYjN<)I^YjeƯ>ٍ'R7^ǀ $CBB0f]ӧOؽ{7ȑ#d磽z߿_Çc鲥0Q__~MMM&^L>OTe=Yv硫KrYtL0A΂@uذaHMM]w;_LWsΡcǎń 0(##0aICƄ owpߎ9RUϟf`ﯙQFIFr[^KX?k0ޠ ^fLVY#::Zbܸq[[[?Xl$_r}26l08NTWW%ne'N }QPPr}rrrn7v---7Q]g{?H8JG݋gydc͚5(**R%nWUZ??NcR_+`޼yR򡙙71{|2}L.sWUU X?[x+W 11,i~j6l@qq&7dԺun: 0  ;̓v0>DėΝ;'|- / Ő?K `=0μ8^+j._ܧAڵko -- o_j:jy R\Vw%}.]ufϞ`ս/<yyyxU_z5nxxxpUl߾}Xn}}}.+F?#f31zh .DMM~8cHKKqP@i=󄦬9y;O kXD 9rD\^WΞ=>|=:oK m"""p8Nعs'Nvt^ʕ+cȑܗ-[ ǎx޼yxwxۈ@N,^EEE;Ue)$c͛o˖-|\kkkO} @kk+8|r Fh._J#|b&=⾊R---뻯}5kt qqq:iiiQ]2&؇v+W~܇rb᲼IYY,Kb62py-GuʓNFh/_큠dn،m݆TLHF'Lq": ._dfXV`۶moN'***SN[TT ???̝;g:vTTf<ФIsG'FGGNYQQp???a͒^z*?@1gl6tww;[?8q"NNVDL{pzmm- 5N8禦&L:+ի}̙3ƢXWy5nD]]옗8|}}1-n|A=3ץjP}=kG,e](**R_,??f~sJOvm3"ApA27$$$`ɨDrr2>>>6m>#;bcco%&&ޓ% kV5;vZCY{Bp?~11_cye0$i7bbb9byul,q888X{EI'zZpq6k;;;t:W~T}}]ߓ䫯z ptJf0L{훨$;;M`dRuABuu5Lƒ\.~xC[ Z;^{ |@m988/_ˑ؎ܞ8=v}lƒ%Kz![ W__x1c׮]8x _ىΫ>jvg&oؾ};;g^؜dBvv6_:([^p8&e9;"\csÍΫ|YZ].:;;=ʺr { >>>1c={6lő#G$~mWPWWE) oO{Jvd~effU:iii^\NNk.ڕ*< (++xi_XB 3+x"##w^ǣgjl6c___ľn#--vɤ?g4j'oى~g[oxQ_\>1˓4j~6n܈cM^hh($;k2bccQUU; )))1wRYY;΅ݑp;rQXXy]\/?v{޲tR씔dfd%^+))ƍcǰtV^z7((HII]- ߫N@^^f3f34lv+K9 \^}s=/~Baa!No屲PkG?ٌXTVV"Ʉ*]&pedDfFL7rP_D ndF2++ ~!n:<,.]'xo,rY: Þ={e%&&e9LΝ;%1#;vo?#رCUGŋ#Ws6 $ʒ,ݱcN>[bʕ(++޹s'BBB$ bAYYRRR$:8{,֮]ŋ-.wo.|~c%3Ob;ae*պupm.+8RV6mBzz:.]JnhىUnr}9ûf/m<jϟkډTkV/3&(QSS7| WkvX7|Q8f]K֠bΑ$ :G;fΜ)L&gǎ{***a ɽ;vpg̙^h,u%Yic(vgN=H,%/ZHbqˇ< ӯ\Ze)~Rh}vѧno>-ҕzt-.w=&ۏX'̆ꆷe'֑۫^xد:әu 95x_O6[|8jn9Ak]lzS#AA V؆"%%%-V,Gx!lxVYYɑLMAxFIJוd7eR#((HYA[tI7VFT8]6i#*5,N,vT6+ 7̯e) K+p:U-g1Ҫޖ|345YZuCi9vӟ+.XM)]b7S*;=~Nm<ٜoE.GYLzZ۷ AANs%GĈu|X,Ξ%O}Չ^^-֧Nz_eisje'OfuD~o7[.XVO;@(//%նZBvv-l6{lqeGͦ >ͭo@0Lm;::3g ~~~Brr`&dee AZņYTY,7N.6\V`0,d2 )))ү fiVD_5e ĉfN8!Å+V J}+Vѣ3g&:tH X,!//l6d2 juE^ DDDV?f_rr`ZO]Cڨ =X1c$톼toٲe+nbnU>V?SyWnsr˖Ug9AzICC`0aRH/ ѣG[/:$ SN!** ?<-[̒%Kaaa6m{nF>~l6KC"[n;"7L(//rVّ'---)o?Owj XjM=jX,.(5nz7mM f#疉 DKӧO#** OFVVJ^구*"**ڰa/_͆P>sN:tMYl1N8e˖ 􇆆f!""ؘ͆!W =z4ԞR3=z4 99UUU:^UUU]HHH@TT͛7'OĬY<]}oZZZ~E!=GTT҂CvYF>YQQѠ~gTT6l؀ܹ'N`sC/H[ӉC?O~ &L@ff&Ǝ 2x'ꔠ dff%KHv^`B7_dɒA"١dsL O<rrrp)X, 8uN: Hv"z_qL?THGN6mHy",, '+Orr Q\ܳ˸#!'qG|2Ѵ{uV~m֭Zl<*>>nyf8juճ(:`,y:4cNX#9fϠχ@<0L0~_~nd9[SlX<]*G9čkt-LOOGTt4׻ӧO{۷o?~Ӗ*YYYn6|cԲ9y{m >\.MޫY%gke~~>1rHt?~|,'ҔEH2`;v,~ӟJ "~tL43fSO=ג%K-K^J vɓ@2x5jV+`޽8qHEii)Ox/ؾ};G@r8wσraϞ=x@Rv `jEKKˠ·Ğ={r`Za2Fp:ܗ +;9bhm//w= sK/#-Yčk]]]Kfc\Պvʕ+X,_ رca2_&L@}}&~ťKPYY~@O!;&w^{5DDD?1BCCf`7jyY~DŬYKKKQPPgy?J۸\.444ॗ^Bmm-V+O`Ocԩ0msTmn /磠& .T *;;[{^Ձ+jXV'|Qˁg}---h 9,YģCDžѣ"&&&Fl_8rPK';kv`G+}+@o뉡JP+nޜ+?d2=ⷵzػw OWDDFF",,LUVpp0O'0q~Ӊe4y&NQ'ZDKVfٜJas1o=]WF.j3n}x3Q+;t(TgoiV؅7:,c dN r]r [Q˅n5,Zo!9 N]!ٳ癝:#сz=-ǚ5kFS@8Ni,PW4}>i"_>yS9ʕ+ߚ{`0Twd3sg^6Zip8{Ųo[ooҭN|8}yZ/IJ#Y_o`crZis}կ7z6G܄򲳳k-ŋvr+//dGGykG8qw~'Ϛ5rDUUWo(7ij>Z6<ܹsm6ǣyLjВ?nbܹ|`fJ:9Ƅ *'?:+4%֧RY)/,ŋHLL6WVYyÇA\_:%U[g_#k7f3JJJz_74/]%`Z/ ߀ G؋(ד,o_L{ԉѨ¢?m?;6Gz9`cgdFrx衇fLKb…X|-ƽmۆ={^:tcƌAss3y,[ w{O_p!y[nʕ+QVV#Gqyﻻ1rH,\555կ~ {wC^6mBDD8v$$$W_XA@JJ _|Le۹ '\vnQXX([Έ]۷6PRR_%y~]&Ǚ3gl2~f1c֭lذ~:ÇKl.&& n:ڵkCq]/o 1a޽Xf,f7LG]]]ne{͛"35k0}tͱIccvK֮]QTT ܹׯ_>ʕ+%I0]K.a͚5| vM;3#S#wGW{BEEjو|ߏ'xByqqqXnf>Xd ')to+֑jtxbE0ꕭU555yfҥKraqS҉ӭesJeyS_^}Mnv܉>Og6n.1 HI削o<~'+;h4"&&'OvNAGG***pUիWqq>o)boe*++ݭO%Y Ţ QLL &MĿmثHɶUUUpzZYӧcĈXٱf/foBF\\v_bرzXXsĈډTY>Ʉٳg#>>!!!\jIdwttH)`?caܹ<F?DN:e:b^gZ7ƃ>)~+++1~xX9sF"*++ y4f6 _^6mGYb1b & 88-~~~(++|ɓc뤽]~[[[QYYXIudi1bΟ?bرC~$&555|V=99| >s?~ܫvC/EEEFr`0 %%hmmŇ~'xB_ڰ䈈TVV?_|3g l… |IVv(((@BB9rD5III6wq&N{bb"^QQ&Nމ_B*b}&KJ, -- ]]]#mZ%y~zT.nbr놿Y& sUW}}#G %%?Tmn…3bEEEp:K=[r(du7߸\UU1_: +!-ȑ#ylKONu555^}||l6뀸:ٲe`Z. Byy{vvP__/L&7"vF#֕+BYY@0Ld$ BEED;v4utt6mҔ%`¯-fǎѣu???2J29gjv]8S{F =ZXh 6MO*>sL.);$TTTْrgdzIMM|7oP__/X,]K)&55U7o`.̛7OHMMUɦMW,[n%Mi&Cn ֑b 1`:>k2+9qݨ\h=ZرcDZv%=[\ŲV'̜9S5rgFk<Mjjo:ٲe=a۹Sʒސ.%ψc41{;HVZUkbΜ9HKKo>51((H1Zعsi={66l/2$w}WīD;NߜN22fˮSX'F?#f3y[[[y n8󟑑> ϱvTR_ ÇoR?<[ڊ˗m߾};v[GW}?Ӊ2)T>zv___g^СCgXpa>@o>ٳGS񨓀{e^j Ov6KOO488AAA8\f8hW-v:׳vT+[_.0Yb|Wb̙3gP?!!'OFee%yiGiUh?QVV&ɠ6حDBBBw gmVߊ~uub{MiA?moUj7^? S4%j!Cn}=H7NԔ)Sw^Ig㦾h#"֯]vaaa\\D϶q1>L&ѣ=T={쒩~c;Z[[5ߪgffG˼ѫAgjmw<@ٻsg{ >>>1cΞ=_*e9rD?ρ돗>~8㑐^/kRRh"źvrI>vڅrr ~nbz6bAoٺu+rrr,=AZZy^&azX'?"##w^~kKԞl(ǾneiiiܷL&U󑙙]vaԩyJ6'l ''wdݻ1~xmx뭷y2331|> T}}}pB~;1x3'AV1e~qb =-P_ݾKy6F 5;Ml^+))ƍcǰtg=ߪV- {"S-RSB&ut7M+?-YIIIe+?>')))|g0,X lvK[tR^IIIufA_I(,,D]]]kCDžV *bqiJ,A^zcf1+?L/2#?_n|AI;{,ul9#uJ|}9zue9LΝ;bFv;;voٱc[ŋ{}Io"n|}}%- ʐ"ٳg%1r\O?4+{(>Hl'gtjݺu|;i=eHcpt3f~1L8Qk[wDZc$:cI˗###sAyy9֭[f,YN $ ɱ4e <vqAAv%ɳ8555S5r]|9^~ٳop:EMM n݊w}9k?4mS\Y9,hcc#ZZZ.;ͨ`@hh(ZZZܬ6446hk r\X .b(P-܌.?<ŋ EXX6繎9:˅6J!UׯQv.NXVo 1W4ҥKژY~N!y>Ϫp~A+Lr7tuu!22%%%9s&nٳgrqr4i,,Wt$z_kG sIڪx^KDdmy٩vdar_*@ݫ5;,YWC|&,q̺A@#IAtz<')>w3S%*}TeR;Sxz7(_lXs< 3(##?wϓlNIJ |l6s:9-~eIzӭ#Ot=;SOJU;c*)+oe{=uZ\Tosκ߻Yc.oϑ4:\FnnW;5A`mTURR [2i=<KgR_7.]l#%$Ki6M> f$;L[tg$պ(5of$70LgevՕ*D>bP*-3dsJUҟ'F#_P\rshh(:;;=.W9-".ƦFMM6%JuZ.xcbYZٍV:WNKf/EuC3|_[MXߞ|@۷@  HA`ہ   HAAA4$   h IAAA@   $AAAq3LÆQQQ5 b#::::  /w}7~ߣFA y |||Ft0"''JA i9ѨA AQVV.RA11,~oEww7)  $Aܪ\v EEEhokbABBz7I`X֎"\vKAA@ nENm6s=6m&MղV6ml۶ MMMp8` ▧555HKKC~~>9ΫXx1ҐKΡC/"33p\\P$Hv9ގӧO#)) 1bݍv455ʕ+&LQGoPL<hooخ0IA-M{{;PPPkv---\zgΜ m4>Ԏ`f$%/_F]] >>aaaBkk+_ǽދ{lYIx@]]._L & niAW_}RbF DO wq]b\z 1hii?QӧOСC/C p8/c(--5 ?_ګA1DZw^,\'Ou#..?^}U466t bCK[%v[>׾ |ghhh~+~$˗qF ,vLA477È#+t_|Ο?ǝw ɄazÆ Chh({ & &M4$˗=3A>|8vE477#>> _$3 8z(.]>|8_5-m% nyֆ#Fjힶ6T»ヒ?'NCpp0|;؈oAI||Wؿ? waUU p@< THpd_2)=ؓfL3T}6X&>%3ܺ7?THEAPrfg}9 z:}>{{Z+Io. | =VGww- Kg?9 :؈V ­ b:o~{ԩScƌA||<8q"9 h I---믱uV|z*\W |0}ߎx`2ގ?pQ\z< 88cƌ'? 9 h IꫯPUU{|kuA 7 ,, !!!0 nDFF~n Faaa6mpAdBpȀ~W"' $ ba6;v ę3g/"%%x@ 0yrXXd%AAԁdU C­ |O>Ass@ bC7$x'r ?Ǿ}`6x7gF:Nt;N>HNN&A7>)?b3vX,Z-r[o%p!-B(A#DDDՏ.DZ#>iӧOGLL ?MMMD)KD!1 0HLLD{{;ZϷ"::+;mގ+W[oE)Pq/- IY,իWoɁnGJJ n[n!!!qaaE[i $ b,ǣU QţG'N]w" M7݄h\.|ŨQ;vH-((@AA-˅s?fL8#11 ˅˗/`4 0 R}N\zK@pp0EA/wqaL0cǎVKK ylڴ /EI$bxB^nF#BCCFɌ a0 [~|種֗_~SNd2CШ DuJAAxMxx8㑗p Bbb", ƍJAAAxGAAAxwVA1bu3g~z?g bX Ø1c'Ν'|B& F_~%>sv_Wqv r gA C~~>u΋ B$ [WoI   AAA $   HAAA#CatٲepwՊ 44؈޽/vkjj0|ʕ+hѢ!۷W^Q`bc|J׍ ++ ӟ0k,ttt{Μ9hllԬw%oGAlK-|Vno?Rʕ+=;Y341"-- ݒzתKgmiU ߷PqWŸX[IHH@ii_t|+=CZ&_/nwjy5#[VbcTmCM.&gj=gUY?Sކu+VN^WCoۆ^=7@Dpp0^{53<(**¦M0cLdLs F:uʯvǎKRSS"RRSy֭[6(=Ś5kv,Z۷oǮ]p<\V N'3<'bӦM8|0rssC⨨@]]`ܹصk_W^ ,رcObp:} e QWW[]1"Uv6oތZͺd㓋/z_$.mgݺu[o'x6 Fѭg닔T,X@ۘw= 4$!C6͐HO{СChllċ/m۶&WKfΜ"oÌ3$zԄ\{rR.],sb||$+9MS˶Ze^p!Lf-}y_VdŊUTT>Z#e9&t\|P -[J}ǎ mGO% ˗Dޟ W_bN7ټyD/]G> N6l $''=\*碢"_lEAhim|AuJlBssrN !11g%횶A\.v[+Jrr`Zl6ml6o?[V~}N̶mۄ\Hj!))I ۷Ohkkv`ZB^^$o,.0}td2Il &IHNN$Ɇ l}Wr[xNLLV+ !ng IDAT8-:{+?}"GO?O3W[%KO8)**rliŜ<~VoKkO<sS+򄼼<~Y߻_7 >Gmdkk+{<53Kjk$!55oCCCWRR"9oII-AjjqzlAgڵ7"-ZqZZ`Z1{l,Yį šC]NNN<9d)sCC֮]擋/ZW,Y})~?bzbjɒ%z9nm!..-~=Ozfzp&-- R}哤$YfH(޽k׮ukLsߏ7\ =7zP-GHf!11PWWl2̛78p6 CGG222PSS)i8pJLLffŋ9s`ݺuHLLT'{5/^cǎυ8p7o-[]g|+RRR3fxmK/+;mJڐAyy9RRR^xo5}r{˺u0c c$1̀n߱x܌3LՁLyy9222< bbLlٲE5Nf-[,ҦIBT}5}?ٲe l٢qbI˗/;v 6MobǘmuB|.N?t8""-9sx=th`s`r/)%%֭fN=:4g߾}yMoDT qyCm?GL9yZ@}4g~+H$ldG}=0E`@ƌr- &xojEXX,|8NMfĎV`` bccU AAAhjjq?E GXF|l^I^.`gy7nҥK%cc~hDXMf<_IPPP0 **PVVDŽw}|. /0mmm<٣87={QF7RQ<[,$$$`Æ f6mc=&M“O>UVP mws'111X,eKs &<<|PwYa7.|d,][nO8x … HNN~;fX,޶9TTTvVXX{ k& /x饗`6%z#ۆtuuik`` N1̖lvCftu7FQFI088+? SNOhZL-7ARSùsX`s̼{źu(['Oŋ1*++q >įkR> uuuHNNƯ~+Ŏl7qt:pmß\r-p\%n=6&O:믿ޤ$/u}HfLƏɬ,U.:\QQ1d¤I/$swK4W=T ٌ_ר7 {9bLŹ\#"즅rmωvVWWǕ+Wo>qqq~1N>7|EHi ￯٩$%%nwhk֬27԰9 ;K":'OɂͽQy g)))Xf vO<a?1{lwߕ@ss䆂xH1%%%|u=-vZ̛7obM|1Zz~Izy磬L#Gp񝓓'i`PM'Lt~UUUn}VXSz}M555k$N-j=izw}WMXbxc}vs3\ 6Gr8PXX9[)m;YS#{[\=+yJėzcN>OZS6~淪Dk؜y-%%26?;%%E27Nβe\Z\DNg_ϿPȾƉ|M5[r=}*jcTߪC㻻xCoեLt؟:\'eee 0s$wNؼ .3ޗ{lƍQ\\qwٝ*ٌ+Ws3[sV\]v>㶀W!}Qωm%+&uŨ5綠[xbs T9"[$⍭28qBRpdEEŋaX消ߑj*.\ /;007uHKKDIIlΞ\쿬&LsV+6ǁթ:p8`#1%H_qmܸ~TC%=ZjNWWKIY8Q\\=*l$M 6SDM埵lI::Fxȑ#kZu)5s[B.^ x'^1=z4-ZիWظq# %ڼxQ}f>qJgkY-'Gכ-ϡR`BJ;ab=k.,,m* ٙLx衇$Dn߾]]]'4Vr䚣EssĖxzxN}$966Vr. Q@>K~ݺuАPN!3Uަ𩧞Bjj*Ù3g"))Iq?ĚϬ7{3=tXZ_j ׿{˒$W0vX>lӦM|yyy[w^lݺ^>l6saV\NbjV;vuQ[[;wG dtttraǎx@cc#ƎM6ERnwqqq|cǎ#O)<<ם .00S0a2MÊ+P__ Sq".x>V̉Dž1%Z5cRk@RGZ+nqqqr*D'555<=CJmޓO񯧘dXVI]J:EֲŮSH@+zYYY\;z(ΑJ-.++쉂kjzs8YcŅ 4myrieBBos .sYYY|R?VW[%:!>Wxx9']tXq_G_~衇3.F3_s9O:,{JBpE=SŹF+~W4Ҫo8;v,&Lj[?<8'N<=1 E>-Vno=q+ #=o0nݎPؿrJץ\rxVW]ŘVu7W+ $dZBBBo7~l{'Rk֝GZچ8^52~ߋ}srmi՝<o)rZ._-y=ȑ#svSA=mW[rRgxU+-]ڪrcv.tXy8TWJ}O9`0h/e 4Oچ/u'_%[Z׬Vn%PorP;!RO񯧘SC&V[mJgx $ za(A1@H#   h IAAA@   ċjooǒ%K縸8RB/e(++7e Cbͅ/\[lq[.[Tvb-z-[Lܶkǿ˿ގ -.|"myL ƿrhV+n;rZɿzNvW+殕1ǶjgOO@u8N-[뼼<<<'s[^&y-~!233QUU%Ç%z{{֜wDsvg[ėKKK`ㄠq8Ç*}bl 2 꼭<_mmm_;fʔ)Ejj*V^^z 5/]tHO ,ܖx̸F.ouFb,Y3f@jj*V9- `޽NV<`Ϟ=_?&ddd`ժU3gMbȩ7222sNPM,':/ڙ vjE9qϞ=:;;Unb8p6ms=JlThÈS ֵ?ZÇNGG؈OȾ/^,XN<W8pH裏|rtttc=6$p``xTUU!""@ee%ӇliHpQYY>ttt ==}λbo>+V/ ,ߟZ' , `Ŋ~zMbHygPUU;@yyOzWZZ ``||(..SO=-[ 11qDK)7v>/کfk0zrmxnڶm׹Ik{L}ՉP,X@bk<{9ZVÖZ_ss!p$_\yy9p뭷"--MN|Xd |N={H7DSS ;F#N>LrۍK̘6m~'=.==߁3f5>yd;T6mڐ__FZZiƵh;čMVV233y{3f :::P^^:W+~Ϝ9# w);wO=Ԉ<7 6'23f d2l V'O,Y8%%%EtD\\fĉů:,hp9bFEM4 ~!&M^{ W_|Vǰ0tuua֬Y8t>ᐈ1fsl1T\.>A '_߂ =U9cƍ\L&L&Q]]=bY9Wvd}nִ)t:մӗ8a1[7Z4axPRR/KDDD??q 8q˗/{;Fvv69 y_8;3*\__,8qbH{ deeזߏ!t 99Y/'V`ϫߖЭ63;;[hnn\.*Mv\BssVn} --~ B I;>vܿSo[[WՊk_yuuu ǎoذvDDp99zWshrZ畾UUU rk+Itd2 ӧO P]]-$%%abb&mTԻRQXX(bvvv%Zz8'k$nb%yN-qkRnҲ%;=XN'Z}yy5ꯉϥS9Zq"Ry8cKNVn-:rzc)1b^m ݻvZ444 .. x{n#JXV̞=gφjEUUOccpI$%%a͚5-6\x>x r:t7nD\\u!y,Yٳgkfš5k4ٿ?RSS:dww7RSS7V3{ld۵Tbԩ_ݍ.Y/x\ŋ-6T#4¯0c:~СC|Ŵ4TUUIX NK zAo_fOckucNԛZ[[ym:O[,Nh'- 1MO8Cψ{uŘ7o9&&|"`P]8mJl6-F JxQܲe |M^ኸrȯٟסfۛfmq1`l_jW\W>k?=6_hVkwxOqk93c{̝;W]\.m7r<'rd> Z;l qvka˓ -[zچRNcQ3i՝cΗcNjZΓ?}ӏץVB@1F#ƍ˞dֵdrLwCx5{5PMy`P7|A˶x:nד=֊g_]OIxbxsě8|͉jm`00umğ<[вKj՝qr-cΟ}T_cN޴;L=@=z4ZN`@rr2:::I\\aZU7{7ͼl|J&"[.{poBB\3zsz|OzsC_uۑ#G0k,455rAčIss3`ټ~>$O$-[ Z8pݍ磱 vCMM khʕC(Μ9sب} ^K_^۷K׍=!vZ" J|+%FlK-)7Tms|?A\b[|ʕ+=;ۯ}ɶ7qtԝV]U}UӟYf)[oݩůmO荋=У' ,PZZݕC[s\wzrVԊnyMʕ+1w\z0=_`.=]߬ֆ舞?˭]OZ꯶Bz8>`kgyqFlڴ 3g4?m8u_FEE:$0w\ PXXptuunv{D=+b{3bڵx'O;Ngy'N!iVTr9w\ڵ ~b?c“O>UV'O濿t?oaa!+~.6I©SсdU[6MbKOv.Ʉ?غusTT#HlYVE*'tp6n܈ŋT]d.ub$99/5kָ)ܿ$-..ץ'HOOW #$8 .믿ʁ=?#qTr2f'Nd[clz<~ qEf[syyy|I8{,JJJ /;y83Kh Hk+|#!!D?#3Qs8tk/Xncfp_~%233U۴Zk駟~* 1]]]m9N^b=,((hzyL[z|"n0IUr-9s\b=*,_شiɿb]<2~ح[o#;;IIIOu\pBL&7]X?GwgϞuO}5XBs-..vGە'5Nb0THu-algX&ߎO b{l6Xv->b⽗|Qmoa(妵'φ Δ'HOY[[vrD[/drۗd2 <@~>}UYVw~JDJ_2~i駟v/gjAUMO?-|ͪ>RڻT-y;O)~{m*)%9'򄼼l^ɚ% ?#>6..N۟sۏD{u"558=H.)) >ea_Μrrrpk:xk׺Z}- |7rcio&~`jUavM's!%K(Ꝓ氘ЀoC\\[z`jFxN955HMMVkLsZENqڽ{7yW}|ڸ_5vOq^=nm VILL!%%(,,-[ CDDN7fþ}с mJN7a`ٰxbnkΜ9XnUmImm-^ŋرcsaa!N7FDD͛e˖3f %%3f;v [lz8XxiSx / 9nݺu3g///GJJ RRRl+f߾}n>*//< /׭['+qOXdff&rdddNXy4c 6l6wƖ-[Td( ڴBT /]cmm-BCCe6rPevv6pMZ|݉رcl|}v7m8ԴUlKsY-C_ub޼yHIIyL)_̛7Oŋ`ݺuZ"8=?(avvĿZq,NX?i -[ Jq"_!EËk[ `0 77&L{!00'Oqy6 ~-V+bb t!3NjKiաFb֌?^b!Υbt;.F~dUoHHHQp444>3G k`aLt@{ߌ40gD<C|mmm&(~>,,Luר(?ىJJOOL_5|6ZZZsyf2SN`0 ;;17a塼}}} W_}t$Um}8RX,v /kbrWgϞe)uՊlTWWcg >>l2롸&$$`ƌ8~s*>ђ\J{~˭LW'NĬYn$''Kr*ׇGVǜ/.qSC5zî.̙3{Ǐ9s格W_}D&f}֞i'y鲿i1FW+NF֖Y}ך#_'&6={0@7 L&&O;w*.>i$>17//ODz_o/uVxgϞ<oyꩧ0w\|M6:===Aw"U<ဣۡ5k0{lddd^}U d݋49H;Pf3ٳgcXt1csN<Ŋ`m!%%K.֭[%;EFF?Dff&/3PYYi"##AAAnw#""`4qEdddp[!!>ljtoo/? _0;}n[w6oތx?9RSSa0rCG`lܸ%%%Z())Q촱|bcǎCVݮAAA_,;cѢECq=pϟYf\̚5 +֭[7 N<N'~~+-dTz.@p Oe00fO<\AIٳA 7H*|}}}1tuɝw'/^Q|p8;wJ:/"_.##VBYY:49pԧ"77yyyx7%Y,TUUdFkk+RSSQ[[+9paĎEsK3nKےw&1Jaǎ7^/?` &;,X*qV+jkkbdM/XwѣG%N2UUU o;v<+''Jj熒p^gfOHdT$8D__:::>Hu`}7= ,@gg'oߎ_~٧rGDDԵPpyK-((ǒ`~T_=ҢsUPIZ,MfPu[jqSrz{{U}RXXg}aaanu[ZZ˗ϥ?Y3'~CBBGtc0_%%#??\… /wD{{;Xp!z.Le˖y5kI}}zhXrJ-;b뀵Yk'CEBʕ+^Yс>!7Q|e45/\W!~Te˰yf|ͨr_HHQYY0<쳚9tܹ(--_sii)VXp۶mDvzwRe z(J2~I{{.dzʐ<±y/_\|GܷGѣ ɓ';Q1m}wYYY0X'W<8p\F:ݴ)ihoks]ıc0eEQaٳU=;9O|u0m4Ԡ(mJ, 1c;'qG1m4>Eo{w{Ann..?^bKJ, VWO m|1%5sDğY'OhjjX)-McGl"n宮ơCw^oqf̘Nɱl~߂ ((yyyOW+Nl6Ŀ>_|Yѿ1?P$o6 5}S\c2{+۫7kb]Q% Yo6% ^'1ϲ2,YĭkCmݻx1m4>봌iygĔ)SuYTWW\+I^e* q"N8xNוM!֜իW!ӜdzG;jX[)aP# VUKinnv;m޼YrѣGݎIJJRk͚+ٲBRRjVܬx.o)f J>}⹘mqu%-?Ҫ;vӧ_ZGJ| ZZ}bHmh՝SkJmӹq8Z+^֝^S#򜩔[:l1ɑ>Jq S>mjST=jΓ97hiV͑J[۞tDɶR۟PˉrrhLܢסeK{N {%J#G0k,455y,Rې1-=tB6|)G*vIK 7khVjHB_om{5?: =@b[ M˖RΥ=ږq-5`05wyXSZ>G顖v*WS[eu魶%lqOjC2$ 녡HApf0I#   $AAAAI   AAA $   HAAA $   _ =4ى"A1bhllT(Z ^{; ntuuh٢dDDbccQ\\L' F AAA[:nömrȁW %IDATAuhO~x[    =%AAA4$   h IAAA@   $A\?f!;;K.Ż g+Ͽ`ҥΆfC?9 v %%:{Mww7233e˖Ļヒ\N$A\ĉ8q\.bbb`4x$r>r,A1"pN/.\I& F===ꫯ0zh&L̙3%IO% #\@܈\x}p=w㦛n "N'l6|~s|8<#{jExx8F#n&}(--w}ሉ!'A#sΡFwFoiiAkk+>|;pmaԩns F#RSSa 0r=z4AI}Ng}AKK X߄#.6ގ=AĈv tMMM@yy9Ο?\.;v,.]ĵL4$Ogg'%v:G}F¨Q`Zߏ7|!!!;Ǐ|7HHH7LN& F MMMpFaĉ BП^49 Ǐ[nŕ+WED\;'MDI4G!ikkS' WGa6a;v O'|0ذa?>$$NLA(hرc^TVVeGZZJJJЀ&;v 6llv7:|4i'A\Iٳ8 44T"r{}{f=q`TVV_rlFh2F& F~)#>>$hooԩSq"""F& v[.$$ h I===hiiH9w4jETdL&Ӏ`ԩnF# ,6M& F---|#<`Ǐ5d2!22RrvIW[  aHFg h IAA0Lx衇Wp@O+\.9 h I#I&aK{ymb8ML4#NE(B#""؝tn \ε WŭYۮ Hz4$0P9؝Im&{TZN;5qJ.\3U*EMNNڵkwkٳ211Q5 e?vuaO>innο7˗/]?RjKm"m=ؔb$I߾}SVS$2l}\ϵeEQ---޽{ToB굺Gbt˲JTTTVkBDGxBHDPH+++UV[7N 4$Ikkk-;wׯ_Fuuf5(j߾}ڽ{|Zʊ$))2VWWJեpwXȲ,zJW\ya:hAruuwNݰR/|>/I**odRuEeY}N8={ϗeEIR>W__t?oW&z? t-MOOұcteݽ{ޙKPdEifٶ!I?N3MS#Ft9#e5kDdϟ?kaaA @'f2bVzo m[tZa,KLFn޼)uW\Zj靦iRd P*R"˗/w^yi NuȑUPPOo:p8Laɶm=zTc-..nxW̃ efΤ56:;vhe:hȲ,;S8V {i uV j||\Vޞ l6e۶u tlRbi+ H$ A@$ (IENDB`cdhit-4.6.8/doc/Figure2.png000066400000000000000000001242141312257207200154070ustar00rootroot00000000000000PNG  IHDR>MsRGBbKGD pHYs  tIME $4v"tEXtCommentCreated with GIMP on a MacwC IDATxw]eܹKfLڤe)",?Tl .XEE]p ) $^fҦe3s~Li $!/{=y<1M9q@=}r;/OLBzy3v<[*""'att2v_fkcR.Mft826!/њ ~Z9hUDDK 6}\SCq?\(rۦ1Ҏ""hr$I:;;5{KM( M&d| YJN'.朳&, Qd6X8Eb  R*K6X*""r"r6AToxP~\+Z'd)hT*'R]]M4>z.X,/<\vjlV(nuI1\I0lvɄM*QXm{0^? 6+)DDQ,ٺu+q0m4/^0M8Ϋ}X,6.]v~_pB5q9g_gj^KCjxxXP#q :kqJ===,[uqW3}tN?qW4=v׭[ϦMB,XV(eeeXkrzihh39 }!Mf_WGyLXz }}|y͸]n^/.KʊCDб!McJpS>@k R;LOOI¥R!-L  Ra``m۶uVfΚI.{TG4pmNnv-[FOO-SZd2$a.]ʂ $wRXRy3\rf/k?>to(:/ଳ"+CDDO`>r`7<墩b1>>/.#y8CXR*/^.w:2*7 b^ t0͸ T23y5*""۶Yf {/;v}FZ[[fMG|eYTTT9s&}}}ھ>R%@DDNV|ƃx 6sTmIFnu\FFFH$h4;"}Tq݄B!.2y9< .䬳7\zDB&i Ã|fx:_UapLP%&l'Ӄ_>o#`uP,ٶmO==\uUL: {8縖L8<3Ac-r;{s| z&VRQ4\鍇|iU]NWCGI)"r\|k[cz0 %(p}8۶h17 0TшQPʥhk}%֮zn*T5IHDp'I~N&yԩbJ.fM׍3 QQ8v??+߳|*8%ϭJFD|ݕ ѷ0p<?vb:W셍gNP[DDCܿ8fЋeu.mOoKZÜS, \Y,#;ߺ ߴ 9H"q\O@&.ZnJX9#H19?t[mz7ѵv ýnel m "#yo[Va V=u|aNf{hx(p:&Ka$RbIU!vtm 㣑Aِ3i'"GJ(0êᔖ(S|M)r#$bh B68)bO{u,ab`off|z$ME0.E篈/i  w3&f8LEQ.( l[*"G*s;H4`:U 1لS.( DD)d!3eM|\L2e)EE%(pdR)]}>۝dx&ǎì"tQS҈vu Q:s6]ӌ XJ9i즣.o'ls\> ;hU2jr*B`"r$[yn`ZAEpFGHS)2*z`'"R6~)*(;޺u>>uQV(*]ERfe2 5>A<+ cCδYiF!ΟȕB:I*#ihnuot\>6n3@mKI!#$"fۡN+Cnf D>ˎCke08;Ber28a`qCj$F26qyKBN*O W ϭEo7O£X)ʽxl>r,AOwL+Ǘ/bczˊ9z-z$ǭpU9s~5WW5R*4L) /s])3J#?3x݅2_7S'Vѐ)p-Jttt܌ijxϠ$$vB)owq\,)jcsՏGínjF475+1RvRt8 n.07ۣ͑-SĹR~N-T/ײjФ.m;^gm/#k8s,8ӫS"D*rmay֮]KSSW]uPHb*fR2OȌ꿛ék*h { ˖-+V7ZZZ}R7nw`f* \B:$9cuW"x./xJL[XDիWb .B&Mک?XEss3zXu|+Pe3@Ѧϥ!ۗ1sB`u9^D2 K.eʕL6s2sL\BRD";v}vjjjvOG]Yb6CC.|44zg13GM}CjfΪeFh W+N322B{{;;vP(F neP(Hq:::زe uuu+q儫b^H$L f/%JYqLjZ5+О"wSSNŲv*4Neblݺh4:NvP7 bBpoQ$X ok-s40O@y6Dm۶aY1M̚5-bq۶r/$sp`*t}_׿^ĴZ/{.E~yx zYXc*˱l2~{uQ__OEEKw& yڹX,r2erbɎںWb$]G~h2y O޼_QO| n=yU/%;:v̿˿0iҤS[l玲b gV;u頯m߳ Wp>g[-ߟGF}\3V ,_KS__~ZZZ8q#yO2dxx'xz̙;N***p\8+Wcoŋ 0M[gɉdp_932u3GaΑc2$;6rV:pOSwSKStAx |A*++wSH˲pX,Ƴ>c=ƪU immeA,R;uDUwDžɕNR&E|&~zrV̞mͧ@|('͒JxL,N~7hH$rD#:8\͛7͆ hoo>:;;iӦ ) 4]V;v~} v<=jQ]vtҸd2yg<-[L&q\Zٳg0MkֲvZ6n-[Ų,:;;Uqr1gΜCZb6Lp(+hc0,/JZ%1F2,۶ƍl9a۩m۶1<<6meeeɺuvS[laٔ:y<f͚uHה ٱ3)j|Uz|a)e<5Ī zzz(ض~n7>O5Yt!Ekk+hn 6nLT;u:!\$I oSŜ򗮛]^^Xr^ Uޗ&-Ncrh/6mo{28_^:;;yX`^{-{a_zDW0hnn[b +袋No~!zl|&#A(~,L\wndt{Oan<o`=aU-4,sw]l>i3ˏcI|cw㩧bɒ%<3|39s6mg3 ---viG$;Q墦h4ʧ?i6oL?˖-c͚5̛73uTZ kvUU4]/`N}~_`:EH7sZn;:4ͲtRyg={6w>'O@ {ZeCc]| .dӦM,_-[|r.2RyGzTlPrj T3i.yf>?lbn?-zDo0 ~)'^;OƳ>Kkk+\sv=wS[laʕ,Y˗s3i$S}Xê*`i\n霳 ˗.ɍus^y^J{N-KZa2)l3Doג^?.kt0CZ^'G @׮]ˣ>ʤI8쳹4w&p [$O<E0dժUر2,\í_`)et8 ~-~،OlV0&@L*ó)r"^Kp 9Rl]gg1r?^ct^xPS,nz{{ :u*ӧOI,ː<ʘlz/nO X\TK0h}^7L;z,:+B]>6m6nw 70e1uTnFFFGXl7g…|Wˉ!g(ජ?J':M?P95EGbE v"s+n.cѢEp D"nfY---\۩" .U"Hu4wM\*AeX Hy}M nw$m}A8@nfs/I&A F-W֓y>Χ+tn丒Y|7~FXh?O>jK?_nE1{l>4]k‘ΐǰK6+-рi&)\҈sOzm; x)?^j_͟{ 3<\bԬfs'p8LKK sy}C~T.םSJ( J\9aFbFFx}3DO8{[z'zN|: p<)/y穼SN544 ^];p!X;u2q…M IDAT*>L6Ii}\'RAud>juFE6Gc*u3Z8-XG)/gˠ"Z-B4`0xH+~~r4ͦˑIc;Ujˬqga0|AMjm6arasw #o38ɵ<cVgj!qx^W|a|>|>~L6ĕkdFdYpCCd il0 dsY6Qq~R&AjdU`8ɋf2P[C嵔yR&'C$k*xWv^o4nvi<]4Vͦ+=yFY2UõF7Vֱ!̒pX \p8{kvS[[!9[2/8-zn0 (gps=TSWIvft .~,}ϫ0"4r;C8`P $CQSWCqYjw+mx3 ǎmplFmsyBP3 m,ϗ.2k 7Mգw{hh2! 48qkz8zc,Sn)(m%p[v al|0M,r/nr88vLޅi_pmUuv6DCw l(06* KPt.߮ džVf#w> ;ik-k֯0OCȭln~^-9r4q\ Ӎ7siQ$_:+] mw2{8Ct"mb_M, `^  rFzJ=G8S"";=nhÀ@#/"&e]ǁLd.πcci^+~c=0<յC̾Zg60\Ar \eS.HƠrr{/\&ސU$=2ِH;R [ˉ&}J|*Eomlq LRRʫKgŽ6sԖia{![yWyMZ83{wF~KEDB, p+? BXQ(pfH'=WiTȱ$O1Sy9ӨX;sM"uK_~]9!4*"r81zy_Ɨ9=33XU#XX(0TiBDS2`mPW̐,o x]{/(""G $ ҷa.OgRKM~@ \9KaOm$""""""4""""""UDDDDDD2黳 ItYWK[K >LeG3JdE^nc9NRaNx ^EN8Ip,"exP}lGlK{i,<9LS7eOO~T C|rBq|!y7Oc%'O.?̆|/8Jn~s\>gLMaeAc).UAjU|Ө\G>.&ם*&`HDDDwBN~|r8@^ǣO~ˇ.Fw.)$J: ~suXz>; ZVjȿros@DDD<^nS`b/"1w>=}Նh_h6|\(B1#] W۸,[y>?{wM([-+t3߮P7xN vdž40sl=xS-qVfXVǬ9);I{b'emsg. \0,ܞ*fTV)-S J"N<8"hxP$W} Ϡ^B&3gV¥e"""kaAŹ\<2~4Rpn%1WFdֱfgu~4}.W5p6}lx4[Q8_m_O.j[DDDd_*k'/]I:>)`vE+Wgt*<9b`c͢C|yd{Cmⲙ AgS|_dRd:oAIFpÆc7}ryUف*G6/ u,#2{WὮXlO\z/Yg2Reu2*޿iQ՜t9!ΣtR^S?Ri  vJ>0&s[^#}û'8bOοG[gӪU=r_hX``ӕ|ۡoxwz9C5/]9_aNvZc%l{Nh} lm?zw_eRkar8i >s)F%6=Ԯnl,(umDg{:̴d7([ؐa8}f[荍>'x aR~tΑlIgK=/vX(IKnaF6'B)oو;L ݻצ9$slNO-VOڌcauǻ XULUwSQ*iKo{W\p#w]l)2 l}t[_xMC>. .ٖ$ؕ`2VImpJ8$SRg \Nj#qy  O.;@<0;mgl|l Nn 54x' F ҏ2mx=[\J]^8-[ep&"̠)ث `cl}t3[SwMT&k9gKػ ؔ[) J$jڲy=w*Q*&[OHہCu%,~;߾r|&vqd'.|n{=*a;y2mvSq,DqwQOAᘎ}7}W[ASN}m,5>/'U9B1M"]x8NtׯYswՃ#4US5 lx"nM\ո{=o<ٻ>oXDi߫'XRmm_dC:ƟӍ/r:`߸q3yS &wC>s??4B8V6HU,pcTXQP&!oȮm';ZlW>kk[/3]2?p3lgz v%さ5SUH 1PC;= dG%"~jB;`oYenu~W6\7P䎁^B^sQs+pw{08991-rFGȍ,ǿϙF o {8*Ȟ]Pl{ݣ\4f2JΈHasWqw,ssWk^E=`]w23%rˋ_Co_pT 3#!{u̍x$Kh_쫘SW%1~bayw7M-=_f*"oSZs4 H^ |4üoi4[^BHw#+Ar2T}ϦƻR~g< ޴ċeoL{+ݛ_cc3w71a9 ?U~~lk.:n];vdholU(G,'/\}hX>[~[f֦~}w.<auce<Νkü1=z; lw2w!`̠!2a y,X~]x>eOyg ;@)8)^m``}B'f>tXo[OĴh4PADD1q?2%j0H:Ʀ1p o0(5o$MpF9?NYsJfCQpL?3&_O$K(T4L ~ WnPFKܳ'S5lvPwM0M~74@1=eDOݮa{j{9+Xۼyn.Jl|/<̪  1\{i{o ^o_ c3 \G_,n>3W|^,cv12ao0J+_Ծo`:~Uͦ"Gˡ|bbF Xcc)xu|qq?v;*tv<(_:e*-~Ǭ4L&kWy:oxC*qQz{O, f> ݘ8`Io1l˩0X&Og#t*,~UÔoYWy:no~)92.NozAe qDC9YH2LG O5\j=̎.p,0&`r,ULgNL>F< JV NwE6&Ξ=v4ͤ:XCb@v Ffd̥qr#d3HEU4 Vp/g|ٙ"Ouɾ؉O0lfpp0CYh}K'G`8Byۤܝd$<`d\fc2cVQ.TIbXB(spEo O|)0Z204](fؘNQp@:|qg, ;;6I,9O0B&I`Z j./>'ζ g,W)sd4<xBY9VbFSce 884BR7)r/F!. `Fxf'2fa r&DbOtq 6 &VTpP  5ٻ;rߩ}d - D+HbkAE{CTx"U.*&ْgwO/3l6]B…|KvμeyyMrߋ#\ax )0vJƫ-@>D&]{ IwM C Y|I ! ^8Vrؙ7?9O|L>ON]AalzD>M .H>Pv73f~s{\u |y wxpS*WρNs gt*=5TPAǏc?5_KL% oW@.z@h?yA}õMxQQ] w8]NG߸b$Z JŅg^XgW Z8*@'m=GYd!uEp҃t[HnR`+v3xyunL |=ǀ=/?N;TfZg%ԘWQ ]ؐ]x.?x6K"NWY{Ao}10tj+/3?>bHWhƏWS 1ÿ壄b<C/g!BAI(YU`6._ sy W2}lAy$J!`OgM(LkABǁAgtQz?7.vHM7t-}\PV9qn22y@\>8aid5[aKk Ã?g "[ir[ q~E;SHq]`z`;1P9q3H zc@]r݅?ZQ+˃tlPmx,BJ\Q@5PKS-^N40}< !>Vl)J# qOЩąɞ+>8 ~u*z=zΠQ\z*+9%o)8vL_ -C6PQīhFOgs*,BeT^@sS;4viE]T7̧<4RrV_[ {ǫi0^c!B7M:"Zo{?3 IDATi.;TpGi4|M7Vg]e7+8 L(g՗y4Q6&2{f^6;Hͭyh +N$ q7U\΅*:3[ ]wqR2O/~IJ$?珻{6ꊆXB\ֱ|!|77~5M,*x<8wqUdzmZ@)ƀc7 ZN+#1N5W\E`:1!Ppll&{ұ p^<&mMxAw4ݵT/0^IE}ۚbj |>KAs+Zq6DFƫCER|>qXQ:.DŽB!;<&jWNP߷]qb¾0~K]ͦ%i%'! .WqERоz*9JQB?sթgU-tMޱzya^sEgO{g|?쇹XQ,8=fpCT "Pg[Ö-y0c//aeX94_Vvl.wrvyF퀒?WϞGY0'zprc U͵;6i4>~R*].|(l΄M.-VRTjp﹕mf2.Y&{ l;vΩ4E9Z& [K(WG#\uO^ï7:og5|]P|?u_V<p"ZE]A4C.P?[re/5cUbِy9f)QMptjL@|s(4E`A+Qw5]0=o<Ǖ𱚒 MNpՌ?T7^9ڽέ4(S L'6^l{dXOuOqZQWJ9\^ſ:=A{;YL U SQu*R-Y|إT\p;O3.Qf}#@ RaYM*v޳p u[GW]< $Sg:GQ$V!Al}唻KZ!]⪢!EVt^$6t3%>/aC\\axzm 7%[7E}s:r K@t&"x5EG/Xv0ܯwB!]±n+.?naYr1?l../?"ogC|+_jS>.] \ :o['֥JbA|NO){s~sKgIr娙g >/_5 _Dcx'WW#_{;//:e :ǵ vť;`i9b.܇bƠm~&lLk<>0Eº|vĉp*&x˸mn"C1W>210(\x ޱvl+0J7DRU_bN2J(wy_;jBy|*~1.%3da Oɽ~ɽ^ #T |oy+8ՙPvJ)q%{>vax56,>ܘ1̥x|9,Ԍ.å?ƇB!ϥë9 m̟#ޭktチ'c{-sa,.|Wt?>NRߔ>0y07r2U[ ||̃\ӪJSOO,j{aW$n|-ŗ*;xr6̷K6n>ymheA`K <8y%We3.1LθYs,3[pc~ϦKy$I $G"ѣ9#9>Dƙ} 9E >I,/#ѵ)ߑX#}~9Ƀj#o8?8jEwio <<ΧGb`u-M+;_c`Bއ5@gǜv_O]3~ʹ3Hq_%]c{`[XQ=^#i9n Ze.8i"??z'W}?IueSjf-41'axrm;^M .T&]:w >tpv)jlp!Bd'_Uɲ{y8&9]!BW!Lw^KYk/DQ}CE A:6Ph$$O !BW!Sr55*yײTv,UJrC~+w/b^i!BLOt)2E6LfȉRaj ĒvdirF55sYkvL CJ|}S$O'm q\MB!$dl;3 W:9!i˗/˲*)^R,'pKL)QQہLCU,*H].tU@S ..S|1ZP6Kv^Uy#unyU)<˔.X$q=&d:MuLSTd:卭O1Jb0b2{1~17Yy6mb֭viE,?( >NqH fzjogcvEzl4V) 9fUwAܒUxxa8ŲU0˱oڀo1WU [TV,z闷MQ^</o1y=&)oc2:&)ol_iyc,1}$1ƌ17Yy7p7x#O<| !^d9!B!%I\B!B<Be&/xM86Nn`lXhn*;G~(I!ǶT9|B!Ĥ䎫Bnb#s<*:8nɷg/ Cvl7 l'_! %"BH*B.d)$;wHϓ(BQa!xR5`#KIDM5p - BI[BI\dpͻ]8n) !BÍ<*,B!uM !!cAbm|uRijYlY ϻ?u x'ɮ{ |^Jℳ ,*tS ߗ"dH$uXrL9"׶lھ=*#;Qlg&=ؕ^v/t`} sńBęr?Fn.VHr-?Gj|/i6" $F [?@)3-dz'ɮg9?Jv$tpyA]J9Xf`zw2On6R{d{D g}Ԗ$BH*R! sXo#aqq:zgN ncIf; &L9In{cC$6{В"TwvvH ᱙o;31XsKBV2/n wߖ}۪%8%>{0(\hgx7Vz Owa/Ka c-$(XtF($;Iocv~@xq`|y%zImyoLJ>z?ay ؛cmaUKvgp=V"OHcDa4ʃ8ٱcɏ>̓@frRY9BI\%H]द.+ X {rE^D?fdܦ5X_0>~~7bwl%,.vu]$VOݽ?z2+Cl{t'lJ~p>m$7z633<ΥItmǎ/žxL H&`xfPI:t'hoJ>;H![U1}(0|*&JI)j~/|; !ȬBq%'،RUS3 i:9SyR55o$N.p*aeqv>N8*e'RdȊ ws7.&8wn̘kbDƼxQ"ۃ$LXr*?}<ZHH0)GA)Y~ZWpH& ,!۹B罗3.,_党?p͗6$$/W ԝ64P1ӣQ"ʓMɹ!BRrMW!EbiGSv׼v.bg2(-M_B0~ɣ us0|ALU!gQ~ɞgtb+;8@'rU` nGp/Go5^lbq/b|vGVU݊;֚gn0:9EHYC cc(xh%B!B(\w?:)M_/[߱B|9p_4 3WP\:jYeglTjQOFeWJ4KY9*N}Kǥ7)2(* *էLs*(GwT03vc俱u^]Sp;dž6cL}+^O@p=B!$B!6`'m&z(ގI;w1zcSJ+`{@u˔F/?94N;Wq<k>v(b.ޭzt_!U!?(%ՄV+h8X%[ JyP4?/{p)Kut_sz *Fa>ȴa&YJPL;2Q+|'c98TEw.;?ĻkqX}8 la)8.s5nF-bo$ 'aY6'K&w 6н!xDz;L!~.aV@H]\_֐aBp> *L>s{~Dx7ޏ,:S_3ˏ?4~u Va|}͒9BI\/OpSĿ[dT\G5v)iҀ`U?mI#{n'~cfnYs-l{ 6Di$QsV1hب:Vώ%Ϡ8~9BI\PL?J-tud9lf7V ѬR ePBcK5Q ?ˈf bUC 6>8LD,>"<6YSM0u ㉼%&ghQmepэj 3CL}oX̓P2hZ2:VQ`Zc2E,AT7yCFUS&_GU1J߂5Ek(-LZw#BlUs%T]f8_=2N:$(5hˏPpM߸۴lփ/@Ȝx(BI\Bd0N`ni9a9)eP# \woD@QpuaIE)b9ɑw!\}cSVNX&a 9fUwAܒ081r8nT}f)z}9so> `2Q= 4\}4e|y$5\<5Ig%$@ӗ)oWs8'(N,obRȊ&5ux\U:ѝb\ *|< &IUP*N>'PV&hLH?S>v|+66sH!U!oN.AvĿt/iO=ڿι`Lrϱa C࿄ZrG!B>ȔBqR W)MkS֯'0k[+B|V,sl^|C!uB !HUPQh(}IklC"Q-dIY;|l-S^tB!$B!  o}7L܄͆8(OEu׃B!$qBqH@;ރy擓.C;ra2B!$qB$4]2ylp M `ؕ&G^M! !xA''oyr8eB#sF !B!U!B!U!B!$B!B!$B!B!$B!B!(d9P6Ų-ۑ8̥R)!LJ&H(cN&ZHeJ%'d$2H&I$:ib96dcci\nt)-/L^ey:O'KZh]DSԗ- pM䕖7LtʛL o#7frXE2/bRTˍ=1qqWEb1G}Ig͏&GYQ:*&-v3~RM5{&eB!B7ɓyGzӛ Y)͗ "}eAv;:dc|x4yƦ <˵jz`uD9sWiFrfV,Ҏf$nI]B!$94VvP>1!u drbCfRYfߍ)rʱ)dHvӞN37%Y#8yd`6cx($`ru$RqbNetFVLtO93pUHbW^·<'I43bj$㛒\3\؂}W"5ɝhEqJ,&]tz;?ģsAx!E/OvgG:IJB!x&p MX5Kpk?zeRoXfCЧ~5?Hov~ {g4])q89;MnB"h(loF cp\b3y"PGp5NaYYv3A0ZrM-|p)jz'V!EWUE:^G+D 깋'w*hޝ[Vhcvar3'}񛘭\2wYcR5Z2uWso>=/hhM$mdle%oLO-7񕖗X-lǭG)hr> !BI\G'Xw=?еbɛ:Vo2%'O.O0,~d6%ژIxbOpO}|O`\WYZJ*^IvwP"ӹm`3o v/-k s<fE*֧.6~9־5^w>V8dڿ z͙kT/o?>2nwhP7` :aP otq^ˋ]NJS.ys ob>{Z"rB !BI\K?V80MHsSz ki jLuo+ m}.v3xke٘ {{{wH9"BH{ׯ},o+ 5pEI'c;B .?@|˸6ZYo6瑮aB8Ng,$ʎ垥dTT^gs uϏw>x:⚥vBz3?mv毹 M q U~PfvampYVTx'{;D'}9͌p 1~;tƬs >\OÁ\.Qt7;L I`/B!$q= i(zLb3bCkoI79M F.Xd %?lZK+2n^o ;ҫZKpTIf0D!Z\fGI\siKk'1ڐm'ӆ I|fE+H2uto57әMd8VLb˜҅$殠+cm|'9:SrdѝNݙA$8٥-渋V޾4 oaW Kنʉ_hT>O%}Hf_$Hػj#Y:^ŏ+iS$`R4Y\B!(&8lޞ֧lȏ(u -|J>&[(l76DzPv??b.I,k-3eiyeRicPv.sMk%ھpV;< ,qΚrO@w}۠ԆH4Oɘ[%sW$ZJD?^Of} lA|G ?^T03^]jhX=Ԡ||7]B!$5H1rmSpǂoOF_{|ۘ)@f>;OOYߋKE0@"oIds$ dz.piU=!U/ 3[36t9; J MPA{' J#x }b.}!N``#vOrbΫ>-ӃtsQ%NFdF;CiLQ ;Qe?]GUrޛ Orq=w!6~'1rr !BI\,t=Cmd-ɕ,w PM5lK S Pv =NmS#K*%8`[ 9PU<:tAj^f`'#mhۆq)6(^\ר*Vc8h>gU=SȰ'vl7bݝ)Na(^aF1}Pi,WrV|vٙ-wqvu_~̝^I&=BqAz\Tmu~ ݢ+,+ X )6LȆd$y?||η_b 0~DDDDDEr[l6-cTo3f40cƵ\ {c+|a͝L!\D8=²l,fKDƞ}X".2M;y+o9t23G.=¯y u{^QHa0K.&k 5ɖ;v .ȥzo^Ջ*c c+y'E\Q["DHiw$SqF !_l/A߻MjJݥr`fv: *C=_N}l)l_ 7mF>NGyxNp:\7I6βgn],4 jy Ԟg?c>68Њ@ڑ4<} B+AnwiN6I>`ȇ"x<>PjTdG:!$xq ˲W%91ozw8LrA,9x'd4 n?Y}k261.Cȼ ]p@~_!d71f 6ODGV~`)K- iaa~/7L:Co|\I 2d0  v Vgs/V? K&dwfecb ҎbgҀ$9rx0MV%GmYN ww^[Ls<5IbDz_.e~ 6T._/,gCb^ܑppSO0 /S65\J2"k5_};䒓Mj(~%[gMQIN-eVeheZMBx=5TU%pO>?"x4GMTllSM]҂_ɻxuhԎI7W<1.hdã*g"XfrH_^?cb6]p'n{{xEEωOՑy)RGGOw_<}k˔ŷrzpǒ1.>T{3F?WLż cwlk gspy``{ V/vR8}k}<=ON',xk$'RryQi)0&CnkEhw-ǟsۦ;,7\U˨v%ky,5_r/xygFN^q6wx5!6F*(_:n&s B)-2ݾ U; ͡24vm+nb$q 'gO~v뒎2<_Պ,Fu!BRê=pu1/w{>-G.$lmكt]7M&%dɟ<\by3lg>}?d^Iy2m`~d2)۰+C>'ﺤ[qSȑ$ə^0L54v1,cWnd6$'^ij,(ɑWJ^k»<\>A͓O4,Ź ?Jܲx1" DDD\~",Y  IDAT***ڧeaYA00e"r004fD<{ξɑw3Nܨ!T@в(qoro|bmYr!Z7Jo㴨%"s33|iaA\z3#ß9ik*ԈȾSȡL,kVyl83H&I{FƇt"NFFɮ5`Pt"deLt0ݲ䔡9l0Uo%KDDDD`6hyBduUa%P" ϫ"DDDD155Hb⪡‡"""""""UDDDDDDD(qQ*""""""UDDDDDD(q%"""""""J\EDDDDDDW%""""""UDDDDDDDW9٪onbm<5v|UU|Nana,'L{O~r6Q"q(N61k?%|4o!.l )3s7fzV9@}}c:CwvdСXϸDdC0Cxoc8oP1m'xy :*(q#솔.H 8(P D(:o3N˸}hQ)Mz,D+SՆ)(#W Ҟc6OHI"oq(3c򮏺7E%̟7J~z]uK+V^(Ǯj M-Baj}&%LN(rt4^"+=L/k a"~nv3 UO1i(>BD^l#7hšz/g1盧 9CQJ΢8˵ D 4LֵpsVdi WƧJ98#~"!Oq}/Dbf 54BN Ed?㐯Gdz1AGK?EX3f;;C&NЏP%L DL-.a`S|"E2Vsw#Y ,N?`5x ˱pz45j_R]ndd4VP\~D*6Es MQ;uP'M9s+hI6'2Gσc*Hd{)$22:BWWeTVVNȖ'3pG+}z%cc`8& \y\yO5 ;lڴT*E$!W#.l޼x<… uzNoys>֞4Ӏ8.ljbضM8ƶt]$3o<,㺸4 oMa,L:@AH$ULj}~y2/ C*W^Os/ŔN7 ,oq99{c~(-G2g寶s[ZZhiine||J`S֭cҥ?e…,Zh4z>|x3<%㖌AoO˽r vWʼyhhh8я~g bB.96g]ƒyڲb+3iHdک|7|foŋﶝZ93멨8۩3`vK"+ȵӨ5#ә4zя~x㍜|B9GJ>7>yikk#Nq%2k, 7 ӧO?8fH2$ciy;+<e|}q)y녺K>g"68MMMOYB6(aÆ B>3iV7>,g<N,CCCXBa~z֮[˺u똘:<|xxX|dǀlM 4Y`ߜcic Ae>J˼Lމab8e‰bXy3tH]t:P:۶SXlk;zFAKK;کt:=%۩zpŹ$X  e~Jʼsm* nC Ί2Q'h#qz ~~k,yʝGގ!L2c <_QdoiUٸq#@2|yH ̛7/| {f`Ek~kG6zVtЧ^E|˳uә7nug ]qu]2 Dbd~~RQQAAv S]]ͬYxy9z0D(Lqaզ #6UZv6wrKҠj gP߲w.;y5tv.ȶv%d!Ms<~MFuu5}O 83dҥ\^zK.Y!G3]#z~t U7cZ>gy ?YX*9 w3<ƍ /~k;(/زWYgŲe˶S>?)ӏ]bO!Vv'?˻ۭ8&Zc)E5TCky{KsRM'f6gZϤ]scyoyN ̚5h4JiYFceY),,5k0:2J{{;3f̠h0@`$=tz(:X$2]lr=t2 "E^N|9lXM#tvq?^nL&IRtww͛@UUդ7šP@ @8:mD ")Y=i>L#HMcVXDC61uKI1ěitl%d2qimm|>OMM 3g};Uk˶mQRRBQq#(I=u>,;=VRXC6*cϴ酄<uɌ ;s8~C'ī+u^l.H011AWW6l`||OCCa]lrxqY~=spWsN]ovr?cf);< q3ix;_I綼8cfY;ն[~.q G-< ?z[Y\yͩ_SW?1GYx~SwqcccTWWsM7M`C.O# >uu3Y\أ8ϞťW[V`Uϝ xn9ASOq1¯<A v׿f<|3ᤓNbv8Gl6K6%c>ojҖK3PWR ϩཟ=ϟQFq™dl=a{%Orqb˵T*E>qw]L6Cl"iqOh{wAnU ">j=8=xO~JΟWa|8ݿk_0o;43@Q)**W;q]2W !Mۋ㿞_CB/~gq\zBׅm!%q~ Y5sUanRx$?=kww7Lز@qVDu/ia6mOo DU]y$Gx9;ziYʂBB^seGYݜf(飲饛yu^>ﱹ*<)KyM9󏳹xdXluaQC1^;)[J(B1$Mp+8B!\ziLZ=?6ƦU/q-I/]vSnb3\pU=W]UNx|zE-F!K>60Gf r&=|6lUl.]TS\$O/xҚ5m]}Wƅw&d<{_4/4kq_Dw͠cjv4TXOCr$30d6zϒHضedǟԻ Tyȑ(\lca&~{'Wz.N_GOӸ:d&z{ .?O-J"](ʤIf!8No=jS;K˩Q[7/",qPa/ia00, C>g'Ǚ5>рV#:PgÉsٿ0'$blʸOu.";"ǃ l;:O tmwnO_ƙ XThn3XD%2YlaN0:ME!T&sIr 2g-EI"roVuIbw˚W͌RS'[%r HMG/-NDu8 P%2L o 7ÜUEːˌGp#q|LD3kZ 4rU1fdC~eR_{?䶲 yR^ A_ LDfL5w-+cxp|I%rgsd36p|֤81$&H3ъo'y2#1NʃQDN dYOǺqvTTI]mrzZEʱ( GH=`&Pc[*A:.eQEm& b#lXO N)fAEɑSOY""""""2)q)Ms\EDDv%ʒCvI6i٘ZXNDDDȡ[0o:.$i]I}sCQ*""rhq&ɳU [\5 &m9=}3pe\4'm_gRN\j^ZW itv|y.$3&0Ӽ;y%"""$of}1~r<%o\)'Tsfo,ʯa>"db=JcQ(q9\d ).&LA7/^+OEe2I8&7'qIDATɹh~>"""%6bK"""J\EDD, 3Tv20} /g0i k~G ף[64MLS#EDô DUQc.:^9KV2 &|>Ogg'pbU6A_:_|?gkN*Ў7"""WTTHvZ֮[#?¬Y89T1""#00f'Y/޵%KEDD2 DZZZK @  cQQSWEFmm-`v0 77*|Hgs}j*FGGk8)))qLT0ɫK.%Jȣ_{_~_/'!Փ%ˑdX~=˖-Od\yDQݯ!M\5dڵ+---dDD;oqԲ⹻ֱv}Cu͢!4ٽa`9m c֛=<@7> !n`݆ ַLDQinn_~^z?v=3fP]]JCB!fI$144D2u]H$8J9***.ln4(.e&6E'bԺ.޶8 q{!Nٰa~0rrtqbll C<'ɨDzU-G;dŊs 7pQ-Q%. 0^jsln8=+W/OӔSPPU m"p 1cR) nyB U~r4zYwSr?;v~7 %f`E^JZE3>>Dl֖V,ZONee%EEEXCGiUᩡ&>N8.Bq|Ba"rinn&`655xeiQ*;JӘ""+weFiJ3ܲU];i+ Щ( ˃US4t'"GD"eZڪQTh x0dXσ@?l3w y,\XBmk&"G6߯J6UDDDDDD}q5Uu""""""2)q%"""""""q9X*""""""J\EDDDDDDW%"""""""J\EDDDDDDWQ*""""""UDDDDDDD(qQ*""""""ǐxvU?^IENDB`cdhit-4.6.8/doc/Figure3.png000066400000000000000000004016131312257207200154110ustar00rootroot00000000000000PNG  IHDR=nsRGBbKGD pHYs  tIME 'L6"tEXtCommentCreated with GIMP on a MacwC IDATxw]eϪ-3)Lz$(`#XP^x徼Wޫb;GD9ሂҤH'}23^LfRy^;ZkzHm   H                )   )   )   )   "`   "`   "`   "`         IN rr ۲_}%IB4$IpR,rdٵmUEUύ  )s>P(`rb6K%, L.+[T)TUWNUUEVp\Ȳvs Q*) 0%g0MAQiRW[K[K ;뀮#Ik:.]GV<n[|   |"tt:M\&288. χ/Qxl&LO&) X2/lƋ187UU̚6;X8o>p*jjj_Qp`dx>l=k.HathjFDpZ[diHJe IJc$+d;`˔IX }q‡-cٙg2kLB PAAD7́bsϱfF6c:s.b…>ga`[i``Y&6e*"NYYQdlow=߳];kv<˘5k\. XI8px۟xi=мyZZ*?IVe=05ɕjKr/K!Ћŝ0:Š%Kg>Uj Flڸ[opes,(2=O&FuU=T²LlXOTg T*N648DWOr_F:cf]("y2[6>N,%d^g׋0_"*],btv! [D8%ֲsx{;CvhlƲl,iYI$YFe1KCtǶ͛kiabxXjy1s֬SH磺M,mmP[mzeKCC$V&Y 2s!|GZ%% 0I_GzN?8vs̛Oc`Nlt¡2==$7l`j{;MMMb!A0aSOҏ~wef{,NNL6)Xm[XmN7?xK 9ȲSYVQF8EρtGoO7u,>kY?!z<6n?KÌv[sf Xq'- +Z cd6l@y1tEAmn7m)5걶z)Ir;MX]]?1E0YF\y%Z8mHNGG7?|5B*HnFWWP:DC,SbwuRAASDXqY|= 1ǁزa#\IUVWSU[ǔi4 2U5IN#棴MX'( d$ %9_. ΐf?| P(=C!5՜qJjijʴ*ziimES9E][nfshll g .zA5k, L NԂ   Lئ5>avSBV$Y¶lr \t^X1[Ȋށ $AUQ,FQT̝/LvQuU|x^`EUMˮe73ܰne;/pGBumњ" `(3c,{ӽw/6n9w|$ V䄹 _|@םp ==؁wˡibϨ(c` Yc2xR ma!`lQyY&.)zV{òյפKm"KyxdQ#OADlLĜ+ݸ<"յf%4LrٌӢ)2B^~?NcT>?I]S "Ix'TS;g$xp=ض,ɸ^t^فKnN\'Pi_өMSZYD#8˴0McXcE$kjqg!ٺ*CW}K.$}֑ =06j2 kVî] Ò`\^\?e-[`\Xn͹n X8[%5]]9ߜa%0An{lmun7:1Mx`Bvx8<rY=NwWt˵+#-K ɥiM31_b!xntxM&}Ve;!:{A4K\$^k$;qtl,S"wb$G#rEk0ReIbV8L@UπWUhADa˲EQ1eRϮ-[PSg5$ EQP sb UA4Jkyo#ü[랧P(tgJkuB O}D7!X̟gvZ2l5Zz4sKM䜥/67״( Uz f0;f͑i- keIbPDe#X͗-I&/$~lxۨMEGϪ$QRcTݎ\U"`ìPjSd-v!A0#2T|r98yjXZM|t]C'}%Y۶h6 ?^w~rٹi#>O?(˟{8 "Hrx9gle: s:QĊDફ.p+VwA4T0㇔I:r<6aY>>YUQ'hqli$ ˢO0N85Y.=?Aۢ'3E%@"oɤٟ/I$1IC6;9З x(G/ ¤lYt<2V$mfVW4$܊ ­(LADpg2_g|ཟյDkB\΋O;mt w?E$FFFXrO2-UAtҩ$u'^{NwSUUE8FSe)\~~#l3V2vvx 98eK%' |NdN[*stdsY'\r);q~Jx'y~uP,ʶ=i6ebGy/N?.K-<:2h$YȤ'14<bt !8r^'jMêMrzQ2MºάpMPlYbWIALAxhT|{?`ŗ P$YUPU#'W!~ z/tSTgjpe0XYf%'@vvN,(F}XAO9W]x 3g:c6 E_tՉ ɴ2GZ[ o-8˯a96!INqr1,Ʋmc$Ke,lzyRdbXCmsO,IJ$ߟ[nK/ _Q*% T ϲ,>rsDZV)ԙ{G?tBZY ">#XÝwŽcN|1[){z_8x_L؎\{S :rT鄶bKceW*\۶IJlŜ–I=8*HL,|$MҤ[Af(IJ܊L˴`07}*ALAxlܸvt.4Ϙ( Ic_掟;D/qޥÝ\w?c{ ´wCC<<;⋑O«yoC b"MީuâEP[tɏ|Ӓٲv^t1,^t=dCgG'|JUfm9%Sg|;aҥ0zn:Bm8HЛq 3'cX3t+Y`G? Bie^0HHӘu4D„]G.Ik "` qo$W,mog̘o_)()Iew?To,0ڻֳ~o|S+J}u]l6bq|GJd_n~p@(p橬vZǖ8*s9سu61g/|Q8rXbQfhmf4FXt7B,j#Qnf}Ի\tT%55hShb+YIPADNwUxauƙDjkpU5T76g;d IQ$#~iL HcE+lˮtɲIb rp.О=tz\r%y{Yx).}Qhmm=mGGGLðd֯_W3 7|3k֬aוeTU=Z֮]?h@|u6gpÎ L^?y9v,ꂡ!Qj{QR)λ"GOK2ņLfO"P@4Y38N&NH pzp@i~M^/M^/S~g3QTR e %QG8mL>뮻뮻={v:#@_D6th}HpU5mSm˲kj&Z[ȯ3JqpEI&гBXXN6/>w,Y4guivbx%AYUUŔ)Sxrvm|C"Rǃ@?}og|l+"rv8jjurISgpЙD!DD Bit1.z;3ņKqepK)&; 22]4 S)rlò&׶%6;'б)^E#4=̋it P0=DV,#!,т)X)tw000۶@QEA[V`0Ȝ1 ˲F?o>iSRU]MGGn..2~aLl\|9k֬yUϹo>osw<  000@wO7=]tg$Il8@ylWCȴhb&-̞1:g$0mt7X\p:ptaydeb,NX$kY,˙64'QӜ87pqVUqfU5A]CPMA89LA@e.\}q IDATg#>WT.dI(g74fJ' ͭbt:M.C4"Ȥ>::JRhd"G?Q6n@__ͧMѤzYhX4tBQ4 IHJ%ȕ$A01li8rm˙#2!d_*ɾPF]geU*$) ,2jX+ "` pb蠮u۷ˍ7]wE(bŊڵk .;FBҥKyg[5-[FAHxeKJ tRO&O$I KeJMWt-_dhd!fSQ=d^ @ǢH)~?઴~T ۭ )ò,{9~Fo~W\/K>˖d2 ?^Nni|+u["2eq 7puױ{n}QId2|[b Z9j/ :a]' |l`(i(y`(EbTh[t ltZ>M9fn7 v`) ^MEe^+ >8Z/V\{^~?:tz pЎKp{Xjդغm+Rye2~/_q,tRgGf`u0ǔISLAWtO|t_{){ F EziF yFYRh̐a3J m=az^VF"Dt4yLj.MŧixU#  9Lnp6,:iٳgsN}ww7O>$1Ӂ99.YJT:L&3]5Nc" Z>Ts]T';a(go2IE:f׮]̛7z}ΝwI[k|n`͚5s9TW;]yzzzyG}=L <]ٶM*¶m DbY$2D0&Ha<xmߏG$\.|Axs~$ffﱿB$8 `XPaP*26U~, AڃA=F x D\.|J"*pJLX,F,#JL02t˶Ig2 ( BXiY -ɟ%j!ܺvL>,qT߀,.^M(!Fe;<.]W\,q| . rE_'J%;<"O<w~-FGϟ?C=IJeO\p… Yhb%›ƧtDtD\7Z,3 9"r{S)fsJ1NA8^vЩLhrsixh hh>di`u"_d6=Qo=p]p`_5Ogs­7p MhW:~k>7¼yV{3g477|eZoe}ly/ r [naʕ\s5 =t6mb  `41$UÔ$z<^,IU#i)(T}LO|.8,Q;ӳITD5 o8Ls[gy&,I|Q Y@T"V(,Ȗ ^#do6öD 'tNltpiuZ.\."fLhh0oO__w`a[1HNv,p߾rO}akW;P`R|"=ݰ`s~׋P[UU/@LGa&|sc\~娪i'.c-mzj>oN/7nއf n^/Fm-nYQdI@g`Guyݠ[0mia'tΗ2,$ɠ&R)5y]s_$%R2AT$/;fW2xգI;A&O tmNEKp`Y0ubL:E~SҶmرu M͸nx.m#2l y, ɶt6~7?`KHӘs&3lٲK.G.{YXl6y/cz<ؼy3;E<ȟLwLw$Jc6H'q'U[=>l2W46";=~U,bf(&ȿ-»~>|^_!M?fI\&S..HHyndGclI$a(< tI]c4FM3UŰF :04Ue/>x%_j1 9Fa+?wjސ)+ jLgy-!jkk I3f%\veD"2aw|4M~ӟ5~TUU)K\s?u(u\xe]t&s.0 ,IJme&mF_GXx]ދ(HhcPvlG hno},V? @cc#+Wk9srJ,YB 4M۬maO=ԛ֍V+al߾'|k2sLwyJM*aYp~G٩mئ[nO%Z^ 54:߮]⪫zq,LM0xF]-N!gR8O >gw< &|ݒnYajF̪s#UU "` -F$fϦajtækwwfYKhuMMi3p]N%ٱB@tm$,<&j6j_iITϔe YOaI -lݰIV/=/}*B0U lY>ˁ8ԩSYt)>;wgʔ)uY̚5FϘia>oc&eeYʱtwwsNmƞ={hhh`…|_L&CWW|S*,4sϟ|W _mftTR].;]p:r&KH_mvzk67_ 3l< je jj|T A4Y74̳#~`b)Ib$=籡APT5:UeV$ZTpvm u@DNiZUU553wRJ"\][6s`6=z"8`4ʌnmSɴY-<^EuV#ˍq-#;ǝSB.ޝ;*mm;C&} 1G*B]S3hm;8=#.<~?ny:I"H'Xne}+R,P(隣+VP.d}݌0<<̙3)Jq̝;M4iӦx vmcՆ$Kq_Ǿ}( ʎ;(Jܹ\.Ǯ]p2uT>l>v|x^E!͊p p7KеŬrm#P.u2/2?x+2o݅>e5RdD޽6y<d縯YB] 7tXH7Kq\N `Z0j0w W.#aVvh0 $F*$<܋i4*kY^WuTyAL,l]#"INږVN7AT&>2`ar (y?Pe>4j"120"xC0&>:BbdsXtE}KxHu-Ѻ| 65u44xTˠdYӶ{Y`8̕W]?^wtMr-vmT$OiYnۍ$ITUUpBJxuكfLӤUObhpL&C$L/2e2mYtwwL&/u]|qL$2|/[N$EQo?uжb1f-_ /︃\v|fEoׯ) EX ]ޅ ^|1:gJnk~x%sd 3Os*^Ů.Oth|>Ӧ3_E GliddI08UoxΟ* o1c-fE4I af(R2RN3APwQ(L88 E0v>.פcz͙m[B(nGw>̮l9wrv "Z[7G@V e2ǥWӶqoIQ444P__CnG?QtRAs쯢(x^1$Q]](yǝw9~yYQ33텭.,u齈%`&[/hc^I&I,7J4,J[",l輪)?eE 8is<(*.'t[H$ҝ".nTMjOR[[{Yz 7m'$//4(6l0tJ #bnOp w$%%V>M_O 8 5j!CQsQDD;޷+tUɿb}:ifbIJB0 77ô:?!$LӼRLAtP|>:-k4GmތЦ~? /΃hjp|Q$$ff;%'sUi 1U%,ˬkmeYS3ճY(PDE(g0V޺ 2ᔸӇ47w@p81nz$.7x?KngKZv6@_qCku1HG x4i<oOja38 vikkW_?k% =I#wޡ+|$I3XlߺqO$ᥗ^;@c Jgg'W+dօRߘ ƌod[TMd HO3ÿk_] \QX]=#SJjwD ߆uхXSRIdx~1$`il |)˯ slV]>\}AQ1=llPSct@'QĒVδۙǽ# 2,khdAcZ5 l#[dbXY}pJv6ssp )bL4j7g_y5_s$p?@هK/c(7E2nN͛2Nrs"9N dYfL6B/^%Ibݺul۶?񏔕._{+[H$-[s͜F'w^z IDATŹ4MifBС "aJnZꪫK;vDtf6Cq.N=U7inUebhm#deݎfw`rmi!CɡmѢ;~QX d7 \]j7m@Gbhoхcz&աM&)uGZ'.("H.99LӇ4 YF7N}&J2#ljm- KKf2*=}5077>~o)Ed &&̞:@yf'N&zq*Ff0qOD85@4Գ{}3S32937yy IMAOJm_`UUETTaSsnҢuҺznPRRۥl 8;zI.ѳl1Sd:h}@N>s\vmfcڴi\7x;8iDC&,f ʒ%K8쳻]gLu-EQDQBk.֯_3qDI$+n|+[>K~#pyO?Ζ3=   v;tteBhh .Ͱn-ߟr )PUӧAa_?՟=Z)a]~rK4p)w#25c21%+YSx*Jsu:tM#r˴(3w8)׉s3O6SdQ5 ,i}uTos (nX.Hi6#ůQƙ7aeYuOUa465}v6mJ]C W\DjzV8LL_i) HD(dg1| DVf&Gr!$L&&dNGp裏r9Eʖ-[?0'N$y׈F3wi4MU^/᠟${Bp0~48t]]B~>q ~e(@:'@4 $^K):)>6KREDn¨$11+ EUQHX)OO~Sϑ!AQ0}SN~7z4~YfI]=KX*W?P;w0wvX9yUOÁI11`LBD"X'TYG*غCIyLfgfSXԏ,=j[ ) ٹVvWdU46a3aD&I(..jbz'MI<>=(7xèipXTUur-UbX0͇-c6EvvŬY6mƙgI 8~rG2_&Xh0LCV˗QVZ‹;C 9vVCဥ>_ !nPzVru(סkrzӯ/YGUSֵ<\Th(}.iG\:wոp8|նRg-sdpij)KME@QUƦnG4ʸ R-fT bĬLILLbBJfb9SX#@s$’}u,&~ Ģ,=ܾ\!==s9+/i8&X],zhoyW_G3l~?P:hfۚ^.+Bpx BM#EOT'/3Ng9P^^vjH ܂رcYh\pӠWY__Hl4el6fϞM?a}MXh;vgڴixz)C$֭T,z$1jT=&IeP0u˖e(]v7'nܴtPkM&HK߸fQk=gH[A;9Gz ?㺂< w+cw!Rd*[0PtG$>CͲGKV^aAQz|Xm=&v77'NI0 IIdۭ;ȚFB!D͒O6Rz|>V+qIq;XTW]ūz&(_ `sJNgrAB 6 :9,˴ <3۸>y0Iߊ(D国RS8sF<Mus誫(((8l67**,p@R$UQ },Tʆ@U6X|je˴78mnsEQhii.)RTTD,\sKZZA,rJ`||wi_Oj2y$̝˦w/[˾ݟqM uy[wҰs;f|Ĉ-%XOrt>;~ }BYRÚ^V 2_#If3B󘐙?%$Rp&}⩮h-mmz/S5:}WUuFP5~ZƆ vI"l)IIN&b&JK%fEV5 N]NLd(&ABF@&'109[.d:iK+aL,ʇ5|XWdr~pz^.)6N!6OX#styrףOp8E"׹a-)PS8P{o:Ξ5bcqưr^~-:ZO{iZR򘨫[cBrj]mz1y\r-(%|BB#AZ7nߓy+sxC"GUU1o<ƌj{+WrmK(.,L4?cXp!6nȿof3INN>}l@QRb{X,Λ39iC=Ėf":ZZx\T]#:묓k=lo=]Ng\$%$A5Zk6} f 5f?]]pmqH$BSC=+Öklo"'N75u)'Tݽ{>t `uYRRL5IPz8WQ|5@Y>,9UU>4ݏ[[UjhUhiA*r Ң(AyDۣ. wS~s- NۃMd6b5349(prA$ (b$Ld'+ 0)3IzD9;^ճh> B, ̚=A`\A!1;7td!6O ygtnc2D"'Spg?cJri-8⡇bχHZMn~8.. զĉOhTNҳpߞa[ew)\SNeШEIH # "XG'X@ TI'2w\ģ8rs-ܹsx<9 n7nmi 0qDE!??z aFɄ ())A9 Ό3Xp!>SN9ǓIQQ6mh4#Fee%uuu̜9[o8GIqq1 yV;n)SP_;֎SQ`zHNZAFjl5CAMMo6]h`BaYX LEѝgb.0=I bb^$;tz96C/XD=DԔ#qNLHS(D] HLUdb1LζvBr zԫȚ|"&4&DN'eNNi3H6$a5%ɄIJVI'<x<\_6hay]mlCu;L&&pQ~3HȰٌAӾMUUVX5yKdle˟e o2iik%9'>yd%=;Énbt{0[vw;kD%BA l`2 dY>px FQ0Pp0Hg{Kg>LȔ)=zj?/kOry뭷?>hlrrrtt9X,*^d.+%vf3 toGUU$IBUU~?ABݻ"SLᢋ.8H0qp: BŪUgѺ9S!°V;+`T}@b} JvU+Ka(L&3:,|&M1ct!@E.wD3n2CNv; HC4EW4JDS֎it4Dh@HQϘJ%~|zSHXSrSr#7Di6"\m(KYT[˶v´?v6gsaA32pɴ cI`vttp?9߁&핛y_suqe8̆ {RMjNN ݸn#MND+NMjaua ҀX4B8h" ƈQ(pF:[ uzuvbw8(03/1޴i=?OqR{ UUU,[իWS__drv NIp:" D DrseBchZ:yn^xMMM\z%D>MBɌba|ছo6Z F۷z6UVzimnQD$$˅h6wG3-N[OG=& ut詉(pMdFJJKɡo_ʰl_~o۶?\qL6hQ˧?eW.Z[[ٱcGw LIhtb>qB`~~Wp8GN999Ӈ2 B߾}Ҷ~EYz N#G~wAst9x`ReժU($IL8hᙧm۩ȀL]%'B#=O=]uu'؜cN[Ͱu+x}POGw(U݈׫ ̊ }Vn쓗G4k^}F~4twqdi hDc"(+vFL,Uш3rTU=ufchR.$Y,&f I$j*8IXnm-[;XB(_ %}IYYy;Fcf[[?YSYct7KEO'H&N^{y*Do>|>5~ĸ[cSr;hMJJ 6ZX-/<[ծ*#}ٜ~68DxB!m֝ŨsiX,ȊСC1͔IZZZȌy(++c֭kg}>3fU|̬x,}=vv\HKՍwN]pAP=sԏ$l-I{A_H q#!UaNd2agr#o, Ũ {::Q5P/Gz:z"7iz >V#SIXlG<-X%T Ʉ8KYw/k'^~(pq~>0 %nGM4n7ʘt2hx9ٹyk]FE$h$BlX1[m|⤣/lp7(++;l2cZzƉ68|JKK5^OP:ʣ-+rmAVXU{OuEqEq,]ʮJV3 b Ţ&n/C vz^LbO_<&f@[.*%Ua6N'1S9j Q&Nωej_,F} @{8DO7*jG+ ({a]|FuV]Tz-lt1"fedJ 676D͆d"j-sqY?.+cCkձ7ZZmsc!;>qj5 cqlٰ#GS<` }X d#SDQbgQO7˥Ȳ7^G5 N0Ρ''5[(pth@L(jwYYY0p rrrhp\IF=%#-1=cW(pXv>hT$I)dY,%%Qtll6[p[-lZ4ӈ*gME}[}Dm"gpC~ssJ7y |صy3U711&2vtr%L $ xAۮv6kPw/̜kݻQew`(H*,X@cc#%%%L<Ç:iS[[ի`L2/~6Ƣ[w}.N;4&Nx;3H$f㦛ngNv9!Cnn!H` | hL(D܂(p(rHr;$%'cٰXE]a IDATƏ#"˺ea²73aOg0wDAOWς֖;6IZɷZ)tIX($tpRX" QGm(nBar gaVA>aG5 L]el6O@!Cao-U[*XBnA!JJWZJX64UET]p*}$z}AQDQDDkRs;vRk-8SSSP!ܢn #5C ࡇޣ'rWpWκj*~aVZEc^\}ҤI?a׮]ۼګl7 .dĈ<!ӟs=tK]{1Fq ްXXVᐤA%aY5""Qj~a6tt֫, ױZjJ|LL$ \.]NrrL(I"b|>MN&olYfOG;OuvZ]=ofLV3aχ$l97گuoUUCư 9 ^N}m-M44 ,X@4“LJzE%%d!=+7L \f @3FGtUu--ljk=AQUZABcTUQeUckZx okW'wv|^TUQrQ !d1jjSaj7"UU#]P@n~ȱ.|:;|t6m`MW$ rl5DA6Lb$!8vRS)NNMc_0v3b{b^\wMJ:@d$G|#UN߯`2ֽcFn.I'a-o<^ IIG'I$ vv B!d%j77ZWBޮĘ-Vܩ$yhd63x,v;as8X6W!.5MCU]|پ};  vgu}zfBPݻ׉WHj,0008HZI=hrldul줢Ϻ `B!06M&TMc, t#Ţ(( vڢW1AУi*C| qk ebj*?*} Ui)** \LOguݸڂO Om(DER# zC($as81$44DArb2`-nJmNGZ w^zК!Cm۶uo9hڋ!LWW/!b1me_3 NBHNV btEdP,Ɔ6v!Cճr{E ;9p"X l6SSz3~?D`e+q2cE{;1'M4ZqjnfuE LN(̸hDk58"Hv*+عχI2E/Td(,KnV`((( 55}#;P7PT}uٳlUU%##", XQGaX)(,awPǥ;"z ֽ~xn;=E!&,TUUFDQdYcnOR;d_~k<{dwL~iLIYS_5M!==@RF7 BQr2رʢ3Uxz7ĽbSRiM8JR\l9k@ˣ[#G2&3ߴˬ|aWWڏ?m[Rk>a$!$Rlhf'-;rh@Q43QDeZ Ģ]Kq rs6|8'+;wgb vEgg' dee!J" v;&q#~ b$#2@X,jcRZZJIIq 2k,/^Lkku]|' 4{TnFbמ=l`@*++y<%%|hDUU;vTWWLID$Q")) c+QTQ;w.zQUEYYnjq @Vfq !5֭inar[Tֿ?S۶-Suiuo'5ikU!5%7LIbUs.8'N~h {7OEin0iUֲNarwh]bXիٲq#$FNQ1ƜqsC%$Id I4(b""_(iD#Qd9 }R,EQeTE%u{PwjhG75 (*-eرL4'&7֬Y||@("55t1b)))qAl:yAd2aXy`.2hMݼC$!CQ [ F4e̜93gۤ )Sxb}NJnn.555,ZO?Sv}s=<=p}}{bdsg:Am(+>Z%K44(#MJJ8f3fq,#uvS˗ޠ K̚5iӦm``ƍ}vJ J89 _ϳ@V+1!),o>FsyS~_(r8hDx|V}^4,*Ay3 Of%qςw0~,n2`Z qqXDQd6wTAiǸ)ӈE#xXf5w33xH5?Cyy9?IMKbe"5 UQ&qsߧOˬYz|'?aر7Dꫯ2w\ιb~u]6~_1sIK,2L\v+#pr 7pɥQeex#~v8LVoTm$w 8fquxYp!W_}qߎ߱xbƎ=܃'Ƀbfu<ڱnnwl93?n`̙}ݽ5008:ܸlFcٌiU9kaZ~($z:߸Q̤7W2wn= YLIE29|'_,ƒ}u u㡃K*%|0{&n u3Tٗ\JFV66AT$͉ibXp{ r߆h ˇa$bʿwdw{*7 ¨tӶvֶQQ≉u:yFUłZDR6JSS~@)QrLѣ/$^پY\= r-7IvEٿ3쳙:tIB? ȶ X0UnȘ駐d44Mcܸqlܸ;wN+BMM c~;WN<7Z^f_nv8`nH`@i7c j*.JKK$d„ XV/_~=Ν;7o[neԩTӠwʲ"Pڏ??[ݱ23RRdA$<%hi.# 4U%B]k+("h::Xp_BDilt_R©G3eFI^^^97õWb}s~z cO74rmj=(\]ܟ; 6 ) o@Ν#ISƸuRkU1M㒒dlXD(2"=T>./vu2W̜<6 ۔\=e>I7]<<C`|#S_w/ϙWv, ?hmm'2yd F >"G4TUEdYf׮]]UV]YgŢE_Zd|-l6sRUU<@$aL8yQ^m73۴]z[5K.$w^&B($&7$ 10qz}gY%2 1ץvgg;<ܧܧ o_@w|>φXv-`+s=͛75E0o^Y[0 J̈Ĝ{?1zMkDb2]:Y&Jsm-OWU?-!pB5e s}8 ƯEI.UUug|42QU0c{q#33xjƴH_o[wᬰ,+/4G D|;7 /SP= co A6^(絊 &)=k&?_ ;[[LI? "$8J0⿵1i:͔ygam+:F)aаdr/FfN#g-foyȊ+%v?aP5p3xy磮}hih`=؆db1Ã|+E(t&MĤIcݺu<3۷tJJJ4h999 <8_:L>sBxuu5ݷ]TVVqc5jQSS]g:5kf͢5kr())!77\7c7"}[~ɾk@ @UUX{k.p\7naCx{F%J1O}hҾqRR22lwuc|ƄDF${nny?䮻`E@Qb=k@eՎ@y+V x^3LϟKK fs˨wZSX?8C\v3.;cD$ ˌNL)S x8DQ7rsGw04;~PI1`:E3Q:ژb$IaזTkԔWHKO@NV^F5Wn =bsl0< :PWáfE& PW]C{!$YhʡFz.(`Q$sΥ!=δabdY># y("-- hѢ3m6voZdffzQXXL&hv*xVTT҂bP8~&Z[["''!Cp50h h@ ErTUrqeq8x 6l`ʕBrr2999L&8N4 łf;4X{,tuuQ]]M0D$***P .#G=v IDAT?l:\ ^=-^LE 2dT~c>ۢML)߽?Y /dCseG3={9%촩$[)?i\z ZZ_fl,RiC4'w \?KQ;wXyTeYVS͸D͋>5<C9Mt ip2vp( 4ֆ~n7xwO,EmE%]Utv$!"9- M1LdfifW( )Y.RRd]T_TU\0mF vss3L4X¡C#sp6NQ E1=~_83xH/$IRZZ/#99˅lseP(lz˂ (,,$;;>Y`0>iQG FL{{;---wy,ڵ Lss3k׭h0eפ$rss1p8"Oȣ=JMu ?Xv-$Fzz1}YuN>  z(ԧ$ȓpDXCG2H5 ر\4iRB!WT;A9k`e]=TU O1qlF[6oM\ÌyZ\SG "%^/em"a0 ˅ ܣy,pt[/*!IW{q8Q ~?m\wb0¶pDSC w ΢C*e{`<] oxlo&KAU% YYV\!1.8~ gGGo` 0<ٚ Eٌb a'6,Bz~4PLfOTKH11,Y^x!zcQCݸI|&N`lJʀ Ɇ sӈ"+4VԲf&'&#_~]g_{pӠWfż >ޯRUU|Az!ƌfz{[o3ɷd>, 㢋.3Xt)mk>1|8%%" t>M$`=tmڄe('7uqcXБDR:u6PLӦ7ۈ쎣Ɂ$z<w@ome;nغ:;@Q{HbN M]hM#ϯF:ze6!f6sŐ-~?k K gg.R{qNvdBQϜ5\f ?Y,X.(P;}Bw{;߻猝6шǍ wSS^Uw jx 4BbG&sI"I̮~3:`MJdzU% _C=-+p'LK.aԩdgg6YMYٱcӟ"TUٹs'7$I455ƅ^Hzz:~]בerϑ#<^/<999\wu92 2 ,yfTUeĈa])((g!*=5k'  "?>USOjY>… Yp!۹ۘ={vt,i^mۆ5UU#Tu\.O?4`@ 0z>}:# [=?<9:ШP\\L d(5M`0PXXO?͎;(**Le0L\}\}B@"7Ɏ<^1rzfI^"S:PáC0QE% k]#!Y#{I4v˵%,1~hzqʙW]GSuPHgq@Om qVvvIo@\\-I^c'##8TUiiiJlBSSW.\ĉ[lQ19EaŊ8G?UUqHD `޽< 33zmo^mFeeqģ2F$6mĕW^?5\Ô)S뮻og&55CW'M׾}t}J<œ1.kVFxٌd6G-7l $z<}odb22 vuұiXϙd6.+EFCںG١KS$' / 2ihdoS#( qqAq_j^KLxT_||Hd/f:^|UخNJwMvʷ\8$!HF#$l^ɌS2J0d8:!rGqltuvgeCK  dI,KF$]d%.‚5=,]{Ánr]..|#=yyyћk^? ,_g̘^/wfٲeQFzz:uuuKո7+u2˲ /KnVz3X l0aL,[W'<{+驨BX;:1x={./ᅥ_K |61kl$ciY<>Es΂F_$:~o.D$G$-v= *s\(9NuwtQSvb,=m"l00!gd."jjj8`0^{-/G=CQ|{I}}=@ 2vXf ^GY檫bܸq$&%;HKK;ǹQ #,,))a…w},[F]eyazp&$;l(f9%Y>%S#-[FʨQ(ɘS41(|?cZBh#OcD]lAϫǍ'ǤIqYБ@Ѽ^ 9F3{iݻںZ YK$ؼy3r7R[[ 7o&99klիW~ϟY$x TU*9NQn3k֬~^E/B:/r^u֭[ǔ)S膥Ak+\(.[ `ɟq&Kw=p"0}{azHO6o?QQz]R5y9f(x~ سLqD$6 Iks!~C$ ~ڲ>\Ed8Ml;,K!<|OAQ^2P3H[[HE~^si~M/<2b$晳@V>:WgRsJ*) hzQ6 'k_ vvpՊlىс}ƌA;t(v{*f*PEQ>5i 4 #=xt]qF~_qm1h `5 JWWoVsB!b/|y\̛7/*{ #55!}BdYfŊ\.R3<۷oo'? ]f~V%җbŊHXUUU>Cq:(e :HPDe4]d2}!jM7=GPdhhf>CB4  q#@LxtE0-ч io:0IR? ImQ8ҡ; #$Hᱭ8x]1B'IǺ.]szndcω19\@ p (XNP{]X2lV | rsu:!(9{6} 6ZŸiӱ;B*,jpe_baY ZX1o~3IYQP >?[|LcE93Լ( 6+̙ h;wҺu l֐ ؒIH@nG10#) 11(f3Z+}j>ěDn|>~/{R%SbD84UDTsŦk `0S,o-"#75,KȲ,KH˞[ٱf"o().>u/H-N?htwvv^6hoGVCȺlwglX7E!Ϟ=Re]U1~}6zz)1ݻ񕖢$ dBKHiy 7vΆѣpCU4QTN%Fn&x }Q)))aȑX,7( /(..fƍ9|EEE̚5s璔P(Dqq1w}7>{/L>;3FnF>.ƅuEQ$)E`͚50i$\_0 +I7|3?˖-n(bcc뮻xYd P8lcnbԨQY .+qf[hCUUv;ݶ ٠@Br eehʅ_#!WŋsC{$M㦟'2}$֭[GZZcLa֭䃏<¯ozΞ{464 gڵ4551uT.O |v;xxg DZDU8{V ^+27aa)S`x̙wy3YN2G=m r~댽lS۷7ULyw7@&2bx?ok`4b.?B捺zulQiCȻ IDAT`"ˆT0WA9h2蚎ku]D_@ѸL[pZ(DbZ)8OH}7# K(%*jSm 5Ԗ~Hs0fPν &NDjJKvpĉ*vl[~4M;j:l!"B};2{e@L+JKMzV6daJL2/T>ɩ/ŕ߹"֯_+BVVC r1dȐHF4F#\p'OsEeRRRHMM%66Īt]d21i$ X`@TҰl$''%$%&a6eYuJ9pX,Ə\رc#_'N>Ph9Qw]FywyywHc\z)zo!M̛5'wr`FLVHSy9CUۿ_$tUTr|2︃,Z݁ Cƍ#珿g /S;0;)?o,a̙pe2e6{[5)&L… ?~< 'ЗNرcYxqt|Qt̙:!genv9" [fk|>3h:߾WUi")f;/,g{g':2]dۏ2ʰ6YGv$6/Aי3Tq F 11Hz"@ΠFH!ډ|zX΢|oIZb ɦj>bw+;ʴQi [l,eԩݗ_aÕKrzv4b,6+L>Af?e,\Qƥk*&)"1OuutT[47DkC5ta5Iw%dffNn^_ߋibe8 V.A|>زEDv>]l==Ag >eؿng w~ᬳDQtŽmp޹k;1cŔ޽{ٽ{7ׯ$..t Ϗd9Ci(r$Fl !Z\Y:tw}fhlln7o :sAvv6w%Q|p:̞=1cPQQA}S[6|ԟ^Ǭ=7cMa}PswP>Cʂ-=- d?4[@UV.E? 'kit\?C蟩3uF ?ڌ\>;naفJn,}?9%9i _D'80= >2aCq ЫjuƊt8Χlmm}&Cqd<&1=%ue˗Y٤ΛH~rHd{y\i6HfIB ?vr|-]r=#ц eu./6͏(X,1MhiivziooesG'=^/`$ DjF&1 aŒ&zo:mM IjHn!n2[ȒDIJd\p sINJtW(-MKXck"Zs #-Q´m )0GӠwP^.{)o1 Rr2t83f SN:ijj*9xأdHsiK 4UD`žLav/d1dp?bpeB d~>,~.Hd=5 j7Ț|j$t!ԨH7( 㸡Ft \8n7]auhYGJ9*6ɩیvs]gDRq'8q7:wYE#Uyί8*LҢE,6줌=(;xRz BȒD0Fjbgm? &a5^ 5P 1S<۱]ƄT$o7stf(txLww7$==uHlll266ɪF5Ŵ&R`lFphgw702>Xe$]GBYQP$?09c^gcbtrK0cbbNulX>q",Y}3l n11pӰ#1va7:K2UMʳ֬%&z`13/Ik@m&״F8AKdZ; [(CU]gAf&74Ճ%%%0WPqk(c)JbOߩIIiv)'_ĥgpagG1GE`Fŗ~;/dǏ?6#At$h3Ҩ`P̜ρgU;CWawV%  p&#:^i_FΙôW_eOEq`H. Dۖ^q0m:L$#Mp%?O3 Ck/k9a";^)2Ѻhi+>/$sHf Fad(4aGpfxUfZȾPQ&F+.g]sqee2]~??(Z^,1LNKc f远LDw[68yC!iiIbs4+sG|!&UH>HS ш:IB(ؾM)Dz& N-% E[Ï(Qn[K̴4a(,p8c!)D@VV !TDEQDqJnw0jh l";;ٺc'oo/{'"3\`1 ;^\hHa;$%.ڡMKf&&OfOndvNà:;d; ܋z]d:))P!(/(=e> B#H聮.*ýpOIR:DugA jfz饗hDIJ:)(+$$YDؕ99 D?%hsDڵBAAH?X6QJl(Ý7R2h `J,%EQDŗ&F*dd2(眃?'j׍MlڶN>)+Ǥۧuh:OdҰad1)ded0f(;bb6syZm,4Y]]TXgnN#%prګ{૪p.jXNƊP[ ^8t]b-zO`غY>+v,UWKE:fΙQDEEL&L}Izz:2o(LfF9}$Ȋ`@e lP0}fǽa'QE'uV^QsFEsD8:u*sk_yYĖ~GAlɢlu֬^v*~$IHMdYfYgCͤwAdrz㾦톀ɉaruccĦL?0O UQ"@*pUU3: [ieX0 0B5t}?VY.GT#}Ik?J08Ia߹a@yEض {i`0ppZ[Zy!F+5{D6Ê I"/;\6ldggcS/I)7D!IF'oRYUɿ^x/:dQZot>F)I JTjk^6Bm-db|%quӑ`֭f k֬! (--%;bbA iFMM ]]]G#ZAfΜdbXVƏO֣6mvGu4 Ǟ{1Sfh췎+**wKĘ1c09s`07n;6\tGhb(0*Ó'a񈌢geMmdL͂L{yd#jO}Xgb\5LoSX(ZwA8t`e%eethFZ1e0ć aLLDIME2:;_4 OY)h󎯪s&{!!ȞDj.j8h먳?E"X**"+03HBvrBHhez_1{|>{*oN# _ 8T3 E z,[7a )ڽ8R22c\L6;.͆йkQmӴgB =; QtbvH%dewKNY3x`bccA:s(J+dHOK3gRVVʕ+Yi ڿQz$2*Jgh&B*eY#.vFÁX]t">!"{L No OV~%pѐ\ݯOG' xs(tR֮]ٹs'999&$IL6 N#;;Ԋe<]QUr!$mF}}=gvsNaذa3h t:(!}8nqF[֯_ρؿ?l6z^窫B$L&;vh4q(hgSFe>s^/;w$99< FAA}Af# \\ͷA 3"7bx>ͨnvpZmuR(r8 к+lΏNO&}u[?hV!65T<O#n7r ٵ V,_"#(j&j_v;sYpr f<|>~m۶X;oct݋udud6 5(g.-V+}Z8*޷E{,?kcwa_\ye3łhq;^^?">ҥKyoHLLd 4.Pݱߎ!zl~ӻOmUUm6>cvIꪫK<< ׋/d޼y|dggӿFɯ~+OJqLmF~Zl+2eee8pm۶os ?~< 8RUv3m4b69>q߻GO^  FmRriDTU؆Cǫ ^z=]ڨx{nw۱]j13 ,sz7ߞ=*M}TԠѡ6˝A6BMV t>-[q݌3?? YY g'msΝПw@ RT9 *NI\wLN.Youӧs$&&b6W\t#P[[ˋ/믿Nnn.cǎ; 22RKT*?zܩKJJ"99C#>͛7_Si IDATr" 1 @.}eXtS!iii3rHDQvqF,XӹwwhE3WT% - "Iұu@2(þYlv1a ?6{CiY^U H^O642|PgNd$gF=o99Q@]=}8iX*,&Mb„ |V"=?j<3)j&>هNWN:SOѹsgrssGee%f⦛n"???Tp.S9"+xe/Fo7|3g~g˅=u*ltϲ",VD.TA p>A{煽{m622HcB~dgӵK232F ! ;׬Z{l,EnSw='{;ȉh O$ bOu>FT_ فjeTiw WO[~t7䬬7U+oU?`HA$gh} 5|~χLIQpZUUJ@E7+ʲ /&gں)( u4r8ѣ;FYvaڵ 60tP|~V?~J gd6?g|a3 ؽ{Q [#˔IJJ:mcUUUE^ CQ>CN&g .:\MZg+喭x 5 eea0؉0 u"d'>2NH"*zL6=zKlt &^/ߖqk%))8t0c )yQ"Eag}L&:Ǵqܠ n0_ `=*#&EU)\(<=o=o`5*N]ZF>zg?_=O0AbF~LS3GFb}wWE$'?PǢ=K}M55l^⭛ \wL~f… tؑ&mTQ9rӦMG,p&i%B0mSWWGYY}t1< LZZGבFdT`Tq,MMML2/_<-'+ SLUȡÇXx1ݻw'**/LrqE_3 p`6kD^kRss̪EA@EQU6ZdLDΨOIDxpy`>v]\øѣIII9'j>Jxb{!j-eqW^W&Y$Ifs= !"+tnӯ(j&D6Nsh# <7X蟪T)g sgG~};(Ō-"ժyf chd̩4GA8VN'F\N'^ݻj(d1T);]6"y?$I$6>ǀ(Ihe]Uؾ|rF_fCnn(v5$mGQv'8?1p8hjjpPVVƪU(++#''3= ӷo_""":t(iiic@Kب3 6U咒VXA}}=X֐XgG+|9IĎIfjdNnyJ"$.sraʥ>/?Y= rj>Jg^w1<:?cSRsi pJm f+ k%:=9m4}lvjt>,(wLӁ`hElьr)Vp'=Vj~gSwBo00phrzbsptvO<Zz9uhxFLիXl) IdtL;v`0b21fQuPkL4ն,吱,pA~{.%HW+z^\A \yj8Zu^|; )9%^:~C1p(d9;صe֭e{E" 6.$t:q1D!bAUULQZQӈ` fA,r8v䠪ꩯkuInwUdwAt\"y=gMY&L .qͦ(JѣTphNJ 540fXͼ~U窣E1dFEEEwf˖-Kf#118"""'6Xo2N`Z[].JJJpb!"Bzcc#Gr=ҩS'uƴ˦1cH>< x15j&Lݻvm6P__jeРAdff֦&oX dn7t:Crٌh񄢎^oQ\\֭[)**B$&L@AAӧO'555 4P0֭]҅ Ix!,lɊ H1ڛtiPr{㉢t… մK8]n9N=ةi{YX\@S뉱^';gQ$YYX_G 4-2mLC"7Fn7"f{yN0 Iݗ'!3'6`2(-S >ȡÌ2lQ%?*)a](I7Y5;ɍ5=v 47Pr`?5GRYV¡ ؀N0-h=* tTACEEص+t]cքh⭗^+^*-#j%n AGl||ÇSYYbv;( 8p*zEΝIII!>>>4=\vMӉXXlFGhz6 8Bٰff4*_E9׋hF=h j _yfWl#c"!()PrQpyv^p9C2-" \Ԭ̟^x ck&f^T$bG>$ڬU &Նk4O@evoʨZTZd%jٲj5(&_=[t:9R~cm{O[fqKbDƌE||¹=lT-zq:ݺCEA )nJDc}G# $PujEEo0PqK>nrpnWh^ON~ym6;); `HDhj(rT0N/325h`>:t8?((2VkHH׳l2>c:wLff&$v)//E_l6yyyx<4ŋ0p@EGQQ%%% :}t q@E;n:t@^^ݻwPYYI^Xx1<>|84***p\-];v ''^z!"@{}vnV $X"##)((Д“Yn-{h4/d'999b%јwggON`4jb>qvlBAS@#"];qlقc !C>SN'*^+Wܾe/;t0(^$_^++\*+2UUR 5|VvˡA##ّ /85=ÍM8gG]_YtҜiVUUGtdEj9@Պ&?? :ݛ7#Is%_oz!r't8||gDĜH S͸˯dg^7%'ҷ_1HH:]B?ueT"r /-|AFcc:>zML6.p >Azuz=7mb޽;_$'% ӟڵk:u*6 EQBQI'|C=D.M&Yt) ,`̙(\e0tmp~ Tliibc1DG#Z,fU jʮ3McU8oE*(@g\u%_N(m@ BHO8b$ N'rk?R΂r>LHF$3-+IwRUjnM` bm3mWq4;DtB6lId9ArVG|PD<7Gejb;pјX3g6ڻ_>4:vHnt|WS$Iܹ͛72` J֭ۗ[rȲ|JcuL<ظP}( 66mڄl6|̘1ny|]OEE1EEEt-&dl6: joNݶrAd0GDhDnGِ d־on'HIFg[>+$hh嗨;vĜrQ`>R^D]2\Tm- VTޡCqWT੩фt,6 AlXʏj^jn|[YPW{T`3*N~b"22pF~*lc; tVN$YU9pf+ SI[< (8Z(W~AfgբM ^MM,#^x|FOT =CTL ]{e%SB)trU<&+g#~2^.2_^a:?WC=#tHxs*n#óLDQ=zhA(^gP ^yZ\󙟟СCQ@ 餱 JKKOY((0's~),ӻwDV㻽*2>SPPln/rQCmd2ѯ_?|>_dYd2ѳgO̙ҥKݻw8MniС0|Zo]^ jj`(-zD@HH Q (Z,wB׽;{q߯EZ[ӣQ9gƎQ].G+Q\+E $ ?yF:ud֎TEUѩ*v2ǎ\xUWϡFJT8t8rqG;fsݧHLKJd@|2#"Ɋ$ 562-316h>͞8UMMZI":,ȰZ ϐ` TV  tEp|ߏjU&`d5{/3h(bZLp%1- W^'D1j dġ={0LZ{0&%<˄q~L֭[0^$"fӱI(..͞iӦ(466eV\IUUJ***7>5VwޭU!fGE*++;wn֭'OFeؾ};+WAUUeee{]&U(*V<' Yx##{o MSY&`jι##b!PRJ !vT>} 1Qf-頤6ol릉 }H9x}>jN`N˃/H0\x42VF@n\.IL >H2"Ķ!uPvs:AUɏ%6lzC)6 C3ZHZ[m8tzX-J~~S>k,!:.,dE9RDt46-[X0Z.H6YMVzt͉lԄmׯȭvmȲj3fDelٲBVXjeԨQh}xٻw/>(qqqgY Т(RU] ڵ+wyO?AϧK._pD'>C)6Ahhlhw6551uTn7|}>AMtt4:tI^adS>f$~9#GA׮otA~ IDATZD1B#6uУ'ْ eXij:I?AN2[ݺ6ڽ6O8e}jISd$cIJNBzVIe3|¾zTNOC5L(І(_5 $X%A=۶yLjӑeȌz ? 6-f$x}PQ( Mf6,_Ɨ1qELv:vxJ@ 1cٶzuU$g6\³)bҥ;p K0{8S"%%%7ܾ};DGGҵ:N~i>s6oZ3;ұ.\ҥKxTUK/SWW׊$7Gws<3mcǎʦMx:u*cǎ%11hnO f?,3n8x jjjl-UU[P)BJrJc5::Yٶm.Æ cĉ$%'a20 0gΜv (8F1G A$B0sgP\ V¸aMHbj |ѱm%- V+=`4jmJQҔWQ4rj2ib e3+O72 f `EFEG10&Nv;ivvX(&X:9&2dM,h':[Xu6|^Yt .XmXmipxǑ$ˮ~7H:8n)=ʛO0lDEi)7ld˚-{~( 1t,6;zz+pǵbİaXmgO8L8 d> ÖХWo=jKݛ6gSDSpI,DEE ʕ+ |GF${1[o')W 㼭pwEQ2tg˖-\|ȲZ;v>222-(I,Yϸq޽{zc+aGqm9j`~~>o[l!+++47G ob=X,fիWѣ۷/~?4VKKJCm9M}>;v P~H֭[IHHgϞ+69CǡC5r)-J<1Rl/D F-Poυ撀Ȣ$&'] @A\lvlA鴞(DD$l o۽M'V,>2 pTU;Xc*IDLPrE .|[0-UU(Ln}/u?Zf3 p^jػy3]FR099;n@CXI8RVuߑ~ٷ|֛4K]v=GڔZe9@Ǽ</HRj:C'L$"&+Y4ӅjALL n^x~(Baa!d۶mvm؂{ǢEw8n g-8 EQ׍l^{5ׯ_ʕ+oZs$&&PTTD^^fǞ={xꩧB"?>>Q. DZ,зo_x (((jt:ꫯZ'(!v߾}Պ<3:LʉY""E$Yd gĉdee2DQDed%L8- Тȥ6i'O--sXx?6:lh.tLtt:FfV ,ɧ(lFm$L?;׷"rIs"ImUJi6-J.()55 6>1Nc$ge' N,ֆfb2} CA%&j2|p)**Wigh|DĜe%W_܈=*ߏ"+?:$$~s׽䣹obGٿs1V}4?-Z/ .婿=|wee%W7h42ydƌCJJJDf͚5,\CqW0m4?ޣٙq!>3KѣG6m+Yv-ߩ[n!&&̌'Mo~Ng\t ԆV\Ղ`ֲl2>#V+K\ڮLdYܮ]Cb`'d{a֬Y/!++ рɁSϐCyXx1FMYYǏffOJ0RZȜ Ňx~P)(Sb֒(!rwOcHMKtQQQ 7 ZqZ ǒ$ EQׯiiiꫬ^ӉN#5E߭8dYw^O>}{HOOGE>墠ӧH`4c%Z(`wyЖhBp ذ ` )ȇk5qPe"M{ْb.r PrXDo'x F;  v@h54(c wi&L .|ͫ_.n߈X0[Xm:ku:3"جVszׇة9%擑f` t5,k ]cY4v_Gv 9 ڟT=PD$QBvY \9i"C 9zڵu]ڵwO>aȐ!w}\|šmyy)**`޼yf׮]?o׬YèQ={6Z>S.6n"V`֬YdIIn8.9~Bb̙|!W_}'xb6kx-2i$4ն>CNNX>sjkk,dܸqL& Bg0Ѓh"~00'>}0{y'ƻKJNl]^OLbIްE7m>x>?,\ʯ(I"8:&&l27uK)wn{=|ʧKٌ4D~uV|SN,ZZ%;kJÇy-e9`"+eg5z2TEbd͌ I>}֭r3uNο_؄xMH^}՛@ !(?j<(JRz:pV"cbtzX Qb(J Jz*KJS_ۛx={b1(|l߾nn Nܹs={6,ӭ[7RSS ,[Yft:1coQwyUTܹsy7IJJr1g^|EN'SLa-Ҷ=n<555||ٓugsΌ3&dx.Zs /ȑ#CLOFMΝ3gwq999 6cِe9in @HJLbʔ)|>lvQQȲܹs1Կ9:GFFӦMCev6;zy6+$!("I@;vl2VZŰØ={6]vԩ<ŋf jlfG6lvDlh ^ߦj ) ۍ `_zǍ$°| J8q"]v^[n&g %YfkxvcFƍ헓ZVի0 ˗ߴ^ |_ѽ6}b-Dμ3${f蟘{pR6ofsQƏ'rP?]ʛsrQAqWN2rI{H|ebЁn;xx .XÆÚZJ,qR-4"hj hmLNHM" iiھnwk*!$-Ug@\CIbDRIUm>{l]twl6HŶNÅD09d0Z#66[f܂(-5 tB.Zċ sa\D݉O +'bc2*Z/A'iت@DUL3fUmv@zv@E>.EWZ hF5tRv%QSulZAG]8vOǟqce֭رQ뮻BQٳgRBXt)N/|И*,,lU7u*Zw!( /"g'8B9TOtCqq1wu-`0pUWEUUU(:pb.t?\F#]t#7t+V`…<Ӥӷo_233ILL Ս5; QQQǜqAScm"JcUTWPTTDaa!;w$//ɓ's}H\\coݺ^~m}`)5GJ2BN.$>Tgtu:P6 ש*?6_l]%++ЏW( u>zbÆǘޝɓ&d2ڵ+߸;Y\3gs2𻃘)9kh1Kyg=KcfJz~ ?bp+MzO }9~=yɺ6.zC‘_ WǤ\ `u+\5Ϙ1}NgϞ=曡L.A<mI߁4LaΝZ7R\\̮]HII!>>$㉍%---f fAz8pǃ(TWWs())={Izz:zwd6aZ<۶m;륡o?""z"$vUIɵ#;h4qM'fuDqdžg{Gee1fll,ii\_`s&^ċYw4G#& ~IٺYQ؟\?wA&A Jl7\͡KS%|8d9Gwal'CVӍk,9B}-z3Lh {DvEJUA4zXw5׭VPk–'Zm˖Bd$kDv?k鳂퓖9`[:`j+/mʁ.#ZKIbRb"#בyy> $6"~Y,l0]=30~BԴ4M,d9@S;vz)--X;$RUU?FX(DG-'GCNcZKQ1 kqQ^^b M,:]+,*o>8x`vm-&'y19?EEEmxn{1c>hqx/ 9,f˱RqtY&(>/O?@UEsss~ӶJdk+  ?:3b0q=ݮ>y2'd؝;b;$mgy} lLKMrUhU'@p7Nwz}3J" .t]\##HJJKEV:ꓽ=^[)"_g| G8Qzu{wpq/n?OfynN۞?$IRP׽o|B'4z$<'"$y[兎;v?$fAj<{{U'h4hZ&{Y˼} ;#"q7{e*ez6~Ǔ}鲎E o%:1@ղ7@+p9|wJc:T3;3oM_@U:d„Q#Ǐ09bc`VEU嶣FCV<<س>o _c˗29-7S^{hj(2%& OW$_= :VC^fٓ"1ɲƍλ0 ImThiaOu?pTRy|T p=ܫsXj?$[צp4ɉm0tI* hQD'yNC} ~0L8 V`…̝;V'|B}}=QQQ7P mƍoڵk?>{/6lgEH9 's-++cz?pwgIQ/^_b0a---ڵ+~$ #x-@H$PGя{J][KӾ}5hj8'ca_~IӪ`>˰aX22UnmI=)ȝm̷eʕ,\Åɸ &FL\aOl#=Mҵ[mD ^J&at%P**HOOɓF\0ɔcMM~UVD&X#, IDATJ*nr,h@\P4/''E1sL|Ix ߵR"::G}寧v4=v{G}G}I5kgMD5kvb۶m1~G}Sz|x}=seܹ]w7[oa4Yf ֭K/F{/hizK ,,}(JRmmgyvOI^/˗/?tS(^}UVZk|`n=\D3ה6 Lp߾33z/(`Th#jf=8D(B\$NnrhnR--Keٿ-466Bl6?VWW_s}n=ߝ}''CL,EӞ=P[KÏ`HLn7(N'j< V+~ - RTy qqq~W&>3_%7 HJ̌z5OA)tkeL5lȐ4P‰}fOQp|\{3QArj26'@0ܰ~7ʌ O>iWMO?eĉ|0?;jp8ΘСC) &nhh ((VIgpv`0Z]HWpֳjUPgzb*눨(셨Ҹoǎuj{e濢z ^^ UzjNCDZQӧCP*Aj $--*)롡x&ɯM&v460V3EQoX'&דm !8Cq]xE:c7rYjΡȑphut&V(*ս~ NŲ %ZhAZz:뻜k֬aΜ9 3F0$I޽ԁ@@@AZZZZ?$bY {v!Gt:]C圂 1 WD ?oHHJV-;w1E)T],_R8Ӄox{t (( Oorm!^ً:: ,1~e+t`4\FG~iys3Ͳ45@jpz%nȣ(8}&AVQ|.g28D#AV66 ^_.izrvv!nCL:uF 3+@0wvjjjp\FmYt:Ѐdf!}q (466R]]%$$N<ئsNMSeIJJ1kllFKpp0!!!ݞ슢e$nNGttt'qҁ Eiimtrp8yǃ",>,df͚5\Cvvv' k]]VbŬ\tnV>Z[Zٺu+-⥗^`̙̘1~àC#++}ߞ5ظq#K,7@rO<;e^4t{nF(,X[o1bΜ9] r'%2vt8&Rk8\RBCS&[[@IJK#(؆"(5(ĔyjU_oADAh ^V-Ć^':"b"""Ɉdjb @b`6),,\hmm&Z[.PVVFcc#vQIMId2!2:$l6IwAkڊ x< q:HTd,HNN&##l&88i8 ^pPO<5+ر` R's*LKk9477SPOsS3S\\LAAǎF$&&b4eHBB\vիW}n|dV%** JvvSINJh4bncZoBM|IONɡC06"m7ЍD-Y5({x8A¤#~G:U/KUFS\\̼yXb#F 2"rz)VZoANNZ pxo~q0 \VVZEYY\qTUWh"-Z{W_V%""*$IB#iK``ĉ<,sܬը(OÉbϞ=y2ٳ{7۷o#GN||<?BCCU\|IF{fF'm @cC#JdoСC'pQ"""`ߟ(:?oӫ=ENGǍGd{~0g?SeT.i'xW'68ivv˩eǎܹʈ&11t @TtaDFEȪjLcAןz=Jcc#d,]rddggM\\܏;i#YQhjq{@EKKi_ I"F N,+-tZ-:WηUVq Tր(2(}:[l7=s!Dcc#?w~/KQ ǎߠiӦ/2K/L&:,X@uM5_~%&L/=gkk g߾/ؽ?Lv~5kﺗdz׋">V9=Q) d'(2G9Goy)++!5!1#G0bP{ڲHٶm^{mDBAA_~%6l ??T Ę1c߿?ZY;(B鬽/IHINA E@d۶m;l6&O_LVVjy=w .)I V%ݸ[E]S%aIn/ 6PTTDNNdҤI~Ӹ{ֱN#==A>|8 InsA>s,X@TT'Md䈑dggs]`e&fjiijt8((*r!@(fѣȧU,zH 񐓚JhPGG#iht:l` ,f3Eխ q@Q$#$ &{7(jhP{E4ݐUN"z>FAګzuh ćuשI@Fpv} Ə#::P+t3f kiŗ-[<͠ ~_k477k׮$!*Sj~r DDDk׮pt74GG}ٳ1999|W>|{a]˄ OXlǏG$xbbcc !!WNeh4WU+A?)0m4<{a͚5^˯Yf=7tRVZJUu5)(.uSxJZID$kF&c/98A@qQQv;Ng.\mlZP`2&3DRJdD811\P>=r)>WA 7"? ʔN'5?-'e]j<ΝOE5puwΒy$YtJh̛71셇w=ztgϞ~3﶐}whݷo_vZlQvJӝdbp'W_QXTH|\<_l.5y"J ;tIZsBHh{Y@UTW=5!!*!>ٺ|d$?)Iqhm6\kS#tT%( ziĴ(j ˍEE|QZ  ]PO #;;,º5uHYs6lTnc:ܽuT/GFv[1%>wCeEQH.Ջc6wky˲js*7v [OU'"W0D&[Ϫ+Xk7F֖ n)v7yrO0|?ORR bL:WW"""x'={6xIHH2yyy,]h>z= k>޵+9<6BBBSLa… %$IBEG]]Ma*3}' 1Z8vLX&%AVj4jusHQj`RU\puj" >:γ55\Zkhݑ$yOrV Fhmmel6""":XX~= pҍmm6{u6_gޒ!=cb"(jpbȝYs|~SQQqZm2{XBCCٽ{7 HĐ!Cz, CKtBN˶u,I(huǨ8pǞp8|0""Q.H%{e@CTΠ|OCB1r~ ,eC>#1+3ߏN64dIl;q-# ujm;w2 &㩩9m٩pj5Z~pB xǘ9sߝD۷/<㷿-[n%99Y'g#IC;瞣/Yf8C.{Dp͝ws|k U(^82H&$r/(ITRQV"9VTj#:14&Μ7_!'e]Ƴ>G}_ޫn^xlU+k(//';;7?6''z~[2k, 77+aÆ8|,X\~o}vZCll,111 iCy {峰E%NAPPP@ee%f8СCV0k-[Ɗ+ .^QQ .ޯœPVAhZH<Z )j%3<\%>3Elge}55qm3.N}}ATcQRG*}Sz~S3~mz 믧_؈f#++lbbbBA9XE4 ZO&QTR:%((X  AصkYy_?V…s746…`a UpL EuqV䓿(Yۜ7E0jjXd&V~(:Jb^#\v{67׋JtJdEO'P`9 vQ3՜ _9:x_oرI6@0Y>B^/(\1,˜'i|ۍ$*,؜WCGI *jPW/ ^xmpM%Lh -f9<ĽzG@ o!v`9[X(QQd\.Z-dfft:᫯O?eϞ=Axx8v%^EQfڅi4Etbl6cZFM 7Dzl߾Ν;)((`L4Æhj_.{""1&$[oqM72`@y^"}A˲S>rr0&&!(r+WT_ε0+b8="Ҹs5|PAfӉ~&lQ% Ci޿oqMh0~Y|kcSuKC3-%$}ןR O"#Nhޣ(EV# ~>aƮGBV&\vRa6w%mc7o5RSOm{sb gn7r@߉h (][`8xʁ''&]7_y 3~΀g oM[f|Ȩ^Ǝ:HKK;@ӑLrRrۇ -A?nI/t<8Qe^߄IŌ)Ȋ!af{#(joik;ZZze_/M+u].'f%pVDjSJh6#J"FŊhBDKVd<7%Xt)wq uܰaØ0a֭|cbb:=߿!C0w\RSSIMMҶ (ITT߱P`6lm"oU dʕ>l63j%((A卲8˘ח溺HZIB$ZZ)+)HQ1 '?dN54D Lvf`L21p;IMMe\z|oڴUVQPP@B=FJJ sAxhii\ةR(**?>L͛n)S!k"IG 'm߾JJJ:J7A 69ѧ/!axw i٘\UU=hN hbbЧ`G(?:̶o}=/w^nsR"^tRm;U`?Fji-/%Z->6:QT-7 76,)y*&B", JJO+ᱹ<|]Wo_fef2<:ꬺ:| X')BT;dE!pN?^мA ɤ(O.=^xZ:z5lQ+P5 grDØ[mܦʊ Wπp-pi \ w&,篞 \toYg>q0o#m^pX6_A՞9x<67#{fMz33fˠ#؂ioyDCcnIn" },O{@=Y#'B\z!v /@cc#ロQFQ&VouQQQAhh(~{JԞ|I-ZҥKիU{Ĥo3FWԪ /{IOOGSSS\~$ PWWW_}ENNW^y%HDkk+֭c>|!C Yw>ع}1+B@@%O 07D5=~-<}?q-DItb4H!!=>S]QNy+7oȳYF.\/-wމlVw`ɒ%q 7tYNIZWWǎ;㪫"%%Ip8|Ch4 (zy72e C bP]]ͪիx7ʫ53)Ba#񺽼+<2g}Δ:Erv;nwY7ZZ2b|<^>8QQЧUz[x%2'v!-rG+˖aF4pWVRq#JEIQn\%%8pWT˅gʝNp\Ĩfl>76clUl~ <=?b6V77,IB[wH8Vj*ƀl }<(-=Gf։˯?m ܪ&LV on>B\:f x)`HxwlE7Wyqs=g&PzM7LH2>YΌY$ix_^s-rQdw+^yi&mFrr2*˸A袋N 6S׬_ٳg3e>KEQHKKcΝ,[k/툴4nf}$%%hY|9C %<,Su|!YQ7l8(_ 'ϙ ڌRBBTEQp8\xm[\aaƪ.[F3@l-?j'^/ri)rK ("# TN4֪d1$D5(!a.(ȧr0{;F=VVW_O~mҢx< 㓒;#!QQXON$6Q QBeEٖ8ᨓB2oR{y6Gq=C {LV4p@}tfkp#۵j<-[|dҥ`2 ]ժ9%O=bB4MMp2`4ˮe3%/DϣjvGQ)((n3c (P V+_~98x '%.!CVIDZzbm^v7wd1&DJv&Rv7>X^ϘKr|>碢"***kV- W^y%w"vmU6noAdd$:뗏`X(..vKW\Ox~=<붮#$Iu^/}AnC'絑+7רO(tk$~m4xdJ PI[=@J2ӓHm4EakE \$*(p8@C7&?q @0V%K^~w荦.vbd:Ir{+>SVX7ݬTXz'!?lL = ^<\+<h~+| IfX*]y>qяz= E~ǣ'Z~=SL9Trv #"<F㡡:9B~~>mc1~@SZZоEDOd\W檫:Zz8l6aaaHnSWWѣG)((G$RS:WIeYFӑ?quy?!-\%,% =F^_}ǞxI222^E—7`hZP,zvPMW,Ο[Zz׊T@u dgÎPxHfƵӖ2[C6OƫWM%@IiigbefR"W%3<2:\YɞF5 %|iج_ Ыj 椏-;c/¶mXj3f`ԨQsfvb\*|CuhV[ק/,]YZ F.ϥ~G0݉QuImw..6skP miI+z};AȧDˉ}ʘ5k=zK. \Ѩ1XZZ?7v!ȖzC.ͫ լդ8 {teΜ9gL6L;vr}II $QRR'|iҤ ' ___xꩧ(,,l4-PQDI`2b4>,c> dO6k!A ۗOƌ O[͘1wwӦYz OkH:L)gGDDЯ_?%(8^}Qkm$b X hEӦVϟW@@è1cw=)p1k$Y6CW_峉MO>kQv) IDAT#U; MS':l-ŋONSvf"In?Vw++xxtQ'atDD`gV+YDyTUumV'VWkW;pL'Z-ا/;֭j' ^(֋UXz5111ӧAĞvriɥ6ϟ˖1g֬[Gl6 mM)&222Xr%_~%YYYw}-~FʽˬYPTREQtF~Sdݺu,_'x^zvLZj;}e![3f \<:IdG DjuN(l_sfMsG?~f5l6;Dr.dYO>L:Y;ִUwwڪ`jyf/^̐!CׯVEQxg'??OOOj23$[n墑LNOLL j%0< 2wXeQ0MxxyQmWlc٩ 4iKO /O?%2EQK_-+OA,)+o_M64 _͛LoU%"/laOqvC}|iuֈZ;AtWС,+N,'t‰x.2dfcqgʕĵjF @Ƒ#<߽ y9n~GRCCJJ ֭;ljb&Ō ^sRLRk¸pBz-vMu;v,'OfĈQ6m "l:R5۶mo<-ATUQe6mpt:%&R&DGGߝ]`Snݺc[8?͘AqQ!HFGE,y6"#y'VJ$]eZl^gÆ D7vب+^z1#C$mFyy9[&((1t:&QJem7\Ggii)7o&$$f 퍷7IIIVcxb/WݦZnLR_jkиE >=a#F0}GlvCywziZdhX6nԖjuWmv\!c)aUbw BwI0p |&ge+[g;;\  d`~$Ut~ůQDd /_jrJ~m5jɓڵ+wfر|׏ Є*Nʶm8p 'Nߟ1c0~xCBB Ak\QbccԩSLAEnf\]]9z(۷ogҤI4jԈx,9,Ӻuk-[ƍݝ*v)M***pcZ}B[_OIҥ  ^7!///dY%[׮o"#%{E%:* NjEG|t:nV|}HKKcϞ=xzzҹsgVmUebbblڴb{8vVOܗ(XLd~wz!Q&9EIM6["\PUg_`O1󫩄xVkGw昧C&K[&Rn5Y^nYeZ5VyYW( 23RkO/< 3d؉sHp#sL' x} ׯcH:w1pO}Z~3f}w9eb<.Wٴ|9,>9zuѣGO<ᄔ"~WdYQF|t:뮻Xd 6m[nѣG߿?a'|BJJ 7n$>>"`8kdՕÇqF>S&MTGDD0n8L&Y1V;ә9sfFby${?CaZUOu:<w#FpGՀ(Iعy?Hn`Mf$I$ꦛnbݻ@z=b42d6mԩSo5~Hv 5gYi߾=3{lΝ$IZEaȑdgg3k,rss q;)^}N|AGDn@M0`}] :#c/c1뛯 *i#kˍPplG^ MF,UE#^PT)J5kP #G3צGvDy뭷S,˄^z@g SN^p}ɖ[NyL"+2I|lݺqƝ&\Sxx8-[d"""x7ٳsn wt:%#0(Gqa>CCYy9۶Yf̞=cRlF3vXr uػ;ڴAVdE!ߏ-PBn7Ɍ5 ^I}|$tMXҡ:NOԩSڵ+)a1<]]e*˄ ;﬷("5ߟիW;.oRE%I3<:3‰S v`=h?G7ylmjv ~h!WMhh>fpu2UtKK@Qx')nun DTr; AHUThUlVkݿs `:q",<_eɒ%||ΛI6Ķ#Ic-%(I9Oxgv1н; ݻç+ΙZP)Zj" vlȐ!<眪fZ9t[R(--%>> f361СCc4mL gG!**;||}۸80?SƏe@`` _~%˖-cĉGǎi֬f.cÃ^zѫW/Þz.ʨwwᨏ/00 :++28&ڵ۷cXx=l4s2jzłhwޗ89ZQtXFUe̋/"w85)*6۸Qo@ٹ/E9z)G~:m{"?1Cp^y |KsË&M ܁M?csQ1m[DE5kԤ tb#ĵmKx~.؏oC=]xŗ0`@q`` > _|]tqq(Mh~Λ)DLf3bcnϧ'AA~ z!!LKZX,йHeNk,] ]j}3VHM 5 y0Y3s9̟{kMY7~LcՊge!"\ؘߙY9Lgub խEAf&4j]vtSM@ 1~-kڶ-j't‰nnr,\7H=B6qF7?4f1G` (Jdo(d\NVy[e>E9>aWh}m$=%}{"!ٍhCй3yjGRSSIܛH.]=3w,:"~ZhAqq1FۛC7PZZJee%FEQȲ9_d{wޤtR~w&M111FtTVfJ o{Jb#HT{vhRUURSSIMMȑ#>|T"""ݻ7?8۷hGEZjɍ7ȤIxtk$>e٧ '"ЄgQO:N' |۹Q>ur^_'Ȼ~Bձz}M/{o=D2m?[XXbJT]_}G:NlwoE$w΃pPڼ G5 ^=-[^ NGXz5ӧOgN;TUO/222NI0f3w~;=+W@BV#sRRRu)s;lR{GՌ0طok֬a׮],\D\.9RTUd2(zpuu=k:Yyy9TVV"Itt***(,,p7oNNxvHZjdtSO=?N^hݺsr@ݨ?<teۤ9޾̮|֫514W ;"+}|H nLaw24$itVEϑqH]d/̒3{|ٳc|-^=U-a ^۳LCߥ[n4kig֋7ÉgtGDv|;~Izм_Y4ExBo;riѧܺofh }K;&3tdJ- pC7jǤؼ{Vʢ"ع2|p^9Aߣ iXox@HZa~͡й3{h0?| #C[{j?4{x4T9l)<:천`:qBӵkWvzҺcǎGqq1鱗ҒlLQQ :‚&'R<"H"+ 4nL-Q`5kN#""K0PUUU zTo΢Ex뭷$ OOZȞf0yxꩧxꩧ$ ڵk+>Ѽys7o^kYyy9IIIXV֯_ yft:UUU$%%Qqz`4iҤ & B-hҤ **Æ ͍p>㥗^_E iiHpp$/?ф'cYVAL.V+a\0(BFf6  z @cB.ÇbƍHD^n.so\U`quE#⌙g`F0 KL|}7хȈH-[W_exiִEKzB2]?gaW_h*L&R)oL pϽ6hGY9݀ -Zjdl-I[#..Z*dx-(Z ǎaNK#"'7AUWUfg57w 8dkcDNQ֘ #I"=4([?//-"؛4Ry > :iUdv9֭<./cI0pTpGMbnݮsTlL& Xڵ+hтq:5I]Mxyy1qDܹs9x O?4꫸b)yyy9jt"{!5h6u\ mk<ēu]>&*Vg馛6l_Y>4Q#Q\TTTrJVZg}x}Qn"##D`ݢE {'ڵsלiӆF>ǘc8p {ǧ퀮zr)d|0nꜾ͸c{/q/+WyJ'Z$M# z#F9B=*6ZQPQ bJKiԺ5ni̊ &'k``XƄCB$LPյ* 6%I.ğ.6rY#*CX8#Ю\}XݮE+{nF9 N8qQQQANvY( ӦMss믿\^qr#kUUxwXpB/_ΰahִ\={PPXh^QQAE.3fS0BTdsa^tL&|}}$IB:Emkvu|$NvhQTf͚믿^X,,XA0 iLvv6/2 ,_R0k:gxjB۶myYl ]vHd$I9œO>f;oӦͅ4oђ-ZOz۶laێ|,J+ *FGD[Y]- H..CIЁf115 slfm<M9b>sMQlY oYHMIȤ 5k&UMhdҖڏɂE2eYm{_LZĵjĕYZزe5}ҭ( ?%q^|9VB1n8\\\`߾} i;O뻢INNBKkܸ5&L?owތ3攑glż+>|3==K[o1j(t:))) <իW_;4kn>`̙Kѣ0`MZQUUE=Fء:3#[>NXx8w1!, (r33itjjBFE}Fj蜢)ee6V.vF~VH5'؃(:$&jC`2T&v U_SELF#dL'q-"pr+"Oi&, 3f̠gϞ݌!??VnʤI uűg~'$Iswtt4;vd˖-̚5ƍ̙3IOOiӦ: 5bnʚ5kh۶-> f<}~%7'Ʉ_j(~-433*  pn؛J.<..]wqwZ1 :KJNo^z9oj g^|Z ĝJl2[%@[CQ4h"?Mj5v_vҟmh"e:f1?K_ʪ**v N\1eY|9֯cԨQNNxx%-Mk>l0222?>Cu'..^x=z8L&F,,_^z9o$H|߷ IDATX~=<{&## w߱zjxG8p qmj/^̼ybȐ!KҀqf>w#vY d `.q9۷obLnn.K,aɒ%| :ш`&7h'IbРANaUUU1qD>CDQo߾L&֮]HMw!33oN_|qΪCyt >34;D^z ( A8Q -KWbWT$=݅h)z{Y,{q:v4JYfaQ֦I⦐:׾Kj(q==TlqKO˥j7v͛4q;apk9g_~?Ϋ#G2c,JKqx`>c^u:U!QvoXvgx!'8iH5+Cl2ӷo_{Һ~e^^^<<uۿL=Յ fϞM^^k +Yx1;v)SHЁ,~VXiԨ9riӦcbaرڑäɓIE^yYr%f͢O>'9CdE믿fƌȲ)"`'Ndǎrw;TimD s)GtB ^ρݻY3o(]w@؞[mJfWnT?WRbg[bUU,VVZCd~۶imFZ4BٲTj2-~+iF$8N<4 [436!}{"4Ee+WD EUI;zÉ{ؿe+k$'p '<(_ի˳믿h֬񶺭@>7nLhhEÇׂ (*j|}|k;j^~rI k_s|>UZc1Vܟ~A0O3q Eaa!,em %Mf=YAAAHnN={`ƍwM_:[e| D믿dLiYYh ېQ)| NGS_hy:VVBMfP)CASMN0Kuz=dfB~>DFڢq\ kӶ,guQ7n[oMRRs̡9m A!w?f*%!$" jdܬ,r22(!/'#PRYqNiIYy9P\\BVNGUQf~IY(9 %+F# *:IW :\ ? 'B~A>gS\TLuu5ddd( Y\\LII9BUU1Lxzz"INOOOt:ヷuʼ_Ѷm[Zn}az"'Ko2}tf̘楗^"<<ϥ'PPX@zZ:TWWSZZJVVVL[;EQ(..q>@@@z<< ___\3|PZZ… ܹ3M6f5NǾm"ni+..ܜ-ssVN$@Vn.9Ȋ&UEEEEa8 fcDDBE_??\\\0c; &ǪL^ٱS[bddPK@gJ/S48cV٫jj(,6@P+@)! @%-56- ֬ն ԶM6e̘בe{r#GSHZ;!GHd4f77\UU#´yEAJ#搛IFJ E=ɠ#" P:6nLX^C233ټy{&raJJ :tn]y(.x5m Dyz3P'Eʊ A@eJKj\RVPLIaՕX+P*q ei'N\{صk7ofǎd%;B4i(j8ٌ9A6GQJJJˣ|˩ҢE IHHhjǪr̙ßyz???wΪUT;VϘ-[ gȐ!q뭷yf',,0;xxⓖR^V~Qm!88 ̻Kf͘0a=oy,A 2]z?-[uV_^AE7o9EWWWL s㊊ JKKCUU ʢ;Z"!!v]'EQصk6l`ܹ&NMhKO?yŴ9| (ɡ4/* E H$A@\? :ZPƓkVQjEE(`6c$<"[Ӳu+.W6df5P^F#oicZ^~Wddh Mu RUt:#dYfʔ)=!gydeexbo,\]] e˖i}7qwwb~t9P_@ii)%%%gA !!Rv\ZVMnY1a)S\R/>O='"6_ҕ+I?ırCDшlF1yx IA#͠!֘(6trbLNemZ( G QXVm]~AiD]KNy8`r]\ pDxeK I'7A|<Q] l˖pغ֭:Щ3k$Ԟj'BwԬv#4o11\^rY("#WRRByy9%V+Ֆj%UûvSƷQqswh47&ɡĕ9?/͛_@ ^>xiS*RUU h4b2k/[IQJ ϣ ?c?xg;]yYD-1~ NEK@@FQljTE=krF''^^^[Vrsr%3#$FͷG+\ho)כL&˚5kX`< b ZnСC ::WFO?ԩSIMMۛs.g}ɓ'3<Ð!C̭JJJXb0m4f͚uswܸqѪU+ƎkƄ HLLt ;vjz6|8/YUsakf"Q^Lԑ ,UEs=VYA[eQMc4RfVpwj2]]hG _У!!ZoMA\gtI``0XPZe I@UU-%fnnn BX‰q=(Cp1UQj_^QЦ]<٤eڵ<=b3y`̙X4iBHHfIQPqvr`'|ɺhނ6qmH:6RZRʈ#巭V+w尿MDHLL ޟ@Ν>}:~-Ѽ~kNF͛qww硇c֬Yٳ@ޟ^\[vax 5k_|ڵ;+<|03g --۽“O>;_%<<~{sGSLat҅F$JȊ ˎe3EEű~#"EdGD^^ HlPSPP"lLIao]wqAxRyuf9ՍϮL;? >y`t4U;eP5D:k/SU֝;zCؗ+.7,y6Ԍ*:SV8-Z?̛}NL֨ LDxʲ B&My2e <q$''wѯ_?z {o'>>>tA7_Cdd$wqFRRgE-Zƀ(,,ˋSF%ܸ{޽;cƌՕ@ظq#~ ۷wGHk?_)h*6DPRL3 ?3HT'h~Z$T<{ˋCr'xxx8\ś/_̙3yر#"˲P_1vl;^_?_vj6Y9taaa״$I VOQƏ|/on??ADU-yYiAh xyҨ12ymτѻW/tZ&˼Fٿ_\c'vcN-]X~dEJmԋYӕp't‰Ç9ڊ$JXkDH.6A@c*LeEE}$I(Id~8Aii)O>ܟ-zG UR]U}IMO@Jbb"YYYdffTu7DDDQk"5EΝOyUqqqn!=<edӃ]TbE$$IkEajRD z;㙾S)` e+OiժQQQurTS$N8qBPhuk۔Vܙc DȊF6UE9ޖNǚeKwHE7\_99YkI٢bZ<r;[fn/6E3qe^m e+ "^J/:%3uc&9tjmgYWVb)2¢"ҳI"@mBhe}J!B /<e{_oW+&׊tHU FZ7 +**];ٳc' 55$ҧg&#'3ظ8>t~uz̴4ĉٳg۶m& 2`СC!>>>b^'|EQx_o(ǝ)( "Rf\.}fQXXH0d2Nll1qEEy9(FZ~JKKؽ{7(Bvv6YYYL6DF#6 ٌԋ&$&!#u4tBzHMEJN>pߏGС(>f7oFLI!媫$&iOAz\\F~?ޒܕގY0i2dfŢ;dU寻]loת*ƘX;a<ӰsaKsKbԣ%U$c6v Lcj㟀HF^ r8/3(BMY)д?UUx^V=<A.~* h$@}hUz1ڪ*v '6>TDbZ:ѱ&#&#LFDIr.FFSUV# !2H>}hMG~׮]=zBq7( $aXz8@("rcbb(,,$::믿ł$I CD(۸>#rľ, _=E¹***d$I"Lgg'(FlPx^fL&SdI"#Gd9a;ۤF `khAdB‰-[(cUEw!ѶzMdZ}y9ł 65˵(QB󖺗xHKa$M"HGTUⁱbIy/DQ8; #ˊB[( I8.0utzjX,ߨLJ"+T6^VdT9"+G& r _bsݴ)ԖG)/](~"QQ H7'ђt~:91`& B_8Dxq'MFfOOK]-omڂbj2F |HIJe|\tE$$$[o" \ʚ/_N>}?>yyyHDV|s=ǪU(,,Tu9N|>/FE. K.vİ\**pU#G0'?{wRj"'mU+ hA8tB9V!zbZ:!nbnG}^saZZIfA=GΝ;ټy3>EEE8, q8.Rrrrxw U1I0dɒ%v&Luzͺu0avKFS#t:袋4h+VajfΜIjJ*V4fϞ͕W^ɲeسg#su  j[,W1- fM\MhԶijwh|5`++ а'MaϪbX>|8;v ??_:6 0l&>}>M\*~gbxHk+?=| IX9TΚ_^ǶKCQqЗVG:::::3Q$\$~DVd:ݝLii)[nXߑG!%%Yf'PVVƎ;BdOᒴXioBTģy02[=Lɠ/SGGGG;C$+ә?>>:>Cx "FAtb0yd Y~=˗/gРAѲ~z ѣ1O?4Rfmb2d v.C>?a?Յf,XBhԅɉ@T4\|1 +C}=LAF&0 |KU=n{\2dBJV|&1}5)h$9 LJd6sw:HKK <7ofڴiL2N'\wu޽[ߙG!99.rJ*V\,\}=]~ٺu+_w=O?4^{-fHQk V$cԩL:4bccIMM嗿!s`#>~hN'^7|.nw$TXexUU#TNeN''N^`͚5FƏږ[$++s=?KtT4,?o'ECl:ܒ+Brr2Æ cӦM|([oMcc#Y2/^̘1cX,ձzjV\~3#ݎ VI)X~dD!/[*χUgANlo={`'+5Q O|M F3=X6l /xq"{ZxlV1-(~o%bzY]`!EL4Q 3/X'1X(N {dA@Dhn%793g䬳bG3.3{O#ql/_N  ;;H(DE{(IآhoiFD F#Wk ,ɬo'3'.Nl|<򗔗GBj*r p=p7/0zdvoK.cKkk+eeelܸ{w}: 8wt.ZЯV'"4Rx'ͣ.3y2=ס<* 9F ׄd8O8Զ)+5lcà0u*u@5M1.TZrI,LT5Dɬ.0utί?Ge$گ~EÈpɵQƄ[U9^g(6U|>A IP9HCN.Jvfvjkɵٳ˯_O?46l`dgg &&&RCPnjClLa<RodqX&Ǝ#m۶Ԅ( +BGG. Euu5۷o[oeԩ1LNJW^Il۸3g}.x饗Xr%gD믧~uQXXHff&QQQأٳ*+#69 ws b1.vҜdlJKVN:_3::W814WTraf8*NF1: Ľ& .7y }SSq9ikhrxhoo*C{w$:7>?֮ś t8 l*ʯq@(g ^yuCÆAZzH*=eXjd>bYgkV7[)遖ؿAr߫aG[.l0>9 e.mߋq݃ٛ^ E4 pr֭YbÑ3->}hMF,vvQ0[-;2FafXA>¢Q=0# + ޮ.~?]N^]x; WC=F)ss9 _xڤ3^e3 f3_Ϟ^@}c#EF-[]jUUU8SSLyw#eImfb:?c|b!{E~[6X:o3O'7FɄC3)H `ޝHE0;=xݿ`}}^|7]őD 2v "ٍ i4OSS.Lf͚ŴizutttM7ݤv'9< kV`,fD<&,2M؅Vue>N{z4(jP{#TUn=NNWvkk&tͷʨQ[bfA1y"c5|jFŌ$:>h$*6(g,dfE< R!qBY٩ ˶&7|<^ &rrs9gh B!|c2vX~?[neڵlܸ vÁb!::X FV5"V+F85LgggD`~~?n~?tvv0 63f0bĈc%yiB-'p(:ؽ< Sυ+0煇7Θ?܏{a2e SL͛7zj9:F3=7n6tqT7G_@y(Yg&|@Κwao{Y}ۯɹLzy[~z+aȚ˛{fOg)& Æq饗2bbbbH[n[nuWIcU%T1bּ&v3{YWUOֽ hB\^&4}>v >r,U%b`~r5d$9^YfYeVY6/1 2]ZI$֬^wFNN999\-Wq׮]47S\\Lɾ}]%PT0Xm3*߾o* tPU!h4HLL C ҷo_?`iNa25jTdYUUؼe3Jilldڵ UU#Oa WT%"8UUnNBBSNeРAzH{<iƫ矁^xw [? znͽ|al6&L`„ pk䗔LeY)[<ʟ^J? Lo@JI Us,g7msYf-k4j?soSƽbkΚä7=@̗w?D;o7:G`Ɍ%lټ2里:E^ţ$iO!'YQH0H$ & lƙNfF3x>ĶK˘D x ( %7D" LfL4 eee(| WUr9,zR]] sDfrrrX,(BBB?`}ckWÕB^>u<8{74/ MokSzw9 xe1:^|^*p\;g+ Pw޹ U(9e yLVIMIpTJu 9Xcc#iLf IDATz$ K{S?K2I(hRSHK%>!4θLuwhzA/?-i2bꆨ L$16W):N9An֮] @||a0P{kύ~=?PU]E3 ~ dffbxpjf3Qv;Evߧ::')$&&ү}gFOkk3G!YV`A Z2{0us*~O9Ç~xL۵dl2.";<.r"UU[;/+:s=T`,.-+ T)DG#GT_d<&:ǎ7utttttgc0|~ӟ"o&6srUWZJqq13gd <W^y;wr2|<~0tttNjj:;yxLJ="=RviF#Q}2SGGGGGȦMxp .bŊ|l޼'( ׯn6 ,44s`Æ PTT\kjXLAJ*hn.HLp.~ȼyYl@~m*+z4M0+BYY6~_xy<jkks)˼_V] rˀbįTx<.6]`SGGGGGgy+~'xn y]ii)rw=,XUUeW^}i#BhYY+WI1LKK=ޗaBYȃd0˭Ej=!::::::';wdǎ[vVZŃ>1 y晬]+{,索*R4"* SY)JSc#JEY---Gl*&tQP5]e!IW$^`&%&BWF TH::::::'o0`^xիW3yd4iIIIoSTT(,]c<ڥ<|>JKٻ{7_RQYI[SFTYB})RDfF: :l(6ڙN/Q^Quپ};шpsb (L&1uEN|lڴ  x<ǰa9r$?mi(7aM&7t筷W^aРAgϞ=lٲ@;VaǸ`v2w^>[vr3QvN'dP™gf;=n`0ȺuNO'tuuIvv6 >#F4:o{KuSIɴ&&<cTd6c4pHt sΝ#* χ(|^~~\UŚ{xkbZ[Ig?)gsqz]{,l{ ե81Zz9_aqU0G ~iPtt?;`q=R(ts::`|_mHSC=I}H$>1Orz:Q1$JHFC$?l2#WTQ0G]& _hUQ3QYQtS_UKb*ngߧB&M =M,]kײ{nl6999$''3j(.2&#FIf!d L&$I:\Q~$"'h"Z[[INNfʔ)}ٌ59NS?}FGG3c &N{, III?@ wߍ( nv~Z{p]vn:q:Ӈ8 EQcxdBţڱ,QU54x3 FQSSCmm-< .L&OyH[axgk֧/cF22[0X,f-\EvC y V+*QSӐ~Z^SY'ws17:\B@?g,FJw߯$|A`!yyt3]y2ě)`4o.bnOYS/Eرm̺NӳLFFFɄ!4!QC"p<~sv`pkhpMiILn^#Ə'( ȁ͍T~v76_-sU'SKSOr8p Ç+fa20̑s;zD* _z(233磺;w2o<kNс"***Xcc#^x!}2>SnF hᡕT|>ILL$ @rr2'~Yx1 ,@e 8q"\s fłhh2a2{̃{Î^;}}]TW_sm!s/&cׇtMb,V$@cjXF# C(OMN7p ZZ c×_C_ٳe5( dF>{UFz`fBDc ywE1P5ow @}=X`TXnj9]`Ꜳqw|twfɌl 1zPS `D--15L`ĉ-[0oox8DQ$/'\z)/,]0v  y`BH=SQADeG|lF]^ˍW_MBbbSe50+5e26 c7OʉLY!NAVfҿp0湬\%PTT#<=_}G ~_JDQr--AQ/HHH ρwhƫ~bO>Aff&-B$~q7 t8eҤIz0|pnVMСC1-°axW?ALL ?8\pyyyǕS]׿իV3}tbcceaǢ$z ;N_BQQ#F,"IT>iW\8DE9qBSPA5t|)"$%a:i0DE,4EOI _ڊa`!ѣ:cBb䥾J>Glb" `We]d'%~HQ@Vڦ (twE bޝm7LKK \'}gDΝh)){P?*izƸQ8wT&ϰC1B`']`꜒䠟<~'&'AX;ӦbAQ֭[Gn^.qθpgW_}Egg'IIIɍT%į~+$S`\\3g .~&6iӦ1eyA`0r@||<>5אNTTImǢ(R[[_̨Qx饗x<=oiiaӦMb!:G[}RV0 A=D0ijVڌi]%Q-/Ktmޯ@SUDILF  FڿH$Chc6`JTTņ*`Q#:JɊ Rsd4a2l\9{6?5 EUuug^\.vlŔ}Kއjrބ  ƌJA~! 9YfE?'=cg]x}sI("I9:@HXSc=72}9k0p'{﹗1cp"'wO>?FQMvʅxP`p GQ*Bsׇ8ٻw/wu'OfƌvAN6 ^v>#V^ @QQiۊGx'5 ج0e cuu ROL T!~,ں֧B,O7cINA0Q:;zq:b@ *#VlDqpп?tvByA)˼g7,V=/{4UeO{&fV+^<0L938ǘr5.0uNMTQu-\t/Y̯o&P8t%=+[Q@jlB52FKoknfܲ}F|wr g^B.tR̙CFFǏgԨQ*}a `81\SQ//ٱcÇgΜ9 y9X ̝;-[ƥ^J~0a#F 3#QI B<aݿ_|QEk7z|>JJJXj_|cȑp Hڵku;93l6=ZF@..mNږ}55)>͆OECG N6!rX3PeG0H2^@ t^o_<{qL LN +?kBFǷn[6%}ri^w&(_b0P<"usIlr2¬P?gúiZ4d(YYeP ddf(J#H" jzmnUE* ,k+}Cmuee܁BM~C~Q"`OVty㦛nc׮]lذz(**"''xE[6Q7rEAKe޽ڵjL)Spw@UU~POCq7uV ,YB{{; >,2dDLE>F;B6 {T{OeYFVdJKc۶ml߾ 238n ӉdX?:،#`Pj++Y+-WRR~H_?P`F꠳?ʂ-5) ƌo҄j߫ V} rZ 6WK}puhȜ7^( ;S2.0utʌNKz^.̾Ax޴ڪ ꫪy陧iki JrZss9쨊ULJM#)%x&V* &>UU47jFFr  /31 AWQ9(&;9<,#"C aС̝;Muu5۶mc۶m477yo߾ZGAA&L"> ::0lٲ*{~uYL8B4 ᄧPy%Ibȑ=Qioo-[_Ȏ;0dee0Ab83A([̺uؼys9DBB---FtFg?_S2}tLfCs HQYp&B;\.M(~I#df1^xҋ?p#dfU{7hߩ{˷Po@gTs//€EQL]PGދ_Y@HAln>aXQ92A:aØ Z`hurQSZAEI1.yv*k ~8~AKL$3//T1, 0 gBE{{yo{u\̞=+ǃ}@y8"""8p n#(( }!0g!CF\_Cxl[(ڵD$OY >C*^Mc}SsOqٌ,ttt1/))^/.Vjjjhnn;wqFE ΘvvvR[[{|><Hss3w>ZV"""ouFTT )8 э:  3֯];A&@~a=$%BSӌK@zGQf,b)&rBESL@ X,6n>s1x`|>6mEon:BSS2Laa!o_Q#Gxزu .+W$""@HJJ:f$ g'=NF{FR mZ1Ƥ]8.#5uTWXQWLĠp@ 0y>,޳yѿN FHHaaa&L"L#kDx$QQQ̝;|BCC %88 .ⲷρhFȩh-HHF} ^N &?ul϶Q8)"--kFGYm$°ٌ!77n:ԋ[<dee+3#;;'xtR:;;y'6lX{=0ptvuR]]M\\adr izcI>I¤(=Z|(FM9TL}*$LBo~gBI]W7΂MK3DBL $$Q~&a*㹉~0%3P: k210*RI8I4|1[,ȲF[b"I2OnIՆkxnNfqɲ 04Au, ,xY!Z躎wZoE4<bRP*,ZhCpZn zgKj2kIp݇8{GWIhllskKK gM|7̜9@ bkO@@8ɂb d^Y!u KN6fPv0Lfd $;t ٗo{\0Ra++%f F+/;oØFTぢbk>P09κ&3K2ɐG_$PDc2m&ښ#4 ˗c  oܸ#Y6BzyPq?7l櫚9P%ńl2ĆM_mieҤI$$$Ɔ #..0"BaZy衇hjj&&&kƼyXf?)255̛7^~rUU9szj>s8p ?Wfڵ\4MCQ$IukI>((( 11[ /P]]oAppdYϡꫯV͛Grr2/_v3+SQ?ncҥ$''q}ROرsGLuUs/c cWP_OZZƍ#2B8cb|v-́FiRqwD׍ ш>̤Fj;5gT#kQ K/Q`x ArAqTWj\3(G̲98^lbh#@p2󗧟fgq>3hpҲ]U g[юSt]rﯹ[HJ\nWt/`%vH IIeI1TSy#E~ GGHvv0fロ+Vot:)((`СDEE:?0]]])||jF|\<='l˚sJ*++4~j%>>LX,tuua6l@ww7gf괩$%%|<+ Rv:O?!c=FPPnZB%qgKپl55K/iapV [?՟}@;CZg?vN.3`"+8.@fĈ0t([{no VX/2Ҩ C@z}3u nx>Q =]eumcJFep!Jfxj?f NF23w:_ց&3 5Y˧I0ifvmcKq)%{tB,gfIR4$YB44]nEł(xݞt,6$qf3j\.Ie $CPMT}ݹ];1B ddAA'6w^ϟرc3g0sغu+[ n:oߎf#33CCtt4$z@ՁnGp5'dG)))z9r$yyy >zjMn#Gaa!%%%\;wLVV$&&cǺnͫ>nU3-6㉿xI쉈%Io$_RЏ$t?_ƻ%\q̼ч_0W@TըUttt?tnva, ޵F*kظ};h 1 &ֈlŃb4!)iH>ycvvkm5j?uZ0kkI&82qdfݯq DDDD䙍{4׮埅E`|wPa@(BĪ*hin|^vˇkVpvpDJjB%@lR2vRRPFC#a>-` Cc]]mmtRW]jմaXHapJ?.7үO@p5СC?~*sdOXeL^wnmj9O{c?*n%cTUE6Џ'-%$cPl,QȒLDNBl,6p"?#iG¸Xa.X 8?X^דkR(!0Y/J 8ǰZ"mU X $ƾ^Ǎ K9S߽ @ fAH "GS @ NOi XDO !0@ 8 /.@AD @p:::رc꣤ΎdEm۷:!f22IO@4lV+iiiDEEBFF+bTM x=hFEEwFyGfFIty.p8(++vi&TMQ^^NEE qbb"Ȋ :73`@.gMp:.8Pw/#(*+˒DZ䦧v FĤpGs8bqA)@pؽ{7*Yj(,Ž2ˆMLDV̤i;a2V[Ik}U|s"xyOhmtPo9%'3< HNN\p$;;u]pa ?`)++c۶m|gڵvHJJb,(Btt42755,ZꣶnBCC2dƍ#++AzFfgW''EIq1;w`KQ9mn7@@j1jGY!6_* @[y*?^``p^F&;3\N1ϫv,suB? 99d&Lc"##eٿqwԞޚ:]vm6V^MEEL|8cǎ%<|A>3&Nٳ vj*}f̘C=߿>`ѢEX[ocyi)L tx]P?4$\ %jq?,S'ND>L-li)h: Nc}嗓w݃rnG'Ecqݺ)+**⩧⮻bĈh14M{北op4U~Yq8_ 8[oUY,.o¸kCNx F_B͆y1i$a0C.=F9n<FVd55̟ /PvE!y_\cǮ]\۰l煘KKJwqp8g(EE\6ˆ#(**⥗^N`ѢE|Xb.\͛  9剦kFDDG g~onnfB\ O=Ŏ ~$/qMհC4?>(}|]:tX+-hn7vchI=Y4ԣ(#ft@@Cw7OmU$/ {BHˮwO?b1dHl6+d_PNO0cHI v)߳]e:nW7gAeƌٹs'ӧOgbZ1L} vrdٲe3y4w>{OLL2ŋSXXȌ3HKKfa ߗO<[l^Cww7,[;w2z^umXnK."8"+q42s?[L قlB\WN$58JKiz2241c0M]ǶRZ7m\BƎ%(7kbҡ{%%4 4!05]穢bttQLOL @p5 #~VoS_0Ayyd $&.U" IDATńjl6c2Yڬ7ÉϓudYywHzx=C[k+{w젤p+߮k?xF4PVVƨѣ׀( {/ K|> B|RSS1Mج6, &鰳mkH{r\n^/nZnʦMhmm媫K/eҥ'*p8}wZFFN-( (++;fC2|pfp~}XeL&,>vrf֭lܸW_ͬf~iii'f }5k_ >d2HQ)KtW'둢cbEoѵj%?iNM4=8"QɦFڞ11[lq.Cƹ{7%%xBl\} ~45doR<4]7ƪNp2r^8V֯uXt;INM%}@ Dœl 7͘L&$Yj ) :"cN*MzzޣAS}蚎ATսf_b_KMFNG M|j*vؽ{7>a(5*ƍcĉܹkoRWWGBBdeeBxx8vݰ} Ť !HԳs?6ޓvQUn줢]vQUUEuu5tM烮|I;ʫOٱcԩ̚5"֯_?Ogg'1p@ j1 =rYرb9:[]שNv\UUEpp0Çgs @A_||&O, Dp\x!̘ %8JJqDIIGPFXL&(FRQLf$t$@wtu}(l2㮫?[q7 4W_hbn!C@VpѼlO>ױDZs'ZM 45BB ́Y ظ%6׀Ƅd$$q)@py<^l^r^~HDyi);Jع{^IŎ]XmGE + aوOfCt>ʍL4TMEW5kkhknFe> uutuhnhՉ$HHMeWElJ &E^.dn^]vNbH9/ERR\s _=رJnʒ%Khoop 2iiiDFFb2:t(b2',, XrHÁ(ܹ׋hhhjFvv6dffCUUNCddee%. <(~vvIOO'++'lٲ"˙?>uuuƢ( (g|X,bbb o:}$ItvvRUUC$݋Ͻ|dƎ_̰a oݘLȲo~adgC@(/S[K'aa`!'$a Ax8))XBC65UUa2kL j6Z6p:`@ej3fҶ{EExHf >xyy@TFENY{hLlba? YTM׍Uˍ;|uuu\9WFq*x0L2tP.2Բw|}}ŋ9NVV?.&X\\C n 00 ,?;Ess3_"%%GyD9bDz,ӟ_ˤIhoool6vihh|EQ툯;vXٌ l=EasW;֭[ !::H7ݶ ,XQ{!EÃa0#Fos-huu~0 BC`&PUkܴM4usFGCPv{ClHw/&̘Uw탢P-6M[UL5YFC=ۍN)>bя~$|^pI;<Y2e nwf0s=tM\c^#<<{YlSLaٻ픔HII L2EsLhG?# %I.2<1DߚJMY{k$IJee%\|L4 ٌΓO>m+'55q3|8S wѰ'946B}!Fo1d_իalf3~; ixXƱ*A%,4Rh5 6fgsDjYxk:>~?!+;i-hjrGH{[I*xwO~"N0~?g[ww7*eeeL݀f̙ ĕ+WsQPPܹs :Hbܸq̞=(ܮZaɓ'OHLHg'|J}jf1x`.^ Kc'L$))-[}wͰax<8Nl6ӦMzK/Aw3_*/8ɂ3kFJ C\NnEMQ`:(,D0Yc#nc!ˌl.HqMBKS# X?;RN%%%mQ#8n罪_zsmo|>^1c0qD\Á:f@p"ȲL]]/ q$''{^9r$ǏG4|>w9.+ x<R4L&ٴezV `͝;a`.24t*llQ cIVrˎzj~d)NHx]?زf5FMrV8eee̚5E 8loo祗^_ :nAttrhmmB-8ep8Xp!{ >ۍ$I8N֭[w}#"#k}}}{ݷo}^u.aT(,,D>h@pVS] ,1.g΂dbb1ƞHl {4xOF$鈢X9>aJ.G8[B` 笓Ćߟ[ogs}i:1^u]'N|>K-[ƝwɄ hMUU?̌3p\lذŋn: %$$ѣG駟=@p2hʕ+Yd ?O6m?Ueh'N'tyf/^̚5kHHH ,, /OɎ#OoN+سn  +.NFFeaPXݐ hUy9AuFLtYfe/yrܹsˑe(JRR=aDu6õ>Ȅ xINNfaY  J f+V?[nϜIMӈ>FEEi<#OL@@Vzgىn$I|>ZېeÇs@pVK >h[%F~,LFtj5cs [W_ר쟺?9qѠ'(cJFmg'0dqG1B` g UU{ƈd~>^x),ટ3&Itv~JT* BbB0'2 Ley袋˰X,}NHH&M:1zkfbԨQ|>`UU?tDd^5&YT$Kt;,x2run}` +˔)S;w.aBX(rZ޺3x`ΝkRXFww1>ge޽<36E@@cH n'< ..ΰ7]CeH$.oG~;C;uNabX ۫nzٷo ,`ncα>*| 0DKK Vwa„ {ol>b,TL&Eᰑ7wط[ Eq"GUbj`LHݳ>&M6ƚ.FmgH1RV}6| +#!&G^/A("Naĉ_<˕?4=(MҢ"}`HucO;5gId6zU>~5w1#))?(#IDaa!~-=s;wQѣYt) ,`Æ l6\.cĈ35kAXhQ#,cZO>l63zhq󉌌>n <<v|7$''3@TT[[[/(jPJ^^ɼrPF BAA6l8TUd2s<!2r 7( cZinjO?e̙$&E@ Gʕ0u!}ABSJJJm ,Ӧ50r7_W'@RyjݿSۋAB!0cpH2(^k0$$4TIe9J,Yw}FV_@q(ih>U}TV{P󮻆>=sW5qOb+YQeBlz^EAN67x#K*}]}袋HMMEe^/#f9sP]]}c&&&db>GqQ1_~%/`L:ɓ'S__wY$ EQPIgٲe2uTz >Oػw/-bҥdff,!tO׬aƘ1|LȆ L&)ZLXTQl߸DY+zU,Y³׮E8q"#L!/+.kQӧS7L<N7EoMK[Zŋ+^vl6Oٱc3fnGɶ2"}  #GBhkF4 ͱvm0fN EE~=H17̈DLW|-n5m/3gANdgb>CZɀ`V.""@pimme|׬ZݻĀ\22 705Mэn藇bR]R:zFQ=@e$IFe$EqMN*vdgqJKغq#1KRR8>YbK.rM~~>AO-XIi cHOO?fI4y}fRPe/(].SZZJ{{;ӧOgƌ <_R .]JP~%f`ԟe}˦+7jcon\COP|%w6of;o`:VI2= )t{5_Υ䆟QXQ+ 9u^_QƑDFF}RmmmְrŬ^dY&))ANDD111DGG:qv$o뽝h{kYtRYYIGG{aǎTVVFVV瓙I\\= _ZZZeOe%V_`%A__之fz-l7\漱og߇իwp]#?Ɯ!D5ڛ`Ȼ1^p= >Ξ4Ҿ obVvL%tۻи;C39!(E.)JB /Z*dEw2nm)fk%#[Ҍ5tgܙBP'X-M] 3{9^yH_/߮o?7u+Zh gЬTimz~{:s'=91='Y*g$ci`<4LpL ^g2J%iHJ{p>HߦyW^їWWU.UPv]K&cy::>#5Mmlh}kK^OھfjX3*JUѱ6ܖi2 Cޱ0-G5R.h%-// f\syy n&-cyV%yj7nhccCjM#`/NGa}uݓǾ(VzzѴ`[Z ?5bZ>IDAT+Hz][[[g6777j,eYEQR*e+(*fNlOm=l`VqE Ǒu3N$Ӕqwlۚ8:ԑQqf[z/+i w*z/("ry\΀,Kei˛Que{dz=bѦy z=a( m?|=ٶz]Uu@9ǂёزmUffTpA,mKYg |$I N'^O|E<I2-]|&'%IUh?q1 {Ez{ P o!#IdeZip4 CxN `&L@0 `& @0 `&  x#Zl:IENDB`cdhit-4.6.8/doc/Figure4.png000066400000000000000000000741031312257207200154120ustar00rootroot00000000000000PNG  IHDR͉sRGBbKGD pHYs  tIME (H"tEXtCommentCreated with GIMP on a MacwC IDATxi\yսU]]M6wZ^[%oY& `3̇|0d$ޢ$)YdRDJMj6}:bq&)V@Xu}}=n!B!4B!d !B!IB!d !B!$B!Bl!B!$B!BH-B!$B!BH-B!$[!BIB!$[!BIB!d !BJol6i4  IGu'VE$LRV;H?EG"lШ7u`0FjtVEVCu<& LZRPV+XVl6M(4 u]qɄf`0P,i4KEZ m\i4)Z~6 Z-*X\r=ϑi6 9l6)JF7ivMP^S,1*\.#Kfl&{WF*L&SO,jZRDTK,j$IZFuױl4hP,%I^dzXjTջr|6^o,FbT.Q.uZmCt}7ͻnb P,l4w<^7}XF#V붱Too덥hb6ohY-HkkkXV6+págmml6vbs0[]]RP:Ava5X1kubjbg|ÁdRdd3d>/~rJ R Ánqc2h6TjX,\n>O}J‚ av;iBZtbHh4@6X,H$0B!V+s+X^^F4|>IݦZ66Lh:m֢kdҙudb`Z,JR)WHv"p};NN'@F9R(p8X,> m=Y~hbAuJrvلurL,hƕjj"fύFb{m<4ԓdsyqm?i* d J&R*b~C?`0|=ݏXV\zb XuTuD"A"g~_bZLV^300pױTZ$LKXO}XJRy,>I>oL&# #\¥K$w^|>tL&/2x<FGGoht: @ `׮]o>VUq&!O:}pe8}4ru]'ONJ6Mswuyy}{?OD~%^|E2'O$J;`6y'|x<&Ν#s)V #xױT(زe ~P(l^w,=se>1::X:պXT*ݴKrH$|eN8+++%ƅBbҥKKbl#pERMW%Ưi.뎱t6^O,7mcǃ߹XU? r0!>${mmG''022B$e,?_H&_TJ}ݻwwFlp~pI&''1L1`ٳڹTv^/6mGUW/?CCCݻF(\^{y^xvA V133sC?lN?۷o'NC=Ν; _ m|%/忨}~"V> ,,,ٺu+cư-rEAJﶱh$-Ş6S8;;__DZZ7cǘr fzzfӧt7C ?XꞰ>Jxױu,E";R*bvvvO?۷R:2T|+wKKKK<3Oc//H'Kرc꫼[T.o… j7KKKK+}mN8X2=mD?KX[LX8{, W?6K}crҭx={0O<Y? ]q:d #!B!$B!Bl!B!$B!BH-B!$B!BH-B!$[!BIB!$[!B!IB!d !B!IB!d !B!$B!Bl!B!$B!BH-B!$B!BH-B!$[!BIB!$[!B!IB!d !B!IB!d !B!$B!Bl!B!$B!BH-B!$B!BH-B! ]@!⣭RP׉ 8r%jZ')u P( c2 w&!ͰD>geebiD"N'cج64[VFVWb$ n7.Ay}xٵkNtMh|lh4X[[:te^~eVVVTKKD"z)~?. ͆d!qo۴Z-</^$rz-?<#<LNNt:17}l6@.wwfbbBl!Bqw LܹsdY2TZF\Vh4x7Z&'&;w'Npi;F,T*F{Gb8q~~p8g>G6J%昛I$qRW^%H0??ygyꩧ὚&ϟ…  EN' `$[!#n?~g7jJښz-O|BxZ-6D .p)9 NgO9HP ͲbE*6gt^L%Y^^ÔeN'iZ4MxwصkXў${Dt]rC3jd !B+={yz0~gllLMj5昝U /;v`R)bowI&ʯ <AbaaۿP(l޼'xP( II"_`nnzݻ׾Jd0'JJx?077Ǒ#GV 2l6ˏcNgaa}Yq{-$B!$b~~7|\.^7@OYLNN{^7vH&kٳ3\>`0$H… y6mڄI|,?<4 N'###x}^<^v>Ο? _Wgvkx-$B!qfg:#YGjjbXT9`tnF=7{=^ڭ* Έu"nl5{VgnnN=iC%fgQ,)w{iifSMg٤nh40jF~H-BdX?Οٟq)\E-H@,⅋T*\.{eo>{,O BBPOj4l6c2RSNf?_o"NJϑ#Gx駙fll ٳgf$ :lٲ>Oزe$[! @0h0<>,^@N{h48vrYz@OfX ?6m"LL&T*.b`<jM%ZP8j`0JH&u5=00 FvM<G42xgnqIB!FW_y˗/ww?t:ͦ͛x jd)+]9rl6K0drr/| >3ug1 %΁upsN"nZcǎqIN8Ν;azzIlZ읻ves<={bjeddU>:6J"d2{%IB!GP]ZZbeuEbM\t) E(hF^^JXYY`ZbQm4ow_hvobt9ĤԜr)&zut:}C-Bt6Ll~ovRtC$B!z?< Uɰnng>oaa˿oo~* gϞUH$FXL"LN{n{nFFFM7.ggv'>:FO3;.kkk|?)_җg֭ߗEe$B!`p Fj4hNZx^5jUkt`{OH9]1ЩxޛN h0׮yrL,#RTg02jU Q32<$333b]D";y$oFOYFs=zgH87oިť%>L"bk.<`,(V'|~IZeqi%r{ ˿8p_FB!>F#r9;^T*r9VZ.]Zb0x筷OOM;#}}}=&)6eorz]}oǶm$[!Bph4ػw/VR)jhTh0P#`ݻw3>>n3 :sTb1JRO7@ f100g۶ma(Kb1@jOQgD"bJh4h$ a  x=d !B^F>|>_9uT{Rtꤟ|I ggNl߾-[CO~C/ Щ ᇉD"?t*v,JjTj5~ӟreΝ;lܹsDQnKFVڣݙj+NJqn4bb\.J i dR-QT(z'\E^xN'W^%N/!JW(ur|E>XqPE=uLP@Ӵ b^Le3Y^iZn l3.WtRϱ~_Z-RtZ bu-jT-Jj!lp%^w8333dK~V{%Jxw)TU5ZN&gΜaaa3R_T8s 6 LP J1`@ *Th,J"QV,,.;TpܹradtժV%&vшjnc44a*X ˅,-/;#L200dl6t:) ~6Rd0mfUZng˖-&\.GVcϞ=lݺ@ ֭[;kFfSO=nZ cr{OWWU F;wfw^v j5hfO=n۷3<5bsU2 \p8|~ul6K  `)ˬP.ՉnW;Ow^"fh4F67ol6344b)ϓfflٲ~FGGUߊhD"T*驺6mz@ @'d2 U,uj\.x=ccc p:a&''>zۚjv;f%u~0F6;<#$I8^bi֭ }vM:MZ&H:>%\6G\f׮]=׶v\W5ؘY,~}Q<۶mSd0zf1uܳ뷽mo2x" fE(7h*2}>6oެz]Tslڴ'2 \j4pǣڸ;qԽ0q"LMxGVKt:ٿ?H&Wu\.\yytDRP,o}^2Թ[sifY-}XZ\\T\Z-VWW|<:55000fWƢDע\xt*ٳgbϫvpzb!?$bDٳsܹGk$Ѷf?\xGFFԿNm40y*iU +b1:8W*,055` 3<4|Cݽ:6 l6v;a4B45h4hZb٘VKjFEMd2ju&J&Q?/ zq:x^u06ٺ6q:`vkZEuVbrعs'R)v;> \. DT,N4M%Y 5un366FVt6&DZihAjt۰ǏgeeR`vN'6 MӨV,--j0Lr Dyf~a, fv>N&Aut]ިw.2A͆jeyy|!ƑH~@2ݻwfF| ǒ`ʹmЛtQvjؽ{7TJaqqM(˔el٢JR66nZ*^Y^`0`tb2nK~]vxزe hZd2aZԅfT2~+f:ǫX,bQc:)axM| rAvnP(NIwy*f,jqu۸]`L,l6wQMg׮]T}R76N'ꢦKxD"l͆I=f^{^X,eѨyI3j`@}nmZ1wb;pmR1B ۍE9y$˅ su]'Lt:YXXPyӽ~͛?dPFwX,3oDݹs'SSSlݺH`cXBuN.W~sc=zh4sʊ… j{D<W'vM4e``ϧFܻO{^n݊caayΜ9k>jV}ޡ{';uR4U'dh4ʑ#Gxwzr9٬E^/gΜ9񯮮RTl6VVV:'m2n˺w"k@;vpy* LVFzp8x52 ; 0Xcǎ:.\茘KĢ1Ѩ:)b1Ξ=KZZi/gΜiL&2 VFVcuuÎ;BaUsttFߺ+++,--qU|>sssiulقQm^W%RV˭1|z- <ַE.P(WVU\.vt:M2T*Q(V=3tBb鉥Jҩ{gn5R43G__ 2tXy{a[TX[[d2<ϟW"d_W' pj4=/i΀XwFɤ,dR}~w_|Erub)5NG*"HN'Pr̥K8yMړKn!>v;+*.4MSIv0h4R,y饗nY|>kv?~ MMMeVt`7͝˩7oҒJDF#T4::3*Խk2|2W^ȑ#wN> +|g߾}=Y,|>{v=zt}=9Χ?i {<99Çվz ns&{ߍٳG%Kf ;v7ߤ^sy4fcjj~'o}mo߾${޽,..oozc_~]n¦Md3YN8ѓXkjh6m399Y5<*EX,*l-ێTY,?ho~\pTߦR)uo/}Kevqyӝ'? z_K1l6vFc߯;n%J2;;O~~H$zsN8/,ϱO<쳝}ж|'X(v2$]{?44}]7\ncp:7=;N|>jjQ(jjf ]vc߆p8LdǎN&b m0V233oosA`6?i,{@e0vh\.uڈ${78uxL۝nx"m4_ߏnKkL&u~ϽK݇hTzcf?y;J100@2V$݋~I$ofKiLLLjʻZto7H&LNNw^~w~'S2"|z3<ێ|K.o[/~__6LN{^n0p~o?L>^/|I&&&CG9az<[ӛt>O߿¥?СCiL&_L8fjjs8v¡# CݷΞ=˙3g _Ҵww5ٙVΝ;ٲe [wr9<ѣGq\BΝ;$7߯ڻ(}7{KKK|;ҥK044Wo{>o߾}h]d< }V_h6~ٟ߯}k\.\.I^l|o&^`eeEe۝Ng,Q󼴺??opQƘ3 =z^Zo,]{7lbbbCtmu=01>g?Y4?YXXСC,..h4u|3lڴ'xBf9f;wlm0T];]VUxATE5Fㆯ,FCwuhhm۶BA=7Z*M 266֭[nfp8|Ǿ*~55dbxhH$¶mynԭm6 2omh4t5Xd2XѭvkDעjFX__[n4|ӲKx=ݮnLu6mtL&xzۯ%|Ry;sN7Vv;>Km m^ tgWf._}>=22¶m${B!QwdO>E\ӟ4\W_}D"E m%IB!Xv?D&9SzZ!IB!GZwA:S|zf\F($B!7h?$oߥ B!$[!BIB!$[!B!IB!d !B!IB!Bl!B!$B!Bl!B!$B!BH-B!$B!BH-B!$[!BIB!$[!Bq7ti!B;&DjJ<\.syjY,硇d22 l% ˔J%F#CCC8FFYm imZF) ,I$\.n7 x<7}vMT"?^m6\.ӘfIB!KWWWrb1_Rz<<{`߭l+W+ď~#4gya>O wL+ W^emmÇsq=ʖ-[Ge&be7T|+yfIB!ĽT*j5.\Ǐ'˱LP 7b˗/i&ڭ ?_XX`~~ .o3;;K:&NiZb12>\.c׮]X,`/--qXXX |8ޫjquaKel6D"[^0H-B!֥nST( >|ӧO}OtJwmH(.(K줖&i&tIL;IΤO2tδdz3mQc_8-YPDQ A;p<1L9%k!s9?|011={7i~p)^}\o.RDkk+r JHR\~FC 9dOO3>>NP\ IDATE(-B!('?͛KܼyB~H$dby;V2Dz =|ӟP.y7H;=zfBzz$x\fdd??! zI&$I^z%q tuve#zT*/2.\_2pH4AB!QZ EQڵkܺu%V+BWW& ͆F,VSb1nMRߵk  CR&X,r9fffj$I, - x< zZ[[ $ 8/^`uu9岺zNP 033 A$fm{-l!BG<`ΰ©Sx뭷bv8fttÎlA~hXYYa||>`dd8_M={vzk׮dhoohXkkkKSTDQ7. JSSW^eaa??QYVz*$ v;$c4wlKB!xu,,..bP(ad45h4z4Z zzT|oyE.#mY7]n굺Z#XV//+LNNNt:6M FqZG.#ˡ(zaѢpnnj:T**zJ}:-ZFْr B!jnbmm!DFEcx뭷ԛ Ym455sbb~0vZ-. VxXڵkE*Je.*X[[W_ӌExWL˗/Jp:V qyA[BB!ģލ#S,h\&311A<t[[Vl6K0xМNߴ:Ѹ>LRJB2P., :ju}VQjj5DѠh4j_3'zxccu X,tz. K{{;+++P,Vt:L&V׋rQ.H$x<44c6h4$IVVVPHKK `P(RQ$ t:BD"pl!BKiZVkC0<vf:,̳>x'=0G z=,n388H8r[qi.\d``>vMOOݼ+LMO1L8pA.'4/W\!a6FCA zֶV1 q~~-BڨK~3h4X-MB:|^Ad6z7QIm6w8Άj1LvBA](H$B8vY]]eiqIv88::{zFFh0ac{ l!B`0OWuԹVjr}h:}322B.ʕ+$D׫NSX]]%T'Z F6эjʑ#GPJ^Gc00  b/bC-vww7~K&-B!T{gdG{5u B쏰^Fq:zۍfkx^.#t91YϩRpE&oM6kX,*ۜ9s掵H?Ϟ={OXdffJB4\.399ɭ[PH$³>l!BHr(araaY<7o$qY_K.155(t:FҢ䦦& ,ZuҚr333 4 Hv~?J:* jD"kԑꦦ&.7/N# QT0Ly\B<'S.abbRj%$d !BFZh$J੧^xi~h7܍hE! q19znvrطoӧ~?F;Ze:}YZ[[r5`0륿L&=l|.O<guuEQ!fqNE(icZy~?~\nl!BqgF_yWP ,--ﲼ=Vbp1ZZZطo-ɤv y={áCg>Ûo< zÇ :ja⛍ewN>kVe",ohuFFFT*x[_[BB!6ژ0D)+Fz=n{'Ky}̍0S6FۏnobbIB!&zB@P՟"\.x cx<!;ri}]p Bz*ۘZ{J%^(;>ivNI,'8wZrLeoy߰>+۵kĖbt:ZZZhjjn鈑fL&6wRĻ0H&\~%o5JqUN8A2$Ny;^]t#.4KK\r7g~b9A:Vq ,VC\‚۩VQ#LrM$.l~^O$Q suFTTXZZ"NfՐ=5=믿~w7 .f("x۷o?pǪZ;a̶krrR`0p-R}!s/2sssayy'Op8~]Y[[{.jbbwq^\\$ɠ|>h5[#t˅nd2}!wٲl6ˍ7n|d2˗h4dY ¦oO355#kT*.\زx|U4x^6{3nv=~l6oÇ`67Cv*J%X[[ɓ;:[}H$¾}I~h4JҎlNd& 2<<\ӧOo:*|1>XokXjmmAGGC&3Hh4J4eff {|{aZ䳡R0;;ӧ9y$:;#j7F۷l65 f?N"^{Jd:kH$BKK :nFQ75exxp8'uD6ennr0o6qbXx<[2*p7VWWY^^&͒ٚ|>ߎ|'cǎDX,4s$rON>'ˑ7>褒J(,--Zl6?Hxgg'O?4pys(:x "0 ,.,{i6immݑ``hhm ado055$|>O.\u6euvvr1EٱRX,,R VK[[ێ~hkk288H0|xCL4exxY>{U.qZp8FFV=}ns(---+Ėb\t'O211A.T*E>T*=Tj{pxBF[у,--=!;֒vuuۋhܱz`ǃfdd=Z z4ld2a2ؽ{7htWm+r-VVVXYY Egg><~qvwaQ Çimm%L\1|oƽ >G =zncZק@)+jvߴV^ﶯ_с޶=vu˗.syr#ۦiooZP(#u||bH>Gׇ{d"Pհܾ}Zf>'ͲF>388jS8}>ʿߕ_+r9um\J$T=?7>nh:l7npqdfXWҼˮVR)RHQ]]];6s$TT*!?N#`2 仡T.]Dl)8t׋'h#w|Ff`0ppMiXxhmmkZN'&m߿;NEQxwd2L&:::hoouG>vZ*'NX,N Hkk=uٮ}ػw/NAy&gΜ!7|j4ߏ㡳sƠxo #£7 `0]Zemmd25B{Gw5i.^V%z 8pH$"1d۷#NY),U6UO`ܖ F~K~|~vndhB^ghph9>>N\&ɠ( ٳGsrlb1L&rl6^`(|>|>ݻϝ;GP֭[q<ػw/hGJh&!BlNVp8̡CgggyYYYh4J2i0[i B![@Ѡhp:8N|~b & F#ӉޱfbIB!؎ӣ8Q?rՊhzl B!.?VT*T]-Bp.t뵾u2l!Bq6BO] B!l!B!$d !B!![!B!![!B B!BHB!BHB!BBB!B!B!-B!l!B!$d !B!$d !B!![!B B!B{] Bj$I"+++ 2 rYEix餻Jl6vh4w\~*"bnvl6<|Vˮ]lb1[t_KXl.DeN`0H0rzN>'N+/q8a4%d !B{S׉'VSH$'JϫxCoo/{GK!n7.CZ)/3??N_"Hgy׋А],}6KKK8q3gpIzzz'd(KCv.c~~$L4CBB!wڵk,--H& JҦqz-cWhkkWWq8ϛazzk׮qe&&&X]]euuU}NVƍq t:ahh԰칹9~H$dffX,ְ'|`KpӲjgf91APbG8`0l~-BT*˼ wd2ɋ/|:::B !{zz':uW_}˪댍[or(Jۻ)o`o\.TT*h4^RVT*mij 4MKB!6DC`0g>:::.x1LW{ôVvj/\vbHEl묭ƫӧ06 2 /_&Jqt:A<㦳󾃶l!BO|X^Y^)F~?vRK44㛖g47ugpaR!LxjłNSkkZ VKV^YѠh4uu_3O6m8NZ 1 `X?p۲,LFx<44c6tHprRh0RըT*EFtn> B!BU.,p8hbT*q(G"}Y GGGlXٳgIg|SqZŋLޚl(װX,U۷9s xār1|gϞ=|ߧX\ARF)LNNr-EٴB!&ZD"NRMFV:\,'5f[,ZZZ6w!1L8N'.\.GRayy‚uT.:Rp8hjjpw+ji:L;box^,ryFwr"DB|n B!Ϊ*ϟKF"zt:MXl4CWʹs8q/dn"LReְlFWW^zmiif>%db18dP(D{G;VUV_%Phôo^܌ᠣZZZx=B!ĝF/O}itT'Nz= +Gߏ7سg===:t|3kNÄa~i^/bW-NT‡tn~(J7xD"q;vp8̡Çh4322"Ӫ !B< ENZF^bl Amt|>F#lfJ^kՅ'xh6a47:M(@ ` L]I݋#t:X-H ׷jaeeޏn:;;}ZlTc~#z:JE}M}[_[BB!6PZF2$ϳ@Pp`6؏z;FXow(Gݎ׸7B!A6%K/qM^}U$@WW===̈#!{E2̎Vi:RD.caa.HL&պEV$I8i)]XhaxUkU,tYָq333ϓJH$8NfggZrPF_G$mx<ױm]dxxz2zw_ rQ;pm.^b1d2,/f{dbl.3gyy饗&QըVhZ.^"2۵k_0Lwf㩧bvn3p*fGa0p8l6f#LrY8jD";Ҷoߦ7^nWoTBXVD"M"E 8q:qlSAFj%َDl{OӼb1Ǚpw.qJ+++z> ^;#KKK,..rMnܸLLL[՘"HH$ O?4ZVBN8p˅8wgΜydwmml6&&&v|_G"u (Bss3tuu0݉x; ZV^FCkk+^~ڰXNFKK .6FFFԉ"e---kƿۿ}󧧧>$=hJȾ?'xP(ٳg-Yv^'ɨm~7̎d2Zb4fY2 ?8Դmbsx<Fp\d2-TU*xNVEo3gfD"mFIL,̙3r9:QovR(ȑ#?@}ؕeVVVVj5t:& PaԓD#Qg6 Et:y&ccc$;vZF-~?zގ{t:9r~ݻwf7MMzjDB==Hꎇl~?izzzhooW|;^/N={xkkkkj_vvucj B].3<]r\|;n|+_sG/*?v!O}=K[M?affvД.555ۇdpp .9}#[c9p||v {GCR}z|_|^w,W_%S*zگMMM;Z* XbG>uwvI8Cv(`[5R?ՐmZyg8pqߎ9Hm͛7/7p=zT6즦&D#̒H$fJ%t:/|ᑿLRh`0B;Z#VhiiRӝ~͸Bv;:NvCbw`/n]vg:::p\s-l6VZ>7RPTtb6e<-ASשjhuZtZz򅐐-p8X]]vlh4A⁡hh4X-Bj#VQUZ Z(|iZ,!>W^n)J\pB@Th4ׇlrIVSƅ|!ĽO(VK PTL& X~!Z2 VVx-B!![!B|G(B!l!B!$d !B!![!B!![!B B!BHB!BܕA_ щIENDB`cdhit-4.6.8/doc/cd-hit-otu-miseq-Figure-1.png000066400000000000000000003513071312257207200205570ustar00rootroot00000000000000PNG  IHDR?A iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o pHYsgR@IDATx|eBMBbٱ]wz* * R =D$@$@͛;0bkqڹ*p z;lvWZcc_WΫ~8~y-i͐ -9א{      B5iFl I~b_<ΘyuCO~X8, gϒp,KslcHHH @jtsHHHm(6rҲh;9o ?|=\m#ĕq9|̈́r:|Z# ?c ިWaa'     h9 1Uls~i9LIHHHZ5]% 4oHHHHHHHHHHH(W `uHHHHHHH" 2bugHHHHHHZL̷6͛%   п֧= 4W)ub +6?6&    肦KmĚ ,޲7gK$@-2Z9_       %@q~w          fHz3 @H; @$ͷ` NIHHAP\oHHh_5HexMwM[ߎ|Nv+\z8.|ң8~A!+WYbhIHH P\3  EgL7l*d1 @}E`-/ 5P8A|n#?S zas/1ld̈́p&|&Yb=>D$@$@$@$@$@$Ђz\kAsTI0 5*3 @s!7e-I2?΃HHjM !;       fGyf73NHH:nHHHHHHHHHHZ-Zs$@$@$@$@$@$@$(]\Y:{IHH" P\$s  DLliR @ gͦ @ 8 g @2Pg1 H\o& Cڴs$@Ab 5=cpI$@DD;`VO[  h(7K TBJ H:IuOHvHDKHHH PlHAkHHHHHHH #ғ@$@$@Hz2^D$@$@$@$@$@$@Af   H>ד"  #]B\= @g7$@$t LN @h~V԰r4  h:t-% >h28d" "p:Ϛ5% F" nk9, @#(&vh&haYӧO3$hA`r 3J$@$@"@jbe      hR"fI @ P\46!      &N@CM~_=DhTOu!mz$@$@$mB 4i3 ~hMzbK̑]VydS R|X4Ҭ `[}- )܂ZckZGY^Nlb4ͺX!u@`"Fm|1fG;""2BIHH%ޒ6J$|* UWK%:ݘꆀ0t^H&bMSNݚf5 @$i [lurpy<%  Az̜$ $ K:gx>c\c}R#4Y#ƣi2 cj#P&'!հ!qOq =$dlI'خ@FbDc4pelB pmaÜ/hj0Nzaz"r;z0L$@$@M`Wt0sS4^5 @ $@q^tNHH@?b*{w=E%6)[!ypȺ B_&Zu}A6\EĔQ;1اc>2HnUwm'V#WF4=APpT8P!ݔq3F ص wKθߣV8,1KIHwl).rp<8!/r7WhD$@$@ͅWsA$B9 ^VUi-.K$"ՍchpvXhK x}}ds! W~ga1- 䏲쿧 #fN0WD^G};:BJ}s4]3\Qꋀ~~5>դb{ [?l`s<3xL$@$@-C͛%  .m"ζ)El'\}e~Ex[Xr|ESЇ ɄhRBº76 SWud/o 8g`}^#8ij5%l. azl>T-osO\謹 H]ya9{'டT7|bJofSXW:L$@$@-~a2 4ciaDWDu;wQBYY,j#!#bu,1.cuqXS\'݊rSv@}1P_n}&/X|V&>>/brl##;0F;'6 tEu\ aC@(߿Mɮ28i:g *m:pP ;B?O¡}b\TR4@ؖlܐ5C/H?c4m:K֩G }oTs{ge+|y !²9rEІ|p7E&WT}i02.Puo8%kzƲߗA׸;:=}n?";֮)_Ѱ [ۈq>˕C  h(I $-?al+ia--?b0`H@)V[IO[u:(|@muO;bnbG8hsZ5%9b{ÃZQ};mu_(;ls:GN)X@X#54${w R6)q7 ;l/ѓ}06ftFPv !Oz*_6n=r"O]P#G ɗiAd)ɿPoN%!-wT7K\uZlxZӸEtIʮH& V i5 -4v4F$@$P9aiPN zG.hZ8psۀLxכp+k &<ux! X%].ry~k~V<s=ަd†'Gh} 6(xŻ=ܟ@)Q͉`uxvwȻ\EJxuj8mCer3,\ ?4*/A'8k#n8^^4|M`!xW^gS :$nOqXs$h^+1UJ갈HHZ Gp.'J$@$@$Pc*J9_=Ur..f0ot!@º6UWN~kvhC+kOf*u]-aRb ^~\NF|Mx;IֵhĠWvh!oqބz%kmۆ+YOdZZZnD'a>ⴟ[%*BcUω\S/SҎX i& CaGeXOHHH¡p$@$h*uh480 TFce~*Xo⥯AP\8v ;)jT~x5XHcS9BSy|ZaX6ZO' ʽupk1J n~!a`pXfI†,"`Cnqr^Ƅ ?XvtvKZ0~`1,x&+'_1v 74\G(@$Є]]8#< 9tIrv5eP6394ᴯ.?' hl}rIEubc"          (Wa]Eb           MZ -M,$@$@$@$@$@$@$@$@$@$@$@Um $@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@MLtL&h 4S έOkk %NT-rnT `D7YN ͚%    ZHuu tHra{ ! o,Sg͗,&wn g֨{]_/b׷ĩs$@$@$@$@$P4㶭:H n311 TPXo++'GqVUXJ"]l\|_ׄې $ B$@$@$ m$=eGqC@Qwrn/3%}hCfHذGkdž9T$(6>L^+Ɂ1X#ߨ.׍? ZPo̺9m.y]9%9*3;sXھ]nn=//uk{# h&BTmI3fͩ@8aaN6Z=9@r0fK_#b]!v.tȜ˗ 9O ]\>Ƹhw49RFO Q #> }<Ẅk\ `[>v C} B_W $^E b.2V'G܊Q9?nblFraj(6i\KjH_sﳿཽv{!b J WÆ;j?ܽH}u$G\6*ko|za"B@ônӛW5ɜ8Ed#9E:do4^Ew0YowLA^ H'ceW*Ye$´#Fwah~WPбedp*?̇wS c6.d>wuO0Ac|[:nFlX=h r;Ƿ;U1HnG}T1'C6fŽC]Tf4 qc䂨B2b}׶τJuOmώsq[Sϼm6a,%|"i`zS̫98"l/z^Sma=|/Sg/4UO \)uEq1 ĒP_ɗL?V'fF["Ӊ?&AHHM`>:kG&ߨ98 T_M&aY |,BKDoV~ja]>CޓشE%vHi^B؞ZRӉF>Vu? ] DKdzD'VXyeʎE3X9(m~WVI(r?q{^N[(Jbi-p=.&2:)dla3m O"˜ z 1cf96]ݾn&--^dO֘Q2w/&Vd-['p Ja=d. @]EOHHHe0*bqdʇkOK ˅{%^aR*MDf/{C} }YD q`/K 6<?D{s\KXWK=Y_] 湝ol;mT&u[4qoz+o*Jom}RJ˷L6֣-]Mz] @z Czk(#ZRjپZA`,PDM6zekoC+S1 !B?wr! ַ4i5C03w &Hv*{ ,K&“L>A< %e5ɷb_b7WsLv:C`? ˃VM٢?D'\u4jZNwEI} _ |Яpq"zbQ? Q(;#F[(Ӆ`5mLO}= ;`6CO$χGyUpCa? yr;Zn2L۴[[C'|WC罟'~۷"þVXl3gyц'":yJ$@-> /0F@$pnSk³*Ǩa"H  '۸"}^ `=@pUل7w9s!nBNO6!1}9l85(܇w`fYi z>ߡ>_h|u UE 5ՆV_?]Uqm 6A 8+on03s>p¿Ify6@E\½SW熈glG> i6[8ոo6( 2hXa*hKiQʀV-mu5s~"GiWT^G_e7 /"3gV^VYRZ _2՟'R;1eSrO#3L_e 3^Y:V/,KbMy%ؿ;"cL]t/ixROE^T4>.)Z1ǩqDw7c'ØTZVvfr=O3Rkt^N9l[.>j:ތشuZ7œro9:ER.Y_8ћ.UhZK0A rcZ;9!M$@$xZ|9]   cMC@6ڷ 1-|Ԙº(&I&Dtwa_+K==c Za,BBVA[ jS-:˰SX3CJ _bEa`b6AosOk 1#9+\i{ma]%kx;鍏8t 럃Y1um37 3\Q# ƝFZD~xԇ ?+L$@F^oON[7AzʶE#gAXπ!譀 D^X)=hSS=g XSS71)M: O;=nyCp~ f#`[֢Tpv]w[7~λc w0u/4ǽVœ:ǍV֟fJMoJ=z ~`ӿ |c7~&7} :ހg0I_do[Xu5{c8|P5)]}{3릔3"˾5;s͒Eɒh  f >f7m(ՕyD$@͟9C  *qJhGUΏﶮz?A9ٺ1 ;<r@ka=ޮb,yŭTjnB xh4d @v^BߦYÍg3G\V;V=ɶ?Χ;۱q0\:P2<^xb^3*C4y=U 8  'OFLM62 k1jH9}iܣj:1<4 쑭OmX2ft28Y7VZf1}jdU㐎7\4K۝>' @wHH@,$3Lh  ˾^Xȩ(;?<7‹8:9-7+CcZ Z?Xc5 EBG8C(_ *83 wP^z`O5 6<EtV.|+WذQ6LE>ؐwXx[z.Ah ~#MqU&X^S 2mA*⯹J\ (h7E^ozcs%]}c,#\[Tun&] L+- F,7Bmr;نi7X+2Va^K6s"+|^`Vע~(|6=NqHO|h3Gxp֜a̛DħcAYZj8XxÍ`cKRq|/s{Aeգ1N@/~A˼W-mEƜGqyXf' ώ;dٺ(nd3iN=rnTG: “ k.[7Di'si]72$ܐRc,2ȫOYiE }B./sϡ]nny7]q3}{MzjeK;h}O4|^3m>HH%Hm IHŷ]44D J#?Be*kR*Ga eD<#;+/A`?~A?a➫GYR.bշWy6eOZsO_aٰ6@J0i\SE?wFlpEh|ƍbW;]|5Ѥ!ZB߈X!B_9aas)!n #C<*{z@{LbPuQg<* &CgMxtv@o(.Z2Vr%<yt1R͎@ޣo^ߌYssVbdPXw7Hiͻ_c??sPY-'7 j]o0&}?<]JbY٥WZيmuteuam'=fVK-|7.YvP13sHk op,Pqu޿>#8`0k:e)>z0LC:gO3sdy ' Hzs Ԓ@[=uzV. yso{so=nV ߪ҉U 7$bH^d@X;~@7>}n|X8'XTTY~8]z^'qI4|=b뽀GVzJU/찮m'$@$ P\o#     ]~7]A+TEX(O-iuU33Vأ~/ڕYšiNa:@nn6Z*EsULy\^53+vu?n1eo]׋CRd$@$Д P\{6yaN־Art{NF'04oWxA2[gG#:Ϫ6KNL]8Sfq]Cc ? 5uzޯ`lu+mqꙢR^Qnf6W[c:7x΀=gXp9'O{=wjW*D2ۿyk^lf 4u jP{/zT?Ƽ2R~ѡ~`$@$@$@$@$D`ʏ&v{|n܀{Y7e1}vRy bגVYӎFX>$_avx,ƪVezg7ԃ<b hƌ_d=XĴWWMƥbo~i|.1?)/zY?(/][34?2u)80G$%sJ?(C,j5LֈKM De#u|qQ1 ˪jg8{,RJeg<.7Wl$ǙIH "0\{ڎԀ_= &$@$@$@$@$$NF\]TCq=;z{o{<89qāa{="[:OG |͇'kœkh/cTأҺ%ZkAJEݧg< ,wV^#Ӣs##kli}qd!mº%*ky]~="XLχ0D[gv^^d^}P8ڷm)BXηtnWZu?_3e`D$@M=כU$@$@$@$@$@$P+179/5*5Rek |uA75*`3v;mMkgǻhEEejrlŀz\ ?=4!ą~_ؐe)bzfAQɶ{ ʗ'&vڍs D2DJtYo"|Y(i {έ\\_~^Y?fɢ<0tYpk؉7+`3jgXwE?"N.ز=}yv>Ey;@IDAT.opd]b" Fz\1wq"Ϛ.WV=7G8*!g^Ce,]!r`VԐ{&3.zBJ}Y7~;C>6D[VK8zvn N~ZJ<^8/}5Xy{dc :zW+#e"oƶe#IHd.Ur:YrJfۓ~.;o?si[7 .==ɖGyǶd{x/X5Oʽg?pḡsE<6tfB^bVR!F6Z\닟 {5޻ ;,GKV ru|K~oEoxwFtgJkj W9 V5@莿"U/T3mC^5TR+ru K%(Oht93I;M_ٮ/KQO׻kd71Sd/VBBfCt mRj9|[11Dl;"%EW#Tv^2 qUYZL_.tK(sEֽ c'%mI[PQ=^"So"[kנZ{ )h}o& gf6mԴ c5GtS h1(K]w({j%kX{XxRp@3?ȭ/hyQ*BՒ$@$@1 >?OCr ȕ9Yy#w<l ckWȯ]p$aC_=_"2KMVlȪq d$Fl? 6\Y-K~$͇ s _F#B/hj0Nzaz"r;z)P#hlN Ĺٝȱ ̨]f}$2S'eαX:EUm!]+'KFZ?u郞hɪg2cr@s3j}P8ڗN,-FvYd=|G$@Fz^#*wjV~Ώmh&] 7VC V=ߺcg||7SV} #v::G+_-\]|8:Mפ^/.aºk?yȁwWy3Ѧ\ϢܾR~_C=R{">FYɗs`ÿ\n૾qMvmy߁azpup]C,p t,o`@cCm膮|sוcrSWYtKp=r$h40PY^֢aǸK ho&U>"/wqr ¦V䏓m>D6CI9X7e?auȿ .o‹x뢄T~ܤܬdva}O0/xƪVQNSQO=G`B}+s,K+wnM#uUk @#5>xS]=L$@$@$P׫Cuey52%Vit2Ւ__YꐑYYqBeC?mo٭?ݝ,? Y,j#"`BJ妼 #q 6gi0x X|2D1MH<u_ N??x.2t v`|Un>_<\fraQ oi c!k[eC^s!kR ` u'a[mQi +#ⵆrig1PÐvuaknJXU`(;>hqDvzjszS}hX6ֹDku>Y6hC>q9CFDv}ݔC O^a5o +V|aJu8FڽJo&'P 4kד=#M+X"{q.'+;hn I,Փ*=q{xS.5_tI7~Iw]hRױ@(l {BfC>zwPɎf#g#sHӸ܅A7RT4.<cM o:ɀgzwuBgrm=<aK 0)sM,ɀ|Au*]6tEm, LZɀx$uZBlZ6j g/uՆ.#?LAx&†B}wfCX6 r4n46 EF}zNS8a[k )ǜn!8\fR n MlUÕR7}b :6u 'է^qӆ!)% 3G!    C LQ1;Bŝ\ ן lG")YY&n$ &~Q&vEAo:CTpxotUˉ!Yl)?y^\oG$}ڠ f:ت@ ,c-P/T.2oOU;GZm4Nj?9kM}Z7cf @s&`/=Ƚ~zqkdnL'jF́vؚaȏXs0F{W_+P9g]\ 1%<92uNŶ*V- 턛C8B.EЗB);*a^"@(Ph )m[+'J_k.ǵx5Xy#Zjq9Cº.XH 7^*ay,p6!}1q^La=؀$@$@$@$@$@$4P\OԹ]iNrx>ۧes-{'壅2Hju_-\򱘖o֙,١sHc٠±YHʆ QQNFF{ӶMqܙH iC3GB!\}GK*4A\4\6}s16,4ZYR/r!wj*$;@\y900ch1ȅR#;R +-v;u<b3rrb5K ջNNQ^YRzë\p ?aW1Їz0bN­M5{XsĪ . /Vڞ K@e"    mfrǍ]{./7~|Yƾr1^6nۨ9XO6s Ÿۼ_gˤ h/}{M$ 8vyQo/7{-/<#vMӔɳwIҩmg׹XHNv,pX` c},@5!n+!$H/}  +EBx{E}"w'ԛ>T_ئȱ†4Ţ@7$} 1GDzO|b`1V/DyA\Hs."Z`y~!l êPI> ePkWjףW깯 a7eowW-W=q,l;ʓ]@P_&2Kko^*/^P{!v'guL{wx;-.!^ ]S{h338G%: +[XpSSi]ٔ7}6@G^ʵ?jh$!/D璃HM,GZSF?,qkN\Č7nZ.%hP-X= $%>$e`䣑s䈝Dc5K 9r1.wMkEA|\Q}F{yAa};?!Q']wpyɥ^-{ײ〾[Z:ݝnY5?x  ZPA&q5i۾nmDN;gh;w=w%r\v:$@$@$@$@$@$U9Tݴ4akVa˄}zo[iL{[jIo+};%Ҭ^<}rvߟrYbFHKIYf`FtҜ  u܇'?hCWvoѭ!K=+.|O;AzGɢ6ٕ=2{F69 TJzxX ,'[Ѓ2󭹯KXTӑ;#h, uE4w8L2[gJR,:Z(]xٷnZygRh˞ty 2s%=xsk۪{rƭ s8}        ^svl[,ޝ$o{]ܰRŵ,Ce;6I=<<4HHHHHHHH P\OC&P+HUj۵ד0Qz_%y$K)pE`tB{@;Y$7ȶ8& )@,yaåzXHH%`t\SҥgvxZ!p􃼱PLI-='?YTdhVu h/rmr/ݰ= XK ErMRd'W eŜFʒ @<x' hIasD Q1+ʬG5 ]6lR;|_׎[ '3 /.q!y"0wyJ鱄HHD(U@$@$@$?1k&IO'Qj]dS5ѫK!m`@=5Id-{6 &S-ʆqr o ֈ`7uς $7 egɗL:#Ө<  h %\eΑHHT(eL w}Ȝ˗w/ڽ >9Uh{E'H)wx)]u#ep26܅c:u ׸e66ᇄ(@[  5 WQBK2?>V0~Z  gE !sý%ZwȞRwz T$ɤZlmƖmTl7a{g{ӽDp;^˕w%F/-& h&i`b PA_":m˫dk,[Dzd.a$˪Ism㹠i@؀d"%WpE3͗ːp  "r&I{ gE1>o"͗^o*'Bfiʃ< xڔqu&Y.M8*6:>ε>{C9ʓUh޵6]- !w'&>AVo<ӺAwN:D ɉDgnzڮ%/cҚٴH#P?#Z -==$C !?_+2eʟ[2@7A;Zi^Wt|˻ӊe)hM*DO蹗rе:u}%K#/}O\~(Xρm\:@Pΐ }fD:o\/̈́o|y ?"sU8v8bnD[!Kr2n<>gezx *:^04[hۆE2Hn?{l!/HÆi[f(?ULJcSΐ%;[߄~u 7Æ;c7F`yrqswnUvA'҆a.?X'*l}Q`1c=T}|׶O}-xW ںH"{@2>RuuD[3|% ~f5C50H@Ub fXCo}U.| Kqѿ/rw3^&+~NrL;wFtr~+^&g{>+>Нto{]贠Oȹ]rxzIl!M#H:ȴ*Q#/@dtSv^~= aInAA6! i5~I= VrN oC&i'b }>Rx?Ɲ↬D$mq2|sI{(G?yB\&kYEvJ"zYpR.ZbQxkXg)#7 ƾbVͽwqRNcbI_~}˿||Ԇ(.΅^bIuzL(@> `}."ߞ!WUv9Mqўv=Ie?ϩr?ʣoK_+dv_oovr>˺[*Γi?;:ku|lDuG#.erX#H6_[]T%!"D#g?<`BryR$?=pv3Y$Ų4\G Gq B_a#X>yۘrq4!'kJ/!:= 4}=G6# A`scj}t xI;ɐ<:gp:^DPXE+fqic/B8|c6%]s T;סm\8L7iOz,B[ E0=z?; !- ,psz,@"!3=V#VWCׂ upB.5L'Aз${l"E@PfC/Z. o>\gݷG?oİ!c6nbhLW[޻M>7ss|vmVy2f3 |7BΕ[g w^乹C;>Kߺt2nIz6 B$_#]3 T*YC ]*r<4K(δ#/j&T =۞ǎY\e BW'^/g*6 Ua(ot96(YWj] .5PG`_M>b~QT]1!m:[7۴D^*ȋA?> rAiMWº *e /x vetC5 ǸsR;"?mJ\S'r*d{́*_9>> ׯƬ.<Ws#ˑd'^Uq4GȆHCo=FCoeVCն@p]Gxt"9o m1u5Y|xwVC.L.Խ \p@2Ľ2Cs{fyk9 c%+ #4<_v@ /]%rp< Ux q4р܋9&P%peDb4pZ_pUV-໿E ˌw%@ 뺡i!f@,z\+a'p'y+y(*t,4 ݠ;@n ;"wt!B%-2*@!&-h>39WN,uDs&bW68!1.Qn;f]iǨ.ctXg%(CTl{G,pYj_zƪnpXhpO-_( 7n.-iQUS%x8?ʊ巅3MݚkkZ-o[ъELrvEq :x&ַapY~3͹9m&μO(+WΛ&m,vq+WM4C?;oo!Qp~s7Ԉ"(G6] I1 m-_>*ň^]w!|L:pw-QM*WW_05fmўnKB%i?ū}@]~3^ nwj e@3,׬E||ICoM؜#|h_bʥ9$Pχ"tqpp&] bŀ QB'h, r]zۈ"(%[Чz}Asߊk^! ӤIdKz :98`;h/ЍP`8JknCd("֤eɪZ);rͬR:wz;\Ю|-[Ï{u!˹錿K]|_+g|z? 7P^9|#eÄVBq㒆}[rS߰YkeiN ڭ|}m҄O|P)VʁtHX$'\2RA1 ʕ$ѡ"K(3|`|bE^b}26K;"ʗ{l/K:ms ä6x!bE_{ĵK^bg%Qm 0V͡w(#'M 5xe-ѣX8匓SXˆ{&ϙDENVx{M/>g/?.v3쎢+@sBTB cYGczg-|b[iac^,z'GABoCC$EBCE@:M\n#]NȔߙ[| nȧ3>u۬/li}RO5]Iå.'JF9KN ,+?!>r,\4Ut fXOz>rqZ /:lF[鸖~ H}7gE,e} SLeBARU]%)K91Q3dc!_{0W[[GM&?a6SsT@Aĵ-##hz%^as cAkbWWm9$35d>E3( }%ƭ*}>BcA6*op=ɚug 9lpa Kn1pE{ C0$j?V"OBFh?4w8YU/A?7_ xG@ sxI\^ 9 E7H"Dz iIj,p C(@DuvmAY)]('y$NkTK0 Vf>b| z2j(IwQPz)(@?^Y>ns=v\?Mv28H>=g}K'oѯW'>Q٬l'$KFگ^PXB>q.**2n]w##l]j>|s\;;NO+<$-OXu״AErw2iݵuKc!yAW..$fĭ.݅Λpn:inV{ek&e.'_Pnix;.Yk$8sr-6};^BECn:l?p E@E`, @@r)Uovq?[x,SP[_gp9~ʫKdPH:<B$uzR x[msY‡\m[X\tB"lF`cPfl^7Y?zJaӞЊ~_i.dle"|K[,exhNP(|ӍT(zXIŨIO*VIǪ" (d'N BZ\W (@3A:4'o_KcbsQS{ z oyQp[w5ktoڷ/X1>7 \׎m׿9 w>Rɼcvݷِ2:\Q𗉾u\jީk+8q773:\D}9&\giA~8#Ff--h::pG L~^0E@PE@PE WpCr,4ntհ'gЬ;$QNzKPm|{>wAeH@J"{(/H("ycÛr1fs/ _QH.?tкA?yqь3X=YfSoاI{݆o-/^qZzfOWe"܈[?}L˓^K~3N;ȡ7Lg}`=nfipWpmu|oÎQ.:ܽi\PE@PE@P<@ &،##%\,p>lS4-i:Д&£g9sZ }2%"dԁ]p/z[y.=~=/g~&O|癶JTH"T׳ ?%zG>,[\vȏ-7p4\XVI&ac~=LfLź[ c6[sl5|[hD-).}-uWxRsK㊀"("("4"dpvS޺AVTw Z_뮅q0gU䰸i)4-&6c״"("("(y@@0h8%0aF`3 Z-Pl/M[$inՒhg9_? $Cs_"KEP zI[y6lߺ̔D9Ö-͆c ߹ɴ{-S i]ﵰ Rk;&8kX#mX۴&)j*dzuE@PE@P)հ`{aE ,X,6%{UGe]l#n1hb@a$i(ul-gTۿ_[0Ѱс žM-Ǹq_dKz3M݆d O%}}5 hO(]ʰ %v,7W+"PO\Oe[iӊj$nhܽoy{<Փײ2d:&%Erˊ&_ q/W:!9d;^gꖵZjd;\c 7Z{2{~ua~!I_?̣ZRZ}>gBpP[0Œ(" \O7 ~1SPd&Q;}[7//MzNڧ_l4-ed5dZgzm2{o-ǎnVe9RS 3, ]6:]dls)"("("SY?,ɸXE7"*q+$֙MBK~[עἓv盖+]6] d䡳Jh߿˿;6397Tw9a|6c/H:;O|eB?;O?_Fcj;_w FV,ߨ%חZ*~bm70]eU [܆?:mlH(nNR<ֽ4Afu`KeTs=t="p)!{}Iu'Hg!.E=vMoMƟnT,^YXqb\>Bi7zԶA("Po\+д^?S&JZɊ+ds_uvS~HnnQ=~rH%+~"߸(ydMvƣkMPie9qԎF/7L@,C.~ ;@IDATpcUy2 CsK_)kX3ݿHƱņZ#^&=wY<{ϑr Y'ɯ fk{͕ƞy|+kf1'Sj굡O6c г@\y}HڷŠMu4(@R=:k7l9{HpO|E+BRݪM3[ w=_D(vd(">JׁY[ VQE ;#{d2Nr6kgzuƒm5XbD9]P, ƿ\?Z= lk#(@Pr=zt;B޻K?|dyroM;H}//t%uSwn}F>"t 9wI{D\UPeW  ҃P]>P: s*#dۢ* RïR~E%܍YAU⺐ˍJ1pm|&kG\!)H0d@h?PCڝbJE@ )r=/I(@Ͼo HOjFxZK1 !+a]+o..3NhOYxtLN,9@Z1EKfPj^|>f3`/)dU·kKCEv|Y [(U aVlAT: `G`0"~l6y@AnEHO5/<);K1t {= wQ_]#/MʥƬhKE@P|M }HSi.{;I+TE }IgR;RRB`ϻgzJ`i%E@p(GА/FA`s 9ZK,7Hv7i7*7X<͑PW8Hh m  TھF^B8>٤ݼK0;io6X=-Wu'Ys,p^pXNh^yiA9F|.b7s5Fa1d?8_s8L? ĒoMͻslyWs. q0 3= uqX` + ;b%;G\E%i~k};XXJ*3.\ VW6ȼ/Yb"T^}`'>$ B2%BPn@$V%0Ƌt%S "66=z]hU+`MGC5Své%PGK&rP= ~hRܜtʃI)NYI_Do0DS0k%_g0xl{9{u8W?y~)odr|fңelZ9ln|r` ^rBk Gw-*mn7EC2w<GO֚WWdqs"9xZG9l$?8%9V>a\eNq}ۚ +ʷ;CV8z89܈c2\݁[`5X@};3*+yq }7u; C+h/0s9\ X&mAA4bIχn*8lHkplz_ -CO}X¯\:z깋!# KcHtO]F/[Tdp׺i!ծf@,nW 镸fbv&tp}/RJ!@Jru C|(77=j-] d("*JSJ9Ur=ϊ">Cfe XyCM[H%w+eƥHTSujCī#!7b)G>2" al܋@45Jj{AX{eP1GЇ0tapcD\ G./ZfP=[9x'aM]dDiMjW2=}Ea(΁ 9<({#9Gp.^ FZ/B|] *۞k8nَ<跣sy..(ZtChŭw]:+6Cfz²m!%'Y$)WNboWd'%ٞbʉ{"Qs([u?z[u+ Ɉu63VLhI]8%=cqڼWRbc9D?hwJBbT9Go("Ъi88'S"uq[J :!tnwF®PnnG7#[`7qn $!\ȱʴ{s6WQ!7?jްz -Mx]aȽvYKP@|v_$ V^e앉WuK\m _-:[/Ni#`}^dܩ*?W5a^]xkYj+@(3֏-2+aU"w,pml A?VucÌm@s(5H# ⍄bZ{qRb Ypෞ<&r d; s0's 9Mi\{w:z@ 1 W<%IH (a30b؀7j0?A@T>Yu8~q0Z.rX> |#s%$Q*"ԍuc5Mq)Ϊ2-iiltǶaY߶a}vġ>dv.C&P"(@a"hCS{4A۱m8 yĒmIqWr!@B%yCO+Ո2l IN**[_vr^TZ[0k"Ew$Ի@@WA&zr؃TEL^ZiI4/\o^[VPE@PE@>| c~8\T㍹ w":- |MZ\gP99:r]u(!E@PE@PE@PE@P2I"9 {W72?30 4wƼFb˹J#`-8_f3Brc4>TEEP % D4E@PE@PE@PA IXaǖ2]S6ZJm;CM7VI}d6G6lhڃ"4\o6ZTPE@PE@PE@2kJZu"XWq-B=$ҭZ/ :1/?yZu@ 7?NW|+wΟs3Q@Wq6m("("("1$w+BςuCB^EP:(F*[ [/GC0@sF`+"("(YB)d/"fiVHk :i;O547 ErXUEPE@PE@PE@P `\ z= oV I6Wj@oB,N0^r]i"ԅ@^uMVE@hͰNfqz@G!›θ !1 bMim̼ ߔJEP"GK[8JJ6tLcèg ņtC%-*@(2TZQP 0R3WsQShշ-"P7U *m\wEQҌ)"`(},ֹr kp΅^WOMiXXuU!/z[=EPrѠׁE@A`5,dXFB>OhthG>=:9E !$mJ᝼92oN9M\Sx,E8Ɩ*h t51a EZ&<[ *O'ZiY&| E@%H+("(AcgCeld6yl+R9^+doD|;:b]Vj[Iige; _1e2Z6 [٭e|zP͆alyR_x" s  <4s ǟ֡9NWCv G< V[7J SR# b5r,pm^+*@c ]11eC&Ƨ'q 2wwuNS] kBUi_Wik癫~E/?fP&@Q9=E@PE@_n@$B r5[4 9n7uk8o?AސR@Wa<{P:CwG|˯c]RkA ipPR{n9. ,jǝÖ)3S6<1)ܫq"[ " yJ}<{|p {YJ"PuBô$*@SFX*Nș{TuhR_BڱD b G8!%f">@8$_#!oKz!"P@H,"1r=nr39i!GFC ն@p@:2'Fe؊7~wTK"#gyʣr uJhR$͒BԿPw!{9\{DuKK$V.\ۯu]\DKŁ~V.:sspnQ.6Vy8\ DR)'$?K1nXx>6q@~!5=~.}qohC&FߎX˄2ѕ$D ~N$b'|RJFJ|.CW^s1ɨ{ ^Ƈ%De<}_֢=`?gCzC_ILjhK(W!l ]*tete[>sQK =$ǞrAr(﫸@ b xd("@4_9"(74CcR,">[Q,+Rq"-l˱WTX޻T8LuρC͍doÓ[GļZp< \F*07ZEZVCO0qE/; BihO68p z]L@B`dWy=TP?g`5i?pڣۼE8l\&kY.ڀqd\O{pmw!Z7 ;M n݂6O\FF}UB?:E Gy85"("AJgX X<}+Ce I^jQ+^hk uZ[b}1a(p̡o8I~b].0QzN_ƌ]nZZ#/K/ģYtu151>9L{!EF{Z?6g1@7:^.EK+"PbGd,I"FR{!#ĺ#H9z(CJU0砖X?q |B`P)G9B(~PPEi"@Rerh^DZyǷ6θBZG4CPE@ \SQ0~:/76Dؾ/׀`lP#,׽su@ \Fgi|xJkkAFd<ǎO*.曮ăyO<> q$Wכ&]nmYWz9 #0uפ ; b~Qєh!>ׯ-A􆡼 s`尒XEEؠC4\]ANDl[>ە VF&AJ`Q^2Rn6ρ{R9!]¸ &WHZ:#G]7uY>zs7 Y z)KzzHCo=FCoeVCն@Z瓥z]Km*T,fᾮ~< E-[|A5>#ܬ]!pUGށh_JA%7C(@s@U_P]wrM׮I8x [7J7:" Prd=DE@( \/ A:1XtרHkfZ5FDL&C%YLX@?j a`Ρ)s)U0Ssqm,yrkԹK2X%a D%9V͍#_5t>\xz#8pErp[RE !2\hq(9.`)؄.ڕH[ ,'x\Pq] ZGK/LSA@ઽ*@#kOX<,_4#PrE {a=+"(M ~ @[R\仸bkbosL[4)n%T: tBKN#O(a#3i$B¤: Q8j(b`+!ġP{$)ڥ RĪD^:EWCŤKZ)u%'%ࢎ"(F)z?ڟ"(MnrTHP 2. \+т>|D`^ T?%d~]L;xfʷwWqueTXn9IT>73mA> vB_1OMr~ ~B=.[Jӓ: }!ڳR$b~# /$RPu9, sԤ$}мm B._I9/Գ~SGk5ˤ_;E@Oq  @/Сޤffr_h+(7?ʷutWG# W[L\EPr\TE@PE@ $c{Hm^/TI%QǕKPHxf`H2IIW*!jK_ms[2 nXVhjqz,t,f|_Rj { l(o?b\ZYBO;v%g{dU,[޺pڝ"4KrHvw8wgCo2<6VriO=E Pr=NNFPE@PE@PE@(`u{ Os2>Lܑ[>{t@#;53TE@PE@PE@P@`8x b[M'1[ƀ܈7%PX'Aݫ("(I)E@PE@PE@P@@!z7|nG,sbI@iTcb'R%16Sv<:& = Z?ޫ@WCW kAϦkθu$6K7c *"4Qg("("(@^ PDϋ$ܻ-mAK_p;8Ãs cO#zcna!-S!na6VE@PE@PE@Pz!HWGl ӱ4Y]l%։GDy᦭E@P0rt"("("4GF  89 JϤ8"\1ԬSҺ,lw tLv՗k^wZ ɤZׯۧ2xEhW l<:1?E@P0ڄO"("("("Sn5|$wTX+g.Cf#/UkТƄ-CmQP&ΈGhBz:z("("("(@!/l=*rdAmq8 2N~\PW-WE@hj(Ψ"6ca2GnA+7aדM )CcNׯ6cVl"oz9-TqF|WO5L<`hTPE Pc9"4eП u`MDGV|TkC\G3@-| _LF^J VT:wR=s Fj 74UQE@P"zBh@PF@^]!t6M~/gS7-:"9ݨ4e -]k_"(M%כ9#RE@P ɵ2җx?8gZ]/b`|'۲:\kOxa90ۖ+mrY*APт mCx4/9 N{hJk.@Qd&WZs&1)8E@P捀j姂L1PUE@P(-PE@P"P!gHJd>*S4i/먻?ANM 2ԭ a$ĺ;-#e7J^X}&2色І hl@q 7O_ g\ /cK%6}&/ l*MrGd@KP@4<~1 Yjm z5fD>ц7쿣Mͻ 7Xi/~pv<юA?NuJ,Kji/ʃFf:],;My@^AggXO9o+a͂&n}݇AM 2շ=-'c)>PT,`N$0&ӑ_J <,=_͹ޡɂ6(\ُHV9e3~Jپ=- ,śtPI"("w? 1ǣqU@.N  Cgq#QMlyEuo)"663z]hU+`Mz܃fT %׫i#bo=ʖn,=\ ~P;{҉5>zMtwŷ(SnaPzVQ ϗ%qO앸5|݅ C+X 8LFaF*:,im C f<Zx\aPJ`|8][ф#Uo1$A}~ӯ2к:}<>]xwO0qgdg.(7ߺ|Ωy!И$0,&*4HV }qmD_G.ǒlׯ_On51-y:侨^rPZo@n8˟hb8|P5>% IF>99|D|;#:E@h(޼=I8iEP溛o4mm"]s`Rf\%W%^#aG>2|A7f-L^y(\ {AX{CV9<>. Ww0@J[p"#O g}qu(v\'a% .ZkŘO>-WF-V9Y"Ǽ7ҝCy?pon|\U"? :XV Ng;ѯܧU<E74#)%srz Ayw~ff%>ӫ&m1hNY1$)r_T2֭nԔ- cgEnЭAN3Z |pQ L@ׂ~Lobb;~Or t (<)q93߳LE;t'4( ARGPgsLNī("("P7$oy+ _+zmи.#GS& Yk0n]w@(ODb7:TgՂ9xE2zy  ⁋${0PnV%ٞc#gK{z3 !ڙ.$"Y>xġXznz[ݏXg{wBs8Yh \HDN)pV8#жGnXwNg]l${q xzuls.7E /zi\PEY";q1FܙڐU@Ӹ.j IZׯ''I,4$qTD0u X -_d*IoMEH%I@G@!K(2{ ="~)]3шnɳQl@x)ғ&=#pH(nmg3B!9n:g.F%Dx_(WP~f@)짜0 Ν۠=ȻJorN^A@(!t_h֥$#"(#@MF"#ך@ɛx){q wlxcEBy0ۻL<ٿ!p+t V4΅ɚķ:~!|1mf<= RGⷱb ]܌Wl~̡n]Q]BM`ݍG9Z8 sx+bSSWKa_hNFg0b)D7ntW30,AВpE;?;?Sm4 t\"jǬdZ, W 蜑v2*/Z{$NCp}6lcE>u]%ٶ:FJbHWC[BoM5cݶ\%,DntC&򊍤>$C)'B N2{A)\l@iCb$w_dVz}gO| CoRACׅXP$PZxy{@~0'<~1guL^$9| PiP~f9X̯GP 'tggPhn'KEPE _ *W*rP(2)Q(Y5*<#+y%njpmD[:A"tSr'nᆓTndHJNUٸ08#@j'V`7Xh6"0&Dl: *11anJmhX6A99:$5)ùqnG*9K2sLc rW}м0Z)#pj|FzN) A`-}L^﹠_{d?0Aկ5 4p aG juMS$yr"@IDAT\iʺC<."8Dj:S$ԉ)4| Y6|q^a'i[ ew%P F `=.z*湤JINGE@PE@PE@PE"Pbz.7*_126a}+SC?LdH%gI^JR6 Y9 Ⲡ>aCs"ΝVATSנ'և<($I3#|m[،zNЦ \"neDlX$_Q tDz6P>E@PE@PE@P@X 6 0tqxuƹ <{B߂DD2/$KyB@[@l'ɨwNr\mo @H("0).GyPMX ,+Sluz[ Z[VLϰ )h9i"("("("() @k|!\f|iأrD('ɚnP[@/N2iZ\.ټv|A31}ޅ :}te %O5=Z#=-Ɋtڟ"("("("47H+8&;/ܔ= KЊT %IQiN%GFRqe8ӕ#= h9 S!ւ=!S3FJBM PkOB*C'![ (L=]e&dgfEPE@PE@PE@PAx\ʵI`Z!_`OC5䏔:%͠l vMzI RMf22Z׳gNE?~H$s'?6 2蚅-I[2̛\ǛHgkhhwz~6Xj~ UT4Ԭу<3E*kӠ<%6VE@PE@PE@P_ d!??(EI&p53 YiD(;PP/n2?Z- ] 17!N!o{:qO&n^'JԒ$ NBih]+=$[S0]8uFh-- M i0'{נC"\dXI&E snqlu&\HPE kDZڱ": @"yFK 2߱6 OW%"4b,/;Q 2cm~p(t\Ä7i ]%J%ЪP!꡸䏐z L?=z" J$(-I:.v 6IP?A݅&7_ c ?W$~ |pr(j_T @z{~P9&<qfM)aХPA O14?zlxyrN^r $ɭgeBw]w /safh9@P~FQތ\ŕ\:"( 0̬q7r:@#OaPGjVT78ލ1.%ri>LEeʍb,7wH&~)hd=q=RaXօqDŠAuCK I򽮐mIϐS[;~:$c +!h/Bb%?@z: xPX)I^N Eݠ{Ay_M4)S@Ņc" :C}3s;C)<$ӝ_h29P Ǻ1*u oʶ$hg(}'& 3$x(?…0y b¡WtZ [ l7eK( ?#B%\csQr=뀊"$A`^ U|D7SQ@lu&D@ ioG?Bq iG%{ NpXlV( [&3_JJlh)/ٸ -ulk0NT}ק-ۤ*ZGg-I)*:zQ(u-$ V>% t$4,>Jr>Bl]PZ D q.,Ӡ|sa6tds12}%AN%mf!Rx,}(:m ]Ja>ύW$8gP^)$Bφ JbjP.@->l\Ra1btE87ˑ,+"(@SAhpcHKwr\HB/)^#(-tAQDIE HJ/BBwHBۛnvnvovn}o>Nyo&mjSEo-iꥳ-7'J+ǐzO8&;V& rM347*񻮷u@08{Yy~ j;qY{'sZ2 %1SP\BD뛾t#f {Aiy$^N7]_y_$/oI+PbR}Hdc<%?$2 J)qMڷdˁE@|oq2}n/3mg7IO44| l" SX4~&pP"gsoL*{_ԝݩ1}R ωL/ _yիoƺ,JM«C pt%/ yh hkG[tQMd |5=-OrzѾkbݯcP-/ꘗh0hz+]֠ 0,i6č*@ zA'Uĕ+U짭L["ƀ1` π뽿 lM<.#;zےm/%;.Nƀt;zH&tHQЋDsIh ㉩񉡷)cNOO%J'3+C1j\ZoVb]\ØagX\XnZN1q=ǚRʻ׺1 {͌a@oe-7a+z09},,u-go$m$K.H 4}Y Y{0z]S] t&i 6!(D U: J3a`)Ge\ ;3czwP~\O? A#VO9nd3͈? =+bEb3!&HzҀ<5 kk5>WvX~~tbx}#m5QYr '0_R^6rvJ4˵b1Ca/_y9.weyx*ގGt_dOñKx~ 5)r raXڈcǗ zl-닁tqvD$g&pm=\ o6_q-/ukJAb~@sxH\ `f O`X$=u~ldSuuޝu` 5p~cjb,6cr"\MFN˲?vr'13zuyv/ %IdެzeW6RgR8Q\)8M#3.rtO"|Ї\LVe˸I<$ù :\Ϻ?saZ @*&00ϼ[+CR?1,ǸzW[\9ikS~^{gg(e‰< Bo݈j_2X(J` rHZv.gE&SU2&w2 +'i:p ܡdsk |Ҷ\ KOu4] M!/53f'9e`.(;)KG{Hg։1` ƀ1` AVIIgCzrg>>cm+vfږYnsneOHċm[ݯCEDԗ+I rO򉄛"'~4H0І?6lO?\'mL˙E󰷛ҟu#]XwOh+11h嶄H͟CZ+)˹oݙ eY5/ѿ]Xϸ NhGmb9j["ǕF /ć@i}cIaR7zp 3cK HT?ق\wQϫ&Oa[֡Z>vگ#GAb tAǃ`Gc ^剚@3p^W</$ `f n . V W[)ˬ_sMXr/]Ӫ5@!xod3" ̩]ۑ[>hݼl7/ystgO 9[}|4?򋸵ً9jzf+\ ǵwxox"Tn5?~K7d|BF4ô6D82ǖ2{3Z@>?7 u`Bt# ^"Nk*3y17q[7{ 9n W2վl{ 6/Sxڋ2L;^cgj}X\4MorOKB>F'arADt>ކ4ha `G]!>6]sxū@N\V_k0c&&t v% +}"tvS D13d@G2{v0 ^K r{sݽ\ִW=mʸ9UNnUbd *qd50,y2(߼*AӦLd|^ 1!~M -a>M= Vrr=`94=Lu#!>peK=&Ru0q:Zƀ1` 41/KPOz"Mf[n`:`'jf =33c0cs$@>:O񴯱gK{՞f9)|NX%_TXW9$gUڧe5u;ZoU40_ VsWCSTXW_lH0$ sºh CqmK82SDL][fTa=W4zcf ƀ1` O!\.$zHX 1Ρ`f w@[c-ƷvI8DKFg1t qT*bnC3{#L-L$DOnFobh3[N%fƪ{7:" Ϸ`ScDez/DcUR F E)mY%W@wU</c2?ݽR(y43"m.Wa=AXvܜk+byf=.~w_ƭ9c0c.6&HHoaDy``8mC v03c0c0c0c0c? xq]b[wykM@"z+h > HO0 z0c0c0c0c0s~%,7ի[An@7{HQmUƆe ƀ1` ƀ1` ƀ1` ƀ1` w.GT͹.]`' 1ZŮ_swf+R`FvVkhb4MXHc0c0c0c0c0 ]¸D-(s h^Ƌq d}㢺׿^ˆ4U/WzF]LiVζƀ1` ƀ1` ƀ1` ƀ1` @`.ay$X kZ/:+| 4hOQJo9 h3q R`>5ZlXrЏ0c0c0c0c0r­xwLBLty#]b&~88Hx^ /', Q87 GG E8ZTenP;MvXƀ1` ƀ1` ƀ1` ƀ1` *^ӧhJv낄w'yK$AItל)[9HBYm3`۪O8:`#c0c0c0c0z/øv J4OD<,0ŒM3 M40Lcia,7xWT"tBy3J!Cqɻ$M,TG8e/ S[ ^@J/4Af@m7*JmnCkF9Kƶ3 fҒ~!M8>i1,h` D_!x?Z.tuڲX *@bDZ :}?D;5 x>%Zs -jܾ$4zpYc֟O˓c/ʩ=8d4_^ t.ڹH,7ZVh5XӤDܺھKX&˧ MMۖXeOP;~T8 iݱeiƀ1` ƀ1` ƀ1` ƀ1` ƀ1- H@8DC@.7 c`% j%ޫ0 , 4]E򏁷H|bqqq*qoͯυƵ!HhAXcMY0c0c0zo95#:2c0ꏁ+z_EX;]B66 \ZH<F!Z%GJ Xf8@mǭ`/׸ծ^iH;?VfXFy7ғQԾ/&2Q"/ILN/r._) W}yN'MGDevpUN"}Ҋmrۏdr$u~LR4aX=̔Xz<:#rkppƀ1` Mo]tպ_r( 3c0v#(ײFufƀ1` ƀ1Б/x+z ⯂csѲ4ՇCUJS×:|[DI}&?m bS~私J; 43a~ <Z@!7#AwL"O!z`]Zi_nkpX :JiznOh?7%5M%bEL<,:yTۀs#ƀ1` \M a$hJ.&VRI+d @b@7fV\7fƀ1` ƀ1Б u¹ H蓳Hxq]3lXf]DJ[!a]HȹP:LK>1%|@~JѢI/C)Y֋ "9{#i%jRJ_h[TmB6#1016e/zDZm`f ƀ1P[ ۱[[[Fc ƀ1` ƀ1` @\X0z%.lp2XTNR }!XGP\PR0GZE FU̷/ux]]02%J/VjR%)TdhPے KRuH.4 ]gzA[4c0c0c0c $3`[@BN Wx\TºTVP/В>XZ,suƖQ/b+݋2./IE &>hYOCgcnXCk)>.eݾFOK l {Z{>m f ƀ1D{[I= |*kn:~lDþՌԯOzҔW+ʸb?fƀ1` ƀ1P? $)O'@2%/čO"q= {\h,t^UEo@ڪ1:9VίØXZ/3⸞`G6(QbMtV}aOK >Gs5~ؠ1` @땺,,k9newWT#} ঁ>Cpaދm= WG@Iqe\@ŏW_ޯ8bW=lڢ1` ƀ1` e 刪o .׃4% ^<ﮀN-.J`I˻/dt_y7%yU; 7N3 F{n=jզ30;t>4 T)ЙU}OK ~ܑV4~kZ;03c33 Ot߿=M?[©`5}4EI+mTq~V"("zP, x+w c0*)PP5`zصc83T[/ƀ1` @9 xa\OMUH($KLia.C;Q-+M1 Y16|<-.E@oM"qӏFIOl|93KXIڮ$*~]P8:]J#>M m];VK颬۵ +,O1#%۲ec028:hvV׋2dƀ1` >M\d#4c0$hJ$=@X0 T0NWl5z+X4^ eSP:l Sz\\ߛ]tW(c@gvfx]_4Ў/%q]/~ _ JVm+~*!{nDd:s Yw^=K7c&GPOn"<&V0>Vyk:_g71` 8S?<pMݮ $JԔ׺y<`;J\ 4;v|*{$V7lM:>oN@ۥM'N@{@vT?P`7zZiU fƀ1` ƀ1` ƀ1PY~As/VɪǪl @d@*yOv,b׃RɀDuykyk 6ƂY&z1` ƀ1` ƀ1` ƀ1` ƀ1` cu2M\Y5wYd@<vt FM5eDx&C1` 3nfƀ1` 1 y4,2c0c6@5ڙüA t1w6]  x0tˢU^ݺW+[uU@.H,Wk]{. 54 Mkf @;:ƀ1` l *2c %gU.H/aƀ1` T;oʕmZ3bdw AU=Nby}`b,:)-LƥAq`*8HP_ Ev낙1` y .op` ƀ1` @f`$v7S .>jƀ1` @d_s9VÄ/ 6ILJ fg@%j${];0.?`ʰ̌c0q0c0i+='qwW"0zW: H\2(|w e+UD C*hp tn2Z_&ES槄ْ@2,Λ3c0:0`zJ,0c0a뾳ɝۿ %3,4c p\T%ڱ6b p)z8~s~8!gT1;Y..&ed-A{(K`'[º6zTc0c0rW3F1` b;@Pw 1` ƀ1P p\{J0=vNC-R$t)l~w"V=$R93c(@$7lEsqqSW n=?"ϸw>W8~T^ *Z\Ccai*_jٴr1x +WZZu˂L7}g@ňc0eUsb*ȋ]o:$@atP.ȴQˉ5+ZX~5riA1752ntf]pX)u݈3HmZL^JV8\6OUkd#% tGZZ'=7iyњMkf tRzv]ec0dkY/׼%;:XAr\ o@` ut*}ԋD͌cHg@7 oω>ouw(h @`۱=r ww~|*7XZ3V15VҶƀ1P 9 c0a@䞜!6<{oqXVl8$,^Pײ`f @Q**G7sYIf\f6G_F0crxng^ڒpuZn]3nUjk)AN ˾h"֨sd%&fk>| 3,4 $?r̷ec3/$RtWƄn2}Hd6QjSjٴrt (d]F_1(跘DZzijP٥dh!3c0*ǔ;a=(0?潛&l4@d\JrSۂY#l-7>"id^dJ~DޚX>Jc-æ| Q/%d-.=n =+)+{ Jׯyu^]~8wjR03c@Z(~0ꄁmg](Wfr@@?(QgV HTtmR ҖL%i:paDcrҙܥ 0ʬ2VMIC·! |D^Rmn{\EupA+KRI]7D| FsV UkHQjÖ A#Pve҉  ɺ\usPJ;htþq|}ón/hKO:YԽ =t6-nj3Wm4o0Uo9vӍ #k_b*'r[z5he}xm継[mlugO ZīzZB|ckflIee97~:P8 a#Uk-n.qm5 #d/PEd{C! 6qn6d?y<,= ;Z>[4<'-= 45Gn~zr>&{KD ۞eݳ#OiND@q>L"mu B\Gy_M֞</1MI0pq_aϏn| [ˌo2;75[\娿o5Lg9zxBATI)Xc0w:< t#OA_H˰4c0dTF-Იoax,1^6 \[Wʩ`rrq]\}S5'-AB3#?-?H/ς8A%D$%H3i:Àg ~Ωg{6x))́SF[`oS5Pq,״. ,x ׀tbyy3Zܠ>&ePڎY|{67|#S\|O2&O[v}47>]!mvc;|QW`gG08 sS&,0c8ϽM}oQOb Vufv9zFcotDQM s `7QJSʨYU $R+ ^,q J kzuX fڇ'} [yT8s;@p HA dҢK@} ڧʗەXϻ@ƒˤlyg/Y66͵+q.[Tӧ+Ӭ,D#jJ,|z< HOxN[q + fikaT涌NhЕ}2P|^[f X}N>(5Ŝ+Ecc\O8!_ygmo< Zc^[+vf乮o5 1DvrƯɅtc0^`c98iems\Z/bL:nprs33ӔᴷO>C~0HhmKzGb, $* uHHI,+u GF Z~1q.q!mQ"W/v .o@ ϛI\}b>K|Vl]9 8|-+M: nگ|WכZxԛ>mIGux?@}qM;6J~|EuϊzRiNkĹ0=H\T/es&>NQY`Z0+W4:>*DOy ;0]߭ .sO;!~nEfŘ:4wɲG pI"~Hyֳc 7{!|ȾՠF<Su`3o>}BP 3cO1CVx"?4Q ulf @O0y:ɻN~ǀ1yQ2]w NTBHk/- -I\6oMׇ X-_1p>(  B9?X[cWo=|5ZP$|{[ȕ`/ko=HNQՄףc/+t|G@y'o4;Dqu }e@)4OVЙ ;Ȼ6M|!æBO iGF=S.&~,P1s6b4]MI:zkqts]dtrw>ԛ *]Ӝs}Lۍ+mӵIf};´5IDo30qEdsA7*)r'Sk'Q| ?mIm:Z+t=!U^X{h>#x$?MXGL'}Vm1z$c*sG&[^kY6az%s]Iw:?ØKY>Ot3-sYmt_ `}r:{N}GOPxV׺qx `XeAMn_|BLȴ/U}u68~'\ӓq wV|Sp'@1` ƀ16yK *93r-b ƀ1` %$iO5: 62 Xf@d@z_ANi_V!q XJνVPI7Ԇہ4JfHoy[ b:hko//ͼ,d8Jπ<;QDb* #҉/!!c$똕r?KK)A>eVGß(ORo1ƻy%X>jK_/F뮾l|*:Q4S0=)vm;pC_קe}Z 5*_%6hQ2,ßz?սH,Z!= kr:ސ}DXohbd8#NbOװmƀ1P p0z ]7mjq6&c0cA~X>fπD uX |ۦY`{}v {$ f,o蝀OxW$*߆'-(f<cZ+@zoLJ7Yyu,'&ZgI +D42{=Vhlcc{ҕW*QJtJL@`g0wVB1@X mbpUQɛCgxb7ksf8 j}Xy%fݴ_FT[3?aJIZL)fhz=9*h4M$q4}Ýr~_i\rdrn^~x@{!^NH_ ~w] lˑؿCVz驴N0شKs_MAF|t&'E=t҉.U:_5~=1H-q_V<-PzZٴ4kWiiI:؏By+0ci8_RuiSow"Jؠu G=d7_r|DChC{bO\8>qXOؓ w(̌-g1ձ{^b֔ԴzTugd` !>&r2?`* L[$ 9Zؗezwwu?p;fܢ|Ԭ[rDy7c6o9u{bE ἃTirsu]B~҇YnE)@,!ݮ<+g#L89HvQbV<,V]DI8׶ Ϸ)p&GB .5sX2_(fSɌe?RaVtN7!νF7'Z0p U5Fb\i饦R˦Ь1֗)B|ff ƀ1` &bdM)& b^N$٢1J=$Vy(VKTzr`7^J}6Bd Z<{Sq< e%9'ȡKX="_c*~ ꇘF`MU oAח"T37W?o8$`%iA$FS7}v}Qͨy19ؗ0=̩SތifPo_;;}u1zMsS4O=2>E(Guv:+zCx|_d|miv$yBo9>x8`]~j|94}>/|}mXUF\|*>c`j{mc0c p ՜pxD=c|gz^̀O6-LiDoN1v-RE:"廛g? ?KE(-h$-5CmICi! |_Nc>'D|c}"ằb镎N#˱-r\׊1}?c72pi{?71Bˏ0sS|ܟG !zm,O[d#"Xu猥Uj*YtrYJwo`'<_dyQy WA32} 4YV7kBnsFSU\{oƾh:y0.[=KvI`4H f0/?cMx_Fn'03ϳҀ$B-'t-ib#%%5~wO4q~駃S@K8v gGd5 \EudG,M9l@w@xttFT;ԣLr٬ T|jr n/V%~DxIg%?<|L[q̿.^L6Ә~lypZƓ uSտm mKvUxnrꞝ3 3Uho +c'yۓ{3 Bkr_nq3.ؖ6(kCɸ_gV7 mhnB\d+e\&_'][vb@tWݯM(U}ԴMkuMt ph?SfbamBr7oh@l6 KM_^D/0j00FBd\c t~{͵bb@Sn`= i_ a|":uOk[Ǹ4D󋀄IO6-4´erV@~owϔ~'"GЙ7i'aJ4M3#YЍW,7mO@ ht /+chav:]mo^a8?kUWx5ý܂׫!'T؛bOγ[ m4s> Vx2f/,V<}hZp&Jͱlُ؟n9nou~sqo}0:ITi/gS]$ :$i`ff ; C@ un+dۆt_RFes}m 9xe1S ݢƹ~c3LVsg8Ԅ';xN&_2c 1zSw֮z̻_"aB<u?@?Cye~p,ɾIE%'<-+`2Xr_@m@ޔǩ1@<')_`1оfא ~VXx!F~Ápaa,g,8*Mu N?]i0V)?⩻7A'K/s%ƀ1` l *2jW.bf ƀxݜ8\͌j2 fR'̎aup*8 i&D ;ݩ-g ==bҾiza*Xh*x_ Sm-`RFL, Qz X6~N{~-4ghWW/[ d{J\׸7}ݧyZl,a!q]EƁ?dz",pM~?ף&Ii15g"0c4nҊ[)cŤ';'G .E`}$$'70G3= @=z[N[}`$ l wp vAט4> } zLo OT o .Z?=x{dpgV 0c4tH`?M.2zt@72_0ôRNeY/fƀ1` 1AT}&b ̀[%Ź+B\op*^ j*ۖj_ywoS D5DA!ۙ ev1z6 H, &0  Ao ?8ns`4M|*P2":ƀ1` H`I+ښǀboyvT!-Ҍc0ꖁ2r|ݮ 8NF)!Iޛr!ӞHg($Ze;Qeu;`pXk>=C+>q z ]!>pCVɺe9;p_Nu3nIkqk튔`1-+O55ǭiy1wEtV//u̸pa[þnƀ1P{ p׎vRTԲi~>#%lkρW,c0cVG@'q/8}DX7Ƹ`ऺ 0cWDV::rP7_VZ3ay2;֣« F!J)hqkr}3nbx!V~--+ʑ\пּv#[R# k\Nj &nV4N띿d:a`Ǐ7{c,PNˆi ƀ1SP7";ڝD\`c0tNA"yaFiQ7JEsAv7Dd)p+~:ޝ_m驌kГ QynI1s ϯ@! T"s>LܭDwֆ1` >ԄX6Bc0 ԼΉv[F}IJ-ƀ1` y GGm.p#=Jwղ&p'nc2l[fxؤ _ ϒZf`0Ӵ<'e mz5ڝX@ 贤eJO+ꏄbSӹx0ࠢ9֘d@I3/x!.QZJc$_>{M\glÌrAo׊|ƀ1'0q6++c̪c~/'~vfֶ1 DQ)}/MI'xF{Һ"Xv,myfoEtcH8/ 0[L!q&΀ǻvee8mGZzi[J=şDLNfY͕ǪZ0xp_NzUB7#;]qظ gz-n1` T>-٬qV Eagcqx)潗>aKRf#p/u7<[ -mJKWwI^<"a#U?#@PLi饦p3軳炭:f顓Cŗ/5+eڬiǒp1H&* ƀ1 ,G9ߍ$zA?`Po= fgVO-̌c>%! ^!IAvR@3MxF/LAt%ٻ73YnQb޴F7n:;h$CPun{dn|X u ~XFT ="3ӭlZ/B8۸ypDi!Q*{xɛ<4tS/W8|4 K`WKhUk 6۰ f?82Wv+3q2GdM?gmSj;-K]Osm"ܯUֽso'ϼ~tSgݠf񤭒ۇZهA6!g]g4-nOzva<u%ؿ>%7 X˷ 'qKoiY=,|nI:-/_6mT8{&8 x:D>gVO:Rv֘߾q$c kO9:V|tňbqb@b@-KMǯrڱOŠ{b[kp M fƀ1` t{!_&!K'{1n: !+KAYw _xgH Z7|uҋ7pGDsk,oxs˴ * v@=]>OY1m[Jx~9e8cA{.n] ~07Eg|Y^-t_#ЉkjLџ.r'^4C @FDΓZI_C+"Ѳ[ޤD^Jd*' O{b87rgt~5:ޙo3c0@EjĹor&6?,˱xX8-C3`'qL7qBS |NP"x/͗qPZ3ȟvghY7,mM4NQw/LbnWwXqCxp[4DoTیo2S`X;D!?WqL,q^VR [m422nQ&:椧 e;~q .`lzH חku85AC8<qlxܚ} \o;ŇL#w-w1v.WGXF\-%Mquo^JoP[%\@zf&>pڧhaق}D<` X-QZ߁n$뷵qih5ڿ2x? Ow]prEW6h"qrDf`in *vqCcn|"2aC⥦ulZ}Q5-G֟}E@d߷H}p*qӹ-zS=mr8z0֭ O;3$!D+!u]wƀ1{ c0uʠN}}t޺Xѧ>=:R 2Yz<+p~ e>|8=T6HS7Ӵ)RIIqH?t&*R zTtS%0c0Jf ފͻxeВႌzbدXwa@9 t#f 7S5͌c@֡T mq:"a+y)Е?x*<ث5=G56x3scx"?H8u\{j.F<`w8"hɛxq[ Bfp\~ZC\HslC8-lil[ hq:$d^Z~!nO뛏XulpJmV0ps&PO4j vGMqf JxoiO7s&>؋^gy^E n[dzǶ:y L34!t4l=` m[dI8 k UWu$oܓ/ن~ׇvo=8?{g'GUSӓL=ŽD$(TT@Y]qpAPEEDWUԇ>İ *;Av% KH !$}gjz;==99sos_ݺuH$\qce?"Lg]DŽq+%zZzpGp#?k>]1 }Ѩ] v aJ~qKėȦ$Ywߊ/j&T?vAGB+-EvlOLj|>V#=ol7To>j5C7F^j9BEfrvqbmI5|c !bz.Y4Jϋ$l(R3;|O x#{7= 2>Y(Q*1r|I y c)yfQaY2;Ң;,sb~ 3$'K:CrVhul:z_"ii&:˦;spljړat12c“}`ߦ^[惡O1S\hCER<;^k".ۤ&vY([*<:] v?T2ZXEPu@?M#ױ}z^4nDF #0hษ0M ~] 8#8@QCT/?OvOi7{dCQiSe+FvK)u,vYsxBձ,K3w*iB19nzZmAPОH Hi( FO":yu`i;uK4=H=aYIe8M5cڐl?g0̶=IʵD_ 4{g>˰{4yѾ ߕf7Qnb!M! =[rM:JoB$t7o#`XP!f.k_&!B{"N>PKuiQ C^&Q)ăBE ѰDMEM*c>Xu8# 7<=dF<']2vdq[ʻtTy*\OCDW!]$vq%iroۣhhlCHЎHtj_|!" [ _ ) rSkCv슗Q;M^(nd;m?=t5ס iˉ-Z|?caj_ڈ ?RDslC~'J즒ROe+8%yiY?7MzǎC-+AʊL'^͂dE x U2:rSv%m$DFS"qb﷥ڷ^;Xij/RI3~fvuuLr>')cYۨg8$Z!y.F!><}2Aބ#8#{pNˠzt"E +]5tvq=MhM#-IvY/L_))+|5A3$-_)LXz/"NM$귢[r {=ؐо‰hy=%kC ׃ o'E}qWу za4sk_RcHF>ih^G"l/u seWkƍ[G^aH6+¿qGʿ7Z2ֲ~a bW^_Y[~G^SH:Dtb6 {-=\3TLCZr;{; Eewc/g9ݛe+Qvlp9-c+6ݷ5XépguAAD ,r&bl^rp@O&4ڊ/`/Nvj:>Qh7awC1Ozpt7utS z:cW7zopGziB'lYFh%y|b8Ph'R%l| d^hR4Wok,DKE'M+vZ)MZh&E<χ I=~MDRn „#sC]Lٌpb\A-k4.I,F+tpHJD 3RH2x3!/̸m]Mf|M^.eގchBCRPV~&˲nj yi֎Gh\Lئit? 5sX}P䇆t>>=N.3+0釉6TlizlcףͶb''u"z!#]𵚙5A{c:[RՉ T䖋#8}$cD}*:OGp:!9%qn[E|Аڀ~ϯ,nRjQ׮A@ųKęw>gRE>e R|ygV^HJDmH7D|D"ł"C4[!KhhGe'&2чb/pPv2}T\QEXNetZ,T"6|Tե:(WJFK$Ez/駇a Y%affGBFePA0@IDAT>2!T_qS֦w`!#;x>OQft`^(TQTnIƠ[u2ߎ.JE詨N*.#(:ڥ|pGD :g^ՒA@'?(0TO<=LUe!^X^8ߌ^nYJD8'e 6dd:]9}PmK8/^O!Cүgח"ڃhxX)Jq9#Z}׃;&G# dmn/"=%1ƜI-ڎ{{.,qUV¯sdΆd?ӏ{e 7_: #{rlP^XRDd; r= ';K+P*3-oG%N~?R?a]"{vei6{.h`Hlx,zdC23,DQb]$%o2ƶ uB$guJ(nG~|Qw[庤P_i>H֑V9V1@0?AE'EЍ/'3<88Et3Bœ^mZ9C9D~ l\aOwGp8~Kym@ ?tfq&$7[lt-& j$ ѾQ}kε0qv*t{u> m7 $!]ZlCw+uyXA=|77lLAƇawX?E__)[ѿfrX59[qH8 "r<Ml٫ZwȃX~K."2rؿ?C~:7^g;Al^Q1 m`_tbd+ F 6a9l0{zdK]ͲGSӌvԬ -kc3l%^ aMMD(ȿ2K":@P\޵k#`g 1ƿ#ڦsޮY[+l%ءlJacPv_@I_N& ո qRkI`ҝi8׻~bWiGzk(;Y8@8;*Xrqz]@XdpRYKySM!#\$ғzN֯4ix&qdZF/Q3ж2y aqӃn"pi?lWԓ 5{\o/A%"c{"z C/!I_c#IP$y>|z~KA7E%Eڱ_Q4D@C ر.tj3X͐2᝴Q>ڢ'hBMh!1~B!Ouٞ_Hoi+b[zv^Ӵ#r!q>Y-xѦ.gYђ/ؾ$W3;5-*ř7 &0B¾|ۏϯW9k\(?_-u`y~(C~6G'[!UG%`}GO]S?VAi]HMd]l5A>>-BGxXioOOz9cA_@/ Qm ].G[QwC=J51}``w;(wp5G9߯y>dg^̷0uSDE d"v M;UlMf7=ă| "_5&`T6KE"AhkbVJ(_>h[KTTnHڳO%ҫd; [Q=(!%:EFXm̰݉_xj,a; <,޳3vU6ڊڬEf*#n,5'Cƶ>͞,/C(7A۷flIaFsFUA-+mQ`l꠾Kvػ!co{FwU B=' r5a1&ّrΔglaSSg?ƅoW1_OR/ef:aȗޱڎ"QL>(9;?NҕCemV?E$KR;d}LÃ]ƹzժR4Χ$ߒ]ʟDiؽOGo7'u™Vu#e Ni.o"@]0q^@@?jC} 'D7\#- y#8#0Hw ."D:iW"k/ݻi}[PyxKu/|`>zQ]gŘKQeU-]P>D(o~F e'P\ ޴ Cnm>( YQ>I]) F~ oHTŐpk ۲EvdYe`<'_.ZlGg,~*) IZ_r o-_̞U456~4wX4؟l>be!&_Z< wf6kh9o<||2ۺxVM`G c"Y'b!^D2·._v1(go8sAg]Hu|d^mZ9^+iT֌Rf|_\F%Φ.hDo䌔ruMçpI0-4?0;mG7$>*dgLk~7ѣPZItI9lR=![ǐ1V5ƹ :*ATJTڭ&ilu-}Q'ir,3DU]Djߋ姚*Ǔ99ڒ| =;3ۗb4?>TLܒpv1I//:~Z0_>_D^9mC^' FL',B[_GkPl|= 6@AnLO## Љf' E¤V֫9A3n~-w-p-y_FE&UۊW֝i6Z}$=)x ]ܛ$B~lAsqG.p!fyc]k>'K-Iv<*R/MyLZ µ=ՃŇ-P͠ք~(=;.Tx-I{^ѓ1 /)Ɠ~ (E~Hd64u^t ]ZJ\ǯP& .O$$+>JتGѿcW;[|/6QB=,akΫ#QGpGp)l͡CymOuqGnpђr1cL!| շJWթ7'c/ qMEnE5WeUǥ|Xz;5)l}>CN^."q4YKK$k|H^|ѤGo)fN$Ԥ#BēRkDzv6i4%*>&e4/{ڀJo.G>eg*u)4i[E~*_z4:D8#8G+wEf Pզyo97Ӿ:D}r~&{DГ2ߣE2D5n"\BhXiEP(_CGQɖlE3f"%PͮZHi}MA{ETRNDk:$e z0Do8<MCoG2+uB8ܟD>LO##8#P.FjtQ)[Fh/-ڴо@7 a}M+/CjpG`#IIHAAkYF5 /-]cIEP@?{(R=1]j@@o |=ݼklߊ4|>ؒ"FB+]s~A< zA1qKx&}73Vt :WzOPr]AEQh?9z8$=]fp;G0chH\J%8#8#0y3ZiyԝtGpG_"B)/>ԣQ6z`=l>G@Ğu͖ }e8󤢶EQ:.C@N@AE@#*[c1 Q ]/H'd{U{"CO u4ۣP44@?.#8# =EKftӻ8#8#0|)(RQʥ=jDtcTK /2^\>ՒC apGp!AC6Tk>x?PC֝ պZk]~ H\F]uGpGp_qC}9!<5Gp@V;<" OØ >b]3ѵQ3?s]"'"}u@1/R}BW3npGp#߾Ժl^EuqGnpܙ1tqz}Hokhfɹ5l~Z>8ttB~/W6Z4+ZvB'`Fo]/x_U'騮mEWJ kuqGg8#8#pMQH.z9k#85#qg>F6ِpuʹHv~zKjVEd.DK;ҁj07D8K5j< Hބ2ĺu3%p!GpGJ 7=IƵ4-ڴrvz 58| 8#c8;cb/"p'?y^l#o>co;`lȦTׁZw(lD.ETzrRGpjB7p59Zm*'vc|M0[%t3 toT^Jgr=qq Ju1S#Ȣ/a+w vbVΖ?m/؊a5@k+/+m GݻidsSome/wqѤkc"'Gc9Rp1 ҫM-sqGTkpGp-Y+8z/L.OlPu'@Ej7.E?CY)1 Q.#Ԏ֤w8_b}δ5(]idi&kY[Pɣ[[>Y~Q5\Bw *Y\DXOf8`qt0Harrvd6gWp'DGpG`"zskOD5dO{c>eo&ϥ`&mΖ>BiRP5f\#GAW37Z EL8?nJ$c6bt;2Q7d(>TKĦ)9[kzp}z Zz4ݴ$(gU?TIe|ˑs_BuC87Nn+^mZwʦc=upqG0zi9-!a~ n5#Dau 7t]Kb}z EZ*\o#8uC`닖4:Յ˲1W-2L3 h '|Nxl bN> @Ijdڲi媮Ue]P7Eʸ]w:vts!LKS^>CWQ͐k3ѹk\\/"*\G ,^Y.vܟ~ =asOM_St-P~7'p-"=9c]f{p"0ufe=Pvq`_ِ% G`"S8/uqG 0 T7'Z|LK"0v-j߶ W!1\v# rsiYӽk[ig\3Xtmq[q.QͶF_rD_ބc"D E+M|#8uGWZ6Z][,cLg"[YpUKlS9HyB2Mjڼ}(x:zUc9殌l+ζ7{%ghʷlĚ3yl'"Mo6g9Nh>>(xs-q arN6 m[L㌕aSYÎ嶌-3lE&6+ˑXۘl؟-oVZ1z+`>bʹ-1/ބgbx&g?V1+"{6E1fl]㝥{7=y}+W)q%"L~uVw}jSG`!1@Dh3\t!fN2gaY0\woxGpgT]7I"} MhyuPM%"}=;ToT|ŒuRR.# VYk9cօ *WCX ro~27k͗S_ov4uڊ:5YO5}BDṛƑTx={"K!pjeDHZsgn('dz2's^+Y|~tfdEDx,C>Di8p >hz*IIZmh{H ;SL=E')y Y6Zf,X~*T9iʃ(Ke6G?)@2-o["z:V|g0 j~K峋#8 G;A1CĭK}JU:JCsSL3k+C̈́OB ]U-cz,X jU>H-:@;и@ަxtt=t:M4{8#8uC]Ttߛ@;:Qx ݯIB9: ݺODŏh&iʮ( 8 AҮ937ػ)Qd6lc5M 6EvAh'וs!OZb{jVZt'_h)-=mfM\$K+D@/~2n\6lOVOO;LD/p0 M#ٯ\qoGpG` uE Š!] .@_u/"3&]_dMPq-$.@P`X՚Qٓ]'puuu݀hLe~̃<`ii*ؽ4 [vzL{>86 0;}vbZKEa)rY˯";|k 'C0{WLu//6fd!ϛ#I26)&B;Dw^t)@Blr--pV~PX-ΓݓC픒ӭ}eC8ʴ\Z}OkG` >-h Vx{8#8!Jp}1`Iv|֛yŸ \\,sM:Z.=OD@7EU.|[Z \Gڗ:늟ы> z[6͖ }^AǢ+rn؂t~&9)~FlP ?:',V4ֱ*XZt,`9> wwd_þ77[btix# 8{׽OG0uE}^M;# (4otOwMv|Ѭ铋*T%8 sP#yNDaOU8n#&Xb+) D!L[*)UNqK*.#u9Q@L߆.RX!֦'H\cvlQ?f>Gv]s;R8?۱9Fl Ux{ަMmQ!s꼝A4$7u;ڋy: G7qL뜹bamrIO|M_esvqܩ\~Mc!Cfx2g;='n؉}e|IߒCi=i㎀#01mYk#U~PvvA$;͘sx+eJ^-䲸?P&J/%ׁZ@ըsWZ ѓ⡌BI [p>BFZ;;g{ gS ϝ TBF9[3o ,Hߜry8F@?^ZZ羦HKd.G6?ug;='퐢 YRO߫oK:#0m3q_JtqGp0y׉"!Z ^2,]hJ]C~I5 y;ym J(,|F1==tG Zg2;GgAkج~T=zJÑ{"YN.}7fG8Gl+G>m"lu 穟y^Ň\a8}':^]1oVLkZ/#o#oQײ:uE`X+ir‡Xf$c3mٲ*NOu kT)}NJŤgV骰^Gk+yy#0x!*0/զNevm*D?sNeTk2;'U;[؊lB0ZzzFGnGL[l/'ux] Hz mk\P$3]V״rWӃx*;CtqGp :o_T/Ef&.!< = M_$蝸_npI H^ G'x2mqY[hDG-a!roZ>h+Y[un2q-)`'D6/>:[@YJ檜V|lrH)[^Yk;$~8bExË%z%T+iؚdq;L8 ts_7ьtO=sr-+-]XMIvRnOb,z[e96igF5<|oGĚMڿ*":\-ֳsq!0j Ռ;GpG`#e#KArՄo' 8GpB I.!T1DSk߯m7$͝35Y'qkQB6? ѻi􅎺jYkQ.x(Gޞ,|J#|ek~ LDM+j3+$PrCCxG̺?BBگԇ&0k>BDWKc1!ۄo1M?pI[Xo^ۘMUW V_/Wd,W 7ͮV&6 [ͺ$F :eQSEFvO6~4cb7Ua_^^o׆']䰵]7Q 揽rK<t6<, 4$:=އލމrܵ[@E[_k;xmGpGՌ ݩ{W?k}vGpG,5\lu?63x{Z &:/q4ۇdx=gkȈun؄nU?tnCd$dw}vql3vX~m?B)BۋY Z/4ޞrߠs0|s<6Qoud `vIyC'| wSUn:v32XJ$Fdfզ^߉RpqGpGpGpz &Xmͷ1=~3\p#8`D&;>)z`8#8#8#8U ۔Fc ZӲ@_)❼b׭]GpG Hc%)=pGpGpGp"|tƮyGpBb=BG)z-8#8#8#8#8# )$ R}Ћѭ{#8#8#8#8#8#0TzKm#8#8#8#8#8#0LM~L6#8#8#8#8#8#0pDײ0Ir=s }=qGpGpG(E?Yo;#8@rZGaRM;rBo8pB8#8@#Th٨#}G \ Gp( (h [.}Ȁ.A5\?S7 \K<#Gd"^9Tg푽9[2XFk=>ԉmZ9[#.؊ B^jkC㰓ͭk7믶ñŋG]Cئp޿wZzvFF9kר'4εVl,{1}X^{mc"bxtጀn]Gp\w>/r2=ڗ.pGxܰp@]7P0VEǢ ;Wiky`-HqM\ϭ `'۹%}6kz?\׷@%,GhYzwGXo9E;3GC%ިӶʥ#ZIV[H+z&Q}{8~zٖMoGexLdK_K+_.ܸlv4NҭsB\ rY)L‡1 yބ+* y%ccd-cfz4e؎! ~9bCޗ2fmL~YT75[>qO~ǜźd1^QiM`aڈmbmֶK1ʫUƊ1of]xlHVP|S# ats8#8Cѷ z Om!= MK+V6-m 43Z2T\Y!I5¬'onlb[g(\aSC^syi,=ha|T> My?A/f.c{AM?rZ5l_Rlc DޤOB>吢,2u[A2>8⥒/C^dd9z$/ˮayu2_ dk(x^NhgqZ 4^|{c-Ӎa%9 ֡/i1;m̡9{`$^C؊o6jr.w&OT 1l4uF&˒\d O/=ft@SKZʕtGp3>s}08#T}լu6(KrTaZF;WnwMôS}8}$~];~{"v|=y;俋؉a=fwpٳ#brdU^V,f oUbgb`?TWA˶ xᦄ;K ="gw0~Rd@͢&m. ȟ1)CI5Dًu/R` 1e/QVze4Ҟ?dl>?`cni~WΚsN;^(?+aT^HmQY{Y_;) [GyO?dQPP٤P,C!Ū0|f:>?Ic(#8#8# pY6+t>~}?ʍ==}:}77Mnmwt7tWtT(7y"D7[mQ}Kx6Bǣ\}K86#QeP9]GpAR!c)6k֖#;4ݐlG3Cjk#ǴJȇo$D>>5jo2Y6vPY[PߡLawȭ.m̰4{BЉf<~)%oci3>lLM>cپ\y4.I{Z,Z 6K)3hd]T&ƮϘӾ)h: ,+F_;lO;9o`g,W߾j;)'=7`~16V˜{vAXv&y kP #,AҾGpGpG@D{{M#Sg Y@c# 3 9'۫ن<]6?v[\otc ]B}Hn0@;%Ig˅-(Swrl}p+ⵌ(dJ66XU$}=5Ze YO-ͯݙ8nwZ]}w`UUgg#<؄ˊ)^L;WZ_r!!?V?.ط,WɼO`%Z1TCNW t!@uC5GpG(A)o<Z8FGpm,i$O}|ſ༔@hYik99BݶeݕYin7mߜW49aϗ[H }\xϲ$ Y5S W$ajZy}Wh-ᡊ~|ۯP'}jFz/Q?<,yu{#F[~c%v9#6,-.MYf+>h_V⽀a<p!@!c#8@xkv >GﯣO??oFqKK _ޠ#0Xo^;}|qw k<7:k\.YbYHH$7=ϑ]24<.M ۴qfXGݺ6}[F4WvW:84|6HHavnx k,{^N%g-v4&[؎n/&C )7ZJ|2hܾpTg߾4gmu[]>ntثO%ۃ~67ڏlBf.{eht4YLM/i%KauvG`8!1pG .{ YZwU7v?=?ޮ#0DM?x74 K!*Kl8]l僒Yflѐ%Y`2g5ѹzzxދ-BGNƭ[N<(.gs'q&D6eM/o`﫴l1;fmGѥ'#fOti/N>}iW"CJ/ `o^v u{}d]Eݢ1ߞ٬%y+u fE/+oH֫7U)=N7=v+:#0pr} wpGpGp$_ R4ZB.VZ>),>&,$z y g,r&f!ӯ*Thm_]P KDwl}Bc|9?R:'.ʗ7>ֻ=$k^p>G>tGpGpG` HC3zQYג>o[ق=(=/ҙ}^vv;3%ÜeYp#.E?zE6z|iv26j2ѴY0>bzOZjOSZ+_>>\yχOY(Q>>#5FTC:ڋ.iYQ5><+(4դ%eG8>x=wGpGpG`@#٢%HXÚ[nzt>+]!H}:d$n#/|sɬ5y?sjVr1LОĶָ#)ilD3y(:^#[Vr`PqA u>]㰿\}I%ѕCzK'ӟlCeּ]Fv2!>zn>:fŷ?ŰzvGthn#8#8#8Cc+ۮ`jk: ѻB::g;W_YWufO-;g߻bwAzҐ #4 ҋ[ ser~KUz!|ֲW cjsVM kIo.KA)$%Ӟ;Q rbvAsCA?3o eLt)C񍅇SoBn7-dlz! >q@νq/SH>>cjR@W0y;#Nު#8#8#8^rVѦsޜÐF7g  Rl/^A̾ 5;Ok< ҷDzִ%TfeGYI { c_@·TݱgnfG 3>1n.%wBb/(У(ƴ^#@V-'7.oa؀|#k}>_b?VSw4e/̖&Hc-ufٝ_'ix0lƞS*ȸΥosgxX||8cS+ Sޘ#878A-saU8Do,f_5':# n G4:{3,#2i_/{mYf WDt}ɼ߯*[ ҧlplC1zoH'oOioP {Ee[r"(Nr;xm4l&nGF[oo_AMߞgvV\fіךE .cΡӨ_dM_mZr:8t$I>M>\W}ϼEGp7.#8@X`8avɧ- k|Iіq:Öcrڰ~&^޸Uoy_6jo0=>h#F}+~S|HAZλF^UX2tCCrp5s.Fyefj0Zlkkr5.,)TV}opC;[rG5G7|;Kl5@^.V [2۪a& /y,~s>ybEdÍwiL*k:oXsEuNjxa'xfM67ee'R#Ұ`a'{5wCnIUYۄ-:VVjhU] єވ-/C-G` "Y[dZ,Sf7O89kÌ-fi,uݖ^Cr+nV E \" ܆j!˵P[REir"`TȖh٠;;\pt]pG8^wHݠ#8+sGUVsOkx#ޤf~y8, t79<@nՑ8y =| sQ5;o#7ik[,7q/ݯgkFodg9^~Cڲ+;I?<͟o#,3ژcN7\kѡdPܳ{SZxJٞ8@".X4rm"驟ffm# 9=0#4/UݯW#8#8c8#0h]i-g:-mm~ fђ%|%c-]zB#6~5ؽ&]0#nӢŋZXi[Z׿eWXϿiN_[?)ﰼe|lQ~Zu*76{6JD'{F}y9<5e<{/[I#8M'c!ho;/lM;+= { s0gͧk|tg^K}}k2]GpG"*VLGpG? ZxR*J綝d1Ǭǐa#[ԃ5?k%V%Y#=^gq IFՅXo/ m,s($gbXJx?G(b5FqG_1cKHgVF#8AgpOGD.h=Vr;(Ti|r /b ͋ƐmϱDHˤh ['{ IfmvޑpdU閙=[ۃd|hku|7%yߵf|*@0釱iII ef>ǨmMlw:Q5~т;?!PU dm!]-N|.ŲFq"Zr[N͏Gemx#E W6eq~n/xGIЫ=𒌝zEdS |ϙ gzyx ڭk< :.jh~qLY-pG8>x=wG` ;0) ꮞI$E Ys@t]ӪkU 1*(ʺk*bTȚ eRt;{{f&|yuSV=u_ 4C+86 Κ!D"yɓSMhrYѰ%ݷ\V?X R>Xh ^ۚn7:fKɧK`|s&x8]нRy)b|9yE:]"ҋ'I٥cc?szt1XzxGW8]tSZWU|gn06"U[pnFୌXi@lZ/d̳#˄UW_*Մ֍C-"k+>);>W-6d'N8\Cv^r;' tUY.~FJs>PjΉ}巷^xWy_uK$3{Ϊ]0ܟJ~ߜJ%Ő^Lw3φ6{4 L th ӡO$@타z! "K L .:X4*N9C*FfW5{tDcc?t!a|fClB.sYٕ .6º=v3^*گΒiƹ//1sqe[ɤG3u~_+} t{JXˌ(ņzW< ?g𫯱A)a[gENУZd&/K#\a{ v 'V[T U(w(5H!ЖT֋mK~Y HH:6:$8z  OWJq#wsqeDw"(=nl#w«,{Lu;8'qũ{N;APWzi?o7W g#' ªz<WF_w^ar5rrxmR~):_ӗ~u"n`<%GRCϿhr ָR]|Tr:FK [ҿU svX鱫gO>K;emz]·Jmj͉ťK![2e%&9_ -*5'7)h>{D=#fr RҊ}_W_+˄kG`8L<lx .e9߄5˒KGKӼI7B*yT_a`?K_oF)Ï򏇛͗K'S"'gtgHHHHHkz~= H>rT+< Q# rV |.$ Qu'|8zSGZjo 1m#瞝nx޵wߑֵ@민̭1.WYb;FԬS/&_X/)}hDM?471ቜm%=G7n.8!ՅyJmHͷ #KNdlPQ߷eZWC°46JWgtQ6L qk;-kt׍PZ1>Q,rE^Yk#0&}8ᅥV5,D.PbXP+}/" zM͆1فo=zt|;lgBd%tLnP6"CX< '9¾8؈O#     ?~L E e/I_ULY4j0>x)G\aM"jDw3B"0j!ŶR{ޤ؄ It|MơI '#U8;ݪD?5[=ܱ!hsq5Z>|Ot@+yЯ0*t2+$P-cxW?hs7.TuC/v%?&\ؠ6iqGE?ði$ULԟ[.l..\g̣zcRǾ<"g/=jOue9;/}/t߃.6xr Ϣ(}_U\O`Jw%;>3}f3lH2ٯ]eaa?WĞ>C0lm7aؾL P\K@$@$膔 ;{)!)XL3"Տ4ݨPcjkkqs5IF͘nӰ!fsXsM^ƎoCJ bqr~5w{SkRSpkhiR̳Pգ&~~|`ܽ2ʁO}=4`%MfwQfj bEJEYhVd" gb{ezN]Km kxq w$ L O޸to_h/y->Rϡ W{λ4aZ_|iSuG Xg!*8ƽ/z67bO7(n>,c߃b @#@q=pNHV&Y/*g2Ï^go7SQ&:ȣ{fj<9IH<Ʀ1QQ=|8|Row͹xJ5mΫ[1|ȅ:f*{[ϾrbgLЀK32"ͷ&/EBڨ6G%]<~foUJ&?n%ts]vz3s, Rz%q~ IbіX~rX,kglG$@$ P\  K@C7Tx\2 O+!il#o65|'qMӭLh؆JwC'$7ExY"Oĕ"ׇWYI|z05FQk<耢ơjDr̦;D8zijOlm&'T7,'U \jtS86g@響co&v0?8lD.X *d{/P4۳6'Q @G$1xUk\ߞƌe̿ݞ̱ ,Wח+^vN$@z{UKTo/F~Y"eIa]9C: zX+s=rJ~-:yk؏,޺"8fOQ$ 4LϘ0 I#F dKG,Td@1R|fMdȠǂ}b<wbWXYuUGXGyϻcxTM7Фsg)tŔinO!U?0^9LC<{AĊS镑_cNqWcI<ƈW9k8O"%\a6& {Lqmݮqysb6vm<`\hU^lȎtFkWp@\rlvYQGxI(A`E͞?)yhR̗~[*ex>Z'4o;ri&iدJ'>6}TESV~bĞ>#}hzQ&zAEkoshϞ3v ~78Wr_`w1W5 tM 5;gM$@mJ xRcpQJ$4i[9ƒ4P,ݼjR[o%xwkg (Zs['#UEВҥ#z7V ԚZTwW,KԦ[>ȡXU|cJ}^Y2-0G&VbI[ȚqY]AmI}8)[+&k>e_;24&swƃ]ϑB<fav|׎Th{o}>+IHV+=L$@@xxódf^*:] U-4v%|]8j K`4OCŪbqNqV_iƎW! AuSˋ a @ZWRdm!8" x!{VO?%{Ş&|n4˺RγatlNR3wWTUJHc_?N[obli9XڻoO6q+F&啕XkM_ lMWvZ74mb ޾~zEBÂf1M΃:Kb5$3lu.7bcdy>zYx1o` ;|j%N61e_% _3gak:k3 @;&bXͧX"eRzBHy@ qYt0A7ku3.1Ƥ,['e6"g9XYwu!RT#]A9PKC1iu J),gWYuX\jI̬ysoXĖGY NS7n^kwދbQ0e+s-.xu10,Nłq%\CpW2N\JO J^bǁgtxft,R~{m4axv_q_v8:լE~uhI㓤v")'khL^@\_: /%%FnJ5ʢiݰ-P[u ,1޺_ljaN+ܠo,#mާRCx*r3}͚.*;a_T^{fmb3+uXT}i&)z×;s3p$2Y -q|z sQhr}~XsMo4o:~f >K}Jo;'gYwTߡ+/Ky3M$о@8 ǹK}&O<_G A/A>;{ć@B!8e*>d{x'K5 ?{CqP<Χ1}+\@wzĤf:qsy$$qV}F%@pn  ]1ڬ!zj릖j%BlYf+BW~"[6`Rhcbf(ubC0軖իmn~Z )$d&M|晷jxnl+E9s.Q=gx_5a=ld4 ֱd&<3 x"\E;!B2F3 nl{ xH;K\7"F5αw% 醻?fHHch$@$@$@$@$@$@$Б t(M3gmeJ>]a=YU€T<λh^NSؼla]K!H%5)uL1}3똌%K1oEDscf.Xp9ⲩ*:07)o5 EgmǢ偑u~ yh3`nYlf&ֵ,(r[7fװdQ  Jz6^ @%`wܡs$@$@$@$@$@$@$zx=!rM3?C -^)I7s1 ˝pp";j'!Oy«zi sY,S&ޜq! i"cruBjZj½zLtΞ=^zOCr~u4 ,gIr4E*7C,qF8a]$w桇RoB[_\b`g#=n >dN^g+^16T]yUc>jhm,\_j3J8!\NXdg8y`nXRP nLK8"(46Ż$#. p0{h%0cRgRޙ& X(wђ 4C*4Ly/y!h^Q(И؇!muxBڈtgsL"OTu=deOs|3ƣ؅T IDATlT<@8#,֋qU_nŎÑUx>tاn^^t`\I=CG7-P!fd!}{E|&ik ) 7{ V  h4HHHHHH:,z))V ane`{_`0 u73UIg7L.DRx>!ZbK%~#_}G 3lB\޲;|y3nL[s ئ:l8[韎o&䌿ԑ6Fp_17NØWg  Fz{`. @^{mR tZy &6"Dgk2SӳpeOvxNK^Ͼƍ̟ڒԿ $Ȁ~:!{2N1ym03ԱڹH^Jtz,Q- 2^9ol{u}:h{ޕJsƂbA/g  Fz{`. @^}P^4  .F3y;mpx!@< n2(FcO&!Azevc;i{zuVB = =s@,5++tGK`<(&sp" ܑpKxqV PRV8yc}v1zqeLxo| R9ei9Dg5"?x4..4-gRvxFCq=N+D4      h p $@$@+Da= 4T ^>c3(_#:?B:VƥTȝk\&I)Id8^7]Tޔ!-sVn2c?{P^&s&8LC|GB+]޳wt,-uY=no'E0=~Ox?n<  q;ޫL\;]F鶥q\6$@$@\ @ 8$HH#=4_Pɱ̫oCk"jz1q*l |M(6fE:Bmi0qm>Xh8ҧBzCeڒ},8?@h H/<}Nd9|Ր]'ߵe}Q|O$@$@$@$@$@$@+=WIH _Xr;%  X&t @W&`>'8w   NC`SN3NHHHHHH]z~< @+ZQUIHHHHHH` P\_ftlH$@$@$< @)6ôqp;        ,4 /IHHHHHz/?HHHHHH:20x8HHHr HHHHHHHkaq۵1p$@$@$@$@$@$@$ tir$@$@$B]qT;&$@$@$@$@$@$@$@+򫼕7% d`>Pq]pHHHHHHH:)nhI,E$@$ L=a] 8Q$@$@$@$@$@$@$@+7! 8⺦HHHHHHHe='N$@$F,&laݻFa7$@$@$@$@$@$@$@v08  IXs@yIM$@$@$@$@$@$@$d$@$@$@Tp>\?BHHHHHHHHHH1Ye/] J$@$@$@$@$@$@˘9} ,gOP׳n`{pdopy4       NB1;Ƀ4HHV8_XW}}8]8*oF$@$@$@$@$@$@$ P\S  X¹j-[HHHHHHHL$@$R pqq]8FP;A#      `v9p$@$@$" p-@ibW!Ӭq]F$@$@$@$@$@$@$@$@$@$@]@2;Bd ebZ@#      Їus$@$@$B \rݤtkrZ:\iHH@W0K$@$@$i \iglj @Pob/COp,iRc74\Lw$ @# M;pIHV*pw/{b4'nGEhǪ$@$@$@$@$@$@$@vP8$  vM@㫯Ë;pџKF=|L @#0]s$@$@$@$@$@$@$`hq94d$q5OIHHKЕh tbtp$@$@$@$@$@$@=3IHHZF`uTֲE$@$@$@$@$@$@^?&  h?PNo?HHHHHHH:3Os#  G`}Ly/*cm~uplDz&ۧxA8¾H> H+x{ߩ냤 t^nfr%5;T ?w<k|{dP&dՔ ߫LxW3%iX.iʤ=..HHH DHHHH3IC=?Upm6.Vš~ 8tSTy86Q+=:+|x.t?yL$@$@$#ՇVIENDB`cdhit-4.6.8/doc/cdhit-user-guide.pdf000066400000000000000000014671221312257207200172440ustar00rootroot00000000000000%PDF-1.4 % 120 0 obj <> endobj 144 0 obj <>/Filter/FlateDecode/ID[<3F236C86A7B44F8483A8D7BDA3A25FA7>]/Index[120 95]/Info 119 0 R/Length 122/Prev 420971/Root 121 0 R/Size 215/Type/XRef/W[1 3 1]>>stream hbbd```b``".HF.ɡf+-6d{IF v~d$dg'H (h0fZ$ue`Fz"g0 3010.S endstream endobj startxref 0 %%EOF 214 0 obj <>stream hb```b``Nd`e``O`f@a+  't4^A3' xW1&s01H=`5cpJ`lg:à|!ARq" 8 R=vݕ s[+F'![,(.[lɂg5ʚTcz:i皨I3?,w_U݄SүQ0a_\&gL9ߒjŲzѕ  `EG6%%Hǁ^zm.w4^q@A$5]8HWkY#pH40C 0!& ! L+ܬ hLHnL&$ t=T%i<\.Gxh(30r1f voe-AF+]Ώ{X@ l/[>>> endobj 122 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 123 0 obj <>stream h޼nF(s 4fAԩ: ,^+3ECbm3C)vܺNpZ15zό>0',#T !A1)iÔ6h-Sy)+ ϔw4'0iO':tU5cCQ#~6/O]z1?f] X!*~ܭfo~(z]߬#].l@ RzOrϛY_5^1#q윫y}կIU?~woڏjlGK y_40#FbU,%~&TcP`.70EŜWcoWfR 8`CW۰81V߭Vqke,7q3{ px P =]Am`ao}+ǜjAe0Fo'ӾO2U`ϡ)JՉ1~S&ѤZ3ٴK䔿h>|rY/nR:uiv(B@ :(k hEةEA% Ydڭ/%?>d23j&Ӵ(RjxJ>]~}w8Λ}j\"zLof#vq3"?iҎ.ņȣC92I#PJ]6pɦg'͛i jh?6C:k7Hy|7Xg4{ŷo(MOLR~^ݚ3 vXI3H=IIԪT.`aibW ׇgS3fz+{+\Q(Z|CFlK#6ʱ$c7(jy0\^7`IĞ!.O C IRoZkiZG"sJ>x-Vq00GPMG=5Cn@֭+*tI6z]I2<қƆii73E{4W2#ـsL #o2lD<*s1QAC>stream Hlj0 ~ CqsB[Dz=c+FqynB_%}lN m1A1NafIMwU~;2%ꃪ*-ޔxJ_!{`{lEsWlU]^|iF]MiY"¾- h,U:K ɽwߴMetvf`%Q !f?]q endstream endobj 125 0 obj <>stream xYr6Q_NE$KMI&:SO'Ƀ,Q]:ޗ,ڒG {v.ſr_(d=?~ř25b] pa㺼fK{A$x_dJɗ9󷽷X>? ~~g)?|𔖜$mZDB<?L[U0N#q>⧗Y92?j,[N;DI3;%;Lيl~7gGl&l}/BN_);A!lHgY9R^_x"P^L5IQ%LeciۖWmg#`g{8!Yd p1 1go3gxkks|W0_0"19{ﺵK>j%}<3z =&FQE2JF&CFE#Z'ĺK ^ k wnX gA %,wX%Gyؗ0DWqFefo5@ b_eM'  /ɚ\[5`؞G Q o(V-b4kM01^zNb9icФ5p̍ҹc^|FTFonw;rPV huh5'' Z9&/3[:Tڊa"ik"BNBMM}94MX)gbHhkȏiJYMNJF]7h'2}#1gb) >stream Hlj0 ~ CqsB[Dz=c+FqynB_%}lN m1A1NafIMwU~;2%ꃪ*-ޔxJ_!{`{lEsWlU]^|iF]MiY"¾- h,U:K ɽwߴMetvf`%Q !f?]q endstream endobj 127 0 obj <>stream Hlj0 ~ CqsB[Dz=c+FqynB_%}lN m1A1NafIMwU~;2%ꃪ*-ޔxJ_!{`{lEsWlU]^|iF]MiY"¾- h,U:K ɽwߴMetvf`%Q !f?]q endstream endobj 128 0 obj <>/Filter/FlateDecode/Height 120/Length 818/Subtype/Image/Type/XObject/Width 120>>stream xˎ ׫_= qP*(G             oyq-hS}lܖ!;dYrߍǪ|m!:bOzwnj}߼~ܳMjhNn{2}-O2彽\Gr%$:{s6U=S^ҷ4F6KKrң{JBt4VV$F=\VsXxr=Cxo*NZs{w̜ڞDGC>/Filter/FlateDecode/Height 428/Length 48071/SMask 130 0 R/Subtype/Image/Type/XObject/Width 1495>>stream xy|T?Ϲ3 , ֺP+.[-tѺ*m}$@2I%k+>v3Vkm;ʢLH =?nn3m&0ssLf9 @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHtXNtI` 0NtK, Ϋd۠Y   '""Ot؟4z #j`88M( "", yIt( Jt&enQ"0 CDD] (Y&C@4 P!1Gz h{!(7r^h!<!((n-ZB"321Tbo!>> ,Bգx hBzE^RzPF/ n/(p9J}x]>//zBJҞ.ԓ-|^esRV>𖻣,ỉrJXr;#DX ԸnrSsɔ"Ld{)Wϴ"0=R0nQo#4-=*M:Sb]>6! c)V%SMmu Q s4fw:CVk-ncՕL.ŏ3(&UASa([ [.kKXi=e) ͚ 5 KX!3;B{f-Pa "*ۅzɚu !֙fTIk(qT%+T`Yk,}b£-[ d[n tF~k^@ "}O@)j G#e̋JP:FTQiko&S:əzaq3BHhmJ,t˔嚟/=S?ŏBȳ OImFy:LĚQ•(0 x!RG3QB`0;!04f/&Lc@[?06 X/ 8r]`ADDDY"YԤ0$*3[&LX&h8&"-pM5jkyiⳎ񹅈 KHHv1©a^dvzQjNqQ$""əfܘ'h(nim(3`-̏@l|G IZ/ J*)82HhLJZdr%0D/ aL1 1vY0t߼|sst@!bp0,3y :B #䏾TSc;1^XqCiQ:z8󶈈G1 CD_+zeec$/Z"O'΋Y~&Ph*/<0!{]LF!^\ d0]C/ z^/fmh/t!"""""!];ʧx""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""I){,BX nD:oq3"""J  %!)%1Y4iNA-n@ҪIt(e(nLu0DDSF,*<\T{+X?Dd֋n X,?BDD&9&!`ysޔ ".Co=8#g$ŧ¤$s@N)$@aHwzKV~\!ǤVIPR_xP6O=&ņ5RJ< @B d@ZPU[`ZW BV$\XBԶט4U]BhBȭ[ZgRs*p/QjjuU""$!"ד)ڗ T<̢zK7zB |-.;R lj"Bo!cT&xfn\*=? @5`vZIiLB{FIxl* ۾]C UJ4 9QuM$Tr5|N?>R9NM@Hz endsN4%_̔(#hE vbeZc~)# < @ղ'uB ƳhQ{ EQjpt}Bʶ'>ADzh$$Q#@Wf P,p$l(7[."S2(Z G~%USy-=U@s\^;1ӪXgVэ^Jg gU.c֋\krS K/ t9ŝKiDhE6exZoU"[gwJmYm@f~[!jk\:֜LJHN?V*UoS0DpFIYrk~̚C@+p"k Fn Oju*ӷ@iAX'Hk @^?8Suo2S/$ 0Yh-~S/#DyWz M8ѹjw̉F› 0ni]Һ--]Xm2`uwB46%A@"ކ3(u cY>w\$}J"yZ Lտ-\Kf9S!l3`|=BL1 tt*%@<\(sɖҮCT:ȔHvipko/KqwoY\'uT^QۤНQ%J>_mD̈ JK۷A46 !PĀ=U✑ _ @\' .eDRJ}Dki/}J:xGՎr\-RU"2D֞СI }R!jbƌ$d0}o=Қ!{novn_a>68, !kV4r;H5( ףV=< `xkkܜ!İǬ 6R8jƙBK~|9Q<0vGh!re*׹^CD0ҸGR|GRj~JQ*-@:AcΎ-~9r|4DL) 69'epul6RヮsM ۅRbη]4Ӳ>pd(Rږ0uUC6Fo7dՖ hm=B;-Z&ȯN!_ {*P⃖%( Ÿ '~0gwJ^,LAIZD Ctgwea%TK(_m48+&ZAmθi$/|UR6HHGyIچߒ""lWSeb[9/|a<QIDDM< :Ɩ(qkcA=njsBm+ȘP-B Hm߫N13Hn;yB>S-k:zam.gytljs](iHx7UOsQupP0G-#!&W4bJ UF<6xlHHUJQȍ>rK?{F FU.C]G҈l{5?J s 4+7")!e8)"0]m0XM_`4Z cIa?x eY?'M*ÿzR|it1Dpu^""I:M >x xh݆G mZ8L^CZ6~u-x^rUjuy`"8W_̈r pnr?2Tmse~/b!]H'YQ8v6UdجÑ @@/"i]yřmq}>_aVMGRUDi8׷@^cL^HH45T^dae`tptn4gك{ۚWZ3Ñq&ŨalX@jy(TZ X jyřB6K UA7e]\wG1FU]-E' @BMUVE ;|pT%$ZR6Ki fm=kQÔ*yƴ-n5-s }QSQ!f~DS%Q]fCG0JBEzcSbX(t kP׶#_ɩI`KpKQ^1EjUmnm @_3Y;U-`"#V{>-m#D[ 3>ў1x᝿(,z*b^NVXj@il-]PUI&fe B>q1_,SZ ԺZSFɟ>@uK8;#(J *\W֭wUZ}\6)1~^q @h`6)"SߘU?Tg1>R foJ8}HW?i7 }3WK^hʀJ hX Ӌ2BW&`P x )jQ Adn "FjZ 7m00}T(޷@V=m[t|dÇU"JS[wNDmVH ѻ#KH@ mEa31| (޸C HdXRv6vzu\JmٔiKL=>s:*:)$@K϶"jV4)`lĵ]rW`:JnZ\ϥ]%]b1̤B̍?|smvy)ĩ3 @J*hp$%Qۂs,+D Q_61'Qw5q)sH{bL=Ϋә^{f[VKTÈw1vg>$(=.#$q(\eChi1b ZZEJLL?׮(Xܻؾ UG͕PT8+xQXF+@^Pcw7Gea ?8ǁNs7Ĕ7|"""$ڶ7R=6xZbY2Ҍ(C i΃ƪ؞w -|tq7o*Z2Eq“VMڴC)! mg̎9uM+qKJ|RBڪ1wU=Q[lύ*!!d֞l %\fa^P6nQnE/Q["""J;z;B JjV4ܜ86 D8=VB6)J,<6%g|>PF Draӆ5Za///Ph- /k]D~G @+;jssA*O› -`C/CD#u0DDDD$ߏpXKXDԦ@@)Jim2wٔZJ+orI=bD`$2 lF}7-R @rx|yE6fMЊVnh;;egԢm? r@j$(BYw#;$uh+r_'ؠ(]ѩUl@R%ʀc78:8v5Զ"`;;jsrI}D*DDxSξjm>="J´/Fv} ?_F?ۣ k 3w>۳~x`qO,#`p!t;BfS'3xb~_~~aǝ8YiYFmrg36k 547k蟕笭|w1C=iəid ؝6P%y}p.gxfEmmD`} M+ ڰVQK@[fሔP+ⶥ\ml?gow5 ܷySX=B+Y\y>]#U yT V="J´o{ `V^?k{<8oE>.|Dnmɮg/nXm>8a豫.{O0 5W1g^l<:0wн=:lov_u|i GVۓ\}Q] @+PT=4y/4Q#̽*UU.^he67KXqa~Å7[k PUDv`X;[;ܞar=yCFf| ȧ tB #=Ԟ (I25^_Fð kNs1n;jsҞ>UKw2CDIY^OWџpGfkZ{}oU^<뵍/e aϺp˾߿G뷿}ߞ3%qҎmY_μc_T({-u,!/{[_Q?iKokÑև&J}>#Y[l5*Ji{{H1n_lQeځF U󑡯)܏mi/*#P|ym nBp3`aYJҗshK%Y(=z̍u1.5|>Tb.>c3o VU/^k߭##ʇ}ݧ??q ӺQ@J=q, =(mUm5 X/!T=K}6gۋrv^4^QIݱ0E{Hd]J} : ۣ2_.}>a_aGO=Sm8/lxrxw[ZUEgl+u]X ̍rJc}-mݎ%$ ̉rJ[X~H%frT^jL%b`٦ G,^3LD""Y9i %ۚZ|sFLl- 3p;C 9ֶgw 3~΃CC{~z|dǶJӢ ڣF5`b}4[=PX sbP8ܔH2:AM#p;0-=1zz %-n!'Hv@oDDDGfa~5h O6LS̼gb-iǜn>2mۦ펑Ѳ0FvfԀ1Bs̴Ey%"r ? YO1Rk%J`Bk F|@y&UZW{7YCg 9(hEcDQg/ @-*`5DQ#7Iuaz=2d/Ya5mZf$ې"l"J)Olcl sŖ(oKҿ]/4ɹ4PM!$$6̋JPؑ)J!*p a4媴^dX܌Қ֋*ӅRR3'*Ju?DDD$utl]hHڝ{.{D[X7~߯ }Ñ8;}꟮.AOp,AIdZ%@đ0694HXWE'RX  R0 @/0:M p[~LS2k@5uX Lc^l!"n@^hj`b*69 ,V^w&Dvy1M0 "",Lo-磡5΃]kܠS;j 7;BY8~gm5[\r`sw%^CXئk2bT,зp_p`fXO Z? adlid>`ۤOcy|1{G/w̚ Zo-/ j0RX ," %g$/6l}0`L?sq-9ק~n' q)6M8}my Q*pk3n̓t4J]~ Hw$/4M,MnM\<:&b3yaHt[\^DPQ~- `uPkbÈ( 0 Ӿ~ҳ?jlFm?Ѻ%*{o/~zL )El:h~]})iYj(MD712(wYi87L ʍ#&~iYgB3uh>G:}Swx })sG)?/f_1 >E(?GnhMnՕkT PT=ks^smn:++-ce敜w+{֊o݇?U)Օm};z[__}wE LH^DO0(4BgνJ Bn/fzP[%z1mh/t!""ua<'<ĚYPcŗT]n@nFWG/UK xڭ\~ճ΍>3)ҿžgхc/9~ڝ/}#hw=W4z~P!-_ %z(@_Wz{:]gyIq27q2{Q$%x2aȱ^s> L˜r1C&{z8)o]{)Wf# i)񃎾Gq~U]wȓr3sO=^.yc-?Z=;"D<:a)[k̺nlmx't_OErvۧ{e0vXww|RuD`]u;#|iݒ.ǝpFR|ҲNsZ[G?r=n|i;>folz@ ;534oXb@7sk=O~SƟNa#"""""" fa&9=/+y_}'q^O}v!""""""h. y~ó?;5|('#7?z|ׅ!""""", }eˁ/|=.lHK6nSxd[-!""""", ho7 0ßt/faPynuD7 if& DT5$QP60"ݗ`ShSMA-n@ҪItz IYnQgLdT*w,D0ԁy{ ϧh%/Q֋n X,?B~:Jԅ\ʞ[ [_MDɊPJ00)I))\~Po=S  +h&4`^{h^GUWE1i7"Uo`A{1 eoѱI7}FU?JYOt>L~ 8̀h|@@"t__^omyFDIY6ZylḜD"z`мa bx,Lj+ 8x+싙_Г/fW;D9xB4vsn,1Cʋxcۓdv=Ӄ] /sp#8 s7?81}5_5x/g)cNs-V^d @1zS9WYiY]|_kY|ܲosNj|w|'x}zA=F6I~X<@&0J@u;E2!`[YnGbp f/!VDӱvor{C둆(%S/)j9`׶zYx!<%Hok?y)߸iF|'δÞ[̏J{'] '{Ot+mGζ1H$ ZB b:%h1}/j* !܆<Ǿ,j`[wߨ!(Ra3 {U.a-̵(k^H}~>B(bڥ;^;)Z?ur<Y6<.i7pPpEc|¸ esUF2˖YCzA1 a,.}k Ehn-o3rV '=8n Ƹ`_Χ{GȆk1 =\ܐUo`ck  5֞:# |g㆟0<0hKEk[Dhl=vYyyyѨR2C|iWF}ixkRm0t_:n~)t<ѧDm`L?1Q2/Kٵp`HS2BK87Z`z?bFgR`[E[jS!vlcrܦrL0-o,[<녲bir&訁Khn66(),L}AUvwvQ_;WL7Gtˁͣq9Wz]~[Usy xE s;Bi2v^矽a C]u٣_~G?8קGޣΙxz4{>b4K{UuvQ\@y-Xն72W>mf`{/{tٮLKe??}uu~~9hֹfe {o ux/[ ,f:sP}nCTR0ZUnG&ƈnص#,l!ǣ46TBM.l>^ؚHP4Eڇ_̴\LE/\Rx5{sK-~'7 76ZGy;:= h^ryOyL..14~Z r>OWZ~ȁ/w6>ŷ~s[mk٤3F3zmLnfm~vA\G ㆟`:Vk_S\3OHW^'OKl:x]g|ƺcOS447,_\cnkҶnҬd4SQ3E#uc˟ ( C1Nb|pKӁS=B^˜ĿuL )C)2-GDi]X3I.̷s^zέO@rgW2s>#Y[VulUϭ}5꽅3V;;Oۣ󟚝W$K|onzP}SO||MYyEb_L=;C_uU5ًSwC{֎lEX+fZϽ_HOQoDĬm&Qr53\O}Uu~᭟P%s*r]g.XrIs3_7Я8v}d}hm~ןUuVzw8E=V_FK bܙz&ڹXLm'|'vg_^??yJ\h8<0bwoՔ˾y.u; $G.ܱQ<4(_޶ê_}{qCs}?> Y91hLJ/k5fe\Zn<;e;v[Sko>uFLlYajL=έ:SqG|}cNw_lKDDDDD=$dJfLQYyõznH]PSU-o90Ftˆξ%g/T>3/?PcN25^pȦ}iw*W̼nk¢8&muMNFvH`haAn!Q\Auz-'@H4dz%ZhwI1f#Gm9y^jK7³>?wt߽kYlghGv/2dg?ҙlKGsyW4]u(BQL.@u%P*Rct[bmb68oի"ޠofaFhwe;dˁƒ"wpk;phk p=ŧn7~ҸvǝiސC;\9|+Fɜ~=POwjXވj#b""""\L.Pҥq+pnb0B5cQn(zJz`ۻFFl[mCfl+'_1\HKggv~^Owjq/lxn5S|G7uU0OQΊ/DDIot/MA_f[ut7#}5Aty Ƥ<|~}Z;js5nQ"jϞw>Ě=9늇!""PO_J)TCpu=6ŠrooM t? @sz9fD`O~.9)GOpڝ3O=a䤏7/Gz9fgݗNygS|מq/W?e߼h]SݒmO=POwj˖,Z6Ϩ<QݍXNt(Q WTPZtԒ #:b=¸皈R [|5z{v?[o5^!w\o}n??~7>-/?zy9N6o(q["-^smn:++-gڜ \PoNbc?}[k(2[=W~Q&Y_3njPʉ=H(qXϟ+jfg-ڄ_99 ;OG/UЁ?}YYG\'-\3<7[5 \~ճmA;jsuׯ~XG]8֯7Q#_XyXc(nP7DDԮ~paDl/zuև7V_WdלyV8˟qnpK㿮eZq???]ռ3ܵ,y?o߰{v|o:~tGmN~e^tw˞f˖_hǏݳ.;=g')Z>zcknL5nI2+D{Vu#6c0? h6)]U!iZm S8uh3fRx8'mzPJda\]U|H?>R\$5ŕtmg*r1ܭ/idq)ߋ!1Bۋ@l(8=L)P4RiD`z'b/JAڣGR0u눘xC8B?E@rSpj`㠡0!Z˘OwS lpW+:Y-ym%PiDIDD5\)1ئo%˚C)RjVZOYh mÑfMٚT ZM%P,wM3;B{f-`"*ۅzɚu !ֹDDjr`I`P;X%fa(ugwd4+T`YX?b£-[ d[n tF~k^@ " bJ^hqn2M!TS-?)c^Wjց6GJk/\C6I\֋ 돛BGnS"f?zKqOdIMC,z&dCB9#WWMMmFy:LĚQ•(0 x!RG3QB`0;!04f/&Lc?06L_z!:/Q'Zhzr*W%$, 4fa,Lj~Je+3[Eg F4W8ۦؚtciⳎ񹅈 KHHv?T8>E3!ËÎ\/T0J)YȚ֤^M2G\z\F/ 4~aDPAVX3f;(ݎI&z fa(1 faRk ? eb,(K\\EKa8Wܨhۇ dD53eVTnW܎F ★yD7zLб?dě0Bzfaz CDJFdH^oo^>&@^"F Xgy\S0?S#L1xҢ`:zxҏ[D^.z[w\ZoAި(0 CD_+aZV6F(%~b=DgCcl¹׵Y aB@5rJbi;*aTƣW%e_]?ZnϏY,^iz"x6qKDArF%'H""idxODD=̹:FG,Η@RJc}8j0t  h :Qg1 C)Y"""s#/fpDLG@D'@DDDDD9ˮM ] :#"JJQ'$$bU9r >%+HIDDDD Ӄ󏼸 h(I1 C)Y""""""1=S5?RӒS^& DD ?Qh{$ Otc4Kf@pF%)KDX/zG)e0#m[$~DW@(Ot.F[%q "Y"LWyJAdMM@7$0-dz·+D!"Zb\J vEIu$8@#~amPȊ[DCoT?& t$=ʆ2z29nT/fJyFۢnv;EKUx2(-kl&* 5C둆(%Syށ/)j9Ar7O2trҐϤ$,5vnӀ0 hFOP &Dkǧ$]bK"4Vk= }q-𪩀2(ErD Iu8 C}kZ[/fT]e.g%ADDqYa=XH=ZOi6YdM(-7Қœ V0(L؄uR`:zqXnnq,|o$~ z!f`Bk4z!!ʣ|&!"nڋmYOT=(}k %+TPǻ|KZ'[nrRG_փgSo+y`>ܨozh2nCGxۄ%;=Uweo䕥2,2U p,,EAu"AXH(3qBJLQsC!%y ֒WՒ]wfzSSU]/ӿt>TuOrPNY$Өw zi0 /Y]0"иO(fȌr:gg$AB5`5RIL3*AjF*G^ ?9n)ZT;-h%Vgshx?T(VY ?pS* !>W)sW﵈.EaD5Ea6SWJNښ]Crه'ۺ~jR#VjP6m)rly+v7.gy++9{>޵nQ^z#,<;u!5T޴/t\]Ɨ|pv@#tY4Q~i+S:͎ թ]mpwǑ$8jZ).Z_)#"KQimDr0Ϩ60v81q{! s\+iDQ )^2wWw;n}{!U,2%xpb1 -Y%Y}{rq> /wǏx:!I&|ϵ ~&[q nkYx<7͎.M9Oº "*n%2JqfDK쇈H#EaDDDDDd&(X/5DdUiFI9JK~+5CJDDcaDDDDduƮxbƬW1x lp2 !b }c_^_J?\\f|1ԳjZDGQYew@4b1c@# H ZDDDDDDN,N*cEDV0""""@}4E:[n*E9YjYl⤡jLrKa򔈬<EDDDDd&58KGIIA H]{ 7͐,<"""""2(b/e/7_TDDI"G,{9">"'6 ߈6EaDtq#,&6m [VR)͊JRFDZSַͤ Yiӥ_Fqm 1yi@ _lфŽ h!HaBiD150VvM(բ Sew 9[|"4Q_ kM/ #-K'6b+.nG[qvĭ9mF"4\6Ճ!E´Ӧ8K.@ g !x1RC} ooxɥcjCJBK݊µ41V|mT.Q\ªaUA"58ve0lpA[DdM.ȃAY+X Dc;OD5xQbu?WyɥR#y[k|`a7Q2嗟w˕7NQZJQaxbu_R7DDҌ$.UfЌ\&pp\_gԇR" F1<~` Mc0RV\xԄߊsýQ0|K3lxDDNeQz+Aml>gՆ{r4<8V2~ I2idJNY6MaHKUoMX).k{ߢȥ&?SuaQ>yw؊rPi+;o;jŋY|| ) S;?>37:pC i,‹B?_KDZEnJQiH{sD G9D٦?F&|bnhoK[AefH)lʱ[Ji+dy(#YM&I&( ӆQF_vdaN5qt(׶RGew@DZPFDZSf3a2 XMkp)45k5헾*])?2gKQ))5kbV7URTLRފ[Àr##ehU,; WxgY= #""cU>Kq_;wARCi! G">aNK-uc.Z)Pt4Q.tӲ;*!+T~jBDd5sm1'#"4FDZӟ6Vm`1,˗YQj}.Oȼ!W\SCpe&FߊܺS(6㷢Xjhv,0;QiZzSl׭7/c2PyM3)6KKG%)ہAzpk-%&"֬@l!`+oQ3O#~/-fk-x$/-(l؊adoل ?O 0KSzӎ0~W.89KYS,F"),\Sox"" 6Yd졺iJ H *""'34&DDeYy`xg($Yvgi4SDDDDDDDd>̓/-""k%^vDDDDDd= WG\vg<]vODDD-kpi\BDDV󊈈,%Y0"i< wܿ>ɽoXY3ٰXCU.goj\sp ܀{}6FƲ; sqcXYlew@J݃ Gi1dAQck7c,V4T""@Qi0(b:ι0cI@,JmbSHi"kByEDd~x> ~/|]GaM<:oŇSk!x>8}j{~cSrru>t(Y}PROm]CgK.E.'(&Ҙs5OD~M&60Kͣ/ ]ĈiovDHwӁoDpÿNdUDZSf3M T%E.&\MOG,%clߟMv&08o;Vd-|^{<:Kcr""3QF6UOS,կ?]n&#|s P!{I0&zu/i6حG7t߯{R.6Mo ?r+pC-ߠ@)+F/S,Ȧ*CkLrZznBUB0QiQ2 `Jy]—`\$fpRyɃّKV|4&>Rc)xKL~m]SIP,"x-g!^8?zPFDDduQK0ïyK"x& >7|U(_s)@  :nC_ިTeV9xGekp}xp px$ñ&.) "K;ཥ#FȪI6C_;xVg Џ~Ï#nGFr>GTRn#^ urbdUS'=KiQ(HÑWn26SOȱwCe:eOi&ɦ1K \o\Dd֔w3E1JdOBy\q~nB<|Wz[/p TӌbJA&WW4;V 7U> &ql4[v,JȚlew@D*`DDDDDD֔0""""""""("( #"""""""ˆn^v|}nYEaDd -hWŠ#Y UDDDd14FDDDDDDDdYEaDDDDDDDD!YvDDDDDd-yV*JuID(Ȋ>V!۷xˆ2-MDe_Dd]GDDDDDf1&ی>>GDVN""""8QNfcg}g3[;_Uz+@93w Kd-hjqL""'3ߣ"֔WDDd2""e:*SG教eMϑ"2_:ԛxlGWa&dAka _`{#T.t/"zZ! K9+ ";O YA}Qlḙg}ɔi],"t/"|a#U#"RDG'];bh.kXDs%}/(SFJ"V0sy""+h5΁DeaaێuYII}lp.l:!EYӉSDVTtzQ`"3[_쒈HٌQ㖌C ;)1ܸɺ*+"U~Kr/*2igѰ0FȆ[0dDD9 St8bRsf%㚕J0WQiob1:Ȋ% cd Ҿ6ŐA0fD̈c1n;]\NCBq) 㹱uSʍ[Vg=khǕ v2 <Db$9LJ`EhȚvMED,=sh G%D oyM1#R>[FodF?22c?uR)]J左t3@>X)x1k^K\";*?d)FS)w#٪I:yH;>XzPK1GD Nɯjїā _"2GV8[fk?l5+[TV$ 9*987TY`pT0xxց2xxmrmE7BgKx;5$OIm*Yq0*RF:yqo`cxM ;9Fn8o#-%pN=9ݷx) 8ZKŜ|WjE,8hi#F70F=aR!0%H|y)e4+ƭ>QŘDapO33DaF1][v\̓*ab%+U$Dp 8,үEdc)iN霢RN"kaI.;[, ߈IO1ё-'8jiP.GJ?^N)}\8Zv%8QVTP8||zb=t1o*q8qo4ȅ 9dih"r4CDDcӅ4HDQ^|3 |R5TͫGU ['+>f74;~vtbKn gV"~ 涄#W+5A@$*r&[MI#p&EPIDIYkDD Y:qˈb>#JV `I=IifP3~$$qGiG.-62JsN3L?#Ņ+x3r^W$AUXF7Lze)BȺ\އșQ EӑЉFd0/̹'*%j)S딢0b.Td 9G@FBNe#_Hh$$ta(Li_?xR~_;|(̤v-?ez3]#GBq&"h0@F:+/>{udqbH%)yʖqKy0aȱB%kXaZYfIF7G}w,T$"KZJC "¦j^d׸AړH3̰>[ c3^ (Cz-%w.&[.'/Ӯ3)6q9Զ47KN* tr,!Y{Åf7c:Ȋ%1rx yED,caT5Ə_0 dWŲ;Yá]0x10((!*r66ԙ׌b0ƊUWbG>3))ݔ^J׸olO$"\#"2bRftPr>1dƕ̐Ő+9[Ƹ/ۧҭ|<*$̥N*3RTe~gWaUJ߶Sl.东=HfGM}H_{vٙN>dnY0@duVYW. CUm`؄W\ӶYe ecƘQ00`Y)yM7vg(0r>ܓʥ~7_v5uK`$e0sS&˲b}5}ɲh&[c1"f89􌛌;^J/+4P^99_3blgm̼IEx(%R>g ;aet qWvQ"xvۍ }WKR<[2W#JMbb mgƾr(6|rzb}tGa|`n/xȏxeEDVEdíZ,f#"RvKǔm\5Al6Y*䬥.&v\+,ԭd\8t8tKu&?,˜vg”"2ŏ!DUTSL)*$j?}.6Wl?Kxʧ (†jOY)SeeMu(2rѯx 1qy䂏8 k$1EΑlb^UòA׊(FC0o?aʒ:phEDzT)pMh#QdX)8=a,_*Ŀ&/&|{4-ZSDkqgKDeYѵLO^4R4We~htEy ,3mK-N؍{w)v Tq s~lXR_"2Uү,4RODdMJC Ѧ9_1}Fh&ew@DDDDD,+o@Y_ˆlj)9mˤ|D&"kMQ2ژ2"""'sH"")sĘl#btӁHDdU/dun6V! }iO3DD6]9J42Jm?f,&"EQ]6S,FD'uuJz%"2jƩWW""N"""k@DDDD+Zvc5;9uA""@8!q$"Rq;)q1w8-\ 9+VuG- >[gX ZSVXti:#"R~y.'~+aܛc)^2fb}c_8܃?80 ll e),Y Y)OIZndſ6ٌ/Խv$%RHc1>5(\8'S΍yǍrIe,/"3 XL,f) $]2v>;i0""Wuc[R,b&`ut5t3R^Sk2z[}݉2mIwleltW,2)c61݌=l 5Łq kkb\ A_ԕM]I5oYʶg;Z|N?;oBT,'dܚq6\3bvk4lvJ^=҆K+O5U^*᭵3*9z3lK0J.EOpIL݌>}NزDcv28\RJQma'+v)u[J%9I227L]$"t*2b!Bhe5Ld-8V9Jfd[՗d/6FgL*w9r駀{R. 9X#VnFZ] kf9B8H0d)*w5 ªJy_QFK HdEUDDiKse,,Q?$%%aMC(r#80=1MS`Q|<ज़e|W %0,oCol0bF#bY8ĆD'+Ey h`!FãYнbdkR`0lddP}AdE}Ek񐟻2aCK #FߚcFxs㹑z F'D倘A HdE8bVes~9f( #Ǒq{UF" GKÍqQE%GEq?Bw\6ȸf->RAJn/&9l)2k=qsX~kb}v8`”Ü#$*}-u\i(AF/|?=qcq(M\Yj]$R&^+W9EDڜDDV3ŁՕvG^caQ=BUpv WLpcvcJ?+5/V;*`B=8ΧWF'RR2;I48=I%L=1QuoG\(Y?൑?kxs8:UÝ; <sp#vȪee\tR52XO1է3>6x"-MN, D|@K,eA&8^hwL.&OM0UIyhrv'RzWSWprvLئqݲ݌k`0riy|HN44Y#h"fqtؑ]&%dihX(I^q>:q餤!ꚎTJY6&?~2ߌ-|6xHU[6iLnv\fc=,LOQ0~e$$cNWo2.Y#lmq1""MVY\HDDFLIJ ⌦V6FY-ON1z`ujB<)K-6xM4DU+8Wq@S/*-F32nRꎤ^WHDΌY)K?BnŸKE zF|? R})][1=ìn 㾢ő;q؅W iZ{`C0 }qwnQuWNuaRGSSl{5_Nxm)de>jlHDΌ/"tK9B,"kd0ceF5y>%$.wx_ooTǎq\, rlխtfE$)ƅgsHa4঑25sG?B%EZߒώے:qSzp(۬Hdf9""R#<iKDV caH C,BRS G8O.>evPi`BjOq1ӑ8WgXJ׸0S3Йme&~pFEmVF׏Er("/{r$ 2ҖJ{N1."tEXǎsqj%,:SUEJ4C>Et>Y :t: 8y{$F8 AܰR0a݋鴼N8#bwԭ8g#GL)EX|:ƕ(&)FĔO1qaÓG1qxq,#tʟS6Q73lhƐD/M)wUZ[DdvҫGàofcuIUG _OQc, q\d`\smS,,B4^%8xIocp +g/d13PWg]tG;c!1R~-ܮ>}7sZӯLa=:`ц_"2gZn""r]Мi[CFQFDdRUDDN`Xa[Dd:)\D|NYҪGDJG'M""rrljg안j """"rt-"骱DD R'U""Ny :^D9`\&"OQbȭ[S/YZ""㍉},쀩g"^tt+{Ӡ1 TsY,} uzY UENY镖~ԧNL"kA""2yMȴ6X!s[gX֌bЇKob"AGح1v2RJ71w8Ynd { LKkEdC0n fXt~ ky 0)Hnܛ oSFD]DbƉMy|̝f$-.SHyp1@ܭ*gAyV(F !QDȲ0p <>,RLDžYzJ=Dp }8u￈|-XDaJ^ZJdg.REDdV@Y ' ct3RFk}kt[ꞽЧMYHkdtJ.It㾱hk&u^Ɩ=vsXvVʶћaW{ޯV[cf.j{FW6=IeRzOQ]>"Eצ""2G+;o2Χ\gx͠-;120\K$D2FVey܀%x|0J. r33nmO›&SĚK쥃pq(ս_ qyQZ btaXzb+.]n$Qv {l)b6nHD4i[^0Xlp1,#3>[9jqlmC>hq S )=)[s83Ky(M۠3AOiVwr ,Z,Kfa [gufƨYln%n}߁E)iѺAtڿ vo^޽a,#/uDB8E(u_"" R% g+ jp1;%\p8e<1C1tpf`9'usn`iqs,]LQQQD,^(o#"_dpAp `? (0?'cI$aZq$ ƶKwCNjc`W}Hqi+EUN( %c,A")y)G H%! {>ܓ|8+ք:9Im{) APC7,'ZSEDDk)_DdlRpvAo!:l<>a4 u<ܓGհNĝHKÉ:DMvqj_m2qUc⌛iwpC9.BWWp?(%$'43@&"kE}Ze=0`\gs, 8{pgi"Zxe]Oza Ӛ R5 g{tSǛK<¢bdJ9I׿8oܷ]5g2f6q̰:# 6۲Zp6GDd.u4c^y7OwHt\̖v&-FTYc\y6`8EBg# 75w'r:UV7 {7T&-ޱq~?㫚v.ZņWC2iM[@gΌߺoYJXDY/SGabrs`>`)7b3El@Let3WVqPdlMyaletݸE!b Jb]&}v `}_4:75팾%?3K)"\]e0JN9*sv<;iw"kppgA/޺ΈYV`4<%xHpIHjO\  w=pq%lJ<'5ƽOF2:IFv ?vu˱s+@6aMؙ1d.~ziuOAm+^>غOn.Tv;gc3i,Rr_[)"~EdUͲFRshV%|X!K82yɎqA:s6%5'd W2qxnlX/\oa$sa2U5\pmuR@dDDDdaVðA9ݔ>3nDD `DVbHDDD6k$WHafS~ʸ՝EDDT Y(L8yܦ#l%Y­X  g)/dE&$ :9 +q<&\XWtYս7v3/#""-QaWDDDD4J[DDX v̗.,EDDi̗.)EDD.&L""",ӧ`HeK%0]cϸs}y"t#-'SlRz0863xp5p:Ч놫=3l9aG1>;s;MSNFJqsJDKY'YT1"32Xr_=x!7M|tnZ2ƽ)O ?Y/ˆL޿Ȇ0vReTMKyp1F&vf^g2gp <ܮ=6~Zߴ@^\8P'D%FDf( _L[Y6/-C{s<.k6VD*"mfq7$"2-c]㖺g/ftSzF7,:Ëdlxa)=7)wp1wPJ'(Ip~b@qe^LF/'//UwD_Vc)[ՓB›S6߸AZ~K͸Z4YNɫ竄ȍ.K;*Ba~v?vqW7l#J7<-|r\3\̞2& jDdi,h4MF0:&N۰'0nʰb;pٜrtwet'g7#T5Ti6?$nĆDdh,ƙMb5b F$t\8p}Pp17Ҁ0!=y =1o*B0mTK1*~$=p G. Wzl0i'*tTwPw{C#7خ>gt暝7YDփ0""""CFn=S~Z|)p&{O3'RcEM3ܫwB͵¤A#erֹ 8052J[.J=nbb7X;J"lղr ,"AQ9 "C &O2vR`ex9 G]xp|e\1v8ʱHol(4`BhlݑMY05}~t45팾OE[|M+8>WQRX {Ed=hx^+U=wqs&8-nB<)/q>LqM~j+nSzF^ɷ}_wqs>kLBUnFjǃ# ` K8aߖ;ߴtsU j+ -MH4Z8exgbbǵRz~PD͓ݴbOvJoq{ƕhR;.xt|b Y; #"gBnW=ZH` ^\TDdG #쿉Kܧrpu+TTφo'`])y[ >cLÅ]Q:-*\7YDV0"~㷺~ӹV?xSW$íSlӶ>|iٝ]u[(L?=ߝ݋?) ?]osOߌѳO_WN4W7ݍ:iyavwo;,"820q#Mx V9QFDnξw.^73KՏg%utw=\w_ziRRzm]o??7`7w?vGu;߳_s/>?qsNчk4OOO~%v@5|G'S1O|(i]ysiJDDd>7GB0^W/[bs,{k[&^zTop?5mvc># O5Iٛo/+IpDd5$1a)Y)Y)#lw}\9cF^b""s0"~7d]SOc,k D_FW'b_ح-;\T?oMmdZJ&mogwwvwU;w6 ?}k#T{o(?ْA JDP<9lX;QQ@;=)QDQ8O$l6 g~gyfv7MUbvm-۳>Vv~48rs~5;svI? JJUl,(`wl=q9 muZSқu-]-;-Zݨ4ٴ gDd 5nt[ToWWEIe+;vu%_-Ztia(,[۶;M[EE']UCB[_egզxeKO`[13$T#0JG:OQQ*M r;Bݤ-\T1 I?jd]wT_("6")O>DyE8lha8-}wgW(*ؚh]]AݰQݺUFG, ٰMHٹ+x5w{MN'>gj𮱞9Ć O~K R(RP>}cw;tq {癕ZI6n\CRǰu[`}y+ZBgQ7lLh7o4f NpXx-Pf2z?} PQ;;jQmW9iYnYϬ9qIG).]rpݬYK ϗ닢" uX.6Z[PپG.MDS:myFx4ewAhꚵ /}j&³V.ԍCC~x}?2fݢyr?5b ?{Rog 0?_zɺe<('_? _/TVW<;/Oٶ;sqvJIagZc|s tkறfF33zmZW() C/6 O5#VqN/Ͽ<)19tio93? [fUL%eћG'vӾ\bl~L+ssK}3y[F4_.xk?6:|&?Ɋ?=˲}XӧwUWŁ/D&cc"""_&`DDuٯocqު+W_ w T{L`7o^ɩXfMt^k,xiY;ᩯ8!V6)~h|R3tdɜOWs}³~g'OH<~%rwӾo5dr1s3{~hj?cB?AB__L٭[P6nX,7x?WK?Xsl-Iozml۞Ł Omٯo1g {@ <06%Nly{wKJ|)bS;5PNt'x~5m~]x2򫮨]0`nY+bIvxcuX3%Ҧ([3ʘ={ :ԏ/{j~VPV1 Touˏ6RL_xY%$]eASPv̛_MCݡ=~BWf"ʇM,1I54)HsŴE_d0C.~I1dJI|4O(o}wFJdmꚵ奬㎅@49 &9'QyBG=Y ٸq .~'2RPmX<燮>wuC27'rX'܈~!|HE|S^<$­XJ_qwyП|&%ʠYԄ6=[TcA0 pߟQKv랥˴ Zi2VVN|O||q}'t}fcW^ߪ~@[o;"|F[o/֭WK넬h(-Rw#xq%N,S)wKa3cUU'eu)ٞ&0DTv)F`Ay3sf`_s_=дsV'K}[j+V.R]&{-gótYľbmK.qW}LP7mι`2QEټ?ad&W_YC|94Vل-ڿx~ѾWj,;Ï?7~g]1zhٴ)'LGy Bl|Mp Gnn@{?|48vϧ"Ԏb>ŃQW>d{X ѨI$_klE=o>fH-H7i6S(Ntd%B 31T ,Jǭdu 3e[KЀ!_`yMzp#`H-sUb|{= su@̄Bgav/ZJk @2 FR~5Q8&~nBɇH&6,Z:(y{GWBDaKQZjv/gbNb=a Q<ذK6:!s=Z٧Kzjػ7iWx\k;ն5^gT5*zQdg&J>| aYNj6RO.^qyzEiv4-vɐJI+ OoRru:q]W ʯ:?L>Bѱw ~ؿnѢb[?i BRuꆍ0 'E|'R OK?nn%^¶hN2҂t:D$`b݂RGRW#:(u'*!mf|> 馏w:2(I"LCP(&tp$!-X) l rwgLw eҭk\;/YQ]RXX(@ uFw(/CA٬թcu~rue6ٴx okP]?@yL(/;Seںpju;Eٵ[ٶ]+B,&4ڴ5( e6uV\%ˍOP}(. gkG۝:-[Ԩhn]`uT]Dqucl94i"&>BG(HGT 6)H~b2Oč3\ ]KLXktwICK!T lpa8A!UC^wb A؟.'y ҙ7Qﶯ';+@]yADH+Jnt Č!{@MDDt%0uAj_DgQIJŭӻPHDO2>; T}s'T )4 D.“JHB e2=I R0 VJ(dmPW#qВBT; ۾ʧ7݀NJFJXz&%@'TQ8O(E=w勐4LA4DEABK5$V9&IPݟ3,EOEi53vDD0DThZ2'uvG_۶m;t駟nwj2'dzj5/8Վ@Dp%1H^L$2aID% |fզb.F@5.SӃuȤ{G['UvIZUa2 AEĀO}Gn}@QFMD ε#""""Bv|mQracEC)8~TPRN4xJQ)PSS4Ʌ{܏tgnNrDٌIL{KΛ(-췳VR$j$ii)kq.6͹n,Xjbxū*.T} UQDDCHDDDDT-J2)?Kb LZd90tb+)[n:Fi)ol"c!7% 5[TBտa~2N䘚D FDDDDDT DNv" 2" LG* #*>qrU떂3݀nB&=3^ȔevʥTts,[Н p20DDDDD$&Ҿ&YPNMdAFᕒW"8b5M(b)jGI*,G*t^K@ғ ,tHPUVnFa*0]#MÜ|>[0sg$r,# fՅiAO݀L'Zm"H2>*w)- xepE-;B/18RݽS,&f@X=0%|;;F@p9 KDDDDJ"X*^D`$t+)k'u2D_Yc@vJ"m<>5;/V%BݷP45/[IDDLVuʁ r9WF$+%x"@$v*Ԛ5Q8(@XG@'v;!QZbFLrsD>sa44JdM#hX!*") xiB`DG5IVZDRgIP/"ܣq=h5p `IWahh 4KU2 &9BL LwڈD{ h&0J4;|#Q$ZKL$_{/BzLIDDIDDDDDuRbERE@DDIDDDDDDDDG0DDDDDDDDG0DDDDDDDDG0DDDDDu[b'N] endstream endobj 130 0 obj <>/Filter/FlateDecode/Height 428/Length 37450/Subtype/Image/Type/XObject/Width 1495>>stream xDko3333d2I$I$I$I$I+W\IJ+I$W$I$I$$3I$I2?眝jk{yA@M!E ?;-g"a3 _= ;RV܁;^#m;֟i┏4 %gI~CS;pw$XXwTP$Ơ#uAb :YP$֠#&')=@/ HdɷǺIƺ ȧ0kDu5HdA]GXDu5Hd,u䋓ՀO2 KB Jv,#Hl[b݃rp||<.B3yA NC/aBW|qPןuUa;]@/ u5O* . j=A8)\ лĺ ~hu>* Xw!:? _6b⠮? 0kPןuUa+]@/ΏS?A)_A>3\ |ׯ?A0_8^GX'A0B _'A]Ab Kpϒ]/Eu #hm,aEe>ز ]#g:)9}BOxXzTO/lS%/N%9i>!' jGЋp!Xw A‸=Eٺ64Smi ʊ]2ia!KYQ3,'-.f^@hCBIAۙ _xFR 5#\*ZbrL .S|`D!m!WF;+'8#G\G=7^L7E?TP є^V; [|&6=Rٸ.5jn'|N*AT6i7zU B#|PeX T p4"D)z:e=O^Qp~@*nlϑGbT+Ԁp,P!CRuCqEh$ƕ|% mGA>2~p=N&|o2ThYlR hEQ41gdN~!_.i:rD*,l}>i*5IVXj:e:mBu u=4XwAH¼ s*-!rpp*Wd+_\+z!C_^2nr! )'duU߫DүI `sJ?#ubIZ1'Ɏ ZnNR4t**L0ć 2ƺ/ͼkppp#IZ!XZA$[Z&\<CVЧ9] -SӇ"7^bּ]!-{_VM+=$8D%b`z uڤqY27h Xy$JH`4HE]) %.9Pף_quSA( auhw_^CEZ&Ci AI :}e$gN }^bp싛n"e8ޏ8v)b j[镣fԐ5;w[-3J#eENô_de MJʣ$Eټ[KC6uED.7ǺAl9A[@J)XwA;ASab`AO/      O]#='&uճs$ZwlIQ?i\sճ!Ȼcw*䨟_ uĭے 9~ۭg lj-$tFsC=1o&^urtsse$kZ)`D±{F)`TQN<9ݿNSTt¬o>"}9irC2Z[`uyG} ѬvGuĩvhoY >45461>lܥ _(fM gk=0ur<&grw΂W(SpM~zC~~ybn3nP7D>*ZnnUS^JO3L iynXS>CԀ n GfriHⴓ:Bl&7#׈-|>}zڣzh"N;+;_̏POLt}|GAxn;;ˤn|T>#J5gqit4+e>H:"3}#gF4|g]Gq%Oz;ҌAp]fKA.=KiHD!P`8un/#ԥ.cYLDt Xڴk:sh ",-3DF&-d 4i f1.u1)Mw.bS$K^^+njjT m,{U7B>2Z2UPA4BuO3Ld`S. I~X*4evM7IJHHml+bO礅bA CS- ctƃyG(U߱c8ɅWb BbU[8u]cKΏߌ&%G1וU'>M|]CUsX*VOAg?”ng im{{]SVn__ZK}4GΧu7U]3 tOCsOrch"(Tz=elK垐qC9Ԯ(8ٜ^ út/a<ܲr6+{|2"Kl`Or(Lub9-F/|ͽU nu0<h_=/ȾzF7O2QɳvOz3~VW2"P' ^x$"r\Lׇ_,!u  ݉`D7/|N}֨ZN^"=c٠C`%CYQq)gu=amQ<$l ?]w<j=paRvzKLZg@d N L2~1BepQN{R',/Ct󞡗%9O_G׵Si{T/zО@]o ^kh e`G\ퟴT7YE1>lD݁~ S< [+ ]HOf70A u =I0Fh %z{AVkUo`+x tpw4@lM3Kn+1vhS<]:A_2}Ӏz uz ZU8mPߌa|6>U?ճ. BbM[X> }c~ģ vu, 2Nvya ]Wru?]]\u=ާ{t]Kc:6o&멜< XyrzֱCؽG-FW#nQtfhX4_чR~L3.$̤vgu<^Ru6$]Wz ]Z\HA]3+0ob*wJt]~)sMZE"!"CN*:ǫ Ts{8BS3G" []S1?Y.Yggl[N[TV EZX Qz'i9u1hAėu#H@]34BuW`௯l9&``D!mAwWNpPY>PC*Ec}azlJxzzdM|C\OM_%>!<S |ET[ #|>5`>kq% HTA]3R9THUi.Sq9M+I9xK@>[8 ķ$"®YYPLFO3\yQ"R#xki C e2&5Q_BbEZ&Cc\6lGGW?Dy_PNmK| rlRfXqe_iPUqdWM; ӿu;GɊqiWiиYy|ܼ[KC6uE0&@]Gy - 1PA> uA: uAs @]G\{z|`P?`YG8@ŗŬn|Pߌ#֧.r9^yTz8֧˔=gyH08_\({=QBtu=4?Py]pڂ{.1~P!/S:kYs=gY]LwA"]f퓊VV.͡f〯p+&_CR['ɏ#B!kћy 4LJ%#R!;Rtu=+S]q7}|8slm,-O<5+ZP׿ \6ٜ.u1=b%$:̧Sd8ulх94Ii`ut왤.u15j6i&SHO1uOi½t3j&%^nTRN=ꔊ~v[kKSc}]MueEYIqaA^nvVFzjJݖ`6ڰUZE?_4GOY*dK:֧& okIK{N!CˇBR< C=GfdcY+]#e,!R@[%:!r9iXFH,ma+&Ȧ3X;B0&+ώ%J͗F~?:TuMx C"ch.I.q -iTz=elK垐qC9Ԯ(8ٜ^ útqTRHb_T:ꍖ TfFz>/>oA$" Å*펑53+'{ ´hP'sy b'Z /ΟnpwGSrFg0'RUx<]Q#]B>}kT)Qq20٠gsʺ&Hd¡Qe.g-l^٨Ś\c;瑧@]3 ΋@\y=) ֔WyO݊o-t* jλ3CYI ޓ{W6xCaP-iM+M^Fk0%X|y tAV**5u~e\34PBCYPeBUM$E]hu%j=9}`=ouA*{UstzB]o0̖DqԞ~G _=l/j5DuzDmTٓK.<M#ȗ_[ًuP!ҮvUv2dsY [@]G/1,e_gsTEc#stQVSmgd:$ #HLH_{5e^-g2hݢҲꚺƦuggWwo?#cS3 K˫k;{SG!0#vќh#ž{[F׃ Q"~=?f7pluLDA@]G(~C D3jZ]ؐb%PCa-%~T~K_gT]D8oX]$KļW<VgT'LpJPLS9y>.G1>Li捉N<-QP.Wf%W`zwa:%e0AݔFļ7bR.]1eٶUVUS3/ S#sK0T@]34BuW`@\*"5S*Cڂ""X=$~X"UXэ'Q٭Ɏ1Ժ>C~I ]ka5@kee-l[[ =V>UDDWCѣB }ADΘyR:}Z%޳B5)z:+E.y/_F#9Gukdf>2n }]4o&Α<6Ax~]lAʸ)=y?.u#?tAh"zbf`u8gdn4Fdk^ yyDm,Ǥnvs9%-\[HE#3D2f|yW Nrd’%f:@ʐg]B]w}k[φԭ"ͣdKdO *̩8zޑ.S!f멘v?k|~z1;u $|`^{UdzS E *&׉A&i6[gbFkHub%&5ں~:I&T"ԇs _5?9ZqzS:Λ*;$eAu\jB%C0Īi0ٚߕ25}(Kٚװ+4~˪idgtiM^R^?|>kf\ PL:7m ~v*Fm18ٞnɸblO^fsڛϸjW2ָ|fq'^Q)δWrBq dGjZFfvN^AaqIYyeUMm}CSsk{;ٹ؀yo&t]h6y\VLA3 $VޓjAd[8 AdP[ؕU9Z"z=9>:\_[Y^759>?z~h֪[3%aςAl9A[@1NHʾYWS]Ifge$mM`I*G:b^:|9:ɦީ#Ɩ| &=KA]G/T0p QBCWA3:_:|9:s QS1CA]G/FF5$$du߸C~|Lĩp}Z5X H4#՗)G(7Za׊{z|`zKT:t= })GV.AGW4yT|znP&D|/uBG_O"oyUPhtْhM;R3rr JJ+kc6u[]%3*r?Gjx ɦBbP AG@>*ʮm5~Qw{~QwgfW66w˫ϳɪilb}rٸKP `BA++Q5A0 ]_+x,"w:q_d1u `V;UxDU iynXS>@OXop92{ZX.iW!SjaȑkKCzڣzh"nʪ>*R7Qu,/WWh驉 Ҩ?ڿ476VWUde8IDɨBEu$Ñ3\˚ٵaY]LwA"]f퓊VV.͡fgR*~$cL0O66GB,LJ%#R!;Rtu=+scu/1VsD]GBWMo 7X,!)e>"{ƩK`.|ϡIJ3d$uQI 7B"|Z-YLǨK]|J] 6T3 ,t= U~ܥ#!eeeK/iR7"+ܠ &藥X:KBR< C=GƲVH&Gʎ bY$C~K6VuB*ӵDailyG(UD>@StmĎ7]3 tOCsOrchAHL)d_(]vNGe<Ԯ$l@-Kx7s/Pud.J]yu$vč0}^}ނ0I trA,S U#/kfWz$$DaZ4˹m1p-VԗOO7zR1Qב/|N}֨S^"=Ҳ8J VAlPb;;d%f&Re.g-lu ΋@\y=) ֔WyO݊U [Tzwg ~t) '.lB ][x:7[E#ς ac2*5u~e\_ҘBEP yeRB&9.N q%n E3O .lcn~Q8Ք/ƈ4nB-)ّGWV745}o{ߑ'-,.on9O\+뇺 G#.~=;f7vapU~|4B׽S'O*GV~|4-TV| 边<>^_]ШG;[k+ˋ s&gw_OZkk*J r390uA$\:E,)BJfMQwrPAES4GL1N/0zz1xOW4L4u$vd=+ROpճ0!п@)ۀ/E [a_EN)niPבbR9f]NQtvV)˶U ?*jvuԌ*I˩u :;Ui %Z",\*Fz`D!mAW0*I ." 1@׮韘M"Mt]aTBⅢ*tSNhR Jo@*XL[ ]Vv|A6+u@kcӀaݡQW i_d˔=w%N9NlChyBp}op'n ]0?j V=!S@>TgŰe=(%_Rukdf>2n R]4/̑<6Ax~]lAʸ)=]e\'*-_т`:~1$~Oxq:6w7f,1C^Q41g@cҀQ;,Q.i:B772Y5"|#?w˻JMp#,1ӐRg?K Sh&Xsz*tޏΒ`gy8][(phYXWaN3gppJ>4;5XOŴ]3d@Ћ٩#jG]N &%Wu<;} \Ġy:1$-f LhMNTW5.EOB1„ Ah>,ꄡ)Q3dg͖Dkݑ_PTRZ^QU][篮0Z3&u}|Vfx,V֢q ))hNcWBHM5aWHiU ~"7ঢ়7_*ʞ4&=MLN_XZ^]?Qw/nn5ZCB_d+˭5뺉\-tRܯ_Owx]. ͓LtXd]ߘc {-\ǜږ@z>fXָ2ӯ4ߪ8+ʦJde M~GGb[KC6uE$ٱDXs,I땺N'~/S)|0>Gণ8= ^e]^vt`aKss y^MuhͳoyO:niTUgDL7uH:Hzt=A* w;tʤyކ;2 чꔜʒw꺭 _}BO ]?2[vD]A!/tu^'?׿uA^%Nɜ Zٚ 58 -mQ ?*Pjp_؅5ցynuzK-  H1DdM-`ߟ/輦-p+xB,R w苺w3]u^7iluAyp=FhtD nt UYne5@'ŊLeܯ#qSM|*u\^b{Y׽bL3 K1-6-`ow5rY/yOׇ "KAZXsex;}ufE]߅D: /C"e/ߏEqE8z_n\69FWtvTE]Or/RJQקb=Qylz^L"8M^qӫyb As h]Uu+:cў@u͕nu]7݊r\{ATb%gWs i8^_L +*h$Xmdܜ:*0'ӈ+pCr#*,ilKhgh~'[އlwIB@;!zqw&+\o q%G LJWGUsD˙으¢ʪֶ4nwO_?G7;pt|r_\]=<|T(:.hݛIYgJ+z><6咕 V[*s #CHn<2]׸B:hrsKaL]^&ߑXu=Yܯ%-OAB}2dxo%éEP]) U7KO^SIuȿ_"ۃcf1; ҈c.x'Ozw$ĭے~Bߗn5d`wlmƜُxWM㚦.u1=b%$:̧S^ {0&).bҒN bj[6H3))tOi½t3j&%^B]/PuJC^]#nHUWŖB j/K9ވpl`Kt"X:Kg~Xެ953lZ!/u9.e ^Rn|NZ(/`Ama+&!ev~c`DWHVBpj}_ËTbV l;~hvɷqh7k!Ζch.I.q -iTz=elK^KwﲻH:o KLsH oalNKr/HaBdyS`d4\|~O !!>bm~zFzb~_M_=kwŕBvG|C3 R|ǴhP'sy .'Z /Οnpu4Z)Hۃ/!ȇ ^t]̵HcO(֨ZDѴ葖,%ⴖplM6(a-.BA)>:t 5ّvHp^DoM9]x෦{zVa@ ;S8ĠKaP=wY}eÎoAn=컶u4uoZ!qVgL%;p5\1r BPT30Mm.Ts2ј*Z g) hheUEDs'&;*] C$mϿAѱŎqb틆l{P q$+𕽍.C%ߞ&pa}? $YS^i VΥ5B/Qh ?w(AY'&%;%4bV=x)zU]g~ Ay.dh9-YewcC! *h4:)jONIq8Ҿ'x =(DU ꍖĤԆe`O`49Sv/6"u]n["\19:2gn*j+ f' f KѷՓN:!Bz`kҗ*A>!DةhϊD\-6?G!oy/[Z(!T}?u <hleJYϒwnm @~V\znMA>#t^qp?ӘHJ0)M4"E4ET ~9b\hc[wN,]wu:o->|W&VUzS"DOHs~gA,!u RH<6Y5A>#m,`~vNnnvfz'E}J´֩ 0xDr' Xe(q ؉*#`*rR8GPD׽%A{Yl?6XdA@ONcW$bhgJHK~eBu =}D PVsdh` `[#6-`K:XOtBu`J``;w7\pykDX ?#,h4/'8A1\7ԌbMe} U+FKcv n@p?,ud(*a j(j/EԛCY ;m)_,h:2MsIMO0N]-nP 8]kt=1d. @>TP=a-90 p]UO4@?}/:_&>Hx`]^_+Aps:e z?]:S)kToc C7:\AH@wuAd}<4@b2G@a tLܜGAtP%=hȇ '3_XG8RuA]bYoF} p.9j ) t1Q *^=#W77%BpL~ coyx)z@sUesBqIùw)zغԋC˺'PG+.O2Ͱ08I=B- '_/@]Rhtw0Bek|2z+GP.t&s{p+-?;VTuEhڞɐT/zО@]oDOj@?̻~/Fg:m1d=oJrĤzu/_26AHFz.|6fVuOfp˺'P-7$A@wu+2ɺ^ 7{IZ< K+{dO|//%]7]K'w z@] ؗa!Dݔ';_ .ڸ$x8̃u}g 3>zB9F ;T@O麖ztO^QDfxDž!4:&:I&__jc\~cr&eoKSgP ]PKǥ!DxB¿0D#aay>"?Yde\Ph Cκ=U3Ŷ#ouQ_!H 4:9mc8 /<=Z'\_:LB(c]oT;4sI FVAkOa)GS!5^9Sy99Xw/ K>*_pYM5M.n_@No4Y6{rJjzFVNn~AQqiYEeuM]}cSK۷?;{~ot|bjzfv~aiyumcs{w'kHY-LYr#xڿIA3\`%f<;f9%}~qu}{rg>s\Etƿ'.qDWbX/u>.qe{yp.F7C+#Qu=ETJc݋ɇŧ%Ϝu> }<\_NLJ{[K 3S [[KscC]MXKppe!(d_XypT/)ZiIQa~^NvfFZ*Ag6tQ^ћ`فu$JS]P ~0_\O)kf<N@5#.㍄,G_'mb]T V&%!j%ٓ)iY9yEE%eU5u M-m߾П#OLNNM_X\ZZ^Y][?8<:vgWAM/>pUb3QhtFr$uJf賕ٮuOEk/!4}ڝ0&*Y)-RJTҶovHRJTҩiYJW$)%J*IKۻSK(Ї̼ f֙gLUpa`ے煱3ICe=~оD)֘}l5F+<=y.f|T2V,4o3r}Zb LJۛˋ3 lomn,/-.7=591>6?Cz{z~u֖ƆښʊҒ‚ܜ7b_(eKK̬ y#2HaLY0 n39+Fo{]oRz{#Iy|DtwG%IJJR,]%F"QJ232RS$͚`1=oyq)5rUFTҜ\UZV.Ew;_rG7*Jյup(g;ѣrsF?ڗ`D3&A[R0Et93Zrnwsgy*>/& mr9kR[zcm*$e)($KRJTRy$ =Lm#FG3%^A]o!:XBuE ^؉^p%{X,^!|~[/qbi[CQR-\dd-kL2lmyAɞ gW(FY7aokynۛ|5z({Q%7JtGM(Q%ZDwF(Qi;zDw.~=Le7Qn,jlx'"^'GϷ॓Kg}̯gV.Zȓj"*Zr/'˫7 9>#{]p.n)ӕ^ۅ/=>*n9KE ҫg[?u Qw'/.olm..oU Gu #VRUY "a\JJLwv^եs;+2J]5FP6rk{80`9<QSP~T׫4Ba-T>^_^OOww6VTZpFjO1ց~f03/P?u<L'1P7̺RNxf׉L|K{ӻ&4 5 ? gC%Oew0zmcQu%2JBqG >v8aK''z*e]tSȺnp Xjwx,(#&xɰJjt;\4>z̃9?8W-xG"l6%Їm[W/]  ҫ^u8~ y8/G˞\׃2D(ܗVEL[Ql:^T:񂅚tz.d QCXx:zZ bE1PBMs )5saRRao~` L.1ey0<-cA]WcCB3ӓ爤XвXg~J8KG|Anj}dQ#6oJz}G_EvPkǶFfAm 9mGpW|{'iF 7l|2Cf@*މI4$9F/Fq/6f͗f^N1K {u} M f"Wa`Ȱ}9=²BlJ? 7̺r= 'rn(6uC]:SBI oKZ=@ nCf7܄$}ŲΩ|dG[1+ ̓64kX3ZEd_9F/Ff{fחfcDNoFNK/pi6?D ?E84e@p~%Z 7z4u]lէjz ZASqb u3Y-doONЗt'{ƨ+^Gx[GM]Z/8K b`"I U! Z؃y5CO\wP*b6ߙ$8n 2wy__AnjPq/ʼn*rw0.\l9639yY"x{pL+Ir<M5oܠ=T,4H`L‘G^B/6ޗfcy^Nחf^NQKCtyy 6Г/K=}b/)'DQ6U7q~F7y9Kp]rSˬGWk.*Tl#_lK_l;[L{cI4XMzKAgt] 8%_tSD[V4*w VW y><ؔYgT^ 8 boi]3Q6k9VyT!9ĤfcQҭm9͆DNqMOjB|/),eg*Hz]VM/Ь'G{;Օ s3SGG~ O]mM TUfgφj]-~#"u]YE_ 6VZ)|rRbUu ;1ڳ }5G:7|!u=.Q]'y6]O D/G:j<H2%P}5ƟoDS%x!O"pUz|7.?gn yvl/}UG4]op.^9ny~]7Ib_ Znxiq|,s %i1=-s >a1ռkTARr~l߃*{"/:ќ`IJIM/(*.-~WC=_!WA?4]1,kcz#~ե86f٘6f6Fy6ͻsJU_BG a*l6rF٨6fWl IiWll CiqfI_Xd̞7<3ֶf=>]\^?8ksw+4NqiYW۾즮bԚ".jRdVduXwIiWb@]7X&%er;ө >OTՐEM Hj+M3#g>)X߾2~RFZN'ۉ.ϐZ=͜Q>=u `>J`|ns .!ɽ:.dV~za'*+̍CUTՀ/ ݪ'Śǚ7?>T(aq&m6vڪ٘6cc27$m6ZZdnxaQ,m62FOBb~.W_ hn_o:ZiꪊҒLkzZJ%ʋTݰ%\ԒS9LV\ ^_d C6VM\TNJܿUbD9 &6X%V%BlϯaٯjҦB]/؀FӍAR5r{PvG :> ܢ#:LOQuJjXR7'-&!,z) ͑F fxwIϰU~ϥct]#XVtu-< +y4YQ>"S^ n:m*靶׈qtzL[چOXP $ 3`RLL.bZ0M|5"F>iْv MiP>DMdOm:]~t=XIzr(/tzz?퐶;FTk-m_|/޹{hx<_ϹU]Ӏ7j|eG,YjUs_xb"ќD. ,%A$D[b*t=XIjHpf.' u64ao,>{*]_*":llgXlM}RػNG|fۗzK>g<v9PfU[Y ƒ%aURvԭ{ec>M€z:IAh e7G < ֔Pg8W4'=S׃aN+*/`[۾=?DuĖ3 RJoP7-Q1n=T,[Tajc8]% t]߀?2}ɘj\{MIX.b4ӣ ) M2 ꩏>u=XIxnn|>Hۦć-lDcFQ J^r륹Jx|v:\-Y[MO׬> 27|-27'_/jKc-%=Nx`b4%$&%eXsȷ. ,'T'\=AIl{,Z*odz\Ϥk[d|u`U^z$PJVb+q[luZ.9d&Ot=YSpuuC0MA1Hy< X(0"6BJkF[R:Sl6 a l6.ƃqTSE+ ڧTEʪwu[;i/}߾9kxtߥյ;G'gW7_@g`|09zxE܈b,έ-=^@%y@!NC/]W%58,9\y+pHc\iw]7NSWlzKi^S.c:~7HKr`zk ,q*X)Hμag2ֈ_D(_% ò)CxE4]W{qRNS|{LGuUq]7}d!$Yi teѵX ^oht ,f9gxۑD@ -#͛|4 UqK]ou})|m#v|5tfHllmfcJl Ҫ-DLq t\y \'xEztUqqGGwq]Njda.u?mV3ԕ͈"򥚦6}RP[=`ίcݳW-m6.ؐ6 f㧴6mfNl7fEnW}5l Fi&l6FhhWi /l6ƶ8:fPzfz^ y@@@~rtcX_]YYwgg&9𽿯O]mM u5Ue%ŅyY֌dK"m0Y~NVu ^$}Zt@ٙ~ ' pLz`?~=4G}aa?6;fceE6f_6f]CfC_a~SXVˆ?3&QqϧqY&X ]T{ #(\!'rTl,IiF*l6jNkRZU)m6Fz0F4`~S`J<+Mo>3DQSk<_u2JrY|OREs$g=QWRi G7b0n?+l0^ ht]UtDr 7<@G;B]Gb2\lj <MdH5@<0/>uRL Fpp#Jք3lx)_o~3>0ro`" ñjxPבpUhe7\n;)#oJf p9}IRvS7KR5N Ƅ<uEiЁysTxF!TD+uZJ0e7vyqKRJjzFfVNn~AQqiyEUM->~..on|7&'5ƮGv oW#VMJL 8f7knOg7w@>;++#%,hF(6fUl|RLjvbBaLCA8ݦ85+˚ES$r YlH\aQ&m6KaEl JIa m66ѱ%6aIu֍ʮc(jfU฻8mm,/o_z>}S`܂ODp ȭnjvƧH4b*~OXlujǦ-lM^ ͝M]F[K~XՕڏutܮ:@\٭HOh*ٚ$wxI%Sc> j^NKaa6fcFlHofKl4P5g}r.7RU@Y:MjP<3ͯwӉ4 [(>r%_eVv~[6-SĖAԣd<_f[ZlI-a(m6Ɛ&F& fBlITaaĿH`{S /rgYS}X9t}-\tw `S5]>C׏OOIDO;At}~=粍q|nAY*tO%$NNg:Udc`;`oWA]}ͯgE% =ϻ.{%\ԒG!Km"WSۇxu2Wdnlp™Eu@<0OPԑKG KJzF&,kFZJAYKpƯ2&oNK]++l53Vy5*b1[xk-Sm@hvnT|ݧjG~zgw ,po:?qt_wEoe&~G(;['6A;1)95-ÚWPX\RVQY]S[WA-c-LK\LE=E j>Ï;YT4ܛ )ʬ#dDq d5+BMQ].3NuūH˲Dj4x7ˎ=Z9 A=᫖!f? Yw.-mln?8:9=;wbvslUM]՟w}UJ*ۺM.oI;ZB \N`w2k`0(/;lOukA+[>uEM|zHymF: Wu]ߔu}'K:ݺUJT_E J S1*fg&9f /7bN?"\ |]+Zr>u}<6'g^c))Ug4T]7%u]Fìػ"7"7| +7| 1j#'`>VW1u𲯑y^ w]?Y >uXX5n3?Dɒ(LbߢzA fQڷ;I.Dc (z0FjRZ^!l6F*l6~ )awQw $sÇfcǷOcY[L[j =Kt!󯊒|\akiw]7ਦ@7ݷC5\廝Nt3eR 7hJW'@: wEa N|5tfBlk"M_bx\$$1\LõQƺHYd+P~Ãɟ58u~Ilz8`uy@McMMI]םRyISR}9DŽŋ+'@%SeSmL>uJiNZT7]WƇ#Su}SRug|t2e6IUQ("QlTIa.l6<{uW77J,aQ\"l6IVa鳰At`Ԥ(:&m6ٹptj os~]\ u n곫3L꤇!,H"E uzܺx|ⶩġI)Qj ou{h>gAbHKsX~Z6}_5T{w A8e#@~Hcpx%Rzuy)HƦҿ fcrbRElt fLl a`-=xc]u!]"HcoI  d }5bl$HF4/]7XmCK$[iʮ 즮bbZtҪz&cFzUW[jeub-a*VFMWYө]5n*4RI3i)IV,Cx$[S\U#[A"k.mQiI 2786㯰٘6ίw3듽&uΙ<+Xȯ@G'vLhRYmZeգBK\kΔEl]OCV_71\אYh0@9{T~Ǝ !Tl\H}aIf*C?Fh6ufTld 丱CDwVo꟦D@8.>؟tF<>]׏ψdJeݣoY վC+WH;"ؙypRxV8sJS/ Vm>_#HFH)*hjيb$B:Ehrc]b:뤢I:Fޭ.FOz`VE8t6l7ϼJ @벷zJ̯N8E5X*LV\;@[ ݜy_F] 6qŦ' }D)awJ}[ו9x`q,)NV9ic]:xb=C+x W /&W#RueNM7ؚ o]S޲'^ɟri0ɶfiO6_CϏ=u}\;6`'հc}U!:$:Y.` 3  \"w]/iO;5*Tߺ)T`>up;|Dc[ +'fL9@{Ҟ"HXHT$u?b%ouN-j⾇æz?] - X%O,cTh}\T%OnıK"{U!:uZ{F+|}>v@׳N­G(l~1VLl<] uhUHwg{U!"uS!lir]p3SJ뺲 r汨I6nӂdx]f]vqEu Qבu=DľW?pt0d~r>lRb(dFT0 ]lkT_.p}Q1]U7LI])MTt]_!:8uź_1qn'z>MC5arxv 0=F_m"Utitԓ{wPVɑ恞*Ry꺾Bu$@]JB~u]Q^5Z]D+׬yK]4W^6<|KфqY.WEnV$8**Rt]W!:XGq S/M(+sψhί+֔&f+ʪ7r|JH%]cA>;!+At=1Bf҄ o~< &ᅺP uA^ z]XjKO,Y]Kt\*bPCDqC{1I{Kts=ɍ /u=Dā+V=Fc-mg'(Ky{npPCD<:%D,h) u=Dċ#󠮇uA H"PPC: Qz@]G$J@]}`Du=D )70*$A]A]GWu=DuA^uyPCDzQGꐤa.hXcd VIQkaNg=ٚ(]5#uݐelMU;r|Hj+HꮆT7]Oj-AzoIy^Y5?L/%TPSA)w` (l&knI*ts,\?(t[OxɢeꁝJ 绀 1zk]qya LtnCU`ՙ?(|v5SuݴpL*y$UT(.fcFZ3E4߶vMUEjc}Ϡx [pÜPp0]_(9P1{Ez/4^a N#V]T ih䆬WzK$A])ٝ/pQ(|NH^G(͎$r iwʟ "f&W%82 pUpɞxGu=Dij`>#Moro\P K :x4kgT7;^%*;2kϫ:(!#u~UVsMawNQXi786Xsz㯄A-ՇzkVgu}KڪdIﴍE>%tT-OF򝚮omvV&wG Kϳr9|K H^^DZ;Wh<96gC]zYfp  h{(Jaﺓgdݵ O~t]O. S%n-]*fC"ANW}R0ACC1Ap%XeG*Lo zu}^USK3=n=B%Kr$ H4ajc8S=TO,git1n|skF躾D=P(zK)f0Ɖ-5> \t8U Gt|( 8E٪]חhbˬ"` .>LoaC H` 4(JoDS>ѥwu&+J8P .ݚ/ p[jP E6;=p]ؠ T^}A[(ޡw kଋʹu.5Ѩn"r|uLnn [/1L]L5z^S.볤G SVp~=ӱ렕ӐۑDvz M̷|,=ss'u} c/stVu`ZΛ7>4ZPףKAmL^.#sFi𹩬*TBq]~\%u|e` Z Hzl;B(!/-=@: ~ʉtg p&Fb. #q B7 zGHHɦJK0M}:ҝA$zbORa/to;* ߛA"qEC g{/TGG `/ u>%ibw%TʋU]WɁ>!z<(tУG'N țu=H?dy5rA$B8OLd_ _Gm9DuyTN oGP-ZQʚ lzHo zr'bDKuBXD[Y7%{A7KFIUBPRLo3Br'b''% endstream endobj 131 0 obj <>/Filter/FlateDecode/Height 262/Length 28043/SMask 132 0 R/Subtype/Image/Type/XObject/Width 729>>stream xYpי8nl)R(Z\/IFqʙUTe2<ܙyIUS5)MT%&d%-oՒ]$.Aľnt߇rH-f&@wNs, rwѠZZk j%EZZk j%EZZk j%EZZk7m0z^i&l64vPhZ!$}>q-|hn4zi&IRӵrli4M;eXmZ-UUTAlE)bFV3 eYn7Ivnr90hX/GZl6k&Bnv Hl4F]ki!ɲ,0Aj5MӚ&A$Q4%$ E4V<˲,[:EQIe,!4s7EQ.7M,꺎.UUieiA ʲ,˲(Zhe]Y%I, B`0C4ڒ$4CaaAh4a4 m. F(iR4Mi-p(dYv3ZV6AK].v$I-eYz]FA5}wOedhred2Lp4;Ei+ϧiy6 g[:T*!v{\\\TUU4eeBJhy$~?6цj4z=LRrl6$IeZ- a(t#Ӳt&].o a8xbAUR$b8§$I$#4M[\\68˹4| X@ @Qq4MPԖ(hT h4Efa, R[jkaan3 Ӊaz#N-R.JjK-$IFQx,R4l6Khߣ BAHV5??C>h^^|>D[HVL&5Mu= >4Mswy$'^'ڽZzW,kZV(ꦉgN(AxgF"f7NzMFQ._~Jb(Bwf!k.ÁbÇeYWa'''$EQ۶msnd2yA?7 #PpqO<B>tҥK7$IO?lRV;ydPz>q8W^ B@`bbrJro$Ip8zzzT*!<ϦMp(F{ǎ[nx</J/RGO&q(>a3333(E-ӧ˗Y}\.h/^rgΜy~iH|p``}H}4 7MdY^ Y rl6hGY!Nt}pH:>zwh4F;ET*{WBnx__BHQwSSSlv```Ϟ=(JT)W^y啅s΍aI"H&yw=ꫯ>lذAT*~_oذᩧElg~C'?IP(gXĻyf^/>}!4440#q…ӧO aўMӌΝwvwڵe˖GyDl&C!{GBakon 0zzzjÇc/qFǣiPl۶mϷaÆbZo~sH$O~ri(fffB?y¡xvr,7==}ҥ_$\.L&򓟤R)׋:}G񦧧r9FXl޽,Hwdttn={vff<hߣ'?[H,>BOp8|+~uuHR??dX,~+_Y}%ziƉO ~A!?~i)27MSSSxnxDo?wԩS7MMozzG?Q\&⦉pB|>o{1s8=PWWr[$-""XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-D)TUu=\.(J"4 !DӴl~faDQ$bJrRN,$jZ*j4!$I==/AV+T2fne9 CAp8ŲfYT_ݾ~zeJX94M,˵zmrr2ɞ9sX,ݻl"h޹sg غu۴i$IPh|&F6 #Nm۶!IH\JǿoT+տD"PLLr?ŋ+(bQ4EQk 8y$Or|t \xԩSgϞ=~x6m6Ln=zTSN={~6fsvvvvv~>rb!4??c~ݻw -}cݞj$ر#)D"fYVZr'NxB|ru^jTUMj[-iZ秦Μ9s $s/^W*YFӬzXH&RE$niv{vv˛6mf===Z6ϧR)eYx<]]]y{@ju޺pB,K^??|^|CӴ=HR/q۷l.;׿* ٹso?x`<\?c~? 4j4SSo޼g nX,}?=r(.ݙJ믟>}zϞ=p8v9]A-[e&˗/W*DP(422^-k XqEB0DZ.3^Cww͛ 4]fE h48IbQ@0ߢz6- e9α c===>/eٳg"JR;-BȲ,EQjZ<O?t$SZ̶NG5Z2,BR۷/L!IR4u!!bWWBhrr2J=3xH,r{;wWv!dZx`iMӸy8| &:QBF#j\.]>t8-·cByQf%>;;Rep2,˰xUFh躎I$vSY0vmYa!"Ivn "q?;w~{;s BOӡP_ AdsKSTUeybbbÆ gqw .ۿ[^΅$ɮ.eK3g*?g4KRT|9gϞ^^/\PTy|>A׭[FqdznݺMmr=PA^0H$岦iW^jDBUUIt:v|% BBV gt$쒿l ΤZPեjٴ,KӴvMQTBx5fY B.s\umitP(Νca'4h4r,nqY%E{ 33NPַ0 b~LJ~in{aǏWpA\sssկjZ,F'/....."ᆳ[\.m={vvn6rm۶OOOo~x\.mUUUU=rɓ'_۷?~ zQe$I!7Qhj#OI+_=];s!hx99Y*#cpg>Fցfgfj#GT*;44O~<ñXgizǎ5Mv=?~ӧNZnƮvzo;Ju߾}.\h4}_۷oWU… x |>x<-9@Q566k.ߏjwyĉjKK1==:Y~]B~p8Yӧ9N玉6.^xܬ wB"qС|>qܦMq_gvڳg$IVk!H$ PGwqKv"I2 VǏ%^rZl6B̴Z- G8 C!N/ J%HPu̙d2ߎ*BD$rw9UP1S,fgg].b:s$x&0fԥbX(4MxyNpo4} 8prsϑ$}Z-=ñm۶7>. !t:Ǐ뭷~_S+4v,{Y~=6l*Z~000)0f!L?#I Ø:s˵~P(tkW6l60&&&h֪-U,5Md2xU nz7op: xFGG5M4-6N! <*hfYuYOHۭp6UU5ɐ$EQzccc^tRp-]j\.w̙bwfa׮]^w׷yfQذaúu|L&oF*BQݻw AnȱGgggB6mڴiӲ^Y}-r{u:v ?p߲e-mA-qSeZkSOiZj6F[)b(w8`.|WG˲=== x<r4l$-EQE^v{V{GEaIzz{^$i-"X(ܱcGwwΝ;ׯ_r,)(ahpHVnwxG B,B!QPaJWm}w@jPhZXZ6 H<Ʋ,EQtCn"#{Bڵs<1IoO٭? K\EQV(R.''':T,j>ǿjZgΜQUUBd*eYz̙3Ns~~>UUPZ|eYj̙3XgU76bX,3IӴ~WST%NZ-e)f (diZVU-,,R)˲4MVxK-..$~|l޴JVjZ[귅'ir[=膞feYKg-4Mk6dd&OM~/2,sL&cq!]5-jR ÏR&EѨVw`ndY<^gy 7>䯧R,,,˒$ϗJZvw7qԖrBHueVUU썮*˸eYJEy4cXRn4nr:w{"FX,? z(ZwYXXh6Z-HV?~rLcRpBXb*km |>gk6Qq!۫E"nWk5իdҲ,]rgxG*JW^}7AWCǭ80 ѣ/^?l6]ov:d2vje)M97M07 UU5 #Fљ~,Vw!<ܣwCQWJt:2u:XѸ_\4MnQT&n333Nx4bTBedk|GT*ቶnomcfff~~_XX??00066j^.gwwDXfW\i4V 7sV4;wNezXĿz#B$pGnZ.z_OOC$ `Qp,SU2!q1444xB~1Mc VI411^z%$ŕp\VZ\ptww?製`v#$I CCC=r%P4MáEeD"p(nD"$^(D':U&Hww  IVy].W" )Z*iӦN EtQՒ$M6_xnGq8ׯljGDgTM,v&i- <!gJ%I+, '(]~|u}B!xYIJe'βP(w?RTTRD(n۲,QzT_uLHcJjCp#4˲LeYei޴i EwI+I(pr|>kAd\V;yq(LL+xI!CQ<~5/-Mxjj*54]($I n BK-NfwRnl3: H4y quӕJ%J.z}vv_GfZtݻpli&I2Ȳ|z~$ϝ;GDR닋4M_zUũ)| z*cŻヒsn_|\.#hVU_4Mlԧ^o w"iaTU8wF9p8xpm<;zM61,CԩSx ft:}e8;s n"B]x1Je2 f"Ν#Iv}݇B\;ѣG3LBMөT 7tn"9 r9|V,+;w\.*;Αcعs>W;77 6hL&OL&sȑ+W8jZT NܹsS⢪( JhƛN&c皉M4 <ƍ'''UU-˦i ׋Wvzyl4MOMMYTL6u6pBjZxk;wnY()< iظq_dST"w\R 7J%0+B'vh,ر#>|xnnٳ7M<ܕ eklI'W_eY6N:>qYSVq(:4СCWHER! \u9\G:N|y.Gɲfq8\6Zuy~qqQeQKRPh6zju(y^8xRU5Oni'CQ*\`( C$!UUM txZmrrߣɱcq:. ø")͆0 $tPǛ~W^/BHX,&G?Q+I\X,y|bsssXliv}…T*foux*@ FQ^X~;Eyd``@VzpgRUU >^ƍO<$VYaϷ^sx<Q~Tz7Wޣ~kرcKܲeΝ;~?n Bl6rDQrX-ZVG?Z[vB,OLL,,,?ɓh8|>Y]s,W)WN:չ.لiʵ !M9|8|E1 r5q}۶L&sMMMԫby|߆O^]nƍVx}à|?+_v3ev;VxG/~ oB0==o|]i_w)oq8kz'~i߅Nfܮ{/ílk_Q>;,4n+W:;Pw^YyBFa!l^6tcFcvv.ƪ(x W!-500 ew:qݕ4Mma0;vleu-Y:B(,#waeX2n4$IxVsf7 EɆZe(2oz'X}-a>w3nf]^33 ëug't 'R<ϻ\.S, ~["u$Ips$ڎz3{zzVuʕt&o|P( MLL|_T?!v =i?SO=uZ633o߾gx˧?O|70pfOwW4D??/oj5]?O uCXOn߾ol47 TCŀ?p�.\8w ƾ|eh^٘q,;>>nݺ[8!jVGʲկ^Y ۍ;r.]Y7O$?Xww3< 5t<[n|d7J<Q${.] m300p!8/=$I>,Yycx9K,_t]7ga9y_~T*#77hwFeV[\\;=zwxx࣏>zӭƉiJD&l7h޲y>R.,,A?{ Q].?Z pVtܿ@L"Ir5>BR+tww_ Z ҋ{5BޑUwY  `pxT$0H8^~No*b,˃CPIb{JR. IB.kt FFFV2;x8EQ,ؤiVU(.];xwѽ7VÃpr#a. В[4$χ,;77gģy"m$?[U'|Z8p 9]XEm$~߲,ǃ'DyB`5ޛeحk:˲4McA- ]I,p"XKP`-A-"XKP`-A-"XKP`-A-"XKP`-A-Dqv>oZ\NQV-q]]]>gf{rRN,$z2l6!$m6[Oo `knje2zJr\>en`(rDzXl6+_5},,{W~kۋjlߋbNnzZRzꁷ$W^y%L"(zꩧ"O#wlG}蚵HH&X,~+_FPfTU4mjj*N8qZ&z^ՖhYty<bSSSϟ.JR 4+WdYEQ\.WZu\6m8v"H$~rx<d2?` i3ӊ0::WI j`YzСCgϞo ,"X^;v믿r/^D>|pZ%nxFY^.˗BA|>ӵ.]( BPft]fff733(׿z#q(K^/˲(|>>|g/ >Oܹ"4M;x`<\V_|zB!BF7he˖g}& bX,ӟʕ+:080XU.++rO|p8.k_94u]_XXKӢ(@ 088qf#oWU\*g29{````!Z6(JFI, ]׳lP,tm|\.͞={!T*i-e)Rx<#Mݭ""ef|!^;vL&[D%Yx$"BpҥNЖ-[6ɲ)z+IR>G5Z2,BR۷/L!IR4u!!bWWBhrr2J=3xv{rr2r9IvYn"j^,^JT*a``  Iı\g@/A4M$AS4Bshd2]\].]>t8-·cByQf%>;;Pep2,˰xUFh躎2M=N$v[eՅ,dFݶ,0 I$A2 CmܻZf;HU* eu]~_T>;|۷|M6Յ/?OlgNSy$p:H,QUujjJUUC7nc-˪T*J_?~-[ahjϟ/˧O(' رrj9pY\.gYUU[`Y5l6w^+b^Bp\!$Ke٥C]B,r׹cFXt\i%A@QTFi&IiZAQAK{\|'F<#lP<|.ۻw/0۷ov;2 sK"oob1$J۷l6j:^'l{ݼy%ÁG*0N>ir8bK/h4绻].WX沸3ʶm6np88n˖-ׯzj\T*K+EQE9y˗Ϟ;;qoo=^wj޲,kqqOKS:+pGlW^T. ES *JTLRq\$iZ$I*%IbX,f2jr=== ,)v].W,f'NH&6$I纮rP6թGo?~QID5\rCjS+/ϳ,0뚦 Poo;4][H, GٳgOooᘜF#?s`0躞L&'''gҙ7xslll۶m1EC3? FE ÕJi\(N=B(V0 )r8nP( UU6EQljv=ZNr<Q, ,`0 tC,+Q(J.t]%EI(v ?$I<{Ϟ=_=?u:)w100йc"٤p8lw3O>}ԩ񱱱ѡu ߿jj68n۶m{Rݷo߅ h4 2 CtOoO>g&h@-s=j! ҡ1e5M9۽tL/c ixI$I:N)wH8NP0 DQH$N'MӥR)ƍ,˒LS43 ˲xz XgEQn)8P0wÿ/pÆiJEEq᯲,OLL#-[ƅ ob.sx24KRTӔ!DQF4um|A] àiiaQ%ɼK"^.>}f%E{ zj5YeYƗy˲ULyvqNfu~h4jag{S6ziin˲v(+w^je=E(Bt:eYM#i2ia ݾt?WjޢHxӉKhӟ4~>899ٙ- =}}}`0}:OF٦BR$bS|x d2Itchhp-=]"a`/UlCCCDݻLV{E} 5~r8d2iuZz322([c]NV. xߡ!,^7EEDdwW)*ۿۭo4MEQO*t:EQ$Ij-*d~oȒ{g>7REQEi6:Sc%"BZ4ω eY-˳Xk΅Vwv>Fj%O?!d)RV_`l6 ;ψY\.OMMlv(r:Vh4zuFw<Eb<6\ U*~DQ,3ӭmhmmeY^B\.u]!j=9Le2F?΅X,3i{JT*e2P^o BHl D(mxS^,JzU޽ZKjOrR"@ P()v(,Y+xsܥt&],qQrY@BbS>-dYVe~~>=|0ݽ{\.+4M+ 5HX/~כkfH$b\Yd-vʕ]\\_xΝD"TRkw$7nnoUZ0̣G B$k,ۥF|Nd2IWXl7YDQƱDVj,,xT*Qp8vf#Hbz_,f`8f7oﱡ\.///9 r9 rZݙE}"둵6&gP(lnn޹sgΩT*Lmoo?'E I=z%S~X^^Ea'N8NE,r/qޠ?y$ӕJezzz]eOjFCQbݼqӃţGZo_\\,V(bTrx/˵Bם={6^ zCbB .b{"d2N5 AնGp'eY&if_~ftfzX,޽{㸽F{B Il>}t h5;/AoZ}}} b1Lv.(l!$IRRi Bol6f9}t(ppv}dd$fP{[hh5>ܹs7죨zL&FzP(,//W*z޺!I}r\*t <^Q{:b:ujYDVaG4NBphgGJ%<!n7EQ}kNLL|B$fX;Vh4_Z}<d2rREv{>K\x;VK.b6_|P($BRa11V% At:^BiG;vpS: ķBh4`3 Ì\~Fr嵵U(Bϱ3ۺO'vww_xQv&h4ZIl{S"EQ<χae&"(^{Fcyy$@ N_:11vwR&I&+++JBAz~/`0ؔۇC"xĩv1HrIRD,Vb}BVU%P($2Uyqwر@ qS>8!>z(fNݽU4 ;|At`0p[S.ikd-n>!.\ N".Xlgmu:*鮮.r,2`~nvnff76VP(d ۅntZMxZmP8/˲`X__Ǜ ry{{[u:j~9.,.|ᇕJ?~x>t)6w?ǮdFϟvY^^tz3&pPp;IMP(d2h4l6g^OOO{nݺ BPZ>xg(qOFԩSxSl2\\\,<_|l'C^gԩS41=3Z`]$i28 o||'xĉ/ߙ3gh4zʕl6v3Zcˍ(av YQDA&d4ze9 ²j5LS,ਣ)Q_?9ҋ/5 NDz, 9EuxޓtȒ,Bz=L+V:d2Fd2y<cXfcoQEb qpph4 ,ۖ+Y8 ҩBNcXPxwpw~qG,l,]X[[> !(z뭷~kxRjDڵknݚy'NM,RTb_߿r NDQ,,,$Jj^yL*/i4wvvohtHdaaannnee%y-YSTZZbjp*lnng?Kӫd2*_@yܞoey}cJZj>av]"ah6|cr{g>w\WWmeH$ƍ/_~썊#~_z wF "2??JzP( KKK! Nb}}6)bٌFc d0,o^fX%IM |nG&W&&&&s##rBRr92,B(_ȿXlP(dZBVՠ78b%ID"Td2?qd0$z]Vhvp4T*dT*ZcL٢ M.b&t,}JC\]]I(^3 ˰,*JRӌeY$)lnnJd4vfC j6$)l6B$E0 Ad@} Zn]]]JRV Il1$zV-,,jG}E޾|XOOçWVVJ\PsEQ`:ubtwu5@ԁG*jD"0 [DGGG:);˲Ω.!a9k )m6\jʲ_!BRǠȲ,2I,+AEQA(dXZZz RT.Kӗ.]bfbbIS,#?BɲfyȈ;{V_fΝ;Fw fooF"{RwttX\.J*#fYD"t:qZ[[[TVUjz{vXϱWFqʕ+^ŋNpV|7x 8z$jd 0\.LE`aF@ j C[ tA4}޽AඍH$ H$Z#E|>_wwh\]]Fjrٟzf3y6yf+YPA<<^KqE\V`09vYfaVju8lvrr_<$)6kZkHgghi:ͦiQfs@ B(+HaFM11 'O;DrjjΝ;333CCCǎ"kx㸳gφGf]|w߿_*:::B]. wy5BeUh$]N!6L&CQ(\aX,rBy~^I3[,ԚB$q24,V~Y,|"`YvFHS(B ˲xy Xʼn V{E14_TZTg?awU*Wr\:yQ&r>sIt:P Yo$KΝEl4M40 Td2{]~7u8Xl AQr,IqM/IRk-PqE׷UTJlbѧK P.[M#4ML&шk#!VJRDžXVۥh(BaX^zF,ʲl6q"d2n@COFϜ9v}>˲Zz~֭ZoBLLLJ}vT_Ñ)5ݻhՇj|>ߞfخߺu+Jq7>> &-Fo?~__jF FcuuѣG(A,t0&2A,t:nQbX2l5hZxqFd2Jl63d3kz"H}h4t A(Rikk뱑""y/ 4D"4xEq{{ubtZl6;Nٌ˒%BT*%Zkn===<ϏNNR\B:t:LLLր___'IrƮ!m{2Ew^z)d2Bp5M ^;샃Fp"?w̙W_}O>b}Άg|W^y'Nh=nnޘCRFFFFFFL&?sիWxŋ>3.kll րOE)$ˊhwF"I4MSeY-.^#8{jm,\>!DQEQ:N BaaL&V}f=Ȉ(NSliUXӥh whhn{>żMzdOm4 Ȳ 5cHVE%DEW?="I( 4ϖt:($Voi=~oȒhve (266(Jħkz+@pԉ(r.akkZFFj?qPh rB7VmLiEur\.>|r.>)xhjRI mW9W+Vk&Nr9 )Ir\*bbQgqRt,mT*d0 C[ 8pXF/+EQ2 Mov~nii)f2+'͛7ݻjծT*mŶrk*jZR}H$RTZݻw/yhهo|"z_nFoMݺ$If 1 c4zF9`Q\۩TJt:}D"ѮzDӴ`WVWWbt^rG?HyVuwwjt:uڵVg4xp x>t:A ߿,r\z5L...nnnƽf ނr/moxP(deBjeYvddl6JH$IR*j w\moz؝L&oݺUTA 4<,;wnff! jqF#_)8N?'H>ŗ^ x!lQe2>|8??2X5Y/ A3.AG*Ls9cǎ4^'$Yd֖|+}}}P/< Zyd2 ?nZ"k)M$Q JމM˲^wxxx;DD"qʕB ·-͆|>_Vs8YZAMyeH 8w8Snm0N'$Ǣ$^tc `h{"f-QwSVIt,R,>j53jey{{ b@铐$z-fdDRT*?OB}n_MB a6K/ lm_o z{{B!^ngf0MpΝ;Tjjj /.Bӧ}>84n7 ۱SGzKZ P2| z6Yl&Z{eWb,Dxw+бcRvPOEt:k6>>ޞZCt9D>s|xD Ԯsfl^?nDt\Eo|.~saIYnwī~.b,8BBftlvnn\)>o#E/ :aQ]J,VpEO4=:: ͐$ܮ%Yv-h} @ME&"Pd Yj,5A @ME&"Pd Yj,5A @ME&"Pd Yj,5A @ME&"Pd Yj,5A @ME&"Pd Yj,5A @M(JLLLt:h4jWJ6mbbBJb EQjWKB [̖Ǐwuuf+ ^G*K2~#hĘjm6fs``d2i4+%q{@QYIH;KFc>Ev!! 揝:%Y%N0 IBq{$jծ_PE:QzΝ;ZQo,;00hf3pȲܺn ETCnb٤8a hv5Iߎ!8j @M4 5A @ME&"Pd ,c endstream endobj 132 0 obj <>/Filter/FlateDecode/Height 262/Length 716/Subtype/Image/Type/XObject/Width 729>>stream xA 0 7ݪp B'Mir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦ49&glMir6MΦvWt endstream endobj 133 0 obj <>/Filter/FlateDecode/Height 317/Length 121724/SMask 134 0 R/Subtype/Image/Type/XObject/Width 920>>stream xw|\Ž7){Wz,ٖ-nC $Z%A|sI{a @ s(€F` io#Yn3gTVT򬃖a4Ă,slPhϼ֎]vLqD4Mh6& 1s/BKӁ _zsXvɒ3,).1GE"ox_Z_0oEihpܳ(˜ǑD·ySrrŋ\Qj0 s !7v_ͫ}h:: x _{Y+~pu!~{_|95x TUF/~@pʕ^bƸU 0,s \M]n,˧ d8w;7~gU}ׯy%sjFa8e,B#9@AB?c-Psɿ/^ 5a]lAVZ<^q<D\ޕ8` D۱y,g֮];-:dY&[_[GQcq$ !3XS=@{{vb dԖy" ca+C[;g_(),()+,2H!B!1B`YBH_wwOWg{sӮ۳ +ưmZ[{իfBUոf1=[b))yG.?n]|GZׅK-k<U=Wp7wfsbבbtgG#ysiee~~)9~aaA9MU/}vd›S\^^\>4PJ)IWp94T\ cx.q`[sSwG;Ɯ-+xBܺ!N-[nڜҋ $d2ܜ99߾XZ)M``s|MS/n7TWCNdeA_47c0 |n,2DžjDNvc{X,DX4D,ݰfȉx(% Ad$Pj2r DI'bH8ܬW?(P-f !@a)J`?LRCAX,N*ft].Ӆ҈ >ϯGE% TLxƴΎu{ze˖-^1 X`@$bZ: (D~Nجh .'h>VJE֯G`dT5{(&'r_ ٠%ӧV+l` р4 0Q |D#zzQr Fd"N&b(DR*Ӛ3@I#̥ݻ0=֯ ܳ'/o9qVvJ9/>`+."` z%0%>ޅ.t̥(j #<FF#8] i6[D0I@a.(/ٳ 1PuyԎ|IIN`am2; a/dA Ո %`4:=^k jDh* *J&~+)<;s(z5߲gyλ B) d4 R6LAJ)PQ Rh4s.8CI4i.OCWTTY3wm?N7^8MY78kD`:hlfM6Xr!50;v0u*<,@|<-(29,GIqr2`0>3CqVsf7 YVQ:B Jie+Y$RR@2>EQںƟ?g0EQK֬\n]`0Rsrf̊LdE{=O|o⪪z}ϿoO?=g[ojuCsP wĉ N'6g@~>LdL&p8@x|p?deA* `\s]]|xp}ʌvxFr?''ʜW8MRJ<_lyjm"q08Ƃ,sjC\4J^.(-DQ#FHɓI#!/);?ZW^Ie27pXnY0aA}mP F#ڵp!XiL+®] >`qh兂_Q1i ҄B<qYMv~BsQ!čyx^)Pi8@\CPay @L(@JUOxPTU;cTr ]pBUGS@:&9bFC?QrQǑ#$mÿ~w݂# Ho6P(o1-Rp sRB1HRd50 iF aF?\|K/|d2 O8JC@Kcfo (%eeFE1:B ٺ壷Wyw)5?gqt:cOƍ~bNC:-(8pU0q"~@a|x%p@)GyEicu cR>+L(Mkڑg B*!юKVO(JC0tč%DK,aR?kNx$½b.ho<)`8Pz0xތ1rP:6 (XF q̬,mcT 0 AX1a^Ǜf[[/8w[wte_~>1qla~%g^zw\D# FV/`2_ep:DA&d} Ce%̫ @~0w.ւ,ǁW<`4,ؑ οZn,WC*+ac:EsÆm_x_M8jPE i?t3L` |>Sl 0.))Oub(iBZt B$-<Ӎ, wÐN02"`퇡 J#ugDC! Dffy$#MBCfeyaNk ̌A׬Xwdk0۱c m͏Evu+t$coV/k_n7LGw864 l6 Phi9 ㏁7]`tvBGu6@x<`Þ=0aL'޽@dg~pP:rd/gF>!(;AB)tG(#0d2PppRPލݡmc_mDMY8p'9Pmw@ifIa1dAEi'S޻%F)LnxP D\5 !D6K I]n;zI1?%UkLNر,D੿r0*&㏡L&d| ,I# P; {l6Xvd`Vx%BsK/vJgn6,#:}\(P}CFS[TGxw8ܓJ%SXRS5~?*PzPïe2 F+<4a4岋.q͖o2by Ì)40M4]di}ul?~IE1%(ݿuZoA?%h8o'5sx%rwwnX-/Zrm=aaCWHp2pÍy45/5Xv`^xv7ڌR.C00ph3eeݻ/>ˆNȈ^ޡ|C%[[4֕LRJò3 !MKw|Cy ނ h^V|f07NFł,sl[lO-+oTT`C a4ӳo??Dk^TRYrE}ѵמh)po O<ȹ瞋ۯ_솳΄xDa[ip0mx?7uu ر>Av6s.̜ &`~xH|J4 f/.Wfo/Bn?n8 ӻ!@НHFU-xG29ɴD"Qad0aw 5U&9 n>; `A9.ǒ̬ΞaRd/)//;Nؿ ;;yI_OO(/) FWNt=y%j׋8|]h~Àp*hnRҩ`/ uw!KJfΜqެgr3yxi893n~vZ]TT(4L>7PWWn_oﺏ>а{˩$=ifb AV`φd2 C$B!K&㌄Q:ҚI39{qW<mWFqEizS}p(#7GdRCKi0^5.gdq:$f1m6c $`0'2' !!Nw|vsq\{kk_o:l6ۤSTU#])55fTWWK`tҷ~$zٺn}?v|>_{G{G[{[wBv<`qR2TM+,(XQ]9a,+/?gQXb n⪺7 e2 BJv(_hpEaenMxB1 0.%zdc\[[ s붌YD,8bf𪓚%X,X,6vg2X,L&Ap:!>$ ͉#\}͖-[ N^jɩ6m0.vKȊEB;`8(APTJ % D#MH\nMf=n0 c,`#$pމ0dw{_o_n+ZWUuk= z=ܣqR_{zjÆ .7͢E*++1wys=v  Ì Lq`Qa4JCᘪ61YG3`(Fi>U M @uRpI0&mFc^bd%cD8lxe=dE|x[ouɒ%?|^^b7Ξ={ڵzy$Iq20_P 󼇽S r*3H$4#L:$+2mR @AQ@nljyәk2Y,8"ljG=̗ s"!7n|\.e˖oOSݼYfz{N'xB {c<{l|#NQwYeFc4mVЬhXDt#SX"iEWՠB$\ *f4ɴt|'h*ZM`x xqFV؎,2̉TG燋dM8_ަ>Űx7^{ٲ,%_( F G.0 sLz,CԁH$JU尦3 2 Dk!xc2ltVY-Ft9 Ay ^[`AaN2]wboM&:0)NvG:JD́p؟Nt&*=LPӂ4* c-hPgkΰ G1\F*,2_ s"0Ɠ'O޳gT4}p8m6KKKVk^^^OOWBpǪo ZV2<0̘BFc9R`jR=2pėLD2i-_AU!t?z{`hЭ SYrlLfQx-Ȋ$0 )0r&@ * ]9clZ&%D4FilS<覛nb555^ve( %%W\q#<~sk|#whp>>WQJ(4N5E êv;ѨGJbX,!%xf|*0 L]`:&T= j&ӝtN,(~VVi v[d$`xd s ,2_Ѵ`0 X$T%Jcxq\*BE#4B!h#z,] L1\h0,$m6sDMㅋΞ={ӦMo.Yv F뮻nɒ%r9眿?, .d2}>{\L{ʕ+͛ך=2Yh0|b1UU倫& ?d3L 4m=h`PJv@\u:l6١2̗Zɔo2MqPX#S#@*JmA΀,C"ޔ7|B`ϱ MIv[$(zM&At"+YD455ܹsWCCoWWFQ J&dv (D[BM*lvnzW!ۃyR#?s'cL:) @"Bi-Ex&VUO8qĉ+jʊʗ_~^櫯g=BH*Rb4kkkMVPP0|yv:FdڗH3FDh?LF/Po<bٜ/%)h,a^MMk?h v=+Ǜk06fZmfyáG᳋ pؙF?1 !D%BRd<MӉx, cь f15(*)>k񒅋L~}x䯱x&4ř_Z=pxɿ@alZ9}Ylڴg EEEYYY^7++KC*%^0ƀ#P #FsC-f0rH&RXk2 wl9 Ȳ\uW2r,9m?wB*tBmz BAdoT` Y̟tү_yys4UTeMfo~vWkӁ?쓘e1q B2_x)zO.]t:EQU0ovM~ߏBxy^V+W>sնHqbs`SVlcTϬTU-OsvANQJxG4[˷msXg,I+,B%(| ]_ !djE!@_}>Q4W ms5Ǜ:kO#,2ǀ**/;{uxsμpi'֪J4PJ4r}Ϟ=vڿnnnmm~x<0 +@~x+bG?6{5Y?d4MgoT! Tr!́ nFekf' }کSݙӓ[CNʺ4MR _ PA5 lr:ff{gyxYnj:dB5bw.wv~Yt&L4~ouvNg^Q媨$cAIbTv=m&`0HH) U"ԁ= !~_oOWG<m=vdb]fwD`X$I# ?ZzB~+r7fb˛?(---{~ dY~ɂ PVV6p~舏1GKSSS:y~ݲ,ٳ'L666JzKKK̙suId6M&qD˝boO+,(wc'Bw-9fEr؟Ǘ?1J[ ěB˗g y5S(H8L^J5mUd<~#$p8elDTu{%I$ !vkkkeY_^Ӵf!i>Kl6 قDoEQEl6B!MĔS9믿h4r'3rَ/`0XU7ޙg˖]oN6V8N#x}0ֺ=&=f8\+@Ղkׄ L[[b zʐ7w+٩[[;TV^t݂I(c}Ɇj43/5}|kKls 2ȚNW6 @΀r%FǕ[ rsfgf M(dF D* Ñr&Mh79hu7lW$"p.op@0c!989N_gQT_<0xh;wkٳg3vW8d2L&@+{ip^xAx``}QٜH&:;:3Ck[VBA4?xGG}\߰/((BO VmyS&uo$w/ > ҟKPJ۷'~lb1XS#^tB 3wsD B^}5y E?i[t-\-- YFcXCClԮ$ip 퇅;<]wݩnv&iس}o3fl COOAA0eJIDl?k`Ci)}6pwF`4RI7X,@fX cPP[[UBӻv@"hm{B0f3$ tb?B3898 ,[{*;}U=k{TuWf=9nυyxD6R {4Ol$Όs;l f[A-˝oxSd!TUUu 7?}ى4>-Xc<7hll,--=d2K^pV}b͢ZRQ &§I!}y[K/==^³Ω()5V{ 78.VOKepr,&G" %qPGTx @< -*p*۶((zwHfˣmd3ƢPZy&ϩNu9=^>GlϮkF#W.ɞ{ C{{Z =زDaQwi~y5.'2 _!SB޽ !6jJT]]w! i$[Q^Y)S@QNJx׿_~)a GzK.DhD* ۷b=Bq8?5߿c֭wh:? .GQ]OoɓhP֬ >(44PQ^EPh MMd10s&6>shQ@GǨ1,i Cl<0۫R2|sK٤_J5J M"EQ#tDM#^)b>D,͹PaOޞ7w8@vwY}=M^_Y1+cN__}tuj/OiF] }v{)2'BNtd¸k?JRdx,9z4iI^̙3- s<r-sTyyyW\qe˖+4s Þ={n#n衇E]|+"˲>p}B@ -qƙL˜̼0w'.7\p*l9`x $=R᤼cq1J0'S#Bj?jHy?ܥn`C3egk0 q#27c/8;;?gΌս+Q(B |Ѱ$'gYaEy&1{;񹜒|*d2@`֭?ڰq5S\^oEU9ϛS\Vf#ZpÆ tہ7 b2ͫ?{ւ $I[/{ȏꨦ;(?3;e{v7B(I-t(bSgw'OX@( )l)IbHK}fv泟gg^p]LJJZlY(c|Sò,0'Pc(ͶpYfM:5""l6[, /B,˒$KgjITp=$Ġ 74n^Ǎ9i1~v4"B]=$$^Y9`AnXtr{[姟}aUX8r̘L |1~| aSQkAW{mŻvn Ο7wn^^Z1o!NΦ8[BMeNpKرc׬Ys嗇㶶 @ Q$ C3ɢX0Pٿk^ $&:FP(@ ZMN/Ʋ,f@}2GV:[?W丫RNK%*].,$EYWm=.^==6˓,˫T|wtN$fٵ*)+s񥏽jJVMQ,cYe9(11`0n0 %鴫듲MpDSX^{Qx]Mp'XP3/+69ih;uzlY˷޼λ2@TZF(75nQkDDDdgg^zq!`@vh+=555K.3v 񝝝W޼yx$I'N[e:/++裏e񄅅~r)z,Ne/7yN3?+ zv{wW0 7|E]4tY7j_ᚦ!/FB K@l=vC0i2̚ oN'h4 d2N%`p sLHÉ(:|&W1B'S&Sd$e2dB۔zndMOXTJju: -J\'Ciii4i47ffܘ!{}kj-A,ojlP5.!ĄYeCi9Aq:|_|['M D1pן  #v+w{ ~pTި/5+aرyòW}y# &7ɉZť?3O(Wy O<)$N^:.&)--4$d4[n8...h4T*H$ŋ+yM*=z6lQQQ߿x~!۟cr::n:lذiS`g{ۦGwGE}$$$vGg-#Ehi &*tvI@2 bbjء\M(rL?~0w vB aRrx|Pc$Ҁ\w+E Y},D\N'#ZAW SMzOӣ #Ø8fDXCMNK!дXV!īT=g4A#412rbdyU.׆ֶ5-5N^D$i[S㶆z@h\b50)[^#dH;s`YdY+;Μׯ~ɒ׳хq)A:1ͤF09,K9yFoM+W挟~ްх )QQEv{=^fEEK,~h4 /=!N;22rɒ% ""Bz㔈OBBH億ŋX`„ 1}01cʕ+nǏgϞ Uk@j2: da 3dҨhNP4VTq4Ѵ"v9 ,ᶜA@@AEJUxeB05/:1xM77 xЄa٭?m~'G\j q4~_}=ְXSL|TRrxtZZa^&JZB7⪵Z>/0 bTJ$I?3N@QȲz^o t454;Z[TO3pm}P)޲Oc_a!$$mLFde˂ [Bu\&OQ6߯s 9\.-k`hUT |&N1c@av E fQ1PS{HHJ>g#!Թ݄@ zl6b@(XYS^Пl4:h)(@2XaϯK.Q z2SvcBA1nzf[e zdS8^v CL&DMX8f4Dcyi hm[[vw^(6 A}r܄xD{B󚫯2K{'ðl鎭w]>g;{)/w\֮.(D42:014z=E' dI!d,b@ X"|LllFff\llRrrNNJǦ Nzr-8uwU[SkZ$4M+^HcgW @c,IB(666&&&''g'=a>(lۺ ZmAA\xl"2MEEEgƆ~QQynmHOL~4 {BEܐ#F@tLoс~h\.b8LxP{=/ ;:n1-mAKb+NAR(uIK! 0 g8 a4fu1ju^odYQi0(J;H9NQXҶfr+ʈ5-ubTTAJ&'/d{zzzm-|bԘ gR?xw sP_xڡ$:BL%ظ8lX855/煋/?͆8E~eeQ bCC:FB˲iiij$Y1b0g7i;22rrr***-o?cƌ53u:{6^]pHA@J $dhh@wC\ݔP4(!E2x<8p<`yW̟OflZ {}~W]LH? 1 R=feYh1_` lɤe )3ϫU*,z&{<+uttz,pUBIY&S)lv,sRBFOvQyqc!%(U*![Vc{Eee^qj@NN`wX0*85 q 9|t~cк{@5mڴi˖-?rՕW^ue7l-/ooo *3Z , CDNq3kQ>Jw((Lʎg9NABE4EQn@mU]kne_`J`"D3 /0-JKKt!0*/oT^-+;P_t:<[%]; (VaJׇ(!!$21,(Z<,***'##;wXl#DC(6xho^=Ŏ@&~?  vm]ZQh b1Q 03cy{[-A/+nkjiA0ޖf:`0y';z-4TrD}^xvEI|l%4z=PzZ1Yv>IIv`9vlvYv|J:8.IgD>`j40iQuץw5vOmm76UXeU}LJLȆ7|?wߝ3gZ]VVs=iZ׫jy_t ;;_qF0ާn O@i>9@-@bUa:eX6M!UO3I0.c e}>0%nIDe3HTxDQjoA XrFs)6.{XV 3LYac,8!BE\͛7 pM7|<M,ZdɎ;^{ѣG_zE q܆ x֤Inp(**OKJJ^~[nNٳ3g<C7KQ,ˆ3nQ K\`˵,wJ crUS0cV%]u6[Ͽ_%ܛNN+B00q:ƊM[*8n "|vB8N|FlȲ$˒Laaf3BT|.3 ~d`b쫧@<^-:MfѠ' ;~V#Bx8^ Z3RcY%sCb~) 6LQky˥jr 0sL%Y˲s]__m .3aڴiVf|3U9 "ęqOS0vQ7ly={b >/| THRGRaBZ$IAR$UR2C_ށ_ᐰ3!nv\d6ߔ5/9̝S :CD0Eizш@ @^$ @zyFEӼFRhNR)! "r YÇOee`Fr:-qqq"؃m?C- b!(:/%GA/I~Q,lj >E"j\ZQtXXG (ϧ8 -bU̱`4 6[{Ͷ1ciy*zq 0\W ##m2dB UXnV9Κ:wT*:))9.*JefN\J岲2Qe,666,8"""55eYQGX.1)Q>ɀH_諰:!5 7 Я_a*IRMM ,Kz"":::9%YE!cƎQѪc bP@}},bcֶcϞ !RMCIp Ln><5,ͪjdXnQSE}`V%MEEz~`Ld> O#=3J7Pu]] `T9*yB0ǫ-q2,?pQ,IN-Bt )iqq#GJKKS/5b٪8iӦZÁ CEEEQ4E!JW!<Oqq(4M$y^Q9;vlfffFFٟ0IIfZvj#ܹsذa .4.\(bWWW]^^>pdz&5555՛~T__xhmhD)h4p\7mL!jɒ%c˅1t999c ҳYPJEŶ7H_礧ߚc6Rs$ ( h7wr33p{j.d^6y.d SR>WN`< PʦJ)'E :6m\u뾲2LaKljdsERR(ibXq4E4MGQԉ$JsQd,aZۚ44ffN;vĉǏ?cqȲm۶f9<<<---??d2QŲ,ByBHR,{"E$A"~",>dŊ=== ?~̙3gԜl_DbBɓ׮]nݺ)S544Yf׮]SLQ. Es{ѓQkrssi$\O汋MQӦb dgL4h4"g aDf((*{n\岞8qYNʅˆl)+{rke3;,-̨g{۵ p~pSڶAnG(Ύފj4*. Դۆ 30Li6ixnͶfZ W-iy N%r 1imk}wF>lD_iDP**fY+gc6K=ZϿ~vNJMAQ`PDP[SSY-h<}_?nܸj3Cccoj*ٜ>**aey87;3͜Cqfff P4,//cq#G<ձV{5Wccc].W}}ӯELgeek7|믿W_I&h4{祗^*..K~ &:jjjxfddvmae4j 08+'6͊@0 $I===対# Rc{dǷ 1ЪG933^p}[ZQ ّQoO?2"!ߵAoj6N$_tw_&ꚴTCZ c0MFG.xP^z}^%6.6Djh GENJV9'e98(V\ȧ.T4hT !$19e䩢t9m}х /9G}K/~˼zl1 b?`T6kx4111ɳfr\vӟ4v{L}ƪ#3>%K̽꪿?gϽ$bQn* L&ӧ~ /\s%~\sq\Gk<M/xȯxSTI8#?&w ^xb:B=o?K.d7E-ZZz} 8 $]0!׭ ȑeL7 ֮YG~yhQ a\|[0!-_RW[Ti4t4]|tD8cX~hBVMM9Ont:.-{zOyt[VI:sOvA4iQ7de>n*! `W~뫖}1⋧:4R%r(t*6h4vB!dܸq˗//++rss.΃%eaҥ;Jvg8STuwx|ݛQ%Y5RrX~~=RvB3fxlrgff48;a~gEuuҥK+**LrTJ Iwlջ+*$:2Llt i:>N !BTW_c1@0Z[VBQ}mN9?pj6!#&+wP&ۻiN@NH`oU*ܐȑJ_(j%<#׍Mvt!_VfZ K:~ g)pK਑5Nguu\.XǮ?n>/>/JJ|}Jvs㎒ >w ǃFo޼i7_?Cf-APBzV:E=Be{*Jwrbugo6oZ/(**4iyW,B޴!c@0$vǎ[lq8]{E]f͚3^ub`B^G~}΁1fy駃BpiEEE999* Qk\AYښ۶oٲE \x;wj>TgB(vӥKXjǮ]$YY#.ꎻ( 5@q7lD[OWK˻@-HĢ+̹+ FbAnlx[Njqmx T5vvMߐ91: 0!_ٜxaaa &r4}"tyתV~`nY}7'>{{Z!y|B]BB6 A00kvѬ^xݚݻxݶ֑yYqIi9qII޸+A0[3CߝcH}+2,=*/'/-W~;G.Ə?~{:&& 555)))##C1s7oijjjhhW!::ztnmȑl9(|ӧOollܼy󫯾ZWWRPPֿbAǻBͮC PUUU^^_XX UUUY!BG|rܸQ/GP.&+t ʁ˜̌٢9 `D/˿G/=xjJ9f'5N[m@H2cI0k: d`}j~l_FPٗuv!`0^ddYN)LLJ ;b,Q⢢ǎ]Qo[[ˀ_|yIr-߷W˪TskVVQ,bϺ=$dC(p :>>":°l\b)"`qu hL7Gb,+šet=Ȳ,,cA !X) U}q[ڜ,%)iM*M#avh%귓Ql7nܷo""" >>؆w)$`0I . '''111** ,eN-\}YgM pgۭV~H9RQ1@QIKQ9:0LZZ`P̷ w?-[ cbbIp ΥY1޴y~8I"r9=z0IJӧG{?)(aM}S{E!ὉWF۩SHeN:9ijL eﯰAA !%S7E{aG ߨ|R@J@M&( $O@%vBB6)@@1AF脄$(2  @@RѪ{\pLJ%v[_#W1*Bgb Xq?=!~ BHrew ]e2A\[ Pj4G%%YƜqc(j4jogoee>###i|`pĉ_1(ꫯz뭷Ptuu-^?OXX '=YDzFtF1d=PUZZzw7vtdyD;@?Ͻ0gcu-MMq,{F WcB--Ԕľe {|> dfRn{$?onrseeK[` }/;X  `d8c=E!oPx>o/^1^l/?aĈ!i{]wݕ,eL9s攔4557hvuuY,sρYf}Ł@@?EQA|Z/v\_E]}lltt~ ,YdѢErKFF;gVCM ,EELqZC䓣G>-l1[Pg/>,CZ&!2h8JP G[[=RRb&!"R$W|0A'hL@GD1 %D0dHO/0` b7>D7wTuvM_}Ezw$W;0jϝUU]uK,Y.niMJ ^B(!$|JHL/ƽU޵+mߙcdY]26_;3Ϝ{s&N9} &lxVTӥB[@[n7lV< ptbFA)*mW{̓# j/RpV7OqO?`bLn{(>wT*¼YXs ,ɢ*$H[;DmɌyOoD_D 8 DeL؇l 4:!;w`"BRLOsQٹn:0T+!) b!67l65jJ%/ l!jWY VV9r._sHNN.**C"=~6$T*Ƙl?~(Z=,˷vۄ "lV5**ꫯqw>S/6o1p8Bb-3 90fn-2a„H{dd z[ 0Ƃ ^[tO?K/]i'I ˇł];a!>j-d=QQ.8uu{v >/AXrb"FDEf Y Cx=!+;P-Ϗ4mM}>ˇ}皊]m] j zo 46Ȣc47wI21YBV?v.wܢ_### I5K0vm`S2py>4]6ԯY=f &j5(eBڶͽi^\ӴiɓUֈ#=z[<"Lh3O2[/# G~cԲe9>L5ʑB ?tnC#GI\ Juvc>cLƸDGGT%{<^{mܸq ޽t6MEFz<;M83f !0;!B[RRף;@H(Cr22J:Jv ~-h׷BV]#GyETE+@  &8B/Ȱ哪JDDȌ䵍M[j!^wߎvuBTVA6j4``C K|`+5hTcEg5DF7N'ivvyVUɟ}&z͸13Ǝu$&tǟ!,dÜ^z?>fM7ɨL)TM,K?17o;oQh%\*Kg&d9pqB/޷oJ rsƏ?ц K0QPtvҶ6wgӉvttp1ƙD!ժ*ѽsx8j2cdY="6Aky;Hd(p B0l(-m#LȇɄ$ :=c6T>z###rssZKzn]xǏk.ŧ3''gΜ9Ϸ' J4~|ݺuO>$3g>cMMM˗/o+ree֭[kkkL#$a<3k֬9ߊhկ~#//oTV̘֨1[nnꌌ9sgv˲7⒒Jb٢+ ):ͶjŊz^(ڻPz}S0z9{71פ(oh|UE>4nl\#?KS|LLݮtz0R @hL8 BTb {/eiqOelS9rdB||nvNqI?_dJKHHOORdJ5g 1v<q\E9&XJRdllaEXGG8pVTUW6;ni)11ôCNֽf2l<={Q^Jc̅b;ֆqm%%y.x]vv!QQA@^),Db" W|k(7朜;vlٲeժU#GLHH9rBT+bԩ]vq111F$%1Z=eʔEBXK/#8IiUUUMMMYYYeeV8qW\=XS2y;CaNIjjꭷޚcǎ+V|52yܳ;r[ƍΪs8^}珕ڥL;+*2eٰi-UG덛,t̝^&2`<c3H*,,|楗wv5rFG;Ib*FB7XT*JHXz[,w:WYvuvR]}/>kӃ7ia0Ο?`vyy}}}SScyUM_,䔨Xj5Z>cV-GbRPJe2*5j (Sʟ\.g]rkss[Y[Yhk4֔yG|ll\Jj.RҌ G {k'L&̜ B/a78b>ԸaFLIjX|y=9fy֬YǏhjj*)))**ڱcG[[fu8%..N *ZI<ϟFR%%%AYq@]]]bBbKKW_}d2GFFƂ 333e椤3MK`ZΝ;nܸso ~zל_L}x>oׯ1-/x/rËmE%Srܟ>f[3e +a^c*1O>g~7u OGϽh|5eUW8疟|E1vޥ?OȈ8 BHDDDDDDEE2!/nEr2J ܮ3 G_ Z-vP hoG(u/P ӝnEņD@@2ĵ3Tߠ.4Ƞ}_gl@!Z=jq u#3c,'Me I1 &VN{1F!'2FE*1~t.a[]T:[Gl3BfdPJ[[[;:4cٖCXl̴;_a[L3J] >ƘER?zo:֎j|៾S|tMto͝w uE^󓻎\rŒ #+nmu8KHHNYdGn.ZP<j5.z=> Jakq1Z$$QTHI^&Ty.k5+Mx8ټ ;e^jJ] MJhgѭ54I8cȑ#?ExLq_ɳ2F%I71d1>_CSyTwIV9K;:G/1*T*N't:`4ֈfS7Pxgp8VCpS:Lm۰v-΅5bջdž:mGO ј-˲vua=n~xIN砿8T׏;VVTNp$DDDuzu:^7L&i=_ !B쿓X .V tv.DG,P%MMllpljuĤD6k֮7ޱԠ*57!%fqfH2h9 |3,(yjZցOnBe8bh4*YF|Fw_0̹3cJcaܱt犢?-sac q7 <^jjjj:PXteVhڙ'q݃HI_^?Mh))>j5d3 PU0 Stގ90i"'bV#& 2Ek pɥGK- Pޖr1w)-zAlʒ`ladnV+`@ϋNx>ḏuu G`СCJKӗ^ဉ%.lZisF$,d ;Xgy!زvcC#97b~JBHN>(Nfl2DB.nC;Yqz3^,5ؾn7FpfB]|VBc!+{LF1nc 3[~epszgϛw^G0a.VjꊋeyRQu TVU765D0xs'bp qU,\X7lkTmآ(`yq&pюȬD b0 .KzWy1]q$Itp9ʞÇZW &,^DlLΪp6,dÄ2x7wwȳOʫ0jxXL,1k ˘6 S"- ؾ#6@M7!7۶<ŗc8ENr@LLA0cx7O1a„ sz(U'i:eh.mmBޕ=j=cցms6K /n]]] dJ5waQ $L{ < ]Ӽh12q`"TSܽm.ѽyloؾ}~o1cL_t-AA/xb۪w?yy 2DEa̙؋DE[AǤI.tg,= * Sv1 IDi)y߮]k/ˉ+.*9lzv %IRL8;vŞ[yߦPO:wW_C!`dƠ5z$  BG\?61ZM"Pp5Iμy>]طcջjUYtIhDmӣr(>r8pVU 2c;;a3&,dÜ=DY+*+].~QIIGW m^;rXucQV^\I " O!DRLOw^Ј4#*  Lc:Ûno駮 p:QxuuۯwW- jo>dzuVQn $I:rH(tVMNNjQT]]]=z^Eqjzĉz~ĉc j„Gݻ^2oN) Eb/fRzfEeeɄ2n8A̛7O &|tϊ0CHk 0qc4uʉĶ|E0AN?[H8>PZc/ A06b1#AǨQʂ(Ern7^v$J $JU|L i<+<JYy98HN)z(>Cwa z`0q={UW>|iw$'GDFeiK7eIJm4oтaF);jR3FLMH:e###A'6@)O%)1?>X__e˖{=|xg*#lX`".W ( qBs3<xrul6l^۳ƏVV0[n[c^#(J6lرcGyyyaaaffV%Kj Z6SJ|Hn̜9s攩S&O,|€R*lϞ=ׯߵkWEEEyyyVVh3fJxjiii fJ}dYO`aaa|||vv̙3N:~xݣ#|_ovug RZuQ#?1@Gɂ A޷;$BF F 2 ! >˖1440?ެ7!$bFLqoE[ϽbXȆ9]B(|wۿ)(15M$14\UL6(Y5Zk]pUߛ33+#c…C1/zdI!GwOn|G~־TCŗ/^hѢP(Իx4QXC@eC \#F~5ct>Swy)Sl<$QF;7|l ӛ@  ---)+w𮲲:鐘TNxAo Ţ!RU > hMNgfd92%9YP4A(6|˷XS^YSx%/St4{?΀`7x>B;B]] {Qq^`Xv- Zt㲜SS *z-?_v'Κ3q)s&%#Rƫ5PH 8W n]c'&J,˞.^_ (].Qu:yxaEEEw1cFH L(NSV@DIO?4,dW...eYĞK{G[9.W~ @M5ZZ"xq6{ddM W=;wr\ *3'p)]'YB BMbf&w;)9B1fF7dzQw/\;aB|yj1*xӏa;|$''&'/dbXSc)*QKeyɔui9 |].W'vǏ7ŮMmT̫9BܷeḰ}[oO>g.јL4٬j0N98knXdInnV{ܞs{qgVBjڵGF\P_W_zuk͵,((D=*NgNOg q9xV+(+sM7]2o8b>Z(Z G=wL8_9;@)I#+RZf7X >4>^~rS(kmhܵyߞ/o|-Zi` ޾o=_#Η&Ph l6Szh6z ]#뉩S ANQ~pz=.J|Kξ 2lIT*h=<1sXk @8WB--5e6m:]O=Ç,999zwt3fHII1L&l1sc)u|^0Lg#Pzn9<x<[n̴lC sDQ3ͯn1cFbbd2ͦc&t5B9ܭVY, e(v.+%%`08\G).>rA bwQ8SHSfÇ~1V=ӟΛ9C?lbyC+&"~3q dlb]&C_].RUfd0H2ChYpa|OףR{s`4=sGzb(uGJ4g^ر^m &pw_8ޮRE?풅_o]7|GLJKS5ZNhu:qFU+.? QDJAQ1y'!\B/ `03Fk+*JKjkkΟi|!L0aۖ- 0 [\\27^^qt: wlo*)\~?) Ο?ҥ;v/GFFFvv`h4juZZV{:0x9QSܙpڽWEI|>_(}eUU<Ϟ=oVnC.4c@++mGyބ̬,^Qkt:N8jGL&n;ғ-zd;].+HKtٳgnذ!<+{׊K6:ĎR}eεWsO[3_vِWvB]9RM2G?fdF%00Q]*:]/,ohk!q*!;b4pDB%pdks[-+MJO?J-BLݢ_(ǟ CJ?c9seY*;rh;w ,f9nuas+1ƴyJ|, P0ht:R%RmU ${~ :jmt::A_|rȜї\wCRYP00|E-Zh?Gx2konn**=|89K|p!`0(BAAܹs+0vl6GGGGFv. V[[[|ZI(cl$I/]]]n#F,fIZjr3` kΝhѢں.`0L<9%%E9 ]w)a{V7pXɏE*uN֨X `rRSSsR-Z4ue˖%$$(Nuuu{w\ ܱc<>*Z>40BϣL7!t8b7!Go)#q&>믏M1⌿ h J:\<[\w8*`رnv9$5ˑ=ꐨ bTP;;] ĦR'Bq:)ۿ3\(B.k\[/hIJffSX,J/?GZ68Njm0 iiiFQ ~e QJ+**ZZZ;6==pDGG+"l*|"[^aQMfF~B^ug4RRE޽{WXlSRR)TuFQgfvf{)J%AzIRTl ( D<+r JGޤPRHBzHl/S~LHܑ~ۙ{}999iiiN~40 PG}~ǫT*ŀ^~ؘXLVo4ڵ/_|Ŏ }+8j/`=uʺa= Z-Ւ D AU @(LސHYxNOLXBݤGz"$IuG-  Vʭ[ oL6ruu䪩?X>wϏJRl9[[r@Q^C'DD ho< R(eXݬjLęI˚H[\|@B;.50"ܥY2A6BV-CyyM2yBRw6OAE'XͦNO~_:dԨQQ FzŁ@۶<>>iiDb{\,-ݱRoa "+++77wݺu8n4ݻwǏ ЊlX9$&.k4IEQ R(N_EQgΜ9~ٳ{n\\\|a}0p1c$I0@gdd8N\޸vGԩS;%\.&xUTT[.77711V]'8*O@MTfݩLlɽT bB*%eraQp")xVkժSI(j"$yTnz n~~˚_~ٿQS ⑞_Z5NgQk"egem4 z:`נoÔ:Zzs: qP`D6@Dr`\yhoY3n}<{8O@tZ.zm0JI~FKHJrXq DZ-S)TYa=|鞱cN}Jz_l殽SID = .$j*]ti4)yԔ/bmjjjE[j2***JJJZ@;M6l8.))n/جqٳg>}Č[QHŋbl3d=z\FZLֵk%Kڵ+))#*8Pѿ?Îg]fCM QR Ri2`Og.TP(ٳΝ-99E %KX)".xq>@`eB\zV }4j]] ,^űF rVHZn]}IHHX,+VذaA:Nӽ[ѵ r%ĕI$Al?~n_jڵk].WJJJLLV裏Z ^yNhBO `f=Czσ07` ]&  vɈ п?D' H˳M!G_rALWA|02oQ>5*eJP7p| 4뫺,sbnn<ϟ7Ar7-hssz&cȒI>u?|!Ch(q13Գ#鶃 Jrv_/.NT&?g?{רDFFh'`YﰴSUWBWϞq]vxu7 0nܸիWyrk1::*?nodd } 0Qs ǥ/]FR5Ahy>(0j9;uʕ+ 0jԨT0Gdɒˉ,E*a={WU (*}H#Au#864$+ vRH `xl@I$ TCQ +pZg)4lQ*!W$h5u(:DRӌB2juUǁj:oMRլqx-VmVRB7w:HwdnU(UJqe%%Yǎ~=} 4(jJr 媹xqقOx=J^h,PQRלo:<Щȑ fsOe({4`RukpN:-fh>q>蕧gEqij9 )))eٵk~/"qܦM|M{セ}Z,~;wX "BiM[z'q $IYӧx{{`Y;vΝ;4]\\Pgywrqߞ8q"""hiADfff.P(.ŁvPR\h 湋:}tjJX&p{\N&!IHe*900g:ՆE?|H7m;~lXJq["Em/qldN= Giv}AD'vѢE ,(..[s<ջwSNM6MRd?Ö-[҇?6}歯<)1&&믿ѣo߾?Z `۩S'\r?Ct/[<7 X-3;:dŷ%''/]TGTZCo{ I@^^^=Jxb-nxkEW;v^zԨQz Iqm# +hCJi(1, +#8 ԛp] :DpHHxD]fܹxduPo`dr=  Id@Sk؋N!b-Z L55oQ߰qz ި `9@mE = 3ir>uk(ʁaA~hvU3|OjV܂f`w&?hXOA@IϿd3.|}Tj/~}o 4px׮f XtT*3f̰aÂc<7N8q„ kNg&6mںu`xgt"nx뭷ۿo-YM2E}O/S"L}jɓVR@}}}lmmݻ׮]T*>n+8<>!A,lL&9s9sx㍈FX~߽eee~ݯu}'۷oJvtĈ*&E"K0&NE]p8hDdHhh_;tڰ0E3̛7WT!6;zh㎂ *()yG!!!_~VD" ~?l8Nfh޽̙3CCCIpf-jE0LMMMHHH@{zwjk!D!K Ьй3Lѣع⑞>8;jH$1),niOTId*l-y_,UvGӞ3dXSQ-hhZq'Yʟ.Oc2BṔv%}9 S(JREKAI8VD"is{CRi1듧'Mz7#nYiWXX؜7ߜܳ}G2n_AlԈ.nw`Ds;}ۖի9<O Im[~=_~V?gϞ5֯_߯_Yf >\l`4?o&77O?믟{U8m۶=▃2d nذ/<رF;3gN}؜j](T*;u$nzm&sϿ/E/qiiѣZWR\\?ǎؼysmmm߾}?E0ͭ3"#"̙sNQƫO>SLӧOqqwz"N].͛3e+.C=r.T^n6(ZF!%\cb}}}%%lC8'\paAAAzzL&딒"aϞe˖o;.{/Μyϛ7Xg8Ny/IhZg=\ jnՊV~}&ԔԴHa݁;vp/n\aǎ1z`m^ɓk=է-q4hbaZ//" IұWlL|SpUݔ\ReuI #.o`r:m<Wx~ nODu.7!a([/b"s|HLL v,=-M蓥=t1Iy^n(;akN~S O}3^:n&uCr?2bv-[>}|-şf=t֙#;wnNm;Ib@}$^ d>C}]vYÇϞ=;44OVVg_+P*ߒDŋ ~ǡC66y^.DFF^U=[la/J ꫏"88׹\.UUGr:YUUDΏM4f6:Lcw˒%{*?8ziP _]z>g?3QPZ>aڮt{z{k~BNIݵ_l6EFw΋2RRJMύW_-]t)))J H  @hhhg,h @&5XK&i\;;;<<<44[n3fѣL.S)UʦN2}zYe(A];?13R*@*;^nitK~K3gF.||||||BBC>FkqDo?;wHZkI?it$ø">OxQgHR0ξzwf_zNyp5G?Ȉ_>{}cse5;/es!vMSJ^^j^bca0P(B'= Pr`.x{#$ L85` !!ϫR!) 4`oHGIYS$>'!?eYAQ (덷;ފ!j (}ӈKYJ"ť"ہMӍ sDz,DZfdVEdqIIUU5=^Je\\q<ĸ8Rw`]\lVHJ")e(7 F)H<+XW՛QPP(*$“y*Q4&_}977Y獰bN67].hv!D1},TVVW k(*&&F.s֩Sqi4N:I$hJo'|ls&4L)R Ӑt(O\.0DVvK2Ntѿ׭[xM !-s˹|~UEEIQ;9>L"8NgNeo8$xRYΕ jmC(q:4Zko 6%:&>.N kL&hA4x |>Yؐ3r`XMC/_VP4Yv$%c aX_~qvq0Vc@83}z8BB<+ "Hy9PrwDX'ǹ6rd:l:p`Ƴ_&.s<'B'}_ ( p7#JB ( EئrBNJ_Itv~R|w&MkI}EyD|x3vEhhAii2@"7~R9/I", ;EEQAd$lƶ \(*Bv62#%KܕҺms 0U.A&,ః$5ݝiI_gF:p]HOKipXbƌ4Moݺh4AtZ|m/^3ꫯDFU"NZQP`аal6… O8&ځkVFSxq_'A.T2"(ʚ]+C^%uDZ˙3_E>xW߾.]H#rً.lZ;Eի*&Vբ=}/?0_? CA\.cMkV6XB~> C@+ .8E+PT \cﳻu*$sSbw*N'дV/>ָHts4}3D':Dq] +W|衇x^{ EQW^kRq>?o޼W^yW^(j1117^9&O|ĉG̚5W^iѨ-[pgf̘1c O׿.[L.?7o޾}#K{g;p%]>NN(>8\H- 6**q j/xUfspLLāwջwBBZmzhgyP?:'W ZS,(ٝu]p:TRw|ǎ[z?O//3g>SJӽIII}]ffs=O"\9spxnHJdI)᭸o;gϞ[u]I]q)5Pg6n˯~᧟~M:psA?{;(-%'{'&JccI1/Pv  D?B5FшsӺ:$Iz 5g[BNx7xJ ^'N8qb ,Xn%<'E 8L&9rȑ#[a׷FDdds3{ns[kٱm R) لLcv6"l^^%Z-K5Z^IaA0IB;)u$"y<4T;ŋ,{y˒ZY/BCNNWU5+P+^ z=3ׂR:pe.i\n X?p.]H }4e[(OZmxJeKԏhVyX@,h6Z-$=QB%!&z}aӞ&$qa6Enf;&&&''6qoiiiWG4~z)0{yy,+ZnQ2LV{t}AcJѻ7RR! /s j4bXF >ǙΜxHX<_xhrp\??J ~G|rL/o<8:Xl:p] G`M z/UbV)f^-qu.>ôhxh7k*H%%з/d?)MpylnF?-0C~\Tl5AҿƐ...޸qckP9Jt@``kIw2Hiym78pZohH6f$tBސJQ_/d\LD1?D}a2a&جx-P?Tݻp L&m@XϜY 4^ݣ5D<&R͂ :"7e+ҴRSt o ; f-~R)RSW}Q GY)~ۆM+9Y9tۉ;w6aӧOd6EQN~nnXqf \Vp M4->{Id>!d2NkRZ Ap:XԒ$Hqm [ uq,X/0 8t L{p8􇿾B^]֭Ņ BY)!:v //梲!@".Kxt>*RguG'pri 5!u6lq\r[}4 BPu$A0LljJyyy9**Ǐ#JZvLںZZB{{{kf#^1Ӏ(\ZZ0`Px~,+j(-xf;Np:8ѩe?_W[GRI&I\ȒA\-JI0 E ȤRF*U*7X~$Hnw;zvfC87X.;;j$r L&Sɂ TL&'&&JeR !)R!W2L7kRtaĽ!2 nx^|Aqlx8E$l3[nky˲vf.qTt8srsvEQ6j 4M @tΝEGa(R(2L.wHwfduͽv g^Kjںrꭡ&w$7d2ԷY&uCoq;ȨHK0A<ϟ?|wGxxɓƔ7ZjÆ я>>xGGYr ࡇ8qСC*mY{)>w\\\\bbbVV֕X,{YzҥKi~_{5 qqqqq:NׯIK,yG?~۶m[bŃ>xԐy%8Ҳ dm(/o B#"2p\oOU~ H [~nDz hTj H) BR*R/~WeFbج69''d2f"##"  Äi4eZ۶mA,t:IU*U\\\XXXxxxLLL&S*kF8q  HqjH?(*¶Q j7Z-V^XXXXX[RRrEdZRihh\.y^.x{{_iTM6.zn;'7xzZ  JRQnXg/P=k4X0ϗn8kdMS <Hjα/&"v@^mŝKd $YXX8sקWTT7n\tiBBI.k…? 4H&mظܹs~71cTUW\rʕ?=CӴ_UUEQJ2bĈ-[diii WeٟV4c ڳgO^̙ۋ9]v2eʗ_~g= ?qܶm}wW߻b].WYyYMuMyygO;_k4j4OP{k|< QxpIR𘆊>6aW](.(8rݦښ*/WDhHN aa>>>zJjWgffv[Z^^^g4f:uرܢ"__t@yZ+ƚ}$I$a7X̖ϟ;wn֭~~~111III]tA>Z)J8/eAB Ol!r?ϫ.E!0^W[(hJcl6WTTfdd?~<77`0FGGwUoqGAh4LcǎY`0&'' y-v;/u pl6UǡP)+d RbhJoWŪ;w]Iv}7z7Ձcu:#x B@AM0lڥK֕JJJ~j?>ú .\ju+{)x`ɒ%56l/߿qBCZn9s̙ٻsr2s}7pTs V66%"4<ߥHm 槟K#CB)1Z2%=z}vrlڵ+'''22{ҥ MӼA-7~D"#޽cA;zw}h~]w鼚%Z- <9g811 [ݓsZ\8 ͅrl6ݻw׮] IIIb8vT0 MD޽ (v={6//oK,ii)…7<[fZc4,eGnA:s|(>R\_M.ӹX6!2Rl0P4-a[R)+h `oi٠={cH2F{Gr VҔSxmr T `H$(cuHļ-4@ȶ $Bщ' <`0 8qbttT*eYڵke^xA̝zWƮVk3ODpڴi"`۶mMa27(dnh2effz6KHH8p L:19駟^dIƞ([nÆ ۺuڵkLQԹsV LNNnE`BQmۖY 1Wfs<DzWڷ ;o0Qf;yܰaBz1ctzJ2&&f߾}&[~qA<$p8.^XUUp8|}}}}}oee_7ÏZvذaryvZܾa4TDxDtTѣy?{͛7n8jԨ'ߌӸ)Qp,8 @Q =zw ,8 "%`f.qV, AҲ 7O!!!ww8т&8qT0~xe3337o޼icFO=228eTs!uLL̙3뜜s6U-&dbUUF^jEGd$.RLS fEnG]07l~ٳg,˲Y\@ ү{y7eeO9ȑ_Ϟup:4,0h@Q K @ךϭj- @pU3 ! Kz4}iy~sQ]{ః  復ںJ \FIk/Ez7e eqY,аT6ψ}fz-!AR͝;ԩSiii*f|={L8O?UO>ڵkm6͛z!]n?UPPТE/R?πndd坻>##cǎ]tTvYYYy ŀDzzVIw݅&$BB Q8o%I $)$%ₜ3a k6"**W^y (0hĉ=i$BQQQl2R9n86jeee߿^>}?T*ڵ3gNgllldddHHJ_"5g"$It9ONJJjy<)5uٞ=Cp0$&e@Jon}0l4K poæM DFGuLډ߶6lb P$;o17KR{ѣ&)&&&***(8XPQ8ydl\E$;뎫woeoQpkj+W45RKL+J{_^2SKܹrp2.{ ;x8HP+?pgwyw< "7em3,|}GX0RJRGM~Pk׾qrrmq][zԢ$A-5j"kIoO Fh(0vXE ,л4lҿȲ ֭G/^ԩS~~~رcg a;tϞ=_ܴigAAAm2, -z7lؐ4gΜ#G }we˖o̙3ϟY___Dt+"DN4>+,,رkp,6W2o^Kt1$?g9`:''߀@a9 &[ #k0dSSR]HIۣYS#Gn_WS3,X`߾}}}$-ŋϜ9kCnڴ);;y#GV YnݬYΞ=;~f͚/::f3G TjU~} wJJ,z"I D~~~VVVbbbRRRnnBhٲeTTԑG<Ê/رsNxx" ~~iP)S# c((NNJhh77 PXR)<$<"^DV$ 4H$mٲe˖- 6o޼V=~VT*wgرcmҴUv23s %E9̸˗O;XxJCVAQ\&`_ >QzL` ؙ,SܜaY322ҋ 8bZuvnչ[Pp܃EtZѣWXХKoP0aիurJB1iҤfDHܹsUV%%%޽{1sF2y͇xXND2 999yyy,C\\baM* ///|}}v.+-jILINlEEEeee7o8N"hZ^wt)lCKr̓_q;ϝ;}( ^@pp3 .xxpe޻͚ 8鈈ܔ?y$ݝU*RtwwDނ;f^(@xJZIIIDZ,o>d0rssY(JRiF׻kڸG^a*59}Gh˖(rtsCbaΝAAE,q$I0ef'!Z.|ZgǕ>Ҏ@Ef"@UF$(ZM/= q]Bi 8iB׻BAArVEP +PYA0~mۂI;Vښ@~>F;_Jd!a^2=S,YfU-ށOD&N=thGs9Ξ;~ӾCChzꫯL&?ngDm##—,Y7" W( j׾ݴibΝ;KJ$I co&ICHǧGm6Aa**.**0Z,RS0'\L srsi)ϋ%X"+"leeerH,2e s2@ (J,E"JERZ,NVdrZvp::˱6$z0a?`Xzݼ IrԨQW>}RSS=i:<<<<w&Y3R*ԮѸ'`eP.l󬟯OC8h4䗗{ny^P- Q"p}ıۖ#8Ep0X -zG0Y3dÚ [΅GcJOZ| uÒ3z C? ==و1}{KJZwHkE ڜX,\]u$w^j^<aYdJ\"}oq,eFc6\lfY KyyQnf#N?{ARo"}CCUZ-rIJ$HDѴL )RT**LNRyxawm۶d7o>iҤ֭[w={o-*7GFFN:_V$Iy^W$]\\:իW9r& ^P(5bwu: ⣏>TTj <5UJ>ԛ_.|tDER,+Ӑs/R18@*T|`1ˢ2 m%Qy]HKN>u{O?քĉwNJJ|#9#=oʔ)ba,4 X,NIIٿcƌӧR*+EQm۵ϟ7͙c^S_, hsr\ͪ/z$CAvpsҋ\Y/oM'ZARCJr56or93ִ4&?.CCt[89vܘBXB|wl˖ヂں4n?..Ɣo Va3e3Z r9H6˰]+IB\$V"˲psEXƾC&>xm;a0< W y/^OC&xk:t.$p(JurBHa2ee /߯szثn^Ք\=KK%ώ@('@JrBƲBR2 Sz7g̘qŋFR+t!(sTѣGo999&L4UUnnnO?}vwwwټg'OU[JBtǏ_`aP(**:uTHHȀ<==)*//sH$JKp|암giZe H")$nUڼsUjXU؅Zs")fr!^-ZNڟ7X[nnj8C&mذaٲecǍ}饗 Eqqqll-[FjZeEEE(b=zTP\d; I,ˮnM>}"##Je~~=׬Y1`FbAZEgߞ2E>~B@L&dBr2.]fHOO^":FM_H Hkظ87uAHܬ4 0Rc<9)sssrzv-3ӒeɁf[J!, jh (vhP'N8wC <7<[:t '@.?79gg²_۶y[#11~}z̙={J'֭[ׯ-5 AQVVѱޥӍYZ88;8ݼ;u4$?7f'q?իW}GQTJJƍǏ?dZMQ0-ZJ7on۶!/4lUsW_}O>.\رcǐ!Cƒ;VPGѢ_~%*:ѩmux'I"4-A ,;͐M-vTߣ<??X,XXMKùHL9:ݡwnϓ WTh*Ie93o6A &SYFzYa!:1a"6ѭjHJ+sfB[,h42ܼkE7KK/ͰY08twWDu1CVjy98n+PdUUxq%pbWA~6YU ֛W>EV-}߄ڃxĄWrg`%TR5'\~_gFř3gV|""ō6GBVV˶ Ex8ptx/(0سb1 N|i=b/;ϵl>~ZL*W ϟɆ $Y, ETY_=mCH,ٿe DzO{M"W-a9/߯4n|ew˜VGœXui79 0n8>>x#a[aFDoe./[Ѷ-K]}i-駟pK*ۧÇfif(--ڵkTcB >cVSy#!ao 9كłDYxo3p'˲E:::RŲd***JOOOJJJIIXE8N,lG>ѭ[=MHTT5 -7ugKxC 􌄄.-C<-ZG$9磏?~f}'O`t!Cb͛G\Eh(ʿ4 hЪ ͛#67Ю=*V^JT8q =C&2 t*=r><:Thӹ8{zo=4x'&"ۄ $]T մZ?,;wnÆ ԩÖmnFVXOF⻭Fi)&p֣Ԅ?ƧKTakh EPׅ:e_=Aű <$ 7J]DD$ѷCn*Ia x`WU Sh68:Gvvu k4JB,VDQ ge_/+ǽ婫.Ijѱ<_f.ij l*8tW//Z$@ol_{;v|${Qxx@^hn0j ? AP! 6mTm!L&KOOOLLcd(d2-Y z~ō:lLZ$2q$EeR\r,k(ʠhJ$}]dRjY#0˵kתTAD"QqqˋiѸjժ۷{{{TGt$!qVسcǻּ>?2{wC75wn]}aa4MKeȱޘ=E|{Dn.  <<0yPDv'ܸV@ػ}BE.aZN ci" 4%hqD, [< Vv-C{mFm؟wz HR$ ͏;ܷo߇NpO,ATX"6m:~dO:9U4++_}UNNȑ#c{s~ b=SlAqX]@ ![7͋3ppl+J@wp-+llaLPh+se 9 RSةo9{,y7x≻)$E,ˆz]xK?U*ߥ?/?b|׮]/^Vŵ/׮5;QR:ͣ{ycϘG]D swe[h!N>'녟׮]{_^zU-(*66l6 WMIדcY666gϞⵥgϞuww N钒VKZUZx+T8>A1 $dS&Lfr//nU=l60QY?У;pbb@Q{sln"Ha$#gVVVddd0C?/sW\?w}׿g}@AAʕ+ccch"ggovܹ .۷ott#v"v59kժUv/_NdϞ= ͛7/\l2H^cT*zŅ L&3n5[;=rAH$[_CV(Rf9Ķd 8pϖ~Ajot TFvᆪi>O;233>3FӾ}{a,D3gkZzϫ?_:tH.iF$ }رc̘1~~~NPVP*C(3ٰ{y:UCR I￿bâ6>:t,pdn)O$C$?+N/7~_k٩A" ̉*顒m۶,߳gO###}}9sk׮7o0h OHk֬m۶k4jnZ7U'%TǍ7r)Scz$E]ti?veԩtE5 >k֬zH$y^";̙3+W\zP7Z^t_nN~gYM6m"lܸqE mӦM]~}~~EQ=ԩS+N$%G¬HO icǎ̊; 1&_^{pBCq&BvIwTmYYD%%`P IlCxD~ԛc u|&wm. 6˳8дFH5,.|MHܺi{;cm[,rzw;v/\R"-CAby8y.b}`k&Np3fFFOYYYӦPH*H<~A;6O?pByy9qw;wΙ3Gty-^ͭ/˲}̙3]\\ :tʕOzjȑswycv{K?~S켼Zhwߚ..]/}Q4M7,!#I?OrrWf6 ڸqr\$͟??ϐ!Jrqzgv{]YfDSG~lO?oΜ9c;FE4MӴ+ǯ\sQyys}饗 ˲Vի~ivvv$I;;;;vkmsO`طy j6D۷p2ns]&P\ӱ㗊0W+ګwZp͸'T 77d#? "Q ϬGQXj}KaeC7@(ore F&u<ÀeY,(2}Vk84Edpxzymۼy߾}?l݇Gv*UkBP'$*{4x,[nݰtVtycY~x''SO5 l&|նoܸqܸq;wDȒ/]t…}\\\,Z(333<}QF'n-J۳fqTڻw>ۆ o,/?U|!pJ ϝ1m`ȍIHhAO\;Cܥ yOi7VKW^ʾ<6j+I~=EE600uǭgK-[P};vwh>0>.N"̜1s...G^bEǎZp8v!#G޺&T\ժպ?WeYm (z ()Af&֮ݎ*meߏΝрaӧ`6c H,2׃ع{,k89! "Qa4rF19GsɞҐZZ Ax)j⻍ܸۑ t֭}0}]w:uz2Ӛ{8{{x(*BHIR%!H$Aޞ9+2868p<[!g-CZZJœ7HҨ./Ukedd_oڼe_U<b4o>k,N7~իWZ,Tq\x e޽{;v,[)88׏i:B)-DX @ ?322222RSS322{K/n IeO<IJe˦Ok9^4hРAR?p`Z߰v.EO1CA'so4<$6s}}.!3ZI<^AϞ>bL|AlaފNLjH|d]NNes<h&%w_~{wΜ? h:vؚ5k&N<+Fuy>h4D[5<( ]f.]@칿6tT|BN*..>>><=_p_Dx~44 d MthWg>+E5Y<hp}^n5!B.Gv6~ވS'1tn H @m׮(x{6Uk4&<rn8sW%_n-/wruUh4RۃhB-9U(Un>bSgs33 r bm Ksn[c--nӦM_tu;:~Ë_|q6-555>>>;'lV5kRѣڵk/^v''' -9qĉ'HHH8~˗w/J\]\,2ח8HP(4bPe0Z P^^^\\\TTռyvM6err|/R^BCCɘ<][.zL^t=Iهp,'wpHr 0p 4 S)"}#9zפt#))&;zLٸ񻮓˻G۳uvv^m\R[/|7AOiq׮] ¬?xU}byWmм9T*PbR_FM;KbS퇠 ? PУ'B[BJ4L'FFt銨(^.)K!7O8qi-U@<]GO Q>,SHLh*5( X?ډqU$aw/E֐JQZSyNji|MD uH$ܹsΝ.LOO/((0-KtْMEE7SR5ZH, mт8W7 wJMV^-q.\سgϼy(h4&"b3xXt\/];p<r9vEI N@At(m"Mh`xyy ]v}c8͕djUM9C|||Ν-KHHȂ B[ZvѢE}ݼy_}Uo/ٳg+ D, h[JIggQ\1B >[+/n d0rԩ'| {'Mdff&ĥdROG//2ǧB\XX(<$$ի5h4[о}DXXޘ;gСC{P$EfelXpB[~~ >d'$_=|Ȏ[ ss"GhRAV B] M?i9Vd9,r".*5ګ_]4HH}]^9%bf^Sbxe%]"RMR_ O/88f*ZG@"An.8pH|9+ @mByy z=ZJPW߅aoybXnݺ w} &5 0tÇ 6 ܹs]&'|}|7mڴp)Oy"##id_PŲl FF(iϧz$V10ׯwknڵkb8,,L.[vkHW5չ矊o>;p[nMQVh4z2SS7-~`YCZ4i1WdǞ;{b\UBUt]cqnSSв{訨` 8>9p_VXr~wrW0Frv `Y HΕT9`\ENB[5EdfC !omBeYQ ܹsK8KLJGiz\0Dqvv ;uD)))r ZO{Zݻܹs?]ǽ{5Y~͛5kMiii#F8vW_}>u̙3Fǜ9sBMLhJmΝ-P O//O/U9&rn'Hfjjnv}}ݻ e2٬YX=xM%:ux{{7ه 6:ujܸq{ڽ{u;/:4<"kݻw֭۷ojcǎ:ujEv6lX|9>}1駟1\ZZ!lRRRҦMX|Kcǎ;r qdt۶m֭[W__q :ؿaW\?~|{/yɓ2܉`2prt=?qv"Zt=ꡟֿKm۵m1#aai7OdtwoZ SLY< MŢEeK< g׃0a"_|[Movڵ,:991jFE]xQP 2DP.y?zwJiBЄڀرc?$77٦ ȑ#<<<y={xׄH$1c'|RX,'Nz,gse<[nѷ2ũSJ-++;}tտM7nx7nW_ܥp͛7 #:utf̘rZvJMMH VrD˗O1?fʫW O_FIxeX6f&ڐ @R B'|y( aÆk3nB|Iq1E6$f4N{$ZxhZRIe2XLMx QRRq\~~>˲<ϗLMeRZ&I9!Ly>-=mʕ~irsrw @*V.4k./#;4 zꩪKΜwf0#~駊S;iҤ)ST*.Oښ@mjbeyxTZVVVY!Ujxquu%Bhlpk׮ <5h}|=;'ޱSG=ڂcҲBaa%}n86$DUk=2]%B8ơZJOO8:nX(!;HzpuUH@< An6Li@@>HJJڴ']=qu׻;:z77T Jσo@jKR$A$A$ 2?''/+ /7;%9EyM1 R);;l...2FSN^V$ Vh*ck]"CJHxjB.J$.δV(UjFT:;;i48n f3YYYeee Dh4LQVPq'MӎiFt0 lݲ5"""446ɮ\Fr祥k֬Yvӈ#fΜ)r`b)****.2dJKKm6[iiiNN0BEh,--tؼ*J$iF&wn߾}fv"Ng=c Թc ;a}SJb[@7uR|Ah(L˗AIjjA@@P * H.(= SP\AdjjԾ`hnX50lVh#tj0 hn5c+T "' tbwr[m[[L&V JMKd:__LѪ}4/ :1ƗkG"b[vlrXm֦]')Ie4ab/!??֭v]P)UJRVR87ܵ)ѣ3w!V^j6LBtK,IOO0aBDDD'qƍ ve``ѣmVZZzᬬ˖oٲ塇7v?l6 <^>hv!Fuއn߾{CsJƒ}m-3a„~ŋϛ7O(ZhQ7Fظ ۷oz "888))ITT*JHݷ HxUx<Sd4l6j0݋?~|ppp7#`۶oߞ,V۴=+zWPqֺSvG-"NK*r9A2$ M@Q pESsb 8f,Xh ܵ+ @NHCj^.en5ApRsqӽ):jA dRa IHJ; ans #BCAz?LcЖ|;  >*ypU[24 GZjp,zNWn%,x" 0N%BRIRJje2%{tʯ%a a~VhZX1n F*dz@Hk%''+/믿~q__^"z*9c<1z:8!NBy斖'N<쳷qwp^PP WܠL?> W};vG%R[@"&NTTF(BW#'8Tyg hB`;nl>dxFCD=5Ğ "57/3pr`4˂JP*0x0ˆ<`P*Wotר 0 \boZ0r&'fBT*o7"-XPRU5aPL&\`0{mQBRՑ1}3 MM5Uwzl쥟~v'r!_}Ֆ[bcc)yMfj#xEp6$ HLHַd龽lVٳqpe=za# _999_|/=:==]8}4=eTz~AR{O<@4؇ BʳXhm0~?h\|~~1G쫯ڕ+W>$HyJz5kքM6m„ ~-K~ox4(::Z' 9kgnAĤĴ7=)YUUУCtjݘ.Ʊ'޺VsSx2(HB<ƀ3+Ϊs]\$ȥXgkUUϿ;L=p}ER( I-FkFy1<`,#x(@ Byh݄-U9-*\_~߾<{e\[BѱqOLxYf씗cǎWmwN4hП}YDD~*-- 0ז Ĥп&((輀R8q_|EBo>;ڿA6K[oK t.\n鄳}_f"Iʭ+WY 8#Ohf̘1z覦&^VQu.??9s0\o9c~,~8ӡ7BI׾"01U.c$MΗ9Y_7߆:r$u);=wg%%10d Nr¾&w\<@ґ=ZS.cE.AYYYei aIdFz EӌD<ǹ+<0>l)))顑tVRR !ɷ>3˱ Ic|K}.ㆆNUjuBg?R4<<}Jh4999nOH8')I!!!!\Vw\.jQuH}}ɓ'1$I^4#(XuWbjAv!I>㚛EfŊ7nyMs>?B BgIM :( "H`hx6xy1L@Rr?{ɑLӷl[]U)tGԉ1+ph"<ڭ.#+r hy{#ǥff,r |%GFر>dY6-#s҃}ݸb!HHj*7]>}HM˖-;}^ܲew0yB6mO $I4 6lشiSFFF`0(@.ggg/^x̘1`=1˱UxYe_9i$\mH$O<մiIjhhnݚ,\srd rao X/\W(k v#Qh E08Z7u5(uf"1$j>kci|*5UeRg$DH"q>e ̝UVIKK[T9Uў u cl"?iȊ\A!Sg _o9ܔ/''!%7 g9xdȐquOPx ZE74tՕb@Fw8qF I].SnÇKFLMBX[\y98`?|ؾG*>1dJ_B!HzyJNnu46BFXU¯GFy ŃNmU,<"VtLk!(yK }'NZ}뮻Zm{?&B^hhhRRR^^ѣG}`2@0 e_:I <0D"!dXJJJ;VVVvq׷o)ShںnLy! Æq&:y/@*O琉X[W}HAn}Ə>dsnhEy>XԄP=RJtӺu\q;CBa6Ɵ 6L v:NJ-,ARq;㵳s@Ӌsr#xʡXh$t97 iY7i\.<˕JRNw;]n#RWGP$ )rG#JZ\flnJ%9㮭24{=ޚVfTn(ʠ ٬hl$Il67CB6vYZZj6ɓ'9;vDGGAze2?Ucy]'nDNJRfffn*4r"##}||ryrr2˲ Äh4έbVVT!(-_񔕕'"""iBpۼD&<!4展rKF@")!u:U~ۍ--{B8ah.T a%zcGACCeWfHZBۈ\[|ŅWȊt^HTU*MNa^NHeVyC}}Uu:ݎ yZMTcm- ` BZ__`bFCLTjG-WBb&H Ii&)JxCuY8(JV *, 0ǎkdmmm9s&$IJ6aj8N8Orr^aРAx@*$IӴ?EQm.dwJ<@UUpO{q;wneeeMMZv-I^p!q;z$((a^$I!$33sԨQmV!}yQޱ7\rՐ,y<{>^"b*r7HC;v~q.xTT`]] f3khiZ]Qz> $2 $a F`LgNeVڊOKNXxθ> + yVϷz<@RB TDGVLF*sR gh y**ƒE3J"? !P$)$-haI@X#n&h[8p`LkA5<<|ҥ60 k׮?ph|7SRR$ۼD\?VQVVv8.Çw8ݎ'-QU]]dɒwy @BH*N4`0>ろ믇JLL\`BlE.  I IՂ?|y74`}hz-MMZh0~ B}v[g: t`6a0<$ gv`HwIE&^X!A"+clD|MV}}<萡C4>Vs/[lʕgϾjB 3N^{gmmz?:?px~Ou% yy{ʎNU>/23)5\.h%x^|!\McL&S* TRÝH/#d2 rƊ; =:--MTJRV7~~plze׮]P(\PP+ 6EziӦiZL6k֬.d,C !Դm۶~_0V{wl޼l6/{7n>H/ɂSL:uƍKJJ:i?!rH PH IBp0S @3@@ 6EEPPT[QrZ0> Tvw>k25 ;P"Pn+w8@N? I-""rzF!yLv:-Elٲeɒ%l%K 򒒒1jS?CJuĉ)o,X +|Wz  x{tl={,ZUiZtIt@Qp(SX}̃ w9ڊ e3X"#+r H/q\Hp?pvݹsosύ;Vd?F͕JEEEVTT$˳T*z555O<dd?cǎJo\:Zk>W^!IRJۤ*.6..UeO>Mq=Nz hJ:$ @ӀC{f:-1V['xգBB.W >4-\?_ʑH׋V:Ղ Q:h^/Ij>ڵK'K@֒| nڵkfϞݯ_|;wܾ}ʕ+z뭬}{M8qҥ4s`F;/yb_hG<РRhTf^{jjj#(((!`F֭[KGikc{c$K/g3Z^= <@3y ADb}{A @g _NRlσB׉#8`Y Ił$^&,6(1每֎@A`[kko#TZSS%z$ϲlFFƦM~'Zj].ǿ; 6MX!ᆧc,h!C|';w h4[ ,4,<<[o}G*5q׿y^Yy :*:4M_<8p_u{ܥ'K׬Y vG+//_zuvvT*mhhرc֭[{챐fU,Vw)r5 y=_h0~~0j4lwCt44PR[SAHy9dLv;};@ r_muUU^/`<=<[) HYfqDGVM1tȏ,=6,:Jh5-+sjݮN]C#D,[kkKS?7ʏ/rhڛoyV@l\NBA;|%u8KMM=zMo.l |駛|ʰ  h4VWWfff^L4M4pԨQšuӧ 5'NA{w}.qqqrK~~덈xWꄿ~ۢ Arll!AѴTB&so=gΜhκs>~z=r |bgO`@nnc<]wrڬrL{.((7?5bҕЧgًfgBWn.Jh T0V #\(/agvS( %Fsx<`S9uowWR[^/`|Wd8s"盄k(EjuȊ\ۻw;o$}|42RV)>BFvNIז1g0[> DZa86yhmqQk]}3f=eLZ'4qR| ۷/)))""GTGm#,gdk|4 k43g4psfC!';gРABtȑ#Abya7W劈__P@31ZD m1pl }7ãӰ}Mͷ@x8dvC@ DǁF#קTVry|b~x%tX᡻Vn` ,ۮ$p N'8 09&0ʺs?.r(/~-kq_,CZg9ٓb/x>tAQ}Dz ^!!= ;ʊ>xznZV#iZѩ2DrYU[!q^z<-f5f8,4DČзoߴs]DCrrrrrr<ÇwUXXhX(R(BQZh(I4d4M_!qYxl6hx<px^ǎyuJu󴚊ϗ,2X$'`ћ0V:-yp`?`Hno| 6l0q;vq/>5w~c2C!#ݖ>iͺ;R|^6/weB9_Ps;f~߭Cx۶Q_ny߭ߍ)w >~ >D`֬Yf*ر͛ˊaJh$`HdBp)ˁcxXv0);c1JokC⸍U5z`Fl./9]CZ "r9DGGGGGq6رcƖSO{f4F(JhaZ<^MK|}||%'EEE$$&p"0LVVWWWxeaƤ;uRU^Vd0EogxCg gVLvh]UlL뻣StdyMϫg?{kۼyӆ~,ka߯|q/ArsTi顃N7jjj7$+x$ t.Mxxyޏ"b464$,449!!_ 5*͆# phNO}^?eBHCmer knjBe] kLq\xu>0Zx]\@>YOkWUV8wn/oh!U]UmZ` <hxOmd)ؘ#üq R tTk91nPTH2 ٕ_| "X CZ]T|_^nt㞏UPxxZWȊ\-(;{ꉊXHXq|||zfڵ |}} 1 μ|p\5ՕDZ[ŅQyD B# =VW7PԸp٥J8 Rn5j9rӦMi4׮]oƍpwvm'NtÇ?oSNoV^"""1[qB>ZP0t'*]x3QhQ(fϟ"^.?sfqiiqϟ~e˖Ϙ1cvZLFDDj{KoqWڬq@z DȊA8p ࡇo޼~:x!Cx߳gOEEEPPٳ9k1<'wԩ+\~e6/Q! )L~my}"FdEDDDnLM6͛7駟޸qm{u͚5Жa"Q x///Bާϙbuuu|B"""tJL芖*vAb,P.:"""""7/4i҂ yٳg/Zh4 }h*-Z18neЌDt˷n+jMS3]r(N@ 8~[Ԓ47',(=_#+֚Lj8QRb0@Y͖jBz}@`=R(  VcccJE>m^]]t4rEEEv ]YYr.FD&0AKNjCBB,* cV??Xbܹs,X{n$ٓZXXث"Z[[kjj+*=nOqq$tVWWwb2,"2h(*33$IXF#XCR[Su۶}=ju82E)V$i&޳ Dcǃ^@6N'L/[T?.<<1%妡Csr,}Yk˾꫻МLMOJLJ :U 11~Հ$UC>#+rE߿py T&Sj>: 1}iRT*:-ERAAA~~~<3 3l0B;p444nt v=888666===333!! =~Tr yVZlٲ/СCkm&q;uTEED*Q BRT*馛rŬf57x^E\AAsd29N׿vDn8lV7߭Z59 U*H-M%NƝeSH1 ۍyv5{< 'JVc2#"{FbeC#IIҔx'a$p1A]j0yۅyyyX]WupזI>Csؐ?NIYYن vu \5ai&Ia@ a$I !0 IsYxx>w4BPZL8201u{8lOqђO>S<0cڴiݸlذ߷ZIII4i\.g$&Զ'_9NwAXX,nx޼yN>}zOjcXVJ677 ۶m9s nnngY`0@```t^zE8KNN2d%T*`6/V!iڦж%"2=nt9++*?>{lУ>:qĞUy~uə3JTFԙ|Wy{E]140R 80ȝth|ۯv,+)XW <66*XLl'BhPN%K?q' @aT,zPvvWVEGV464yIͽmIR0"sK]Ty׫nYHRy^8[G=N/x7{`<"W`xX\.x)B&+6z9mIr\D^v+?~Bw`Ȑ!BC͛wQ~ j@VVAcdڼy)S\.VR\˹455͛7bs=2aϱ+E: $vVr***VZk׮󺘶tp8֯[ԩ'FB|e[|fmQDhcdk~qː!u,OO jMWñr) b(*J/ <9_?+sjbyjƌ%^#+riM>IYr29}6ur悄1@ H$P_&!9Gݺ9_],X0SO=T*>5CoZ]vKoNf~'N dfx`2 4& P֖ݻBG\Xtx~,!zxlBi*~**33s+߮Yǖ|  .;V{ pW cL? VNё':G<-1 0&!Sȓ ^Oz{\v<~gy\'&$ !V#"">˗ϙ31mi)NXXҥKI?1sL^/+ʗ_~yС?xmmm񼼼~1oL&z|Vzze˾+~{̘1_AؾcԨQ^ $zj VeddD:$I^6UNI<,Be]umlP@bD^R3N|7dŀ>~%i;.?yrQ1Ot (:DѓAO~|#-[nٽ{/?*.`B* BPh47Sziy jj|`V֭y#ޯE MTѭȊ\Rɱ?9O24}/?Y2&oDoER)11:wAjݿ\A f^|H$Iƍ7fAGyyyÆ BBk޹cgHpJ ;v{vxF#s7`PRY>Y21 i]c*mZ+*l_|,)>@1AVhLAmh0 6˜lUyVu+̃D^Vf8 򥩠c 04#˧NrԩS.\RY!BME5}NNt+" 6 Rŭ~-1Ux4Ā?uյT\|@$a_k:>YRa0`#޶WToY7w.`l;|Daj9C Y BX81rlLP_ 24##O.|u?~d( Y Bp]xinjKM7.$4 A! Q% A%<Ƙ=]]e%E%N=Ғ9ucϿ E cۗ-[f0&M( 8qY 3B;Ƹرcǎ+..NKK[l^߲e(y@Xnʕo]dIlllvvvzF`(i@B/|9Jl c1f9nwee򪪪222~<(ZOJ%deAxZ⒞ow@Sѡᴏ^TÁQQB\9'P``y oҶWcf̲۷QDܶ[! A { Z;ž1p)(K/)4VŸla˽h(dE!; ඕ޶#GsW{L]cCǦxacنh !JPljZ_U]]~4&-<B3 y0\EGG?w_iiѣG}H_NY" hAZbhnj.///--mllJӦM[jV:kòlLLLtt 6ol6 CZZZhhorr2Xx雔V0USܽ<󘯬lmm-,,Gy$99y?NJ#}" !#DAS#__wuyzۀ硺n㆚H׿ٛD!p 0~,J ؿ! Pyw'O4 ,2ʼn.kJŸD4?uD!+2dV6 Bvĉ憺wֽ W(^ڰ(ZE0!<0V/p4BxZfK[sR4DDFd0$gO3V珐PEǘM\+x(*99yܸq+Wl]]]_ ""BP Rh4j4BB[FrԩufϞ=yd??>q8w|m<4MgdddeeQe6O:Q\\,HBCC5Mtt4erV/2(TQ^{IaT*H$A@ZZ믿{w}rƌ ,ʤ$24y ?ڎ 6F#zv?J!,--pr0B~(+I@ЛﶃCYw@*},.Y˽xx~o{ /yk/o'?'D!+rLxT* E nT]mZ*+V]x<(zL ByJSt>z_DŽ`c  ɢcccWP̙3NLp,{arUAQ(Z/ zӧ:u*99YӍ3>P*cƌŲlyEf.6V!lR\\lZ}}}F`455mܸblٲW^V.((ػwJ뮻D-%JP8Q MR qjho08<Z-PGzV1. p, 0LRoSb1.$o+QȊ\MqqP PolofB >[{ B0v;~k:@V e %-/HN8o~v c2mݺ^۶m?, yu"WºU0 SXXjժKqAjݶmۚ5kl)D@q_|k [[Z6o؉8W9s!(@P0Pv}toZ19'R^ywlflVr: BVd!x$s]BWrR\pk}UVqI ˃.\J .\f͛{>>+VHKKjZVL2]B>0n7?8ㆆ 4Xp@WtCbboXr0c辄fa* B:N@" C Y"')) >lO<W@t8.>>_\m۶Y_|qܸq}6<0(d2 cjjjBBBh!4b8B+@y~s  O< ހ( \NJGF\<l#!, F` f8pr "P _,OHnGP0Lp(dE94\HRYPHe2(RHerBb(J4&VJ"HR<OϊL&#x >x&N<(*Ca<L$=ؘ:eBӲ$1,!DM30'Ntvƥju:A s,'tNL3w+U(R-O;t(Je=]]I BRqr,0eD"9qHMMK$'0 )hf+**JJJ:pDz;z|0sLDbN8Q^^-ZYX_x4͈4Muww'''+ʾw\BHff2Bt9rDR7npษSٳ磏>8RXXxiJxvJ/g6nܘ@ojj>}R%ގR4]: %yC+d2x{tv??d~9[d2HM Cz92Y<{W!5D@C=TV.KM:mp2OwmT"I=g L1?>c{I!1Dw^~ؾ}k3aL&ӝdzRV=wvwh3~4}K݉Ȱ =d2O? "czj8|(y "̥K~뛘_2)) cL4Bd2=rT׏;vįY233CBB y睦O>D\:V~MW6[ll߹^puu{'}}۶{Ew_yEyZzAF=<+|s{[[dddvv^ ȨO?vGtT$TZB`t365 5 @c!"۷V 7éSaB>>rAq451 }al`0cLBVdt:ݿ֬ٷws\bjژȸxDӄ1Ƙ|Q]v}7.ݧBn+oJ?T!?x(JhK!0NjLz_\1Gٷop8233SRR|}}1!&ݝ󛖊.Ո222II).(+*~nv`>f XY{ ƀDEAtto$B PÀFmm۝ 9yʜ1x-v#i%bI^XaDd(<ӧKKM144".."6N1DD" a !1 D*"fݞ~aD*#<?F)DQBiLMe$644511&66+3S=Lqmmڵk'Mtf"?‚G9sF.Ʀ!zJ$t8=7FvPBe撒teuz?3JR"\*TTTh4`gTs0x86ˋzF5^|UH秴18I~˒[}usO7˔YDIzRgTT~L~MMAGX,0A@S0`0&~RufρV+PL`6!`V14>l1366>,,08b #߃#GQXR?:.eEȊ 33223256666vwuV~s8pZF(QRƽB 2@BHT"e=K7645{zRR0 ){^  7BhNKKKII:nWͭBO쀀 YK`03rm6Z][gZJONGZ6[@3̠N!~u˕RJЪT>zLr]f^Wk4 B}"M11116aVkYYȑ#[x*P/455 a!V d:.&&F.+J?????s$>>>>>caGmmf+++y>''eٞZʋ$h|>x*<B9ڰ!2n iiU1 I!Z[`jAdd!Fc_nDŽ,1wLps˘#22`R*{h4L.K>tZ!_4z# YDT*CC}K,r8Fe 1d/ȵzy{Xq]]]UUMc+J90a\.i8',vv8qؘ+`Wɧd" Y+Se hIhTBꤩ3drs- **ib=~k11q FczZZLllLLX'JSSSiiiyyݻO>%Hh09> !TUUŲ,M_ZyT)S$&& !E'555eeeO*++fB0 R422(bbcbB}bشis--NS&''gggō3&<<|Ə1ڬZvv(2ҔW**{y4 X.@>, v뫜,K:P]]'LMJJ jևUc[$D!+rɔ|sgWyiBBǍӇG;DB!h !Dh+K 5f񒥋-̼xw ȟ\ܫ#2T$S'L:.!)[g*Hx tBgu*;]zDѣE3gxONNM[UUvٳg/Zh,ҏӧO6m ̜8q?M}9#^!XǏ;v.ov=::jQXXnٲ%!!!==}ҤI:NBPl6M2eժUۚ뮻D)8p7ٻ$HIIP I` M1\2lwhj\oPY|eu.ݾ~K^tcFn9oIg/UWּr=L< ˲׿6m4qEzB5|B!n;77wYYY>eڻo/(E.znڴi ._[~j޼yO?eٯzӦM Sq8ܿ|oibTmds\+0\m={⢯֭5mr+-LVKy!+Zt4# YA`YvM7yxDp;47[|G^$~_~322~i`}QŲl2^y|GE7޸Ԟ^oo[oU(Z|IVVw1hJYVիO~뭷E.eOR=~Od4"(777]cΙv}98@%7ݔσ7|_/b?Ϲ~QO^d5nXǑ(''g~~~J+##޻m-V˦Mϝ7K.S2LF3Lo:L!0Ƭv9껯,+0kE嬫ƚ;"&ݻbܹ111*J*InUq F8rwU\\YVVK$t(R D"UK (9*\.WSSSAA=-ܲyG~~饗׿\WA@"GV/ P%$jnj m0g]m /6Rn˦lr~s:"K_ Bg[f"].stTUYKJӥ }v%?S1!(BVdp!N#kIsM} 'N0 BHA-JM!Md!z<e!`#y1ƶƆZ06# 'PNT*B ) BBH" ZcxIjWF&㥡w}w05xj^Ur2Pk.;>XnHL [P\ Dx<+rO5g*"BVdp,yXR1kэsnZL5%EUs+erWOѴG- yZd0Hr 0 N"'>> ä<0LPP7P'E9fNtEE˲fe2Yddd|||ZZZll?q<;mG}}_~s e#yDEEw}N***Yvmkk+4-8k#""8J^^^Vq+!qBv czꩺncqI_q㼽{df*?(\!8DnS7xZZ!HI 60 9tP DղQ9sM(͙Chb>u45頻66;t Ç T]:]7k;; :aa/(dE. RS&NJ<QBQcv:*++v;EQv3 ?:e %2I!/HB oJ h <&rsaJOv"C|X A[,2a΀ 羖ttv {01A *QȊ 'Z~Rto'm,:4a w-3>{ywF }N~XVV6cƌٳgL=3 su͙3 )r>|'/SSS[d2mذt nmٗyn"Cv?}m駟L<믷7xc˗/1hryyO>,99˫/Tcq{.11QPݻwOW^WIBttvvZXbEvv0_k-['XZA4`2iطrʀWf x ` sf|}cۣ&ء YsJ$W [|𫯾:v؇~X\233-ZgӦN3 NzGƍx\.={vggg}v 73N8NWd1]n7 Ad;h0CQ(,! n8|3sD_XwQTrc|Ȉwb?sD!+r͠cy"ԻrJJJ>6A566޻˗/ x<Eq˲'N6md)Tײ.B"Z[[y+WFeJ~YYY'Os'd9Z @tRR<cafSRRRHdcر0oh .$pΔ'Tr⭖c||aoD!+rm(q>{>'Ϝyeee "QBl6{SRRN'BbX9::Ommmioo7LuuuDn߸qcMMͣ>vBѣVbhkk볁¾t}7B0: )Jlx  _#gsR3S'zDD½³q5so$/缆L~BVڀnr#QLbY6//oǎ~HKdX8nϞ=vz衇Nt:?V~g͛rlrQj&LsNB#EF1㜜[׿={@QTGGǹ60mڴ^zp쳩/hT(2L;ZJR3BSEQ& <~J3@Q A\'B Ղ NiOf8VP*!9NYKE"<ֹ6aYrrV{DNZyrxK,INI\3B(fÆ ]wݍ7(J!^^^ӧOPv}Ǐ8N)nllddEATQǠ̙ FY+!<# <uu2w5jkA*fQȊ 1,lǁDBQ/?\Q鰯5ӝ+{0 x9s+ZQ^C*C"صk׎;vŊ~~~|Gt^NTBlmmk&G.Bq!JSR t:`ly?aaa=P`` P'p ? Jr)Je֯__]U n}oV0 }/bԩ`$DrI]DF3Qku@?p~s@n.0>À Uc;L~~Qaa[ ""fc2*˪ D!+2ӦM[o}uG9.LiQSj4oB!?Z_ fhF"Y~'5UVy݈ޛȰh0v+ 8w!TXXxرV0 +V8o'Lm۶rА1qÇ[oyEd2Ų۝d„ x"'--盯;u:P 77СCF^kooM&SBB#<"4 c|jjh|w ].Mə%0 Phw E;'(;11;i"ɺ:;w9g”ScΜ5 8EqCI 6CIIpjk@`y@&]YM-A*SQ4Hep ^^Z_[dpΜٺuKJN<%uR6MS<Ƙy$ Rիo5w :B 4MS4MQD&-;yd&߳lYX`t_~W (eYa,H$K655w󐐐[#B={-mǎ;k֬3f=+W\z>'BiBmmmv*,,5kw5b@z?q 7$˛vY^^>o޼˗ ~־۷Cr de0|-_'j"˃"?R6;=$$@|544Á_tuХ" Y!a2Ϝ؄11IIcb^yccL;u@3tUI:.- ) !(DS!f\G]eEEqQeiI:i'MJ2 xD~־}mrҒB(bIi OG.GEE]( !1X,y{{z\rlMuV (J.l6ϝ;w޼ycǎ"WTZZ{m۶dogOy_y.ﱿ?>iYҜrp3/6qlGWW<9O~QDqCm ݞB~ͼ总ggLnޜ~xف1YYw-Z$W)Ι;gΜ1ck}Dm{gVP!> "A}?dE6X,VV r9 k!`=`oY*__P*{hmVB{dٱ¤%! YKST\T\z̙3UR419'4&&42Z&|1c0&!0] C(/㓦hd6jk*J-f!0hLl̘4S|D&===- Ź%%%E 1cDEEz???8# /Zf!$P@)p[,@p"אz끜;uؓu\}&󦓩Rk~1IOOH u2ґyUu_~7M,Rz5_37NJJ:hU.@U?7w\9+WΜ*sU!.-4 qN}+!!z0RjwŇZֳNFJuW}~rvnЅ߿a=V|GΏw>'7ov[Y> ߙїΌ4M_dv{ރ<;ё8^h#έXǢBmD#QV.mj_zZ.--VrT, d L,f|>fYj fSJ֋/VVVvwvs+;RJaXRȇ,4Z=ڽhȍðhDQjs%UXbXdnhfqb2yk8xVL'Z策t:~Cck{Z !RaqFB[LKn= )og'Qi"mUW3'''qdY,aUJug8#ZTZkRڅ *Q)*EQ϶0 ,N6,)H$h`Bk})Y<;S1ڗrRaR*ێ71&I1qw>/Filter/FlateDecode/Height 317/Length 939/Subtype/Image/Type/XObject/Width 920>>stream x10 7 q$ xrw2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& AƄ cB1!ȘdL2& A\J endstream endobj 135 0 obj <>/Filter/FlateDecode/Height 318/Length 39220/SMask 136 0 R/Subtype/Image/Type/XObject/Width 942>>stream xw`յ03mgvfV+Vݲ-YƀiL Gyn.6[Q4I_:$`VS$pT!,ˉd+6vgb}YxG2sC!pT!rt gX^(fkmWAɸi@l5Q9yBh4~zŋq6e )Bxp8<+V/… ,YrG{9pZ ubր[*<}ǻ2$۞M D Ɍzwwի?Ӛ+rƌGut:,b"C~b̟?tl6y/((Qe?WۺSO;꽛g9qJߦUoviŸlfUGMbp8fگbs9'''  joookk맟~\. Lz 00Q v 4Mc(|hr|hIɆȸ|;S4RLOqY(f5T]¶]׃ !&1Q6@KKKsssլt:ML(lFGGǓO>zi劢|sTUM$_|^A+ϟ?6=j*]{a^iIiKz ]n34’;sL$#!??z' 4]TT&[o(/>EQ4p5#Bk:‡&WkM2.G:HZ-qJ,=5Ǔ_1ec9U0Q_0Bh3 cͯZ[[d|>_ee>>B7a ǹ\.\UU4Mn˕3Q!dcF&bbN4x͂ݵ% 73fR x<[i:@t4Fx}wo s1gq>fr ФP`{F(/V`F ͒c-~~[_0ݼf`Y"k &:---VZrW\QQQp‰*b+lڬkII7ͯjʕ_cB""OKۋY#Gǚ |]T$26GÙR}ݧ~z̙~g)Į_Ba([=-Zdbe!NURr4 8K6ДB.T.?9 ߽/;k7^RñIC}@RjT Lni{AjG""]hkP(63<"4! y;+ $i^ˀv|*H džbI#~/xIOJr~H |#^kbhFF{($vq+òVkvSFƁ)BQG#9E:j/eyVOС02J?(fE 2(Jb) MXEс>Pi9٪! S|H#JMc(hp:ⱎiX"wL{JOW{g9)L3[QofRPLۨN?.+J+I?zuYسQ3:ܖ[>Lݛ*(rM& ^\\̲f~-z";|GBS3Jӎ;{IلcFcXqQ:dIFI2D%zSh\T:ɑȲ3/<.oA.NiQޯቖ1t9 Z>xF[@KSp͉W-ȥ@Q[[aÆ-[]qew`@=%=QQ#='|VӔW^յvs=񔗗Sd_$.D-r?$BOFٖg_}a帩t2oڴiڵK.---ݣ_q]|ÛKJdіK<=*:<}(ʊ+֭[7}9sTUUPXUU]xggg[[[kk$- PyvdtBe?#jV>i!r4mmm:N" ;LQ5UNʑH)??j!DK BN?𐤥kmy+ʖ_K&3_{|]qOZ'MnȞKӫ׬Mu馛^}ˌ7{@ i 70m4whyݼ+6F対qd54=h+^w?x|+~/tIJ2Tklb}i=6C bCL&J%+?Gy;N>G OX%!$N744tuw~qټӧO1BTE6 yfvEQ+HB8>u@)~"H)H4qjAXݲy˖-[ꚛ{{{98EMӳg3'0"+]Q4VoNQ9ݗhmHSن G9#?L4W>S3Zd)%*!TjŊ]]]_uuuI'TVVVTT$bxN]pa}}5k֬Ysg|>}:TɁdopNf)g)wqtsn[fM#EQ">YFƯk~g!f{u-_|͚5vZii)~-3q[P;OGNv&o牦o|f-@n76yqg# S5f&E6 w˖-|Iii{M7 C9dۢiI6nfnw'fMy MOIR5;8lk$kU.JR=^d7aщNk"=aijrLQ3wuu|3fz8;mٸqc<u>{9o[@eaIreٲe]tQeeeFIo8oƢW~^… jC<Lfhf(YT<|Ύ `J&֯[lٲ>{ѢE˖-#= q\yy7ߜv…  FybYKs*򲼱gS;q&~= 16wɈIZ^^/ xlV ǟpd2î $d4 <\X`zd1Y2:sgr?va@2QDw<>}qߟM^f ,˞~ &IUUYe0PJj7X'95]e7robqgϻc+fî\n\.چ;M~t\.I$rDaۯ&]pPZџYXEf !Ĉ׵4vf,YXǫ F뚑сƞ>0Ctd4Xc_B M,KljnǺ Bh,PUUı 0c=j:he)"ě־R柽]r) =o|k}_3\ ݶ@'˳=;!Pմ(eM-n?rhf̕tWJ(aYf~88`Y)b8 V.Ƀ8P4g$bL&`s@8Upf*m$j0OF'B ucmj)3x ĕrbdgEE1t"z=s#M{28juДCtC꯾L?[0-򊸰a /ar'UӧHLE:,0,eP݉PpC}- 4/2g?>7OYT!2vg8*| ܞJ~\-XЁıf,ް:S'md-jz*h r}8c~bx}܍>0>$ЌY0gZLc/~HE *)!F>A\`Ωtv^2x!"ФE;^*n@3vOF=huC{WC!BW1HB!4Ea(B!( B!0B!0F!BS!BhP!BMQ #B)jbV3 )%{`B!B{l6fq>>1p*/nkغUN&'d!BeyʽÄԃ~9s&d!BNI&/=T*{P4MfQLB!q|l!BMQ #B) CaB!4EMX1䌚{*<w4!JZ3̔2jai54 ksNzIB 0hJr׃.87O}E9SAULot(7282BhAݖ>[,p?c HYPpAq=3} ?"U[xNڭg_S5뎾id6+JC̲r4f[!N8ppZُW H:*! =~3䱦=s_J);#/se# ;B2i2o5j~\Nv?S Qs_}(L7xoD( ,Gu̙o2 >]g")蒼|tקw&b:OXKߎ$!ΪV5\0sh;(Ȇmz*)-ʿrnygXLCzZȆhOP.~U96B~XRc }e'w> D>t4vFgƼSP^iMވko6EgWI"1%wT/K3Z EciYFu3эϮ{ _,ܳ' yv?g5&I5߫٬_o -ƫikm-8Tf s;>JN BQ͡fX,BMAr(l詾2ФD /H3 Vb}چp]rЏ5EjL4/Y%NEL,X6koO p[6p8EѴd]鉮H<$fA) Pat*h ֦֦Tw TMCS@t%N4[@O~!Zg+ꤙeV0ٟh -Almޔ,`Keu5(h! RјF Yו@mwnё'24E C(O*Шq DO4$fdR9ٝ3M2d}{4q3`zL:5 7'yBet*ݔMe?|YRJq ZB[5 z0Ez!j*7 zXUYd 9 c M7]bY/GHJl 3^ѸA ?w}r3A4V v-ߝʙe;͵l( ,`*rMZQSm/y8gHjúojxX۷CWw%TVl 5bD7}p)h~GZpdff`<ܖW2 }lpm| Cf i \`X #dǘ?h}k 7$3@{'׹o\;f)2RrNÔq<[[_Mqw\\W .=f ^nNW7w܅wϛ#vXh;~~{f-9pn4]nw"Tvi2h }}hM@ -ʵN, MW{9EQvq9~Eˢ 1R[j1?vNQam ww޻= \6"M}q4e.+mĖq5]#U %sp*.]=j2gyFh}g',/9z-<=taBpCj/H@F4p3.}tњe5Zэ!sjt `-tցw ^Gs@?;{^z7Wl8m菬άQTID@Ckͽ}$$';CrK_|s&@`E߀+fXkN}៮*:g1Q(=o W}>2gp @vi3S~1say3Qi]W+ -KޮsݶWrW4͙(*Tog\8oE9 oJz"gQ_p>|^Z),k(j$%Q3۰"U>w!ϬGsU|޵LO.;RH@֣w_K)waN#FmM|񗕘Mp~] z:xs 9Z$zo>|*}j?kjt _;7eyچ5#TolJƁ57EC{ڟ8w;<*8.k?9i>QR5~?n+ss.azmU DFRCtUJCohNji҈O?&tƕ!!r}G+}Ù3MN>;eZ>#?Z2ۙv?ΖcEjfp0=쩓 .rZD̼sޜݰO =mAHLsZRpeQ` [zU- FV; \h\0XIE+"G@@-g(w{βXݑxmR''5B@5m&@7D8"MqEy:yDZ8`р$e?MI6IJ&wi9NbɰDSMN~],b fmi-t8`7WzcJ9..M鑐&P MM!a; @Z[T2l*pLk8-i3 RV)[vߐhpYy=+vm .Q6OqH#)ZUokyg?]-[98jl0p",P9cK=+v!rdm#BSm[Յmg:}ڐB vT;L,EY'&(sQB@ E鮲_/r ;A>6.}S -?y0H8>/Le5Cfғ։BciQPΞM͡N`u%jaE) -4A?E / v1ok;GyNq'Λ&"T虉j}[2|o>C*!䐨Ҙ}B!4X( ТK*fsr}KC5h eNUy;;W`)bwqXz[g_QAz[*QRUd9o.w\pruJJF 4iTUc8Rg)'@XF`f{^bϕQ<ﱌҬmnQ|"\z%װ5Y]*9_`X#Iu @R8U-8ZHAY8u .& $iPP7MUDJ E3c(l MnU^bǜfv[ bi[( &z @p a(Uʞ95B>`6MXzb o(xWlp385yh}xc6QA( 1 dCӀ *v#n k1cb,՝ss9n?yPt6E }?t5g)DQ*9OL(4 L;2 E {04!CveTmlɩg '2uhae:!pLSżsn~ mw4a;\{Ns>wμ@zwT64jlWS4&%/tD[o {3\md'a}#-?z|**;.|mVWV4KN/+ңvx,?ge >8Ǽ3BU >fb(\8̋=]G ##7| ]򊢮 *` ic%ّA : B{}wD0Q-ArM:SN7ˡ^ny{ = =J4ؾ p: e`@D435B)Ls~ي7Vxh,B_߶]J!A}-!0>dڒ9mw| URYb9A,h' >/[z!?yO*yLQ+Wb\4- 4!Nfh7mr̛M 푣/ YTޚWrgEsGjCOAx(cȤ5_\~OĽgFͽ_^[Pm i[\O> ~f7C4DAmDә{BlQ!ךbnpK-&PӑTm!Ey1ZG_3 v4A3W(rgs\BGrVI#?9=얱"E(hZYTm [I.͙ ͭm R{ckaϿ2pZc LCغtVo0^1wA}Ɓ)GBb4>zϗ,@nG_2:\ VIzw[Utֵ:sGLy\T&J8{ɮ}ŒFGHZ"6!y<.SBh:dCa9='gas8֣THcxwl_FʁI5JwEkW |ȚϘQDcO;D{WPz$o/c`酁lnS‰sӚj2ҧ(uaF]jF.0@ X>8yl_iNWK$_P }tr+`SnHG^ oEߘxv ^C rC=sShxq \y {Q*ʾ٧oֹum9'\vןWL~ᦞ'ߪ{򭺑:GsOfx0!\pUgӍsiȑڃSR58zH$z+o%V \{ŏvNW쵻L!vb=v!5o8|9>_!`oIWC"}-XRuƻ/ ]uW~gd =/0uookk]}dEK*N\/سv)pެ^?%o@n픕ߝ}Er ˞ Wp弓V>7Y;-_fsΫ:y_fݶ$=u~sgdۜ82*(N6F8WHBP@tE>^7W얊lu%'[!drz9oəX\$I^q?(ǻrYe` DGJDKQoA 9*lYКJ@Z]`)ݹVI *RYg9}kڭgP&Z~GiYԽO.tz-A/*~$G / \4MNE9rLGEYki>ϜR?nݓj M.rX *% ^ [+rWR ;9tO'D쳲>WjwXbPU}j9 ;lQwX(>#뜐6GWQ=gC<+p^b@>I*t5xA;9{uUe[w{bb79-vr $e{\S1HȂʝyg:b9A lsJeFw*]yY:? z)vx,ːѵ8FGDl995ҺAT~X^ ȤR"]!+XOwHd3~3g! ^;d쬅%6v Äe ߫^X_+kSs=vl}g]`+]v;te `9z 'TF"!:)Jys_˳gJA=[ǁmڌ\lPF_dLz>y*~UwZ^!MB9WƋ?esєSR5=RpHv,PB腩0BhB6C$n̴FzdQ)!T!41XlBxl,qRcۻV/gϚ?tA!t8d͝y晊qu12JKZ3c̛pσR L%N y8kNB!P/ӓL^!1d$/Ϝ9scli8n…`0]WC,|G'-:aJ<t`@ 4,Pt]tp[,<% J3jdLdAk3h&;6ԦjLtMJix }ҍٿfk6Q٣xTLSe!LOM;NQC>3K ?P_tԮ̮5?}4G9Sw)?UuJg"MXdqϭI+t]xyyC+B0B0%d5%S xHHeqL6FLɥl90a/bf'Y<"ع{^h3:b 0>?`ɸλ,T3}hyd$Joڦ]{c>9)0/8,{#a[|ňThN־-C`[$ZDO+z~69|b9\4i&XP]o~{6=ygTYx>ܱة9'ebAmNoQW|l$4 XE.[*\F lw` ;[ݭ'Lq !a*dg6_y1e_N?|f08Vilڡ\F[h]Ey4viO9OsAp+W`Y%7|IX$/- ۮ[U3`w~qX\46?C 'nR2Y5mOݣlV \[evB6 #45c)\S]6ªarV6eNTwx:Rb 'u{p| UPLu?a#dKOP6r}%59ťjδ^'S_kZ! Y2U8~XsBK(li.meʦO~KO_./poJ`gv͌㳶#azXz<=`pEg {n.9R!k{Ekφz]oU.d*pS/-]ߌs?r ?7+? (V@CSa&5tQJϖYR8B9&rZKi ii 1["fGRǂ2{qm?{b}dmL l$JK^@i5K+y~T`C^fa~ؖ!gj^mIPsWڷHkY*nM9`O15 -{HlEX쩐f#|L/q^Bォ0BAWh*ch)Q#ԭ;V%aL%j0H0%*rhJ e8 IJ(++A0bf4Ɍ$[6GBH5ޤRV*|5BM( #4ّFVQ?M` "80Fhrk}/ʲ_=1Ef[D!ta*ФEx/ͦt?iW.^i If0vpV-d>jXJ6Bax*1N<"v) 2޿mfF*SUV#1 Sgt.5K ʸݍDzB:UA! L,@rn>[}qeuV]}om7^f8(mK\v/?[P^6̮Q6f~;H t9[}q'?;ݾfͣ7.Uy͌v[!$073bC}q6BMjKdt眏%fKWZνdRȴS Q=J}}O+q>p O;}ίqog9Kt?oF.\F[*y]<]swxeielY6B> #4N_Ÿr$<%d`J\V._8]ܟ߉DS{rGSaw gԓEޟ_̨"O\~E(atrGYSPL굟}/宑:)pm$y Bmg!WOb^+Z֌XӦIfJ)j-vӉe[qD(/sVUgݽJdx'L@Gz_Zlq28)Vv\&#q,e)ACSa&=9w-bjϢ<%n5kO0ALܫ[C=+``hJ1(:Nw溮8-B ,b5VJao)@6T*.~&,S/ 9Kq@s}BQVLpVǩmEE79E1[lCGMs8pX˕3GꐦH6wƅyg@;H{μ;U| rC(": #>[LMd>}"~[)٥j2bʄ W $9pbE!4c!ფvl4ǭ{ԀJb6nvV- 3!:,W!ؼH(vm6v&Ub4EWl2< HK `BM #>cO'vo+ u@**P ޗB&'!YNYTmt{V `= BSaa@!p%E ! ܮ^KJHljBhrT!tNt?|a`3Ey`kOJ^W!,s!BhT!BMR #BI SaB!4Ia*B!&)LB!$Ԇd2i0@& EQX*TaJ&3H9B3( u1a@I&% OE`f*48.@RUQ(kSI&U=6Kq)nḌa16%#t_m@x\4 bZ̜uߝ<ұ}xҁ Bh uwr? BI SaB!4Ia*B!&)+|0 =D3)D >4gLfjCJr2:8S2B!ttTPͤ._F6 # ,j`pµp'V{=Y{'hWݳ%C"ʲ|ld­6 g,!QSbLKw/0AeWMj3+n@[|2ݵg ȧ=Zpr.mQZv̉.g~1v#MaB訁8ROWWqdim3l0W:rgZɮTu 0`Z&nY|TmKBNͻgq,D@dt~Rt(ۇBc&d=μⷻu{yw6}Vfsx'9e65ߏm׵'83k\נ;%ʏRP~Y{ Q_Yu9oDQ!Bv`%z{ֿ'͜_;O $4P~ޏs>Md$ubE,'~Ԓy7T|dP›&^㗝 uZ|e_1哲aPjLZw?U(ݺwX}gHrcH 5|C#ɔ!M2n(T=v{ doimdfy]C!Єp!nķ4~E-jrȴ-yr9nV߾%0"_45G3t/Et :~S`a`Qe5ψ'~ғ3EH7ஏs]mBCM_|Ai~qWN홍?ӳf:0Z6Jg8(t: !;cZOe~fDX>n \w5p !:"0* 駖-XgC_4W~)U(70Ichͯ{:Z../;;'6`jOuFVÎ ji~# y^_jڪHó-&fwZHp?rBagd{€mb:g^9gTbW<9Ui˲j4=-[v]'@ͤ;?}C͞uaTUurŝ*%á/=}[m?R"m}ϷK,{HSJsNfzCCK{<=Ҩ \|DVD*@G#Bs&%O-cmFVDN ^ dF&Ktn3)lۀ`OUCj]Nlsco\\p,M&pevWoqQ)86dwHxa!k4 '+\+9VH(" =Ȥ3`2#NԭQU5S3xT\5#o fH05[וRY9m/ - M/mVs⊖-q*uHk: }[PYr=UyZ2)Hﴦ%}Ao#vP+r o(bj  F!&7qRixJ^7o oQr{z,F!&8L T3 SU Oc~;=7/2HB֭|f!{4 U'4%Q)p-rQ: f+2  ZkH)ҒȨiݝV~M'֬)u=Y=0ڀV䲼/^h0n;WF,`$3IXtp{Sm}+>giVꤾv;G7 Fk|i_:=dY %vbDg!X0>T!hS>]Q\A:B;u\ّoe3f2cTy:!1B;0;9ZH2@_H@lJࠀR"m&c8"%)c0= fE >78rL4LظR z=q) ,>APLúΦd1햹AJ(PB=013*,KYyyYyJۂ5ʢqux}?a* S;o嬞s)}7uЬdSHdi Hsw#noK5} M 5`% `d-aSkudd~B)Pod痗V_\#[Bl]tFQn--u[yw<_X^G3}M!`--=ߐ@x꿚\W7}J0B9IzӺwo~s#jdy/gq }kKz=!:jaR"pwu`c>M=0.QJ+s4*2n?&XB9|[i\ţ[4ԑh  itoC4Ž8>L}wH'Kv5 S[W++~]Q]+eHB[DFyvd۱T# ٤^P_m=-ʾ"cz(.Я=ɔdP@!Dx'Rg(m`(ilH&ĀT$Dzd <$eP@iJƴ6m3Ѡ *J4 oϡo.uT2`h7@su2-ÀJ*OvDh! }kwHݻC:eYݠw"dJ -ݴ3jUZpdZnTz3{^4wǚJ4 *Ҁy МҍLjmV63]]TTz23MDU^<:V DJEB0[_0P;?kk̠Y -ﯽw<࢜i <܀hٟݶaWjprt__+Ñbd[,4Z_߿ʷ_zc`Gow^.];75U0 eWR܀\TR!- w"} 7_+;}0CoWpgN,Y*~'> 'Z3=KU몋~'nYsxBQ_Yu9 3ϛCWC]˞ǔ&p..p G1pLۦI)y=B!z|5?t_C7KQ X;ŅEmw\t_[ϽTͲsrf[gLsz|@esw͌ y^Z8 w@}7%ςxp|n1_%ZIhɪ. YJ5Q⇂ߝP8yHtȵ-!:`*w'Q$.9hX )u:uz!K\\*Xr<9E_JJEo{jH#C>+˖sW`d!Ⱦ! 7{V%Zݰ5drzDOmo8ʋ."Ǜ$v(LW6%|{FwF*RO*- F*Ҽ*ԙd);=}~dbmDmnZJHvk3&:Yq,Z1F! !}9gikX{#ju`W >_nw٬e=Ög_k[PǪA}Y2BU@N]Qe[ك/O8T?꒞yt19{/j3:Yx/hDC0> $JE HkTCwTusr#*gFj8 uCwL5Y[;x~1S3{#ұ}xGؖlO?ϩŃlH1AiOC'Q6sjçUJxGSӱކ-;{CRaM2%I1CKvF8yS[o#'UeK~aD@0t+ټ56IS$lܮ&=9^ijU 24s D>PШmY~Dz5_(:cꚦ3XsK@@p JG>u/v6gԴޤi_QpTewٌwBhVjɺH'/oY^[l؅}\e$ ϙǫ Ml -ʷ^UהϖJeПg:r1L\fag'HSJ8 6|$Dh&XVWDs]G *$ ʨ K,َD(,vc1Bؾ|5׉8zzq'LX'A촾H4XkWS43sس_|inpD )OgN /}{Kݝ,% 4bxvv q& K-}%I<<Ѣ!ES+/;;pzNɸ;[VnN斻9âcㆍ>(t:;;{UUv/]IJKK'P*L`̞WEskGބZ[Wn)q"w^e۶m۲eOoChڥF/VAzPU 9v!2?a tb&d2MMM$\.Q/NᮮƦ9!~Ί g{ L׵l3X^0csFQs8]={a8@bvرjժG}tƌfͺ}>'^m; wQ7>2>ҡ1 # >#MMMzkMMMYY9~Oz=^~CFNJL0K=Ԭ%Ew }~=ܧ~Z[[}oΜ9-[쩧D"'|׾?_ʳ󃪯.)*$GeVUS;;:~;w*r7n K<߰aË/ؘQ3)NfxQɲ\\\Вjnݲ+EQZZZt]7nt6s;ر#HKD" ]]]R:}Q)5!"֬eC;AtDGKj|OMݩddx(^2dUUwKXK&}w?!uuuw?UUݯad&Ԕ?+#}\sȿ>P;r,|M2'gV#V^*hDt:">^޽;ԳʊB@`ӦM5nڸG4-++vʹQ !6nܸbŊ'|rԩ-% B|p҅QfV9Y3bX98Kp2Gl^zt=SxWYY)2!ۻ࿷f4тvb71)cqK ݦSI{&7`BmS⤆vh}ykц|?!=w{ȑ#v***>}ҥKy?:ue°d$&)݁0e!OqS:CRwNv^.}ɔ)SniP>~cx`ҤI7h&T?4pZjܹ^ɓmf-YdΜ9_ph8-3kBPZ#N <{[^NPwXKn=$r--o}se.qEx*˲߿{{srr:}ol6Ϝ9p…ǎ;sѣG^ywYiYAAͳVcB9OLz̢k"\(sxEC]l$MVEUTT~˖-+//g}Ů3DyvJ,o9FH'EFM&S&b,fˍn^,L:Jt-!qYZN⡀b*F+W"b,z ͊斔 M)##fMT^ :H/wY& 7_gYU{ FT1!ߚ1jdj"5@'@ˎaux<xd˖-6l5kU~۶m B999=>L"H-?Xؾ#$-UUYNFqz\UU).,K3kO%oo]'9q ㇪xvB8iWrLhox󁏘{e $G9SgcS K($$(1Y6b|oL^f<}1 $-f(᯶!EQ !"Ă>yaNpXy`\(\A8G᪟F/OCģJi8q,l_C(Nֺi}~{ײMNɚn9eF@*fTIPZ|9cID ;#`~D!Szh?m\Su鍸AJ?`IF>Ub:=9&vԽ?JhJQo#F7w=}]3L#3z N3ɸ Ly.PLu0|'?|MYcaV jgߨ׶̇lb /EdI/U) UG6UipTY}~{~aԷ"n0v,Ă]-1:t.W/ßݴ6Z&IJĽblx`n-؂p:Q㱋CcOvvi /Mۄ"Y^YC6vƒQstvjPw=s6FrWtyK3 !N/4,5: YD}]P !dgPҖY^ĐA}(l-Σ:T{6 00mƕOCiRaHS+ pDUŤ(DhJciVTA* pè S'u%x٬rGM2 H60TB5 '_c*#_k5znڬL)kd5Ѣ'(60HS u UͿ;LL|C)9c?nVIY|-M!]HF*#{wtEW͝?}Vqq?ѻ?}YU_4pȅFRa%B{N_Eln˳%sghwġOz^GhR1@B* 0T"!"%t97d扖 i6fihS\{bqQUU+ 0(BQ,4vnBCUs7u6bGDVF5N@U`d1gpA7ޙ)Jz〲0!hX>oD(eP]HFM3J\=;{iY(rPFLQB *X$I4M46P(fy#*p+<ژLh yjl 0b*(b2v{c1/xBӗO,Z~b7A4g#6 Kuuu=-[lq̀b r4XJZ 9w*7n/,59 k1X`0F#0 $I˥j1rCUxp _:[n ZSiS]I3"ɪI5ͷfOe00&Bm۶B~Ἴ+ |#sc(pxᄑg*ׯXbӦMNl6#(e-f Q$I---d̬Lْ` LN٭%N[UYuvQ-ME 0H4P0L^^ބ m6:H ٳgϞ=sΙ3g._|…ƤϜ EUeNq[Pl[u֏z4J) pĉ .lݺuʕ ,1s_7)4SaȲL&;::, /TEv\<~ppY R2Mi<VEesr5atOI!QAi`(,`G詯XuwrV^yuLuln@3 x\%*C3zC_(Ә3'0nl%ɮSʭh0T UaW_j8TRaHSײW`@URaHSH M!4TRaHSH M!4TRaHSH M!4TyP endstream endobj 136 0 obj <>/Filter/FlateDecode/Height 318/Length 942/Subtype/Image/Type/XObject/Width 942>>stream x1 0 'R7E,1Wv B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îaWȰ+d2 v B]!îq+ endstream endobj 137 0 obj <>stream xݼ XUU8^{ssrsH 7(`&rr-Q2 l4rrAS8Md5jk}8}{}kFyՈE-=BO73˪KrDg!-m_jH*[T}B`SJ>H EU?8öRߪpzO?XmPzHEu2\pk-+mJy:Y' 49הV\r\C(¯tBx{]n̫;gM0Y|i{\EYG oo1Jlr"͛/;5_p)?D=,8pH@}ndOVG)DLiHƄȂ"?l(  CQ Gv"Q(Ʊ60QQ RH4 Fih ơhJ2P&P6Ad(MCMGBT 4B%h6\Nt68 *@'ux> }עﰞGA斈ۊvAЇN#0" W'{$%8WqYV p Y}mv6l-1zmFWC%9t|(Hϣki0w3: vx-:@zt^8K:/=ҷpPCDoKxށ+P1K"ub\B" btF:/VMjqV0e] p#P(K@s9߭ʷlFomœwVy!fg%z-Z!mQ>h?|I[H)xK(ǛkZWBh~FA:@_ȒH#uy{o5hf{͛K`i)qhO~'N/w`[v 6{At@]A7gg{l~sU55^{0_z *hX!=m  ؗ9=ZAD]纇#sI>#Q!mx]l |Lu(i"hV$Ld7ם6%^N)E,)~QxQӧwчV&`!QEQ |İ%Ȫ> @@WoJagRMBPt->&+<,4$8(cM^FN2HϽac;7n\8ݕܝ ((8"R#HT=W? {*Uk8k_:i)MKw҃;Bv;WA#-w&"3M;tD;6>5wVf!x `if3Mm\-g\e./rŚfIXmp#'1od%0l$@Q)6NK 5s5kES9.?u9{g<:EIkޢnL׍cx܄L~#_}%!.Q߹:KD$/cQ t& b &M>m83 ѡaǘAw{͗4F eNw?%y$)kFLIq"q 9~Q?mIU^~冎Ά6Dkl`ZUմiK6tlp6 6 8=iӪlx1)!1}pwgpc|1lXS;M'YBYlF/8,^HAMN:R>ʆ1eXҘ{8npYwhPIQ+l}CZ/spo.+ ~pF0rw Ғi_C$}hΎaT8i-*GE"N\;AqwQ(! &)S/:/{7''9cWf֍9mn|pl=;žy%Uda76}|虜l/86v͙m5fyo`&Nc/`Q"݊Щ:& Hl&B{{i(@ -L̻ɂ-"M֮]eE:/\にap5ؠEp{[|MHk0tM]E S8 wƛ H44@<"YwUkl!($t^qzX\'a/qaxdI88 @.;<]ptn>Ӹn8x ]b;=ңbD F,{x/?щO,fg%vN4ߢ2q(Y{D?Zɝe8 ]W)u ZX `9"F]<%aX]`%0pk> :P pP/0܉w w4Fna7-v˻5u Ϡg333gt1EGQ(9*G5GGuGG 9?SSSSsN[ a5)X֔dB =i#GO/H=uݖ͛lݼy7W~͕+Qӧ'oSuN#(M_ӻF|^7r]8ӣh/iviQr@]=\WX Haʊ4:~)cA>(oB,[CLqv6 Ȭ>i&CB=ֱcy_xmɳ#v*lx8gq+uNIƸIxHul_}ku^-fF߿I0ay{ʭ|O 5f|8 &>~ͺ}^rf6yߓ>EHd.<u[d ʒp", Ed(16>v.E.*eᾃڹsmgwV4),m"1>篢JѶ;-nX1taW2ᑺ0ct EH=At*EpZXNI25۷87|¤}2IwcUBG@8`:z/hC8X1^^Wp||R1C!Ct>:<p6e Ch3adAD$ hBͦ-v=_'ٮCbMN£XlJ=sHǃ3DP~E Ou/3!qmuVx蓧Om;n*=d쬗F{4oܙwB0}Y)5-@uCوQ<}W,Q'*N"4GraW/Yf͒%[s-|w~ȁmx JKJ_1>Lׅ5??LM t߆6n鵿O x|ԣ/C5pIuzG⧦)ȼvR<O-w@K `<G& ` xa%TSgkzVzE8`>|sУݏE@Ԯ׵[7v-p !0)9dY" <[a1O1}b|7~7_ݿvt >kn^?T+ܿI(V~f3,_6AϢYAsI6rRC?7Nr뇺VrᑣA?'p:c)g:Ydnjl,nu=3 )-xng*φ:vFnI!0sa\A|stDŇc-9tS7Kt?=޸LJՐf?J5i@Nh]KHR\,]]}8I [{녣=XS5dž!lQa+:Dj{ އO3RqAVh3"0A  3>rjT Sm 9KTj8KEڅ8tSoɓG_}\1unǵL#L˥g@|mǑp2'WEQ/pl;n9"4|`‚'|Gm:-Ğ>\W{^2 QTϥ$C,E4h X-Ic&l#NUsW7V/QVp-(i3jMvFNf@s<|3h_(53 Vq.V :w~I+xǛSvg֡¦KVAeVq?' ܇+UFlh)Z;Rf%:\j֮y j$$ 6(F41$L'i D3K,'wkl@8E c׽GWhN& l4z{ȕhl[EE~|L h3^ Aip%,z%y)aIW_O:<&=FC$^gĦ EXՍidvۤ'S@%j&xwzmz ?\bz&>WsnȺ kLs R,p%=J7mNdX0aM њњYKXik2 ,\y^+d~|" X+j3F7՞H߼'y#|hGn"~m(8RNp<ڜ=5 H}ɦ ;wlذcw}O%;8t5ojpOAqnFƭfV5ڂt)PDx@hMT/[ٵc޼Rb֭۾?{ޢ~i-v]%`6PqL*^R6wqFb)G hl<Z5A3^lZá`L36ɝ.`n';GCBDr"ɔEGD6 dDO,(ěEp_}1)T y4ZǘhUgzl)^5?8mE˧kX~mmOxٷv͏$f^5Լa <sQ68ô:Awe a"{v ~=.;,; =W4{/$|ڗbdq>^4`jD#`Uٞw~p=4YcӶ^^fvJ{;n]eQ~߆ {/7kӊ=w Оr rԠ81H / `x@qyZ>k2NXu;xc)2\g3|}E*d%5Fk~h7ϜuwzZNŕ'fƓzǎ76pnScnj;ᤂ X!^sbV@kAy$ vBĶ6 8@_{ّ+yNJ/Ł#yRm>qfAu^G=SB?(iA#2b2f!Tj AkdDAՇ=`ÃE -:HIg8=+LH!Z8ۤ8mLƐTq4V;F70XgJwwh t%yE c3Y*6@9-)(:ٺZO^8z໳HdGb8ٕsWSu8a`'O;laAb'" $DC:܃8VNDc,srK6aC(^hbP+EJ w 2=6iMZ_!H{8Ð Ylm-4f\!`)*fYx4_xO>W )f\$6v&JiLn!!5H'q?ubKާ,ũ](.cRԲ_9 <$ږ-ɠBAm/籚KIqAr H |.yvNq{t~Gɾ[œ&p=[2dzxA",)~ ~oicO><-=LA=_>vX[M$6/ 앇.TֆRT"Вo}k,*kO&O/ p| ^z*2~ F?_ֿ7&a 4T^8y:x;J^ѳ?Ɓ;nw5(qmY дX#6ۏ b^6fEom+,t%+G!蹢_-ij%4)<ɞ{=={l{ j1RSSy@SkOvyCO_߿qHB]uwGo9#&0y+ !(`ԑo3@dN 0rPN(Ж@6ЯYE[+L|@ 2n:fFs F$zfVS'EǔG i;xpS Hã/|FrƘu擱_VV@ɬEBA-޾-ޝaba5b5Lf|a"S2E/u9 ;\/}{'5m\nu6cQ>:w<_lg4~n-^ND1eb5u)0V]dhrovTy8(j&|zcՕ'7w6{,̟#yi'b|A#kflq z[>|4H'^&/%CdV߿Jfd+Jsl^CWu8ge/*kI$g[;Vx,ZU 4u%̿DbL'-&I1 K.XY]$VsRSȜ k6lmݸjC+Zgˮ!{9|(!~sZa|;ez:CإC"3`YCSoEꃉ N{WOpxG'd ct$fX ve->D]VV &QF]]xyWVJ |/YZoxgJw~v};)9 r& rFK&C)6pqZ{aYBFxw']xKb_"呅 R6U!BT  Mv(jƒ4SHf<[Tr-5͚[*2ݝӿI~Bn}{VtNo{v~uϮsɏ{v ~ t?ct4kŤ&[CeGkk7ѳ{(c긋Wn:'%IRI&Itt[z@z`zPzpzHzhzjZTfhWVWZ[mA!aQxLx[)<Y9eC9>6%7#B2a +>]% ƥ+V{=z'ث n&q`2s#XQ":)X&p_w+)BE}l-kȅ=`}t< s[a]S!}{>AB,ģLl/$:TsAò_d!_^A6l=%[fW藐&7B1\\s/w4>x>YPHGc Bڽ;u5zYFZm]* H{{aFflؑ-I( ,NNt4O7OXa%vܧZ:4'7z|lU}tM-2CxemD~Z,bӲchR)s5odP%\*͘U}(xMb䁅Dy`Os_iKE/zx}bs Mk#QQeW÷zNZV pg= CzA'rރ3+|E({Mg>9o=Z}iaA+[72۟Nۿ,BxJ7'U>ѱ'z s{(u}4V `?vB MM Cϋ<0}4R7kd \~1q^ 4(wZqvZ1/z;4],%A %kV+y{11:#,6+d6ey{{e}Es}b6yUkao>naiރic'yYZ@cWwi%גkgudY#hpbB0,2޹T>w-8(aL~]b~J4{E\u30{gB!$\$goMhV3r$dv)ѺbmY(#}J>(.|磶$W ʝ&?B = !:_ѽwyQP#"{xIr;N GBn$ȈǞ(5r/*K8|rI˄ [?3e5sftߴ7ַ}Y[xdk`]?[i)??=7䟒C@Zn}sT#hMd'(P0:JC!A~&S_UDA~ rY-+FI6Q s!eښ;fnɚK8[<Β-?n۶o>~@wĈ!bhB@&C 1zƝca;T`@ ><`]iR _bk;*E/FMzHpI?ja8@zh NJ/Rc4Oʙ~OAoG|KGh 8RA֓] yCO|I̕h5uckerzFߦkpjnc|WRxwiYo7o47b¢-Y|B|Vtt_}~o/f+g{7WV>d -ZViJZL+Y؂${Ɛgm<< Km~AmK]m[RZdjۀBjKF#f-?M䫰6f- -.Rmm ԶB7j["m@cB-nE)ZQెrSkT VtoFk5nOÿis ҰR.1ޭ|)UWyUUiLEܪs2NϏG3xOԍmgrkjI,?17F:(Q{VwߌWpe *nQ?/ u?&>j0(6pV(AT F/EĔXy{kcG\ND LE݉F&alU28SXÿ E<~*݉}.Z\m1.Bi*3hG3T,l0=vgbXǍW]~ot`?/=8w⌼B F)Uehbم&äb茷fdeO(0, |H` 03yyil,ΤiG32s @JFf^21/#wZ=+cZƤE0~v 3Eӳ'10{b1 Nqt'e>:`g l9f| ).(,CeVnQv=0SX2y F '^/WQlJ`VvF,bhXЮuLUV#wZ8PI5`Jo>eȣx~b!9^u}vC4Rܯk`s%`̙,laV{ U 59ؠ<,lgb/mj(WCխUnſPr9ֳx1)VI+kE _`o&,x Fm#M w%%דɏG+Z)xlZ Zz%Z:\uW?Ky|Ho)&\%_n@g7ů&///%|,σg\\B>G' >NH.R1%}'}Dɇ~6_)?Jr.Ώ!(ym%oYJޢ̽L?y74%Srj%yW)y;.JNPr)9F#R'%zi#Oŗ8摗9Lɋm5CzCp:t<Y9"&J^JV'L&OxYLJ}džI[IF~K^Jd@iYH~c&.JEdPH;F<"Q փGȃsH#8O6v KH tf`fB6Q _gSBڒ)dd=+Uܳ #d7YN2JRhL#b4)Sr%uImzTSD*J$ŔT&dRN%e ä2J"0R;)? &\dk×1_2f$bJ()d:%$ix4#dP2%7@2NJdrv4Ip5Er* YБ5L̴Hdbt i! a"\9Ӎӛ8;jJ7t#INK@x@au2CJҀi.2zx4z*EaHJRIA҈$N)$dJA$)$B+1$#dX4̗ زfCmbm)`m+b)JI %&ϔdDQi2ID؇I+} J`0JB) ކP R $AR@ r0?%aL|`/|+%ܒḬB LFd"&w^zHy xh#ӭQ=PDOfD2%/!@N a u[p;?6˟PS endstream endobj 138 0 obj <>stream x R@?-""%KdkAhF3_hv6ԮvkhjÍux'dtg:dS|tLWڵwvnsw=azܓг{ދ^^}ا>ܗhZgf/ endstream endobj 139 0 obj <>stream x} |EpUW$t2G'!$$\$3I23[QE ȲDWXŨ+bTW=}/zueFҼq%B8K-{Sqlp."$dYTaLGH\ /Wv`WVϪi9)x?2°C#KxUmMރնrCA+BQ`|p]VY,G+zTxns[2cv>ǰ+x>ϋ=:$?ғ@z' H#:Qį&gi_)F IBCpQp]ݻjp."]MM7voB2p($퐌? ˴GAH:`BQ:Ψ Pw@( zިn@P b4 Bq( F hnDP"nB#h$JB(42P&h4eP> P!*BŨCD4 MFSTT +p<@ukh@P2 ze\Urx.E\/\B+Z\vtf/ċQ- (a04^#Bq3@ԈB Äl8glv2>P-PPpg&@{8#q-.+Q=ȗLA x7ì"O B>@xIFa$` T/^t}M\R=Z4 4s R.'B.3xFG9Kw`OzNbR=.N*,cl^aȸ 0I-Ԣx#t VW+Gna#n(yKŵLc(Zڃ뀖>@DHڣ놖 ]zg0R2 -Cې kNQI2nJ;^7!J o lkj/K6I]7hMbtԉk 3& IOЦAgxh'4>ƨn7tR^tTA3}N5.'ІGG#&' >.8t}׃7!>SOLŞiNwS*{i56Ds8~orñͅ| 2dJLI|h3*8 QGKΎ{gOÛ1Kށ}%q,΍<'B:.!Psj.{օ@V̱;C)vCCt>D`Kxo)-?'[]On;Ҥ̏rsG#놏P [e 7 ][HR$' O8%%-(M_{~S!o:`!>np;. ؊B Gx=wMHJNHZ{|m}wݻ_Blslcڏvp;'`_z)kO,䮂WKsoMONܟ|Fo`}t˒C-=1-aZouFO>$r=2`fsU߾<3wq㞇|'w`̇t~Ġ燳t4]s_V0X!4Dy ?;O/;~}:1SO"ς}/w' /ė4?F8x>B +ɟjOj[H? /V3ɓ=yDS ^؅Q >ݝ@[|I<#>qoFXGLu.'Ћ\%0xijY| DB8N9zw#"{b?6<FL!z~\ /]w,(Z_\߀uXC{yӯq!CW/M\2冾{ы<& @ yg; +B/Hsݻ' kzѪ< e@!d{k~qyK ӓ_o@ 22qo+s =[g3 F E&<5~&M+{MO ='oN,~L~o D?z~f/*6;ȧc1nݳEq;[QP2ړ՘UzBOD(*+ϞC/~{}e`?P8vgX55V[ۻ{G>Oى'N0t6Y :t6TPg!uxUO>0O~cq+t#=6pB1mzFݏN;_Jo [,[j%~g-^Loi߾E11n̺>F/*2T.;g| ;ޗ+;9~G粂!|XFfi󃐣 @woATO X쭃mJҦ>Pj_Xf!aoAqq]!~;~#N'e9c[ngY@g {C'՜7bAgxUKxZ03݋GJ&zvTn; Coa=wPnVt+z)-dj,lk&Qt yi_lq&Mcӟ}z G\&zuGˠd~-QɎuEC1Rqz挅94Ϡ/x4F2A}m-0\AIw_3dr#BW[Fב`:̠Mߞ}d/iJ 53Of1AT`4 ZT|,D̷Lj@wG}G>5,/^M;ul|&DG4[ yx)/2ku ƟSˍ(u0`n~Bߥ[GC?1\0b(ȿ<$"f5f-VOW~ƍ+ݸYmt ;#.gX qGjԈt8G'aZAQ߸ .:b4Vkzk{xART3!셂>8L\5ܞFVl|iՌ=ZE4G'M:9ߤʁ<1YckKv,Dh.%,:z)}Acwd:>|\EyKex^t+Gw0!n;!yz=[j|)sfO[v2w h…*}X`;-o 1;NqݐS=b?7v>hKh*}+n>1N]-X ^Ncp k>:߸C7=^6Ix2 \;!m8Gሡ8W8Sx4 *^q;mQ@ˬu;/YIcJtÔ Bp'&xт\φ8s(~Fi\~@{,vpDhvlӤ_w˃JBvBN4v>LBaBNv#7 H خ]VxN(U( !oU{m<^Lj!Σ*8\"h„sXeﱴk9U=:-g=k*&m]bckoZY*k 9 @w(+ReTUlUo7JpWkW\g eVcUdA2 O+ɾwؘsaxR>VA?g6 zC C{`V2A gaGLvjOdܚjq8T[-WQowt@>o9܍u5yR虁F;D沊5V5r3*V x4UI!8;WܶGд&Ըbu !.g&{aœ +lmVO:xUG덶JݾlNm'i %wPV/}vcW3j!v HC]ZKk|Zd~|_~rKTWtՅזM>Uއ)l6%^^ pئ7igYygor7!>Y,m]$3hLgљt.U*|Wiq8g0Pap5x7B&&XkxdD@GO2cUϑ5Us_KQ]̜Y¨=>*Zjhicxl T_ mvi64,xnGqo2{} 8miXyF73%`͊朳 2P%*+㐡, P5oރR0ZBI~"োɽ?_Rɽ ͹}sIQ,f5 OxQm+J6T)4!u^:wXo/}jJiJٰ_ oA>՜b) w+շD&Ioc|نx}"={^/?)r7̲8i5 S.7T+ *&[_ыѕ0nQh&P5K9?OX&m= cFaFuh$G|Ldd4Z2B*ܨus5!898ӡ=*@t1SģYRNIDQOӡu+lzRzu>7u_3?)~ >6 (iH9FTda<}.Ng2ʓzZ1 <-)VΦ~= <GsJnE`U[(a@KݙR QڊZ / I% -_^m~}S p{Y9Em=X}WJl?ח}u'p($ 6A]-By-!#CIC*>Z; IA鈴Z[o>I#YZ[@B&hUkжhm uvim(ھ( ~(ThD;j v0G]oR ,@fT )PpU Jr@&d@Y JFp(Vxp9 &3F!T 5 Xa9bTkL|K+\Sx|P71SmYseKSWE)]Nd(YX%Z)`PN49fUSEi6kb44CIR^eVaRV^SVm.W6lZXd¥rabPaTRmV4Aw @V[ TZZp+;66n85*19fUܚ4_Ilؿ-*8\ZLxY. =~ap0wsp&\.{F@:&iq*lJS^xIW+cšxt@X ,~a2adTfs\i+m$s3rdVZp%-hyk\$+CYϪmۻEf3ȼ= -\ӡw09> wfS3irUr*V1UkTS=eַv-U 6|̬yP5-k8]+1?T{00hw՗=ɀY+K" ÍKV.>ҐC!FrଆcQu2@J.M3-GG+T:k[=U[^ c!GLxQ8f5TfM}=S7{u-, hYݪIhhWF#ߙ&D9ǧxW$5y,T-]f{8aeaYq>l㙡޹EWg+hpJƼsG,.kkOd{i7,;k>uZ fq)T $kT/X?W"N 㱘Ρ c$oyqb?9k_Oy~NPqyh`lfmu+ֵrjۭWn缾;crw%fLkW}[R׬wڭ7l۱Z{ޖC5t6W%6^ښ+|eMk{'Vy1ʹޥ=w|ߴs;ۯv|{иŸZvdN="?>L> >dRLն}cѻX%zʩ-ve2*EIvfhQ?MF[EerWg(Q)`4Y 銭J,orXN:S29L@a1 ;@cJS),nr8a3 J90-Sybpe;O$WId_@fT NlzV^c1Y]\ F0 J5ٗs06cM1A0sYx[M3W'3ͮ*[ 5BCU%q<'F2wgUFs͡8M`6WfZ;SKVU ͬǺj3CE M|Ѧ8m1lz|jp6&Pj439\ e&.Ef'\`ˬbouLqV25`JN¡XlSb+YvSŪLfAtP׃ 5\rUu,@ ૦!ir6*XIC fxq^IWm-؀=k,2ab#e 'S$':C"F7*7sqfVe(Y"y.g^b'3^/;LKO [wVnokFFýVM™V\7aY⫎ZlǨz3L,%f'tX-6uSj Xq(ȕjlfU@ɞ0Ô b^vmvh@iQiI*yzV,:Z91[+l&:W_+S*Jhs6Ge"˼ͥRSj:Hn_YWAZ/瘜5`Kxj%VU;ao߱V[j%WJrWJj%JW%X!I^咬Ko*V߻d67LZ2ZɤIdR~M$Y2)dKrF1GHnTG:R~Ku${WGʯ6#TGY[Js#_Q~A#_Q~F#§u > r,bw}p{gFWXU;ka8`yym*-c^뻜D^y?'Na("8Gn$5S kX`@;܍vEõ ̯#k(A5?6݁_@4'&8/HM>6BzA!pM>Cp;>ӗ_}?͏JXUPK$̯(i.iPJ/H\! t)Si.I~l ))%Qros=#Kg)9#3I7e8rZ&_7SK¤S|@l '$%C|Ng|@I:n$t"VvGhh!҇a RD?'#~r&x_G9t0D:ԋ-b48@$%PdIG$)I1f W Z ?W endstream endobj 140 0 obj <>stream xV@{JVD"٢l&Cx&mk{;h ion`pch:މ;٩&:ݙ6T:߅.6ݥ.7ӕvflw\~zأ-Şj׽mz߇>-}{?Ziٯ~yŸ J endstream endobj 141 0 obj <>stream x} |L9;f!r#b+L$dRK&BIg&!TjQjhj( --yZj<{ν^~?;s9ݿ_3!B3A ]b=3?•o(^CG•YlSPn> ff?ڣxB"ܣ-k!r#;$)ښc22ݤ+p&v1t+܏̙UC6\@(p3ɅW#pC鋸?G=XXhj@ -~naA!aR ơJZ$,rH#Qċcdۥw⑘7AHQ?\ϥ#\M-RRw?E1|0#:Wi HkkEmg=WΙ3|k"b3w*!hjd<'X PF>h7C9@V5jTP[0E;ڣ#DQ0BPWꆺP@G8"P$ң(4E4 C(ţ$RP*JC#H4 lƢqhqӉHwInx 11]PAJ*CxhDB>1RBߐc*K@mDS?ta3c^fX?< @QFk fa:2TcY'{[. Q[T*n)Z1Qr b4*U5@Q).g{tYdg 0ILǕ蒘e͝BH5Id)[m ~6 FLfX߆v. &.tvK":F"+kpYT.7$`v!(Ƹ}Q]oU)QvewmmHivvh<,qݮ԰#a.y$ Lü>1ۥ /&}nԨś_\d+qF'-|fג/XZZIxz˗Ϝ|W{:w)|ef?Q6AB#ٔ>N-5~>́ox]#CYfq[[C|AX'4i^K_RT@x;w|GRMOp CXdܹL*.Hs|{"~) %+onAԡ %ALfOzF5 ߼s Kdx'.#Q>ATh &:u_Ae|C+Dž.Bŵ> Q(+lCVGoA,/_@96,Kw倫ͣBc74K>FI9HW߂ M}Bx7:@># ]xEwʕpI= 1@{uJyԊ</@^2-2-ǝ>< wѻOTrij -[8ljN”-8+d$u^ |8?*++'毈T68h߿3V2ǿdGVAs,wzg.WkR_MݙՊ嫟[t?i jsp韂t^V:{yŤBvw*';ۢfmЃ1$Po70|o}Ts L8G~T{{3P3?Tu!W:~O7R_7UUc4iBz]Qt{jvo3@'g,_ក SJKL--0r~ϰuG._?zA I=ݻ~dw'zuXzw Bkk&ȥrS 7҉'μ5|;yOjuZ3- .yʹZz믯. Y\4{vQLyW͝W:c/6s .5~}LW}|YdIG 3 vF?sXg#n5(o*( OCh-}¡C?'A21P={YY|aax@ٿ!8)J`o,4aX׌'o=.$tiR٠u@ɀo=N6lƮ N0̐r \]+h*& !E|dN*78p]l ><40dmc*9MQ.7L6ۨ}}z6v~ZZװP㯄ֽ*mV]3PDоC=pxjTѮzl]fMm<}fA CcWN؅aOZާ85ide̸ͯ'SnszFhQ _Hb~9|zX,+%Z>(ZÄ͆YӦ7im[qa*~9 | d\LX'P WT)oI^d[ug<>bl'+}SY*ndx"\hRz{Ι5k?[ke,#dч͖G +ze?ȳ?Ɇot O-1]~BcVL?c>3)q=Iƍ?lA&H 0x cBjExgJH]oMWt-e+Ks^z ֚5,FUUd7v|B3*]i遂 E殊ct.]BߥLoߍsnܼyð~>=9||:)0i2Ti2 U /_UU`ɾZ0VwhxZ+<Dug~ծY|MTU~T߻$XR<'ڧ2IsGn~=+hJX\K`݃QV/r G& ۥ5R$ozئ&35ׅ[aǭ6՝ooQsGl.R߅޻t=NyxXFnvN@8b _[gOnAg/^<]3>Sq͌OzSU}>wr+qC4Qy}w\=}U Go_VA%ܗ=uO:YH~_?upųE͞;w4O/˰ϗN|vr!~edaui0'qڦ+vݩO,?6eOj[) v98ԦE/8P׏QO>^X3@68VKb! '$5:澪)U@v=˫wji xcѵǯ5cW3 npk83Xbv?[ހ'Cҝ|2@Zݿ`x]Mz-^2X?~$+_}%a1ǫO\y&t3?\wRXɸ51kFmK q1\{"[V5RNkxMe5@ҧ)]} Quq* uL9~kalƧ***z8uUչߗ=1-OBfX)De o3}AHHe5&ݝǤQ}XD٬eegُXk}n6 ]\x.!hMx37RyZƣn˒ YQ7ر!zQ~ywg(löv|رs;Wk ya7^ֱuK5yߵX#k w?p-E Ċ fGF4f ~Cp+ >n\7îs}c#GM^BX6e&az`0e عm W+fPkF7ZvJĜҚ[84\횫VSsV~9˖͙#V,u{ΞS.Bp,Ԫ#/&X}32YͲ gw`Y%:'湫6m~K c5kh12_)C}F`^?1:%$~M8;jfLG>qzago6uu a_:b&|oKBms[@is~BO n 7꓆Nh͖MYfUdO|Ӧ>k NJeX)CXa՛۲3C;PpjK_4қ1gU9sN_'~|s/~Х0}gpo'h8y1%z#~ӦkIc}Ntr] ln1%ePL׃+篮 6jĠ&\5 $Q?~,Yci'T%"{˖7))wJǗTH/5j)?w);3?Byުk'{ amʼF6kΟB˸VLI![oc<ŗ`G[HY5€ug=@~)3]tAt7n- 飘=O-$/抁=9 !ix)sSe$O+,cF(\07kN-L8 9J3evtaԳ3p+d[3fDgzi7}eZ_;t䢛-n7?VxU]{J]OFWŸur_xp#||`3+ {nXqқ?bs7(]zrkmxH7O٫i^@]ҏ[?2s,<$~DFԸgI DH%HXޛD %ui~dZ/7;Xg֗N]I>CuuBq:Y+p zkFEskF ćBbeǎ9rZU\~ .JŻjC+PUTځqˌqw '9B|tV:̕^P uQI۫g::q$QLCLM7dYEEBjK}8K,8z\p湐RGuuBoU#Y㯤o:jӈÁoq|TƩHAw)Ī77Ug$p0!؟$WtbqZ WW'J4>![/C%p}<5.g\+ `Oµp\S4-kh䆲hvp 'BvծwüvzZ\([~B)>L$=ZpF+'3W9W@b.*udOXL“A>^6 $o؍Ml^p2OQ7X[-F=s(>ؘB @UIp|.[ꥻ^W0C?6b ^OF$LʅτI;Nld!6[=hqX&R{iC@:utStκnmu{F5(QN)jюFo5qƽ/k^ r;9J)jc'v?^ڣGG_z|yPxs^^^x3f: 8W2!'^P8|Y]c K Hkc XSXBmCUmy"E繎ic/ԣڸ)rN{#7DC:CG ژX8m,uX q#Ԗm>3/YPN|mȧC(Q!*A87l;:Lȫ W(2BAƆpY P>xbP(KAIu&S F՞uTSR1b)hƇ60P@dc3.X `2o.) | sa%7;ǦttP%Dk,&C~S)I ʪ$&K"߱'ۚb(Ο`.Vr14Vd MV`1)JaQF^nb4r "&sp\qk\-FU& Jh*`z0@D CodCi&5\t Q]0we2Rɦ,sfFl*}QWx5ŀ#c,B o׮F@Z\b5Y2MYfK)Q.8w [cҙxmhsa+%wZ!ʴf;XH2ŷiv9A]T/& dW#Wݙ^d(KU)O )s.|d3 'œ,xa%r|3r9O9|ͤɕͩhVZK/3~_J Xmj^`8TMNvpU 6\#ںxI[n9ʄ=M>GA&xh>b+d(Ou<:)t(:uf yB&%q_ˀU_UiEs&pVı:} g%|>*CK=T-: vs{]2vE:9 pjB=[z22S] -FlyUhtP<1: pF@b`N:. V)%<GaL@# Q0p+ xHNCؒ3q0 z 툀Tg!U*=s;lE4Ts):8$vp|`^qƧ$af8#X~fS3>ù*\(XWesTKE🐍e)\ RaJ,A2;hT`O叅O?_c 10eT._8C01-2}y\U"瑜R8Hr8Z!( 鹦b9t2Q1u3?pY#4]8UW}"E\Ff@UT8]})FpR#\t~f]?)rJZcQϡ¹b$oyj9s@ uׯ#p&w[0Sar6Txܥs-?v۵jtVugKu,<U3Z5x:VkyG>]uUj hJ̼4U&L/z'zyugZWxYO('B~ޫT&ML|E,rӰs mUnBY*kՓ!^ r<9u4oA Fk=&>*  HH3$:%6d O9I !%Pilsrtxl28&%9%I`v'娄𔘄xeD WyQ"bcₕ!LT6 cD}D c)tF$'뇧9H#Epθ .ÓRʈd},2{&DqH}2k2;nMH}x, Lfl\K?9ThcyUsg0Z5 )U%,~y`8XM<}wI^c 2E6d2)#|z)VC],8JClֱY/daXhɅ-,6H&f-ScآS\)L*NbS^IZY9-2[5ѹ2m}Mȍfld(+?\:Y9uA暑dg:HҒ|&du ΂E#⨕ZIVd5`P$쬕Y+Q+w__+.k+<$gKV.)\˟I.0+dԒIJ&L%{J&I-%74#)dGuHvU VG GkGwGO46 ^4!G~3ؕ&ՕΌ_B\-/ Nʝ5œ®ZƼۯ5]QO)wVjoQRG~ "7^:%?S GD>.]J{\&?Pr/~0HɅw2~LΝ*&go)9C7~tS>i䋽$%gȉ NL#BtO P1%Q!%#iM>Nާ9{-ɻ %(y)y7)Od/%{s)ٽk]Uc]{ɮbkARAjZIɫed%P)f$/y[FGD*}ȋd3%(7xIw'z#Y ZJ?O&'KIJzzW^=JH0wgSNz&{7w;%C]ݥ҃A!HN:AR&$ȝ$MHC#iSMZ'i lIܴ>#ijN?loAQG/%>C7=4F%'%O)Ɣ4F(4#0K(^BpS(q"o3pϿVbr endstream endobj 142 0 obj <>stream xϵP@%7blШF7k|ؤ&7Mkz3٬f7k~ Zآ-ky+Z٪Vk}ئ6mk{;ٮvk:ءwx':٩Nw|إ.w]z7٭nw~zأ=y/Fw/ 5~_oz;L g Ox?tЇ>}:K endstream endobj 143 0 obj <>stream hޜXio7O᷶@M> @'M&1r CQPYvtmCR6={383r*bWK:Sc8(\ &>0K⍦BaV0Y|/iLͩyAF4PQ| 1mQ x{OODdr q#Rch *IM *H`K5Wq0'#(0RETp\Pm]|#"QT\S]|cJnQĹ&Go5Iq1B(j)>^7AN_4^Nxv.ns>?ޭuB4_$-kymz8U|T0CrFN&!ґ5WJ~$; c4LQ4wI`.;2(e2$- s2T`?{>а|5-%$S{N%jJG|G˖T y/lq> ]F=M`xb.NAQG WN)"W,TCiCApe}*T \T(7"9<*Qm@t4Oh XD)@]JeIR@ ,QreZW*y@t|?N41@8ڔHh-"P0z5 %<V:Ta`yx2_zq:D ]'򱺯d^PڂfCQ~K$.np}BNT%=)؄V_ `+0{?Lu9_bhɤ}ְ큋nh,1Yq'>vԙlIԖyƇh?->+*LQAe Mm1T B#XS3Ԥ|5 Jc=lo9,ȀPHEEZ!ߖ_4_u"#V]bɄc7r[zRuSue5թCn偧:ZWCnR{ ,SߝhhZM+u#nB LSMX6〠W]n߇]NRFL*~@<E*d PbtM*PAо3AASJ)֩HEZhPQSLJ2D -zzO iDL> v1S4<$a^7bv"2q hCMSf ȏгZ`oU7{\ޟ: ȈRTGCiZo1 W}LwUʊCݏ6(rTVءHU3Ey*Dv*䗂7s_cXųyROjlZPzwLρ8ȱN?]e}ļMXb;'+ endstream endobj 1 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 2 0 obj <>stream x[[oޢoT84٫pډvh>P-1&E[$*y.R C\s:NL$QJףWi|%(~w+N+틿^fqMS.>}y88$fI\'0.Wq,!Gh&]AkM΢$J*:>SxoC;*6ߺl)˼9nu `;xMmo`5PN|ʳxna9Ns]F3iY KxO0S':׏9yb"AϿ噩Hȁ/aƽ,~=BFf Fڴ6[`TQdhR jhN/4|O'մ4Zy^ۿ%g B}>dImEBMVB_7eLUg8ԏf~B0f&qm2SȪ4ئ´ kB&Zd?G߂l.uO` Mh֥{F54a 8gRQ>2*!Jѻ`=g }o@Вtc5Vzq{A6vO`@4Č9Y54,5|Σj-a% 10sL, ZSשpP_)Wg?c^¶2 {aE`I,LFܜ!JoM&Ej28<\0\w~=n}'@MZ嘔 8$K;ںHRvk pddUDx,ED/tO"8N К;x3&@~:xZkpV:xB~4=<_৳ɫ{x ^MO׳<`y^@ޯ$ӻA4SBWz$@@G!r@6Mgޑݤ[[?IbҬE>FƎ)̅ExM\E ؋D}b$^Pk+5X1R^)_$MV0lm Gn6/XگgkYtDz%uIr2h4ǀd0f9@x-(@fmB238[W7[[? e*sb&o!x ˞Q8*=ro9PPd {YIO²Mٔ%Heڲ** m:~M^݁(n6*X_&g?Y۸LiԐ>M#Nz۰9C4UקD^J1^)*\ΖQ/h G3jݭ;a0ʤy) bcV3xE0$h54&G90`Qhڙwumj[mm(Y4i +]@'5)K< P0;D:떄!<'[\&aS` } r~4=,_`ɫ{XBFQ²hgnum:X~=n,[.|}A XP5Fœ.I/&[G0ǂ̔B# @IvVIޙwƀr,kSzS,e_ûZ3e÷OBZT\Z@h)Y6!Ti/g*\:7JX0ҏORARэ\˰1)l{o{\.C8lTYw2,[8 &gd >ڢ$k}o*,uwwLD6T';b[U{J pJ$XOԘObgUop/z ",gQke{.+YǤTp[KMK`Fev+ D&XY-xנHMxmOv%ʮ%+[D>XK,3XTcb7p+d HS OTd_7t㩿iiBfIiF{?{hV e }kl=7v2CΚ̤M|#&տ+6NTX((Q4ĩRf k@T-O #+{b4F59bϫrn]|S=rtvJqLd7MA0-ˬ\V= ;LCKx]^11Pñ+Vp/`[9[xf䣃۔j?J K@كVRlӘg?9Xd(76{)Ah] />)Y !9HsIDg)vPyH͂}zMNZ䏩S>y F"xR{;^6.b& |7MChP9S|?X^B!,W {\űy- JRUԗk۳}ّc3ZkZ :o7Mf}!sxhs1iY9lS:X? g-NnL8#35zG៛,? -qcE%y`C^S 4}I,8G^K|׈ D .$(2ťsz7ڽ$JggѴfc1}} :3؋ at>stream hWMo7Oɰ"9;pK=A]M]yoiKIزc;5 _bf0$xTxG͉Tprh9yt\uvO8('|-:_Gǿ}Ru[7Ӷ\vx߮f<ú;I-jM/)H#ub1ʟnRuoY?M_5rh $Zj֢7lcs6iJd4繃Θͮ;cc{bA, NtOe_+ ){WJ)= qUolp™ȃ6Y5@$oU_.*[%VGM7Ayqq!E3>'$]QRLr>98ΫIqXj3iQqenUOD:ِ}M2?f}k `ڲshVۏ؝vИ^#cVlnЩd-$=G.1ln\B4KžڏSAd6s7$saḄ<$HƀIPJ< ̓x̆ND9"H%Id‡k;>" P(ޑH08-3 ?y,)3sz.x#V VEŸNxhky0r1h(3~I4ضgF$FQq:  C8D7lDa&iRnD4xjmѕ]!PnC"so ,矡%6Y}@n3(gWkW+%#b.*;QkQ58U{+hKAXD<-ʣ;U|w4c|G8d$!xy t 20aP% endstream endobj 4 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 5 0 obj <>stream xZKF*7^sC*Vewv Jɲ˖6v(.EޗH6!?2G|h ɥ*mah#ˢ,KyhsOv(ƺEWVk aqE8O dXX)űsq*ˢ8Uh;-?D 0%گys !~]e 9\3 .28Ai( M[R)p/% d5"5:`j°qMui2~4~|[)džOڶE؜OIݝZ>ǔ{C]ng ^aK<AI>PߐjK5R/1?ؠ=_],Jb--~6VTZ/]_&aݐݭHy~_,q*wpsQoE|Ө'.?0ќ/C؜~=z|dנ #@7xrfkas|,yư9= 47'[]]G0޼jۇo#n~ǶVoNڄ8o_~5tÇ'N!@[#q/ϪlQjKDpG)6%ܦ .WPr#mU~%"ɰK$\qd@BZONFu:ć';sA Ի&L=ֳw_|=O f>iڄOMIiƧjkh d'so&=O *˹{2,[ݗ}0>ZUj>f|lO}wV 9DRE 2AܛI=Sw(h">s= qh]MOc2/pg%e&xHնgC"Y4s +@)^2-ͤдv*id=z-Q4WtrG[{.|siev#n ]t;^5@/uɅKSX3,Ls}{3'бD6Mˠ,b]d=ֳlw_.lxچTwJe]~!q2KgiڶPutNGvMt&#N{3G VNF4X9Mݓ 'gBqBnUfZ|2!'}e55LD.0 !po&=KڈP\#Ʉ׳lw_Y7ꮘWP]^w͢-b3+6ţ@&>`FX6E;"Ʉ׳lw_hρE.#,l іBKub F\0Lz #L"]#Ʉ׳lw_i~">Gwny-R3%tbQ B\Lz !$"vn2!,[ݗ}FQcwנSJ '8>[P&%]HNgh8}7؉Kof]:a&!YΠ풍%bIg~=ĝ^8L!QKJ'8{٥V9O(eT75nvSqpq)Fn-s8f 1.Ag`y(E~*|B4VsJ ֽrM7f9=J~1=G&;Rjal4J rs8 W.` \?4 o\|]}uT9\/ wy\l5EMb1exCh54#>)|2Ϟ Ywwqxgx&Eox  6 8{w2K7BϞ~ݾlk,\ݿ[%E]%} &f7u]&Ft.eOwuazJ~qgIKR;+"µgOY endstream endobj 6 0 obj <>stream hj0Q|ծC^ MI{ 9ĶDX2ykYvEY':uҊC;;^+4 >W󙸋.lP64 <Ԁ<hA@nL?;!{&kaȺr!~S*HMi'^QuLUI"Qm>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 8 0 obj <>stream xZKo\y5 4VgF">d#- 8%!!<|]=/Rɵ`w\GnpZr罐H3ٓTf/[ʘnЛT q0Oﰨe)Ti?[yɬO0A(uUsRJ~5P\\Qn=?$^ o1ck~gKZr=_D"LFP9+76dkaglֆݲK5L]W7\-_xR;/=Gݳ):Ǿkާ=Q{@Kp|Ay~F-@9~ w=e?xX=<`#)KQ8p#ۿU; [Vuόh (R5ӨRxV{fP)MkV0[Sάla} EK ֏nRrxn SO Aem)t$*}KiP ЪBwBn ndShy^Kn%ĔjAv]ĨXzpPJ_y>2G.{Y`y$I_40$a(Kd%_* ~?$/$+* J"{H+K FCs4Vf^:U검6Sy<3Vwy`;d )JjloN@k Vp 7GOGBosރ `*U6Ag;#[mӦ<x.?'ڠ_8t"W㓚 y'^"޾}qPΌZ%խ&oKfY`MPвql"'܌MPl"g.uWBF)} ѸЊ &y<vw,lڻ:Q]JcwoS.,ûB&-gDōO#%Y!~O84>8@2jq)eu,SC'= Ӧ{lqrd A!`G(G57.D/ u:ZNɲG,3[֕hޏ浄do+}oQz{KP,|bw+v߳}%}]" 9KfnʆyD SD rޛ d%#dtdD;R@OYxE{܍,$qa} 56gnֱo0{?SLʞ^.UGe)#_T[hLbi'iQз_zRJe sCQ8.F endstream endobj 9 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 10 0 obj <>stream xZms5g $3-/ JR2c;v]4_jt3tҳϮk%qr0*糲@PF)7F[ OiS_9a^Rۈ |9y9~e? {'gW Lnu/orOO/7h !X8S&Y΂q* #~'6J- Kke:iٷ٫mI _1=e[[O)۰ Q ɼSoHC)4߹mɔ$˭qJHeΈJ-OUZҦ-{7R/`{9(^g?>_K<ħ ]q>/gk<јX NNZ1eK,;X;99ҀPH砥( JmAXQ@ +@U]ssKDf޸MT˪ >J<?Qa9N?!lyNQ--n*d1֙`䂁 Ŀ[uV;4m羲 eY=qqONJ#ζeg;"09HUqQ;j#M-]F^1wǤZ&;ی>y 3^}7syƞWq5 kʳV'cG>=!\BM"yc/3z :XVxa&\W(fׯ0 4|a]v xwM|'Ƅ Ғ7.E_I(qgPYxW\kDwxѾALms?/ \ǻ5ŢB; -mGvǔ[6$ ӤxtO7Q)zj㡢Gn4dLbpyK_Ē>aPF dEoJdS !sZwaFYRAu" GWKXE;"͆V.ѝ_X` ֙R4 q[~jAUqP(_gmj-^ZƬ9366yS"ۃyRcHuA-\/]]gE7{2$ǚcͣƱ6OKHYA}fi/z~bQ3I6ʸ}V\K Sw|}pT>ilNJ[4 ?V;>PGzƎKaEuL"Ā ͺ7ZJ}zWT|8oչÌ[q Vv]ݥP(t__2#3p2}%S_ʜB0YU׫c9XY4fLyww1p-}E[7 T8F{MV𙘐n@L_vP3&qP Vڂioۤ,oW#TH=@eգr) Nq>Ν{5(@&?2(S`Ap i5F +zY4ه"Y|4oՕaGdu#U6O-$ bڒYzxWLZ?J2hgϺK rIN&f S|ːO0`ɰc#!KG jPsԶ}m۽?+A- X쬜Mnwj,Xߟn`4\ǽ?1! ;jιyRUs׻}#]Y)R;Y,{6~! [ic,|z#ZwR%FoGJhю`i S"QgyRʡ}gwXm")*<  +{E~iO 7,2d~ͺ6iBntuf޶#7I > yV&A_զBqv? a?HͿhG endstream endobj 11 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 12 0 obj <>stream xX[o6^+2wJ֡ڬ6ubX¹{ubǎ?>K$۱0LQ+ůj!/wsZp$oRs_,DfL'NIۙi蔟d?5ZiANg+x-&K{/b%^Gq"&'<<-g q5B*NaOecv8!; ;exL2Q0Gv. Xj|6q9=̝EۨLnh@] ac1:`W6.;bc#XczbJ~i\d᯶oWvN4+Gh"&4*U]UbRSY֤g%r>ǗwU4Zem*tuAV1>N (1A;$@FBP 3ጞ)\f'ȥx#hyUQUN1pgr cghcļsMFmN'd |N19b"07BsWϩM\pWcϨ7&wlڅ'w]1z@ ԠT5O1{v=$=E DP|%ۚɽLR\+B! tsV ouKk {hss:i=Rߐ1 ϰ_XSxi͑x6k {2?E-3*jl8<\R~&~LYL/lӠ.fN87³v9;Fi._sw&9f+.*-=.{]Ph(ǙkH v2Q':zeO*- Uz(qάK"|f@DF NɭNE!u{y2S^Kl҅{Qθ%_}9fQ#* }ʻ` \ZrdKm%Nc9jMz18=)ԌUph({8!Wj!Bl$l Y[ |AuZ {kZ,;w)O*,u-iVj&CM^!ھjλUT(*ҿ;Ye!'qx_]K\(Kjk8S溮amu3\BqL$uIө7NHgLiWwiDb {U)74j g֔A~pAXc}@Dԏ:qSTn#Q]ys$w2J0ci4}A`{1ްfO v~92fjsΈ;'uB7b!!UQH%HA"C[|S%B+dxw tsmR=aXS/! Δ[$&˜p0G^@`EV7KX87\h(!o#:zS6H`s:$%_VERÍ? Z endstream endobj 13 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 14 0 obj <>stream xY[o7 ϝ>hfAf,nQȖ0]IӢK9T(3߹{.Z8-yQy7݄BZ;5C. oO]WדSRhha+P\+jj{{R35C. &VBU}+D!0*ٞr1QwAԾ [@{ffeDA'UFl!Z'0Qw*U+Dzrn"j?Ayz?;_h^Ғ+3A 8+5B)A09)L2 vbfal>g?%{‰J07-*Lc)`g=[KbƝl.wKQ84E;FV2X^;gU7ͿUQZhzar* bJףJ6r2y9nI~q3{i * d3v /o0ُ/1n5q _?u݀Kװ^`n8szѵF UH&wP9]%,l9$=LFgWDzP ,_DICͯ~1]YS2(}qxD;֜_hu"B!j"tֹ εTD" wr讬'Q%6lӐϢB2Y ߾cl 툲oV=d?5[ -T9JDO?"Q`#vަ3jRD/JnC>Ϋ΄ #pYFBnh> FAA~i> #gB^>V*e~"SqRvV%>Y+QC>T`T(JAakvr\)JU8r8b40M=O_qd㣭c*~ 9iT[cN9ZZ] ⰣЛ %Xqm[fɑVjQDT;:PnA!y!ʮb &1GXŘdŔR]]zhcE(ZPQAKxOe){MPi9ݕ60WzEJJjm-WhyvTuѻpHDNm"mo5X#tU?U3V&]"F(@&ՓI=Lo&O8\ e./YtiDY(deAYe4oFSFtt*FdWO2``[hS Y޾vԾ>KW[a++xC_zԾ6wϛS(hZ8: /mՕr +:&?)'PWk~tz>ߠRhhW=(K'"nlOvڂcWo.==p<(|D ,aQc\o @1?;XpR~ oª+,9wF!31]UCV Ϋcܜ^Ypۀ Z ZǼ';۶EfE}0?uԚ` endstream endobj 15 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 16 0 obj <>stream xZmo6g HMStC:t[ⷸvu~wGɖi9Th#6EQsw<(aUO) m skpiMG8c|;Zo|χhPFcg>WWD$yGs\ᢓ:~Iż_ Fǟ^葋vA0h b!K`ٯ,g dݰՒ)\+0;_KzG=,K5K*45њ]X]u .`9^sk}s.AS@|naz1| CIq} Go; к13xv~$\O O ڍW_?GVdނDCe0_yG_:H}eH[Ց(ƨa1:uf[N:_2ڛCv/j Ô#X %R;2JdvU92UZǔTńWW)bmA+2 wYB>y x`~9}{}og>#Þ؛ʸ-dkÝ~у;frH%OZqa!8٪Uycw"*ˢ>=۰涆<^Us}1eZazQp mg#b?aA){fތ,5$ Njf=.8R>RqsRH亸zrڈJXo *¡m02}^sIeZnI_ȗ[2UV@Rk?y15¤i~\v,-Ȕw{GM +HӘ#ˢ8"P;+o_˻0Ztҥ\lI1gDs*zXoEҽQѓC'bP1I)i`As蹜fByimwpG7"(K"/ju#ċuւɒ1mvh4KJ"m{'|"rFwpZϲ:c:0~ rbEV _s c: ןȕ߇FT4-bڄMw[|LFpj˯I+G 1lOs7TKKP\8b\&|b"]3 G+ۮ4 g?';Q!wG]'KpSJSFZ#6^8[viI[!7g{+}va+-r8.cq9 bY2ķ}NIjq{oh/V1W7$m-u;9z Hg4Yc8%槹T2 zWUWC :5Gk[u p?:MX@TqyNbmr:fL^|L*3>*5™tHykc[4Be^HS2s}]9#k_+녷ߊ+zozXY=D`UkXc҉pi̘}">ҳ7)㕩[5bFCVlO%"g: *cjwR6 r#I,*x}PHH{bl(A ^?k,}X.»Wkm>f)6̟6x;IsC-V+`ʄbYởAm,@J-|Tg*|_3zlٔ%֓z1{Z$ljY[ ;yaPYx yNjhQj@+#UH^xWl/ \Tz?\= endstream endobj 17 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 18 0 obj <>stream xYYs7־WʄpͱJRIևvJQ$E"(Cx^ g58}@KNKp&8\\;EuďJk#`!JcZbvJ m+[ e|77ň0 F-(:FGUJƸ0<DT8t<?R* 5 jTTY:?R5@-3k_W/#)\Wb_S>\ "9~K )qL2rvwGW8tŧ^!x%σ򞜿",l Ud(6leOP{zx'> ccp (`b=tYeQm]|m\:6+Xv{j hfcϡ6d<])߅M ѽ; E|Қ6G= F^MNTD©h-!@g Sh(CIC፮* Nz\ۣ|y[fE3}qȘ霦1y)A>p|N 6)<_1G=ό>iS-4<=vԬ圤4TV&x8\YGǾѿ?6tT3*tb<7W"AgT_Mi;#5y;-kYo0RAOzwlCy҆z!*.Qxex=P[w~HK ?8Y_7`# Чw%go1Up endstream endobj 19 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 20 0 obj <>stream xZmo6g އ] fwqޡ{.Ptn>tb;{M!)˴HN#EQ33 GwT EA3LKCCi&s`ִtGsJCt 0'q=d5/P挗''3NAvPt8_ Z#9 (O!J2 qSTdCn%["c!)'YCy3z ,–%69u`!КB{&17 ISr 3o{M0paзx=3?; ˜<"B\_`VnygE4@ <Z3UgN~=5FJ^2j*l򴕥3k0xX֧NΙp-0S*ba,c }Kq|qiȊ nSGbv6YfK؍ITh o_%]ŔɚuS>ܕ@gɣi-[`;^pDA*05~%xOOt󲍏]%+$#fυ 7@ gIt]a((3Dߒ9yI?lI>}k+8سDm;}#-VIpM9gFL`Z[!^^u/VE꾳eڷlZ0355t: 8G.L)az[~ȳz_g-^3h\Vh)Zpъnȑ|JZ)D{ee\D{ =z}^Xo>D5x>/C)lЙ غE}y4w@OmK4l0mpfGc e9uW*8V;@Ǐ0!eZ,߃ppoEG03vڜOF:" qyݠkfbOm|2fUlhD lp>WL^u7pRH MΊM(%5Y߳s6`#_]FAYcZݰ{Y.Нv3 Xg+XO1ktMS*6zVoqn?,~vwaGn uᄉ>מKu3"/}_x/C,#Pov Zq62G giA.9d\.h!qŖ6QM7 ߷U&Wl/{i~?{ K_ov/E\?œ?Z[2W mX;gK/( f\>QGeEΘ*|t CWV%5\xk?䭽m_ Q0fNtץLKkRhm>؞e\ݰ F0~PII7X\xn"=Rǫ,2l+Z=Be5꙾B:{T|/IY>&Ď"Gx]@ rIjǡ9&;kB2{P]s.~DW? ygЎj5PY#x6,5C9j0%Elqdښa~B{fWҪ(AP=BU<^LnhCu+;F֡!/ s6r-"wf:֎Zm}%EII$[!.ӼJF\bwG-=Wut}9CFqlmQ?ٔ}yawĕd<8cZikn9xY7ȴE̿XBOޣOR$/(kqɜRY |sQ'{K8ǹv7d_pɺ حTF(LM`.̥њKʛ˶bOAy endstream endobj 21 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 22 0 obj <>stream xYK6^+p Cq>H&^JO2a]''pWk ruÿ"8-4(2'sLIK[JƩ #~ ,"Un%̞K*5)']؞-Y.3ق-Dn3Q^|z(J (2 zWHkTDo'؟3RBFjY W(4]ިT;;|3C:K DflG \_Ak~gow}m`5g߂" JLw v d ZS|}5]F{<)]Y!u:2N%cGT5+vY iugLwg1uH%H-{*ɂo?\Xafp[ λ"5!#9b"%hJ#oZ7IZj[c{O GֺY l!؁&{ >?\ $[܌0~`xF gT"5-(R#ZY5ڸ'*E)iTb+jT+|M{ =\d&{Bʵ"YG/4:T˜2$~FsӵX[@A V& q-b9k6ꯓ+e"k֟N1%Y5҆Pl5+E)-em r O{5i&{XXן{_#ߌ; d7wZkSe4YKm< sR%b 4׏ń?I, { tw=E0͖2V*( 'f>l@k-pK?[v;wBZ׃9eBID8I }+tR0dC{ݸäa8#t-b;}gt*#t$;3{TIeʨoƯYQs59t}HG9.*m EąYZnkV0׫i"jjdSM+=89U'1_'PݧZ;'?#Y]/(΂C6`09s"d?T9Ӳ_{ t0xn)ڤGo1oD&<ã,M8n3bSkG.zrbDI;&fs1Պ6"vt`wǝG|End#fꜼ*I[pMQ&O ;%eJcg h _cOExț;\kh=>7z4ocƉuI/[2 ޮRqP U1O(Z8M獻e?9+B MxA?l@,xF;4c?#}|3_Z .X,yt@{TP騜{8}+SF(N|^ohN/73tV]wn<'Y]ݤwtEE5;N7eV #uw="ʾ bdNغJT}HkS6na5:6O5e endstream endobj 23 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 24 0 obj <>stream xZm6g ^Z`+b^Ek[܇!ލSE;3d)H_yf8?rUw>V|QU+5|έUՐy:ǜ%k܎VfBϝBoY#IŋKoLQƯ6ĘTm+~ ] s] P9 #+ٖ3ؚMM3V,c9voKO X /[X0W;T6yn5ǰ9{f97P ڦ 7 y<f?vŖ0Yk&nuz0}0v;!\_<fh7|z( Za _HFH}ȁ[͞]F/.^a)F~WJ)x1˹*syJ1PN/ L9?& 쇼DeԎl؀>w~NB5!?V>}1%U/AM|npW;-**69}nk]4"]_S&ƫuwGN)OW"BD>HJrQvZxE3\%hdK$+ؾDZ(f5C~!vJFܨ=UvP~OE6[T%(=j9nE@ilhYI9鼊 U*a響OHSwꐦWhe≫XjѢ9lַ_X_雹5"U"8QW8ư }S.ja+Fl[ڒ~F̚eɀ_~8:) :iǚͬ3JV}cφK !S_ @5%n"vH/l띥dʋ0r8:<8"{`4RK%E+cC۴5?V.Ox"B[r8"K1ܓ^Vg ܈z<aXj#)>Z8;E7vB?+"}ҁ,C ']dׯl%Lc m( R"&;[^c.첮O%~}KɸdϚm uyj`dxS,j mg3b?;tOjż5Y,[72UH5>pZ)xWrI:^rhIX כ:•q7,w)cM5χgc&7Bg)_HB4w@Zq yC}Ӱvhfo#dк7.Guq> /Ir<¾}O%M:amzsy":ᘬlONmEC*c0㟲)p:uÇ'+s>4>]d.d_%٢ۆץwVwG2)lrN5 K`d ҿt=~OؾB : GЮy?8ΖS s!/,DZ'KS<4_Pt*ukwV aF [bR _D~{/t:Suӓ.uUW(U?CݗE"RJ뻿{Q]J'bd endstream endobj 25 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 26 0 obj <>stream xZI6\+0v*ظ$$8qyS砖jbRJs H;WeTM |oCӷ4T ED,fZt;D1HZPK?W)(;:-X&eYgh#&s&ǂ9gaFEь{=|u5z?U9g`d_] ┫[ Pjf!J2 $й$"$P3z< DaWweN$'J2J5I&s-yLIErR xSȆH_?bp#4Ӱbi$AB֒=}9OR)y2wFJ8[ Td;VCmfo94'̔S5 Q,oD'ֆA{QV9O` @?)(#|KКgWBߥka< ͸LT̔ë\+ƄeL[㴎ײ55}~N.jQF}e[IƏ) ~ۂ~)mg HvXs0 7n)HB {3!¬kZpXRwx季t | I)y ^AtV{._Cd},_:fB_Fw 9٢rij<ښN,V0*gl,G"a?DLO8KXC}_*p5R4Na*ca$8NY?JN05i%ِVm yPCqB=^^O@BQ}4Yl+䯄U9Ǻq‡HYOCkWv}E]>%=N(Bs;]<#c>ʙDᢇ1ҙfq2^gvc.<'gyA#>Öt S^kt(1w1ޗylud:G1dߩGP@4gi:F:y(w{HSw,pm+TTc`:2a"zثsihKӠZHL#bGe ;VӹIREBQ&x 2BBW-ǀOTexx=$빚7JȤsks׷7aX!ϏqJ'l֟N6fll޶ mkB~F:khE>H5 5{6q&E>C6o[;:D{Ac{4i,auV pA:,ے5Fw.?VF2y,7'GIgJUð@ҌMlp'u-yÃnQ+MR 59RgpS&UZCҎϞ"mGt"ɒ4AUs v9 `ՠ Ge c^p3/H3Upd۞ Z;aI\YSOϢ8QL*N[!ݴ?t{h:t[!OU=m(ħ$#jEC7N 1qǟkt}txxPxjg~GDg rWKO7I`i;{!Ծ3VpXCu^|m*(ONK}}eV3~FU.~VS]ѪČdU~/kkÝ`X 2k=%n`L̀Sť a2e R<{Alkf fso@M@q!mΙ $bmBrn-[ovr_^oF6\hzlWoIz׉NcAI==U@7y  b`9G!XA{gSSAOGkAؗ@,- X8in Zo[A:zȊ1ovPC׵[~vpk79XKbXSU}2ڻg==zdF8Ryefq5{>FNN* a}=iu%λʯ8S< /uBZI&kYs + i endstream endobj 27 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 28 0 obj <>stream xYn浟Eh̐EI)zYhnE/B]$m3CRh%9) "EqfH;.-7ZZª/ >iEf;{Cx9%Q$Iw3DS%6倷!B!,JÞ({$"H=:^ -{87?JcwrWG(l6!9I>΀XYC^ĵZs0wS5VhQ^ūr Km[! ߓȷH!ώ2"j툒A色pq(5j9)s2gDx i `G gYg͒f=6\Fh0p*>=b*2nEcYX1{?:ifE7~Q{"Ρecޔ-( oi;l̄q_ 9i;Y'7Usx$Ja:W(mA,7#ϢןzwêYQ\Ck7ć.9%}_ô{Iɟ+=OF09Ŀ[hXo >A^}{_緔ӊ4>*6F%KuKB4}/Ql'M7|08Xfg)lrsS۴4V;>؏ZF9fFLA;´W.dh#&VdEI>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 30 0 obj <>stream xXKs6F`|i2cAuI2u6IrMYC="QտKAV;Q\~bAFtEeT8JY'tQmh:;y{`~Ew^p:{SIJW^.z>GO.טf @')q>!1')+'%`,;P9;:ǩDQ[3G}t4Qgo\U ɂ{2&%nX"^ߝ8d$"q%,-TW=-O3\ d = z &R#0s'p!W2e<ἜIa0Oq%96}N*nam Au4LIّA} hduֺ'v%[?t L# 04G~,AVca5)How3+iVi.0-<5 ߱^2F>9,p|z6NJ&!}Cc4NR: BB"Ƕ@Ԯ1]rSt1cMXƩ8Vaf9g8YjhisXW(}ycSC0D Iˍmf=Ccj`Ts75Z ڰ 5}`/٦ pdWޕJ K3˔!P#@gVX4T\80O>{Kpwv#6*F"\at၄T>Ӆ4wڦMc=ƠpmӁ%kL–흩@'iKB'F*IM Q݃1:z;PCmF4P+ly*wn/m{Xtb*rd|CLe|O-2b' i-+[|?-t'Ae{iDfEC}-0jte8ļap6d?\}t/1ۆhVyp掣it؄G=Ӂ^VWݦz|xXƹ})'^OLҗby'\Z;A}m ' pU0YcMw&bXbh D8qb'8Y(_̣eJ|\o>l+n:lA$'[ &KV?1oߒͳSیm~y콻nBE&/SH n ߻6vmuoB=5C|Licxy77x5MX:. ;mksb8jq'>}5uKv Sd&SOpێ9Ml~[Irw7 endstream endobj 31 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 32 0 obj <>stream xYko~կX9 "nM4wEZR帛/=sg(ʖ,@0y{﹏<(g|VfWm2sQh6+ʂlQXe(5q~eȦQcc&I<X*aP".ޱ/?p ^VbkB<>yM[d"OUOci`֒lS7V'oݼpXrs,3³WeSE@\$+}laOo"}~:_*`:s |6$HF'#OQ.K&'+?W×׫e_H3CYNAXۑ]Џ8_ɣ_7!|!V(b~*Ms8}=UNGZd<{7_ЀpaEȲǧ`4~IBu8l皘sٿVwkPĻ vg&CȄ[ފ ;I$ɚTYn (]aŹzJOSq_x Z.~:\`K+p-"<OHy5)C}i^L+WEkTЧ?A|ܴ9DORRoj3"yZ5~[~~OvQec6E",+Z/[Mol|l^N@֤o&̹x2lHP }͡<oQ̴)> JmQcM8y÷6$`IHgKw5}@H#gYDe}t_"moYҳf-{X^dHK|),72y\ll蛂)m³"M?nj˿a8- =Oɥ'&[h_5ʯtZp؈:EҜ=fl0VS>{5#̫&v j/SAtP%=vIZ9P*weg==:c"Jwaq_RΈ]^iB4H=%) h/I)]gIȅ2}ǔs :اOs? |j< 1B$|u00a1p.&;I,1 qtB&U*;g8+;L|̞Ϻ637z֘tSa@ endstream endobj 33 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 34 0 obj <>stream xXnFݾZ`P hDk.%hI8HQdR-v_K.D rBɽ͞9s!8: ( s&uGG2HPIWOZR)̣ufk0VԏLs(1ѱԁ1d"f[TKb=*tD2HDb>Zzv1يE,zgw@$^@YϿǸ )%Sy(XYa`:DE(D*p|U #|8 qtӘڒHd!5 ıb. 1?NH\RE)? W"56eD0~cH5=gLy3#1όT.wP=(8 q{J8G{1oжy'00" .`ݮIjKw}̶x衖*JDơ;j8*U\ư7O@*ys9.u˙E).t\N"X p 1 W!Vh) +iudeUxD^R\,񴀥 nݪ\oUf<Ǩ8ws/~$7/xd2&Uɦ/q[+V7N)g5H jg0^=VGUq!aht )!W`Xw#:I'%Z׸0>g%1b;v>AKH<81M{k'˹ek~sy lϽ2r~i}#xm3y۸.1B-Q߾'MQrnmT"DZ"A>\ =)~-^lej&>͸W޼.O9O۽#śC%kltH ď̏]W"sO6/Fq0A˹7@$1 # `Y{Y)֗Tl~;*>)yWZnfB)֊_,%Hg d W-n;ڦ/c ϥ+InKN٥b˞qc1'Iםr3atҿrA~\'/>^z7},o֦QɴyuY)7w ηX9;pTSHntˏrh᪡mMu1{1’0fcÿw)r[[6A-/NCV}L9 wnDSpblβb"eXep YBZuLtPeCA{/D^n4kl, :}o0Ƈ+vUmfԦc+j*,?<_Y}d3#< P]Wϐ'`fT،Z״Y:=,͖Yd]ߍ8u>p~R54lْ(Nӷ9}+CMAQj}LXkN9k7̕Li[ӾA@dfAPI}ߙX(He8^Q6/D2NRM8EwEk1 endstream endobj 35 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 36 0 obj <>stream xXo6^WjF$E u6i3-vwJN_>HGq",;<7 kݺNGm##bJ |5'ht4m\,i\LTY8-,]t]LQjtJ1I * sktd]4I*d+=72E=E\(%~PٝeN{2E#iy!ewazAKxQ#I$?]"QďW7Կ?h vLnV%֔,p#;+ؚmgWlɦxڰ;ijb,e5tZ! gaIe$qvak kX\s [\`gsHs/ vKrbb2Fh}^RW#Y M-3[Dg:вՙiiyu5]Vs?m"78We"4vb4crS>k*A!uJIx6Xq^*LzFFS!й GZO.cRޑ2f`9 5E6tɳ4 q ucDfAE)izZ $/}$ ѓM)OWLDs~CaS F"HI=~u[1qn7Ln76X@9nC7~?ɗ]Bǹy s.Ye+I'&'XdV;MTo &"ڃ]pTS!.ý6X"3DJJņaqX'Z mnBZTԷS USJqANi,Hn4]8:7.mV/Zn]^ڏgq GС<z6X1\`ϙvg_%_s5)a[lb:Hk4vOq zL~)b`T!& 5_!OHb5Y,)iMV[PU+Ĵ^tӤpy]K>k!har m)#rsTr+8iL7SǼm0NFa%1cuɵ.^wsZ ]gB]G֮8_kzLO;c,C&L^8wWsadVs\!P)pPHҭ#W%ۗΰSA62[sYє20\BʼnHouEsG3 {Fvrk* rAzTG¶PݻZ+( A6ʯ7ʺ7M_ ;m0<3 ԙ{5d/ j'n0iO7Aaՠe*lWlO)d)yobV۬*S >z_R` GY`)rᓊ'B}mN*3W6 {{@*Y .n|LkTulJF `oNfi;H>[[a ¿–ሽ}|p1uq]>t\OKaU逸^2D4gdjGΘj>4[N$_g R~;cvX|&Yۋƈ<2טi endstream endobj 37 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 38 0 obj <>stream xY[s4`FoЙDŒmx*26ʃdIw7ёd˶6u2N,K;5fii^Рf%ZKTKxRS`R|g2XfNلvlt26fR2#b-?8CFY^}&J1YDㅉ J(L 0 &|"/Ԫ5Q\%ZKuq&#M5G\TP*bQFCyqПsNM~ON|;LL8=L~\s+%>dq(J e2hZjb"۞"Dtz*Q2S*tW@d! lBRt5! Sex ! (ToCIp} wK5< ;p@3?+ |nzpw W> c99 tP(3,"4u3_ ~Zs&x>~F,a,C\&IªHYu(Q9F+HoJ^}F3trGh#ܧ\jc9N-{v;ȉ-ߋjä*^"[u`&1Ihs?7_gCLf`Oa%XŇ6wwň 2U5\w5t,yͽC`wwdYVzn`%ΰ3+ώ> Ʒ;\G^ݻDYX]bW0|n[Nq׸!ஂ KTֽEݡBA_5 SeՃ2`Fȭi1Ÿ 84 6}?&aBy8Lk>Cz{>U[S+ %ClVR3y1!KkS)& [pg[j빽[ۧ! v2Cl،I5Dܮ#+8FF'^^\ZvW[cgΣR31N}*nQHXYܢ9>*ʪ`c8S]@Q5zP5M֋E^oA/n!""r>5-d3aӂ0FEojlV>c>ψGh3Y&$<,F@T] b5x,qwAzX]“fv -g*7G,?g3BSq%ܙPdgsJc"bUL⇞WkNin+9*]ysAu0G.8C3;qۨCefr4;Yy~c\1%֧x5H;>62eKl{|rudes;{\_S8X}Nb*`\BYM5eT\]pXGU'H-q9y*wX;N]S~JR-S/g{abImHGqEnșTwV2Dڬob힔j+ (7a,1r}M{x w&28dbF{'t}]`r/SJ|{Ⱦc+F3#cTꀟz/oC endstream endobj 39 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 40 0 obj <>stream xY[o67uܜsa* KȾLw;%Ni)w^[k٥h@h$ HsnY洢I2zGKEtG Q Xsz,Z醾]]Ў)΂U1 (ы.T4QDe*q9 yF<*F4Z#01NgD/S̶*\XaAN~}xf$nz˯`ʼ_^ҋ!p~uZrJ4apE )HC9<ɚA.;Or</ t6zDI4\srCJurX_w ֳoo/\?atOvOY+` |K^{s@>G&@ w?z#A )1LgEH]HGQ̌xR;S$"gDm%Ya}d-괂;9^n:Vy Y0~΂Vg,aWe $?V)!DOC0 rB.̀ASLd;O#v3g obt8 dek]"Yt\Wj5:}\ÌRto =?+ $+P@)&5HAV#~nq'9R!̆6}O]-]B>,DsS{4_#gkfyK#7W+dZ{vsBL#%AK {^HLH[ Ãw߿ a{s?Cbh2ctWq  AR G6@b0ٖF$=Õ,C"=*$[iEv԰3}Rx\gakw+ b@#APH|սA2#cK"E曟Bo }I~GP"7 N:+LfϐHVa*uBZ6,1ˀl$N8Cڵ4)4"mL IY`|esXJM~m_upo*.t- rG W(M Jhp!)˳{>P(f;w?aX\e8*{K̆crq@3![g*P=T`Jj7dlfʦ́qو9+@dھ1]­UU9g],screb{ O n5t+EG)@l ‰%uc*^"XaܠvN_a("8&.أ30Oocْ>wOP7#g8ǡ4nuTaT䕓$)ST<Fj 2FED CM3Nҋ*6nњ5N9tP\fӻ[[ =};5S &o=MGB:k;p dA"W]2)}TkVGkݑNvzs2 &VF`a{*0ܓ{$LNO;:M?'ŢPi [݋J LPh99ĴbKK'-R]%'c`oSޗZ?CCrફlU{ @u[zkH:_kTmS<:q@ Emm*r] ECkܕHZG~Mܦl/rtABZ‡ۉ1Gs5$cInnv{ƬP|0zsb(O`mo9tk&-D|={~vNpJBtςW3mmG< uvy@G{L!>'{] 2&s yxސ]5ީS*`} 3hh=JI{;bz)gpDn=y@PUlVhwXS=!& Ex:$mu /ZL,:2}0j0nˎgp)H(Vp@h.G'H 80D"Io\?>.l߽4mDž۾O))Ow ̭L endstream endobj 41 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 42 0 obj <>stream xYK6fћC Xsŗ(% IPൽNe=D=h+Yp7áBoiBwT EBLe9]JH& D0nLcO*ZA =(yθDkjIESK?A'D͒"KClIESK?AzD$ =p_Nsz$L vL;tDO_ }1BR;Ê( 08"HB81Py W:YѡXCMI{P&yN7՟dMfdE3%s2%X_*ݙ DkXHA l! )vd<&@AL w;p`?A9}XЅf\#2%x!@\0:"##Hf_RJxa< I uL {3À>V!!n |soM" P'C7%:X;6mu 4X$+[xV MPoifvK%Hw@96x-m2X70ZvcԆdvbмdS\x u 8ud7EnZ^ƎMzO/ϨJ1Dv} \ǎtk\u F0aw-?Gc|b2-Ϳo]tz(|9s{CMM @>tWe6,5k+>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 44 0 obj <>stream xYko7Zi>-blMb4 l,ɊZR%n󥇗4#l5νq!9pyE%D$yė@(ODZi:M+ _[>"7 ұBG_h%&L 1x1uu"4f-]ITuh+-Vz{!ENK(QZFҢiA&1"TNrJ]qh$(-V H4rQ+D䥋JBHPZ4s1H.*4M !W϶)$ɯ6L3NTn 2հ".dQ* N8=g#e;[ vlʞ^3K%1}+ڑ'0|Lc>\l.03nkss)Xں,*8VU" (ʄNu}arlL vc]b eR*r$J@@Γ*4U9R&@"Ӆ|Ŕ:R2picqI{F)]^eCm)_%ZҲK"1IZ[7kouDX1}uFAO,S)2n` ٚÿ~ 6iI!2wP z75K8Ԍ(%MR#z) N37מ{*2'n|#Gmi%!gD-3$$|h5פL#sfhCEˊhY8@YB \}@K W! Ǹ,qw='{Uƌ*kLCsWy bIuzBT:5O)T - 0)v][Yق WJtmZTcZwqĹ@A7fSF\. v"E=%8`j|pdLɡ|ĺ+9,蚦$)#{lKP8x0|X)kJT?R%ʅ'-1NU;v, d As! GZ{~(Qx_wʪ='>ѽ-ҲFzHɘh"mE+Yz  PkЊ[OAUNW{֯W@mEO.<8bLyG2!|>;-{ ma{S־KPY"$k}9@we>U-ƩHx/(O nU1Fg3V}E(=e/k\b,CU2#ѯj0{UPcV"%zB]ߏےA:o endstream endobj 45 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 46 0 obj <>stream xZ[o}ohsH/m ͺ݇lPȺl%+n33"D3~q(TDe""v q8+4ZqV],+_ _c/dH)]%9y9-C) ÆGI㨿6Xk\,YĆ +ow@$_o'?95|\/!\ q$"pXs Y$K%qZs_cqƴ_(1Y_W}î؎-ؖw^{V9["UQ?ІrBa ґWV$NzI2\$yAiO2ՂrVZs2yk,moE8Mp'w<x  _~dSv k՗lk<?;<|ܧl0aDcr`#B\:8YSHC7O3X,pHU^%arÎt&D yGBo)hUxxReVMw$7Vwv?'OIm ̔q!Ѵ$d6%G_=@VZa9'1!9Y睵Q'vt[!L(g?v0v ~<I\9m 2&ZٟrvԸW_%` R-ؐQi-ה/?QSr+ϐX rʂ.jw/S ԹGX>msZ:T"U\POȮΗ9HGh}3'>FWFEM3c'_VZ{݉*ћEDח`769m;b7v=>ۮsZVē6:υ9zX=ɞPnTɹҥy+֕r'\I3 BPPJ~SK6Z+;[s 9ig;N?qu@ne5NEuّ8@ݞa-?gm,yc-¦>)nX"&{[ISKwPLf'O 2 #/IFIV;5̂tI 9Q4S$,w WI%tU(9aN4QGqgsQJXM3<nǍ2ȄYǙ4QVw䜅m{ڐ/4MS[fOCMcR %n'|B8̫xOy h`+li#3o7F!9|\7棶lw $A (cNbթ88 ,@PxҞ30 endstream endobj 47 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 48 0 obj <>stream xYYs6F_+4 &th:IsX>$y%YVB&_Kw J"h׷.a~#~c%x*cы$JLRscHRJ?|; BnIgcP]e"M^y ( tQ*, 4jq/囫짣]騤&L$q06B8Pgkovnrg*`~EYGy9~v&D@ ;wOҿO-9Sb-4(A" #b/؀l8[%݊ +1Rv gCG 8rC@gaHe$!K6Y][&p=gֲ'`ݍ/aXrkXy9u8`LXc  ZÜ%d^y$RaHb"gQ h2FYYG?;H{L-Hp&Dg:ՙiDVseQNA)Ey8|wD^| Zq װDa~ P췲De)9J~{IKE C|9 G@"K}\ 6͹dZ;(rr'Ly@VvکC,/wqBsxgW%9p8 0- 8 -CǮswxGU^rI'N51ωKb%~ER/C.aF<g,oAQВl7}ŷ]ҍPzԙ܄\{Lljv=Gp@Ξ$j&]-BޫD  c{#w]m!ڑB˱6X,Gw'gq>HMRav\r8a 0 t^Ǻ $'oL(8{^Ii @~O{f;z:ؿY PuAtQZ}gm3b!aȷhZq75tAA_?!?⬁?*;<8׳yMsogD]3t^|kq gg car3g B)nӜY#UuJg@!];{ ?O$SǼ"HQ 0R%Η]RUlK>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 50 0 obj <>stream xZYo7~_&E-2H[ I6MȺV-v\w8$W=RvorfM/hFL3-sJ3]P3yKG|dQ-]LͬWyƄo4gt3SȲ8gNg^tnu/'ޯ~GN(uO!J2  qSN Y=O^>'8@qFaW]' e,t5ߑI<# lɄlȗp\9IS~ƌΜpcDa5LXI^(ZgA}s̪`6r" }0*Zg׻L鰓sf5G'3iU -ߙ~Mp| ws'9FK伄ѧp_Ȥ0~l&ew}8mo0܍tqrr WY83Ƶ |WtYҢM^M$ G gG(W=,S8,|8_qW.Je2VHfߥ :gBYx^LY;zp=6pGxf fNt°LU9/`-y. mh>^yX͙)y<vp{j ֩LF[ -ZORbx" ev]xQ:B2%;VO`͹1wZ ZK4!6m:/X)GQFa57Gʯ_[LV n0nDm|,] [59OM#{%Ax_{ !F:obR:.3vjDtsXA<nڹmA C>L;?v"rNnWmd dx^;ࢺa\m5M؆geP7/ŞmZ ;Ĩ-znzgެ,r!*._hOZ:vi[-9LF~6!b_:ni> ǝ  z?QW㬒/շWq;W5]} _=02q5oO%K˙]O;Z.밫,XkarfD@V*tJve< } |6^SW\~w#Fpǝ ;tm`>p*W8xΡ6lg+c0(㓷t2LYyxzeZLGoӍIlng]yls^lwso1>Vɺ}!O[3JG۞ʘ+.j/[!xo`zTF$V&2AeMeMUut Yxƚ8ӍJY~ș5u؞dR7abiÌ鮯ޠc@p16C~}r-<xXo1p]lcJ2^t}W_oz Vܞy񽟥# ˺A:]ڮ5V-VU%^Z!Os2Yy_.3+T v :au/`Ś8Nb?C凘yp$c);l?}5˳ tܚ3)C yN 2_l endstream endobj 51 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 52 0 obj <>stream xZmo6g 6#^u 6M}Xĝ;4~,Rj)腢w<#FOYn@DCelYӁPJ畞Zf"nU{Jt+:3^aMf wu`y7J)rsU&Bs jq&Tӟs VNUA!uJFolhZE 龀1;Xc{5<pޒbg&_xzdi$2m:$,b rf 8- G Wy -;L(TCsttM/cO !_Q"J!؞E$î|F Fm_U8Ba^rMۏNm}]h1 Juo`}N&7"Io׽-{pƘ ,e>5IQ?ܯzZr,d3-S};ʑ/!X~F|KH+ʉ|{ ޮ+j|] B7nIo=Ŀ%D3dkz;& ǁՂ<}E/gjDH.#@#k!p}"WkY~nό)XKmv;vS{%ruE84ywmƮc1ZSul\ʇl8x9z=<ew Js8<;`X#38Zr?~c i춍y;e3փ oqe)ƑD/+@6ev58]hYZl;'nȦFtI6;^i\7S GRh M!ϟ 5QB65~mme8|8Rk;RQS V뗯ñh%Ѷ&6T]掍vA>])_ޯ*u85P呙q犮vϸqu Y3Y8HrYQEs? {;8e[z&T cDEfnao:´TUTXCkW>E ~{*g_I(ѐU+؞~[NzVz jqj \&8>L|ޱQmWR[{wfH SEf\HQּ.}_2v궎d<䇍N/}5UB ҹ> x 1ktͤ"MJY.o{D4ReԲf;bx!^<8lEzN ǦX-غ12Zoͻڬ0\y.tK{Xa^:h>?w XiCTCbvهeA7zǫfƤeoFBޣ=]%vݣ$sopC9t|_R,0ue۔ݩ)Հ~FA7\Vw endstream endobj 53 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 54 0 obj <>stream xYKs6YN zhN3iNFh[)m)5t(cvmc>E?PNTeLgaZz̚VTfWKTZ*JK:)X!eteJСSкFLkrth% R-a -FXaULJ(aR0J1H 1 V D&J;[ *ղ 'D nlg# ~DhnirZp 9GkA&NG;O2jq)}| PnQI`9 hP 'Ply>=~YCq+lJ5;t&xH!yJ'ǀg %p䈬ȔLH\ҽ:rdByހJ^9;)\۔I(y 9A#3  7;u!\xm5!H7xoFzH2ZL+W0v4XeGݑސ{$ifnf5TY9x{ޥF[#;|x8 ]/n2 n#)&& O..|4`4,ym.6F#Hʸǡ]ƪ}k2iQ ⴆY/} 35΂Im-|D'%j;EaL `FeWX03{rX "!Qx e|Yθڎgx s/>q+"œQ.ܵgl-qTS"cJWYm`+?{;JM' LgnioԦșiT S*W ownU>s֭x7:ԳC؋.gB60F#D l{[as>INng #=0#e~ ?WP0 %n[ǵ5Ll:}kqƸ=˖Xo!虀hP%fewFl'ՙ`B#bd{3LJm89\E$%ӈ뛴}V >p9vmnXS xj㗍L)zJRyǻbSfn.ۍa mԗba^Y5w "3 0af6[D˄hJg.P ?,|G2 Mo,-5~l]n8!܈ai.a/1{#9kuh]- B:` WQιlW荣 YY>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 56 0 obj <>stream xXߏD^^7RzmIEQ.Uė|I.?zڎI:5dz3|3;.!q$t$BW42ZG"M:%nQѶRp .Qjw1ZZ"%Td&勜Wo@LLi 1H3!q z b % ;u R[TkWu( wAT2j 1S Cm+AD4 ̤Љ!Ji!q zh$7Ը gKV- sʻ0 u :.o$/{Jc"7`}~q}A8+J,p%[1lFxZ]9b!,ejZ%ç;G2B$nOe~wA4v[ ; 736O=-- p=hOw 3ܭ39p}y r4ڼז3 clVI3SI ~D2RmjCӆDee)2fV$ c"ݳN07$IΚ qb^Ws^oC2b SƦYJ Zȝ1<(ו*F0*'nKzw֮?5>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 58 0 obj <>stream xX[o6^63ëDCvZa]a&vle%R%C;WpӒWe-JUy(U%|ƝӢ*7qI*3OBb *>RXו%_N[xYF'0wB!i'͆솱NhFє4 fln[!]Zxl4V:AtRZ& qy^R|UHCo ߠǤ_{2~˿ Z0#?ɽsL3q<m߱86,+K53j`oطl~`~f+6eKMRTN[._;ldG͹ڨęWϋ$eO(n]fR!Rw=֫CoŻ`zJy6/=>TN`?GW-'.cҧxakܟÑ_F25=-;j#Üjb|dKaj˝EET.W frdg2w%TKsFx',4:6cÜK/; os,Y: 3ޓDȦiYƦg?L=-1\S'|9k4}E1x}pt'˩vIC%ъن08@Eh{vi+z+qJ㥁DUTxDx{8\NA\c/i5 vh`WWbs\Y41[A۴V?@#\S3W?ItdO뼨d>.O`wq?98xUbrjkvqbxȧ3XS}M3 xb=3>aJ&ܚ%?.懮(z@cn܊:6bNfVeϾHV7TMszNVhVXmJ\4 oK^9|-$ / ڦ * #4 A2jtCkqC3j5#*!7HZd<42]#=LV#OӼ ٲV^S%voJx4Ъ 7OwRAsQ endstream endobj 59 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 60 0 obj <>stream xX[o6^6-P3`a-6 Ų:$^mǵd_>YN+9΅b`,U(,ؼW`3fyfUfl-xu빺tf)J%u!j®lZ3ai ؔka{Ь~ \.i.uxQ4mfUgWm J-VT\٦zzЬ~ 6G [B "*cxjg e tј՜LnrִfEu5| v0;We(hV 'Ujob+cx)/2\9J#uYޜ1hUωThń3vpbR>qd!Y0X`a9.a16Huc͘j"Rf.gM?n_38]'Zi9XFJ+ZaY2n endstream endobj 61 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 62 0 obj <>stream xZKw۶t]s" >Kۼz&QE-6[BQv|Oy7  AQ"H7# @E!OD %&0 dI$7ٳg?(s~$ 0; 8=\G|'ͬ4!_)38Q24'G%Voٞf™*d0HU}t@d %?aj)ȊDO3yR,{R htHQGs2h"M ?(D+8/֓;>D<?~gkobcWp{&8p.Xǟ! >; >7=)+QX c3Fٗ=RQ@^ ;`C4>1İRa @ BhwFj#wh)ly&*(%E0E8 ]h(" FDzh#ߠ=hc?=c:߶pD Z|(c#cRX_ kK4B/鉏0})%^5[QRkk`Èǒ\G ~Ⱥdёfq·OQۢ|q9FFl?w25ۏ2+ Ehx}BPy6S;BA:N73JLy$)ی?chy$Y_d$ 8JФ66PGL>TsheNӼ@&(im` 36 kqV#78tmtQΠ5Q˵ѻ|Za.B 6k]fr`M1e-CѼXTu*rE}I?p ([mwl8˘[#VH5%MI4VcsY;2fd/1T`>PL}䒘q8@;×Ǽmi{6B;\40,"Sk4uJ(&& $&>=\ԕm#"DΡ.17sw0rФM'%7sZptoO[rNJS$~qޅ9T4MZnkdgDX]G$DF/i0ּCi1$ D4z܊$%aQV$;_byᎡa-3 *y|!`A.,# U({FqOO&i-7 4-msnv&u}GR'2` EtW3Dn>u}z/a f»e*YyZy|]z^ya Lmq;~6ugBgqVb۸5[Aldٵ̓ zA]cO?EXlzZon/{$0"@kg͂i,7 64(2Memw;*2`2lF,7kw̺bO-$kI~|f͚g8ڦ!hڭ5/n5/3e c1)(a]k׌uvm*l{o}%mvpfCfg<2#8bxo^ۚ@*K{=Kb>_)c8Nov NaVFXotaay2m~;`cugm?g+HҀYaKo_/FwycƧqcgvv*DSc9]wqGl@s ?: endstream endobj 63 0 obj <>stream hďj@DS > )2n" KVB$"m0p'(I2h9G<)ƔqJ0ײmq7)sLCL["e/݉^Trb/Eڨ_抲J< ]:+c0V8΁SǏ >/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 65 0 obj <>stream xZ[o[>#_5`-^ͅu8h:Ru!EѦD";/fvHJZ!mvvogH]T)oufS\.URa\{2|S ̕I]Еst띙T[oAjWj9Qg iȨj,/ UuJ~kUCԟY .i  *O}dD%UrM2I^l41I ۠j^>S1t 7LIۗ7$ s`f\gh$ۙJCnO9d`%/0Y j%Q:(yh-Q7%7 E+Jf^>FTYJvc?(*<DeڗU]3WGFZWz:Sj-qk"Ժ25\EG]ex/OU9Ҵ;ARv;D0)<}K`3m\FښB* T]E_Ҷ>2g>VmHxh)E2X&2Bȅsp )jT؆.j :F)M)J hɲX4eQ;L>s@DYG%4¯6( |HET"*.0U{ujͰ;6}&]E/11y\l!B؃!+9߈)vV+5]M(HIЋdvtYME=^EpNƔp£ª1LJ ۼiFGK1HGwXFPDw=nqtW:ltL+@~5|44e/dT\'Q /ѸwrJ[G Po_I߳J}tбNW6kA: bXl#2ZAzk5t,a%=HGwui/9myĪ@؞c{)plq:88۸`,6VhQzc%5ؿFz,6VvQ6꾫|Laj+-Ngf)nW-]C2Q_=tpF5KS>*hK;>cb_tPesnK<Oh}_i+r\H~[b^[WGӵbm]t?DaƸz!H^9 [qhl}sl]04A_ ftE2"ĤaP\Rl`!2ZAz |M >';b i;/)½&T޶lrRnkDh)MVmiI&u]w׼`v:Nlt>9lkn+MϹL; 1m25ϊ9@<9z:$8oVޑՁw%lQ>Rl 2ZAzJbj$8rPl [A$;G`HPh#D\`$SVcFjd.35ܑO6ܕCbG]~j:DgyaZḩ0/ĽQcWUO&gp~eQ_IɋϿCyedyY'CNJlGC s)1lO?0qyLƒŔDCm |yQ@]V=>qaed> x'_w7wx'cS9peNe6t |'ŚMh)5:`ҽSFbͦuGwuߕMq39aI7)ż5/Q=9b[1b3ݭF!֌cKv [qL^t𜱵QZ>stream hMs6Sp?<=i{LCҞ29@DaL /Q97+ϾX6Ѵ$mJZ5m**jhSS6 @'aH$v|_?~mW c7couw[o[|̖MYx^ zsq?w2cwysÿ u;({m|odG"="ρ8'xIGz2lov{rӾ FG>qbGXa-f\}ǎ,d Vۧ/Ȁbf/ד`oa'3"/_])!+ u|}!D2%PL+Z5%yIV*i+wz5!<y|-ֆ/)Ezgf7Ǵt)B\7 xңj> D(YQ4L}3 y.U[fc]/vt:N~`o tf8eqSĚH 枴'ѨZ)djf YQm|])1%9#\*H+ 6>Y \_,{&ȘZ'Gv5P@B,*gu t퓵dBk\n͔~NY&΍nfkhaxp>VnKU0ۄ!$5 vP@FIZ V <Na lOƿJd>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 68 0 obj <>stream xYr7E^xKR% ы2Y2ۢ\DtŲ2{%ٔ5ե=; GJTeBF _$WBK ni5M*BZ1HX6"1cg -Ee%X)iU &~=De"MCuMQk-I$ &~=F G *Hd(3#d^k{$,*TA {BQ,8hm⪢aIѤ`]E{XE6gW7H$׃]܆oc>I񌖌g1 vJ I r S,bl[2N#o=YAX1 )k<#^4ri|~`C35۰)[r؂ݲi~$RYY3 FAYdS`~W4Zf"L-sIeڬզ6NྩJ)rf9ۇL1W5D8{&l[ѯ ko;|7r~?N_7P"29oFxT xck|qJW7::+M \aeAHFWx}WRKnW'be 3uy ?x D?B;aH+d1 3޶ |"5M0v05u (@cC茡)P5I`G6Fȱoxn@j[X'SMILD]alNdY=7;U0QB Z;Jr#t.Kꏻ_},/E)ϫ6-v3dA(IkoqNJB[VNyZI im>Y }ΧB)y/WNy,йMY xPgY|w- Fmm-V'( S*x&kSdt.<;i^'=}#w,+f>LtvR"Q>Ȥ];pJNhKB@]љgK9f[)7jѯjŸ=7*T#,'qzP,Љ R]ӱm`FV=;l)! UUe$)$u%<+qgMgIRInGl5Rm|Tu0X?I7\~ f8(Z9Eސl}uP"CH( 틌O,}_/5%Ö!Ե#:j:v?SX}Ҡj/Pϝ1ux$>!%O㣴ώ>q%M+u|Uu$8{ƽq=G5>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 70 0 obj <>stream xZo# I!n"PyY&BHRL2Ojҙ)([Zݾfgg~oxQ"W/BWDkyDYq]*K_k>)Duwtz2H>꒯?<gUFsS"keJ?}baD]hT."&3B¸Ў7h٥ҏE;a@"9Hz.'/%_4LE7c7c~D񊆌cp#BU$T8&a a3(ݲ9AYIVcx+kFPξa"scJ(Lg)3d¼ ̸_Bۼm-kt;/-d;|C]%;agL@]y/k?V>70C8Dg7?}q``)\5Kr R:%ڷnDJ'[<º X9ã])sxNUY]ϩ^2T0 ,|%)%K_рuQJQV*ȵ}<>!9Y|4fP*KשsQąZ ~j   |rrݐ=;6zVv ZS t`J;@uq&`{p` S(_T_)8rbaz4ȟ٘S!ʱ>u5(a):sxNi Z,"P'lhݢeܢHC 0z%q`p E@[,96azr\^oW@&x>;k]|ER"  TCvqn-7V耱% NGZTt*ڥ6q(J2I+*ȤŊbPAٺDX"]<Ȥ"m8Gq]<`iS6$ξmŒ0g'tM> ķ;ݭG}-JwE Z{bfH*ՑLEG KK%/wI\Piݒi_3!wz(oȧaģ; ~c߾b#*SޚB ם¾cOWfTgaSWȴٚ \|Kh.NbɕUv$:ÅŰKN@CVd_+vVRG8DBrn~ y &~D76G@ʹKGE>Vݖb;PSH+PzI23xYgqKfW2/4濂| endstream endobj 71 0 obj <>stream hUn0dU  QVI1L$N'iD,^$<IT&Xh'as &X8Y-aLrp_W'OǾ[rZ4pj:zT7CJ߽N {ױHDkIO C[ $'! /7F36yz@\;}/R:,rvc)Y;/wʦݼ;ǷC(©̩0ShbT#}@ 01m endstream endobj 72 0 obj <>/MediaBox[0 0 595.28 841.89]/Parent 118 0 R/Resources 149 0 R/Rotate 0/TrimBox[0.0 0.0 595.28 841.89]/Type/Page>> endobj 73 0 obj <>stream xYmo|_ߚi_o Ej #LRbRgfwǓDwm F/۾OH;.dudN9Dxq&Z[/ÙNB-|CCU:%D^!LG%s'2|1єC7#1"tfq]k:&D{׏F!DnY IrCxu K#v ij5wF+[c[+KmHMi+}Zcy[YӺ`M " }_6/1MsxtlO=}CN'l+КF aB6`εZ9eUIif}2.fmjϝtԃ':Su~VjԟHݪs5Wh(V<e"6U !>n~?e;(X8 )4Md86I񞭚?X|j^!Gu Ku+P- %9/ Sus$_HF25o;lj%t˒N O#,YaHʩmc HH{$P_jEk%#$f"7\5x!p+tk|ĨKP8wqz[p,<84Z}è_NuHh2Xz(^1!(M~D?d<qL3tg[i8תҶ/LDOg0J?ArhVzU1Zp%(!+R+$&\F]pJo!Qs|7_JÎu *^=uG&1ݚc \:/'_>+EryS r=e~A?@oy@^K8;C8 ci#6~DÂJ(h]0cE/sN%cv' OxČ%/ϤވA#]축DePM X9LoQx|O< @AX5?ipTC-?{(\h{Z^%'~$׌̇"K/Ch^G,͈ ˸G)Ѩ·9Kn=sﲣn'%1c՞uwm߯aضdIY:ΠD񾾺Ͻ'G^ܷ:P'fpY8;׮;Uap+&X2ߍSϥ1z=bbޡ[hz_egTroyi:ŋ;;M=|bX#p='_ y'wov'N_5 &Lg+}CmW AmYvąyηWu{Ž9j.XbGnQ'N\_DS3V17BiYzsDt3jg 6CH%HǤR q@)Lx .q8;ũjV0[Cd0Q%{? 7#?70]XKHX%a:JR+FKūNjN`8ᜧ&V]r֧?%|,eŝ܋._r"8!dp`oD!u!LH-l "+!s)"I!@Ә=nM^$:n0)l&N7qti7 ϖcV h˼e=\;]Lk|[{wP @c endstream endobj 74 0 obj <>stream h޼Ks0QtlzY@f!~4Ml ၿH[:FZid׊T'RK+ y XI'4rb\@\G);˹Ʊ?]lϺacu!ןihk,QM?vE)sIǧ?Tv8؈ֳ&JY޲3؁mU x5 ;a"bgT#;tȾ0f%cʼnV+3V7];ojhVNxSp` y"I[W=Ӷӿqn(Fq%ݥrR+L6Զ Y%l v !g/&Dl@J'<$BWDB@5 aBb-n#]Ʋ$ٜ2MeD\yF;Tgm ICyG&;rzĞ(3D.4]Acypf=E.@x]X&顄5*`opSJ_q ݁ܠb5Fr՟j6S=@mHhZ PΝ6>stream 2017-05-01T17:53:42+01:00 2017-05-01T09:52:20-07:00 2017-05-01T09:52:20-07:00 mPDF 6.0 application/pdf CD-HIT User's Guide uuid:2909c9cd-75a7-c245-b7d7-5152e22ee9ed uuid:79bc2a57-fc80-834b-8f15-2534984d747a endstream endobj 76 0 obj <>stream h,ϻ @W7mҤL#b'BBQ!#ۜ9_1#rHM<'Y1WQIjzͶ=#(D! QB b 8$  H@R G ]k맷||/ 7 endstream endobj 77 0 obj <>stream h24T0Pw.JM,sI,Ip2204705044756160T70POAS``ijddk`QPRZ`gYZZ^^ig`! endstream endobj 78 0 obj <>/Filter/FlateDecode/ID[<3F236C86A7B44F8483A8D7BDA3A25FA7>]/Info 119 0 R/Length 232/Root 121 0 R/Size 120/Type/XRef/W[1 3 1]>>stream hbb&FV.&F+wDdEނHn' "H8}Q f?lz0S \FF_ f$w]{+"\8 I\f8= H`7`9TYzo@$odDžXlT`*0NMȣd "-LcO ?9.d" e8@ endstream endobj startxref 116 %%EOF cdhit-4.6.8/doc/cdhit-user-guide.tex000066400000000000000000001137251312257207200172670ustar00rootroot00000000000000 \documentclass[12pt,a4paper]{article} \usepackage[latin1]{inputenc} \usepackage{amsmath} \usepackage{amsfonts} \usepackage{amssymb} \usepackage{scalefnt} \usepackage{titlesec} \usepackage{hyperref} \usepackage{cite} \usepackage{graphicx} \usepackage{wrapfig} \usepackage{xcolor} \usepackage{fancyvrb} %\usepackage{tikz} %\usepackage{pgflibraryarrows} %\usepackage{pgflibrarysnakes} %\usetikzlibrary{decorations.markings} %\usetikzlibrary{patterns,fadings} \addtolength{\hoffset}{-4em} \addtolength{\textwidth}{8em} \addtolength{\voffset}{-4em} \addtolength{\textheight}{8em} \setlength{\parindent}{2em} \linespread{1.1} % also in front page \renewcommand\FancyVerbTab{\textcolor{tabcolor}{$\mid$}} \newcommand*{\justifyheading}{\centering} \titleformat{\section} {\normalfont\Huge\bfseries\justifyheading}{\thesection}{1em}{} \titleformat{\subsection} {\normalfont\Large\bfseries}{\thesubsection}{1em}{} \usepackage{listings} \lstset{ % language=C, % choose the language of the code basicstyle=\small\ttfamily, % the size of the fonts that are used for the code numbers=left, % where to put the line-numbers numberstyle=\small\ttfamily, % the size of the fonts that are used for the line-numbers stepnumber=1, % the step between two line-numbers. If it's 1 each line will be numbered numbersep=5pt, % how far the line-numbers are from the code backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color} showspaces=false, % show spaces adding particular underscores showstringspaces=false, % underline spaces within strings showtabs=false, % show tabs within strings adding particular underscores frame=single, % adds a frame around the code tabsize=2, % sets default tabsize to 2 spaces captionpos=b, % sets the caption-position to bottom breaklines=true, % sets automatic line breaking breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace escapeinside={\%*}{*)} % if you want to add a comment within your code } \title{CD-HIT User's Guide } \date{} \begin{document} \scalefont{1.1} \maketitle \vspace{10em} \begin{center} Last updated: 2012-04-25 \href{http:\slash \slash cd-hit.org}{http:\slash \slash cd-hit.org} \href{http:\slash \slash bioinformatics.org\slash cd-hit\slash }{http:\slash \slash bioinformatics.org\slash cd-hit\slash } Program developed by Weizhong Li's lab at UCSD \href{http:\slash \slash weizhong-lab.ucsd.edu}{http:\slash \slash weizhong-lab.ucsd.edu} \href{liwz@sdsc.edu}{liwz@sdsc.edu} \end{center} \clearpage \tableofcontents \clearpage \clearpage \section{Introduction } CD-HIT was originally a protein clustering program. The main advantage of this program is its ultra-fast speed. It can be hundreds of times faster than other clustering programs, for example, BLASTCLUST. Therefore it can handle very large databases, like NR. The 1st version of this program, CD-HI, was published and released in 2001. The 2nd version, called CD-HIT, was published in 2002 with significant improvements. Since 2004, CD-HIT has been hosted at bioinformatics.org as an open source project. Since its release, CD-HIT has been getting more and more popular. It has a significant user base, I estimated at over several thousands users. It is used at many research and educational institutions. For example, at {\bf UniProt}, CD-HIT is used to generate the {\bf UniRef} reference data sets (\href{http:\slash \slash www.pir.uniprot.org\slash database\slash DBDescription.shtml}{http:\slash \slash www.pir.uniprot.org\slash database\slash DBDescription.shtml}). It is also used in {\bf PDB} to treat redundant sequences (\href{http:\slash \slash rutgers.rcsb.org\slash pdb\slash redundancy.html}{http:\slash \slash rutgers.rcsb.org\slash pdb\slash redundancy.html}). In 2006, the 3rd major updates were published and released with abilities to perform various jobs like clustering a protein database, clustering a DNA/RNA database, comparing two databases (protein or DNA/RNA), generating protein families, and many others. The CD-HIT web server was implemented in 2009, which allows users to cluster or compare sequences without using command CD-HIT. The server provides interactive interface and additional visualization tools. It also provides pre-calculated and regularly updated sequence clusters for several widely used databases. CD-HIT-454, a special version of CD-HIT was implemented in 2010 to cluster artificial duplicated reads in pyrosequencing (454) data. Currently, CD-HIT package has many programs: cd-hit, cd-hit-2d, cd-hit-est, cd-hit-est-2d, cd-hit-para, cd-hit-2d-para, psi-cd-hit, psi-cd-hit-2d, cd-hit-454. I also developed some utility tools, written in Perl, to help run and analyze CD-HIT jobs. This program is still under active development; new features and new programs will be out in the future. It can be copied under the GNU General Public License version 2 (GPLv2). \clearpage \section{Algorithm } Algorithms for CD-HIT were described in three papers published in Bioinformatics. \begin{itemize} \item 1. Clustering of highly homologous sequences to reduce the size of large protein databases. Weizhong Li, Lukasz Jaroszewski \& Adam Godzik. Bioinformatics (2001) 17:282-283, \href{http:\slash \slash bioinformatics.oupjournals.org\slash cgi\slash reprint\slash 17\slash 3\slash 282.pdf}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11294794}{Pubmed} \item 2. Tolerating some redundancy significantly speeds up clustering of large protein databases. Weizhong Li, Lukasz Jaroszewski \& Adam Godzik. Bioinformatics (2002) 18: 77-82, \href{http:\slash \slash bioinformatics.oupjournals.org\slash cgi\slash reprint\slash 18\slash 1\slash 77.pdf}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11836214}{Pubmed} \item 3. Cd-hit: a fast program for clustering and comparing large sets of protein or nucleotide sequences. Weizhong Li \& Adam Godzik. Bioinformatics (2006) 22:1658-1659 \href{http:\slash \slash bioinformatics.oxfordjournals.org\slash cgi\slash reprint\slash 22\slash 13\slash 1658}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?db=pubmed&cmd=Retrieve&dopt=Abstract&list_uids=16731699}{Pubmed} \end{itemize} I suggest that you read these papers if (1) you want to understand more details about the algorithm or (2) you want know why it is so fast. If you don't have time to read these papers, the algorithms are summarized below. CD-HIT web server and CD-HIT-454 are described in these two papers: \begin{itemize} \item 4. Ying Huang, Beifang Niu, Ying Gao, Limin Fu and Weizhong Li. CD-HIT Suite: a web server for clustering and comparing biological sequences. Bioinformatics, (2010). 26:680 \href{http:\slash \slash bioinformatics.oxfordjournals.org\slash cgi\slash reprint\slash btq003v1}{PDF} \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash pubmed\slash 20053844}{Pubmed} \item 5. Beifang Niu, Limin Fu, Shulei Sun and Weizhong Li, Artificial and natural duplicates in pyrosequencing reads of metagenomic data. BMC Bioinformatics, (2010) 11:187 \href{http:\slash \slash www.biomedcentral.com\slash content\slash pdf\slash 1471-2105-11-187.pdf}{PDF} \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash pubmed\slash 20388221}{Pubmed} \end{itemize} \subsection{CD-HIT clustering algorithm } Clustering a sequence database requires all-by-all comparisons; therefore it is very time-consuming. Many methods use BLAST to compute the all vs. all similarities. It is very difficult for these methods to cluster large databases. While CD-HIT can avoid many pairwise sequence alignments with a short word filter I developed. In CD-HIT, I use greedy incremental clustering algorithm method. Briefly, sequences are first sorted in order of decreasing length. The longest one becomes the representative of the first cluster. Then, each remaining sequence is compared to the representatives of existing clusters. If the similarity with any representative is above a given threshold, it is grouped into that cluster. Otherwise, a new cluster is defined with that sequence as the representative. Here is how the short word filter works. Two proteins with a certain sequence identity must have at least a specific number of identical dipeptides, tripeptides and etc. For example, for two sequences to have 85\% identity over a 100-residue window they have to have at least 70 identical dipeptides, 55 identical tripeptides, and 25 identical pentapeptides. By understanding the short word requirement, CD-HIT skips most pairwise alignments because it knows that the similarity of two sequences is below certain threshold by simple word counting. Another reason why CD-HIT is so fast is the use of an index table. I just use very short word with size 2~5. For instance, the total number of possible pentapeptides is only 215 (each position has 21 possibilities, 20 amino acids plus "X"), and the index table requires only 4 million entries, which just matches the RAM scale of current computers. Index table makes the counting of short word very efficiently. And a longer word is more efficient than a shorter one. \subsection{Algorithm limitations } A limitation of short word filter is that it can not be used below certain clustering thresholds. In a worst case scenario (figure below), when mismatches are evenly distributed along the alignment, the numbers of common short words are minimal. So theoretically, pentapeptide, tetrapeptide, tripeptide and dipeptide could only be used for thresholds above 80\%, 75\%, 66.67\% and 50\% respectively. \begin{figure}[!h] \includegraphics[width=\textwidth]{Figure1.png} \end{figure} Short word filtering is limited to certain clustering thresholds. Evenly distributed mismatches are shown in alignments with 80\%, 75\%, 66.67\% and 50\% sequence identities. The number of common pentapeptides in (a), tetrapeptides in (b), tripeptides in (c), and dipeptides in (d) can be zero. However, biological sequences are not lines of random letters; proteins usually have more conserved regions and more diverse regions as the result of specific constraints of evolution. Situations such as in above figure are very rare in the real world, and the actual number of common short words is much higher than in the worst case scenarios. We did a large-scale statistical analysis on short words. We found, for example, even at 70\% identity, sequences still have statistically significant number of common pentapeptides. Current CD-HIT is based on this short word statistics. But the short word filters are still limited to certain thresholds. The reasonable limits of clustering thresholds for pentapeptide, tetrapeptide, tripeptide and dipeptide are approximately 70\%, 60\%, 50\% and 40\%, respectively. There is another problem introduced by the greedy incremental clustering. Let say, there are two clusters: cluster \#1 has A, X and Y where A is the representative, and cluster \#2 has B and Z where B is the representative. The problem is that even if Y is more similar to B than to A, it can still in cluster \#1, simple because Y first hit A during clustering process. While this problem could be reduced by multiple-step clustering (see following sections). \subsection{CD-HIT-2D comparing algorithm } The above short word filtering and index table can also be used in other sequence comparison tasks, for example, comparing two data sets and reporting the matches between 2 datasets over a certain similarity threshold. This is a very common job, so I developed another program cd-hit-2d for fast comparison of two dataset. \subsection{DNA/RNA clustering \& comparing } The original CD-HIT was developed for protein clustering. But the short word filtering and index table implementation can also be applied to DNA/RNA. Therefore, I wrote another two new programs cd-hit-est and cd-hit-est-2d. I believe they can be very useful in handling DNA sequences. \subsection{PSI-CD-HIT clustering } The lowest threshold of CD-HIT is around 40\%, in many applications, people need a much lower threshold, like 25\%. I am planning to develop such application (may be called CD-HIT-LOW, I don't know yet), but for now, I use PSI-CD-HIT for this purpose. PSI-CD-HIT is actually a Perl script I wrote, which runs similar algorithm like CD-HIT but using BLAST to calculate similarities. Below are the procedures of PSI-CD-HIT: \begin{enumerate} \item Sort sequences by decreasing length \item First one is the first representative \item Using 1st one blast all remaining sequences, pick up its neighbors that meet the clustering threshold \item Repeat until done \end{enumerate} \subsection{CD-HIT-454 clustering } We implemented a program called cd-hit-454 to identify duplicated 454 reads by reengineering cd-hit-est. Duplicates are either exactly identical or meet these criteria includes: (1) they start at the same position; (2) their lengths can be different, but shorter one must be fully aligned with the longer one (the seed); (3) they can only have 4\% mismatches (insertion, deletion, and substitution); and (4) only 1 base is allowed per insertion or deletion. Here, (3) and (4) can be adjusted by users. We allow mismatches in order to tolerate sequencing errors. \clearpage \section{User's Guide } \subsection{Installation } Most CD-HIT programs were written in C++. Installing CD-HIT package is very simple: \begin{itemize} \item download current CD-HIT at \href{http:\slash \slash bioinformatics.org\slash cd-hit}{http:\slash \slash bioinformatics.org\slash cd-hit}, for example cd-hit-2006-0215.tar.gz \item unpack the file with " tar xvf cd-hit-2006-0215.tar.gz --gunzip" \item change dir by "cd cd-hit-2006" \item compile the programs by "make" \item you will have all cd-hit programs compiled \end{itemize} \subsection{Installation of multiple threaded version } You can take advantage of multiple-threaded function of cd-hit to speed up calculation. Please compile the programs by "make openmp=yes". OpenMP is supported in most recent Linux systems. There are some macros defined in a cd-hi.h that control some basic parameters. I believe, in 99\% of the case, that these setting are fine. But you can change them also. I list some of them here: \begin{lstlisting} #define MAX_SEQ 65536 Max length of sequences. #define MAX_DIAG 133000 This number should be the double of MAX_SEQ. #define MAX_GAP 65536 Max allowed gap length in dynamic programming subroutine. #define MAX_LINE_SIZE 300000 Max allowed length of a single line from input FASTA file. #define MAX_FILE_NAME 1280 Max allowed length of filename. \end{lstlisting} Please note that, the above values may not reflect the actual values used in the program, please refer to the source file if you want to know the exact values. \subsection{CD-HIT } CD-HIT clusters proteins into clusters that meet a user-defined similarity threshold, usually a sequence identity. Each cluster has one representative sequence. The input is a protein dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Basic command: \begin{lstlisting} cd-hit -i nr -o nr100 -c 1.00 -n 5 -M 2000 cd-hit -i db -o db90 -c 0.9 -n 5 \end{lstlisting} where\\ \texttt{db} is the filename of input,\\ \texttt{db90} is output,\\ \texttt{0.9} means 90\% identity, is the clustering threshold\\ \texttt{5} is the size of word\\ Choose of word size: \texttt{-n 5} for thresholds 0.7 ~ 1.0\\ \texttt{-n 4} for thresholds 0.6 ~ 0.7\\ \texttt{-n 3} for thresholds 0.5 ~ 0.6\\ \texttt{-n 2} for thresholds 0.4 ~ 0.5\\ Complete options: {\bf The most updated options are available from the command line version of the programs. Running the programs without any argument will print out the detailed options.} \begin{lstlisting} -i input input filename in fasta format, required -o output filename, required -c sequence identity threshold, default 0.9 this is the default cd-hit's "global sequence identity" calculated as: number of identical amino acids in alignment divided by the full length of the shorter sequence -G use global sequence identity, default 1 if set to 0, then use local sequence identity, calculated as : number of identical amino acids in alignment divided by the length of the alignment NOTE!!! don't use -G 0 unless you use alignment coverage controls see options -aL, -AL, -aS, -AS -b band_width of alignment, default 20 -M max available memory (Mbyte), default 400 -n word_length, default 5, see user's guide for choosing it -l length of throw_away_sequences, default 10 -t tolerance for redundance, default 2 -d length of description in .clstr file, default 20 if set to 0, it takes the fasta defline and stops at first space -s length difference cutoff, default 0.0 if set to 0.9, the shorter sequences need to be at least 90% length of the representative of the cluster -S length difference cutoff in amino acid, default 999999 if set to 60, the length difference between the shorter sequences and the representative of the cluster can not be bigger than 60 -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -uL maximum unmatched percentage for the longer sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -uS maximum unmatched percentage for the shorter sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -U maximum unmatched length, default 99999999 if set to 10, the unmatched region (excluding leading and tailing gaps) must not be more than 10 bases -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive it is recommended to use -B 1 for huge databases -p 1 or 0, default 0 if set to 1, print alignment overlap in .clstr file -T number of threads, default 1; with 0, all CPUs will be used -g 1 or 0, default 0 By cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast mode). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) \end{lstlisting} Alignment coverage control: See the figure below, the -aL, -AL, -aS and -AS options can be used to specify the alignment coverage on both the representative sequence and other sequences. -s and -S can control the length difference between the representative sequence and other sequences. \begin{figure}[!h] \includegraphics[width=\textwidth]{Figure2.png} \end{figure} \texttt{ aL = R$_a$ / R\\ AL = R - R$_a$\\ aS = S$_a$ / S\\ AS = S - S$_a$\\ s = S$_a$ / R$_a$\\ S = R / S\\ U = S$_1$ + S$_2$\\ uL = U / R\\ uS = U / S } Output: The output .clstr file looks like \begin{lstlisting} >Cluster 0 0 2799aa, >PF04998.6|RPOC2_CHLRE/275-3073... * >Cluster 1 0 2214aa, >PF06317.1|Q6Y625_9VIRU/1-2214... at 80% 1 2215aa, >PF06317.1|O09705_9VIRU/1-2215... at 84% 2 2217aa, >PF06317.1|Q6Y630_9VIRU/1-2217... * 3 2216aa, >PF06317.1|Q6GWS6_9VIRU/1-2216... at 84% 4 527aa, >PF06317.1|Q67E14_9VIRU/6-532... at 63% >Cluster 2 0 2202aa, >PF06317.1|Q6UY61_9VIRU/8-2209... at 60% 1 2208aa, >PF06317.1|Q6IVU4_JUNIN/1-2208... * 2 2207aa, >PF06317.1|Q6IVU0_MACHU/1-2207... at 73% 3 2208aa, >PF06317.1|RRPO_TACV/1-2208... at 69% \end{lstlisting} where\\ a "$>$" starts a new cluster\\ a "*" at the end means that this sequence is the representative of this cluster\\ a "\%" is the identity between this sequence and the representative \subsection{CD-HIT-2D } CD-HIT-2D compares 2 protein datasets (db1, db2). It identifies the sequences in db2 that are similar to db1 at a certain threshold. The input are two protein datasets (db1, db2) in fasta format and the output are two files: a fasta file of proteins in db2 that are not similar to db1 and a text file that lists similar sequences between db1 \& db2. Basic command: \begin{lstlisting} cd-hit-2d -i db1 -i2 db2 -o db2novel -c 0.9 -n 5 \end{lstlisting} where\\ \texttt{db1} \& \texttt{db2} are inputs,\\ \texttt{db2novel} is output,\\ \texttt{0.9} means 90\% identity, is the comparing threshold\\ \texttt{5} is the size of word Please note that by default, I only list matches where sequences in db2 are not longer than sequences in db1. You may use options -S2 or -s2 to overwrite this default. You can also run command: \begin{lstlisting} cd-hit-2d -i db2 -i2 db1 -o db1novel -c 0.9 -n 5 \end{lstlisting} Choose of word size (same as cd-hit): \begin{lstlisting} -n 5 for thresholds 0.7 ~ 1.0 -n 4 for thresholds 0.6 ~ 0.7 -n 3 for thresholds 0.5 ~ 0.6 -n 2 for thresholds 0.4 ~ 0.5 \end{lstlisting} More options: Options, -b, -M, -l, -d, -t, -s, -S, -B, -p, -aL, -AL, -aS, -AS, -g, -G, -T are same to CD-HIT, here are few more cd-hit-2d specific options: \begin{lstlisting} -i2 input filename for db2 in fasta format, required -s2 length difference cutoff for db1, default 1.0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 0.9, seqs in db1 may just >= 90% seqs in db2 -S2 length difference cutoff, default 0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 60, seqs in db2 may 60aa longer than seqs in db1 \end{lstlisting} \subsection{CD-HIT-EST } CD-HIT-EST clusters a nucleotide dataset into clusters that meet a user-defined similarity threshold, usually a sequence identity. The input is a DNA/RNA dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Since eukaryotic genes usually have long introns, which cause long gaps, it is difficult to make full-length alignments for these genes. So, CD-HIT-EST is good for non-intron containing sequences like EST. Basic command: \begin{lstlisting} cd-hit-est -i est_human -o est_human95 -c 0.95 -n 8 \end{lstlisting} Choose of word size: \begin{lstlisting} -n 8,9,10 for thresholds 0.90 ~ 1.0 -n 7 for thresholds 0.88 ~ 0.9 -n 6 for thresholds 0.85 ~ 0.88 -n 5 for thresholds 0.80 ~ 0.85 -n 4 for thresholds 0.75 ~ 0.8 \end{lstlisting} More options: Options, -b, -M, -l, -d, -t, -s, -S, -B, -p, -aL, -AL, -aS, -AS, -g, -G, -T are same to CD-HIT, here are few more cd-hit-est specific options: \begin{lstlisting} -r 1 or 0, default 0, if set to 1, comparing both strand (++, +-) \end{lstlisting} \subsection{CD-HIT-EST-2D } CD-HIT-EST-2D compares 2 nucleotide datasets (db1, db2). It identifies the sequences in db2 that are similar to db1 at a certain threshold. The input are two DNA/RNA datasets (db1, db2) in fasta format and the output are two files: a fasta file of sequences in db2 that are not similar to db1 and a text file that lists similar sequences between db1 \& db2. For same reason as CD-HIT-EST, CD-HIT-EST-2D is good for non-intron containing sequences like EST. Basic command: \begin{lstlisting} cd-hit-est-2d -i mrna_human -i2 est_human -o est_human_novel -c 0.95 -n 8 \end{lstlisting} Choose of word size (same as CD-HIT-EST): \begin{lstlisting} -n 8,9,10 for thresholds 0.90 ~ 1.0 -n 7 for thresholds 0.88 ~ 0.9 -n 6 for thresholds 0.85 ~ 0.88 -n 5 for thresholds 0.80 ~ 0.85 -n 4 for thresholds 0.75 ~ 0.8 \end{lstlisting} More options: Options, -b, -M, -l, -d, -t, -s, -S, -s2, -S2, -B, -p, -aL, -AL, -aS, -AS, -g, -G, -T are same to CD-HIT-2d, here are few more cd-hit-est-2d specific options: \begin{lstlisting} -r 1 or 0, default 0, if set to 1, comparing both strand (++, +-) \end{lstlisting} \subsection{Multi-threaded programs } Multi-threaded cd-hit programs were implemented with OpenMP. Option "-T n" will enable cd-hit to run in parallel in a single multi-core computer. The default value of n is 1 (single thread). "-T 0" will use all the cores in that computer. We have run cd-hit on 4-core, 8-core to 32-core computers and have observed a great speedup. \subsection{CD-HIT-PARA } CD-HIT-PARA is a script that runs cd-hit, cd-hit-est in a parallel mode. It splits the input database; runs cd-hit or cd-hit-est in parallel on a computer cluster; and finally merges the outputs into a single file. You can run it as you run cd-hit or cd-hit-est. The input is a protein or DNA/RNA dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. There are two ways to run jobs on a cluster: by ssh to a remote computer and by queuing system (PBS and SGE are implemented). In any case, you should have a shared file system, the path to your working directory must be same on all the remote computers. This script can also be used if you are clustering a very large database and your computer doesn't have enough RAM. In that case, all the divided jobs will still run on a single computer. Implementation (see figure below) \begin{enumerate} \item divide input db into many small dbs in decreasing length \item clusters the 1st db by cd-hit \item run cd-hit-2d for other dbs against 1st db \item repeat cd-hit and cd-hit-2d runs till done \item Combine the results \end{enumerate} \begin{figure}[!h] \includegraphics[width=\textwidth]{Figure3.png} \end{figure} Basic command: \begin{lstlisting} cd-hit-para.pl -i nr90 -o nr60 -c 0.6 -n 4 --B hosts --S 64 \end{lstlisting} where\\ \texttt{--B} hosts is a file with available hostnames\\ \texttt{--S} 64 is the number to split input db into, this number should be several times the number of hosts More options: \begin{lstlisting} --P program, "cd-hit" or "cd-hit-est", default "cd-hit" --B filename of list of hosts, requred unless -Q or -L option is supplied --L number of cpus on local computer, default 0 when you are not running it over a cluster, you can use this option to divide a big clustering jobs into small pieces, I suggest you just use "--L 1" unless you have enough RAM for each cpu --S Number of segments to split input DB into, default 64 --Q number of jobs to submit to queue queuing system, default 0 by default, the program use ssh mode to submit remote jobs --T type of queuing system, "PBS", "SGE" are supported, default PBS --R restart file, used after a crash of run \end{lstlisting} \subsection{CD-HIT-2D-PARA } CD-HIT-2D-PARA is a script that runs cd-hit-2d, cd-hit-est-2d in a parallel mode. It splits the input databases; runs cd-hit-2d or cd-hit-est-2d in parallel on a computer cluster; and finally merges the outputs into a single file. You can run it as you run cd-hit-2d or cd-hit-est-2d. The input is a protein or DNA/RAN dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Basic command: \begin{lstlisting} cd-hit-para.pl -i nr -i2 swissprot -o swissprot_vs_nr -c 0.6 -n 4 --Q 20 -T "SGE" --S 2 --S2 20 \end{lstlisting} where \begin{lstlisting} --P program, "cd-hit-2d" or "cd-hit-est-2d", default "cd-hit-2d" --B filename of list of hosts, requred unless -Q or -L option is supplied --L number of cpus on local computer, default 0 when you are not running it over a cluster, you can use this option to divide a big clustering jobs into small pieces, I suggest you just use "--L 1" unless you have enough RAM for each cpu --S Number of segments to split 1st db into, default 2 --S2 Number of segments to split 2nd db into, default 8 --Q number of jobs to submit to queue queuing system, default 0 by default, the program use ssh mode to submit remote jobs --T type of queuing system, "PBS", "SGE" are supported, default PBS --R restart file, used after a crash of run -h print this help \end{lstlisting} \subsection{PSI-CD-HIT clustering } PSI-CD-HIT clusters proteins into clusters that meet a user-defined similarity threshold, which can be identity or expect value. Each cluster has one representative sequence. The input is a protein dataset in fasta format and the outputs are two files: a fasta file of representative sequences and a text file of list of clusters Basic command: \begin{lstlisting} psi-cd-hit.pl -i nr60 -o nr30 -c 0.3 psi-cd-hit.pl -i nr60 -o nr30 -c 0.3 -b hosts \end{lstlisting} \begin{lstlisting} More options: \end{lstlisting} Options, -l, -d, -s, -S are same to CD-HIT, here are few more psi-cd-hit specific options: \begin{lstlisting} -ce clustering threshold (blast expect), default -1, by default it doesn't use expect threshold, but with positive value, the program cluster sequences if similarities meet either identity threshold or expect value threshold -L coverage of shorter sequence (aligned / full), default 0 -M coverage of longer sequence (aligned / full), default 0 -R (1/0) use psi-blast profile? default 0, perform psi-blast / pdb-blast type search -G (1/0) use global identity? default 1, sequence identity calculated as total identical residues of local alignments / length of shorter sequence -be blast expect cutoff, default 0.000001 -b filename of list of hosts, to run this program in parallel with ssh calls \end{lstlisting} \subsection{Incremental clustering } It is easy to make incremental update with cd-hit /cd-hit-2d. For example: \begin{lstlisting} nr is the nr database of last month month is the new sequences of nr of this month \end{lstlisting} In last month, you ran: \begin{lstlisting} cd-hit -i nr -o nr90 -c 0.9 -n 5 \end{lstlisting} This month, you can run incremental clustering \begin{lstlisting} cd-hit-2d -i nr90 -i2 month -o month-new -c 0.9 -n 5 cd-hit -i month-new -o month90 -c 0.9 -n 5 cat month90 >> nr90 clstr_merge.pl nr90.clstr month-new.clstr > temp.clstr cat temp.clstr month90.clstr > this_month_nr90.clstr \end{lstlisting} This approach is much faster than runing from scratch. It also preserves stable cluster structure. \subsection{Hierarchically clustering } With multiple-step, iterated runs of CD-HIT, you perform a clustering in a neighbor-joining method, which generates a hierarchical structure. \begin{figure}[!h] \includegraphics[width=\textwidth]{Figure4.png} \end{figure} Commands: \begin{lstlisting} cd-hit -i nr -o nr80 -c 0.8 -n 5 cd-hit -i nr80 -o nr60 -c 0.6 -n 4 psi-cd-hit.pl -i nr60 -o nr30 -c 0.3 \end{lstlisting} This way is faster than one-step run from nr directly to nr30. It can also helps correct errors by one-step clustering (see last paragraph in algorithm limitation section). \clearpage \section{CD-HIT tools } \subsection{cd-hit-div, cd-hit-div.pl } Both the executable binary program cd-hit-div and the perl script divide a FASTA file into pieces. The difference is that cd-hit-div sorts the sequences before dividing them while the perl script does not. Commands: \begin{lstlisting} cd-hit-div -i input -o output -div n cd-hit-div.pl input output n \end{lstlisting} where "n" is the number of output files. The output files will be named as output-0, output-1 etc. \subsection{plot\_len.pl } This is a script to print out distributions of clusters \& sequences. Commands: \begin{lstlisting} plot_len.pl input.clstr \ 1,2-4,5-9,10-19,20-49,50-99,100-299,500-99999 \ 10-59,60-149,150-499,500-1999,2000-999999 \end{lstlisting} where \begin{lstlisting} 2nd line are sizes of cluster 3rd line are lengths of sequences \end{lstlisting} It will print distribution of clusters and sequences : \begin{lstlisting} Size # seq #clstr 10-59 60-149 150-499 500-1999 2000-up 1 266312 266312 36066 103737 103285 22727 497 2-4 208667 81131 1229 14680 44607 20006 609 5-9 156558 24198 118 2148 12026 9388 518 10-19 155387 11681 30 596 5024 5462 569 20-49 176815 6007 6 139 2212 3135 515 50-99 106955 1568 0 24 410 955 179 100-499 154209 896 0 3 124 597 172 500-up 43193 40 0 0 1 14 25 Total 1268096 391833 37449 121327 167689 62284 3084 \end{lstlisting} \subsection{clstr\_sort\_by.pl } This script sort clusters in .clstr file by length, size Commands: \begin{lstlisting} Clstr_sort_by.pl input.clstr no > input_sort.clstr \end{lstlisting} Where, "no" means by size of the cluster \subsection{clstr\_sort\_prot\_by.pl } This script sort sequences within clusters in .clstr file by length, name, etc. Commands: \begin{lstlisting} Clstr_sort_prot_by.pl input.clstr id > input_sort.clstr \end{lstlisting} Where, "no" means by id of sequences \subsection{clstr\_merge.pl } It merges two or more .clstr files. The cluster orders need to be identical. Commands: \begin{lstlisting} cd-hit-2d -i db1 -i2 db2 -o db2new -c 0.9 -n 5 cd-hit-2d -i db1 -i2 db3 -o db3new -c 0.9 -n 5 clstr_merge.pl db2new.clstr db3new.clstr > db23new.clstr \end{lstlisting} \subsection{clstr\_merge\_noorder.pl } It merges two or more .clstr files. The cluster orders do not have to be identical. Commands: \begin{lstlisting} cd-hit-2d -i db1 -i2 db2 -o db2new -c 0.9 -n 5 cd-hit-2d -i db1 -i2 db3 -o db3new -c 0.9 -n 5 clstr_merge_noorder.pl db2new.clstr db3new.clstr > db23new.clstr \end{lstlisting} \subsection{clstr\_ renumber.pl } It renumbers clusters and sequences within clusters in .clstr file after merge or other operations Commands: \begin{lstlisting} Clstr_renumber.pl input.clstr > input_ren.clstr \end{lstlisting} \subsection{clstr\_rev.pl } It combines a .clstr file with its parent .clstr file Commands: \begin{lstlisting} cd-hit -i nr -o nr90 -c 0.9 -n 5 cd-hit -i nr90 -o nr60 -c 0.6 -n 4 clstr_rev.pl nr90.clstr nr60.clstr > nr60_from90.clstr psi-cd-hit -i nr60 -o nr30 -c 0.3 clstr_rev.pl nr60_from90.clstr nr30.clstr > nr30_from90.clstr \end{lstlisting} \subsection{make\_multi\_seq.pl } This script reads the .clstr file, it generates a separate fasta file for each cluster over certain size and saves it in designated subdirectory. To run this script correctly, "-d 0" option should be used in the cd-hit run and it is better to use "-g 1" in the cd-hit run to get accurate clustering results. For example, Commands: \begin{lstlisting} cd-hit -i db -o dbout -c 0.6 -n 4 -d 0 -g 1 make_multi_seq.pl seq_db dbout.clstr multi-seq 20 \end{lstlisting} will generate fasta files in "multi-seq" directory for clusters with more than 20 member sequences. Files will be named as "clusterN" where "N" is serial number of a cluster. \subsection{clstr2xml.pl } This script converts a cluster file or combines multiple cluster files from a hierarchical cd-hit run to xml format. The output is sorted by sequence length (default) or cluster size. The input cluster files must be in the order of being generated, that is, the cluster file with higher identity cutoff comes first. Command: \begin{lstlisting} clstr2xml.pl [-len|-size] input1.clstr [input2.clstr input3.clstr ...] \end{lstlisting} \clearpage \section{CD-HIT Web Server } The CD-HIT web server is available from \href{http:\slash \slash cd-hit.org}{http:\slash \slash cd-hit.org}. All basic functions of CD-HIT are provided through tab-based interfaces in our web server. For CD-HIT and CD-HIT-EST, users can upload a FASTA file, select a desired sequence identity level and other parameters. CD-HIT-2D (CD-HIT-EST-2D) can compare two databases uploaded by users. H-CD-HIT and H-CD-HIT-EST in our server performs hierarchical clustering up to 3 steps. The CD-HIT-454 web server is also available from \href{http:\slash \slash cd-hit.org}{http:\slash \slash cd-hit.org}. \clearpage \section{References } If you find cd-hit helpful to your research and study, please kindly cite the relevant references from the list below. \begin{enumerate} \item Clustering of highly homologous sequences to reduce the size of large protein databases. Weizhong Li, Lukasz Jaroszewski \& Adam Godzik. Bioinformatics (2001) 17:282-283, \href{http:\slash \slash bioinformatics.oupjournals.org\slash cgi\slash reprint\slash 17\slash 3\slash 282.pdf}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11294794}{Pubmed} \item Tolerating some redundancy significantly speeds up clustering of large protein databases. Weizhong Li, Lukasz Jaroszewski \& Adam Godzik. Bioinformatics (2002) 18: 77-82, \href{http:\slash \slash bioinformatics.oupjournals.org\slash cgi\slash reprint\slash 18\slash 1\slash 77.pdf}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11836214}{Pubmed} \item Cd-hit: a fast program for clustering and comparing large sets of protein or nucleotide sequences. Weizhong Li \& Adam Godzik. . Bioinformatics (2006) 22:1658-1659, \href{http:\slash \slash bioinformatics.oxfordjournals.org\slash cgi\slash reprint\slash 22\slash 13\slash 1658}{PDF}, \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash entrez\slash query.fcgi?db=pubmed&cmd=Retrieve&dopt=Abstract&list_uids=16731699}{Pubmed} \item Ying Huang, Beifang Niu, Ying Gao, Limin Fu and Weizhong Li. CD-HIT Suite: a web server for clustering and comparing biological sequences. Bioinformatics, (2010). 26:680 \href{http:\slash \slash bioinformatics.oxfordjournals.org\slash cgi\slash reprint\slash btq003v1}{PDF} \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash pubmed\slash 20053844}{Pubmed} \item Beifang Niu, Limin Fu, Shulei Sun and Weizhong Li, Artificial and natural duplicates in pyrosequencing reads of metagenomic data. BMC Bioinformatics, (2010), 11:187 \href{http:\slash \slash www.biomedcentral.com\slash content\slash pdf\slash 1471-2105-11-187.pdf}{PDF} \href{http:\slash \slash www.ncbi.nlm.nih.gov\slash pubmed\slash 20388221}{Pubmed} \end{enumerate} \end{document}cdhit-4.6.8/doc/cdhit-user-guide.wiki000066400000000000000000002313461312257207200174320ustar00rootroot00000000000000====== CD-HIT User's Guide ====== Last updated: ~~LASTMOD~~ [[http://cd-hit.org]] Program developed by Weizhong Li's lab at UCSD [[http://weizhongli-lab.org]] and JCVI [[http://jcvi.org]] [[liwz@sdsc.edu]] ===== Introduction ===== CD-HIT is a widely used program for clustering biological sequences to reduce sequence redundancy and improve the performance of other sequence analyses. CD-HIT was originally developed to cluster protein sequences to create reference databases with reduced redundancy (Li, et al., 2001) and was then extended to support clustering nucleotide sequences and comparing two datasets (Li and Godzik, 2006). The CD-HIT web server was implemented in 2009, which allows users to cluster or compare sequences without using command-line CD-HIT. The server provides interactive interface and additional visualization tools. Currently, CD-HIT package has many programs: cd-hit, cd-hit-2d, cd-hit-est, cd-hit-est-2d, cd-hit-para, cd-hit-2d-para, psi-cd-hit, cd-hit-454, cd-hit-dup, cd-hit-lap, cd-hit-OTU etc. There are also many utility scripts, written in Perl, to help run and analyze CD-HIT jobs. Briefly: * cd-hit Cluster peptide sequences * cd-hit-est Cluster nucleotide sequences * cd-hit-2d Compare 2 peptide databases * cd-hit-est-2d Compare 2 nucleotide databases * psi-cd-hit Cluster proteins at <40% cutoff * cd-hit-lap Identify overlapping reads * cd-hit-dup Identify duplicates from single or paired Illumina reads * cd-hit-454 Identify duplicates from 454 reads * cd-hit-otu Cluster rRNA tags * cd-hit Web server Cluster user-uploaded data * cd-hit-para Cluster sequences in parallel on a computer cluster * scripts Parse results and so on * h-cd-hit Hierarchical clustering Recently development of cd-hit, especially the multiple-threaded version introduced in 2012 (Fu et al), enables clustering of very large NGS datasets. For example, it only took cd-hit less than a day on a 32-core computer to cluster a few hundred million protein sequences from a metagenomics study. ===== Algorithm ===== __**[You can skip this session if you are eager to use the programs, no problem].**__ Algorithms for CD-HIT were described in these papers. *1. Weizhong Li, Lukasz Jaroszewski & Adam Godzik. Clustering of highly homologous sequences to reduce the size of large protein databases. Bioinformatics (2001) 17:282-283, [[http://bioinformatics.oupjournals.org/cgi/reprint/17/3/282.pdf|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11294794|Pubmed]] *2. Weizhong Li, Lukasz Jaroszewski & Adam Godzik. Tolerating some redundancy significantly speeds up clustering of large protein databases. Bioinformatics (2002) 18: 77-82, [[http://bioinformatics.oupjournals.org/cgi/reprint/18/1/77.pdf|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11836214|Pubmed]] *3. Weizhong Li & Adam Godzik. Cd-hit: a fast program for clustering and comparing large sets of protein or nucleotide sequences. Bioinformatics (2006) 22:1658-1659 [[http://bioinformatics.oxfordjournals.org/cgi/reprint/22/13/1658|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pubmed&cmd=Retrieve&dopt=Abstract&list_uids=16731699|Pubmed]] *4. Limin Fu, Beifang Niu, Zhengwei Zhu, Sitao Wu and Weizhong Li. CD-HIT: accelerated for clustering the next generation sequencing data. Bioinformatics (2012) 28:3150-3152, doi: 10.1093/bioinformatics/bts565 [[http://bioinformatics.oxfordjournals.org/content/28/23/3150|PDF]] *5. Ying Huang, Beifang Niu, Ying Gao, Limin Fu and Weizhong Li. CD-HIT Suite: a web server for clustering and comparing biological sequences. Bioinformatics, (2010). 26:680 [[http://bioinformatics.oxfordjournals.org/cgi/reprint/btq003v1|PDF]] [[http://www.ncbi.nlm.nih.gov/pubmed/20053844|Pubmed]] *6. Beifang Niu, Limin Fu, Shulei Sun and Weizhong Li, Artificial and natural duplicates in pyrosequencing reads of metagenomic data. BMC Bioinformatics, (2010) 11:187 [[http://www.biomedcentral.com/content/pdf/1471-2105-11-187.pdf|PDF]] [[http://www.ncbi.nlm.nih.gov/pubmed/20388221|Pubmed]] *7. Weizhong Li, Limin Fu, Beifang Niu, Sitao Wu and John Wooley. Ultrafast clustering algorithms for metagenomic sequence analysis. Briefings in Bioinformatics, (2012) 13 (6): 656-668. doi: 10.1093/bib/bbs035 [[http://bib.oxfordjournals.org/content/13/6/656|PDF]] ==== CD-HIT clustering algorithm ==== Clustering a sequence database usually requires all-by-all comparisons; therefore it is very time-consuming. Many methods use BLAST to compute the all vs. all similarities. It is very difficult for these methods to cluster large databases. While CD-HIT can avoid many pairwise sequence alignments with a short word based heuristics. CD-HIT is a greedy incremental clustering approach. The basic CD-HIT algorithm sorts the input sequences from long to short, and processes them sequentially from the longest to the shortest. The first sequence is automatically classified as the first cluster representative sequence. Then each query sequence of the remaining sequences is compared to the representative sequences found before it, and is classified as redundant or representative based on whether it is similar to one of the existing representative sequences. In default manner (fast mode), a query is grouped into the first representative without comparing to other representatives. In accurate mode, a query is compared to all representatives and grouped to the most similar one. Based on this greedy method, we established several integrated heuristics that make CD-HIT very efficient. **Index table**: Most sequence alignment tools use short words or k-mer (k is the length) to speed up computation. For example, BLASTN uses 11-mer and BLASTP uses 3-mer by default. An index table, as opposite to a hash table used in most fast alignment methods, uses a unique index for every unique k-mer, therefore an index table is much faster than a hash table. In CD-HIT, we use k=2~5 for proteins and k=8~12 for DNAs, because the all the k-mers can be indexed in computer memory. **Short word filter**: Two sequences of a certain identity must share at least a specific number of identical k-mers. It is possible to tell that the identity between two sequences is below a cutoff by counting common k-mers. The filter checks the common k-mers and rejects unnecessary alignments. **Short word statistics**: It is the key for the high efficiency of a short word filter (Li, et al., 2002). Through statistical analysis of real alignments, we identified the distribution of common k-mer at different sequence lengths and identities, and applied the results to short word filter. **Banded alignment**: The short word filter not only filters out unnecessary alignment, when alignment is needed, it also identifies a narrow band for banded dynamic programming alignment, which is much faster than regular dynamic programming. **Reduced alphabet (to be implemented)**: This is for protein clustering. In reduced alphabet, a group of exchangeable residues are reduced to a single residue (I/V/L==>I, S/T==>S, D/E==>D, K/R==>K, F/Y==>F), and then conservative mutations would appear as identities in sequence alignments. It improves the short word filter for clustering at low sequence identity below 50%. **Gapped word (to be implemented)**: Short word filter using gapped word allows mismatch within a word such as “ACE” vs “AME”, “ACFE” vs “AMYE”, and “AACTT” vs “AAGTT”, which can be written as “101”, “1001” and “11011”. At low identity cutoff, a gapped word is more efficient than an ungapped word for filtering. ==== Algorithm limitations ==== A limitation of short word filter is that it can not be used below certain clustering thresholds. For proteins: * word size 5 is for thresholds 0.7 ~ 1.0 * word size 4 is for thresholds 0.6 ~ 0.7 * word size 3 is for thresholds 0.5 ~ 0.6 * word size 2 is for thresholds 0.4 ~ 0.5 (also see psi-cd-hit) For DNAs: * Word size 10-11 is for thresholds 0.95 ~ 1.0 * Word size 8,9 is for thresholds 0.90 ~ 0.95 * Word size 7 is for thresholds 0.88 ~ 0.9 * Word size 6 is for thresholds 0.85 ~ 0.88 * Word size 5 is for thresholds 0.80 ~ 0.85 * Word size 4 is for thresholds 0.75 ~ 0.8 Because of the algorithm, cd-hit may not be used for clustering proteins at <40% identity. Cd-hit-est cannot cluster very long sequences either (e.g. genome sized sequences). In such cases, please use PSI-CD-HIT, which will be introduced in following sections. ===== User's Guide ===== ==== Installation ==== It can be copied under the GNU General Public License version 2 (GPLv2). Most CD-HIT programs were written in C++. Installing CD-HIT package is very simple: * download current CD-HIT at [[https://github.com/weizhongli/cdhit/releases]], for example cd-hit-v4.6.6-2016-0711.tar.gz * unpack the file with " tar xvf cd-hit-v4.6.6-2016-0711.tar.gz --gunzip" * change dir by "cd cd-hit-v4.6.6-2016-0711" * compile the programs by "make" with multi-threading (default), or by "make openmp=no" without multi-threading (on old systems without OpenMP) * cd cd-hit-auxtools * compile cd-hit-auxtools by "make" ==== CD-HIT ==== CD-HIT clusters proteins into clusters that meet a user-defined similarity threshold, usually a sequence identity. Each cluster has one representative sequence. The input is a protein dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Basic command: cd-hit -i nr -o nr100 -c 1.00 -n 5 -M 16000 –d 0 -T 8 cd-hit -i db -o db90 -c 0.9 -n 5 -M 16000 –d 0 -T 8, where\\ ''db'' is the filename of input, \\ ''db90'' is output, \\ ''-c 1.0'', means 100% identity, is the clustering threshold\\ ''-c 0.9'', means 90% identity, is the clustering threshold\\ ''-n 5'' is the word size\\ ''-d 0'' use sequence name in fasta header till the first white space\\ ''-M 16000'', to use 16GB RAM\\ ''-T 8'', to use 8 threads\\ Choose of word size: ''-n 5'' for thresholds 0.7 ~ 1.0\\ ''-n 4'' for thresholds 0.6 ~ 0.7\\ ''-n 3'' for thresholds 0.5 ~ 0.6\\ ''-n 2'' for thresholds 0.4 ~ 0.5\\ Complete options: __**The most updated options are available from the command line version of the programs. Running the programs without any argument will print out the detailed options.**__ -i input filename in fasta format, required -o output filename, required -c sequence identity threshold, default 0.9 this is the default cd-hit's "global sequence identity" calculated as: number of identical amino acids in alignment divided by the full length of the shorter sequence -G use global sequence identity, default 1 if set to 0, then use local sequence identity, calculated as : number of identical amino acids in alignment divided by the length of the alignment NOTE!!! don't use -G 0 unless you use alignment coverage controls see options -aL, -AL, -aS, -AS -b band_width of alignment, default 20 -M memory limit (in MB) for the program, default 800; 0 for unlimitted; -T number of threads, default 1; with 0, all CPUs will be used -n word_length, default 5, see user's guide for choosing it -l length of throw_away_sequences, default 10 -t tolerance for redundance, default 2 -d length of description in .clstr file, default 20 if set to 0, it takes the fasta defline and stops at first space -s length difference cutoff, default 0.0 if set to 0.9, the shorter sequences need to be at least 90% length of the representative of the cluster -S length difference cutoff in amino acid, default 999999 if set to 60, the length difference between the shorter sequences and the representative of the cluster can not be bigger than 60 -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -A minimal alignment coverage control for the both sequences, default 0 alignment must cover >= this value for both sequences -uL maximum unmatched percentage for the longer sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -uS maximum unmatched percentage for the shorter sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -U maximum unmatched length, default 99999999 if set to 10, the unmatched region (excluding leading and tailing gaps) must not be more than 10 bases -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive !! No longer supported !! -p 1 or 0, default 0 if set to 1, print alignment overlap in .clstr file -g 1 or 0, default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -sc sort clusters by size (number of sequences), default 0, output clusters by decreasing length if set to 1, output clusters by decreasing size -sf sort fasta/fastq by cluster size (number of sequences), default 0, no sorting if set to 1, output sequences by decreasing cluster size -bak write backup cluster file (1 or 0, default 0) -h print this help Alignment coverage control: See the figure below, the -aL, -AL, -aS and -AS options can be used to specify the alignment coverage on both the representative sequence and other sequences. -s and -S can control the length difference between the representative sequence and other sequences. {{ :cd-hit-figure2.png }} '' aL = Ra / R\\ AL = R - Ra\\ aS = Sa / S\\ AS = S - Sa\\ s = Sa / Ra\\ S = R / S\\ U = S1 + S2\\ uL = U / R\\ uS = U / S '' Output: The output .clstr file looks like >Cluster 0 0 2799aa, >PF04998.6|RPOC2_CHLRE/275-3073... * >Cluster 1 0 2214aa, >PF06317.1|Q6Y625_9VIRU/1-2214... at 80% 1 2215aa, >PF06317.1|O09705_9VIRU/1-2215... at 84% 2 2217aa, >PF06317.1|Q6Y630_9VIRU/1-2217... * 3 2216aa, >PF06317.1|Q6GWS6_9VIRU/1-2216... at 84% 4 527aa, >PF06317.1|Q67E14_9VIRU/6-532... at 63% >Cluster 2 0 2202aa, >PF06317.1|Q6UY61_9VIRU/8-2209... at 60% 1 2208aa, >PF06317.1|Q6IVU4_JUNIN/1-2208... * 2 2207aa, >PF06317.1|Q6IVU0_MACHU/1-2207... at 73% 3 2208aa, >PF06317.1|RRPO_TACV/1-2208... at 69% where\\ a ">" starts a new cluster\\ a "*" at the end means that this sequence is the representative of this cluster\\ a "%" is the identity between this sequence and the representative ==== CD-HIT-2D ==== CD-HIT-2D compares 2 protein datasets (db1, db2). It identifies the sequences in db2 that are similar to db1 at a certain threshold. The input are two protein datasets (db1, db2) in fasta format and the output are two files: a fasta file of proteins in db2 that are not similar to db1 and a text file that lists similar sequences between db1 & db2. Basic command: cd-hit-2d -i db1 -i2 db2 -o db2novel -c 0.9 -n 5 -d 0 -M 16000 -T 8 where\\ ''db1'' & ''db2'' are inputs,\\ ''db2novel'' is output,\\ ''0.9'' means 90% identity, is the comparing threshold\\ ''5'' is the size of word Please note that by default, cd-hit only lists matches where sequences in db2 are not longer than sequences in db1. You may use options -S2 or -s2 to overwrite this default. You can also swap db1 and db2: cd-hit-2d -i db1 -i2 db2 -o db2novel -c 0.9 -n 5 -d 0 -M 16000 -T 8 -s2 0.9 cd-hit-2d -i db2 -i2 db1 -o db1novel -c 0.9 -n 5 -d 0 -M 16000 -T 8 (swap db1 and db2) Choose of word size (same as cd-hit): -n 5 for thresholds 0.7 ~ 1.0 -n 4 for thresholds 0.6 ~ 0.7 -n 3 for thresholds 0.5 ~ 0.6 -n 2 for thresholds 0.4 ~ 0.5 Options: -i input filename for db1 in fasta format, required -i2 input filename for db2 in fasta format, required -o output filename, required -c sequence identity threshold, default 0.9 this is the default cd-hit's "global sequence identity" calculated as: number of identical amino acids in alignment divided by the full length of the shorter sequence -G use global sequence identity, default 1 if set to 0, then use local sequence identity, calculated as : number of identical amino acids in alignment divided by the length of the alignment NOTE!!! don't use -G 0 unless you use alignment coverage controls see options -aL, -AL, -aS, -AS -b band_width of alignment, default 20 -M memory limit (in MB) for the program, default 800; 0 for unlimitted; -T number of threads, default 1; with 0, all CPUs will be used -n word_length, default 5, see user's guide for choosing it -l length of throw_away_sequences, default 10 -t tolerance for redundance, default 2 -d length of description in .clstr file, default 20 if set to 0, it takes the fasta defline and stops at first space -s length difference cutoff, default 0.0 if set to 0.9, the shorter sequences need to be at least 90% length of the representative of the cluster -S length difference cutoff in amino acid, default 999999 if set to 60, the length difference between the shorter sequences and the representative of the cluster can not be bigger than 60 -s2 length difference cutoff for db1, default 1.0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 0.9, seqs in db1 may just >= 90% seqs in db2 -S2 length difference cutoff, default 0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 60, seqs in db2 may 60aa longer than seqs in db1 -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -A minimal alignment coverage control for the both sequences, default 0 alignment must cover >= this value for both sequences -uL maximum unmatched percentage for the longer sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -uS maximum unmatched percentage for the shorter sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -U maximum unmatched length, default 99999999 if set to 10, the unmatched region (excluding leading and tailing gaps) must not be more than 10 bases -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive !! No longer supported !! -p 1 or 0, default 0 if set to 1, print alignment overlap in .clstr file -g 1 or 0, default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -bak write backup cluster file (1 or 0, default 0) -h print this help ==== CD-HIT-EST ==== CD-HIT-EST clusters a nucleotide dataset into clusters that meet a user-defined similarity threshold, usually a sequence identity. The input is a DNA/RNA dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Since eukaryotic genes usually have long introns, which cause long gaps, it is difficult to make full-length alignments for these genes. So, CD-HIT-EST is good for non-intron containing sequences like EST. Basic command: cd-hit-est -i est_human -o est_human95 -c 0.95 -n 10 -d 0 -M 16000 - T 8 cd-hit-est -i R1.fa -j R2.fa -o R1.95.fa -op R2.95.fa -P 1 -c 0.95 -n 10 -d 0 -M 16000 - T 8 Choose of word size: -n 10, 11 for thresholds 0.95 ~ 1.0 -n 8,9 for thresholds 0.90 ~ 0.95 -n 7 for thresholds 0.88 ~ 0.9 -n 6 for thresholds 0.85 ~ 0.88 -n 5 for thresholds 0.80 ~ 0.85 -n 4 for thresholds 0.75 ~ 0.8 Options: -i input filename in fasta format, required -j input filename in fasta/fastq format for R2 reads if input are paired end (PE) files -i R1.fq -j R2.fq -o output_R1 -op output_R2 or -i R1.fa -j R2.fa -o output_R1 -op output_R2 -o output filename, required -op output filename for R2 reads if input are paired end (PE) files -c sequence identity threshold, default 0.9 this is the default cd-hit's "global sequence identity" calculated as: number of identical amino acids in alignment divided by the full length of the shorter sequence -G use global sequence identity, default 1 if set to 0, then use local sequence identity, calculated as : number of identical amino acids in alignment divided by the length of the alignment NOTE!!! don't use -G 0 unless you use alignment coverage controls see options -aL, -AL, -aS, -AS -b band_width of alignment, default 20 -M memory limit (in MB) for the program, default 800; 0 for unlimitted; -T number of threads, default 1; with 0, all CPUs will be used -n word_length, default 10, see user's guide for choosing it -l length of throw_away_sequences, default 10 -d length of description in .clstr file, default 20 if set to 0, it takes the fasta defline and stops at first space -s length difference cutoff, default 0.0 if set to 0.9, the shorter sequences need to be at least 90% length of the representative of the cluster -S length difference cutoff in amino acid, default 999999 if set to 60, the length difference between the shorter sequences and the representative of the cluster can not be bigger than 60 -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -A minimal alignment coverage control for the both sequences, default 0 alignment must cover >= this value for both sequences -uL maximum unmatched percentage for the longer sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -uS maximum unmatched percentage for the shorter sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -U maximum unmatched length, default 99999999 if set to 10, the unmatched region (excluding leading and tailing gaps) must not be more than 10 bases -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive !! No longer supported !! -P input paired end (PE) reads, default 0, single file if set to 1, please use -i R1 -j R2 to input both PE files -cx length to keep after trimming the tail of sequence, default 0, not trimming if set to 50, the program only uses the first 50 letters of input sequence -cy length to keep after trimming the tail of R2 sequence, default 0, not trimming if set to 50, the program only uses the first 50 letters of input R2 sequence e.g. -cx 100 -cy 80 for paired end reads -ap alignment position constrains, default 0, no constrain if set to 1, the program will force sequences to align at beginings when set to 1, the program only does +/+ alignment -p 1 or 0, default 0 if set to 1, print alignment overlap in .clstr file -g 1 or 0, default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -r 1 or 0, default 1, by default do both +/+ & +/- alignments if set to 0, only +/+ strand alignment -mask masking letters (e.g. -mask NX, to mask out both 'N' and 'X') -match matching score, default 2 (1 for T-U and N-N) -mismatch mismatching score, default -2 -gap gap opening score, default -6 -gap-ext gap extension score, default -1 -bak write backup cluster file (1 or 0, default 0) -sc sort clusters by size (number of sequences), default 0, output clusters by decreasing length if set to 1, output clusters by decreasing size -sf sort fasta/fastq by cluster size (number of sequences), default 0, no sorting if set to 1, output sequences by decreasing cluster size -h print this help ==== CD-HIT-EST-2D ==== CD-HIT-EST-2D compares 2 nucleotide datasets (db1, db2). It identifies the sequences in db2 that are similar to db1 at a certain threshold. The input are two DNA/RNA datasets (db1, db2) in fasta format and the output are two files: a fasta file of sequences in db2 that are not similar to db1 and a text file that lists similar sequences between db1 & db2. For same reason as CD-HIT-EST, CD-HIT-EST-2D is good for non-intron containing sequences like EST. Basic command: cd-hit-est-2d -i mrna_human -i2 est_human -o est_human_novel -c 0.95 -n 10 -d 0 -M 16000 - T 8 cd-hit-est-2d -i db1.R1.fa -j db1.R2.fa -i2 db2.R1.fa -j2 db2.R2.fa -o db2_novel.R1.fa -op db2_novel.R2.fa -P 1 -c 0.95 -n 10 -d 0 -M 16000 - T 8 Choose of word size and options are the same as CD-HIT-EST: Options: -i input filename for db1 in fasta format, required -i2 input filename for db2 in fasta format, required -j, -j2 input filename in fasta/fastq format for R2 reads if input are paired end (PE) files -i db1-R1.fq -j db1-R2.fq -i2 db2-R1.fq -j2 db2-R2.fq -o output_R1 -op output_R2 or -i db1-R1.fa -j db1-R2.fa -i2 db2-R1.fq -j2 db2-R2.fq -o output_R1 -op output_R2 -o output filename, required -op output filename for R2 reads if input are paired end (PE) files -c sequence identity threshold, default 0.9 this is the default cd-hit's "global sequence identity" calculated as: number of identical amino acids in alignment divided by the full length of the shorter sequence -G use global sequence identity, default 1 if set to 0, then use local sequence identity, calculated as : number of identical amino acids in alignment divided by the length of the alignment NOTE!!! don't use -G 0 unless you use alignment coverage controls see options -aL, -AL, -aS, -AS -b band_width of alignment, default 20 -M memory limit (in MB) for the program, default 800; 0 for unlimitted; -T number of threads, default 1; with 0, all CPUs will be used -n word_length, default 10, see user's guide for choosing it -l length of throw_away_sequences, default 10 -d length of description in .clstr file, default 20 if set to 0, it takes the fasta defline and stops at first space -s length difference cutoff, default 0.0 if set to 0.9, the shorter sequences need to be at least 90% length of the representative of the cluster -S length difference cutoff in amino acid, default 999999 if set to 60, the length difference between the shorter sequences and the representative of the cluster can not be bigger than 60 -s2 length difference cutoff for db1, default 1.0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 0.9, seqs in db1 may just >= 90% seqs in db2 -S2 length difference cutoff, default 0 by default, seqs in db1 >= seqs in db2 in a same cluster if set to 60, seqs in db2 may 60aa longer than seqs in db1 -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -A minimal alignment coverage control for the both sequences, default 0 alignment must cover >= this value for both sequences -uL maximum unmatched percentage for the longer sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -uS maximum unmatched percentage for the shorter sequence, default 1.0 if set to 0.1, the unmatched region (excluding leading and tailing gaps) must not be more than 10% of the sequence -U maximum unmatched length, default 99999999 if set to 10, the unmatched region (excluding leading and tailing gaps) must not be more than 10 bases -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive !! No longer supported !! -P input paired end (PE) reads, default 0, single file if set to 1, please use -i R1 -j R2 to input both PE files -cx length to keep after trimming the tail of sequence, default 0, not trimming if set to 50, the program only uses the first 50 letters of input sequence -cy length to keep after trimming the tail of R2 sequence, default 0, not trimming if set to 50, the program only uses the first 50 letters of input R2 sequence e.g. -cx 100 -cy 80 for paired end reads -p 1 or 0, default 0 if set to 1, print alignment overlap in .clstr file -g 1 or 0, default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -r 1 or 0, default 1, by default do both +/+ & +/- alignments if set to 0, only +/+ strand alignment -mask masking letters (e.g. -mask NX, to mask out both 'N' and 'X') -match matching score, default 2 (1 for T-U and N-N) -mismatch mismatching score, default -2 -gap gap opening score, default -6 -gap-ext gap extension score, default -1 -bak write backup cluster file (1 or 0, default 0) -h print this help ==== CD-HIT-454 clustering ==== We implemented a program called cd-hit-454 to identify duplicated 454 reads by reengineering cd-hit-est. Duplicates are either exactly identical or meet these criteria includes: (1) they start at the same position; (2) their lengths can be different, but shorter one must be fully aligned with the longer one (the seed); (3) they can only have 4% mismatches (insertion, deletion, and substitution); and (4) only 1 base is allowed per insertion or deletion. Here, (3) and (4) can be adjusted by users. We allow mismatches in order to tolerate sequencing errors. To find duplicates in Illumina reads, please use cd-hit-dup (see later sections) Basic command: cd-hit-454 -i 454_reads -o 454_reads_95 -c 0.95 -n 10 -d 0 -M 16000 - T 8 Options: -i input filename in fasta format, required -o output filename, required -c sequence identity threshold, default 0.98 this is a "global sequence identity" calculated as : number of identical amino acids in alignment divided by the full length of the shorter sequence + gaps -b band_width of alignment, default 10 -M memory limit (in MB) for the program, default 800; 0 for unlimitted; -T number of threads, default 1; with 0, all CPUs will be used -n word_length, default 10, see user's guide for choosing it -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AL alignment coverage control for the longer sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -AS alignment coverage control for the shorter sequence, default 99999999 if set to 60, and the length of the sequence is 400, then the alignment must be >= 340 (400-60) residues -B 1 or 0, default 0, by default, sequences are stored in RAM if set to 1, sequence are stored on hard drive it is recommended to use -B 1 for huge databases -g 1 or 0, default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -D max size per indel, default 1 -match matching score, default 2 -mismatch mismatching score, default -1 -gap gap opening score, default -3 -gap-ext gap extension score, default -1 -bak write backup cluster file (1 or 0, default 0) ==== Multi-threaded programs ==== Multi-threaded cd-hit programs were implemented with OpenMP. Option "-T n" will enable cd-hit to run in parallel in a single multi-core computer. The default value of n is 1 (single thread). "-T 0" will use all the cores in that computer. We have run cd-hit on 4-core, 8-core to 16-core computers and have observed a great speedup. ==== CD-HIT-PARA ==== __** [CD-HIT-PARA is no longer supported, since the multi-threaded cd-hit become available.] **__ CD-HIT-PARA is a script that runs cd-hit, cd-hit-est in a parallel mode. It splits the input database; runs cd-hit or cd-hit-est in parallel on a computer cluster; and finally merges the outputs into a single file. You can run it as you run cd-hit or cd-hit-est. The input is a protein or DNA/RNA dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. There are two ways to run jobs on a cluster: by ssh to a remote computer and by queuing system (PBS and SGE are implemented). In any case, you should have a shared file system, the path to your working directory must be same on all the remote computers. This script can also be used if you are clustering a very large database and your computer doesn't have enough RAM. In that case, all the divided jobs will still run on a single computer. Implementation (see figure below) - divide input db into many small dbs in decreasing length - clusters the 1st db by cd-hit - run cd-hit-2d for other dbs against 1st db - repeat cd-hit and cd-hit-2d runs till done - Combine the results {{ :cd-hit-figure3.png }} Basic command: cd-hit-para.pl -i nr90 -o nr60 -c 0.6 -n 4 --B hosts --S 64 where\\ ''--B'' hosts is a file with available hostnames\\ ''--S'' 64 is the number to split input db into, this number should be several times the number of hosts More options: --P program, "cd-hit" or "cd-hit-est", default "cd-hit" --B filename of list of hosts, requred unless -Q or -L option is supplied --L number of cpus on local computer, default 0 when you are not running it over a cluster, you can use this option to divide a big clustering jobs into small pieces, I suggest you just use "--L 1" unless you have enough RAM for each cpu --S Number of segments to split input DB into, default 64 --Q number of jobs to submit to queue queuing system, default 0 by default, the program use ssh mode to submit remote jobs --T type of queuing system, "PBS", "SGE" are supported, default PBS --R restart file, used after a crash of run ==== CD-HIT-2D-PARA ==== __** [CD-HIT-2D-PARA is no longer supported, since the multi-threaded cd-hit become available.] **__ CD-HIT-2D-PARA is a script that runs cd-hit-2d, cd-hit-est-2d in a parallel mode. It splits the input databases; runs cd-hit-2d or cd-hit-est-2d in parallel on a computer cluster; and finally merges the outputs into a single file. You can run it as you run cd-hit-2d or cd-hit-est-2d. The input is a protein or DNA/RAN dataset in fasta format and the output are two files: a fasta file of representative sequences and a text file of list of clusters. Basic command: cd-hit-para.pl -i nr -i2 swissprot -o swissprot_vs_nr -c 0.6 -n 4 --Q 20 -T "SGE" --S 2 --S2 20 where --P program, "cd-hit-2d" or "cd-hit-est-2d", default "cd-hit-2d" --B filename of list of hosts, requred unless -Q or -L option is supplied --L number of cpus on local computer, default 0 when you are not running it over a cluster, you can use this option to divide a big clustering jobs into small pieces, I suggest you just use "--L 1" unless you have enough RAM for each cpu --S Number of segments to split 1st db into, default 2 --S2 Number of segments to split 2nd db into, default 8 --Q number of jobs to submit to queue queuing system, default 0 by default, the program use ssh mode to submit remote jobs --T type of queuing system, "PBS", "SGE" are supported, default PBS --R restart file, used after a crash of run -h print this help ==== Incremental clustering ==== It is easy to make incremental update with cd-hit /cd-hit-2d. For example: nr is the nr database of last month month is the new sequences of nr of this month In last month, you ran: cd-hit -i nr -o nr90 -c 0.9 -n 5 -d 0 -M 16000 -T 16 This month, you can run incremental clustering cd-hit-2d -i nr90 -i2 month -o month-new -c 0.9 -n 5 -d 0 -M 16000 -T 16 cd-hit -i month-new -o month90 -c 0.9 -n 5 -d 0 -M 16000 -T 16 cat month90 >> nr90 clstr_merge.pl nr90.clstr month-new.clstr > temp.clstr cat temp.clstr month90.clstr > this_month_nr90.clstr This approach is much faster than running from scratch. It also preserves stable cluster structure. ==== Hierarchically clustering ==== With multiple-step, iterated runs of CD-HIT, you perform a clustering in a neighbor-joining method, which generates a hierarchical structure. The third step use psi-cd-hit, please see psi-cd-hit section for details. This way is faster than one-step clustering. It can also be more accurate. There is a problem with one-step clustering. Two very similar sequences A and B may be clustered into different clusters. For example, let the clustering threshold to be 60%, IAB (identity of AB) = 95%, IAC ≥ 60%, but IBC < 60%. If C was first selected a cluster representative, then A will be in cluster “C”, but “B” will not, resulting near identical AB to be in different clusters. Hierarchically clustering will reduce this problem. {{ :cd-hit-figure4.png }} Commands: cd-hit -i nr -o nr80 -c 0.8 -n 5 -d 0 -M 16000 -T 16 this generate nr80 and nr80.clstr cd-hit -i nr80 -o nr60 -c 0.6 -n 4 -d 0 -M 16000 -T 16 this use nr80 to generate nr60 and nr60.clstr psi-cd-hit.pl -i nr60 -o nr30 -c 0.3 this use nr60 to generate nr30 and nr30.clstr clstr_rev.pl nr80.clstr nr60.clstr > nr80-60.clstr nr60.clstr only lists sequences from nr80, script clstr_rev.pl add the original sequences from nr but not in nr80 into the output file nr80-60.clstr clstr_rev.pl nr80-60.clstr nr30.clstr > nr80-60-30.clstr nr30.clstr only lists sequences from nr60, script clstr_rev.pl add the original sequences into file nr80-60-30.clstr ===== CD-HIT AuxTools ===== CD-HIT AuxTools is a set of auxiliary programs that can be used to assist the analysis of the next generation sequencing data. It currently includes programs for removing read duplicates, finding pairs of overlapping reads or joining pair-end reads etc. ==== cd-hit-dup ==== cd-hit-dup is a simple tool for removing duplicates from sequencing reads, with optional step to detect and remove chimeric reads. When two files of paired end reads are used as inputs, each pair of reads will be concatenated into a single one. A number of options are provided to tune how the duplicates are removed. Running the program without arguments should print out the list of available options, as the following: Usage: cd-hit-dup -i input.fa -o output.fa [other options] (for single reads FASTQ) cd-hit-dup -i input.fq -o output.fq [other options] (for single reads FASTA) cd-hit-dup -i R1.fq -i2 R2.fq -o output-R1.fq -o2 output-R2.fq [other options] (for PE reads FASTQ) cd-hit-dup -i R1.fa -i2 R2.fa -o output-R1.fa -o2 output-R2.fa [other options] (for PE reads FASTA) Options: -i Input file (FASTQ or FASTA); -i2 Second input file (FASTQ or FASTA); -o Output file; -o2 Output file for R2; -d Description length (default 0, truncate at the first whitespace character) -u Length of prefix to be used in the analysis (default 0, for full/maximum length); -m Match length (true/false, default true); -e Maximum number/percent of mismatches allowed; -f Filter out chimeric clusters (true/false, default false); -s Minimum length of common sequence shared between a chimeric read and each of its parents (default 30, minimum 20); -a Abundance cutoff (default 1 without chimeric filtering, 2 with chimeric filtering); -b Abundance ratio between a parent read and a chimeric read (default 1); -p Dissimilarity control for chimeric filtering (default 1); === Option details === -u Length of prefix to be used in the analysis (default 0, for full/maximum length); For pair-end inputs, the program will take part (whole or prefix) of the first end and part (whole or prefix) of the second read, and join them together to form a single read to do the analysis. A positive value of this option specifies the length of the prefix to be taken from each read. If a read is shorter than this length, letter 'N's will be appended to the read to make up for the length. When this option is not used or is used with a non-positive value, the program will use the length of the longest read as the value of this option. For single input analysis, only a positive value of this option will be effective. It also allows the program to use only the prefix up to the specified length of each read to do the analysis. In case that a read is shorter than this length, no 'N' is appended to the read since it is not necessary. -m Match length (true/false, default true); "-m" specifies whether the lengths of two reads should be exactly the same to be considered as duplicates. -e Maximum number/percent of mismatches allowed; Maximum number/percent of mismatches can be specified to control the similarity between two reads for duplicate and chimeric detection. For duplicate detection, any two reads with number of mismatches no greater than the specified value are considered to be duplicates. For chimeric detection, this option control how similar a read should be to either of its parents. -f Filter out chimeric clusters (true/false, default false); This option specifies whether or not to carry out an additional step to filter out chimeric clusters. -s Minimum length of common sequence shared between a chimeric read and each of its parents (default 30, minimum 20); A read or cluster representative is considered as a potential chimeric only if it shares at least the number of bases specified by this option with either of its parents. This option is effective only if the option is set to true for filtering chimeric clusters. -a Abundance cutoff (default 1 without chimeric filtering, 2 with chimeric filtering); Each read is associated with an abundance number, which is the number of duplicates for the read. cd-hit-dup always assumes the input contains duplicates and perform the duplicate detection step. If no duplicate is found, the input is assumed to have duplicates remove in advance, and then, the program will try to obtain the abundance information from the descriptions of the reads, it interprets the number following "_abundance_" as the abundance number. The abundance cutoff is mainly used for chimeric filtering to skip chimeric checking on reads with abundance below this cutoff. -b Abundance ratio between a parent read and a chimeric read (default 1); This option specifies the abundance ratio between a parent read and a chimeric read. So for a read to be chimeric, either of its parents must have abundance at least as high as the ratio times the abundance of the chimeric read. -p Dissimilarity control for chimeric filtering (default 1); Internally dissimilarity is measured by percent of mismatches with ungapped alignments. By default the percentage cutoff is set to 0.01 (one percent). This option specifies a multiplier to this percentage cutoff. A higher value will increase the dissimilarity thresholds in chimeric filtering. === Output files === cd-hit-dup will output three or four files. Two of them are the same as the output files of CD-HIT: one (named exactly the same as the file name specified by the "-o" option) is the cluster (or duplicate) representatives, the other is the clustering file (xxx.clstr) relating each duplicate to its representative. For paired end reads, another file by the "-o2" option is the cluster representatives for R2 reads. The last file (xxx2.clstr) contains the chimeric clusters. In this file, the description for each chimeric cluster contains cluster ids of its parent clusters from the clustering file xxx.clstr. === Examples === == Duplicate Detection == Remove duplicates using default parameters: cd-hit-dup -i input.fa -o output By default, only reads that are identical are considered as duplicates. If "-m" is set to false, duplicates will be allowed to have different length, but the longer ones must have a prefix that is identical to the shorter ones. cd-hit-dup -i input.fa -o output -u 50 This only compare the first 50 bases of all sequences, considering that in Illumina reads, sequence quality are better at the beginning of the reads. Remove duplicates with a few mismatches: cd-hit-dup -i input.fa -o output -e 2 cd-hit-dup -i input.fa -o output -e 0.01 The former will allow each duplicate read to have up to 2 mismatches when aligned to its representative; and the later will allow up to one percent mismatches. Remove duplicates from paired end reads: cd-hit-dup -i pair-end1.fa -i2 pair-end2.fa -o output -o2 output-R2 Each read from "pair-end1.fa" and "pair-end2.fa" will be joint to form a single read to detect duplicates. If they all are of the same length, the full length of each ends will be used in forming the single read; otherwise, the default value of option "-u" will be used to determine how the single read is created. cd-hit-dup -i pair-end1.fa -i2 pair-end2.fa -o output -o2 output-R2 -u 50 This only consider the first 50 bases from both R1 and R2 reads. Remove duplicates from paired end reads with control on how the paired end are jointed: cd-hit-dup -i pair-end1.fa -i2 pair-end2.fa -o output -o2 output-R2 -u 100 With explicit "-u" options, any reads shorter than 100 will be padded with 'N's, and the longer ones will be cut down to 100 base long. Then each pair of the 100 base long reads will be jointed to form a single 200 base long read. == Chimeric Filtering == cd-hit-dup offers a very efficient way to detect chimeric reads. The basic idea is to find two parent reads whose cross-over is sufficient similar to the chimeric read, while each single parent is sufficiently dissimilar to it. Such dissimilarity is measured by the percent of mismatches for no-gapped alignments. For a given percentage "p" (from option "-p"), a chimeric read must share at least "p" percent mismatches with any other single read, namely, it much be sufficiently dissimilar to any single read. For more robust detection of chimeric reads, a background percentage "p_bg" is calculated as the mismatch percentage shared between the candidate chimeric read and the single read that is most similar to the candidate. If "p_bg" is greater than "1.5*p", "1.5*p" will be used as "p_bg" instead. For a read to be classified as chimeric read, there must exist two reads/parents such that, the leading part of the read is sufficiently similar to one parent, and the rest is sufficiently similar to the other parent, with at most "p+p_bg" percent of mismatches in each part. And the crossover between the two parents must share at most "p_bg" mismatches with the chimeric read. Chimeric filtering with default parameters: cd-hit-dup -i input.fa -o output -f true Chimeric filtering with specified similarity level: cd-hit-dup -i input.fa -o output -f true -p 1.5 Chimeric filtering with specified abundance difference: cd-hit-dup -i input.fa -o output -f true -a 2 which means each parent of a chimeric read must be a least as twice abundant as the chimeric read. Chimeric filtering will produce a cluster file named like "xxx2.clstr", in which each cluster entry is a chimeric read/cluster. For example, ...... >Cluster 4 chimeric_parent1=2,chimeric_parent2=8 0 256nt, >FV9NWLF01CRIR3_abundance_23... * >Cluster 5 chimeric_parent1=2,chimeric_parent2=0 0 250nt, >FV9NWLF01B4TBX_abundance_21... * ...... here "Cluster 5" contains a chimeric read "FV9NWLF01B4TBX", whose parents are identified by cluster numbers "2" and "0" from the associated "xxx.clstr" file, >Cluster 0 0 252nt, >FV9NWLF01ANLX2_abundance_2239... * >Cluster 1 0 246nt, >FV9NWLF01C3KOB_abundance_1465... * >Cluster 2 0 260nt, >FV9NWLF01AQOWA_abundance_1284... * ...... So the parent reads of the chimeric read "FV9NWLF01B4TBX" are "FV9NWLF01AQOWA" and "FV9NWLF01ANLX2". ==== cd-hit-lap ==== cd-hit-lap is program for extracting pairs of overlapping reads by clustering based on tail-head overlaps (with perfect matching). The basic clustering strategy is the same as that in standard CD-HIT programs. In this program, each read is clustered as either a "representative" or a "redundant" read. For each "redundant" read, it must have a prefix that is identical a suffix of its representative read. The options of this program can be obtained by running it it without any arguments: [compute-0-0 cdhit-dup]$ ./cd-hit-lap Options: -i Input file; -o Output file; -m Minimum length of overlapping part (default 20); -p Minimum percentage of overlapping part (default 0, any percentage); -d Description length (default 0, truncate at the first whitespace character) -s Random number seed for shuffling (default 0, no shuffling; shuffled before sorting by length); -stdout Standard output type (default "log", other options "rep", "clstr"); The two options "-m" and "-p" can be used to control the minimum overlap that is required to classify them as overlapping reads. Each pair of overlapping reads must have overlap length no less than the threshold specified by "-m", and must also not be less than the length threshold computed from the "-p" option. Since the overlapping reads are searched using a greedy strategy, so different sortings of reads may lead to different result. So it is advisable to run the program multiple times with read shuffling by different random number seeds, and then collect and merge the results. Sometimes it may be more convenient to pipe the results of this program as stdout directly to the stdin of other programs, to do this, the option "-stdout" can be used to choose which type ("log" for program console information, "rep" for representative reads in FASTA or FASTQ format, "clstr" for the clustering output in CD-HIT format) of results to be writen to the stdout. The output format of this program is the same as the standard CD-HIT. In the .clstr file, the alignment positions indicate how the reads are overlapped. For example, >Cluster 0 0 75nt, >1_lane2_624... * 1 75nt, >1_lane2_7169... at 1:65:11:75/+/100.00% 2 75nt, >1_lane2_36713... at 69:1:1:69/-/100.00% 3 75nt, >1_lane2_141482... at 1:56:20:75/+/100.00% The cluster member #0 in cluster #0 is the representative of the cluster, and it overlaps with each of the other members in the cluster. For cluster member #1, "1:65:11:75/+" tells that the first 65 bases of member #1 overlaps with the last 65 bases of member #0; "69:1:1:69/-" indicates that the last 69 bases of member #2 overlaps with the first 69 bases of member #0. ==== read-linker ==== read-linker is a very simple program to concatenate pair-end reads into single ones. It support the following options: [compute-0-0 cdhit-dup]$ ./read-linker Options: -1 file Input file, first end; -2 file Input file, second end; -o file Output file; -l number Minimum overlapping length (default 10); -e number Maximum number of errors (mismatches, default 1); Only the pairs of reads that share at least a minimum overlapping length with mismatched no more than the maximum number of errors, are jointed to form a single read. ===== PSI-CD-HIT clustering ===== The lowest threshold of CD-HIT is around 40%, in many applications, we need a much lower threshold, like 25%. Also CD-HIT-EST can not handle very long sequences (e.g. genomes, scaffolds). PSI-CD-HIT clusters proteins at very low threshold, it also cluster long DNA sequences, through blastp, blastn and metablast. PSI-cd-hit is a Perl script, which runs similar incremental algorithm like CD-HIT, but using BLAST to calculate similarities. Below are the procedures of PSI-CD-HIT: - Sort sequences by decreasing length - First one is the first representative - Using 1st one blast all remaining sequences, pick up its neighbors that meet the clustering threshold - Repeat until done ==== Installation ==== please download either legacy BLAST or BLAST+ and install the executables in your $PATH. The programs required by psi-cd-hit.pl are blastall, megablast, blastpgp and formatdb for legacy blast, and blastp, blastn, psiblast and makeblastdb for blast+. ==== Usage ==== Basic command: psi-cd-hit.pl -i nr60 -o nr30 -c 0.3 More options: input/output: -i in_dbname, required -o out_dbname, required -l length_of_throw_away_sequences, default 10 thresholds: -c clustering threshold (sequence identity), default 0.3 -ce clustering threshold (blast expect), default -1, it means by default it doesn't use expect threshold, but with positive value, the program cluster seqs if similarities meet either identity threshold or expect threshold -G (1/0) use global identity? default 1 two sequences Long (i.e. representative) and Short (redunant) may have multiple alignment fragments (i.e. HSPs), see: seq1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Long sequence |||||||||||||||||| ///////////// i.e. representative |||||||||||||||||| ///////////// sequence ||||||||HSP 1 |||| ////HSP 2 /// |||||||||||||||||| ///////////// |||||||||||||||||| ///////////// seq2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Short sequence << length 1 >> << len 2 >> i.e. redundant <<<<<<<<<<<< length of short sequence >>>>>>>>>>>>>> sequence total identical letters from all co-linear and non-overlapping HSPs Glogal identity = ------------------------------------------------------------------- length of short sequence Local identity = identity of the top high score HSP if you prefer to use -G 0, it is suggested that you also use -aS, -aL, such as -aS 0.8, to prevent very short matches. -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -g (1/0), default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -circle (1/0), default 0 when set to 1, treat sequences as circular sequence. bacterial genomes, plasmids are circular, but their genome coordinate maybe arbitary, the 2 HSPs below will be treated as non co-linear with -circle 0 the 2 HSPs below will be treated as co-linear with -circle 1 -------------circle----------- | | seq1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 1 \\\\\\\\ ///////////// \\\\\\\\ ///////////// HSP 2 -> ////HSP 1 /// <-HSP 2 ///////////// \\\\\\\\ ///////////// \\\\\\\\ seq2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 2 | | -----------circle-------------- program: -prog (blastp, blastn, megablast, blastpgp), default blastp -p profile search para, default "-j 3 -F F -e 0.001 -b 500 -v 500" -dprof database for building PSSM, default using input you can also use another database that is more comprehensive like NR80 -s blast search para, default "-F F -e 0.000001 -b 100000 -v 100000" -bs (1/0) default 1 pipe blast results from into parser instead of save in hard drive (save time) compute: -exec (qsub, local) default local this program writes a shell script to run blast, this script is either performed locally by sh or remotely by qsub with qsub, you can use PBS, SGE etc -host number of hosts for qsub -core number of cpu cores per computer, default 1 -shf a filename for add local settings into the job shell script for example, when you run PBS jobs, you can add quene name etc in this file and this script will add them into the job shell script e.g. your file may have followings #PBS -v PATH #PBS -l walltime=8:00:00 #PBS -q jobqueue job: -rs steps of save restart file and clustering output, default 5000 everytime after process 5000 sequences, program write a restart file and current clustering information -restart restart file, readin a restart file if program crash, stoped, termitated, you can restart it by add a option "-restart sth.restart" -rf steps of re format blast database, default 200,000 if program clustered 200,000 seqs, it remove them from seq pool, and re format blast db to save time -J job, job_file, exe specific jobs like parse blast outonly DON'T use it, it is only used by this program itself -k (1/0) keep blast raw output file, default 0 -P path to executables ==== Examples ==== == Protein clustering == First, we use cd-hit to cluster the input down to 60% identity cd-hit -i db -o db_90 -c 0.9 -n 5 -g 1 -G 0 -aS 0.8 -d 0 -p 1 -T 16 -M 0 > db_90.log cd-hit -i db_90 -o db_60 -c 0.6 -n 4 -g 1 -G 0 -aS 0.8 -d 0 -p 1 -T 16 -M 0 > db_60.log Cluster on a single computer ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec local -core 16 clstr_rev.pl db_90.clstr db_60.clstr > db90-60.clstr clstr_rev.pl db90-60.clstr db_30.clstr > db90-60-30.clstr Here, -ce 1e-6 and -c 0.3 means cutoff at either 30% identity or 1e-6 e.value -G 0 means global identity -aS 0.8 means that alignment must cover 80% of shorter (redundant) sequence -g 1, slow but accurate mode, allowing sequences to be grouped to its most similar cluster -core 16, use 16 threads for blast search -clstr_rev.pl will combined all the cd-hit runs, see Hierarchically clustering Cluster on a computer cluster (with qsub) ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec qsub -host 8 -core 8 -shf qsub_sh_template clstr_rev.pl db_90.clstr db_60.clstr > db90-60.clstr clstr_rev.pl db90-60.clstr db_30.clstr > db90-60-30.clstr Restart: ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec local -core 16 -restart db_30.restart ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec qsub -host 8 -core 8 -shf qsub_sh_template -restart db_30.restart In case of program crash, it restart from where it stops without re-running blast searches. == Clustering very long DNA sequences == ./psi-cd-hit.pl -i db.fna -o db90.fna -c 0.9 -G 1 -g 1 -prog megablast -s "-F F -e 0.000001 -b 100000 -v 100000" -exec local -core 32 ./psi-cd-hit.pl -i db.fna -o db90.fna -c 0.9 -G 1 -g 1 -prog blastn -circle 1 -exec local -core 32 Here, First example uses megablast Second example uses blastn -circle 1 means consider circular genome (see psi-cd-hit options above) ===== CD-HIT tools ===== ==== cd-hit-div, cd-hit-div.pl ==== Both the executable binary program cd-hit-div and the perl script divide a FASTA file into pieces. The difference is that cd-hit-div sorts the sequences before dividing them while the perl script does not. Commands: cd-hit-div -i input -o output -div n cd-hit-div.pl input output n where "n" is the number of output files. The output files will be named as output-0, output-1 etc. ==== plot_len.pl ==== This is a script to print out distributions of clusters & sequences. Commands: plot_len.pl input.clstr \ 1,2-4,5-9,10-19,20-49,50-99,100-299,500-99999 \ 10-59,60-149,150-499,500-1999,2000-999999 where 2nd line are sizes of cluster 3rd line are lengths of sequences It will print distribution of clusters and sequences : Size # seq #clstr 10-59 60-149 150-499 500-1999 2000-up 1 266312 266312 36066 103737 103285 22727 497 2-4 208667 81131 1229 14680 44607 20006 609 5-9 156558 24198 118 2148 12026 9388 518 10-19 155387 11681 30 596 5024 5462 569 20-49 176815 6007 6 139 2212 3135 515 50-99 106955 1568 0 24 410 955 179 100-499 154209 896 0 3 124 597 172 500-up 43193 40 0 0 1 14 25 Total 1268096 391833 37449 121327 167689 62284 3084 ==== clstr_sort_by.pl ==== This script sort clusters in .clstr file by length, size Commands: Clstr_sort_by.pl < input.clstr no > input_sort.clstr Where, "no" means by size of the cluster ==== clstr_sort_prot_by.pl ==== This script sort sequences within clusters in .clstr file by length, name, etc. Commands: Clstr_sort_prot_by.pl input.clstr id > input_sort.clstr Where, "no" means by id of sequences ==== clstr_merge.pl ==== It merges two or more .clstr files. The cluster orders need to be identical. Commands: cd-hit-2d -i db1 -i2 db2 -o db2new -c 0.9 -n 5 cd-hit-2d -i db1 -i2 db3 -o db3new -c 0.9 -n 5 clstr_merge.pl db2new.clstr db3new.clstr > db23new.clstr ==== clstr_merge_noorder.pl ==== It merges two or more .clstr files. The cluster orders do not have to be identical. Commands: cd-hit-2d -i db1 -i2 db2 -o db2new -c 0.9 -n 5 cd-hit-2d -i db1 -i2 db3 -o db3new -c 0.9 -n 5 clstr_merge_noorder.pl db2new.clstr db3new.clstr > db23new.clstr ==== clstr_ renumber.pl ==== It renumbers clusters and sequences within clusters in .clstr file after merge or other operations Commands: Clstr_renumber.pl input.clstr > input_ren.clstr ==== clstr_rev.pl ==== It combines a .clstr file with its parent .clstr file Commands: cd-hit -i nr -o nr90 -c 0.9 -n 5 cd-hit -i nr90 -o nr60 -c 0.6 -n 4 clstr_rev.pl nr90.clstr nr60.clstr > nr60_from90.clstr psi-cd-hit -i nr60 -o nr30 -c 0.3 clstr_rev.pl nr60_from90.clstr nr30.clstr > nr30_from90.clstr ==== make_multi_seq.pl ==== This script reads the .clstr file, it generates a separate fasta file for each cluster over certain size and saves it in designated subdirectory. To run this script correctly, "-d 0" option should be used in the cd-hit run and it is better to use "-g 1" in the cd-hit run to get accurate clustering results. For example, Commands: cd-hit -i db -o dbout -c 0.6 -n 4 -d 0 -g 1 make_multi_seq.pl seq_db dbout.clstr multi-seq 20 will generate fasta files in "multi-seq" directory for clusters with more than 20 member sequences. Files will be named as "clusterN" where "N" is serial number of a cluster. ==== clstr2xml.pl ==== This script converts a cluster file or combines multiple cluster files from a hierarchical cd-hit run to xml format. The output is sorted by sequence length (default) or cluster size. The input cluster files must be in the order of being generated, that is, the cluster file with higher identity cutoff comes first. Command: clstr2xml.pl [-len|-size] input1.clstr [input2.clstr input3.clstr ...] ===== CD-HIT Web Server ===== The CD-HIT web server is available from [[http://cd-hit.org]]. All basic functions of CD-HIT are provided through tab-based interfaces in our web server. For CD-HIT and CD-HIT-EST, users can upload a FASTA file, select a desired sequence identity level and other parameters. CD-HIT-2D (CD-HIT-EST-2D) can compare two databases uploaded by users. H-CD-HIT and H-CD-HIT-EST in our server performs hierarchical clustering up to 3 steps. The CD-HIT-454 web server is also available from [[http://cd-hit.org]]. ===== Use cases ===== Here, a use case is defined as a sequence clustering related problem or application that cannot be easily solved with existing clustering approaches, such as CD-HIT. However, it is feasible to solve such a use case by customizing current clustering algorithms or utilizing current approach in a very intelligent way or non-standard manner. In the last years, we have developed many use cases in addressing various problems. We will release these use cases after additional testing. These use cases will be described in the following chapters. ===== CD-HIT-OTU-MiSeq ===== This use case is developed for clustering 16S rRNA genes into OTUs for microbiome studies. In recent years, Illumina MiSeq sequencers became dominant in 16S rRNA sequencing. The Paired End (PE) reads need to be assembled first. However many reads can not be accurately assembled because the poor quality at the 3’ ends of both PE reads in the overlapping region. This causes that many sequences are discarded in the analysis. CD-HIT-OTU-MiSeq has unique features to cluster MiSeq 16S sequences. - The package can clustering PE reads without joining them into contigs. - Users can choose a high quality portion of the PE reads for analysis (e.g. first 200 / 150 bases from forward / reverse reads), according to base quality profile. - We implemented a tool that can splice out the target region (e.g. V3-V4) from a full-length 16S reference database into the PE sequences. CD-HIT-OTU-MiSeq can cluster the spliced PE reference database together with samples, so we can derive Operational Tax-onomic Units (OTUs) and annotate these OTUs concurrently. - Chimeric sequences are effectively identified through both de novo and reference-based approaches. The most important unique feature of CD-HIT-OTU-MiSeq is to only use high quality region at the 5’ ends of R1 and R2 reads. For example, the effective read length can be 200 bases for R1 and 150 bases for R2. The effective portions of PE reads are clustered together with spliced PE sequences from the reference database to derive OTUs (Figure). {{:cd-hit-otu-miseq-figure-1.png|}} ==== Installation ==== First download and install full cd-hit package * download current CD-HIT at [[https://github.com/weizhongli/cdhit/releases]], for example cd-hit-v4.6.2-2015-0511.tar.gz * unpack the file with " tar xvf cd-hit-v4.6.2-2015-0511.tar.gz --gunzip" * change dir by "cd cd-hit-v4.6.2-2015-0511" * compile the programs by "make" with multi-threading (default), or by "make openmp=no" without multi-threading (on old systems without OpenMP) * cd cd-hit-auxtools * compile cd-hit-auxtools by "make" * CD-HIT-OTU-MiSeq scripts are inside a folder like cd-hit-v4.6.2-2015-0511/usecases/Miseq-16S CD-HIT-OTU-MiSeq uses Trimmomatic for sequence quality control. It can be downloaded from [[http://www.usadellab.org/cms/?page=trimmomatic]] or [[https://github.com/timflutre/trimmomatic]]. We also have a copy at [[http://weizhongli-lab.org/download-data/cd-hit-otu-miseq/]]. * modify NG-Omics-Miseq-16S.pl Please edit usecases/Miseq-16S/NG-Omics-Miseq-16S.pl, in the top few lines: $CD_HIT_dir = "PATH_to_cd-hit"; $NGS_prog_trimmomatic = "PATH/trimmomatic-0.32.jar"; #### where you have installed Trimmomatic ==== Download reference and sample datasets ==== Reference database and sample datasets can be downloaded from [[http://weizhongli-lab.org/download-data/cd-hit-otu-miseq/]]. The reference database Greengene-13-5-99.fasta.gz was processed from original Greengene database, so that sequences with more specific annotations are at the beginning of the file. You need to download and gunzip it. You can also download Greengene and generate it. You should download Greengene from [[http://greengenes.secondgenome.com/downloads]], or [[ftp://greengenes.microbio.me/]]. Please download file like greengenes_release/gg_13_5/gg_13_5_otus.tar.gz, unpack the tar file. You may find gg_13_5_otus/taxonomy/99_otu_taxonomy.txt and gg_13_5_otus/rep_set/99_otus.fasta. There is a script: usecases/Miseq-16S/greengene-ann1.pl. Commands: /greengene-ann1.pl -i gg_13_5_otus/taxonomy/99_otu_taxonomy.txt -j gg_13_5_otus/rep_set/99_otus.fasta -o Greengene-13-5-99.fasta The Miseq-otu-example.tar.gz contains two Miseq 16S samples. You can download and unpack to test. ==== Usage ==== **Step 1. prepare fastq files and sample file:** Most projects have multiple samples sequenced at the same region. You should already have paired ended fastq files for these samples, put them in a working directory in similar way as the testing datasets, where the R1.fq and R2.fq are placed in separate folder for each sample. So in the working directory, you should have files: sample_name_1/R1.fq sample_name_1/R2.fq sample_name_2/R1.fq sample_name_2/R2.fq ... sample_name_N/R1.fq sample_name_N/R2.fq Then, please prepare a sample file in the working directory. The file should look like: sample_name_1 R1.fq R2.fq sample_name_2 R1.fq R2.fq sample_name_N R1.fq R2.fq **Step 2. Reference database preparation:** We implemented a tool that can splice out the target amplicon region (e.g. V3-V4) from a full-length 16S rRNA reference sequence database, such as Greengene, RDP and Silva, into PE sequences. If there are multiple samples in a project sequenced with the same amplicon of same variable region, only one spliced reference database is needed. To run: path_to_cd-hit_dir/usecases/Miseq-16S/16S-ref-db-PE-splice.pl -i sample_name_1/R1.fq -j sample_name_2/R2.fq -d Greengene-13-5-99.fasta -o gg_13_5-PE99.150-100 -p 150 -q 100 -c 0.99 Where Greengene-13-5-99.fasta is our re-formatted Greengene sequence file. This program will output spliced PE files gg_13_5-PE99.150-100-R1 and gg_13_5-PE99.150-100-R2. **Step 3. Run sequence QC and OTU clustering for each sample:**. In the working directory, run PATH_to_cd-hit-dir/usecases/NG-Omics-WF.pl -i PATH_to_cd-hit-dir/usecases/NG-Omics-Miseq-16S.pl -s sample_file -T otu:150:100:0.97:0.0001:PATH_to-gg_13_5-PE99.150-100-R1:PATH_to-gg_13_5-PE99.150-100-R2:75 -J write-sh where: 150 and 100 are the effective length, 0.97 is the OTU clustering cutoff, 0.00001 is the abundance cutoff, 75 is the length for chimeric checking at each R1 and R2 read This command will generate shell scripts for QC and for OTU for each sample. The scripts will be in WF-sh folder. You can first run the qc.sample_name.sh and then run otu.sample_name.sh NG-Omics-WF.pl [[https://github.com/weizhongli/ngomicswf]] is a very powerful workflow and pipeline tool developed in our group. It is not fully released yet, since we need more time to document this tool. However, you can try to use NG-Omics-WF.pl to automatically run all your samples. First edit NG-Omics-Miseq-16S.pl and modify cores_per_node around line #36, then nohup PATH_to_cd-hit-dir/usecases/NG-Omics-WF.pl -i PATH_to_cd-hit-dir/usecases/NG-Omics-Miseq-16S.pl -s sample_file -T otu:150:100:0.97:0.0001:PATH_to-gg_13_5-PE99.150-100-R1:PATH_to-gg_13_5-PE99.150-100-R2:75 & After the job finished, the OTU results will be in sample_name/otu folder, important files include * OTU.clstr: file lists all clusters and sequences * removed_chimeric*: chimeric sequenced removed * small_clusters.list: low abundance small clusters removed **Step 4. pool all the samples together:** Please run PATH_to_cd-hit-dir/usecases/pool_samples.pl -s sample_file -o pooled_sample. This will pool sequences from all sample and re-run OTU clustering. We can pool hundred of samples without problem. After job finished, additional files will be available from pooled_sample directory * OTU.clstr: file list all clusters and sequences from all samples * removed_chimeric*: chimeric sequenced removed * small_clusters.list: low abundance small clusters removed * OTU.txt: spread sheet list number of sequences in each OTU for each sample, it also show annotation for each OTU. * OTU.biome: OTU.txt in biome format ===== References ===== If you find cd-hit helpful to your research and study, please kindly cite the relevant references from the list below. - Weizhong Li, Lukasz Jaroszewski & Adam Godzik. Clustering of highly homologous sequences to reduce the size of large protein databases. Bioinformatics (2001) 17:282-283, [[http://bioinformatics.oupjournals.org/cgi/reprint/17/3/282.pdf|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11294794|Pubmed]] - Weizhong Li, Lukasz Jaroszewski & Adam Godzik. Tolerating some redundancy significantly speeds up clustering of large protein databases. Bioinformatics (2002) 18: 77-82, [[http://bioinformatics.oupjournals.org/cgi/reprint/18/1/77.pdf|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=11836214|Pubmed]] - Weizhong Li & Adam Godzik. Cd-hit: a fast program for clustering and comparing large sets of protein or nucleotide sequences. Bioinformatics (2006) 22:1658-1659, [[http://bioinformatics.oxfordjournals.org/cgi/reprint/22/13/1658|PDF]], [[http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pubmed&cmd=Retrieve&dopt=Abstract&list_uids=16731699|Pubmed]] - Ying Huang, Beifang Niu, Ying Gao, Limin Fu and Weizhong Li. CD-HIT Suite: a web server for clustering and comparing biological sequences. Bioinformatics, (2010). 26:680 [[http://bioinformatics.oxfordjournals.org/cgi/reprint/btq003v1|PDF]] [[http://www.ncbi.nlm.nih.gov/pubmed/20053844|Pubmed]] - Beifang Niu, Limin Fu, Shulei Sun and Weizhong Li, Artificial and natural duplicates in pyrosequencing reads of metagenomic data. BMC Bioinformatics, (2010), 11:187 [[http://www.biomedcentral.com/content/pdf/1471-2105-11-187.pdf|PDF]] [[http://www.ncbi.nlm.nih.gov/pubmed/20388221|Pubmed]] - Limin Fu, Beifang Niu, Zhengwei Zhu, Sitao Wu and Weizhong Li, CD-HIT: accelerated for clustering the next generation sequencing data. Bioinformatics, (2012), 28 (23): 3150-3152. doi: 10.1093/bioinformatics/bts565, [[http://bioinformatics.oxfordjournals.org/content/28/23/3150|PDF]], [[http://www.ncbi.nlm.nih.gov/pubmed/23060610|Pubmed]] - Weizhong Li, Limin Fu, Beifang Niu, Sitao Wu and John Wooley. Ultrafast clustering algorithms for metagenomic sequence analysis. Briefings in Bioinformatics, (2012) 13 (6): 656-668. doi: 10.1093/bib/bbs035 [[http://bib.oxfordjournals.org/content/13/6/656|PDF]] cdhit-4.6.8/doc/dokuwiki2latex.dao000077500000000000000000000303531312257207200170340ustar00rootroot00000000000000#!/Users/min/projects/dao/dao load sys; const latex_head = @[latex] \documentclass[12pt,a4paper]{article} \usepackage[latin1]{inputenc} \usepackage{amsmath} \usepackage{amsfonts} \usepackage{amssymb} \usepackage{scalefnt} \usepackage{titlesec} \usepackage{hyperref} \usepackage{cite} \usepackage{graphicx} \usepackage{wrapfig} \usepackage{xcolor} \usepackage{fancyvrb} %\usepackage{tikz} %\usepackage{pgflibraryarrows} %\usepackage{pgflibrarysnakes} %\usetikzlibrary{decorations.markings} %\usetikzlibrary{patterns,fadings} \addtolength{\hoffset}{-4em} \addtolength{\textwidth}{8em} \addtolength{\voffset}{-4em} \addtolength{\textheight}{8em} \setlength{\parindent}{2em} \linespread{1.1} % also in front page \renewcommand\FancyVerbTab{\textcolor{tabcolor}{$\mid$}} \newcommand*{\justifyheading}{\centering} \titleformat{\section} {\normalfont\Huge\bfseries\justifyheading}{\thesection}{1em}{} \titleformat{\subsection} {\normalfont\Large\bfseries}{\thesubsection}{1em}{} \usepackage{listings} \lstset{ % language=C, % choose the language of the code basicstyle=\small\ttfamily, % the size of the fonts that are used for the code numbers=left, % where to put the line-numbers numberstyle=\small\ttfamily, % the size of the fonts that are used for the line-numbers stepnumber=1, % the step between two line-numbers. If it's 1 each line will be numbered numbersep=5pt, % how far the line-numbers are from the code backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color} showspaces=false, % show spaces adding particular underscores showstringspaces=false, % underline spaces within strings showtabs=false, % show tabs within strings adding particular underscores frame=single, % adds a frame around the code tabsize=2, % sets default tabsize to 2 spaces captionpos=b, % sets the caption-position to bottom breaklines=true, % sets automatic line breaking breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace escapeinside={\%*}{*)} % if you want to add a comment within your code } @[latex] const open_doc = @[latex] \date{} \begin{document} \scalefont{1.1} \maketitle \vspace{10em} @[latex]; const make_toc = @[latex] \clearpage \tableofcontents \clearpage @[latex]; const make_fig = @[latex] \begin{figure}[!h] \includegraphics[$(size)]{$(figure)} $(caption) \end{figure} @[latex] class TextSection { var tag = ''; var name = ''; var output = ''; var subsections : list = {}; routine TextSection( tag = '', name = '' ){ self.tag = tag; self.name = name; } } class WikiParser { routine Parse( source :string ); routine ParseBlock( section :TextSection, source :string ); routine Formatting( source :string ); routine HandleIndentedCodes( source :string ); routine HandleTable( source :string ); } routine ToHex( self :string ) => string { const hex_digits = '0123456789ABCDEF'; hex = ''; self.change( '^[\n]+', '' ) self.change( '[\n]+ $', '' ) self.iterate::{ hex += hex_digits[ X / 16 ]; hex += hex_digits[ X % 16 ]; } return hex; } routine FromHex( self :string ) => string { ch0 = '0'[0]; chA = 'A'[0]; decoded = ''; for( i = 0 : 2 : self.size()-1 ){ ch1 = self[i]; ch2 = self[i+1]; ch1 = (ch1 >= chA) ? 10 + ch1 - chA : ch1 - ch0; ch2 = (ch2 >= chA) ? 10 + ch2 - chA : ch2 - ch0; decoded += ch1*16 + ch2; } return decoded; } routine Convert( self :string ) => string { self.change( '__(.*)__', '%1' ); self.replace( '_', '\\_' ); self.replace( '&', '\\&' ); self.replace( '%', '\\%' ); self.replace( '#', '\\#' ); self.replace( '<', '$<$' ); self.replace( '>', '$>$' ); self.change( '%*%*(.*)%*%*', '{\\bf %1}' ); self.change( '([^:])//(.*)//', '%1{\\it %2}' ); self.change( '\'\'(.*)\'\'', '\\texttt{%1}' ); self.change( '~~LASTMOD~~', sys.ctimef( 0, '%Y-%M-%D' ) ); return self; } routine WikiParser::Parse( source :string ) { const pat_nowiki = '( %< %s* nowiki %s* %> (.*) %< %s* / %s* nowiki %s* %> | %%%% (.*) %%%%)'; blocks = source.extract( pat_nowiki, $both ); source = ''; blocks.iterate::{ [block] parts = block.capture( pat_nowiki ); if( parts ){ source += 1; source += 'nowiki'; source += 1; source += (parts[2] + parts[3]).ToHex(); source += 2; }else{ source += block; } } const pat_marking = ' %< %s* (%w+) %s* %> (.*) %< %s* / %s* %1 %s* %>'; blocks = source.extract( pat_marking, $both ); source = ''; blocks.iterate::{ [block] parts = block.capture( pat_marking ); if( parts ){ source += 1; source += parts[1]; source += 1; source += parts[2].ToHex(); source += 2; }else{ source += block; } } const pat_headline = '(^ | [^=]) (={2,6}) ([^=].*) %2'; const pat_headline2 = '(^) %s* (={2,6}) %s* ([^=].*) %2'; blocks = source.extract( pat_headline, $both ); top_section = TextSection( '================================' ); cur_sections = { top_section }; first_sect = top_section; all_sections = { top_section }; while( blocks.size() ){ block = blocks.pop( $front ); tokens = block.capture( pat_headline2 ); if( tokens.size() == 0 ){ ParseBlock( cur_sections.back(), block ); skip; } tag = tokens[2]; title = tokens[3]; while( cur_sections.size() and cur_sections.back().tag <= tag ) cur_sections.pop(); if( cur_sections.size() ==0 ){ io.write( 'ERROR: too long headline for \"', block, '\"!\n' ); return ''; } cur_section = cur_sections.back(); sub_section = TextSection( tag, title ); cur_section.subsections.append( sub_section ); cur_sections.push( sub_section ); if( first_sect == top_section ) first_sect = sub_section; all_sections.push( sub_section ); } title = ''; tag_section = ''; if( cur_sections.size() > 1 && cur_sections[1] == first_sect ){ title = first_sect.name; if( first_sect.subsections.size() ) tag_section = first_sect.subsections.back().tag; } all_sections.pop( $front ); all_sections.pop( $front ); front = '\\begin{center}\n' + first_sect.output + '\n\\end{center}\n'; output = all_sections.reduce('')::{ [sect,text] headline = ''; if( sect.tag == tag_section ){ headline = '\n\\clearpage\n\\section{' + sect.name.Convert() + '}\n\n'; }else if( sect.tag < tag_section ){ headline = '\n\n\\subsection{' + sect.name.Convert() + '}\n\n'; } return text + headline + sect.output; }; const pat_hex = '{{\1}}(%w+){{\1}}([0-9A-F]+){{\2}}'; blocks = output.extract( pat_hex, $both ); output = ''; blocks.iterate::{ [block] parts = block.capture( pat_hex ); if( parts ){ switch( parts[1] ){ case 'code', 'file' : output += '\\begin{lstlisting}\n'; case 'sup' : output += '$^'; case 'sub' : output += '$_'; case 'nowiki', 'del', 'latex' : } output += parts[2].FromHex(); switch( parts[1] ){ case 'code', 'file' : output += '\n\\end{lstlisting}\n'; case 'sup' : output += '$'; case 'sub' : output += '$'; case 'nowiki', 'del', 'latex' : } }else{ output += block; } } head = '\\title{' + title.Convert() + '}\n'; head += open_doc; head += front; head += make_toc; output = head + output + '\\end{document}' output.change( '[\n]{2,}', '\n\n' ); #io.writeln( '=========================================' ); #io.writeln( all_sections ); #io.writeln( output ); return output; } routine WikiParser::ParseBlock( section :TextSection, source :string ) { const pat_list = '^({{ }}+ ( [%*%-] ))'; lines = source.split( '\n' ); blocks = { lines.pop( $front ) + '\n' }; while( lines ){ line = lines.pop( $front ); line2 = line[]; line2.trim(); match = line.match( pat_list ); if( match.start >= 0 or line2 == '' ){ blocks.push( line + '\n' ); }else{ blocks[ blocks.size() - 1 ] += line + '\n'; } } blocks.push( '' ); heads = { '' } output = ''; while( blocks ){ block = blocks.pop( $front ); head = heads.back(); head2 = ''; match = block.match( pat_list ); if( match.start >= 0 ) head2 = match.substring; if( head2.size() > head.size() ){ begin = '\\begin{itemize}\n '; if( head2[ head2.size()-1 ] == '-'[0] ) begin = '\\begin{enumerate}\n '; output += begin; heads.push( head2 ); }else if( head2.size() < head.size() ){ end = '\\end{itemize}\n'; if( head[ head.size()-1 ] == '-'[0] ) end = '\\end{enumerate}\n'; output += end; heads.pop(); } if( head2.size() ){ output += '\\item '; output += Formatting( block[ head2.size() : ] ); }else{ while( heads.size() > 1 ){ head = heads.pop(); end = '\\end{itemize}\n'; if( head[ head.size()-1 ] == '-'[0] ) end = '\\end{enumerate}\n'; output += end; } output += Formatting( block ); } } while( heads.size() > 1 ){ head = heads.pop(); end = '\\end{itemize}\n'; if( head[ head.size()-1 ] == '-'[0] ) end = '\\end{enumerate}\n'; output += end; } section.output = output; } routine WikiParser::HandleTable( source :string ) { lines = source.split( '\n' ); lines.append( '' ); output = ''; last = ( size => 0, fields => {} ); lines.iterate::{ if( X.match( '^ [%^%|] .* [%^%|]$' ).start <0 ){ if( last.fields.size() ){ output += '\\hline'; output += '\n\\end{tabular}\n\\end{table}\n\4'; } last = ( size => 0, fields => {} ); output += X + '\n'; return; } fields = X.extract( '[%^%|]', $both ) io.writeln( fields ); if( X.size() != last.size or fields.size() != last.fields.size() ){ # new table: if( last.fields.size() ){ output += '\\hline'; output += '\n\\end{tabular}\n\\end{table}\n\4'; } output += '\3\n\\begin{table}[!h]\n\\begin{tabular}{'; fields.iterate::{ if( X == '^' or X == '|' ){ output += '|'; }else{ # TODO alignment output += 'c'; } } output += '}\n'; output += '\\hline\n'; }else{ output += '\\hline\n'; } fields.iterate::{ if( X == '^' or X == '|' ){ if( Y and (Y+1) < fields.size() ) output += ' & '; }else{ output += X.Convert(); } } output += ' \\\\\n'; last.size = X.size(); last.fields = fields; } blocks = output.extract( '{{\3}}[^\3\4]*{{\4}}', $both ); blocks.apply::{ if( X.size() and X[0] == 3 and X[X.size()-1] == 4 ){ return '\1nowiki\1' + X[1:X.size()-2].ToHex() + '\2'; } return X; } return blocks.sum(); } routine WikiParser::HandleIndentedCodes( source :string ) { lines = source.split( '\n' ); blocks = { '' }; indented = 0; while( lines ){ line = lines.pop( $front ) + '\n'; if( line.match( '^%s%s%S' ).start == 0 ){ if( indented ){ blocks.back() += line; }else{ blocks.push( line ); indented = 1; } }else{ if( indented ){ blocks.push( line ); indented = 0; }else{ blocks.back() += line; } } } blocks.apply::{ if( X.match( '^%s%s%S' ).start != 0 ) return HandleTable( X ); return '\1code\1' + X.ToHex() + '\2'; } return blocks.sum(); } routine WikiParser::Formatting( source :string ) { const pat_link = '%[%[([^%|]*)(| %| (.+)) %]%]'; const pat_figure = '%{%{ %s* (| wiki) %s* : %s* ([^ \t\n%?]+) %s* (| %? ((%d+) (|[xX] (%d+) ))) %s* (| %| (.*) ) %}%}'; source = HandleIndentedCodes( source ); parts = source.extract( '(' + pat_link + ' | ' + pat_figure + ')', $both ); parts.apply::{ [text] tokens = text.capture( '^' + pat_link ); tokens2 = text.capture( '^' + pat_figure ); if( tokens ){ url = tokens[1]; url.replace( '/', '\\slash ' ); if( tokens[3] ){ return '\\href{' + url + '}{' + tokens[3] + '}'; }else{ return '\\href{' + url + '}{' + url + '}'; } desc = tokens[1]; if( tokens[3] ) desc = tokens[3]; }else if( tokens2 ){ size = 'width=\\textwidth'; file = tokens2[2]; caption = ''; if( tokens2[4] ){ size = 'width=' + tokens2[5] + 'px'; if( tokens2[7] ) size += ',height=' + tokens2[7] + 'px'; } if( tokens2[9] ) caption = '\\caption{' + tokens2[9] + '}'; return make_fig.expand( (size=>size, figure=>file, caption=>caption) ); } return text.Convert(); } return parts.sum(); } routine main( file : string ) #{ Usage: %P input_wiki_source_file #} { source = io.read( file ); parser = WikiParser(); output = parser.Parse( source ); file.change( '%.wiki$', '' ); fout = io.open( file + '.tex', 'w+' ); fout.write( latex_head ); fout.write( output ); fout.close(); } cdhit-4.6.8/license.txt000066400000000000000000000432541312257207200150200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. cdhit-4.6.8/make_multi_seq.pl000077500000000000000000000032061312257207200161650ustar00rootroot00000000000000#!/usr/bin/perl #note you have to use "-d 0" in the cd-hit run #note you better to use "-g 1" in the cd-hit run # this script read the .clstr file, it generate a seperate fasta file # for each cluster over certain size # for example, if you run cd-hit -i db -o dbout -c 0.6 -n 4 -d 0 -g 1 # then you will have a dbout.clstr # now run this script: # ./make_multi_seq.pl db dbout.clstr multi-seq 20 # my $fasta = shift; my $clstr = shift; my $out_dir = shift; my $size_cutoff = shift; die unless (-e $fasta); die unless (-e $clstr); die unless ($out_dir); $size_cutoff = 1 unless ($size_cutoff); if (not -e $out_dir) {my $cmd = `mkdir $out_dir`;} open(TMP, $clstr) || die; my %id2cid=(); my $cid = ""; my @ids = (); my $no = 0; while($ll = ) { if ($ll =~ /^>/) { if ($no >= $size_cutoff) { foreach $i (@ids) { $id2cid{$i} = $cid;} } if ($ll =~ /^>Cluster (\d+)/) { $cid = $1; } else { die "Wrong format $ll"; } @ids = (); $no = 0; } else { if ($ll =~ /(aa|nt), >(.+)\.\.\./) { push(@ids, $2); $no++; } else { die "Wrong format $ll"; } } } close(TMP); if ($no >= $size_cutoff) { foreach $i (@ids) { $id2cid{$i} = $cid;} } open(FASTA, $fasta) || die; my $outfile_open = 0; my $flag = 0; while($ll=) { if ($ll=~ /^>(\S+)/) { my $id = $1; my $cid = $id2cid{$id}; if (defined($cid)) { close(OUT) if ($outfile_open); open(OUT, ">> $out_dir/$cid") || die "can not open file to write $out_dir/$cid"; $outfile_open = 1; $flag = 1; } else { $flag = 0; } } if ($flag) {print OUT $ll;} } close(FASTA); close(OUT) if ($outfile_open); cdhit-4.6.8/plot_2d.pl000077500000000000000000000071241312257207200145340ustar00rootroot00000000000000#!/usr/bin/perl use Image::Magick; $file90 = shift; $segs = shift; $out_file = shift; my $image_xx = 800; my $image_yy = 600; my $border = 20; my $border2 = $border/2; my $lab_margin = 30; my $scale = 200/10; my @seg_colors = qw//; my @seg_sizes = qw/1 2 5 6 8 10 12 14 16 18 20/; my $p = { magick => Image::Magick->new(), border => 2, grid_color => "#eeeeee", gif_file => $out_file, height => $image_yy+$border+$lab_margin, width => $image_xx+$border, }; $p->{magick}->Set(size => "$p->{width}x$p->{height}"); $p->{magick}->Read('xc:white'); my @clstr_nos = (); open(TMP, $file90) || die "Can not open file"; $readin = 0; my $this_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { if ($readin) { $clstr_nos[$this_no]++; } $this_no=0; } else { $readin = 1; $this_no++; } } close(TMP); if ($readin) { $clstr_nos[$this_no]++; } @segs = split(/,/, $segs); @segs_no = (); for ($i=0; $i<@segs; $i++) { $seg = $segs[$i]; if ($seg =~ /-/) { ($b, $e) = split(/-/, $seg); } else { $b= $e = $seg; } $no1 = 0; for($j=$b; $j<=$e; $j++) { $no1+= $clstr_nos[$j]; } print "$seg\t$no1\n"; $no2 = int($no1/$scale); $no2++ if ($no1 % $scale); $segs_no[$i] = $no2; } my @covered = (); my $xmin = $border2; my $xmax = $image_xx+$border2; my $ymin = $border2; my $ymax = $image_yy+$border2; $p->{magick}->Draw(primitive => 'line', points => "$xmin,$ymin,$xmax,$ymin"); $p->{magick}->Draw(primitive => 'line', points => "$xmin,$ymin,$xmin,$ymax"); $p->{magick}->Draw(primitive => 'line', points => "$xmax,$ymin,$xmax,$ymax"); $p->{magick}->Draw(primitive => 'line', points => "$xmin,$ymax,$xmax,$ymax"); my $no_segs = $#segs+1; for ($i=$#segs; $i>=0; $i--) { $size = $seg_sizes[$i]-1; $c = "#000000"; $no2 = $segs_no[$i]; for ($j=0; $j<$no2; $j++) { $x1 = rand($image_xx)+$border2; $x2 = $x1 + $size; $y1 = rand($image_yy)+$border2; $y2 = $y1 + $size; if ($x2 > $xmax) {$x2 = $xmax; $x1 = $x2-$size;} if ($y2 > $ymax) {$y2 = $ymax; $y1 = $y2-$size;} if ($size) { $p->{magick}->Draw(primitive => 'Rectangle', points => "$x1,$y1,$x2,$y2", fill => $c); } else { $p->{magick}->Draw(primitive => 'point', points => "$x1,$y1", fill => $c); } } $x1 = $border2 + int($image_xx/$no_segs)*$i; $x2 = $x1 + $size; $y1 = $ymax + int($lab_margin/2) - int($size/2); $y2 = $y1 + $size; if ($size) { $p->{magick}->Draw(primitive => 'Rectangle', points => "$x1,$y1,$x2,$y2", fill => $c); } else { $p->{magick}->Draw(primitive => 'point', points => "$x1,$y1", fill => $c); } } $p->{magick}->Write($p->{gif_file}); #build color index my @colors = (); for ($i=0; $i<$steps; $i++) { $j = $i/$steps; my ($r, $g, $b) = get_gradient_color_255_old($j); my $c1 = uc(sprintf("#%2x%2x%2x",$r,$g,$b)); $c1 =~ s/ /0/g; $colors[$i] = $c1; } # return color sub get_gradient_color_255_old { my $ratio = shift; my ($r, $g, $b); if ($ratio >= 0 and $ratio < 0.2 ) { $r = 255; $g = int( 1275*$ratio ); $b = 0; } elsif ($ratio >= 0.2 and $ratio < 0.4 ) { $r = int ( 255 - 1275*($ratio-0.2) ); $g = 255; $b = 0; } elsif ($ratio >= 0.4 and $ratio < 0.6 ) { $r = 0; $g = 255; $b = int ( 1275 * ($ratio-0.4) ); } elsif ($ratio >= 0.6 and $ratio < 0.8 ) { $r = 0; $g = int ( 255 - 1275*($ratio-0.6) ); $b = 255; } elsif ($ratio >= 0.8 and $ratio <= 1.0 ) { $r = int ( 1275 *($ratio-0.8) ); $g = 0; $b = 255; } return ($r,$g,$b); } cdhit-4.6.8/plot_len1.pl000077500000000000000000000042161312257207200150650ustar00rootroot00000000000000#!/usr/bin/perl $file90 = shift; $segs = shift; @segs = split(/,/, $segs); $len_segs = shift; @len_segs = split(/,/,$len_segs); my @clstr_nos = (); my @clstr_len = (); open(TMP, $file90) || die "Can not open file"; $readin = 0; my $this_no = 0; my $this_len = 0; my $max_no = 0; while(my $ll=) { if ($ll =~ /^>/ ) { if ($readin) { $clstr_nos[$this_no]++; $max_no = $this_no if ($this_no>$max_no); if (not defined($clstr_len[$this_no])) { $clstr_len[$this_no] = []; } push(@{$clstr_len[$this_no]}, $this_len) } $this_no=0; } else { $readin = 1; $this_no++; chop($ll); if ($ll =~ /\*$/) { if ($ll =~ /(\d+)(aa|nt), /) { $this_len=$1;} } } } close(TMP); if ($readin) { $clstr_nos[$this_no]++; $max_no = $this_no if ($this_no>$max_no); if (not defined($clstr_len[$this_no])) { $clstr_len[$this_no] = []; } push(@{$clstr_len[$this_no]}, $this_len) } print "Size\tNo. seq\tNo. clstr"; my @tlen_nos = (); for ($j=0; $j<@len_segs; $j++) { $len_seg = $len_segs[$j]; print "\t$len_seg"; $tlen_nos[$j] = 0; } print "\n"; my $tno = 0; my $tno1 = 0; for ($i=0; $i<@segs; $i++) { $seg = $segs[$i]; my @lens = (); if ($seg =~ /-/) { $no = 0; $no1 = 0; ($b, $e) = split(/-/, $seg); $e = $max_no if ($e =~ /up/i); for($j=$b; $j<=$e; $j++) { $no += $j * $clstr_nos[$j]; $no1+= $clstr_nos[$j]; push(@lens, @{$clstr_len[$j]}); } $tno += $no; $tno1 += $no1; print "$seg\t$no\t$no1"; } else { $tno += $seg * $clstr_nos[$seg]; $tno1 += $clstr_nos[$seg]; push(@lens, @{$clstr_len[$seg]}); print "$seg\t", $seg * $clstr_nos[$seg], "\t$clstr_nos[$seg]"; } for ($j=0; $j<@len_segs; $j++) { $len_seg = $len_segs[$j]; $no1 = 0; my ($b, $e); if ($len_seg =~ /-/) { ($b, $e) = split(/-/, $len_seg); } else { $b = $e = $len_seg; } foreach $tlen (@lens) { $no1++ if (($tlen>=$b) and ($tlen<=$e)); } print "\t$no1"; $tlen_nos[$j] += $no1; } print "\n"; } print "Total\t$tno\t$tno1"; for ($j=0; $j<@len_segs; $j++) { print "\t$tlen_nos[$j]"; } print "\n"; cdhit-4.6.8/psi-cd-hit/000077500000000000000000000000001312257207200145665ustar00rootroot00000000000000cdhit-4.6.8/psi-cd-hit/README.psi-cd-hit000066400000000000000000000022131312257207200174040ustar00rootroot00000000000000 For protein sequences (1) Please use regular cd-hit to cluster your database down to 60% using commands such as cd-hit -i db -o db_90 -c 0.9 -n 5 -g 1 -G 0 -aS 0.8 -d 0 -p 1 -T 16 -M 0 > db_90.log cd-hit -i db_90 -o db_60 -c 0.6 -n 4 -g 1 -G 0 -aS 0.8 -d 0 -p 1 -T 16 -M 0 > db_60.log (2) (a) option for local execution on a single computer: ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec local -core 16 ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec local -core 16 -restart db_30.restart (to restart if program crash) ./psi-cd-hit.pl -help to see all options (b) option for running on a cluster using a queueing system (qsub) ./psi-cd-hit.pl -i db_60 -o db_30 -c 0.3 -ce 1e-6 -aS 0.8 -G 0 -g 1 -exec qsub -host 8 -core 8 -shf qsub_sh_template For very long DNA sequences ./psi-cd-hit.pl -i db.fna -o db90.fna -c 0.9 -G 1 -g 1 -prog megablast -s "-F F -e 0.000001 -b 100000 -v 100000" -exec local -core 32 ./psi-cd-hit.pl -i db.fna -o db90.fna -c 0.9 -G 1 -g 1 -prog blastn -circle 1 -exec local -core 32 ./psi-cd-hit.pl -help to see all options visit http://cd-hit.org for more info cdhit-4.6.8/psi-cd-hit/cd-hit-div.pl000077500000000000000000000015551312257207200170640ustar00rootroot00000000000000#!/usr/bin/perl #not like cd-hit-div, this script do not sort input #or throw away seq $in = shift; $in or die "no input file"; $out = shift; $out or die "no output file"; $div = shift; $div or die "no div number"; @fhs = (); for ($i=0; $i<$div; $i++) { my $tf = "$out-$i"; $tfh = "FH". $i; open($tfh, "> $tf") || die "can not open output files for write"; push(@fhs, $tfh); } open(TMP, $in) || die "can not open input file"; my $seq; my $des; my $no = 0; while($ll = ) { if ($ll =~ /^>/) { if ($seq) { $i = $no % $div; $tfh = $fhs[$i]; $no++; print $tfh $des, $seq; } $des = $ll; $seq = ""; } else { $seq .= $ll; } } if ($seq) { $i = $no % $div; $tfh = $fhs[$i]; $no++; print $tfh $des, $seq; } close(TMP); for ($i=0; $i<$div; $i++) { $tfh = $fhs[$i]; close($tfh); } cdhit-4.6.8/psi-cd-hit/clstr_select_rep.pl000077500000000000000000000010501312257207200204560ustar00rootroot00000000000000#!/usr/bin/perl my $by = shift; my $min; my $max; if ($by eq "size") { $min = shift; $max = shift; } $rep = ""; $no = 0; while($ll=<>){ if ($ll =~ /^>/) { if (($no >= $min) and ($no <= $max)) { print "$rep\n"; } $rep = ""; $no = 0; } else { chop($ll); if ($ll =~ /\*$/) { $rep = ""; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $rep = $2; } else { die "format error $ll"; } } $no++; } } if (($no >= $min) and ($no <= $max)) { print "$rep\n"; } cdhit-4.6.8/psi-cd-hit/clstr_select_seq.pl000077500000000000000000000007561312257207200204740ustar00rootroot00000000000000#!/usr/bin/perl my $by = shift; my $min; my $max; if ($by eq "size") { $min = shift; $max = shift; } $rep = ""; $no = 0; while($ll=<>){ if ($ll =~ /^>/) { if (($no >= $min) and ($no <= $max)) { print "$rep"; } $rep = ""; $no = 0; } else { chop($ll); if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $rep .= "$2\n"; } else { die "format error $ll"; } $no++; } } if (($no >= $min) and ($no <= $max)) { print "$rep"; } cdhit-4.6.8/psi-cd-hit/fetch_fasta_by_ids.pl000077500000000000000000000006601312257207200207300ustar00rootroot00000000000000#!/usr/bin/perl my ($gi_file, $seq_file) = @ARGV; my %gi1 = (); my $gi; open(TMP, $gi_file) || die; while($ll = ) { chop($ll); $ll =~ s/\s.+$//; $ll =~ s/^>//; $gi1{$ll} = 1; } close(TMP); my $flag = 0; open(TMP, $seq_file) || die; while($ll = ) { if ($ll =~ /^>/) { $gi = substr($ll,1); chop($gi); $gi =~ s/\s.+$//; $flag = ( $gi1{$gi} ) ? 1 : 0; } print $ll if ($flag); } close(TMP); cdhit-4.6.8/psi-cd-hit/fetch_fasta_exclude_ids.pl000077500000000000000000000006601312257207200217470ustar00rootroot00000000000000#!/usr/bin/perl my ($gi_file, $seq_file) = @ARGV; my %gi1 = (); my $gi; open(TMP, $gi_file) || die; while($ll = ) { chop($ll); $ll =~ s/\s.+$//; $ll =~ s/^>//; $gi1{$ll} = 1; } close(TMP); my $flag = 0; open(TMP, $seq_file) || die; while($ll = ) { if ($ll =~ /^>/) { $gi = substr($ll,1); chop($gi); $gi =~ s/\s.+$//; $flag = ( $gi1{$gi} ) ? 0 : 1; } print $ll if ($flag); } close(TMP); cdhit-4.6.8/psi-cd-hit/psi-2d.pl000077500000000000000000000316231312257207200162310ustar00rootroot00000000000000#!/usr/bin/perl my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; chop($script_dir); $script_dir = "./" unless ($script_dir); use Getopt::Std; getopts("i:j:b:o:c:l:d:q:",\%opts); die usage() unless ($opts{i} and $opts{j} and $opts{b} and $opts{o}); my ($i, $j, $k, $cmd, $ll); my $db1 = $opts{i}; my $db2 = $opts{j}; my $bl = $opts{b}; # $bl is output file that blast db against db2 # formatdb -i db2 -p F # blastall -n blastn -i db1 -d db2 -m 8 my $output = $opts{o}; my $circle = $opts{c}; my $cutoff_len = $opts{l}; $cutoff_len = 0 unless ($cutoff_len); my $cutoff_idens= $opts{d}; $cutoff_idens= 0 unless ($cutoff_idens); my $cutoff_idenq= $opts{q}; $cutoff_idenq= 0 unless ($cutoff_idenq); my @id_db1 = (); my %id_db1_2_len = (); %id_db1_2_len_nN = (); my $db1_no = 0; my @id_db2 = (); my %id_db2_2_len = (); %id_db2_2_len_nN = (); my $db2_no = 0; read_db1(); read_db2(); open(OUT, ">$output") || die "can not open $output\n"; open(BL, $bl) || die "can not open $bl\n"; my $last_qid = ""; my @bl_sbj; my $bl_data_no=0; while($ll = ){ next if ($ll =~ /^#/); chop($ll); my @lls = split(/\t/,$ll); if ($lls[0] ne $last_qid) { if ($bl_data_no>0) { my $bl_data = { 'no' => $bl_data_no, 'sbj' => [@bl_sbj], }; process_this_bl( $bl_data ); } @bl_sbj = (); $bl_data_no = 0; } my $frame = ""; $frame .= ($lls[6] < $lls[7]) ? "+" : "-"; $frame .= ($lls[8] < $lls[9]) ? "+" : "-"; $bl_sbj[$bl_data_no] = { 'qid' => $lls[0], 'id' => $lls[1], 'iden' => $lls[2], 'alnln' => $lls[3], 'ms' => $lls[4], 'gap' => $lls[5], 'qfrom' => $lls[6], 'qend' => $lls[7], 'sfrom' => $lls[8], 'send' => $lls[9], 'expect' => $lls[10], 'score' => $lls[11], 'frame' => $frame, }; $bl_data_no++; $last_qid = $lls[0]; } close(BL); if ($bl_data_no>0) { my $bl_data = { 'no' => $bl_data_no, 'sbj' => [@bl_sbj], }; process_this_bl( $bl_data ); } close(OUT); ################################################################################ sub process_this_bl { my $bl = shift; my ($i, $j, $k, $ll); keep_strand_with_top_hsp($bl); if ($circle) { reset_alignment_coor_for_circle_seq($bl); } filter_short_hits($bl); #### remove hits based on total lengths #### still need to remove based on co-linner hits return unless ($bl->{no}); my $qid = $bl->{sbj}->[0]->{qid}; my %hit_ids = map { $_->{id}, 1} @{$bl->{sbj}}; my $hit_no = 0; my $text_data = ""; my @hsp = (); #### [id, len, qfrom, qend, sbegin, send, expect] my $hsp_no = 0; my $hit_len = 0; for ($i=0; $i<$bl->{no}; $i++) { my $p = $bl->{sbj}->[$i]; my $id1 = $p->{id}; if ($hsp_no) { if ($id1 ne $hsp[0]->[0]) { if (($hit_len >= $cutoff_len) and ($hit_len >= $cutoff_idens * $id_db2_2_len{$hsp[0]->[0]}) and ($hit_len >= $cutoff_idenq * $id_db1_2_len{$qid})) { @hsp = sort {$a->[2] <=> $b->[2]} @hsp; $text_data .= print_hsp($qid, @hsp); $hit_no++; } @hsp = (); @aln_lens = (); $hsp_no = 0; $hit_len = 0; } } #check whether overlap with previous high score HSPs my $overlap_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (overlap1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3])) { $overlap_flag = 1; last; } if (overlap1($p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $overlap_flag = 1; last; } } next if ($overlap_flag); #check whether this HSP cross with previous high score HSPs my $cross_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (cross1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3], $p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $cross_flag = 1; last; } } next if ($cross_flag); push(@hsp, [$id1, $len_sub, $p->{qfrom}, $p->{qend}, $p->{sfrom}, $p->{send}, $p->{expect}, $p->{frame}]); $hit_len += abs($p->{sfrom} - $p->{send}); $hsp_no++; } if ($hsp_no) { if (($hit_len >= $cutoff_len) and ($hit_len >= $cutoff_idens * $id_db2_2_len{$hsp[0]->[0]}) and ($hit_len >= $cutoff_idenq * $id_db1_2_len{$qid})) { @hsp = sort {$a->[2] <=> $b->[2]} @hsp; $text_data .= print_hsp($qid, @hsp); $hit_no++; } } print OUT ">$qid\t$id_db1_2_len{$qid}\t$hit_no\n"; print OUT $text_data; } ########## END process_this_bl sub print_hsp { my ($qid, @hsp) = @_; my $hsp_no = $#hsp+1; my ($i, $j, $k); my $print_hsp_return = ""; my @str1 = (); my $aln1 = 0; my @str2 = (); my $aln2 = 0; for ($i=0; $i<$hsp_no; $i++){ push(@str1, "$hsp[$i]->[2]-$hsp[$i]->[3]"); $aln1 += $hsp[$i]->[3]-$hsp[$i]->[2]; push(@str2, "$hsp[$i]->[4]-$hsp[$i]->[5]"); $aln2 += $hsp[$i]->[5]-$hsp[$i]->[4]; } my $sid = $hsp[0]->[0]; $print_hsp_return .= "\t$qid\t$id_db1_2_len{$qid}\t$id_db1_2_len_nN{$qid}\t$aln1\t". join("|", @str1). "\n"; $print_hsp_return .= "\t$sid\t$id_db2_2_len{$sid}\t$id_db1_2_len_nN{$qid}\t$aln2\t". join("|", @str2). "\n"; return $print_hsp_return; } ########## END print_hsp sub overlap1 { my ($b1, $e1, $b2, $e2) = @_; my $t; ### if ($e1 < $b1) { $t = $e1; $e1 = $b1; $b1 = $t; } if ($e2 < $b2) { $t = $e2; $e2 = $b2; $b2 = $t; } return 0 if ($e2 < $b1); return 0 if ($b2 > $e1); return ( ($e1<$e2)? $e1:$e2 )-( ($b1>$b2)? $b1:$b2); } ########## END overlap1 sub cross1 { my ($q_b1, $q_e1, $q_b2, $q_e2, $s_b1, $s_e1, $s_b2, $s_e2) = @_; my $fr_q1 = ($q_b1 < $q_e1) ? 1 : -1; my $fr_q2 = ($q_b2 < $q_e2) ? 1 : -1; my $fr_s1 = ($s_b1 < $s_e1) ? 1 : -1; my $fr_s2 = ($s_b2 < $s_e2) ? 1 : -1; my $fr1 = $fr_q1 * $fr_s1; my $fr2 = $fr_q2 * $fr_s2; return 1 if (($fr1 * $fr2) < 0); # one ++ and one +- my $t; if ($q_e1 < $q_b1) { $t = $q_e1; $q_e1 = $q_b1; $q_b1 = $t; } if ($q_e2 < $q_b2) { $t = $q_e2; $q_e2 = $q_b2; $q_b2 = $t; } if ($s_e1 < $s_b1) { $t = $s_e1; $s_e1 = $s_b1; $s_b1 = $t; } if ($s_e2 < $s_b2) { $t = $s_e2; $s_e2 = $s_b2; $s_b2 = $t; } # after above transformation # 0 q_b1 q_e1 q_b2 q_e2 qlen # query 5' ==================================================================== # match |||||||||||||||| ||||||||||||| # subject 5' ========================================================================>>>>>> frame + # 0 s_b1 s_e1 s_b2 s_e2 slen # match |||||||||||||||| ||||||||||||| # subject 3' ========================================================================>>>>>> frame - # slen s_e1 s_b1 s_e2 s_b2 0 if (($fr1 > 0) and ($fr2>0)) { # both ++ return ( (($q_b2-$q_b1)*($s_b2-$s_b1) <0) ? 1 : 0); } else { # both -- return ( (($q_b2-$q_b1)*($s_e1-$s_e2) <0) ? 1 : 0); } } ########## END cross1 ########## let the top hsp to start at 0 for both query and subject ########## i.e. the begining of HSP to be new original - coordinate 0 ########## then reset all other HSPs' alignment coordinates sub reset_alignment_coor_for_circle_seq { my $self = shift; my ($i,$j,$k); my $last_id = ""; $j = 0; my $hsp_count = 0; # number of HSPs for a subject for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); if ($id1 ne $last_id) { if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } $j = $i; $hsp_count = 0; } $last_id = $id1; $hsp_count++; } #last subject if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } return; } ########## reset_alignment_coor_for_circle_seq ########### if a hit has multiple HSPs on both + - strands ########### keep only the HSPs, whose strand is same as the top HSP sub keep_strand_with_top_hsp { my $self = shift; my ($i,$j,$k); my %id_2_strand = (); my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my $id1 = $p->{id}; if (not defined($id_2_strand{$id1})) { $id_2_strand{$id1} = $p->{frame}; } if ($p->{frame} eq $id_2_strand{$id1}) { #### this stand is same as the top strand push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END keep_strand_with_top_hsp ########## remove short hits sub filter_short_hits { my $self = shift; my ($i,$j,$k); my $qid = $self->{sbj}->[0]->{qid}; my %hit_len = (); for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my $id1 = $p->{id}; $hit_len{$id1} += abs($p->{sfrom} - $p->{send}); } my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my $id1 = $p->{id}; if (($hit_len{$id1} >= $cutoff_len) and ($hit_len{$id1} >= $cutoff_idens * $id_db2_2_len{$id1}) and ($hit_len{$id1} >= $cutoff_idenq * $id_db1_2_len{$qid})) { push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END filter_short_hits sub read_db1 { my ($i, $j, $k, $ll, $len, $id, $len2); open(TMP, $db1) || die "Can not open $db1\n"; $len = 0; $len2 = 0; while($ll=){ if ($ll =~ /^>/) { if ($len > 0) { $id_db1_2_len{$id} = $len; $id_db1_2_len_nN{$id} = $len2; } chop($ll); $ll =~ s/\s.+$//; $id = substr($ll,1); $len = 0; $len2 = 0; } else { chop($ll); $ll =~ s/\s//; $len += length($ll); $ll =~ s/N//ig; $len2 += length($ll); } } if ($len > 0) { $id_db1_2_len{$id} = $len; $id_db1_2_len_nN{$id} = $len2; } close(TMP); @id_db1 = keys %id_db1_2_len; $db1_no = $#id_db1 + 1; return; } ########## END read_db1 sub read_db2 { my ($i, $j, $k, $ll, $len, $id, $len2); open(TMP, $db2) || die "Can not open $db2\n"; $len = 0; $len2 = 0; while($ll=){ if ($ll =~ /^>/) { if ($len > 0) { $id_db2_2_len{$id} = $len; $id_db2_2_len_nN{$id} = $len2; } chop($ll); $ll =~ s/\s.+$//; $id = substr($ll,1); $len = 0; $len2 = 0; } else { chop($ll); $ll =~ s/\s//; $len += length($ll); $ll =~ s/N//ig; $len2 += length($ll); } } if ($len > 0) { $id_db2_2_len{$id} = $len; $id_db2_2_len_nN{$id} = $len2; } close(TMP); @id_db2 = keys %id_db2_2_len; $db2_no = $#id_db2 + 1; return; } ########## END read_db2 sub usage { <){ chop($ll); if ($ll =~ /^>/) { $seq =~ s/\s//g; if (length($seq) > $len_t) { add_seq($des, $seq); } $des = $ll; $seq = ""; } else { $seq .= $ll; } } $seq =~ s/\s//g; if (length($seq) > $len_t) { add_seq($des, $seq); } close(DBIN); ($NR_no >=1 ) || die "No sequence readin"; print OUTT "Total seqs $NR_no in $db_in\n"; return; } ########## END read_db sub add_seq { my ($des, $seq) = @_; $des =~ s/\s.+$//; push(@seqs, $seq); push(@dess, $des); push(@lens, length($seq)); push(@idens, 0); push(@passeds,0); push(@NR_clstr_nos,0); push(@in_bg, 0); $NR_no++; return; } ########## END add_seq sub open_LOG { open(OUTT, ">> $db_out1") || die "can not open $db_out1"; select(OUTT); $|++; ### file handle flush print OUTT "Started $date"; open(LOG, ">> $db_log") || die "Can not open $db_log"; select(LOG); $|++; ### file handle flush select(STDOUT); return; } ########## END open_LOG sub write_LOG { my $txt=shift; print LOG "$txt\n"; } {## use static variables my $last_NR90_no=0; my $last_NR_passed=0; sub watch_progress { my ($i0, $NR90_no, $NR_passed, $NR_no, $flag) = @_; my $i1 = $i0+1; if ( $i1 % 10 == 0 ) { print OUTT "."; $flag = 1 if ( $i1 % 100 == 0 ); } if ($flag) { my $t1 = (int($NR_passed/$NR_no*10000)) / 100; my $t90 = $NR90_no - $last_NR90_no; my $tno = $NR_passed - $last_NR_passed; my ($tu, $ts, $cu, $cs) = times(); my $tt = $tu + $ts + $cu + $cs; print OUTT "$i1 finished $NR90_no clusters $NR_passed passed $t90/$tno clstr/passed $t1% done $tt cpu\n"; $last_NR90_no = $NR90_no; $last_NR_passed = $NR_passed; } return; } } sub close_LOG { my $date = `date`; print OUTT "Completed $date\n"; my $total_cpu = total_remote_cpu(); print OUTT "Total CPUs on remote hosts: $total_cpu\n"; close(OUTT); close(LOG); return; } ########## END close_LOG ###### need to change to read dir because sub total_remote_cpu { my ($i, $j, $k, $ll); my $tt = 0; for ($j=0; $j<$num_qsub; $j++) { open(TCPU, "$seq_dir/host.$j.cpu") || next; while($ll = ) { chop($ll); $tt += $ll; } close(TCPU); } return $tt; } ########## END total_remote_cpu sub job_parse_blout { my ($i, $j, $k); my @hits = process_blout_blastp_blastn($job_file); open(BLOUT2, "> $job_file.out") || return; foreach $i (@hits) { print BLOUT2 join("\t", @{$i}), "\n"; } print BLOUT2 "#\n"; close(BLOUT2); return; } ########## END job_parse_blout sub write_restart { my ($i0, $i, $j, $k); open(RES, "> $restart_file") || die; for ($i0=0; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; print RES "$i\t$NR_clstr_nos[$i]\t$idens[$i]\t$passeds[$i]\n"; } close(RES); return; } ########## END write_restart sub read_restart { my ($ii, $i0, $i, $j, $k, $ll); my @lls; open(RESIN, $restart_in) || die; $NR_passed = 0; $NR90_no = 0; $ii = -1; $i0 = 0; while($ll = ) { chop($ll); @lls = split(/\t/,$ll); $i = $lls[0]; $NR_clstr_nos[$i] = $lls[1]; $idens[$i] = $lls[2]; $passeds[$i] = $lls[3]; $NR_passed++ if ($lls[3]); if ($lls[2] eq "*") { #rep $NR90_no++; $ii = $i0 if ($lls[3]); } $NR_idx[$i0] = $i; $i0++; # idx of sorted , see write_restart } close(RESIN); $ii++; # $ii to be last rep processed return $ii; } ########## END read_restart sub write_db_clstr { my ($i0, $i, $j, $k); my @NR90_seq = (); for ($i=0; $i<$NR90_no; $i++) { $NR90_seq[$i] = []; } for ($i0=0; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; next unless ($passeds[$i]); $j = $NR_clstr_nos[$i]; next unless ($j < $NR90_no); push(@{$NR90_seq[$j]}, $i); } open(DBCLS, "> $db_clstr") || die "Can not write $db_clstr"; for ($i=0; $i<$NR90_no; $i++) { print DBCLS ">Cluster $i\n"; $k = 0; foreach $j (@{ $NR90_seq[$i] }) { my $des = (split(/\s+/,$dess[$j]))[0]; print DBCLS "$k\t$lens[$j]"."aa, $des... "; if ($idens[$j] eq "*") { print DBCLS "*\n"; } else { print DBCLS "at $idens[$j]\n";} $k++; } } close(DBCLS); @NR90_seq=(); return; } ########## END write_db_clstr sub remove_raw_blout { my $NR_sofar = shift; my ($i0, $i, $j, $k, $cmd); return if ($keep_bl); for ($i0=$NR_sofar; $i0>=0; $i0--) { $i = $NR_idx[$i0]; next unless $passeds[$i]; next unless ($idens[$i] eq "*"); #only reps have blout my $fout = "$bl_dir/$i"; last unless (-e "$fout.out"); #removed from last call if (not $bl_STDIN) { $cmd = `rm -f $fout`; } $cmd = `rm -f $bl_dir/$i.out`; } return; } ########## END remove_raw_blout sub remove_raw_blout_bg { my $NR_sofar = shift; my ($i0, $i, $j, $k, $cmd); return if ($keep_bl); my $tmp_sh_script = "$tmp_db-rm-$NR_sofar.sh"; open(OUTRM, ">$tmp_sh_script") || die "can not write to $tmp_sh_script"; for ($i0=$NR_sofar; $i0>=0; $i0--) { $i = $NR_idx[$i0]; next unless $passeds[$i]; next unless ($idens[$i] eq "*"); #only reps have blout my $fout = "$bl_dir/$i"; last unless (-e "$fout.out"); #removed from last call if (not $bl_STDIN) { print OUTRM "rm -f $fout\n"; } print OUTRM "rm -f $bl_dir/$i.out"; } print OUTRM "rm -f $tmp_sh_script\n"; ## remove self close(OUTRM); sleep(3); $cmd = `sh $tmp_sh_script >/dev/null 2>&1 &`; return; } ########## END remove_raw_blout_bg sub fish_other_homolog { my ($i, $j, $k, $i0, $j0, $k0); $id = shift; # real idx, not sorted idx my @hits = (); wait_blast_out("$bl_dir/$id.out"); open(BLPOUT, "$bl_dir/$id.out") || return; while($i=) { last if ($i =~ /^#/); chop($i); push(@hits, [split(/\t/,$i)]); } close(BLPOUT); my $rep_len = $lens[$id]; foreach $i (@hits) { my $id1 = $i->[0]; next unless ($id1 < $NR_no); next if ($idens[$id1] eq "*"); #existing reps next if ($lens[$id1] > $rep_len); # in opt_g=1 mode, preventing it from being clustered into short rep if ( $passeds[$id1] ) { #### if this hit is better -g 1 mode my $old_e = (split(/\//,$idens[$id1]))[0]; if ($i->[3] < $old_e) { $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; } next; } $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; $NR_passed++; } return; } ########## END fish_other_homolog ########### if a hit has multiple HSPs on both + - strands ########### keep only the HSPs, whose strand is same as the top HSP sub keep_strand_with_top_hsp { my $self = shift; my ($i,$j,$k); my %id_2_strand = (); my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); if (not defined($id_2_strand{$id1})) { $id_2_strand{$id1} = $p->{frame}; } if ($p->{frame} eq $id_2_strand{$id1}) { #### this stand is same as the top strand push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END keep_strand_with_top_hsp ########## for blastpgp -j no (no>1) ########## keep hits from the last round sub keep_hsp_of_last_round { my $self = shift; my ($i,$j,$k); my @new_sbj = (); my $new_no = 0; my $last_score = 9999999*9999999*9999999; # a big one for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my $score = $p->{score}; if ($score > $last_score) { ## this is new round of hits @new_sbj = (); $new_no = 0; } $last_score = $score; push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END keep_hsp_of_last_round ########## if a query hit a subject with multiple HSPs ########## only the top HSP is kept sub keep_top_hsp { my $self = shift; my ($i,$j,$k); my %id_exist = (); my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); next unless ($len_sub >0) ; if (not defined($id_exist{$id1})) { $id_exist{$id1} = 1; push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## keep_top_hsp ########## let the top hsp to start at 0 for both query and subject ########## i.e. the begining of HSP to be new original - coordinate 0 ########## then reset all other HSPs' alignment coordinates sub reset_alignment_coor_for_circle_seq { my $self = shift; my ($i,$j,$k); my $last_id = ""; $j = 0; my $hsp_count = 0; # number of HSPs for a subject for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); if ($id1 ne $last_id) { if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } $j = $i; $hsp_count = 0; } $last_id = $id1; $hsp_count++; } #last subject if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } return; } ########## reset_alignment_coor_for_circle_seq sub process_blout_blastp_blastn { my ($i, $j, $k, $i0, $j0, $k0); my $blout = shift; my @blhits = (); #### need $len_rep my $len_rep = 0; my $bl = readblast_m8("", $blout); if ($blast_prog eq "blastn") { keep_strand_with_top_hsp($bl); } if (($blast_prog eq "blastpgp") and (not $prof_db)) {keep_hsp_of_last_round($bl); } if ($g_iden == 0 ) { #### Local identity keep_top_hsp($bl); #### local alignment, only the top HSP for ($i=0; $i<$bl->{no}; $i++) { my $p = $bl->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); my $frame = $p->{frame}; if (not $len_rep) {$len_rep = (split(/\./,$p->{qid}))[1]; } my $iden = $p->{iden}; next unless (($len_sub >0) and ($len_rep>0)); my $cov_aS = $p->{alnln} / $len_sub; my $cov_aL = $p->{alnln} / $len_rep; my $exp1 = $p->{expect}; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { push(@blhits, [$id1, $iden, $p->{alnln}, $exp1, $frame]); } } return @blhits; } #### END if ($g_iden == 0 ) else { #### Global idnetity if (($blast_prog eq "blastn") and $circle) { reset_alignment_coor_for_circle_seq($bl); } #### get colinear non-overlapping HSPs my @hsp = (); #### [id, len, qfrom, qend, sbegin, send, expect] my $iden_letters = 0; my $aln_letters = 0; my @aln_lens = (); my $hsp_no = 0; for ($i=0; $i<$bl->{no}; $i++) { my $p = $bl->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); my $frame = $p->{frame}; if (not $len_rep) {$len_rep = (split(/\./,$p->{qid}))[1]; } next unless (($len_sub >0) and ($len_rep>0)); if ($hsp_no) { if ($id1 ne $hsp[0]->[0]) { #### 1. parse previous subject's HSPs my $iden = int($iden_letters / $hsp[0]->[1] * 10000)/100; my $cov_aS = $aln_letters / $hsp[0]->[1]; my $cov_aL = $aln_letters / $len_rep; my $exp1 = $hsp[0]->[6]; my $frame = $hsp[0]->[7]; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { #push(@blhits, [$hsp[0]->[0], $iden, $aln_letters, $exp1, $frame]); push(@blhits, [$hsp[0]->[0], $iden, join(":", @aln_lens), $exp1, $frame]); } #### 2. init some values @hsp = (); $iden_letters = 0; $aln_letters = 0; @aln_lens = (); $hsp_no = 0; } } #check whether overlap with previous high score HSPs my $overlap_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (overlap1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3])) { $overlap_flag = 1; last; } if (overlap1($p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $overlap_flag = 1; last; } } next if ($overlap_flag); #check whether this HSP cross with previous high score HSPs my $cross_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (cross1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3], $p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $cross_flag = 1; last; } } next if ($cross_flag); push(@hsp, [$id1, $len_sub, $p->{qfrom}, $p->{qend}, $p->{sfrom}, $p->{send}, $p->{expect}, $p->{frame}]); $iden_letters += int($p->{iden} * $p->{alnln} / 100); $aln_letters += $p->{alnln}; push(@aln_lens, $p->{alnln}); $hsp_no++; } if ($hsp_no) { #last record #### 1. parse previous subject's HSPs my $iden = int($iden_letters / $hsp[0]->[1] * 10000)/100; my $cov_aS = $aln_letters / $hsp[0]->[1]; my $cov_aL = $aln_letters / $len_rep; my $exp1 = $hsp[0]->[6]; my $frame = $hsp[0]->[7]; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { #push(@blhits, [$hsp[0]->[0], $iden, $aln_letters, $exp1, $frame]); push(@blhits, [$hsp[0]->[0], $iden, join(":", @aln_lens), $exp1, $frame]); } } return @blhits; } } ########## END process_blout_blastp_blastn sub overlap1 { my ($b1, $e1, $b2, $e2) = @_; my $t; ### if ($e1 < $b1) { $t = $e1; $e1 = $b1; $b1 = $t; } if ($e2 < $b2) { $t = $e2; $e2 = $b2; $b2 = $t; } return 0 if ($e2 < $b1); return 0 if ($b2 > $e1); return ( ($e1<$e2)? $e1:$e2 )-( ($b1>$b2)? $b1:$b2); } ########## END overlap1 ## modified on 2013_0818 to hancle +- frames sub cross1 { my ($q_b1, $q_e1, $q_b2, $q_e2, $s_b1, $s_e1, $s_b2, $s_e2) = @_; my $fr_q1 = ($q_b1 < $q_e1) ? 1 : -1; my $fr_q2 = ($q_b2 < $q_e2) ? 1 : -1; my $fr_s1 = ($s_b1 < $s_e1) ? 1 : -1; my $fr_s2 = ($s_b2 < $s_e2) ? 1 : -1; my $fr1 = $fr_q1 * $fr_s1; my $fr2 = $fr_q2 * $fr_s2; return 1 if (($fr1 * $fr2) < 0); # one ++ and one +- my $t; if ($q_e1 < $q_b1) { $t = $q_e1; $q_e1 = $q_b1; $q_b1 = $t; } if ($q_e2 < $q_b2) { $t = $q_e2; $q_e2 = $q_b2; $q_b2 = $t; } if ($s_e1 < $s_b1) { $t = $s_e1; $s_e1 = $s_b1; $s_b1 = $t; } if ($s_e2 < $s_b2) { $t = $s_e2; $s_e2 = $s_b2; $s_b2 = $t; } # after above transformation # 0 q_b1 q_e1 q_b2 q_e2 qlen # query 5' ==================================================================== # match |||||||||||||||| ||||||||||||| # subject 5' ========================================================================>>>>>> frame + # 0 s_b1 s_e1 s_b2 s_e2 slen # match |||||||||||||||| ||||||||||||| # subject 3' ========================================================================>>>>>> frame - # slen s_e1 s_b1 s_e2 s_b2 0 if (($fr1 > 0) and ($fr2>0)) { # both ++ return ( (($q_b2-$q_b1)*($s_b2-$s_b1) <0) ? 1 : 0); } else { # both -- return ( (($q_b2-$q_b1)*($s_e1-$s_e2) <0) ? 1 : 0); } } ########## END cross1 ## modified on 2013_0818 to hancle +- frames sub cross1_before_2013_0818 { my ($q_b1, $q_e1, $q_b2, $q_e2, $s_b1, $s_e1, $s_b2, $s_e2) = @_; my $t; if ($q_e1 < $q_b1) { $t = $q_e1; $q_e1 = $q_b1; $q_b1 = $t; } if ($q_e2 < $q_b2) { $t = $q_e2; $q_e2 = $q_b2; $q_b2 = $t; } if ($s_e1 < $s_b1) { $t = $s_e1; $s_e1 = $s_b1; $s_b1 = $t; } if ($s_e2 < $s_b2) { $t = $s_e2; $s_e2 = $s_b2; $s_b2 = $t; } return ( (($q_b2-$q_b1)*($s_b2-$s_b1) <0) ? 1 : 0); } ########## END cross1 sub readblast_m8 { my ($i, $j, $k, $ll, $no); my ($q_seq, $filename) = @_; my $fh = "BL" ; if ($bl_STDIN) { $fh = "STDIN"; } else { open($fh, $filename) || return; } my @this_sbj = (); $no = 0; while($ll = <$fh>) { chop($ll); my @lls = split(/\t/,$ll); my $frame = ""; $frame .= ($lls[6] < $lls[7]) ? "+" : "-"; $frame .= ($lls[8] < $lls[9]) ? "+" : "-"; next unless ($lls[0] and $lls[1]); $this_sbj[$no] = { 'qid' => $lls[0], 'id' => $lls[1], 'iden' => $lls[2], 'alnln' => $lls[3], 'ms' => $lls[4], 'gap' => $lls[5], 'qfrom' => $lls[6], 'qend' => $lls[7], 'sfrom' => $lls[8], 'send' => $lls[9], 'expect' => $lls[10], 'score' => $lls[11], 'frame' => $frame, }; $no++; # BLASTP 2.2.24 [Aug-08-2010] # Query: gi|388328107|pdb|4DDG|A Chain A, Crystal Structure Of Human Otub1UBCH5B~UBUB # Database: pdbaa.fa # Fields: Query id, Subject id, % identity, alignment length, mismatches, gap openings, q. start, q. end, s. start, s. end, e-value, bit score #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 91.81 171 9 3 6 171 1 171 6e-89 323 #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 96.51 86 3 0 235 320 155 240 2e-41 166 } close($fh) if (not $bl_STDIN); my $self = { 'no' => $no, 'sbj' => [@this_sbj], }; return $self; } ########## END readblast_m8 sub blast_formatdb { my ($i0, $i, $j, $k, $len1); open(FDB, "> $tmp_db") || die; $j = 0; $len1 = 0; for ($i0=$NR_no-1; $i0>=0; $i0--) { ### from shortest to longest $i = $NR_idx[$i0]; last if ($idens[$i] eq "*"); ### last if reach rep next if ($lens[$i] < $opt_aL_lower_band); next if ($passeds[$i] and ($opt_g==0)); my $seq = $seqs[$i]; $seq =~ s/(.{70})/$1\n/g; $seq =~ s/\n$//; #print FDB ">$i $dess[$i]\n$seq\n"; print FDB ">$i.$lens[$i]\n$seq\n"; $j++; $len1 += $lens[$i]; } close(FDB); while(1) { opendir(SEQDB, $seq_dir) || next; my @leftseqs = grep {/lock/} readdir(SEQDB); closedir(SEQDB); last unless @leftseqs; sleep(3); } return(0, 0) unless ($j > 0); my $cmd_line = "$formatdb -i $tmp_db"; $cmd_line = "$formatdb -in $tmp_db" if ($bl_plus); my $cmd = `$cmd_line`; ((-e "$tmp_db.phr") and (-e "$tmp_db.pin") and (-e "$tmp_db.psq")) || ((-e "$tmp_db.nhr") and (-e "$tmp_db.nin") and (-e "$tmp_db.nsq")) || ((-e "$tmp_db.00.phr") and (-e "$tmp_db.00.pin") and (-e "$tmp_db.00.psq")) || ((-e "$tmp_db.00.nhr") and (-e "$tmp_db.00.nin") and (-e "$tmp_db.00.nsq")) || die "Can not formatdb"; return($j, $len1); } ########## END blast_formatdb sub remove_blast_db { my ($i, $j, $k); $cmd = `rm -f $tmp_db`; $cmd = `rm -f $tmp_db.p*`; $cmd = `rm -f $tmp_db.n*`; return; } ########## END remove_blast_db my $common_usage = <> << len 2 >> i.e. redundant <<<<<<<<<<<< length of short sequence >>>>>>>>>>>>>> sequence total identical letters from all co-linear and non-overlapping HSPs Glogal identity = ------------------------------------------------------------------- length of short sequence Local identity = identity of the top high score HSP if you prefer to use -G 0, it is suggested that you also use -aS, -aL, such as -aS 0.8, to prevent very short matches. -aL alignment coverage for the longer sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -aS alignment coverage for the shorter sequence, default 0.0 if set to 0.9, the alignment must covers 90% of the sequence -g (1/0), default 0 by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -circle (1/0), default 0 when set to 1, treat sequences as circular sequence. bacterial genomes, plasmids are circular, but their genome coordinate maybe arbitary, the 2 HSPs below will be treated as non co-linear with -circle 0 the 2 HSPs below will be treated as co-linear with -circle 1 -------------circle----------- | | seq1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 1 \\\\\\\\ ///////////// \\\\\\\\ ///////////// HSP 2 -> ////HSP 1 /// <-HSP 2 ///////////// \\\\\\\\ ///////////// \\\\\\\\ seq2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 2 | | -----------circle-------------- -sl, length of very long sequences to be skipped, default 0, no skipping e.g. -sl 5000 means sequences longer than 5000 aa will be treated as singleton clusters without clustering, to save time, especially when there is -aL option in place, very long sequences will not be clustered anyway. program: -prog (blastp, blastn, megablast, blastpgp), default blastp -p profile search para, default "-j 3 -F F -e 0.001 -b 500 -v 500" -dprof database for building PSSM, default using input you can also use another database that is more comprehensive like NR80 -s blast search para, default "-F F -e 0.000001 -b 100000 -v 100000" -bs (1/0) default 1 pipe blast results from into parser instead of save in hard drive (save time) compute: -exec (qsub, local) default local this program writes a shell script to run blast, this script is either performed locally by sh or remotely by qsub with qsub, you can use PBS, SGE etc -host number of hosts, ie number of qsub jobs -para number of parallel blast job per qsub job (each blast can use multi cores), default 1 -blp number of threads per blast job, default 1 number of threads per blast job X number of parallel blast job per qsub job should <= the number of cores in your computer if your computer grid has 32 cores / node, do either of the followings -para 4 -blp 8 -para 8 -blp 4 -para 16 -blp 2 -para 32 -blp 1 -bat number of sequences a blast job to process -shf a filename for add local settings into the job shell script for example, when you run PBS jobs, you can add quene name etc in this file and this script will add them into the job shell script e.g. template file for PBS #!/bin/sh #PBS -v PATH #PBS -l walltime=8:00:00 #PBS -q job_queue.q e.g. template file for SGE or OGE #!/bin/sh #\$ -v PATH #\$ -q job_queue.q #\$ -V #\$ -pe orte 8 job: -rs steps of save restart file and clustering output, default 5000 everytime after process 5000 sequences, program write a restart file and current clustering information -restart restart file, readin a restart file if program crash, stoped, termitated, you can restart it by add a option "-restart sth.restart" -rf steps of re format blast database, default 200,000 if program clustered 200,000 seqs, it remove them from seq pool, and re format blast db to save time -J job, job_file, exe specific jobs like parse blast outonly DO NOT use it, it is only used by this program itself -k (1/0) keep blast raw output file, default $keep_bl -P path to executables EOD sub print_usage { print < $seq_dir/$id") || die "Can not write"; #print SEQ "$dess[$id]\n$seq\n"; print SEQ ">$id.$lens[$id]\n$seq\n"; close(SEQ); $k++; last if ($k >= $total_jobs); } if ($exec_mode eq "qsub") { for ($j=0; $j<$num_qsub; $j++) { my $t = "psi-cd-hit-$j"; my $cmd = `qsub -N $t $remote_sh_script`; my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} print LOG "qsub querying $j, PID $qsub_id\n"; $qsub_ids{$qsub_id} = 1; } } elsif ($exec_mode eq "local") { #my $cmd = `sh $remote_sh_script >/dev/null 2>&1 &`; my $cmd = `sh $remote_sh_script`; } return; } ########## END run_batch_blast3 sub write_remote_sh_script { my ($i, $j, $k); my $local_sh = < $remote_sh_script") || die; print RESH < $remote_perl_script") || die; print REPERL <> $seq_dir/host.\$host.cpu`; EOD close(REPERL); my $cmd = `chmod 755 $remote_perl_script`; return; } ########## END write_remote_perl_script sub wait_blast_out { my $out = shift; print LOG "waiting for $out"; while(1) { if (-e $out) { my $last = `tail -1 $out`; chop($last); last if ($last =~ /^#$/); } sleep(1); print LOG "."; } print LOG "\n"; return; } ########## END wait_blast_out sub SGE_qstat_xml_query { my ($i, $j, $k, $cmd, $ll); %qstat_xml_data = (); #### global $cmd = `qstat -f -xml`; if ($cmd =~ / all.q\@master BIP 0 0 0 0.08000 linux-x64 ... all.q\@node016 BIP 32 0 32 42.59000 linux-x64 ####### running jobs in this section 3535 0.51468 cd-hit ubuntu r 4 ... ######## pending jobs in this section 3784 0.60500 cd-hit ubuntu qw 32 ... EOD my @lls = split(/\n/, $cmd); $i = 2; #### skip first 2 lines for (; $i<$#lls+1; $i++) { if ($lls[$i] =~ /(\d+)/) { $id = $1;} if ($lls[$i] =~ /([^<]+)/) { $name = $1;} if ($lls[$i] =~ /([^<]+)/) {$state = $1;} } if (defined($id) and defined($name) and defined($state)) { $qstat_xml_data{$id} = [$name, $state]; } } } } 1; cdhit-4.6.8/psi-cd-hit/psi-cd-hit-local.pl000077500000000000000000001350021312257207200201600ustar00rootroot00000000000000#!/usr/bin/perl -w ################################################################################ ######### PSI-cd-hit written by Weizhong Li at http://cd-hit.org ################################################################################ our $pid = $$; our $db_in; ################### our $db_out; # input / output our $len_t = 10; ################### our $NR_clstr = 0.3; # our $NR_clstre = -1; #thresholds our $g_iden = 1; # our $opt_aS = 0.0; # our $opt_aL = 0.0; # our $circle = 0; # our $opt_g = 1; #################### our $blast_exe = "blastall -p blastp -m 8"; ######################### our $prof_exe = "blastpgp -m 8"; # our $prof_para = "-j 3 -F T -e 0.001 -b 500 -v 500"; # our $prof_db = ""; # our $bl_para = "-F T -e 0.000001 -b 100000 -v 100000"; # program our $bl_STDIN = 1; # our $keep_bl = 0; # our $blast_prog= "blastp"; # our $formatdb = "formatdb"; ######################### our $exec_mode = "local"; ####################### our $num_qsub = 1; # our $para_no = 1; # compute our $sh_file = ""; # our $num_multi_seq = 50; # our $batch_no_per_node = 100; ####################### our $reformat_seg = 50000; our $restart_seg = 20000; our $job = ""; our $job_file = ""; our $date = `date`; our $restart_in = ""; our $pwd = `pwd`; chop($pwd); our $db_clstr; our $db_log; our $db_out1; our $seq_dir; our $bl_dir; our $blm_dir; our $restart_file; our $tmp_db; our $remote_perl_script; our $remote_sh_script; our $bl_path; our $bl_plus = 1; #### use blast+ our $bl_threads = 1; our $skip_long = 0; our %qsub_ids = (); #### a list of qsub ids our %qstat_xml_data = (); our @blm8_buffer = (); our %blm8_data = (); sub parse_para_etc { my ($arg, $cmd); while($arg = shift) { ## input/output: if ($arg eq "-i") { $db_in = shift; } elsif ($arg eq "-o") { $db_out = shift; } elsif ($arg eq "-l") { $len_t = shift; } ## thresholds elsif ($arg eq "-c") { $NR_clstr = shift; } elsif ($arg eq "-ce") { $NR_clstre = shift; } elsif ($arg eq "-G") { $g_iden = shift; } elsif ($arg eq "-aL") { $opt_aL = shift; } elsif ($arg eq "-aS") { $opt_aS = shift; } elsif ($arg eq "-g") { $opt_g = shift; } elsif ($arg eq "-circle") { $circle = shift; } elsif ($arg eq "-sl") { $skip_long = shift; } ## program elsif ($arg eq "-prog") { $blast_prog= shift; } elsif ($arg eq "-p") { $prof_para = shift; } elsif ($arg eq "-dprof") { $prof_db = shift; die "option -dprof no longer supported!";} elsif ($arg eq "-s") { $bl_para = shift; } elsif ($arg eq "-k") { $keep_bl = shift; } elsif ($arg eq "-bs") { $bl_STDIN = shift; } ## compute elsif ($arg eq "-exec") { $exec_mode = shift; } elsif ($arg eq "-host") { $num_qsub = shift; } elsif ($arg eq "-para") { $para_no = shift; } elsif ($arg eq "-shf") { $sh_file = shift; } elsif ($arg eq "-blp") { $bl_threads = shift; } elsif ($arg eq "-bat") { $batch_no_per_node = shift; } ## job: elsif ($arg eq "-rs") { $restart_seg = shift; } elsif ($arg eq "-rf") { $reformat_seg= shift; } elsif ($arg eq "-restart") { $restart_in= shift; } elsif ($arg eq "-J") { $job = shift; $job_file = shift; } ## blast path elsif ($arg eq "-P") { $bl_path = shift; } else { print_usage(); exit(); } } # speical jobs if ($job eq "parse_blout") { job_parse_blout(); exit();} elsif ($job eq "parse_blout_multi") { job_parse_blout_multi(); exit();} if (not (defined($db_in) and defined($db_out))) { print_usage(); exit(); } if ($blast_prog eq "blastn") { $formatdb = "formatdb -p F"; $blast_exe = "blastall -p blastn -m 8"; } elsif ($blast_prog eq "megablast") { $blast_prog = "blastn"; #### back to blastn for blast parser type $formatdb = "formatdb -p F"; $blast_exe = "megablast -H 100 -D 2 -m 8"; } elsif ($blast_prog eq "blastpgp") { $blast_exe = "blastpgp -m 8 -j 3"; } #### for blast+ if ($bl_plus) { $formatdb = "makeblastdb -dbtype prot -max_file_sz 8GB"; $blast_exe = "blastp -outfmt 6"; $bl_para = "-seg yes -evalue 0.000001 -num_alignments 100000 -num_threads $bl_threads"; # program if ($blast_prog eq "blastn") { $formatdb = "makeblastdb -dbtype nucl -max_file_sz 8GB"; $blast_exe = "blastn -task blastn -outfmt 6"; $bl_para = "-dust yes -evalue 0.000001 -num_alignments 100000 -num_threads $bl_threads"; # program } elsif ($blast_prog eq "megablast") { $blast_prog = "blastn"; #### back to blastn for blast parser type $formatdb = "makeblastdb -dbtype nucl -max_file_sz 8GB"; $blast_exe = "blastn -task megablast -outfmt 6"; $bl_para = "-dust yes -evalue 0.000001 -num_alignments 100000 -num_threads $bl_threads"; # program } elsif ($blast_prog eq "blastpgp") { $blast_exe = "psiblast -outfmt 6 -num_iterations 3 -num_threads $bl_threads"; } } if ($bl_path) { $blast_exe = "$bl_path/$blast_exe"; $formatdb = "$bl_path/$formatdb"; } (-e $db_in) || die "No input"; ($db_out) || die "No output"; $db_clstr = "$db_out.clstr"; $db_log = "$db_out.log"; $db_out1 = "$db_out.out"; $seq_dir = "$db_in-seq"; $bl_dir = "$db_in-bl"; $blm_dir = "$db_in-blm"; $restart_file =" $db_out.restart"; $tmp_db = "$db_in.$pid"; $remote_perl_script = "$tmp_db-bl.pl"; $remote_sh_script = "$tmp_db-bl.sh"; $cmd = `mkdir $bl_dir $blm_dir $seq_dir`; write_remote_perl_script(); write_remote_sh_script(); return; } ########## END parse_para_etc sub read_db { my $des = ""; my $seq = ""; my $ll; open(DBIN, $db_in) || die "Can not open $db_in"; while($ll=){ chop($ll); if ($ll =~ /^>/) { $seq =~ s/\s//g; if (length($seq) > $len_t) { add_seq($des, $seq); } $des = $ll; $seq = ""; } else { $seq .= $ll; } } $seq =~ s/\s//g; if (length($seq) > $len_t) { add_seq($des, $seq); } close(DBIN); ($NR_no >=1 ) || die "No sequence readin"; print OUTT "Total seqs $NR_no in $db_in\n"; return; } ########## END read_db sub add_seq { my ($des, $seq) = @_; $des =~ s/\s.+$//; push(@seqs, $seq); push(@dess, $des); push(@lens, length($seq)); push(@idens, 0); push(@passeds,0); push(@NR_clstr_nos,0); push(@in_bg, 0); $NR_no++; return; } ########## END add_seq sub open_LOG { open(OUTT, ">> $db_out1") || die "can not open $db_out1"; select(OUTT); $|++; ### file handle flush print OUTT "Started $date"; open(LOG, ">> $db_log") || die "Can not open $db_log"; select(LOG); $|++; ### file handle flush select(STDOUT); return; } ########## END open_LOG sub write_LOG { my $txt=shift; print LOG "$txt\n"; } {## use static variables my $last_NR90_no=0; my $last_NR_passed=0; sub watch_progress { my ($i0, $NR90_no, $NR_passed, $NR_no, $flag) = @_; my $i1 = $i0+1; if ( $i1 % 10 == 0 ) { print OUTT "."; $flag = 1 if ( $i1 % 100 == 0 ); } if ($flag) { my $t1 = (int($NR_passed/$NR_no*10000)) / 100; my $t90 = $NR90_no - $last_NR90_no; my $tno = $NR_passed - $last_NR_passed; my ($tu, $ts, $cu, $cs) = times(); my $tt = $tu + $ts + $cu + $cs; print OUTT "$i1 finished $NR90_no clusters $NR_passed passed $t90/$tno clstr/passed $t1% done $tt cpu\n"; $last_NR90_no = $NR90_no; $last_NR_passed = $NR_passed; } return; } } sub close_LOG { my $date = `date`; print OUTT "Completed $date\n"; my $total_cpu = total_remote_cpu(); print OUTT "Total CPUs on remote hosts: $total_cpu\n"; close(OUTT); close(LOG); return; } ########## END close_LOG ###### need to change to read dir because sub total_remote_cpu { my ($i, $j, $k, $ll); my $tt = 0; for ($j=0; $j<$num_qsub; $j++) { open(TCPU, "$seq_dir/host.$j.cpu") || next; while($ll = ) { chop($ll); $tt += $ll; } close(TCPU); } return $tt; } ########## END total_remote_cpu #### process m8 format output from multi-query search sub job_parse_blout_multi{ my ($i, $j, $k, $tfh, $ll, $t1, $t2); $tfh="BLM8"; open($tfh, $job_file) || die "can not open $job_file"; @blm8_buffer = (); my $last_id = ""; my $this_id = ""; my $tquery; while($ll = <$tfh>) { next if ($ll =~ /^#/); ($this_id, $t1) = split(/\s+/, $ll, 2); if (@blm8_buffer and ($this_id ne $last_id)) { #### blast results of last query my @hits = process_blout_blastp_blastn(); $tquery = (split(/\./, $last_id))[0]; my $no1 = $#hits+1; print ">$tquery\t$no1\n"; foreach $i (@hits) { print join("\t", @{$i}), "\n"; } print "#\n"; @blm8_buffer = (); } push(@blm8_buffer, $ll); $last_id = $this_id; } if (@blm8_buffer and ($this_id ne $last_id)) { #### blast results of last query my @hits = process_blout_blastp_blastn(); $tquery = (split(/\./, $last_id))[0]; my $no1 = $#hits+1; print ">$tquery\t$no1\n"; foreach $i (@hits) { print join("\t", @{$i}), "\n"; } print "#\n"; @blm8_buffer = (); } close($tfh); return; } ########## END job_parse_blout_multi sub job_parse_blout { my ($i, $j, $k); my @hits = process_blout_blastp_blastn($job_file); open(BLOUT2, "> $job_file.out") || return; foreach $i (@hits) { print BLOUT2 join("\t", @{$i}), "\n"; } print BLOUT2 "#\n"; close(BLOUT2); return; } ########## END job_parse_blout sub write_restart { my ($i0, $i, $j, $k); open(RES, "> $restart_file") || die; for ($i0=0; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; print RES "$i\t$NR_clstr_nos[$i]\t$idens[$i]\t$passeds[$i]\n"; } close(RES); return; } ########## END write_restart sub read_restart { my ($ii, $i0, $i, $j, $k, $ll); my @lls; open(RESIN, $restart_in) || die; $NR_passed = 0; $NR90_no = 0; $ii = -1; $i0 = 0; while($ll = ) { chop($ll); @lls = split(/\t/,$ll); $i = $lls[0]; $NR_clstr_nos[$i] = $lls[1]; $idens[$i] = $lls[2]; $passeds[$i] = $lls[3]; $NR_passed++ if ($lls[3]); if ($lls[2] eq "*") { #rep $NR90_no++; $ii = $i0 if ($lls[3]); } $NR_idx[$i0] = $i; $i0++; # idx of sorted , see write_restart } close(RESIN); $ii++; # $ii to be last rep processed return $ii; } ########## END read_restart sub write_db_clstr { my ($i0, $i, $j, $k); my @NR90_seq = (); for ($i=0; $i<$NR90_no; $i++) { $NR90_seq[$i] = []; } for ($i0=0; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; next unless ($passeds[$i]); $j = $NR_clstr_nos[$i]; next unless ($j < $NR90_no); push(@{$NR90_seq[$j]}, $i); } open(DBCLS, "> $db_clstr") || die "Can not write $db_clstr"; for ($i=0; $i<$NR90_no; $i++) { print DBCLS ">Cluster $i\n"; $k = 0; foreach $j (@{ $NR90_seq[$i] }) { my $des = (split(/\s+/,$dess[$j]))[0]; print DBCLS "$k\t$lens[$j]"."aa, $des... "; if ($idens[$j] eq "*") { print DBCLS "*\n"; } else { print DBCLS "at $idens[$j]\n";} $k++; } } close(DBCLS); @NR90_seq=(); return; } ########## END write_db_clstr sub remove_raw_blout { my $NR_sofar = shift; my ($i0, $i, $j, $k, $cmd); return if ($keep_bl); for ($i0=$NR_sofar; $i0>=0; $i0--) { $i = $NR_idx[$i0]; next unless $passeds[$i]; next unless ($idens[$i] eq "*"); #only reps have blout my $fout = "$bl_dir/$i"; last unless (-e "$fout.out"); #removed from last call if (not $bl_STDIN) { $cmd = `rm -f $fout`; } $cmd = `rm -f $bl_dir/$i.out`; } return; } ########## END remove_raw_blout sub remove_raw_blout_bg { my $NR_sofar = shift; my ($i0, $i, $j, $k, $cmd); return if ($keep_bl); my $tmp_sh_script = "$tmp_db-rm-$NR_sofar.sh"; open(OUTRM, ">$tmp_sh_script") || die "can not write to $tmp_sh_script"; for ($i0=$NR_sofar; $i0>=0; $i0--) { $i = $NR_idx[$i0]; next unless $passeds[$i]; next unless ($idens[$i] eq "*"); #only reps have blout my $fout = "$bl_dir/$i"; last unless (-e "$fout.out"); #removed from last call if (not $bl_STDIN) { print OUTRM "rm -f $fout\n"; } print OUTRM "rm -f $bl_dir/$i.out"; } print OUTRM "rm -f $tmp_sh_script\n"; ## remove self close(OUTRM); sleep(3); $cmd = `sh $tmp_sh_script >/dev/null 2>&1 &`; return; } ########## END remove_raw_blout_bg sub fish_other_homolog_multi { my ($i, $j, $k, $i0, $j0, $k0); $id = shift; # real idx, not sorted idx my @hits = (); if (defined($blm8_data{$id})) { @hits = @{$blm8_data{$id}}; } my $rep_len = $lens[$id]; foreach $i (@hits) { my $id1 = $i->[0]; next unless ($id1 < $NR_no); next if ($idens[$id1] eq "*"); #existing reps next if ($lens[$id1] > $rep_len); # in opt_g=1 mode, preventing it from being clustered into short rep if ( $passeds[$id1] ) { #### if this hit is better -g 1 mode my $old_e = (split(/\//,$idens[$id1]))[0]; if ($i->[3] < $old_e) { $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; } next; } $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; $NR_passed++; } if (defined($blm8_data{$id})) { delete $blm8_data{$id}; } return; } ########## END fish_other_homolog_multi sub fish_other_homolog { my ($i, $j, $k, $i0, $j0, $k0); $id = shift; # real idx, not sorted idx my @hits = (); wait_blast_out("$bl_dir/$id.out"); open(BLPOUT, "$bl_dir/$id.out") || return; while($i=) { last if ($i =~ /^#/); chop($i); push(@hits, [split(/\t/,$i)]); } close(BLPOUT); my $rep_len = $lens[$id]; foreach $i (@hits) { my $id1 = $i->[0]; next unless ($id1 < $NR_no); next if ($idens[$id1] eq "*"); #existing reps next if ($lens[$id1] > $rep_len); # in opt_g=1 mode, preventing it from being clustered into short rep if ( $passeds[$id1] ) { #### if this hit is better -g 1 mode my $old_e = (split(/\//,$idens[$id1]))[0]; if ($i->[3] < $old_e) { $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; } next; } $idens[$id1] = "$i->[3]/$i->[2]aa/$i->[1]%"; $passeds[$id1] = 1; $NR_clstr_nos[$id1] = $NR90_no; $NR_passed++; } return; } ########## END fish_other_homolog ########### if a hit has multiple HSPs on both + - strands ########### keep only the HSPs, whose strand is same as the top HSP sub keep_strand_with_top_hsp { my $self = shift; my ($i,$j,$k); my %id_2_strand = (); my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); if (not defined($id_2_strand{$id1})) { $id_2_strand{$id1} = $p->{frame}; } if ($p->{frame} eq $id_2_strand{$id1}) { #### this stand is same as the top strand push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END keep_strand_with_top_hsp ########## for blastpgp -j no (no>1) ########## keep hits from the last round sub keep_hsp_of_last_round { my $self = shift; my ($i,$j,$k); my @new_sbj = (); my $new_no = 0; my $last_score = 9999999*9999999*9999999; # a big one for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my $score = $p->{score}; if ($score > $last_score) { ## this is new round of hits @new_sbj = (); $new_no = 0; } $last_score = $score; push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## END keep_hsp_of_last_round ########## if a query hit a subject with multiple HSPs ########## only the top HSP is kept sub keep_top_hsp { my $self = shift; my ($i,$j,$k); my %id_exist = (); my @new_sbj = (); my $new_no = 0; for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); next unless ($len_sub >0) ; if (not defined($id_exist{$id1})) { $id_exist{$id1} = 1; push(@new_sbj, $self->{sbj}->[$i]); $new_no++; } } $self->{no} = $new_no; $self->{sbj} = [@new_sbj]; } ########## keep_top_hsp ########## let the top hsp to start at 0 for both query and subject ########## i.e. the begining of HSP to be new original - coordinate 0 ########## then reset all other HSPs' alignment coordinates sub reset_alignment_coor_for_circle_seq { my $self = shift; my ($i,$j,$k); my $last_id = ""; $j = 0; my $hsp_count = 0; # number of HSPs for a subject for ($i=0; $i<$self->{no}; $i++) { my $p = $self->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); if ($id1 ne $last_id) { if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } $j = $i; $hsp_count = 0; } $last_id = $id1; $hsp_count++; } #last subject if ($hsp_count > 1) { # it is necessary to reset coordinate when at least 2 HSP my $p_top_hsp = $self->{sbj}->[$j]; my $len_q = (split(/\./, $p_top_hsp->{qid}))[1]; my $len_s = (split(/\./, $p_top_hsp->{id}))[1]; my $ref_q = ($p_top_hsp->{qfrom} < $p_top_hsp->{qend}) ? $p_top_hsp->{qfrom} : $p_top_hsp->{qend}; my $ref_s = ($p_top_hsp->{sfrom} < $p_top_hsp->{send}) ? $p_top_hsp->{sfrom} : $p_top_hsp->{send}; for ($k = $j; $k<$j+$hsp_count; $k++) { $self->{sbj}->[$k]->{qfrom} -= $ref_q; if ($self->{sbj}->[$k]->{qfrom} < 0) {$self->{sbj}->[$k]->{qfrom} += $len_q;} $self->{sbj}->[$k]->{qend} -= $ref_q; if ($self->{sbj}->[$k]->{qend} < 0) {$self->{sbj}->[$k]->{qend} += $len_q;} $self->{sbj}->[$k]->{sfrom} -= $ref_s; if ($self->{sbj}->[$k]->{sfrom} < 0) {$self->{sbj}->[$k]->{sfrom} += $len_s;} $self->{sbj}->[$k]->{send} -= $ref_s; if ($self->{sbj}->[$k]->{send} < 0) {$self->{sbj}->[$k]->{send} += $len_s;} } } return; } ########## reset_alignment_coor_for_circle_seq sub process_blout_blastp_blastn { my ($i, $j, $k, $i0, $j0, $k0); my $blout = shift; my @blhits = (); #### need $len_rep my $len_rep = 0; my $bl = defined($blout) ? readblast_m8("", $blout) : readblast_m8_buffer(); if ($blast_prog eq "blastn") { keep_strand_with_top_hsp($bl); } if (($blast_prog eq "blastpgp") and (not $prof_db)) {keep_hsp_of_last_round($bl); } if ($g_iden == 0 ) { #### Local identity keep_top_hsp($bl); #### local alignment, only the top HSP for ($i=0; $i<$bl->{no}; $i++) { my $p = $bl->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); my $frame = $p->{frame}; if (not $len_rep) {$len_rep = (split(/\./,$p->{qid}))[1]; } my $iden = $p->{iden}; next unless (($len_sub >0) and ($len_rep>0)); my $cov_aS = $p->{alnln} / $len_sub; my $cov_aL = $p->{alnln} / $len_rep; my $exp1 = $p->{expect}; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { push(@blhits, [$id1, $iden, $p->{alnln}, $exp1, $frame]); } } return @blhits; } #### END if ($g_iden == 0 ) else { #### Global idnetity if (($blast_prog eq "blastn") and $circle) { reset_alignment_coor_for_circle_seq($bl); } #### get colinear non-overlapping HSPs my @hsp = (); #### [id, len, qfrom, qend, sbegin, send, expect] my $iden_letters = 0; my $aln_letters = 0; my @aln_lens = (); my $hsp_no = 0; for ($i=0; $i<$bl->{no}; $i++) { my $p = $bl->{sbj}->[$i]; my ($id1, $len_sub) = split(/\./, $p->{id}); my $frame = $p->{frame}; if (not $len_rep) {$len_rep = (split(/\./,$p->{qid}))[1]; } next unless (($len_sub >0) and ($len_rep>0)); if ($hsp_no) { if ($id1 ne $hsp[0]->[0]) { #### 1. parse previous subject's HSPs my $iden = int($iden_letters / $hsp[0]->[1] * 10000)/100; my $cov_aS = $aln_letters / $hsp[0]->[1]; my $cov_aL = $aln_letters / $len_rep; my $exp1 = $hsp[0]->[6]; my $frame = $hsp[0]->[7]; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { #push(@blhits, [$hsp[0]->[0], $iden, $aln_letters, $exp1, $frame]); push(@blhits, [$hsp[0]->[0], $iden, join(":", @aln_lens), $exp1, $frame]); } #### 2. init some values @hsp = (); $iden_letters = 0; $aln_letters = 0; @aln_lens = (); $hsp_no = 0; } } #check whether overlap with previous high score HSPs my $overlap_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (overlap1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3])) { $overlap_flag = 1; last; } if (overlap1($p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $overlap_flag = 1; last; } } next if ($overlap_flag); #check whether this HSP cross with previous high score HSPs my $cross_flag = 0; for ($j=0; $j<$hsp_no; $j++) { if (cross1($p->{qfrom}, $p->{qend}, $hsp[$j]->[2], $hsp[$j]->[3], $p->{sfrom}, $p->{send}, $hsp[$j]->[4], $hsp[$j]->[5])) { $cross_flag = 1; last; } } next if ($cross_flag); push(@hsp, [$id1, $len_sub, $p->{qfrom}, $p->{qend}, $p->{sfrom}, $p->{send}, $p->{expect}, $p->{frame}]); $iden_letters += int($p->{iden} * $p->{alnln} / 100); $aln_letters += $p->{alnln}; push(@aln_lens, $p->{alnln}); $hsp_no++; } if ($hsp_no) { #last record #### 1. parse previous subject's HSPs my $iden = int($iden_letters / $hsp[0]->[1] * 10000)/100; my $cov_aS = $aln_letters / $hsp[0]->[1]; my $cov_aL = $aln_letters / $len_rep; my $exp1 = $hsp[0]->[6]; my $frame = $hsp[0]->[7]; if (($iden/100 > $NR_clstr or $exp1<$NR_clstre) and ($cov_aS >= $opt_aS) and ($cov_aL >= $opt_aL) ) { #push(@blhits, [$hsp[0]->[0], $iden, $aln_letters, $exp1, $frame]); push(@blhits, [$hsp[0]->[0], $iden, join(":", @aln_lens), $exp1, $frame]); } } return @blhits; } } ########## END process_blout_blastp_blastn sub overlap1 { my ($b1, $e1, $b2, $e2) = @_; my $t; ### if ($e1 < $b1) { $t = $e1; $e1 = $b1; $b1 = $t; } if ($e2 < $b2) { $t = $e2; $e2 = $b2; $b2 = $t; } return 0 if ($e2 < $b1); return 0 if ($b2 > $e1); return ( ($e1<$e2)? $e1:$e2 )-( ($b1>$b2)? $b1:$b2); } ########## END overlap1 ## modified on 2013_0818 to hancle +- frames sub cross1 { my ($q_b1, $q_e1, $q_b2, $q_e2, $s_b1, $s_e1, $s_b2, $s_e2) = @_; my $fr_q1 = ($q_b1 < $q_e1) ? 1 : -1; my $fr_q2 = ($q_b2 < $q_e2) ? 1 : -1; my $fr_s1 = ($s_b1 < $s_e1) ? 1 : -1; my $fr_s2 = ($s_b2 < $s_e2) ? 1 : -1; my $fr1 = $fr_q1 * $fr_s1; my $fr2 = $fr_q2 * $fr_s2; return 1 if (($fr1 * $fr2) < 0); # one ++ and one +- my $t; if ($q_e1 < $q_b1) { $t = $q_e1; $q_e1 = $q_b1; $q_b1 = $t; } if ($q_e2 < $q_b2) { $t = $q_e2; $q_e2 = $q_b2; $q_b2 = $t; } if ($s_e1 < $s_b1) { $t = $s_e1; $s_e1 = $s_b1; $s_b1 = $t; } if ($s_e2 < $s_b2) { $t = $s_e2; $s_e2 = $s_b2; $s_b2 = $t; } # after above transformation # 0 q_b1 q_e1 q_b2 q_e2 qlen # query 5' ==================================================================== # match |||||||||||||||| ||||||||||||| # subject 5' ========================================================================>>>>>> frame + # 0 s_b1 s_e1 s_b2 s_e2 slen # match |||||||||||||||| ||||||||||||| # subject 3' ========================================================================>>>>>> frame - # slen s_e1 s_b1 s_e2 s_b2 0 if (($fr1 > 0) and ($fr2>0)) { # both ++ return ( (($q_b2-$q_b1)*($s_b2-$s_b1) <0) ? 1 : 0); } else { # both -- return ( (($q_b2-$q_b1)*($s_e1-$s_e2) <0) ? 1 : 0); } } ########## END cross1 ## modified on 2013_0818 to hancle +- frames sub cross1_before_2013_0818 { my ($q_b1, $q_e1, $q_b2, $q_e2, $s_b1, $s_e1, $s_b2, $s_e2) = @_; my $t; if ($q_e1 < $q_b1) { $t = $q_e1; $q_e1 = $q_b1; $q_b1 = $t; } if ($q_e2 < $q_b2) { $t = $q_e2; $q_e2 = $q_b2; $q_b2 = $t; } if ($s_e1 < $s_b1) { $t = $s_e1; $s_e1 = $s_b1; $s_b1 = $t; } if ($s_e2 < $s_b2) { $t = $s_e2; $s_e2 = $s_b2; $s_b2 = $t; } return ( (($q_b2-$q_b1)*($s_b2-$s_b1) <0) ? 1 : 0); } ########## END cross1 sub readblast_m8_buffer { my ($i, $j, $k, $ll, $no); my @this_sbj = (); $no = 0; while($ll = shift @blm8_buffer) { chop($ll); my @lls = split(/\t/,$ll); my $frame = ""; $frame .= ($lls[6] < $lls[7]) ? "+" : "-"; $frame .= ($lls[8] < $lls[9]) ? "+" : "-"; next unless ($lls[0] and $lls[1]); $this_sbj[$no] = { 'qid' => $lls[0], 'id' => $lls[1], 'iden' => $lls[2], 'alnln' => $lls[3], 'ms' => $lls[4], 'gap' => $lls[5], 'qfrom' => $lls[6], 'qend' => $lls[7], 'sfrom' => $lls[8], 'send' => $lls[9], 'expect' => $lls[10], 'score' => $lls[11], 'frame' => $frame, }; $no++; # BLASTP 2.2.24 [Aug-08-2010] # Query: gi|388328107|pdb|4DDG|A Chain A, Crystal Structure Of Human Otub1UBCH5B~UBUB # Database: pdbaa.fa # Fields: Query id, Subject id, % identity, alignment length, mismatches, gap openings, q. start, q. end, s. start, s. end, e-value, bit score #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 91.81 171 9 3 6 171 1 171 6e-89 323 #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 96.51 86 3 0 235 320 155 240 2e-41 166 } my $self = { 'no' => $no, 'sbj' => [@this_sbj], }; return $self; } ########## END readblast_m8 sub readblast_m8 { my ($i, $j, $k, $ll, $no); my ($q_seq, $filename) = @_; my $fh = "BL" ; if ($bl_STDIN) { $fh = "STDIN"; } else { open($fh, $filename) || return; } my @this_sbj = (); $no = 0; while($ll = <$fh>) { chop($ll); my @lls = split(/\t/,$ll); my $frame = ""; $frame .= ($lls[6] < $lls[7]) ? "+" : "-"; $frame .= ($lls[8] < $lls[9]) ? "+" : "-"; next unless ($lls[0] and $lls[1]); $this_sbj[$no] = { 'qid' => $lls[0], 'id' => $lls[1], 'iden' => $lls[2], 'alnln' => $lls[3], 'ms' => $lls[4], 'gap' => $lls[5], 'qfrom' => $lls[6], 'qend' => $lls[7], 'sfrom' => $lls[8], 'send' => $lls[9], 'expect' => $lls[10], 'score' => $lls[11], 'frame' => $frame, }; $no++; # BLASTP 2.2.24 [Aug-08-2010] # Query: gi|388328107|pdb|4DDG|A Chain A, Crystal Structure Of Human Otub1UBCH5B~UBUB # Database: pdbaa.fa # Fields: Query id, Subject id, % identity, alignment length, mismatches, gap openings, q. start, q. end, s. start, s. end, e-value, bit score #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 91.81 171 9 3 6 171 1 171 6e-89 323 #gi|388328107|pdb|4DDG|A gi|388328107|pdb|4DDG|A 96.51 86 3 0 235 320 155 240 2e-41 166 } close($fh) if (not $bl_STDIN); my $self = { 'no' => $no, 'sbj' => [@this_sbj], }; return $self; } ########## END readblast_m8 sub blast_formatdb { my ($i0, $i, $j, $k, $len1); open(FDB, "> $tmp_db") || die; $j = 0; $len1 = 0; for ($i0=$NR_no-1; $i0>=0; $i0--) { ### from shortest to longest $i = $NR_idx[$i0]; last if ($idens[$i] eq "*"); ### last if reach rep next if ($lens[$i] < $opt_aL_lower_band); next if ($passeds[$i] and ($opt_g==0)); my $seq = $seqs[$i]; $seq =~ s/(.{70})/$1\n/g; $seq =~ s/\n$//; #print FDB ">$i $dess[$i]\n$seq\n"; print FDB ">$i.$lens[$i]\n$seq\n"; $j++; $len1 += $lens[$i]; } close(FDB); while(1) { opendir(SEQDB, $seq_dir) || next; my @leftseqs = grep {/lock/} readdir(SEQDB); closedir(SEQDB); last unless @leftseqs; sleep(3); } return(0, 0) unless ($j > 0); my $cmd_line = "$formatdb -i $tmp_db"; $cmd_line = "$formatdb -in $tmp_db" if ($bl_plus); my $cmd = `$cmd_line`; ((-e "$tmp_db.phr") and (-e "$tmp_db.pin") and (-e "$tmp_db.psq")) || ((-e "$tmp_db.nhr") and (-e "$tmp_db.nin") and (-e "$tmp_db.nsq")) || ((-e "$tmp_db.00.phr") and (-e "$tmp_db.00.pin") and (-e "$tmp_db.00.psq")) || ((-e "$tmp_db.00.nhr") and (-e "$tmp_db.00.nin") and (-e "$tmp_db.00.nsq")) || die "Can not formatdb"; return($j, $len1); } ########## END blast_formatdb sub remove_blast_db { my ($i, $j, $k); $cmd = `rm -f $tmp_db`; $cmd = `rm -f $tmp_db.p*`; $cmd = `rm -f $tmp_db.n*`; return; } ########## END remove_blast_db my $common_usage = <> << len 2 >> i.e. redundant <<<<<<<<<<<< length of short sequence >>>>>>>>>>>>>> sequence total identical letters from all co-linear and non-overlapping HSPs Glogal identity = ------------------------------------------------------------------- length of short sequence Local identity = identity of the top high score HSP if you prefer to use -G 0, it is suggested that you also use -aS, -aL, such as -aS 0.8, to prevent very short matches. -aL alignment coverage for the longer sequence, default $opt_aL if set to 0.9, the alignment must covers 90% of the sequence -aS alignment coverage for the shorter sequence, default $opt_aS if set to 0.9, the alignment must covers 90% of the sequence -g (1/0), default $opt_g by cd-hit's default algorithm, a sequence is clustered to the first cluster that meet the threshold (fast cluster). If set to 1, the program will cluster it into the most similar cluster that meet the threshold (accurate but slow mode) but either 1 or 0 won't change the representatives of final clusters -circle (1/0), default $circle when set to 1, treat sequences as circular sequence. bacterial genomes, plasmids are circular, but their genome coordinate maybe arbitary, the 2 HSPs below will be treated as non co-linear with -circle 0 the 2 HSPs below will be treated as co-linear with -circle 1 -------------circle----------- | | seq1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 1 \\\\\\\\\\\\\\\\ ///////////// \\\\\\\\\\\\\\\\ ///////////// HSP 2 -> ////HSP 1 /// <-HSP 2 ///////////// \\\\\\\\\\\\\\\\ ///////////// \\\\\\\\\\\\\\\\ seq2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx genome / plasmid 2 | | -----------circle-------------- -sl, length of very long sequences to be skipped, default $skip_long, e.g. -sl 5000 means sequences longer than 5000 aa will be treated as singleton clusters without clustering, to save time, especially when there is -aL option in place, very long sequences will not be clustered anyway. -sl 0 means no skipping program: -prog (blastp, blastn, megablast, blastpgp), default $blast_prog -p profile search para, default "$prof_para" -dprof database for building PSSM, default using input you can also use another database that is more comprehensive like NR80 -s blast search para, default "$bl_para" -bs (1/0) default $bl_STDIN pipe blast results from into parser instead of save in hard drive (save time) compute: -exec (qsub, local) default $exec_mode this program writes a shell script to run blast, this script is either performed locally by sh or remotely by qsub with qsub, you can use PBS, SGE etc -host number of qsub jobs, default $num_qsub -para number of parallel blast job per qsub job (each blast can use multi cores), default $para_no one qsub script can run multiple blast jobs -blp number of threads per blast job, default $bl_threads number of threads per blast job (option -blp) X number of parallel blast job per qsub job (option -para) should <= the number of cores in your computer if your computer grid has 32 cores / node, do either of the followings -para 4 -blp 8 -para 8 -blp 4 preferred -para 16 -blp 2 -para 32 -blp 1 -bat number of sequences a blast job to process, $batch_no_per_node -shf a filename for add local settings into the job shell script for example, when you run PBS jobs, you can add quene name etc in this file and this script will add them into the job shell script e.g. template file for PBS #!/bin/sh #PBS -v PATH #PBS -l walltime=8:00:00 #PBS -q job_queue.q e.g. template file for SGE or OGE #!/bin/sh #\$ -v PATH #\$ -q job_queue.q #\$ -V #\$ -pe orte 8 job: -rs steps of save restart file and clustering output, default $restart_seg everytime after process 5000 sequences, program write a restart file and current clustering information -restart restart file, readin a restart file if program crash, stoped, termitated, you can restart it by add a option "-restart sth.restart" -rf steps of re format blast database, default $reformat_seg if program clustered 200,000 seqs, it remove them from seq pool, and re format blast db to save time -J job, job_file, exe specific jobs like parse blast outonly DO NOT use it, it is only used by this program itself -k (1/0) keep blast raw output file, default $keep_bl -P path to blast executables EOD sub print_usage { print < 0); open(SEQ, "> $seq_dir/$id") || die "Can not write"; } #print SEQ "$dess[$id]\n$seq\n"; print SEQ ">$id.$lens[$id]\n$seq\n"; $k++; last if ($k >= $total_jobs); } close(SEQ); if ($exec_mode eq "qsub") { for ($j=0; $j<$num_qsub; $j++) { my $t = "psi-cd-hit-$j"; my $cmd = `qsub -N $t $remote_sh_script $j`; #### pass $j to qsub command my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} print LOG "qsub querying $j, PID $qsub_id\n"; $qsub_ids{$qsub_id} = 1; } } elsif ($exec_mode eq "local") { #my $cmd = `sh $remote_sh_script >/dev/null 2>&1 &`; my $cmd = `sh $remote_sh_script`; } #### wait finish all submitted if ($exec_mode eq "qsub") { while(1) { SGE_qstat_xml_query(); last unless (%qsub_ids); my $wait_flag = 0; foreach my $qsub_id (keys %qsub_ids) { if (defined($qstat_xml_data{$qsub_id})) { #### still running $wait_flag = 1; } else { delete $qsub_ids{$qsub_id}; } } if ($wait_flag) {print LOG "wait submitted jobs\n"; sleep(1); } } } #### read in all parsed blast output %blm8_data =(); opendir(BLMDIR, $blm_dir) || die "can not open $blm_dir"; my @bl_files = grep { /^\d/ } readdir(BLMDIR); closedir(BLMDIR); foreach my $blf (@bl_files) { open(BLMTMP, "$blm_dir/$blf") || next; while($ll = ) { next if ($ll =~ /^#/); chop($ll); if ($ll =~ /^>/) { my ($id, $no1) = split(/\s+/, substr($ll,1)); my @hits = (); for ($j=0; $j<$no1; $j++) { $ll=; chop($ll); push(@hits, [split(/\t/,$ll)]); } if ($no1>=1) { $blm8_data{$id} = [@hits]; } } } close(BLMTMP); $cmd = `rm -f $blm_dir/$blf`; print LOG "parse and then rm $blm_dir/$blf\n"; } return; } sub run_batch_blast3 { my $i0 = shift; my ($id, $i, $j, $k, $cmd); #### wait before qsubs if ($exec_mode eq "qsub") { while(1) { SGE_qstat_xml_query(); last unless (%qsub_ids); my $wait_flag = 0; foreach my $qsub_id (keys %qsub_ids) { if (defined($qstat_xml_data{$qsub_id})) { #### still running $wait_flag = 1; $cmd = `qdel -f $qsub_id`; #### at this point, all running jobs are not necessary, print LOG "force delete un necessary job $qsub_id\n"; } else { delete $qsub_ids{$qsub_id}; } } if ($wait_flag) {print LOG "wait submitted jobs\n"; sleep(1); } } #### delete seq files from last batch opendir(DIR1, $seq_dir); my @files = grep { /^\d/ } readdir(DIR1); closedir(DIR1); foreach $i (@files) { $cmd = `rm -f $seq_dir/$i`; print LOG "remove un necessary seq file $i\n" } } my $total_jobs = $batch_no_per_node * $num_qsub * $para_no; for ($k=0; $i0<$NR_no; $i0++) { $id = $NR_idx[$i0]; next if ($passeds[$id]); next if ($in_bg[$id]); next if ($lens[$id] < $opt_aL_upper_band); $in_bg[$id] = 1; my $seq = $seqs[$id]; open(SEQ, "> $seq_dir/$id") || die "Can not write"; #print SEQ "$dess[$id]\n$seq\n"; print SEQ ">$id.$lens[$id]\n$seq\n"; close(SEQ); $k++; last if ($k >= $total_jobs); } if ($exec_mode eq "qsub") { for ($j=0; $j<$num_qsub; $j++) { my $t = "psi-cd-hit-$j"; my $cmd = `qsub -N $t $remote_sh_script`; my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} print LOG "qsub querying $j, PID $qsub_id\n"; $qsub_ids{$qsub_id} = 1; } } elsif ($exec_mode eq "local") { #my $cmd = `sh $remote_sh_script >/dev/null 2>&1 &`; my $cmd = `sh $remote_sh_script`; } return; } ########## END run_batch_blast3 sub write_remote_sh_script { my ($i, $j, $k); my $local_sh = < $remote_sh_script") || die; print RESH < $remote_perl_script") || die; print REPERL <> $blm_dir/\$host.\$instance`; } elsif ($bl_STDIN) { \$cmd = `$bl2 $opti $seq_dir/\$id | $script_name -J parse_blout $bl_dir/\$id -c $NR_clstr -ce $NR_clstre -aS $opt_aS -aL $opt_aL -G $g_iden -prog $blast_prog -bs 1`; } else { \$cmd = `$bl2 $opti $seq_dir/\$id $opto $bl_dir/\$id`; \$cmd = `$script_name -J parse_blout $bl_dir/\$id -c $NR_clstr -ce $NR_clstre -aS $opt_aS -aL $opt_aL -G $g_iden -prog $blast_prog -bs 0`; } \$cmd = `rm -f $seq_dir/\$id`; \$cmd = `rm -f $seq_dir/\$id.lock`; } (\$tu, \$ts, \$cu, \$cs) = times(); \$tt = \$tu + \$ts + \$cu + \$cs; \$cmd = `echo \$tt >> $seq_dir/host.\$host.\$instance.cpu`; EOD close(REPERL); my $cmd = `chmod 755 $remote_perl_script`; return; } ########## END write_remote_perl_script sub wait_blast_out { my $out = shift; print LOG "waiting for $out"; while(1) { if (-e $out) { my $last = `tail -1 $out`; chop($last); last if ($last =~ /^#$/); } sleep(1); print LOG "."; } print LOG "\n"; return; } ########## END wait_blast_out sub SGE_qstat_xml_query { my ($i, $j, $k, $cmd, $ll); %qstat_xml_data = (); #### global $cmd = `qstat -f -xml`; if ($cmd =~ / all.q\@master BIP 0 0 0 0.08000 linux-x64 ... all.q\@node016 BIP 32 0 32 42.59000 linux-x64 ####### running jobs in this section 3535 0.51468 cd-hit ubuntu r 4 ... ######## pending jobs in this section 3784 0.60500 cd-hit ubuntu qw 32 ... EOD my @lls = split(/\n/, $cmd); $i = 2; #### skip first 2 lines for (; $i<$#lls+1; $i++) { if ($lls[$i] =~ /(\d+)/) { $id = $1;} if ($lls[$i] =~ /([^<]+)/) { $name = $1;} if ($lls[$i] =~ /([^<]+)/) {$state = $1;} } if (defined($id) and defined($name) and defined($state)) { $qstat_xml_data{$id} = [$name, $state]; } } } } 1; cdhit-4.6.8/psi-cd-hit/psi-cd-hit-old.pl000077500000000000000000000112261312257207200176450ustar00rootroot00000000000000#!/usr/bin/perl -w ################################################################################ ######### PSI-cd-hit written by Weizhong Li at http://cd-hit.org ################################################################################ our $script_name = $0; our $script_dir = $0; $script_dir =~ s/[^\/]+$//; $script_dir = "./" unless ($script_dir); require "$script_dir/psi-cd-hit-local-old.pl"; parse_para_etc(@ARGV); open_LOG(); our @seqs = (); our @dess = (); our @idens = (); our @lens = (); our @passeds = (); our @NR_clstr_nos = (); our @in_bg = (); our @NR_idx = (); our $NR_no = 0; our $DB_no = 0; our $DB_len = 0; our $DB_len0 = 0; our $DB_len_reduced = 0; our $DB_len_reduced2 = 0; #### for write_restart etc purpose our $opt_aL_upper_band = 0; #### sequences < this length will not be submitted unless reformatdb our $opt_al_upper_bandi= 0; our $opt_aL_lower_band = 0; #### sequences < this length don't need to be searched my ($i, $j, $k, $i0, $j0, $k0, $ll); read_db(); our $NR_passed = 0; our $formatdb_no = $NR_no;; @NR_idx = (0..($NR_no-1)); @NR_idx = sort { $lens[$b] <=> $lens[$a] } @NR_idx unless (-e $restart_in); our $NR90_no = 0; our @NR90_seq = (); $i0 = 0; if ( -e $restart_in) { $i0 = read_restart(); } ## restart after crash elsif ($skip_long > 0) { #### skip very long seqs for (; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; last if ($lens[$i] < $skip_long); $NR_passed++; $NR_clstr_nos[$i] = $NR90_no; $idens[$i] = "*"; $passeds[$i] = 1; $NR90_seq[$NR90_no] = [$i]; $NR90_no++; $DB_len_reduced += $lens[$i]; } } #### set init opt_aL_uppper/lower_bands if ( ($opt_aL > 0.3) ) { die ("option -aL > 1.0") if ($opt_aL > 1.0); #################### ################### ################## ################# ################ ############### <-upper band ############## <- seq below not submit, unless band change ############# ############ ########### ########## <- lower band ######### <- seq below not in format db ######## ####### ##### #### ### ## # my $total_jobs = $batch_no_per_node * $num_qsub * $para_no; my $space = ($total_jobs > $restart_seg) ? $total_jobs : $restart_seg; my $d1 = $i0+$space; $d1 = ($NR_no-1) if ($d1 >= $NR_no-1); $opt_aL_upper_band = $lens[ $NR_idx[$d1] ]; $opt_aL_lower_band = int($opt_aL_upper_band * $opt_aL); $opt_aL_upper_bandi= $d1; write_LOG("set opt_aL_band $opt_aL_upper_band($opt_aL_upper_bandi) $opt_aL_lower_band"); } ($DB_no, $DB_len) = blast_formatdb(); $DB_len0 = $DB_len; $DB_len_reduced = 0; $DB_len_reduced2 = 0; for (; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; run_batch_blast3($i0) unless ($in_bg[$i] or (-e "$bl_dir/$i.out") or $passeds[$i]); if ( not $passeds[$i] ) { # this is a new representative $NR_passed++; $NR_clstr_nos[$i] = $NR90_no; $idens[$i] = "*"; $passeds[$i] = 1; $NR90_seq[$NR90_no] = [$i]; fish_other_homolog($i); $NR90_no++; $DB_len_reduced += $lens[$i]; $DB_len_reduced2 += $lens[$i]; } watch_progress($i0, $NR90_no, $NR_passed, $NR_no, 0); if ((($i0+1) % $restart_seg == 0) or ($DB_len_reduced2 > $DB_len0/10) ) { write_restart(); write_db_clstr(); remove_raw_blout_bg($i0); $DB_len_reduced2 = 0; } my $opt_aL_format_flag = 0; if ( ($opt_aL > 0.3) ) { #### formatdb maybe needed if current length of seq.i0 close to opt_aL_upper_band my $total_jobs = $batch_no_per_node * $num_qsub * $para_no; if ( ($opt_aL_upper_bandi - $i0) < $total_jobs ) { #### seqs left for possible submission < total_jobs my $space = ($total_jobs > $restart_seg) ? $total_jobs : $restart_seg; my $d1 = $i0+$space; $d1 = ($NR_no-1) if ($d1 >= $NR_no-1); $opt_aL_upper_band = $lens[ $NR_idx[$d1] ]; $opt_aL_lower_band = int($opt_aL_upper_band * $opt_aL); $opt_aL_upper_bandi= $d1; $opt_aL_format_flag = 1; write_LOG("set opt_aL_band $opt_aL_upper_band($opt_aL_upper_bandi) $opt_aL_lower_band"); } } if ((($i0+1) % (int($NR_no/10)) == 0) or ($DB_len_reduced > $DB_len/10) or $opt_aL_format_flag ) { ($DB_no, $DB_len) = blast_formatdb(); $DB_len_reduced = 0; } #if ($formatdb_no - ($NR_no-$NR_passed) >= $reformat_seg) {blast_formatdb(); } } ## END for ($i=0; $i<$NR_no; $i++) watch_progress($NR_no-1, $NR90_no, $NR_passed, $NR_no, 1); if (1) { ### print NR db open(DBOUT, "> $db_out") || die "Can not write $db_out"; for ($i=0; $i<$NR_no; $i++) { next unless ($idens[$i] eq "*"); my $seq = $seqs[$i]; $seq =~ s/(.{70})/$1\n/g; $seq =~ s/\n$//; print DBOUT "$dess[$i]\n$seq\n"; } close(DBOUT); } write_restart(); write_db_clstr(); remove_blast_db(); close_LOG(); cdhit-4.6.8/psi-cd-hit/psi-cd-hit.pl000077500000000000000000000113011312257207200170630ustar00rootroot00000000000000#!/usr/bin/perl -w ################################################################################ ######### PSI-cd-hit written by Weizhong Li at http://cd-hit.org ################################################################################ our $script_name = $0; our $script_dir = $0; $script_dir =~ s/[^\/]+$//; $script_dir = "./" unless ($script_dir); require "$script_dir/psi-cd-hit-local.pl"; parse_para_etc(@ARGV); open_LOG(); our @seqs = (); our @dess = (); our @idens = (); our @lens = (); our @passeds = (); our @NR_clstr_nos = (); our @in_bg = (); our @NR_idx = (); our $NR_no = 0; our $DB_no = 0; our $DB_len = 0; our $DB_len0 = 0; our $DB_len_reduced = 0; our $DB_len_reduced2 = 0; #### for write_restart etc purpose our $opt_aL_upper_band = 0; #### sequences < this length will not be submitted unless reformatdb our $opt_al_upper_bandi= 0; our $opt_aL_lower_band = 0; #### sequences < this length don't need to be searched my ($i, $j, $k, $i0, $j0, $k0, $ll); read_db(); our $NR_passed = 0; our $formatdb_no = $NR_no;; @NR_idx = (0..($NR_no-1)); @NR_idx = sort { $lens[$b] <=> $lens[$a] } @NR_idx unless (-e $restart_in); our $NR90_no = 0; our @NR90_seq = (); $i0 = 0; if ( -e $restart_in) { $i0 = read_restart(); } ## restart after crash elsif ($skip_long > 0) { #### skip very long seqs for (; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; last if ($lens[$i] < $skip_long); $NR_passed++; $NR_clstr_nos[$i] = $NR90_no; $idens[$i] = "*"; $passeds[$i] = 1; $NR90_seq[$NR90_no] = [$i]; $NR90_no++; $DB_len_reduced += $lens[$i]; } } #### set init opt_aL_uppper/lower_bands if ( ($opt_aL > 0.3) ) { die ("option -aL > 1.0") if ($opt_aL > 1.0); #################### ################### ################## ################# ################ ############### <-upper band ############## <- seq below not submit, unless band change ############# ############ ########### ########## <- lower band ######### <- seq below not in format db ######## ####### ##### #### ### ## # my $total_jobs = $batch_no_per_node * $num_qsub * $para_no; my $space = ($total_jobs > $restart_seg) ? $total_jobs : $restart_seg; my $d1 = $i0+$space; $d1 = ($NR_no-1) if ($d1 >= $NR_no-1); $opt_aL_upper_band = $lens[ $NR_idx[$d1] ]; $opt_aL_lower_band = int($opt_aL_upper_band * $opt_aL); $opt_aL_upper_bandi= $d1; write_LOG("set opt_aL_band $opt_aL_upper_band($opt_aL_upper_bandi) $opt_aL_lower_band"); } ($DB_no, $DB_len) = blast_formatdb(); $DB_len0 = $DB_len; $DB_len_reduced = 0; $DB_len_reduced2 = 0; for (; $i0<$NR_no; $i0++) { $i = $NR_idx[$i0]; run_batch_blast3_multi($i0) unless ($in_bg[$i] or (-e "$bl_dir/$i.out") or $passeds[$i]); if ( not $passeds[$i] ) { # this is a new representative $NR_passed++; $NR_clstr_nos[$i] = $NR90_no; $idens[$i] = "*"; $passeds[$i] = 1; $NR90_seq[$NR90_no] = [$i]; fish_other_homolog_multi($i); $NR90_no++; $DB_len_reduced += $lens[$i]; $DB_len_reduced2 += $lens[$i]; } watch_progress($i0, $NR90_no, $NR_passed, $NR_no, 0); if (($i0+1) % $restart_seg == 0 ) { write_restart(); write_db_clstr(); } my $opt_aL_format_flag = 0; if ( ($opt_aL > 0.3) ) { #### formatdb maybe needed if current length of seq.i0 close to opt_aL_upper_band my $total_jobs = $batch_no_per_node * $num_qsub * $para_no; my $opt_aL_upper_band_old = $opt_aL_upper_band; if ( ($opt_aL_upper_bandi - $i0) < $total_jobs ) { #### seqs left for possible submission < total_jobs my $space = ($total_jobs > $restart_seg) ? $total_jobs : $restart_seg; my $d1 = $i0+$space; $d1 = ($NR_no-1) if ($d1 >= $NR_no-1); $opt_aL_upper_band = $lens[ $NR_idx[$d1] ]; if ($opt_aL_upper_band < $opt_aL_upper_band_old) { $opt_aL_lower_band = int($opt_aL_upper_band * $opt_aL); $opt_aL_upper_bandi= $d1; $opt_aL_format_flag = 1; write_LOG("set opt_aL_band $opt_aL_upper_band($opt_aL_upper_bandi) $opt_aL_lower_band"); } } } if ((($i0+1) % (int($NR_no/10)) == 0) or ($DB_len_reduced > $DB_len/10) or $opt_aL_format_flag ) { ($DB_no, $DB_len) = blast_formatdb(); $DB_len_reduced = 0; } #if ($formatdb_no - ($NR_no-$NR_passed) >= $reformat_seg) {blast_formatdb(); } } ## END for ($i=0; $i<$NR_no; $i++) watch_progress($NR_no-1, $NR90_no, $NR_passed, $NR_no, 1); if (1) { ### print NR db open(DBOUT, "> $db_out") || die "Can not write $db_out"; for ($i=0; $i<$NR_no; $i++) { next unless ($idens[$i] eq "*"); my $seq = $seqs[$i]; $seq =~ s/(.{70})/$1\n/g; $seq =~ s/\n$//; print DBOUT "$dess[$i]\n$seq\n"; } close(DBOUT); } write_restart(); write_db_clstr(); remove_blast_db(); close_LOG(); cdhit-4.6.8/psi-cd-hit/qsub-template000066400000000000000000000001731312257207200172750ustar00rootroot00000000000000 #\$ -S /bin/bash #\$ -v PATH #PBS -v PATH #PBS -l walltime=8:00:00 #PBS -M liwz\@sdsc.edu #PBS -A camera ## PBS -qsmall cdhit-4.6.8/usecases/000077500000000000000000000000001312257207200144405ustar00rootroot00000000000000cdhit-4.6.8/usecases/Miseq-16S/000077500000000000000000000000001312257207200160655ustar00rootroot00000000000000cdhit-4.6.8/usecases/Miseq-16S/16S-ref-db-PE-splice.pl000077500000000000000000000334241312257207200217200ustar00rootroot00000000000000#!/usr/bin/perl ## =========================== NGS tools ========================================== ## NGS tools for metagenomic sequence analysis ## May also be used for other type NGS data analysis ## ## Weizhong Li, UCSD ## liwz@sdsc.edu ## http://weizhongli-lab.org/ ## ================================================================================ my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; chop($script_dir); $script_dir = "./" unless ($script_dir); use Getopt::Std; getopts("i:j:o:r:e:p:q:c:d:N:t:u:d:M:T:S:",\%opts); die usage() unless ($opts{i} and $opts{j} and $opts{o} and $opts{d}); my ($i, $j, $k, $cmd); my ($ll, $lla, $llb, $id, $ida, $idb, $seq, $seqa, $seqb, $qua, $quaa, $quab); my ($len, $lena, $lenb); my $fastq = $opts{i}; my $fastq2 = $opts{j}; my $ref = $opts{d}; my $output = $opts{o}; my $trim_R1 = $opts{p}; $trim_R1 = 100 unless ($trim_R1); my $trim_R2 = $opts{q}; $trim_R2 = 100 unless ($trim_R2); my $clstr_cutoff = $opts{c}; #### post clustering my $full_frag = $opts{S}; my $prime_len = 45; my $output_R1 = "$output-R1"; my $output_R2 = "$output-R2"; my $session = "OTU-session-$$"; my $output_S = "$output-single"; my $consensus_db = "$output-consensus"; my $cd_hit_2d = "$script_dir/../../cd-hit-est-2d"; die "no $cd_hit_2d" unless (-e $cd_hit_2d); my $cd_hit_est = "$script_dir/../../cd-hit-est"; die "no $cd_hit_est" unless (-e $cd_hit_est); my $format = input_test($fastq); #fasta or fastq my $cdhit_opt_M = $opts{M}; $cdhit_opt_M = 16000 unless defined($cdhit_opt_M); if (defined($clstr_cutoff)) { die "Clustering cutoff $clstr_cutoff is not reasonable, should be <=1.0 and >= 0.97" unless (($clstr_cutoff <=1.0) and ($clstr_cutoff>=0.97)); } my %FHZ=(); my %ref_map = (); foreach my $f (($fastq, $fastq2)) { my $R = ( $f eq $fastq ) ? "R1" : "R2"; open(OUT, "> $consensus_db.$R") || die "can not write to $consensus_db.$R"; my %con = (); my $num_seq = 0; open_files_z_safe("TTTa", $f); if ($format eq "fastq") { while(1) { ($lla, $ida, $seqa, $quaa, $lena) = read_next_fastq("TTTa"); last unless ($lla); for ($i=0; $i<$prime_len; $i++) { $c=uc(substr($seqa, $i, 1)); $con{$i}{$c}++; } $num_seq++; } } else { #### fasta my $seqa = ""; while($ll = ) { if ($ll =~ /^>/) { if ($seqa) { for ($i=0; $i<$prime_len; $i++) { $c=uc(substr($seqa, $i, 1)); $con{$i}{$c}++; } $num_seq++; } chop($ll); $seqa = ""; } else { chop($ll); $seqa .= $ll; } } if ($seqa) { for ($i=0; $i<$prime_len; $i++) { $c=uc(substr($seqa, $i, 1)); $con{$i}{$c}++; } $num_seq++; } } #### END fasta close(TTTa); my @cons = (); #which letter my @cons_v = (); #abundance for ($i=0; $i<$prime_len; $i++) { my %t = %{ $con{$i} }; my @k = keys %t; @k = sort { $t{$b} <=> $t{$a} } @k; push(@cons, $k[0]); push(@cons_v, $t{ $k[0] } / $num_seq); } ## set minimal consensus to be 30 for ($i=33; $i<$prime_len; $i++) { if ( ($cons_v[$i ] <0.75) and ($cons_v[$i-1] <0.75) and ($cons_v[$i-2] <0.75) ) { $i = $i-2; last; } } my $trim_len_new = $i; print OUT ">$R\n"; for ($i=0; $i<$trim_len_new; $i++) { print OUT $cons[$i]; } print OUT "\n"; close(OUT); my $cmd_line = "$cd_hit_2d -i $consensus_db.$R -i2 $ref -d 0 -c 0.8 -n 5 -r 1 -p 1 -b 5 -o $session.$R-vs-ref -G 0 -A 30 -s2 0.01 -M $cdhit_opt_M > $session.$R-vs-ref.log"; print "running $cmd_line\n"; $cmd = `$cmd_line`; my $parse_template=<Cluster 0 0 45nt, >R1... * 1 1479nt, >1111882... at 1:42:4:45/+/95.24% 2 1500nt, >1111856... at 1:42:4:45/+/88.10% 3 1426nt, >1111848... at 2:44:3:45/+/90.70% 4 1530nt, >1111847... at 1:42:4:45/+/85.71% 5 1497nt, >1111839... at 1:41:5:45/+/85.37% 6 1492nt, >1111819... at 1:42:4:45/+/88.10% 7 1482nt, >1111782... at 1:42:4:45/+/88.10% 8 1496nt, >1111776... at 1:42:4:45/+/88.10% 9 1500nt, >1111768... at 1:42:4:45/+/85.71% ... >Cluster 0 0 45nt, >R2... * 1 1428nt, >1111883... at 483:440:2:45/-/84.09% 2 1479nt, >1111882... at 511:468:2:45/-/88.64% 3 1336nt, >1111879... at 435:399:2:38/-/86.49% 4 1402nt, >1111874... at 469:426:2:45/-/84.09% 5 1500nt, >1111856... at 513:470:2:45/-/84.09% 6 1530nt, >1111847... at 532:489:2:45/-/86.36% 7 1497nt, >1111839... at 509:473:2:38/-/86.49% 8 1492nt, >1111819... at 514:471:2:45/-/88.64% 9 1482nt, >1111782... at 502:464:2:40/-/84.62% 10 1496nt, >1111776... at 516:473:2:45/-/84.09% EOD open(TMP, "$session.$R-vs-ref.clstr") || die "can not open $session.$R-vs-ref.clstr"; while($ll=){ next if ($ll =~ /^>/); next if ($ll =~ /^0/); chop($ll); if ($ll =~ /^\d+\s+\d+(aa|nt), >(.+)\.\.\./) { my $id = $2; my @lls = split(/\s+/, $ll); my @lls = split(/\//, $lls[-1]); ##516:473:2:45/-/84.09% my ($query_start, $query_end, $rep_star, $rep_end) = split(/:/, $lls[0]); $ref_map{$id}{$R}=[$query_start, $query_end, $rep_star, $rep_end, $lls[1]]; } } close(TMP); } my %ref_cut; foreach $id (keys %ref_map) { next unless (defined $ref_map{$id}{"R1"}); next unless (defined $ref_map{$id}{"R2"}); my @R1_info = @{$ref_map{$id}{"R1"}}; my @R2_info = @{$ref_map{$id}{"R2"}}; next unless ($R1_info[4] eq "+"); next unless ($R2_info[4] eq "-"); my $p1 = $R1_info[0] - ($R1_info[2]-1); #### 1-based, can be -1 value for V1 my $p2 = $R2_info[0] + ($R2_info[2]-1); #### 1-based, can be longer than len($seq) $ref_cut{$id} = [$p1, $p2]; } open(TMP, $ref) || die "can not open $ref"; open(OUT1, "> $output_R1") || die "can not write to $output_R1"; open(OUT2, "> $output_R2") || die "can not write to $output_R2"; if ($full_frag) { open(OUT3, "> $output_S") || die "can not write to $output_S"; } my $seq; my $des; $id = ""; while($ll = ) { if ($ll =~ /^>/) { if ($seq) { if ($ref_cut{$id}) { $seq =~ s/\s//g; my ($p1, $p2) = @{$ref_cut{$id}}; my $len = length($seq); my $seq1 = ""; my $seq2 = ""; if ($p1>=1) { $seq1 = substr($seq, $p1-1, $trim_R1); } else { my $pad = 1 - $p1; #### add NNN at 5' $seq1 = "N" x $pad; $seq1 .= substr($seq, 0, $trim_R1-$pad); } if ($p2 <= $len) { my $p2a = $p2 - $trim_R2; #### 0 - based substr idx if ($p2a < 0) { #### not long enough $seq2 = substr($seq, 0, $p2); } else { $seq2 = substr($seq, $p2a, $trim_R2); } } else { #### add NNN at 5' my $pad = $p2 - $len; my $trim_t2_t = $trim_R2 - $pad; $seq2 = "N" x $pad; my $p2a = $len - $trim_R2_t; #### 0 - based substr idx if ($p2a < 0) { #### not long enough $seq2.= $seq; } else { $seq2 .= substr($seq, $p2a, $trim_R2_t); } } $seq2 = reverse_complement($seq2); ### now have $seq1 $seq2 print OUT1 "$des loc=$p1 len=", length($seq1), "\n$seq1\n"; print OUT2 "$des loc=$p2 len=", length($seq2), "\n$seq2\n"; if ($full_frag) { if ($p1 < 1 ) {$p1 = 1; } if ($p2 > $len) {$p2 = $len;} my $eff_len = $p2-$p1+1; my $seq1 = substr($seq, $p1-1, $eff_len); print OUT3 "$des loc=$p1:$p2 len=$eff_len\n$seq1\n"; } } } chop($ll); $des = $ll; $id = substr($ll,1); $id =~ s/\s.+$//; $seq = ""; } else { $seq .= $ll; } } if ($seq) { if ($ref_cut{$id}) { $seq =~ s/\s//g; my ($p1, $p2) = @{$ref_cut{$id}}; my $len = length($seq); my $seq1 = ""; my $seq2 = ""; if ($p1>=1) { $seq1 = substr($seq, $p1-1, $trim_R1); } else { my $pad = 1 - $p1; #### add NNN at 5' $seq1 = "N" x $pad; $seq1 .= substr($seq, 0, $trim_R1-$pad); } if ($p2 <= $len) { my $p2a = $p2 - $trim_R2; #### 0 - based substr idx if ($p2a < 0) { #### not long enough $seq2 = substr($seq, 0, $p2); } else { $seq2 = substr($seq, $p2a, $trim_R2); } } else { #### add NNN at 5' my $pad = $p2 - $len; my $trim_t2_t = $trim_R2 - $pad; $seq2 = "N" x $pad; my $p2a = $len - $trim_R2_t; #### 0 - based substr idx if ($p2a < 0) { #### not long enough $seq2.= $seq; } else { $seq2 .= substr($seq, $p2a, $trim_R2_t); } } $seq2 = reverse_complement($seq2); ### now have $seq1 $seq2 print OUT1 "$des loc=$p1 len=", length($seq1), "\n$seq1\n"; print OUT2 "$des loc=$p2 len=", length($seq2), "\n$seq2\n"; if ($full_frag) { if ($p1 < 1 ) {$p1 = 1; } if ($p2 > $len) {$p2 = $len;} my $eff_len = $p2-$p1+1; my $seq1 = substr($seq, $p1-1, $eff_len); print OUT3 "$des loc=$p1:$p2 len=$eff_len\n$seq1\n"; } } } close(OUT1); close(OUT2); if ($full_frag) { close(OUT3); } close(TMP); if (defined($clstr_cutoff)) { my $output_R1_tmp = "$output_R1.$$"; my $output_R2_tmp = "$output_R2.$$"; my $cmd_line = "$cd_hit_est -i $output_R1 -j $output_R2 -d 0 -c $clstr_cutoff -n 10 -p 1 -b 5" . " -o $output_R1_tmp -op $output_R2_tmp -G 1 -g 1 -M $cdhit_opt_M -P 1 -l 11 -sc 1 > $output_R1_tmp.log"; print "running $cmd_line\n"; $cmd = `$cmd_line`; die "Can not run $cd_hit_est" unless (-e "$output_R1_tmp.clstr"); $cmd = `mv $output_R1_tmp $output_R1`; $cmd = `mv $output_R2_tmp $output_R2`; $cmd = `mv $output_R1_tmp.clstr $output.clstr`; if ($full_frag) { my $output_S_tmp = "$output_S.$$"; my $cmd_line = "$cd_hit_est -i $output_S -d 0 -c $clstr_cutoff -n 10 -p 1 -b 5" . " -o $output_S_tmp -G 1 -g 1 -M $cdhit_opt_M -l 11 -sc 1 > $output_S_tmp.log"; print "running $cmd_line\n"; $cmd = `$cmd_line`; die "Can not run $cd_hit_est" unless (-e "$output_S_tmp.clstr"); $cmd = `mv $output_S_tmp $output_S`; $cmd = `mv $output_S_tmp.clstr $output_S.clstr`; } } $cmd = `rm -f $session*`; # need %FHZ # open one or more files including zipped files # above open_files_z may have broken pipe problem # so this safe sub, open each file individually sub open_files_z_safe { my ($fh, @files) = @_; my ($i, $j, $k); my $no = $#files+1; $FHZ{$fh} = { 'files' => [@files], 'no' => $no, 'open_idx' => 0, }; my $f0 = $files[0]; if ($f0 =~ /\.gz$/ ) { open($fh, "gunzip -c $f0 |") || die "can not gunzip -c $f0\n"; } elsif ($f0 =~ /\.bz2$/) { open($fh, "bzcat $f0 |") || die "can not bzcat $f0\n"; } else { open($fh, $f0 ) || die "can not open $f0\n"; } return 0; } ########## END open_files_z_safe sub read_FHZ { my $fh = shift; my $ll; $ll = <$fh>; if ($ll) { return $ll;} ##### read from existing opened file #otherwise, last opened file reaches EOF if ($FHZ{$fh}->{open_idx} < $FHZ{$fh}->{no} -1 ) { ### still file not opened yet close($fh); #### close last open file $FHZ{$fh}->{open_idx}++; my $f0 = $FHZ{$fh}->{files}->[ $FHZ{$fh}->{open_idx} ]; if ($f0 =~ /\.gz$/ ) { open($fh, "gunzip -c $f0 |") || die "can not gunzip -c $f0\n"; } elsif ($f0 =~ /\.bz2$/) { open($fh, "bzcat $f0 |") || die "can not bzcat $f0\n"; } else { open($fh, $f0 ) || die "can not open $f0\n"; } $ll = <$fh>; return $ll; } else { #### no more file to open, return undef return undef; } } ########### END read_FHZ ########## read_next_fastq sub read_next_fastq { my $fh = shift; my ($lla, $seqa, $lla2, $quaa, $ida, $lena); $lla = read_FHZ($fh); return unless ($lla); chop($lla); $lla =~ s/\s.+$//; $ida = substr($lla,1); $seqa = read_FHZ($fh); $seqa =~ s/\s+$//g; $lena = length($seqa); $lla2 = read_FHZ($fh); #read ID $quaa = read_FHZ($fh); $quaa =~ s/\s+$//g; return ($lla, $ida, $seqa, $quaa, $lena); } ########## END read_next_fastq sub reverse_complement { my ($in_seq) = @_; my $opposite = reverse $in_seq; $opposite =~ tr/ACGT/TGCA/; return("$opposite"); } sub input_test { my $f = shift; open(TTT, $f) || die "can not open $f\n"; my $ll = ; close(TTT); my $c = substr($ll,0,1); if ($c eq ">") {return "fasta";} else {return "fastq";} } ########## END input_test sub usage { < "qsub-pe", "cores_per_node" => 8, "number_nodes" => 64, "user" => "weizhong", #### I will use command such as qstat -u weizhong to query submitted jobs "command" => "qsub", "command_name_opt" => "-N", "command_err_opt" => "-e", "command_out_opt" => "-o", "template" => < "sh", "cores_per_node" => 8, "number_nodes" => 1, }; $NGS_batch_jobs{"qc"} = { "CMD_opts" => ["100"], "execution" => "sh_1", # where to execute "cores_per_cmd" => 4, # number of threads used by command below "no_parallel" => 1, # number of total jobs to run using command below "command" => <\\SELF/qc.stdout 2>\\SELF/qc.stderr perl -e '\$i=0; while(<>){ if (/^\@/) {\$i++; print ">Sample|\\SAMPLE|\$i ", substr(\$_,1); \$a=<>; print \$a; \$a=<>; \$a=<>;}}' < \\SELF/R1.fq > \\SELF/R1.fa & perl -e '\$i=0; while(<>){ if (/^\@/) {\$i++; print ">Sample|\\SAMPLE|\$i ", substr(\$_,1); \$a=<>; print \$a; \$a=<>; \$a=<>;}}' < \\SELF/R2.fq > \\SELF/R2.fa & wait rm -f \\SELF/R1.fq \\SELF/R2.fq \\SELF/R1-s.fq \\SELF/R2-s.fq EOD }; $NGS_batch_jobs{"otu"} = { "injobs" => ["qc"], "CMD_opts" => ["150", "100", "0.97", "0.0001", "path_to_spliced_ref_db-R1", "path_to_spliced_ref_db-R1", "75"], "execution" => "sh_1", # where to execute "cores_per_cmd" => 2, # number of threads used by command below "no_parallel" => 1, # number of total jobs to run using command below "command" => < \\SELF/seq.nr.log #### cluster at 99% PE and SE for R1,R2 $CD_HIT_dir/cd-hit-est -i \\SELF/seq.nr -o \\SELF/seq.chimeric-clstr.R1 -r 0 -cx \\CMDOPTS.6 -c 0.99 -n 10 -G 0 -b 1 -A 50 -T 1 -M 8000 -d 0 -p 1 > \\SELF/seq.chimeric-clstr.R1.log $CD_HIT_dir/cd-hit-est -i \\SELF/seq.nr.2 -o \\SELF/seq.chimeric-clstr.R2 -r 0 -cx \\CMDOPTS.6 -c 0.99 -n 10 -G 0 -b 1 -A 50 -T 1 -M 8000 -d 0 -p 1 > \\SELF/seq.chimeric-clstr.R2.log $CD_HIT_dir/cd-hit-est -i \\SELF/seq.nr -j \\SELF/seq.nr.2 -o \\SELF/seq.99 -op \\SELF/seq.99.2 -P 1 -r 0 \\ -cx \\CMDOPTS.0 -cy \\CMDOPTS.1 -c 0.99 -n 10 -G 1 -b 1 -T 1 -M 8000 -d 0 -p 1 > \\SELF/seq.99.log $CD_HIT_dir/usecases/Miseq-16S/filter-chimeric-and-small.pl -c \\CMDOPTS.3 -k \\SELF/seq.nr.clstr \\ -i \\SELF/seq.chimeric-clstr.R1.clstr -j \\SELF/seq.chimeric-clstr.R2.clstr \\ -a \\SELF/seq.99.clstr -f \\SELF/seq.99 -g \\SELF/seq.99.2 -o \\SELF/seq.99f $CD_HIT_dir/clstr_rev.pl \\SELF/seq.nr.clstr \\SELF/seq.99f.clstr > \\SELF/seq.99f-all.clstr $CD_HIT_dir/cd-hit-est -i \\SELF/seq.99f -j \\SELF/seq.99f.2 -o \\SELF/seq.97 -op \\SELF/seq.97.2 -P 1 -r 0 \\ -cx \\CMDOPTS.0 -cy \\CMDOPTS.1 -c 0.97 -n 10 -G 1 -b 10 -T 1 -M 8000 -d 0 -p 1 > \\SELF/seq.97.log $CD_HIT_dir/cd-hit-est-2d -i \\SELF/seq.97 -j \\SELF/seq.97.2 -i2 \\CMDOPTS.4 -j2 \\CMDOPTS.5 -o \\SELF/seq.97.ref -op \\SELF/seq.97.ref.2 -P 1 -r 0 \\ -cx \\CMDOPTS.0 -cy \\CMDOPTS.1 -c 0.97 -n 10 -G 1 -b 10 -T 1 -M 8000 -d 0 -p 1 > \\SELF/seq.97.ref.log $CD_HIT_dir/clstr_rev.pl \\SELF/seq.99f-all.clstr \\SELF/seq.97.clstr > \\SELF/seq.97-all.clstr $CD_HIT_dir/usecases/Miseq-16S/filter-nontop-ref.pl < \\SELF/seq.97.ref.clstr > \\SELF/seq.97.reftop.clstr $CD_HIT_dir/clstr_merge.pl \\SELF/seq.97-all.clstr \\SELF/seq.97.reftop.clstr > \\SELF/OTU.clstr rm -f \\SELF/seq.chimeric-clstr.R1 \\SELF/seq.chimeric-clstr.R1.log \\SELF/seq.chimeric-clstr.R2 \\SELF/seq.chimeric-clstr.R2.log rm -f \\SELF/seq.97.ref \\SELF/seq.97.ref.2 \\SELF/seq.97.ref.log mv \\SELF/seq.99f.log \\SELF/chimeric-small-clusters-list.txt EOD }; $NGS_batch_jobs{"otu-pooled"} = { "CMD_opts" => ["150", "100", "0.97", "0.0001", "path_to_spliced_ref_db-R1", "path_to_spliced_ref_db-R1", "75"], "execution" => "sh_1", # where to execute "cores_per_cmd" => 2, # number of threads used by command below "no_parallel" => 1, # number of total jobs to run using command below "command" => < seq.97.log $CD_HIT_dir/cd-hit-est-2d -i seq.97 -j seq.97.2 -i2 \\CMDOPTS.4 -j2 \\CMDOPTS.5 -o seq.97.ref -op seq.97.ref.2 -P 1 -r 0 \\ -cx \\CMDOPTS.0 -cy \\CMDOPTS.1 -c 0.97 -n 10 -G 1 -b 10 -T 1 -M 8000 -d 0 -p 1 > seq.97.ref.log $CD_HIT_dir/clstr_rev.pl seq.99f-all.clstr seq.97.clstr > seq.97-all.clstr $CD_HIT_dir/usecases/Miseq-16S/filter-nontop-ref.pl < seq.97.ref.clstr > seq.97.reftop.clstr $CD_HIT_dir/clstr_merge.pl seq.97-all.clstr seq.97.reftop.clstr > OTU.clstr $CD_HIT_dir/usecases/clstr_2_OTU_table.pl -i OTU.clstr -o OTU.txt rm -f seq.97.ref seq.97.ref.2 seq.97.ref.log EOD }; ############################################################################################## ########## END 1; cdhit-4.6.8/usecases/Miseq-16S/NG-Omics-WF.pl000077500000000000000000001323311312257207200203160ustar00rootroot00000000000000#!/usr/bin/perl # =============================== NG-Omics-WF ================================== # _ _ _____ ____ _ __ ________ # | \ | |/ ____| / __ \ (_) \ \ / / ____| # | \| | | __ ______| | | |_ __ ___ _ ___ ___ _____\ \ /\ / /| |__ # | . ` | | |_ |______| | | | '_ ` _ \| |/ __/ __|______\ \/ \/ / | __| # | |\ | |__| | | |__| | | | | | | | (__\__ \ \ /\ / | | # |_| \_|\_____| \____/|_| |_| |_|_|\___|___/ \/ \/ |_| # # =========================== Next Generation Omics data workflow tools ======== # # Workflow tools for next generation genomics, metagenomics, RNA-seq # and other type of omics data analyiss, # # Software originally developed since 2010 by Weizhong Li at UCSD # currently at JCVI # # http://weizhongli-lab.org/ngomicswf liwz@sdsc.edu # ============================================================================== use Getopt::Std; use POSIX; getopts("i:R:s:J:Q:r:j:Z:t:S:T:",\%opts); die usage() unless ($opts{i} and ($opts{s} or $opts{S})); my $sample_in = $opts{s}; my $sample_command_in = $opts{S}; #### ';' delimited samples, ':' delimited entries, e.g. sample1:R1.fq:R2.fq;sample2:R1.fq:R2.fq or sample1;sample2;sample3 my $input_conf = $opts{i}; my $this_task = $opts{J}; our $G_NGS_root = $opts{r}; my $queue_system = $opts{Q}; $queue_system = "SGE" unless $queue_system; my $subset_wfs = $opts{R}; my $subset_jobs = $opts{j}; my $second_opt = $opts{Z}; my $opt_file = $opts{t}; my $opt_command_in = $opts{T}; #### ';' delimited jobs, ":" delimited entries, e.g. JobID_A:opt0:opt1:opt2;JobID_B:opt0:opt1 my $pwd = `pwd`; chop($pwd); my $sleep_time_min = 15; my $sleep_time_max = 120; my $log_dir = "$pwd/WF-LOG"; my $log_file = "$log_dir/LOG"; my $log_fileq = "$log_dir/LOGq"; my $sh_dir = "$pwd/WF-sh"; my $sh_bundle_dir = "$pwd/WF-sh-bundle"; my $subset_flag = 0; #### run only one job, subset of jobs, or jobs in sub workflows my %subset_jobs = (); my %qstat_xml_data = (); my ($i, $j, $k, $ll, $cmd); ######## scan through WF configration ######## and generate job list require $input_conf; my %job_list = (); # as $job_list{$t_job_id}{$t_sample_id} = {}; my ($t_sample_id, $t_job_id, $t_execution_id); my ($t_sample, $t_job, $t_execution); task_level_jobs(); my @NGS_batch_jobs = sort {($NGS_batch_jobs{$a}->{'job_level'} <=> $NGS_batch_jobs{$b}->{'job_level'}) or ($a cmp $b)} keys %NGS_batch_jobs; $cmd = `mkdir -p $log_dir` unless (-e $log_dir); $cmd = `mkdir -p $sh_dir` unless (-e $sh_dir); $cmd = `mkdir -p $sh_bundle_dir` unless (-e $sh_bundle_dir); open(LOG, ">> $log_file") || die "can not write to $log_file"; ######## parse NGS_samples my %NGS_sample_data = (); my @NGS_samples = (); if (defined($sample_in)) { open(TMP, $sample_in) || die "can not open $sample_in"; while($ll=){ next if ($ll =~ /^#/); next unless ($ll =~ /^\w/); chop($ll); my ($id, @data) = split(/\s+/,$ll); push(@NGS_samples, $id); $NGS_sample_data{$id} = [@data]; if (not (-e $id)) { $cmd = `mkdir $id`;} } close(TMP); } elsif (defined($sample_command_in)) { my @lls = split(/,/, $sample_command_in); foreach $ll (@lls) { my ($id, @data) = split(/:/, $ll); push(@NGS_samples, $id); $NGS_sample_data{$id} = [@data]; if (not (-e $id)) { $cmd = `mkdir $id`;} } } else { die "no input samples"; } my %CMD_opts = (); if (-e $opt_file) { ##format example ##CMDOPT JobID_A:opt0:opt1:opt2 ##CMDOPT JobID_B:opt0:opt1 ##CMDOPT JobID_C:opt0:opt1:opt2:opt3 open(TMP, $opt_file) || die "can not open $opt_file"; while($ll = ){ next if ($ll =~ /^#/); next unless ($ll =~ /^CMDOPT/); chop($ll); my ($i, $opt1) = split(/\s+/, $ll); my ($job_id, @opts) = split(/:/, $opt1); $CMD_opts{$job_id} = [@opts]; } close(TMP); } elsif ($opt_command_in) { my @lls = split(/,/, $opt_command_in); foreach $ll (@lls) { my ($job_id, @opts) = split(/:/, $ll); $CMD_opts{$job_id} = [@opts]; } } ########## processing subset of jobs if ($subset_wfs) { my @wfs = split(/,/, $subset_wfs); $subset_flag = 1; foreach $i (@wfs) { my @jobs = @{ $NGS_batch_sets{$i}->{"jobs"} }; foreach $j (@jobs) { $subset_jobs{$j} = 1; } } } if ($subset_jobs) { $subset_flag = 1; my @jobs = split(/,/, $subset_jobs); foreach $j (@jobs) { $subset_jobs{$j} = 1; } add_subset_jobs_by_dependency(); } if ($subset_flag) { my $job_str = join(" ", keys %subset_jobs); write_log("Running subset of jobs: $job_str"); } my $verify_flag = 0; foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} $t_job = $NGS_batch_jobs{$t_job_id}; $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $pe_parameter = ""; #### setup pe parameters if ($t_execution->{'type'} eq "qsub-pe") { my $t_cores_per_cmd = $t_job->{"cores_per_cmd"}; $t_cores_per_cmd = 1 unless ($t_cores_per_cmd); $pe_parameter = "#\$ -pe orte $t_cores_per_cmd"; } if ($t_job->{"cores_per_cmd"} > $t_execution->{"cores_per_node"} ) { $verify_flag = 1; write_log("$t_job_id needs $t_job->{\"cores_per_cmd\"} cores, but $t_job->{\"execution\"} only has $t_execution->{\"cores_per_node\"} cores"); } my $cmds_per_node = POSIX::floor( $t_execution->{"cores_per_node"} / $t_job->{"cores_per_cmd"}); my $nodes_total = POSIX::ceil($t_job->{"no_parallel"} / $cmds_per_node); $t_job->{"cmds_per_node"} = $cmds_per_node; $t_job->{"nodes_total"} = $nodes_total; if ($t_job->{"nodes_total"} > $t_execution->{"number_nodes"}) { $verify_flag = 1; write_log("$t_job_id needs $t_job->{\"nodes_total\"} nodes, but $t_job->{\"execution\"} only has $t_execution->{\"number_nodes\"} nodes"); } my @CMD_opts = (); @CMD_opts = @{$t_job->{CMD_opts}} if (defined($t_job->{CMD_opts} )); @CMD_opts = @{$CMD_opts{$t_job_id}} if (defined($CMD_opts{$t_job_id})); #### command line take over default foreach $t_sample_id (@NGS_samples) { my @t_commands = split(/\t/, $t_job->{"command"}); my $t_command = ""; foreach my $c0 (@t_commands) { my $c1 = $c0; $c1 =~ s/\\SAMPLE/$t_sample_id/g; $c1 =~ s/\\SELF/$t_job_id/g; # take it easy, assuming maxium 20 input files $c1 =~ s/\\INFILES\.0/$t_job->{"infiles"}->[0]/g; $c1 =~ s/\\INFILES\.10/$t_job->{"infiles"}->[10]/g; $c1 =~ s/\\INFILES\.1/$t_job->{"infiles"}->[1]/g; $c1 =~ s/\\INFILES\.11/$t_job->{"infiles"}->[11]/g; $c1 =~ s/\\INFILES\.2/$t_job->{"infiles"}->[2]/g; $c1 =~ s/\\INFILES\.12/$t_job->{"infiles"}->[12]/g; $c1 =~ s/\\INFILES\.3/$t_job->{"infiles"}->[3]/g; $c1 =~ s/\\INFILES\.13/$t_job->{"infiles"}->[13]/g; $c1 =~ s/\\INFILES\.4/$t_job->{"infiles"}->[4]/g; $c1 =~ s/\\INFILES\.14/$t_job->{"infiles"}->[14]/g; $c1 =~ s/\\INFILES\.5/$t_job->{"infiles"}->[5]/g; $c1 =~ s/\\INFILES\.15/$t_job->{"infiles"}->[15]/g; $c1 =~ s/\\INFILES\.6/$t_job->{"infiles"}->[6]/g; $c1 =~ s/\\INFILES\.16/$t_job->{"infiles"}->[16]/g; $c1 =~ s/\\INFILES\.7/$t_job->{"infiles"}->[7]/g; $c1 =~ s/\\INFILES\.17/$t_job->{"infiles"}->[17]/g; $c1 =~ s/\\INFILES\.8/$t_job->{"infiles"}->[8]/g; $c1 =~ s/\\INFILES\.18/$t_job->{"infiles"}->[18]/g; $c1 =~ s/\\INFILES\.9/$t_job->{"infiles"}->[9]/g; $c1 =~ s/\\INFILES\.19/$t_job->{"infiles"}->[19]/g; $c1 =~ s/\\DATA\.0/$NGS_sample_data{$t_sample_id}->[0]/g; $c1 =~ s/\\DATA\.10/$NGS_sample_data{$t_sample_id}->[10]/g; $c1 =~ s/\\DATA\.1/$NGS_sample_data{$t_sample_id}->[1]/g; $c1 =~ s/\\DATA\.11/$NGS_sample_data{$t_sample_id}->[11]/g; $c1 =~ s/\\DATA\.2/$NGS_sample_data{$t_sample_id}->[2]/g; $c1 =~ s/\\DATA\.12/$NGS_sample_data{$t_sample_id}->[12]/g; $c1 =~ s/\\DATA\.3/$NGS_sample_data{$t_sample_id}->[3]/g; $c1 =~ s/\\DATA\.13/$NGS_sample_data{$t_sample_id}->[13]/g; $c1 =~ s/\\DATA\.4/$NGS_sample_data{$t_sample_id}->[4]/g; $c1 =~ s/\\DATA\.14/$NGS_sample_data{$t_sample_id}->[14]/g; $c1 =~ s/\\DATA\.5/$NGS_sample_data{$t_sample_id}->[5]/g; $c1 =~ s/\\DATA\.15/$NGS_sample_data{$t_sample_id}->[15]/g; $c1 =~ s/\\DATA\.6/$NGS_sample_data{$t_sample_id}->[6]/g; $c1 =~ s/\\DATA\.16/$NGS_sample_data{$t_sample_id}->[16]/g; $c1 =~ s/\\DATA\.7/$NGS_sample_data{$t_sample_id}->[7]/g; $c1 =~ s/\\DATA\.17/$NGS_sample_data{$t_sample_id}->[17]/g; $c1 =~ s/\\DATA\.8/$NGS_sample_data{$t_sample_id}->[8]/g; $c1 =~ s/\\DATA\.18/$NGS_sample_data{$t_sample_id}->[18]/g; $c1 =~ s/\\DATA\.9/$NGS_sample_data{$t_sample_id}->[9]/g; $c1 =~ s/\\DATA\.19/$NGS_sample_data{$t_sample_id}->[19]/g; $c1 =~ s/\\INJOBS\.0/$t_job->{"injobs"}->[0]/g; $c1 =~ s/\\INJOBS\.10/$t_job->{"injobs"}->[10]/g; $c1 =~ s/\\INJOBS\.1/$t_job->{"injobs"}->[1]/g; $c1 =~ s/\\INJOBS\.11/$t_job->{"injobs"}->[11]/g; $c1 =~ s/\\INJOBS\.2/$t_job->{"injobs"}->[2]/g; $c1 =~ s/\\INJOBS\.12/$t_job->{"injobs"}->[12]/g; $c1 =~ s/\\INJOBS\.3/$t_job->{"injobs"}->[3]/g; $c1 =~ s/\\INJOBS\.13/$t_job->{"injobs"}->[13]/g; $c1 =~ s/\\INJOBS\.4/$t_job->{"injobs"}->[4]/g; $c1 =~ s/\\INJOBS\.14/$t_job->{"injobs"}->[14]/g; $c1 =~ s/\\INJOBS\.5/$t_job->{"injobs"}->[5]/g; $c1 =~ s/\\INJOBS\.15/$t_job->{"injobs"}->[15]/g; $c1 =~ s/\\INJOBS\.6/$t_job->{"injobs"}->[6]/g; $c1 =~ s/\\INJOBS\.16/$t_job->{"injobs"}->[16]/g; $c1 =~ s/\\INJOBS\.7/$t_job->{"injobs"}->[7]/g; $c1 =~ s/\\INJOBS\.17/$t_job->{"injobs"}->[17]/g; $c1 =~ s/\\INJOBS\.8/$t_job->{"injobs"}->[8]/g; $c1 =~ s/\\INJOBS\.18/$t_job->{"injobs"}->[18]/g; $c1 =~ s/\\INJOBS\.9/$t_job->{"injobs"}->[9]/g; $c1 =~ s/\\INJOBS\.19/$t_job->{"injobs"}->[19]/g; $c1 =~ s/\\CMDOPTS\.0/$CMD_opts[0]/g; $c1 =~ s/\\CMDOPTS\.10/$CMD_opts[10]/g; $c1 =~ s/\\CMDOPTS\.1/$CMD_opts[1]/g; $c1 =~ s/\\CMDOPTS\.11/$CMD_opts[11]/g; $c1 =~ s/\\CMDOPTS\.2/$CMD_opts[2]/g; $c1 =~ s/\\CMDOPTS\.12/$CMD_opts[12]/g; $c1 =~ s/\\CMDOPTS\.3/$CMD_opts[3]/g; $c1 =~ s/\\CMDOPTS\.13/$CMD_opts[13]/g; $c1 =~ s/\\CMDOPTS\.4/$CMD_opts[4]/g; $c1 =~ s/\\CMDOPTS\.14/$CMD_opts[14]/g; $c1 =~ s/\\CMDOPTS\.5/$CMD_opts[5]/g; $c1 =~ s/\\CMDOPTS\.15/$CMD_opts[15]/g; $c1 =~ s/\\CMDOPTS\.6/$CMD_opts[6]/g; $c1 =~ s/\\CMDOPTS\.16/$CMD_opts[16]/g; $c1 =~ s/\\CMDOPTS\.7/$CMD_opts[7]/g; $c1 =~ s/\\CMDOPTS\.17/$CMD_opts[17]/g; $c1 =~ s/\\CMDOPTS\.8/$CMD_opts[8]/g; $c1 =~ s/\\CMDOPTS\.18/$CMD_opts[18]/g; $c1 =~ s/\\CMDOPTS\.9/$CMD_opts[9]/g; $c1 =~ s/\\CMDOPTS\.19/$CMD_opts[19]/g; $t_command .= "$c1\n"; } my @t_infiles = map { "$t_sample_id/$_" } @{$t_job->{"infiles"}}; my @t_injobs = @{$t_job->{"injobs"}}; my $t_sh_file = "$sh_dir/$t_job_id.$t_sample_id.sh"; my $f_start = "$pwd/$t_sample_id/$t_job_id/WF.start.date"; my $f_complete = "$pwd/$t_sample_id/$t_job_id/WF.complete.date"; my $f_cpu = "$pwd/$t_sample_id/$t_job_id/WF.cpu"; $job_list{$t_job_id}{$t_sample_id} = { 'sample_id' => $t_sample_id, 'job_id' => $t_job_id, 'status' => 'wait', #### status can be wait (input not ready), ready (input ready), submitted (submitted or running), completed 'command' => $t_command, 'sh_file' => $t_sh_file, 'infiles' => [@t_infiles], 'injobs' => [@t_injobs], 'start_file' => $f_start, 'complete_file'=> $f_complete, 'cpu_file' => $f_cpu, }; my $v_command = ""; foreach my $vf (@{$t_job->{"non_zero_files"}}) { $v_command .= "if ! [ -s $t_job_id/$vf ]; then echo \"zero size $t_job_id/$vf\"; exit; fi\n"; } if (not -e $t_sh_file) { write_log("Write sh file to $t_sh_file"); open(TSH, "> $t_sh_file") || die "can not write to $t_sh_file\n"; print TSH <{"template"} $pe_parameter my_host=`hostname` my_pid=\$\$ my_core=$t_job->{"cores_per_cmd"} my_queue=$t_job->{"execution"} my_time_start=`date +%s`; cd $pwd cd $t_sample_id mkdir $t_job_id if ! [ -f $f_start ]; then date +\%s > $f_start; fi $t_command $v_command date +\%s > $f_complete #times >> $f_cpu my_time_end=`date +%s`; my_time_spent=\$((my_time_end-my_time_start)) echo "sample=$t_sample_id job=$t_job_id host=\$my_host pid=\$my_pid queue=\$my_queue cores=\$my_core time_start=\$my_time_start time_end=\$my_time_end time_spent=\$my_time_spent" >> $f_cpu EOD close(TSH); #validate_cmd_line($t_command, $t_sh_file, $t_sample_id); } } ########## foreach my $c0 (@t_commands) } ########## foreach $t_job (keys %NGS_batch_jobs) die if ($verify_flag); if ($this_task eq "log-cpu" ) { task_log_cpu(); exit 0;} elsif ($this_task eq "list-jobs" ) { task_list_jobs(); exit 0;} elsif ($this_task eq "snapshot" ) { task_snapshot(); exit 0;} elsif ($this_task eq "delete-jobs" ) { task_delete_jobs($second_opt); exit 0;} elsif ($this_task eq "write-sh" ) { exit 0;} elsif ($this_task ) { die "undefined task $this_task";} ################################################################################################ # _____ _ _ _____ _____ _ _ _ _ _ # | __ \ | \ | |/ ____|/ ____|| | | | | | (_) | | # | |__) | _ _ __ | \| | | __| (___ | |__ __ _| |_ ___| |__ _ ___ | |__ ___ # | _ / | | | '_ \ | . ` | | |_ |\___ \ | '_ \ / _` | __/ __| '_ \ | |/ _ \| '_ \/ __| # | | \ \ |_| | | | | | |\ | |__| |____) || |_) | (_| | || (__| | | | | | (_) | |_) \__ \ # |_| \_\__,_|_| |_| |_| \_|\_____|_____/ |_.__/ \__,_|\__\___|_| |_| | |\___/|_.__/|___/ # ______ ______ _/ | # |______| |______|__/ ########## Run NGS_batch_jobs for each samples http://patorjk.com/software/taag ################################################################################################ my %execution_submitted = (); # number of submitted jobs (qsub) or threads (local sh) my $sleep_time = $sleep_time_min; while(1) { my $flag_job_done = 1; ########## reset execution_submitted to 0 foreach $i (keys %NGS_executions) { $execution_submitted{$i} = 0; } my $flag_qstat_xml_call = 0; foreach $t_job_id (keys %NGS_batch_jobs) { my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $exe_type = $t_execution->{type}; $flag_qstat_xml_call = 1 if (($queue_system eq "SGE") and (($exe_type eq "qsub") or ($exe_type eq "qsub-pe"))); } SGE_qstat_xml_query() if $flag_qstat_xml_call; ########## check and update job status for submitted jobs foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next if ($status eq "completed"); ########## check file system to update job status ########## in case this is a restart run check_submitted_job($t_job_id, $t_sample_id); next if ($t_sample_job->{'status'} eq "completed"); $flag_job_done = 0; } } if ($flag_job_done) { write_log("job completed!"); last; } ########## check and update job status based on dependance foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "wait"); my @t_infiles = @{ $t_sample_job->{'infiles'} }; my @t_injobs = @{ $t_sample_job->{'injobs'} }; my $t_ready_flag = 1; foreach $i (@t_infiles) { next if (-s $i); #### non-zero size file $t_ready_flag = 0; last; } foreach $i (@t_injobs) { next if ( $job_list{$i}{$t_sample_id}->{'status'} eq "completed"); #### injob completed $t_ready_flag = 0; last; } if ($t_ready_flag) { $t_sample_job->{"status"} = "ready"; write_log("$t_job_id,$t_sample_id: change status to ready"); } } } ########## submit local sh jobs my $has_submitted_some_jobs = 0; foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $t_execution_id = $t_job->{"execution"}; if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} next unless ($t_execution->{'type'} eq "sh"); next if ( $execution_submitted{$t_execution_id} >= $t_execution->{"cores_per_node"} ); #### all cores are used foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "ready"); next if ( ($execution_submitted{$t_execution_id} + $t_job->{"cores_per_cmd"} * $t_job->{"no_parallel"}) > $t_execution->{"cores_per_node"} ); #### no enough available cores #### now submitting my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; for ($i=0; $i<$t_job->{"no_parallel"}; $i++) { $cmd = `sh $t_sh_file >/dev/null 2>&1 &`; } $cmd = `touch $t_sh_pid`; $t_sample_job->{'status'} = "submitted"; write_log("$t_job_id,$t_sample_id: change status to submitted"); $execution_submitted{ $t_execution_id } += $t_job->{"cores_per_cmd"} * $t_job->{"no_parallel"}; $has_submitted_some_jobs = 1; } } ########## submit qsub-pe jobs, multiple jobs may share same node foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $t_execution_id = $t_job->{"execution"}; next unless ($t_execution->{'type'} eq "qsub-pe"); next if ( $execution_submitted{$t_execution_id} >= $t_execution->{"number_nodes"} ); #### resource full my $t_cores_per_node = $t_execution->{"cores_per_node"}; my $t_cores_per_cmd = $t_job->{"cores_per_cmd"}; my $t_cores_per_job = $t_cores_per_cmd * $t_job->{"no_parallel"}; my $t_nodes_per_job = $t_cores_per_job / $t_cores_per_node; foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "ready"); my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; open(TID, "> $t_sh_pid") || die "can not write to $t_sh_pid"; for ($i=0; $i<$t_job->{"no_parallel"}; $i++) { my $t_stderr = "$t_sh_file.$i.stderr"; my $t_stdout = "$t_sh_file.$i.stdout"; $cmd = `qsub $t_execution->{"command_name_opt"} $t_job_id $t_execution->{"command_err_opt"} $t_stderr $t_execution->{"command_out_opt"} $t_stdout $t_sh_file 2>$log_fileq`; my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} print TID "$qsub_id\n"; #### $cmd returns qsub id, write these ids to pid file for future qstat $execution_submitted{$t_execution_id} += $t_nodes_per_job; write_log("$t_sh_bundle submitted for sample $t_sample_id, qsubid $cmd"); } close(TID); $has_submitted_some_jobs = 1; $t_sample_job->{'status'} = "submitted"; } } ########## END foreach $t_job_id (keys %NGS_batch_jobs) ########## submit qsub jobs foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $t_execution_id = $t_job->{"execution"}; if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} next unless ($t_execution->{'type'} eq "qsub"); next if ( $execution_submitted{$t_execution_id} >= $t_execution->{"number_nodes"} ); #### resource full my $t_cores_per_node = $t_execution->{"cores_per_node"}; my $t_cores_per_cmd = $t_job->{"cores_per_cmd"}; my $t_cores_per_job = $t_cores_per_cmd * $t_job->{"no_parallel"}; my $t_nodes_per_job = POSIX::ceil($t_cores_per_job / $t_cores_per_node); my $t_cmds_per_node = int($t_cores_per_node / $t_cores_per_cmd); my $t_jobs_per_node = int($t_cores_per_node / $t_cores_per_job); ########## 1. this loop process jobs need 1 or more nodes per sample, ie. bundle within a sample, e.g. blast against refseq foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "ready"); next unless ($t_jobs_per_node <= 1); #### unless need >= 1 node, including jobs use between (51%-100%) cores per node last if ( ($execution_submitted{$t_execution_id} + $t_nodes_per_job) > $t_execution->{"number_nodes"}); #### no enough available queues my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_bundle = "$sh_bundle_dir/$t_job_id.$t_sample_id.$$.sh"; my $t_stderr = "$t_sh_bundle.stderr"; my $t_stdout = "$t_sh_bundle.stdout"; my $t_sh_pid = "$t_sh_file.pids"; open(TID, "> $t_sh_pid") || die "can not write to $t_sh_pid"; open(BSH, "> $t_sh_bundle") || die "can not write to $t_sh_bundle"; print BSH <{"template"} cd $pwd EOD for ($i=0; $i<$t_cmds_per_node; $i++) { print BSH "sh $t_sh_file &\n"; print BSH "sleep 3\n"; } print BSH "wait\n"; close(BSH); for ($i=0; $i<$t_nodes_per_job; $i++) { $cmd = `qsub $t_execution->{"command_name_opt"} $t_job_id $t_execution->{"command_err_opt"} $t_stderr $t_execution->{"command_out_opt"} $t_stdout $t_sh_bundle 2>$log_fileq`; my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} print TID "$qsub_id\n"; #### $cmd returns qsub id, write these ids to pid file for future qstat $execution_submitted{$t_execution_id}++; write_log("$t_sh_bundle submitted for sample $t_sample_id, qsubid $cmd"); } close(TID); $has_submitted_some_jobs = 1; $t_sample_job->{'status'} = "submitted"; } ########## END foreach $t_sample_id (@NGS_samples) ########## 2. this loop process jobs need less than 1 node per sample, ie. bundle jobs across samples, e.g. qc my @t_bundle = (); my $available_nodes = $t_execution->{"number_nodes"} - $execution_submitted{$t_execution_id}; my $no_sample_can_be_processed = $available_nodes * $t_jobs_per_node; my @t_samples = (); my $t_batch_no = 0; foreach $t_sample_id (@NGS_samples) { #### same loop as next, to find out @t_samples and last sample can run my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "ready"); next unless ($t_jobs_per_node > 1); #### unless a node can host 2 or more jobs last if ( $t_execution->{"number_nodes"} - $execution_submitted{$t_execution_id} <=0); push(@t_samples, $t_sample_id); } my $last_sample_can_run = $t_samples[-1]; @t_samples = (); foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; next unless ($status eq "ready"); next unless ($t_jobs_per_node > 1); #### unless a node can host 2 or more jobs last if ( $t_execution->{"number_nodes"} - $execution_submitted{$t_execution_id} <=0); push(@t_samples, $t_sample_id); #### bundle @t_samples to one qsub job if ((($#t_samples+1) == $t_jobs_per_node) or ($t_sample_id eq $last_sample_can_run)) { my $t_sh_bundle = "$sh_bundle_dir/$t_job_id.samples-$t_batch_no.$$.sh"; my $t_stderr = "$t_sh_bundle.stderr"; my $t_stdout = "$t_sh_bundle.stdout"; open(BSH, "> $t_sh_bundle") || die "can not write to $t_sh_bundle"; print BSH <{"template"} cd $pwd EOD foreach $i (@t_samples) { my $t_sh_file = $job_list{$t_job_id}{$i}->{'sh_file'}; for ($j=0; $j<$t_job->{"no_parallel"}; $j++) { print BSH "sh $t_sh_file &\n"; print BSH "sleep 3\n"; } } print BSH "wait\n"; close(BSH); $cmd = `qsub $t_execution->{"command_name_opt"} $t_job_id $t_execution->{"command_err_opt"} $t_stderr $t_execution->{"command_out_opt"} $t_stdout $t_sh_bundle 2>$log_fileq`; my $qsub_id = 0; if ($cmd =~ /(\d+)/) { $qsub_id = $1;} else {die "can not submit qsub job and return a id\n";} foreach $i (@t_samples) { my $t_sh_file = $job_list{$t_job_id}{$i}->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; open(TID, "> $t_sh_pid") || die "can not write to $t_sh_pid"; print TID "$qsub_id\n"; #### $cmd returns qsub id, write these ids to pid file for future qstat write_log("$t_sh_bundle submitted for sample $i, qsubid $cmd"); close(TID); $job_list{$t_job_id}{$i}->{'status'} = "submitted"; } $has_submitted_some_jobs = 1; $execution_submitted{$t_execution_id}++; @t_samples = (); #### clear $t_batch_no++; } } ########## END foreach $t_sample_id (@NGS_samples) } ########## END foreach $t_job_id (keys %NGS_batch_jobs) #### if has submitted some jobs, reset waiting time, otherwise double waiting time print_job_status_summary(); if ($has_submitted_some_jobs) { $sleep_time = $sleep_time_min; } else { $sleep_time = $sleep_time*2; $sleep_time = $sleep_time_max if ($sleep_time > $sleep_time_max); } write_log("sleep $sleep_time seconds"); sleep($sleep_time); } ########## END while(1) task_log_cpu(); ################################################################################ ########## END Run NGS_batch_jobs for each samples ################################################################################ close(LOG); ########## sub write_log { my @txt = @_; my $i; my $date = `date`; chop($date); foreach $i (@txt) { print LOG "$date $i\n"; print STDERR "$date $i\n"; } print LOG "\n"; print STDERR "\n"; } ########## END write_log sub SGE_qstat_xml_query { my ($i, $j, $k, $cmd, $ll); %qstat_xml_data = (); #### global $cmd = `qstat -f -xml`; if ($cmd =~ /(\d+)/) { $id = $1;} if ($lls[$i] =~ /([^<]+)/) { $name = $1;} if ($lls[$i] =~ /([^<]+)/) {$state = $1;} } if (defined($id) and defined($name) and defined($state)) { $qstat_xml_data{$id} = [$name, $state]; } } } } ########## check submitted job by checking pids, or qsub ids ########## update job status from wait|ready -> submitted if pid file exit (in case of restart of this script) ########## update job status from wait|ready|submitted -> completed if sh calls or qsub calls finished ########## these pids or qsub ids are done sub check_submitted_job { my ($t_job_id, $t_sample_id) = @_; my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my ($i, $j, $k, $flag, $ll, $cmd); my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; # status won't change unless there is a pid file return unless (-e $t_sh_pid); my $status = $t_sample_job->{'status'}; if (($status eq "wait") or ($status eq "ready")) { $t_sample_job->{'status'} = "submitted"; write_log("$t_job_id,$t_sample_id: change status to submitted"); } my $exe_type = $t_execution->{type}; if ($exe_type eq "sh") { $cmd = `ps -ef | grep "$t_sh_file" | grep -v grep`; if ($cmd =~ /\w/) { # still running $execution_submitted{ $t_job->{"execution"} } += $t_job->{"cores_per_cmd"} * $t_job->{"no_parallel"}; } elsif (validate_job_files($t_job_id, $t_sample_id)) { $t_sample_job->{'status'} = "completed"; write_log("$t_job_id,$t_sample_id: change status to completed"); } else { $t_sample_job->{'status'} = "error"; write_log("$t_job_id,$t_sample_id: change status to error"); } return; } elsif (($exe_type eq "qsub") or ($exe_type eq "qsub-pe")) { my @pids = (); open(CHECK, $t_sh_pid) || die "Can not open $t_sh_pid\n"; while($ll = ) { chop($ll); next unless ($ll =~ /\w/); push(@pids, $ll); } close(CHECK); my $finish_flag = 1; foreach $i (@pids) { if (($queue_system eq "SGE") and %qstat_xml_data) { if (defined($qstat_xml_data{$i})) { $t_sample_job->{'status'} = "running" if (($qstat_xml_data{$i}->[1] eq "r") and ($t_sample_job->{'status'} eq "submitted")); $finish_flag = 0; $execution_submitted{ $t_job->{"execution"} } ++; } } elsif ($queue_system eq "SGE") { $cmd = `qstat -j $i | grep job_number`; if ($cmd =~ /$i/) { $finish_flag = 0; $execution_submitted{ $t_job->{"execution"} } ++; } } else { $cmd = `qstat -r $i | grep $i`; $j = (split(/\D/,$cmd))[0]; if ($j == $i) { # this job is running $finish_flag = 0; $execution_submitted{ $t_job->{"execution"} } ++; } } } if ($finish_flag == 1) { if (validate_job_files($t_job_id, $t_sample_id)) { $t_sample_job->{'status'} = "completed"; write_log("$t_job_id,$t_sample_id: change status to completed"); } else { $t_sample_job->{'status'} = "error"; write_log("$t_job_id,$t_sample_id: change status to error"); } } return; } else { die "unknown execution type: $exe_type\n"; } } ########## END sub check_submitted_job # WF.start.date and WF.complete.date need to have non-zero size sub validate_job_files { my ($t_job_id, $t_sample_id) = @_; my ($i, $j, $k); my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; return 0 unless (-s $t_sample_job->{'start_file'} ); return 0 unless (-s $t_sample_job->{'complete_file'} ); return 0 unless (-s $t_sample_job->{'cpu_file'} ); return 1; #### pass } ########## END validate_job_files sub print_job_status_summary { my ($t_job_id, $t_sample_id); my ($i, $j, $k); my %job_status = (); my $job_total = 0; foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} foreach $t_sample_id (@NGS_samples) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $status = $t_sample_job->{'status'}; $job_status{$status}++; $job_total++; } } print STDERR "total jobs: $job_total,"; foreach $i (sort keys %job_status) { print STDERR "$i: $job_status{$i},"; } print STDERR "\n"; } ########## END print_job_status_summary sub validate_cmd_line { my ($i, $j, $k); my ($t_command, $t_sh_file, $t_sample_id) = @_; my @cmds = split(/\n/,$t_command); my @warn_path = (); foreach $i (@cmds) { my ($key_cmd, @opts) = split(/\s+/, $i); if ($key_cmd =~ /\//) { if (not -e $key_cmd) { push(@warn_path, $key_cmd); } } @opts = grep {/\//} @opts; foreach $j (@opts) { my @opts1 = split(/,|;|>|<|\|/,$j); foreach $k (@opts1) { $k = "$t_sample_id/$k" unless (($k =~ /^\//) or ($k =~ /^\./)); if (not -e $k) { push(@warn_path, $k); } } } } if (@warn_path) { print STDERR "File or program doesn't exist in $t_sh_file: ", join(" ", @warn_path), "\n"; } } ########## END validate_cmd_line sub add_subset_jobs_by_dependency { my ($i, $j, $k, $ll, $t_job_id, $t_sample_id, $t_job); while(1) { my $num_subset_jobs = scalar keys %subset_jobs; foreach $t_job_id (keys %subset_jobs) { $t_job = $NGS_batch_jobs{$t_job_id}; my @t_injobs = @{$t_job->{"injobs"}}; for $j (@t_injobs) { $subset_jobs{$j} = 1; } } last if ($num_subset_jobs == scalar keys %subset_jobs); } } ########## END add_subset_jobs_by_dependency sub task_level_jobs { my ($i, $j, $k, $ll, $t_job_id, $t_sample_id, $t_job); my %job_level = (); while(1) { my $change_flag = 0; foreach $t_job_id (keys %NGS_batch_jobs) { $t_job = $NGS_batch_jobs{$t_job_id}; my @t_injobs = @{$t_job->{"injobs"}}; if (@t_injobs) { my $max_level_injob; foreach $j (@t_injobs) { next unless defined ($job_level{$j}); $max_level_injob = $job_level{$j} if ($job_level{$j} > $max_level_injob); } next unless (defined($max_level_injob)); $max_level_injob++; #### one more level if (not defined ($job_level{$t_job_id})) { $job_level{$t_job_id}=$max_level_injob; $change_flag = 1; } elsif ($max_level_injob > $job_level{$t_job_id}) { $job_level{$t_job_id}=$max_level_injob; $change_flag = 1; } } else { if (not defined ($job_level{$t_job_id})) { $job_level{$t_job_id}=1; $change_flag = 1; } } } last unless ($change_flag); } foreach $t_job_id (sort keys %NGS_batch_jobs) { $NGS_batch_jobs{$t_job_id}->{"job_level"} = $job_level{$t_job_id}; } } ########## END task_list_jobs sub task_snapshot { my ($t_job_id, $t_sample_id); my ($i, $j, $k); if ($this_task) { my $flag_qstat_xml_call = 0; foreach $t_job_id (keys %NGS_batch_jobs) { my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_execution = $NGS_executions{ $t_job->{"execution"} }; my $exe_type = $t_execution->{type}; $flag_qstat_xml_call = 1 if (($queue_system eq "SGE") and (($exe_type eq "qsub") or ($exe_type eq "qsub-pe"))); } SGE_qstat_xml_query() if $flag_qstat_xml_call; foreach $t_sample_id (@NGS_samples) { foreach $t_job_id (keys %NGS_batch_jobs) { check_submitted_job($t_job_id, $t_sample_id); } } } my $max_len_sample = 0; foreach $t_sample_id (@NGS_samples) { $max_len_sample = length($t_sample_id) if (length($t_sample_id) > $max_len_sample); } my $max_len_job = 0; foreach $t_job_id (@NGS_batch_jobs) { $max_len_job = length($t_job_id) if (length($t_job_id) > $max_len_job); } print <=0; $i--) { print ' 'x$max_len_sample, "\t"; foreach $t_job_id (@NGS_batch_jobs) { print " ", ($i{'status'}; if ($status eq "completed") { print " +";} elsif ($status eq "submitted") { print " -";} elsif ($status eq "running" ) { print " r";} elsif ($status eq "wait" ) { print " .";} elsif ($status eq "error" ) { print " !";} else { print " _";} } print "\n"; } } ########## END task_snapshot sub task_list_jobs { my ($i, $j, $k, $ll, $t_job_id, $t_sample_id, $t_job); foreach $t_job_id (@NGS_batch_jobs) { $t_job = $NGS_batch_jobs{$t_job_id}; #my @t_infiles = @{$t_job->{"infiles"}}; my @t_injobs = @{$t_job->{"injobs"}}; #print "\tInput_files:", join(",", @t_infiles) if @t_infiles; print "$t_job_id\tIn_jobs:[" , join(",", @t_injobs), "]\tJob_level:$t_job->{'job_level'}\n"; } } ########## END task_list_jobs sub file1_after_file2 { my ($file1, $file2) = @_; # if not exist file1, assume it is in future, so it is newer if (not -e ($file1)) {return 0;} if (not -e ($file2)) {return 0;} my $mtime1 = (stat($file1))[9]; my $mtime2 = (stat($file2))[9]; return ( ($mtime1 > $mtime2) ? 1 : 0); } ######## END file1_after_file2 sub file1_same_or_after_file2 { my ($file1, $file2) = @_; # if not exist file1, assume it is in future, so it is newer if (not -e ($file1)) {return 0;} if (not -e ($file2)) {return 0;} my $mtime1 = (stat($file1))[9]; my $mtime2 = (stat($file2))[9]; return ( ($mtime1 >= $mtime2) ? 1 : 0); } ######## END file1_after_file2 sub task_delete_jobs { my $opt = shift; my ($i, $j, $k, $ll, $t_job_id, $t_sample_id); my ($mode, $c) = split(/:/, $opt); my $tmp_sh = "NGS-$$.sh"; open(TMPSH, "> $tmp_sh") || die "can not write to file $tmp_sh"; print TMPSH "#Please execute the following commands\n"; foreach $t_sample_id (@NGS_samples) { my %job_to_delete_ids = (); if ($mode eq "jobids") { %job_to_delete_ids = map {$_, 1} split(/,/,$c); } elsif ($mode eq "run_after") { die "file $c doesn't exist!" unless (-e $c); foreach $t_job_id (keys %NGS_batch_jobs) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; next unless (-e $t_sh_pid); #### unless the job is submitted #$job_to_delete_ids{$t_job_id} = 1 if (file1_same_or_after_file2( $t_sample_job->{'start_file'} , $c)); $job_to_delete_ids{$t_job_id} = 1 if (file1_same_or_after_file2( $t_sh_pid , $c)); } } else { die "unknown option for deleting jobs: $opt"; } # now %job_to_delete_ids are jobs need to be deleted # next find all jobs that depends on them, recrusively my $no_jobs_to_delete = scalar keys %job_to_delete_ids; while(1) { foreach $t_job_id (keys %NGS_batch_jobs) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; next unless (-e $t_sh_pid); #### unless the job is submitted my @t_injobs = @{ $t_sample_job->{'injobs'} }; foreach my $t_job_id_2 (@t_injobs) { $job_to_delete_ids{$t_job_id} = 1 if ($job_to_delete_ids{$t_job_id_2}); } } last if ($no_jobs_to_delete == (scalar keys %job_to_delete_ids)); #### no more depending jobs $no_jobs_to_delete = scalar keys %job_to_delete_ids; } if ($no_jobs_to_delete) { print TMPSH "#jobs to be deleted for $t_sample_id: ", join(",", keys %job_to_delete_ids), "\n"; print "#jobs to be deleted for $t_sample_id: ", join(",", keys %job_to_delete_ids), "\n"; foreach $t_job_id (keys %job_to_delete_ids) { my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $t_sh_file = $t_sample_job->{'sh_file'}; my $t_sh_pid = "$t_sh_file.pids"; print TMPSH "\\rm -rf $pwd/$t_sample_id/$t_job_id\n"; print TMPSH "\\rm $t_sh_pid\n"; print TMPSH "\\rm $t_sh_file.*.std*\n"; #### find the qsub ids to be deleted my $qids = `cat $t_sh_pid`; $qids =~ s/\n/ /g; $qids =~ s/\s+/ /g; print TMPSH "qdel $qids\n"; } } } close(TMPSH); print "The script is not delete the file, please run $tmp_sh to delete files!!!\n\n"; } ########## END task_list_jobs sub task_log_cpu { my ($i, $j, $k, $ll, $t_job_id, $t_sample_id); my %cpu_info; foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; foreach $t_sample_id (@NGS_samples) { $cpu_info{$t_job_id}{$t_sample_id} = [$t_wall, $t_cpu]; } } foreach $t_sample_id (@NGS_samples) { my $f_cpu = "$pwd/$t_sample_id/WF.cpu"; open(CPUOUT, "> $f_cpu") || die "Can not open $f_cpu"; print CPUOUT "#job_name\tCores\tWall(s)\tWall_time\tCPU(s)\tCPU_time\n"; my $min_start = 1402092131 * 999999; my $max_end = 0; my $sum_cpu = 0; foreach $t_job_id (keys %NGS_batch_jobs) { if ($subset_flag) {next unless ($subset_jobs{$t_job_id});} my $t_job = $NGS_batch_jobs{$t_job_id}; my $t_core = $t_job->{"cores_per_cmd"} * $t_job->{"no_parallel"}; my $t_sample_job = $job_list{$t_job_id}{$t_sample_id}; my $f_start = $t_sample_job->{'start_file'}; my $f_complete = $t_sample_job->{'complete_file'}; my $f_cpu = $t_sample_job->{'cpu_file'}; my $t_start = `cat $f_start`; $t_start =~ s/\s//g; $min_start = $t_start if ($t_start < $min_start); my $t_end = `cat $f_complete`; $t_end =~ s/\s//g; $max_end = $t_end if ($t_end > $max_end); my $t_wall = int($t_end - $t_start); $t_wall = 0 unless ($t_wall>0); my $t_cpu = 0; if (open(TCPU, $f_cpu)) { while($ll = ) { chop($ll); if ($ll =~ /^(\d+)m(\d+)/) { $t_cpu += $1 * 60; } } close(TCPU); } $sum_cpu += $t_cpu; my $t_walls = time_str1($t_wall); my $t_cpus = time_str1($t_cpu); print CPUOUT "$t_job_id\t$t_core\t$t_wall\t$t_walls\t$t_cpu\t$t_cpus\n"; } my $t_wall = ($max_end - $min_start); $t_wall = 0 unless ($t_wall>0); my $t_walls = time_str1($t_wall); my $sum_cpus= time_str1($sum_cpu); print CPUOUT "total\t-\t$t_wall\t$t_walls\t$sum_cpu\t$sum_cpus\n"; close(CPUOUT); } } ######### END task_log_cpu sub time_str1 { my $s = shift; my $str = ""; $str .= int($s/3600); $str .= "h"; $s = $s % 3600; $str .= int($s/60); $str .= "m"; $s = $s % 60; $str .= $s; $str .= "s"; return $str; } ########## END time_str1; sub usage { < $LOGf") || die "can not write to $LOGf"; my $f2 = "$dir/seq"; ################################################################################ #### Stage 0 ----------- clustering at 100% - stage 0 ################################################################################ my $clstr = "$f2.dup.clstr"; my $clstr2 = "$f2.dup2.clstr"; if ($restart_n <= 0) { nice_run("$cd_hit_dup -i $input -i2 $input2 -o $f2.dup -o2 $f2.dup.2 -u 100 -d 0 -m false -f $chimera_f > $f2.dup2.log"); nice_run("cat $f2.dup.clstr $f2.dup2.clstr > $f2-stage0.clstr.tmp"); nice_run("$script_dir/cd-hit/clstr_sort_by.pl < $f2-stage0.clstr.tmp > $f2-stage0.clstr; rm -f $f2-stage0.clstr.tmp"); nice_run("$script_dir/clstr_sort_rep.pl $f2-stage0.clstr $input > $f2-stage0-rep.fa"); # # /home/oasis/data/etc/git/cdhit/cd-hit-auxtools/cd-hit-dup -i qc/R1.fa -i2 qc/R2.fa -o otu/seq.dup -o2 otu/seq.dup.2 -u 100 -d 0 -f true > otu/seq.dup.log # no work # /home/oasis/data/etc/git/cdhit/cd-hit-auxtools/cd-hit-dup -i qc/R1.fa -i2 qc/R2.fa -o otu/seq.dup -o2 otu/seq.dup.2 -u 100 -d 0 > otu/seq.dup.log # # what if cd-hit-est # /home/oasis/data/etc/git/cdhit/cd-hit-est -i qc/R1.fa -j qc/R2.fa -o otu/seq.nr -op otu/seq.nr.2 -sf 1 -sc 1 -P 1 -r 0 -cx 100 -cy 100 -c 1.0 -n 10 -G 1 -b 1 -T 1 -M 8000 -d 0 -p 1 > otu/seq.nr.log # /home/oasis/data/etc/git/cdhit/cd-hit-est -i otu/seq.nr -o otu/seq.nr.R1 -r 0 -cx 100 -c 1.0 -n 10 -G 1 -b 1 -T 1 -M 8000 -d 0 -p 1 > otu/seq.nr.R1.log # /home/oasis/data/etc/git/cdhit/cd-hit-est -i otu/seq.nr.2 -o otu/seq.nr.R2 -r 0 -cx 100 -c 1.0 -n 10 -G 1 -b 1 -T 1 -M 8000 -d 0 -p 1 > otu/seq.nr.R2.log # /home/oasis/data/etc/git/cdhit/cd-hit-est -i otu/seq.nr -j otu/seq.nr.2 -o otu/seq.99 -op otu/seq.99.2 -P 1 -r 0 -cx 100 -cy 100 -c 0.99 -n 10 -G 1 -b 1 -T 1 -M 8000 -d 0 -p 1 > otu/seq.99.log # /home/oasis/data/etc/git/cdhit/cd-hit-est -i otu/seq.99 -j otu/seq.99.2 -o otu/seq.97 -op otu/seq.97.2 -P 1 -r 0 -cx 100 -cy 100 -c 0.97 -n 10 -G 1 -b 5 -T 1 -M 8000 -d 0 -p 1 > otu/seq.97.log # do not sort 99.clstr, always trust cd-hit-dup ordered sequences # /home/oasis/data/etc/git/cdhit/clstr_rev.pl otu/seq.nr.clstr otu/seq.99.clstr | /home/oasis/data/etc/git/cdhit/clstr_sort_by.pl > otu/seq.99-full.clstr # /home/oasis/data/etc/git/cdhit/clstr_rev.pl otu/seq.99-full.clstr otu/seq.97.clstr | /home/oasis/data/etc/git/cdhit/clstr_sort_by.pl > otu/seq.97-full.clstr # # combine ref # /home/oasis/data/etc/git/cdhit/cd-hit-est -i seq.99.wref.R1 -o seq.97.wref.R1only -r 0 -cx 100 -c 0.97 -n 10 -b 5 -T 1 -M 8000 -d 1 -p 1 -G 0 -A 50 -g 1 # } if (not $debug_mode) { my $no1 = count_seqs_from_fasta_file($input); my $no_clstr = count_clstrs_from_clstr_file($clstr); my $no_clstr2 = count_clstrs_from_clstr_file($clstr2); print LOG "Number_contigs\t$no1\n"; print LOG "Number_unique_contigs\t$no_clstr\n"; print LOG "Number_unique_chimaric_contigs\t$no_clstr2\n"; } ################################################################################ #### Stage 1 ---------- clustering at 99.25% #### distance 0.75% ################################################################################ my $seq_n = `grep -c "^>" $input`; $seq_n =~ s/\D//g; my $cutoff = int($seq_n * $abs_cutoff); my $c1 = 0.9925; if ($restart_n <= 1) { if ($fast_mode) { nice_run("$script_dir/cd-hit-auxtools/cd-hit-dup -i $f2-stage0-rep.fa -o $f2-stage1 -d 0 -m false -e 3 > $f2-stage1.log"); } else { nice_run("$script_dir/cd-hit/cd-hit-est -i $f2-stage0-rep.fa -o $f2-stage1 -c $c1 -n 10 -l 11 -p 1 -d 0 -g 1 -b 3 $cdhit_opt > $f2-stage1.log"); } nice_run("$script_dir/cd-hit/clstr_rev.pl $f2-stage0.clstr $f2-stage1.clstr | $script_dir/cd-hit/clstr_sort_by.pl > $f2-stage1-all.clstr"); nice_run("$script_dir/clstr_sort_rep.pl $f2-stage1-all.clstr $f2-stage1 > $f2-stage1-rep.fa"); } if (not $debug_mode) { $no_clstr = count_clstrs_from_clstr_file("$f2-stage1.clstr"); print LOG "Stage1 clustering at $c1\n"; print LOG "Number_clusters_stage1\t$no_clstr\n"; } ################################################################################ #### Stage 2 ---------- clustering at 98.50% #### distance 1.50% ################################################################################ $c1 = 0.985; if ($restart_n <= 2) { if ($fast_mode) { nice_run("$script_dir/cd-hit-auxtools/cd-hit-dup -i $f2-stage1-rep.fa -o $f2-stage2 -d 0 -m false -e 6 > $f2-stage2.log"); } else { nice_run("$script_dir/cd-hit/cd-hit-est -i $f2-stage1-rep.fa -o $f2-stage2 -c $c1 -n 10 -l 11 -p 1 -d 0 -g 1 -b 3 $cdhit_opt > $f2-stage2.log"); } nice_run("$script_dir/cd-hit/clstr_rev.pl $f2-stage1-all.clstr $f2-stage2.clstr | $script_dir/cd-hit/clstr_sort_by.pl > $f2-stage2-all.clstr"); nice_run("$script_dir/clstr_sort_rep.pl $f2-stage2-all.clstr $f2-stage2 > $f2-stage2-rep.fa"); } if (not $debug_mode) { $no_clstr = count_clstrs_from_clstr_file("$f2-stage2.clstr"); print LOG "Stage2 clustering at $c1\n"; print LOG "Number_clusters_stage2\t$no_clstr\n"; } ################################################################################ #### Stage pre-3 ---------- filtering ################################################################################ if ($restart_n <= 3) { nice_run("$script_dir/clstr_select_rep.pl size $cutoff 999999999 < $f2-stage2-all.clstr > $f2-stage2-rep-big.ids"); nice_run("$script_dir/fetch_fasta_by_ids.pl $f2-stage2-rep-big.ids $f2-stage2-rep.fa > $f2-stage2-rep-big.fa"); nice_run("$script_dir/fetch_fasta_exclude_ids.pl $f2-stage2-rep-big.ids $f2-stage2-rep.fa > $f2-stage2-rep-small.fa"); if (-s $clstr2) { nice_run("$script_dir/clstr_select_rep.pl size 1 999999999 < $clstr2 > $dir/chimaric.ids"); ## save chimaric ids nice_run("$script_dir/fetch_fasta_exclude_ids.pl $dir/chimaric.ids $f2-stage2-rep-big.fa > $f2-stage2-rep-big-good.fa"); ## exclude chimaric reads from $t1-pri-rep.fa nice_run("rm -f $f2-stage2-rep-big.fa"); nice_run("$script_dir/fetch_fasta_exclude_ids.pl $dir/chimaric.ids $f2-stage2-rep-small.fa > $f2-stage2-rep-small-good.fa"); nice_run("rm -f $f2-stage2-rep-small.fa"); } else { nice_run("mv $f2-stage2-rep-big.fa $f2-stage2-rep-big-good.fa"); nice_run("mv $f2-stage2-rep-small.fa $f2-stage2-rep-small-good.fa"); } } if (not $debug_mode) { print LOG "Min_clstr_size\t$cutoff\n"; my $no_seq = count_seqs_from_fasta_file("$f2-stage2-rep-big-good.fa"); print LOG "Number_clstrs_above_min_size\t$no_seq\n"; } ################################################################################ #### Stage 3 ---------- clustering at 97% ################################################################################ $c1 = $otu_cutoff; if ($restart_n <= 3) { nice_run("$script_dir/cd-hit/cd-hit-est -i $f2-stage2-rep-big-good.fa -o $f2-stage3 -c $c1 -n 8 -l 11 -p 1 -d 0 -g 1 -b 5 $cdhit_opt > $f2-stage3.log"); nice_run("$script_dir/cd-hit/clstr_rev.pl $f2-stage2-all.clstr $f2-stage3.clstr | $script_dir/cd-hit/clstr_sort_by.pl > $f2-stage3-all.clstr"); nice_run("$script_dir/clstr_sort_rep.pl $f2-stage3-all.clstr $f2-stage3 > $f2-stage3-rep.fa"); nice_run("mv -f $f2-stage3-all.clstr $dir/OTU.clstr"); nice_run("$script_dir/cd-hit-otu-table-faa.pl -i $dir/OTU.clstr -s $f2-stage3-rep.fa -o $dir/OTU-dist.txt -f $dir/OTU.fa"); } if (not $debug_mode) { $no_clstr = count_clstrs_from_clstr_file("$dir/OTU.clstr"); $no_seq = count_seqs_from_clstr_file("$dir/OTU.clstr"); print LOG "OTU clustering at $c1\n"; print LOG "Number_OTUs\t$no_clstr\n"; print LOG "Number_seqs_in_OTUs\t$no_seq\n"; my ($tu,$ts,$cu,$cs)=times(); my $tt=$tu+$ts+$cu+$cs; print LOG "Total_CPU_time\t$tt\n"; } close(LOG); sub usage { <" $clstr`; $n =~ s/\s//g; return $n; } sub count_seqs_from_clstr_file { my $clstr = shift; my $n = `grep -cv "^>" $clstr`; $n =~ s/\s//g; return $n; } sub count_seqs_from_fasta_file { my $faa = shift; my $n = `grep -c "^>" $faa`; $n =~ s/\s//g; return $n; } cdhit-4.6.8/usecases/Miseq-16S/clstr_2_OTU_table.pl000077500000000000000000000044451312257207200217020ustar00rootroot00000000000000#!/usr/bin/perl # use Getopt::Std; getopts("i:s:S:o:f:j:",\%opts); my $input = $opts{i}; $input = "OTU.clstr" unless $input; my $output = $opts{o}; $output = "OTU.txt" unless ($output); my ($i, $j, $k, $str, $cmd, $ll); my %count = (); my %count_t = (); my %count_s = (); my $OTU_2_ann = (); my $tree_flag = 0; #### for greengene header format # >4360486|k__Bacteria;.p__Firmicutes;.c__Clostridia;.o__Clostridiales;.f__Lachnospiraceae;.g__Roseburia;.s__faecis open(TMP, $input) || die "can not open $input"; my $OTU=0; while($ll=){ if ($ll =~ /^>/) { $OTU++; } else { chop($ll); if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { my $id = $2; if ($id =~ /^Sample\|([^\|]+)\|/) { $sample_id = $1; $sample_id{$sample_id}=1; $count{$OTU}{$sample_id}++; $count_t{$OTU}++; $count_s{$sample_id}++; } else { $OTU_2_ann{$OTU} = $id; $tree_flag = 1 if ($id =~ /\|k__Bacteria;.p__/); } } else { die "format error $ll"; } } } close(TMP); my @sample_ids = sort keys %sample_id; open(OUT1, "> $output") || die "can not write $output"; print OUT1 "OTU"; foreach $sample_id (@sample_ids){ print OUT1 "\t$sample_id"; } if ($tree_flag) { print OUT1 "\t", join("\t", qw/Kingdom Phylum Class Order Family Genus Species/); } #print OUT1 "\tTotal\n"; print OUT1 "\tAnnotation\n"; for ($i=1; $i<=$OTU; $i++){ $ann = "None"; if ($OTU_2_ann{$i}) { $ann = $OTU_2_ann{$i}; } print OUT1 "OTU$i"; foreach $sample_id (@sample_ids){ $k = $count{$i}{$sample_id}? $count{$i}{$sample_id} : 0; print OUT1 "\t$k"; } if ($tree_flag) { my ($tax_k, $tax_p, $tax_c, $tax_o, $tax_f, $tax_g, $tax_s); if ($ann =~ /k__(\w+)/) {$tax_k = $1} else {$tax_k = "";} if ($ann =~ /p__(\w+)/) {$tax_p = $1} else {$tax_p = "";} if ($ann =~ /c__(\w+)/) {$tax_c = $1} else {$tax_c = "";} if ($ann =~ /o__(\w+)/) {$tax_o = $1} else {$tax_o = "";} if ($ann =~ /f__(\w+)/) {$tax_f = $1} else {$tax_f = "";} if ($ann =~ /g__(\w+)/) {$tax_g = $1} else {$tax_g = "";} if ($ann =~ /s__(\w+)/) {$tax_s = $1} else {$tax_s = "";} print OUT1 "\t", join("\t", ($tax_k, $tax_p, $tax_c, $tax_o, $tax_f, $tax_g, $tax_s)); } #print OUT1 "\t$count_t{$i}"; print OUT1 "\t$ann\n"; } close(OUT1); cdhit-4.6.8/usecases/Miseq-16S/filter-chimeric-and-small.pl000077500000000000000000000142571312257207200233520ustar00rootroot00000000000000#!/usr/bin/perl use Getopt::Std; my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; chop($script_dir); $script_dir = "./" unless ($script_dir); getopts("k:i:j:o:p:c:s:t:m:e:Z:a:f:d:R:g:",\%opts); die usage() unless ($opts{k} and $opts{i} and $opts{j} and $opts{a} and $opts{f} and $opts{g} and $opts{o}); my $input0 = $opts{k}; ## nr.clstr my $input = $opts{i}; ## R1 only clstr my $input2 = $opts{j}; ## R2 only clstr my $clstr_99 = $opts{a}; ## seq.99.clstr #### can be any 2nd -preclustering e.g. 98.5% my $seq_99 = $opts{f}; ## seq.99 - fasta file R1 my $seq_992 = $opts{g}; ## seq.99 - fasta file R2 my $output = $opts{o}; ## seq.99f my $abs_cutoff = $opts{c}; $abs_cutoff = 0.0001 unless ($abs_cutoff); my $output_2 = "$output.2"; ## seq.99f.2 -- R2 my $output_cls = "$output.clstr"; ## seq.99f.clstr my $output_log = "$output.log"; ## seq.99f.log my ($i, $j, $k, $str, $cmd, $ll); my $num_total_seq; my %seq_nr_size; my %seqs_of_nr; open(LOG, "> $output_log") || die "can not open $output_log"; open(TMP, $input0) || die "can not open $input0"; if (1) { my $rep; while($ll=){ if ($ll =~ /^>/) { $rep = ""; } else { chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $num_total_seq++; if ($ll =~ /\*$/) { $rep=$id; $seq_nr_size{$rep}=0; $seqs_of_nr{$rep} = [];} $seq_nr_size{$rep}++ if ($rep); push(@{$seqs_of_nr{$rep}}, $id) if ($rep); } } } } close(TMP); my %seq_R1_clstr; my %seq_R2_clstr; foreach my $f (($input, $input2)) { open(TMP, $f) || die "can not open $f"; my $rep; while($ll=){ if ($ll =~ /^>/) { $rep = ""; } else { chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; if ($ll =~ /\*$/) { $rep=$id; } if ($rep) { if ($f eq $input) { $seq_R1_clstr{$id} = $rep;} else { $seq_R2_clstr{$id} = $rep;} } } } } close(TMP); } #### open $clstr_99 first time open(TMP, $clstr_99) || die "can not open $clstr_99"; %rep_2_otu = (); $OTU = -1; while($ll=){ if ($ll =~ /^>/) { $OTU++; } else { my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $rep_2_otu{$id} = $OTU; } } } close(TMP); my %chimeric_ids = (); #### those ids are candidates, if they are recurited by other non-chimeric clusters, #### then they are not chimeric anymore foreach $i (keys %seq_R1_clstr) { my $rep1 = $seq_R1_clstr{$i}; my $rep2 = $seq_R2_clstr{$i}; next if ($rep1 eq $rep2); next unless ($seq_nr_size{$rep1} >= $seq_nr_size{$i}*2); next unless ($seq_nr_size{$rep2} >= $seq_nr_size{$i}*2); my $OTU1 = $rep_2_otu{$rep1}; my $OTU2 = $rep_2_otu{$rep2}; next if ($OTU1 eq $OTU2); $chimeric_ids{$i} = 1; } #### parse seq.99.clstr my $cutoff_clstr_size = int($num_total_seq * $abs_cutoff); $cutoff_clstr_size = 1 unless ($cutoff_clstr_size >= 1); #### singleton will be removed #print LOG "cutoff_clstr_size\t$cutoff_clstr_size\n"; open(TMP, $clstr_99) || die "can not open $clstr_99"; open(OUT, "> $output_cls") || die "can not write to $output_cls"; my %good_ids = (); my @seqs_this_cls = (); if (1) { my $clstr_txt = ""; my $clstr_size = 0; my $rep; while($ll=){ if ($ll =~ /^>/) { if ($clstr_txt) { if (($clstr_size > $cutoff_clstr_size) and (not $chimeric_ids{$rep})) { print OUT $clstr_txt; $good_ids{$rep} = 1; } elsif ( $chimeric_ids{$rep} ) { foreach $j (@seqs_this_cls) { foreach $i ( @{ $seqs_of_nr{$j} } ) { print LOG "$i\tChimeric_cluster\t$rep\t$clstr_size\tP1:$seq_R1_clstr{$rep}\tP2:$seq_R2_clstr{$rep}\tOTU1:$rep_2_otu{$seq_R1_clstr{$rep}}\tOTU2:$rep_2_otu{$seq_R2_clstr{$rep}}\n"; } } } else { foreach $j (@seqs_this_cls) { foreach $i ( @{ $seqs_of_nr{$j} } ) { print LOG "$i\tSmall_cluster\t$rep\t$clstr_size\n"; } } } } $clstr_size = 0; $clstr_txt = $ll; $rep = ""; @seqs_this_cls=(); } else { $clstr_txt .= $ll; chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $clstr_size += $seq_nr_size{$id}; $rep=$id if ($ll =~ /\*$/); push(@seqs_this_cls, $id); } } } if ($clstr_txt) { if (($clstr_size > $cutoff_clstr_size) and (not $chimeric_ids{$rep})) { print OUT $clstr_txt; $good_ids{$rep} = 1; } elsif ( $chimeric_ids{$rep} ) { foreach $j (@seqs_this_cls) { foreach $i ( @{ $seqs_of_nr{$j} } ) { print LOG "$i\tChimeric_cluster\t$rep\t$clstr_size\tP1:$seq_R1_clstr{$rep}\tP2:$seq_R2_clstr{$rep}\tOTU1:$rep_2_otu{$seq_R1_clstr{$rep}}\tOTU2:$rep_2_otu{$seq_R2_clstr{$rep}}\n"; } } } else { foreach $j (@seqs_this_cls) { foreach $i ( @{ $seqs_of_nr{$j} } ) { print LOG "$i\tSmall_cluster\t$rep\t$clstr_size\n"; } } } } } close(TMP); close(OUT); foreach my $f (($seq_99, $seq_992)) { my $fout = ($f eq $seq_99) ? $output : $output_2; open(TMP, $f) || die "can not open $f"; open(OUT, ">$fout") || die "can not write to $fout"; my $flag = 0; while($ll = ) { if ($ll =~ /^>/) { $gi = substr($ll,1); chop($gi); $gi =~ s/\s.+$//; $flag = ( $good_ids{$gi} ) ? 1 : 0; } print OUT $ll if ($flag); } close(TMP); close(OUT); } close(LOG); sub usage { < $output_log") || die "can not open $output_log"; open(TMP, $clstr_99) || die "can not open $clstr_99"; if (1) { my $rep; while($ll=){ if ($ll =~ /^>/) { $rep = ""; } else { chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $num_total_seq++ if ($id =~ /^Sample/); if ($ll =~ /\*$/) { $rep=$id; $seq_nr_size{$rep}=0; $seqs_of_rep{$rep} = [];} $seq_nr_size{$rep}++ if ($rep); push(@{$seqs_of_rep{$rep}}, $id) if ($rep); } } } } close(TMP); my %seq_R1_clstr; my %seq_R2_clstr; foreach my $f (($input, $input2)) { open(TMP, $f) || die "can not open $f"; my $rep; while($ll=){ if ($ll =~ /^>/) { $rep = ""; } else { chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; if ($ll =~ /\*$/) { $rep=$id; } if ($rep and ($id =~ /^Sample/) ) { if ($f eq $input) { $seq_R1_clstr{$id} = $rep;} else { $seq_R2_clstr{$id} = $rep;} } } } } close(TMP); } my $cutoff_clstr_size = int($num_total_seq * $abs_cutoff); $cutoff_clstr_size = 1 unless ($cutoff_clstr_size >= 1); #print LOG "cutoff_clstr_size\t$cutoff_clstr_size\n"; my %chimeric_ids = (); #### those ids are candidates, if they are recurited by other non-chimeric clusters, #### then they are not chimeric anymore foreach $i (keys %seq_nr_size) { next unless ($i =~ /^Sample/); my $rep1 = $seq_R1_clstr{$i}; my $rep2 = $seq_R2_clstr{$i}; next unless ($rep1 and $rep2); next if ($rep1 eq $rep2); next if ($rep1 eq $i); next if ($rep2 eq $i); next if ($seq_nr_size{$i} > $cutoff_clstr_size); if (defined($seq_nr_size{$rep1})) { next unless ($seq_nr_size{$rep1} >= $seq_nr_size{$i}*2); } if (defined($seq_nr_size{$rep2})) { next unless ($seq_nr_size{$rep2} >= $seq_nr_size{$i}*2); } $chimeric_ids{$i} = 1; } #### parse seq.97fwref.clstr #### do chimeric checking for sample-only clusters open(TMP, $clstr_99) || die "can not open $clstr_99"; open(OUT, "> $output_cls") || die "can not write to $output_cls"; my %good_ids = (); if (1) { my $clstr_txt = ""; my $clstr_size = 0; my $rep; my $refonly = 1; while($ll=){ if ($ll =~ /^>/) { if ($clstr_txt) { if ( not $refonly ) { if (not $chimeric_ids{$rep}) { print OUT $clstr_txt; $good_ids{$rep} = 1; } elsif ( $chimeric_ids{$rep} ) { foreach $i ( @{ $seqs_of_rep{$rep} }) { print LOG "Chimeric_cluster\t$i\t$rep\t$clstr_size\tP1:$seq_R1_clstr{$rep}\tP2:$seq_R2_clstr{$rep}\n"; } } } } $clstr_size = 0; $clstr_txt = $ll; $rep = ""; $refonly = 1; } else { $clstr_txt .= $ll; chop($ll); my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $clstr_size++; $rep=$id if ($ll =~ /\*$/); $refonly = 0 if ($id =~ /^Sample/); } } } if ($clstr_txt) { if ( not $refonly ) { if (not $chimeric_ids{$rep}) { print OUT $clstr_txt; $good_ids{$rep} = 1; } elsif ( $chimeric_ids{$rep} ) { foreach $i ( @{ $seqs_of_rep{$rep} }) { print LOG "Chimeric_cluster\t$i\t$rep\t$clstr_size\tP1:$seq_R1_clstr{$rep}\tP2:$seq_R2_clstr{$rep}\n"; } } } } } close(TMP); close(OUT); foreach my $f (($seq_99, $seq_992)) { my $fout = ($f eq $seq_99) ? $output : $output_2; open(TMP, $f) || die "can not open $f"; open(OUT, ">$fout") || die "can not write to $fout"; my $flag = 0; while($ll = ) { if ($ll =~ /^>/) { $gi = substr($ll,1); chop($gi); $gi =~ s/\s.+$//; $flag = ( $good_ids{$gi} ) ? 1 : 0; } print OUT $ll if ($flag); } close(TMP); close(OUT); } close(LOG); sub usage { <){ if ($ll =~ /^>/) { if ($clstr) { print $clstr; print $best_ref if ($best_ref); } $clstr = $ll; $best_ref = ""; $best_score = 0; } else { if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { my $id = $2; if ($id =~ /^Sample/) { $clstr .= $ll; } elsif ( $ll =~ /\/([\d|\.]+)%$/) { my $iden = $1; if ($iden > $best_score) { $best_score = $iden; $best_ref = $ll; } } } else { print STDERR "format err: $ll"; } } } if ($clstr) { print $clstr; print $best_ref if ($best_ref); } cdhit-4.6.8/usecases/Miseq-16S/filter-refonly-cluster.pl000077500000000000000000000011211312257207200230400ustar00rootroot00000000000000#!/usr/bin/perl use Getopt::Std; my $script_name = $0; my $script_dir = $0; $script_dir =~ s/[^\/]+$//; chop($script_dir); $script_dir = "./" unless ($script_dir); my ($i, $j, $k, $str, $cmd, $ll); my $num_total_seq; my %seq_nr_size; if (1) { my $clstr = ""; my $refonly = 1; while($ll=<>){ if ($ll =~ /^>/) { print $clstr unless ($refonly); $clstr = $ll; $refonly = 1; } else { $clstr .= $ll; my $id; if ($ll =~ /\d+(aa|nt), >(.+)\.\.\./) { $id = $2; $refonly = 0 if ($id =~ /^Sample/); } } } } cdhit-4.6.8/usecases/Miseq-16S/greengene-ann1.pl000077500000000000000000000041721312257207200212230ustar00rootroot00000000000000#!/usr/bin/perl ## =========================== NGS tools ========================================== ## NGS tools for metagenomic sequence analysis ## May also be used for other type NGS data analysis ## ## Weizhong Li, UCSD ## liwz@sdsc.edu ## http://weizhongli-lab.org/ ## ================================================================================ use Getopt::Std; getopts("i:j:o:r:e:p:q:c:d:N:t:u:d:M:T:S:",\%opts); die usage() unless ($opts{i} and $opts{j} and $opts{o}); my ($i, $j, $k, $cmd); my ($ll, $lla, $llb, $id, $ida, $idb, $seq, $seqa, $seqb, $qua, $quaa, $quab); my ($len, $lena, $lenb); my $file1 = $opts{i}; my $fasta = $opts{j}; my $output = $opts{o}; my %id_2_ann; open(TMP, $file1) || die "can not open $file1"; while($ll=){ chop($ll); my ($id, $txt) = split(/\s+/, $ll, 2); $txt =~ s/ /./g; $id_2_ann{$id} = $txt; } close(TMP); my %id_2_seq = (); my $id = ""; open(TMP, $fasta) || die "can not open $fasta"; while($ll=){ if ($ll =~ /^>(\d+)/) { chop($ll); $id = $1; $ann = $id_2_ann{$id}; $id = "$id|$ann" if ($ann); } else { $id_2_seq{$id} .= $ll; } } close(TMP); my @ids = keys %id_2_seq; @ids = sort {length($b) <=> length($a) } @ids; open(OUT, "> $output") || die "can not write to $output"; foreach $id (@ids) { print OUT ">$id\n$id_2_seq{$id}"; } close(OUT); sub usage { <){ next if ($ll =~ /^#/); next unless ($ll =~ /^\w/); chop($ll); my ($id, @data) = split(/\s+/,$ll); push(@NGS_samples, $id); } close(TMP); } elsif (defined($sample_command_in)) { my @lls = split(/,/, $sample_command_in); foreach $ll (@lls) { my ($id, @data) = split(/:/, $ll); push(@NGS_samples, $id); } } else { die "no input samples"; } foreach $i (@file_list) { my $target = "$output/$i"; foreach $j (@NGS_samples) { my $source = "$j/$job/$i"; if (-e $source) { print STDERR "cat $source >> $target\n"; $cmd = `cat $source >> $target`; } else { print STDERR "Warning, $source missing\n"; } } } sub usage { <