$stringtoclean =~ s/%3d/=/g;
	$stringtoclean =~ s/&/&/g;
	$stringtoclean =~ s/<//g;
	$stringtoclean =~ s/"/\"/g;
	$stringtoclean =~ s/'/\'/g;
	return $stringtoclean;
}
#------------------------------------------------------------------------------
# Function:     Copy one file into another
# Parameters:   sourcefilename targetfilename
# Input:        None
# Output:       None
# Return:		0 if copy is ok, 1 else
#------------------------------------------------------------------------------
sub FileCopy {
	my $filesource = shift;
	my $filetarget = shift;
	if ($Debug) { debug( "FileCopy($filesource,$filetarget)", 1 ); }
	open( FILESOURCE, "$filesource" )  || return 1;
	open( FILETARGET, ">$filetarget" ) || return 1;
	binmode FILESOURCE;
	binmode FILETARGET;
	# ...
	close(FILETARGET);
	close(FILESOURCE);
	if ($Debug) { debug( " File copied", 1 ); }
	return 0;
}
#------------------------------------------------------------------------------
# Function:     Format a QUERY_STRING
# Parameters:   query
# Input:        None
# Output:       None
# Return:		formatted query
#------------------------------------------------------------------------------
# TODO Appeller cette fonction partout ou il y a des NewLinkParams
sub CleanNewLinkParamsFrom {
	my $NewLinkParams = shift;
	while ( my $param = shift ) {
		$NewLinkParams =~ s/(^|&|&)$param(=[^&]*|$)//i;
	}
	$NewLinkParams =~ s/(&|&)+/&/i;
	$NewLinkParams =~ s/^&//;
	$NewLinkParams =~ s/&$//;
	return $NewLinkParams;
}
#------------------------------------------------------------------------------
# Function:     Show flags for other language translations
# Parameters:   Current languade id (en, fr, ...)
# Input:        None
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub Show_Flag_Links {
	my $CurrentLang = shift;
	# Build flags link
	my $NewLinkParams = $QueryString;
	my $NewLinkTarget = '';
	if ( $ENV{'GATEWAY_INTERFACE'} ) {
		$NewLinkParams =
		  CleanNewLinkParamsFrom( $NewLinkParams,
			( 'update', 'staticlinks', 'framename', 'lang' ) );
		$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
		$NewLinkParams =~ s/(^|&|&)lang=[^&]*//i;
		$NewLinkParams =~ s/(&|&)+/&/i;
		$NewLinkParams =~ s/^&//;
		$NewLinkParams =~ s/&$//;
		if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
		if ( $FrameName eq 'mainright' ) {
			$NewLinkTarget = " target=\"_parent\"";
		}
	}
	else {
		$NewLinkParams =
		  ( $SiteConfig ? "config=$SiteConfig&" : "" )
		  . "year=$YearRequired&month=$MonthRequired&";
	}
	if ( $NewLinkParams !~ /output=/ ) { $NewLinkParams .= 'output=main&'; }
	if ( $FrameName eq 'mainright' ) {
		$NewLinkParams .= 'framename=index&';
	}
	foreach my $lng ( split( /\s+/, $ShowFlagLinks ) ) {
		$lng =
		    $LangBrowserToLangAwstats{$lng}
		  ? $LangBrowserToLangAwstats{$lng}
		  : $lng;
		if ( $lng ne $CurrentLang ) {
			my %lngtitle = (
				'en', 'English', 'fr', 'French', 'de', 'German',
				'it', 'Italian', 'nl', 'Dutch',  'es', 'Spanish'
			);
			my $lngtitle = ( $lngtitle{$lng} ? $lngtitle{$lng} : $lng );
			my $flag = (
				  $LangAWStatsToFlagAwstats{$lng}
				? $LangAWStatsToFlagAwstats{$lng}
				: $lng
			);
			print "
 \n";
		}
	}
}
#------------------------------------------------------------------------------
# Function:		Format value in bytes in a string (Bytes, Kb, Mb, Gb)
# Parameters:   bytes (integer value or "0.00")
# Input:        None
# Output:       None
# Return:       "x.yz MB" or "x.yy KB" or "x Bytes" or "0"
#------------------------------------------------------------------------------
sub Format_Bytes {
	my $bytes = shift || 0;
	my $fudge = 1;
# Do not use exp/log function to calculate 1024power, function make segfault on some unix/perl versions
	if ( $bytes >= ( $fudge << 40 ) ) {
		return sprintf( "%.2f", $bytes / 1099511627776 ) . " $Message[179]";
	}
	if ( $bytes >= ( $fudge << 30 ) ) {
		return sprintf( "%.2f", $bytes / 1073741824 ) . " $Message[110]";
	}
	if ( $bytes >= ( $fudge << 20 ) ) {
		return sprintf( "%.2f", $bytes / 1048576 ) . " $Message[109]";
	}
	if ( $bytes >= ( $fudge << 10 ) ) {
		return sprintf( "%.2f", $bytes / 1024 ) . " $Message[108]";
	}
	if ( $bytes < 0 ) { $bytes = "?"; }
	return int($bytes) . ( int($bytes) ? " $Message[119]" : "" );
}
#------------------------------------------------------------------------------
# Function:		Format a number with commas or any other separator
#				CL: courtesy of http://www.perlmonks.org/?node_id=2145
# Parameters:   number
# Input:        None
# Output:       None
# Return:       "999,999,999,999"
#------------------------------------------------------------------------------
sub Format_Number {
	my $number = shift || 0;
	$number =~ s/(\d)(\d\d\d)$/$1 $2/;
	$number =~ s/(\d)(\d\d\d\s\d\d\d)$/$1 $2/;
	$number =~ s/(\d)(\d\d\d\s\d\d\d\s\d\d\d)$/$1 $2/;
	my $separator = $Message[177];
	if ($separator eq '') { $separator=' '; }	# For backward compatibility
	$number =~ s/ /$separator/g;
	return $number;
}
#------------------------------------------------------------------------------
# Function:		Return " alt=string title=string"
# Parameters:   string
# Input:        None
# Output:       None
# Return:       "alt=string title=string"
#------------------------------------------------------------------------------
sub AltTitle {
	my $string = shift || '';
	return " alt='$string' title='$string'";
	#	return " alt=\"$string\" title=\"$string\"";
	#	return ($BuildReportFormat?"":" alt=\"$string\"")." title=\"$string\"";
}
#------------------------------------------------------------------------------
# Function:		Tell if an email is a local or external email
# Parameters:   email
# Input:        $SiteDomain(exact string) $HostAliases(quoted regex string)
# Output:       None
# Return:       -1, 0 or 1
#------------------------------------------------------------------------------
sub IsLocalEMail {
	my $email = shift || 'unknown';
	if ( $email !~ /\@(.*)$/ ) { return 0; }
	my $domain = $1;
	if ( $domain =~ /^$SiteDomain$/i ) { return 1; }
	foreach (@HostAliases) {
		if ( $domain =~ /$_/ ) { return 1; }
	}
	return -1;
}
#------------------------------------------------------------------------------
# Function:		Format a date according to Message[78] (country date format)
# Parameters:   String date YYYYMMDDHHMMSS
#               Option 0=LastUpdate and LastTime date
#                      1=Arrays date except daymonthvalues
#                      2=daymonthvalues date (only year month and day)
# Input:        $Message[78]
# Output:       None
# Return:       Date with format defined by Message[78] and option
#------------------------------------------------------------------------------
sub Format_Date {
	my $date       = shift;
	my $option     = shift || 0;
	my $year       = substr( "$date", 0, 4 );
	my $month      = substr( "$date", 4, 2 );
	my $day        = substr( "$date", 6, 2 );
	my $hour       = substr( "$date", 8, 2 );
	my $min        = substr( "$date", 10, 2 );
	my $sec        = substr( "$date", 12, 2 );
	my $dateformat = $Message[78];
	if ( $option == 2 ) {
		$dateformat =~ s/^[^ymd]+//g;
		$dateformat =~ s/[^ymd]+$//g;
	}
	$dateformat =~ s/yyyy/$year/g;
	$dateformat =~ s/yy/$year/g;
	$dateformat =~ s/mmm/$MonthNumLib{$month}/g;
	$dateformat =~ s/mm/$month/g;
	$dateformat =~ s/dd/$day/g;
	$dateformat =~ s/HH/$hour/g;
	$dateformat =~ s/MM/$min/g;
	$dateformat =~ s/SS/$sec/g;
	return "$dateformat";
}
#------------------------------------------------------------------------------
# Function:     Return 1 if string contains only ascii chars
# Parameters:   string
# Input:        None
# Output:       None
# Return:       0 or 1
#------------------------------------------------------------------------------
sub IsAscii {
	my $string = shift;
	if ($Debug) { debug( "IsAscii($string)", 5 ); }
	if ( $string =~ /^[\w\+\-\/\\\.%,;:=\"\'&?!\s]+$/ ) {
		if ($Debug) { debug( " Yes", 6 ); }
		return
		  1
		  ; # Only alphanum chars (and _) or + - / \ . % , ; : = " ' & ? space \t
	}
	if ($Debug) { debug( " No", 6 ); }
	return 0;
}
#------------------------------------------------------------------------------
# Function:     Return the lower value between 2 but exclude value if 0
# Parameters:   Val1 and Val2
# Input:        None
# Output:       None
# Return:       min(Val1,Val2)
#------------------------------------------------------------------------------
sub MinimumButNoZero {
	my ( $val1, $val2 ) = @_;
	return ( $val1 && ( $val1 < $val2 || !$val2 ) ? $val1 : $val2 );
}
#------------------------------------------------------------------------------
# Function:     Add a val from sorting tree
# Parameters:   keytoadd keyval [firstadd]
# Input:        None
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub AddInTree {
	my $keytoadd = shift;
	my $keyval   = shift;
	my $firstadd = shift || 0;
	if ( $firstadd == 1 ) {    # Val is the first one
		if ($Debug) { debug( "  firstadd", 4 ); }
		$val{$keyval} = $keytoadd;
		$lowerval = $keyval;
		if ($Debug) {
			debug(
				"  lowerval=$lowerval, nb elem val="
				  . ( scalar keys %val )
				  . ", nb elem egal="
				  . ( scalar keys %egal ) . ".",
				4
			);
		}
		return;
	}
	if ( $val{$keyval} ) {    # Val is already in tree
		if ($Debug) { debug( "  val is already in tree", 4 ); }
		$egal{$keytoadd} = $val{$keyval};
		$val{$keyval}    = $keytoadd;
		if ($Debug) {
			debug(
				"  lowerval=$lowerval, nb elem val="
				  . ( scalar keys %val )
				  . ", nb elem egal="
				  . ( scalar keys %egal ) . ".",
				4
			);
		}
		return;
	}
	if ( $keyval <= $lowerval )
	{    # Val is a new one lower (should happens only when tree is not full)
		if ($Debug) {
			debug(
"  keytoadd val=$keyval is lower or equal to lowerval=$lowerval",
				4
			);
		}
		$val{$keyval}     = $keytoadd;
		$nextval{$keyval} = $lowerval;
		$lowerval         = $keyval;
		if ($Debug) {
			debug(
				"  lowerval=$lowerval, nb elem val="
				  . ( scalar keys %val )
				  . ", nb elem egal="
				  . ( scalar keys %egal ) . ".",
				4
			);
		}
		return;
	}
	# Val is a new one higher
	if ($Debug) {
		debug( "  keytoadd val=$keyval is higher than lowerval=$lowerval", 4 );
	}
	$val{$keyval} = $keytoadd;
	my $valcursor = $lowerval;    # valcursor is value just before keyval
	while ( $nextval{$valcursor} && ( $nextval{$valcursor} < $keyval ) ) {
		$valcursor = $nextval{$valcursor};
	}
	if ( $nextval{$valcursor} )
	{    # keyval is between valcursor and nextval{valcursor}
		$nextval{$keyval} = $nextval{$valcursor};
	}
	$nextval{$valcursor} = $keyval;
	if ($Debug) {
		debug(
			"  lowerval=$lowerval, nb elem val="
			  . ( scalar keys %val )
			  . ", nb elem egal="
			  . ( scalar keys %egal ) . ".",
			4
		);
	}
}
#------------------------------------------------------------------------------
# Function:     Remove a val from sorting tree
# Parameters:   None
# Input:        $lowerval %val %egal
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub Removelowerval {
	my $keytoremove = $val{$lowerval};    # This is lower key
	if ($Debug) {
		debug( "   remove for lowerval=$lowerval: key=$keytoremove", 4 );
	}
	if ( $egal{$keytoremove} ) {
		$val{$lowerval} = $egal{$keytoremove};
		delete $egal{$keytoremove};
	}
	else {
		delete $val{$lowerval};
		$lowerval = $nextval{$lowerval};    # Set new lowerval
	}
	if ($Debug) {
		debug(
			"   new lower value=$lowerval, val size="
			  . ( scalar keys %val )
			  . ", egal size="
			  . ( scalar keys %egal ),
			4
		);
	}
}
#------------------------------------------------------------------------------
# Function:     Build @keylist array
# Parameters:   Size max for @keylist array,
#               Min value in hash for select,
#               Hash used for select,
#               Hash used for order
# Input:        None
# Output:       None
# Return:       @keylist response array
#------------------------------------------------------------------------------
sub BuildKeyList {
	my $ArraySize = shift || error(
"System error. Call to BuildKeyList function with incorrect value for first param",
		"", "", 1
	);
	my $MinValue = shift || error(
"System error. Call to BuildKeyList function with incorrect value for second param",
		"", "", 1
	);
	my $hashforselect = shift;
	my $hashfororder  = shift;
	if ($Debug) {
		debug(
			"  BuildKeyList($ArraySize,$MinValue,$hashforselect with size="
			  . ( scalar keys %$hashforselect )
			  . ",$hashfororder with size="
			  . ( scalar keys %$hashfororder ) . ")",
			3
		);
	}
	delete $hashforselect->{0};
	delete $hashforselect->{ ''
	  }; # Those is to protect from infinite loop when hash array has an incorrect null key
	my $count = 0;
	$lowerval = 0;    # Global because used in AddInTree and Removelowerval
	%val      = ();
	%nextval  = ();
	%egal     = ();
	foreach my $key ( keys %$hashforselect ) {
		if ( $count < $ArraySize ) {
			if ( $hashforselect->{$key} >= $MinValue ) {
				$count++;
				if ($Debug) {
					debug(
						"  Add in tree entry $count : $key (value="
						  . ( $hashfororder->{$key} || 0 )
						  . ", tree not full)",
						4
					);
				}
				AddInTree( $key, $hashfororder->{$key} || 0, $count );
			}
			next;
		}
		$count++;
		if ( ( $hashfororder->{$key} || 0 ) <= $lowerval ) { next; }
		if ($Debug) {
			debug(
				"  Add in tree entry $count : $key (value="
				  . ( $hashfororder->{$key} || 0 )
				  . " > lowerval=$lowerval)",
				4
			);
		}
		AddInTree( $key, $hashfororder->{$key} || 0 );
		if ($Debug) { debug( "  Removelower in tree", 4 ); }
		Removelowerval();
	}
	# Build key list and sort it
	if ($Debug) {
		debug(
			"  Build key list and sort it. lowerval=$lowerval, nb elem val="
			  . ( scalar keys %val )
			  . ", nb elem egal="
			  . ( scalar keys %egal ) . ".",
			3
		);
	}
	my %notsortedkeylist = ();
	foreach my $key ( values %val )  { $notsortedkeylist{$key} = 1; }
	foreach my $key ( values %egal ) { $notsortedkeylist{$key} = 1; }
	@keylist = ();
	@keylist = (
		sort { ( $hashfororder->{$b} || 0 ) <=> ( $hashfororder->{$a} || 0 ) }
		  keys %notsortedkeylist
	);
	if ($Debug) {
		debug( "  BuildKeyList End (keylist size=" . (@keylist) . ")", 3 );
	}
	return;
}
#------------------------------------------------------------------------------
# Function:     Lock or unlock update
# Parameters:   status (1 to lock, 0 to unlock)
# Input:        $DirLock (if status=0) $PROG $FileSuffix
# Output:       $DirLock (if status=1)
# Return:       None
#------------------------------------------------------------------------------
sub Lock_Update {
	my $status = shift;
	my $lock   = "$PROG$FileSuffix.lock";
	if ($status) {
		# We stop if there is at least one lock file wherever it is
		foreach my $key ( $ENV{"TEMP"}, $ENV{"TMP"}, "/tmp", "/", "." ) {
			my $newkey = $key;
			$newkey =~ s/[\\\/]$//;
			if ( -f "$newkey/$lock" ) {
				error(
"An AWStats update process seems to be already running for this config file. Try later.\nIf this is not true, remove manually lock file '$newkey/$lock'.",
					"", "", 1
				);
			}
		}
		# Set lock where we can
		foreach my $key ( $ENV{"TEMP"}, $ENV{"TMP"}, "/tmp", "/", "." ) {
			if ( !-d "$key" ) { next; }
			$DirLock = $key;
			$DirLock =~ s/[\\\/]$//;
			if ($Debug) { debug("Update lock file $DirLock/$lock is set"); }
			open( LOCK, ">$DirLock/$lock" )
			  || error( "Failed to create lock file $DirLock/$lock", "", "",
				1 );
			print LOCK
"AWStats update started by process $$ at $nowyear-$nowmonth-$nowday $nowhour:$nowmin:$nowsec\n";
			close(LOCK);
			last;
		}
	}
	else {
		# Remove lock
		if ($Debug) { debug("Update lock file $DirLock/$lock is removed"); }
		unlink("$DirLock/$lock");
	}
	return;
}
#------------------------------------------------------------------------------
# Function:     Signal handler to call Lock_Update to remove lock file
# Parameters:   Signal name
# Input:        None
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub SigHandler {
	my $signame = shift;
	print ucfirst($PROG) . " process (ID $$) interrupted by signal $signame.\n";
	&Lock_Update(0);
	exit 1;
}
#------------------------------------------------------------------------------
# Function:     Convert an IPAddress into an integer
# Parameters:   IPAddress
# Input:        None
# Output:       None
# Return:       Int
#------------------------------------------------------------------------------
sub Convert_IP_To_Decimal {
	my ($IPAddress) = @_;
	my @ip_seg_arr = split( /\./, $IPAddress );
	my $decimal_ip_address =
	  256 * 256 * 256 * $ip_seg_arr[0] + 256 * 256 * $ip_seg_arr[1] + 256 *
	  $ip_seg_arr[2] + $ip_seg_arr[3];
	return ($decimal_ip_address);
}
#------------------------------------------------------------------------------
# Function:     Test there is at least one value in list not null
# Parameters:   List of values
# Input:        None
# Output:       None
# Return:       1 There is at least one not null value, 0 else
#------------------------------------------------------------------------------
sub AtLeastOneNotNull {
	if ($Debug) {
		debug( " Call to AtLeastOneNotNull (" . join( '-', @_ ) . ")", 3 );
	}
	foreach my $val (@_) {
		if ($val) { return 1; }
	}
	return 0;
}
#------------------------------------------------------------------------------
# Function:     Prints the command line interface help information
# Parameters:   None
# Input:        None
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub PrintCLIHelp{
	&Read_Ref_Data(
		'browsers',       'domains', 'operating_systems', 'robots',
		'search_engines', 'worms'
	);
	print "----- $PROG $VERSION (c) 2000-2018 Laurent Destailleur -----\n";
	print
"AWStats is a free web server logfile analyzer to show you advanced web\n";
	print "statistics.\n";
	print
"AWStats comes with ABSOLUTELY NO WARRANTY. It's a free software distributed\n";
	print "with a GNU General Public License (See LICENSE file for details).\n";
	print "\n";
	print "Syntax: $PROG.$Extension -config=virtualhostname [options]\n";
	print "\n";
	print
"  This runs $PROG in command line to update statistics (-update option) of a\n";
	print
"   web site, from the log file defined in AWStats config file, or build a HTML\n";
	print "   report (-output option).\n";
	print
"  First, $PROG tries to read $PROG.virtualhostname.conf as the config file.\n";
	print "  If not found, $PROG tries to read $PROG.conf, and finally the full path passed to -config=\n";
	print
"  Note 1: Config files ($PROG.virtualhostname.conf or $PROG.conf) must be\n";
	print
"   in /etc/awstats, /usr/local/etc/awstats, /etc or same directory than\n";
	print "   awstats.pl script file.\n";
	print
"  Note 2: If AWSTATS_FORCE_CONFIG environment variable is defined, AWStats will\n";
	print
"   use it as the \"config\" value, whatever is the value on command line or URL.\n";
	print "   See AWStats documentation for all setup instrutions.\n";
	print "\n";
	print "Options to update statistics:\n";
	print "  -update        to update statistics (default)\n";
	print
"  -showsteps     to add benchmark information every $NBOFLINESFORBENCHMARK lines processed\n";
	print
"  -showcorrupted to add output for each corrupted lines found, with reason\n";
	print
"  -showdropped   to add output for each dropped lines found, with reason\n";
	print "  -showunknownorigin  to output referer when it can't be parsed\n";
	print
"  -showdirectorigin   to output log line when origin is a direct access\n";
	print "  -updatefor=n   to stop the update process after parsing n lines\n";
	print
"  -LogFile=x     to change log to analyze whatever is 'LogFile' in config file\n";
	print
"  Be care to process log files in chronological order when updating statistics.\n";
	print "\n";
	print "Options to show statistics:\n";
	print
"  -output      to output main HTML report (no update made except with -update)\n";
	print "  -output=x    to output other report pages where x is:\n";
	print
"               alldomains       to build page of all domains/countries\n";
	print "               allhosts         to build page of all hosts\n";
	print
	  "               lasthosts        to build page of last hits for hosts\n";
	print
	  "               unknownip        to build page of all unresolved IP\n";
	print
"               allemails        to build page of all email senders (maillog)\n";
	print
"               lastemails       to build page of last email senders (maillog)\n";
	print
"               allemailr        to build page of all email receivers (maillog)\n";
	print
"               lastemailr       to build page of last email receivers (maillog)\n";
	print "               alllogins        to build page of all logins used\n";
	print
	  "               lastlogins       to build page of last hits for logins\n";
	print
"               allrobots        to build page of all robots/spider visits\n";
	print
	  "               lastrobots       to build page of last hits for robots\n";
	print "               urldetail        to list most often viewed pages \n";
	print
"               urldetail:filter to list most often viewed pages matching filter\n";
	print "               urlentry         to list entry pages\n";
	print
	  "               urlentry:filter  to list entry pages matching filter\n";
	print "               urlexit          to list exit pages\n";
	print
	  "               urlexit:filter   to list exit pages matching filter\n";
	print
"               osdetail         to build page with os detailed versions\n";
	print
"               browserdetail    to build page with browsers detailed versions\n";
	print
"               unknownbrowser   to list 'User Agents' with unknown browser\n";
	print
	  "               unknownos        to list 'User Agents' with unknown OS\n";
	print
"               refererse        to build page of all refering search engines\n";
	print
	  "               refererpages     to build page of all refering pages\n";
 #print "               referersites     to build page of all refering sites\n";
	print
"               keyphrases       to list all keyphrases used on search engines\n";
	print
"               keywords         to list all keywords used on search engines\n";
	print "               errors404        to list 'Referers' for 404 errors\n";
	print
"               allextraX        to build page of all values for ExtraSection X\n";
	print "  -staticlinks           to have static links in HTML report page\n";
	print "  -staticlinksext=xxx    to have static links with .xxx extension instead of .html\n";
	print
"  -lang=LL     to output a HTML report in language LL (en,de,es,fr,it,nl,...)\n";
	print "  -month=MM    to output a HTML report for an old month MM\n";
	print "  -year=YYYY   to output a HTML report for an old year YYYY\n";
	print
"  The 'date' options doesn't allow you to process old log file. They only\n";
	print
"  allow you to see a past report for a chosen month/year period instead of\n";
	print "  current month/year.\n";
	print "\n";
	print "Other options:\n";
	print
"  -debug=X     to add debug informations lesser than level X (speed reduced)\n";
	print
"  -version     show AWStats version\n";
	print "\n";
	print "Now supports/detects:\n";
	print
"  Web/Ftp/Mail/streaming server log analyzis (and load balanced log files)\n";
	print "  Reverse DNS lookup (IPv4 and IPv6) and GeoIP lookup\n";
	print "  Number of visits, number of unique visitors\n";
	print "  Visits duration and list of last visits\n";
	print "  Authenticated users\n";
	print "  Days of week and rush hours\n";
	print "  Hosts list and unresolved IP addresses list\n";
	print "  Most viewed, entry and exit pages\n";
	print "  Files type and Web compression (mod_gzip, mod_deflate stats)\n";
	print "  Screen size\n";
	print "  Ratio of Browsers with support of: Java, Flash, RealG2 reader,\n";
	print "                        Quicktime reader, WMA reader, PDF reader\n";
	print "  Configurable personalized reports\n";
	print "  " . ( scalar keys %DomainsHashIDLib ) . " domains/countries\n";
	print "  " . ( scalar keys %RobotsHashIDLib ) . " robots\n";
	print "  " . ( scalar keys %WormsHashLib ) . " worm's families\n";
	print "  " . ( scalar keys %OSHashLib ) . " operating systems\n";
	print "  " . ( scalar keys %BrowsersHashIDLib ) . " browsers";
	&Read_Ref_Data('browsers_phone');
	print " ("
	  . ( scalar keys %BrowsersHashIDLib )
	  . " with phone browsers database)\n";
	print "  "
	  . ( scalar keys %SearchEnginesHashLib )
	  . " search engines (and keyphrases/keywords used from them)\n";
	print "  All HTTP errors with last referrer\n";
	print "  Report by day/month/year\n";
	print "  Dynamic or static HTML or XHTML reports, static PDF reports\n";
	print "  Indexed text or XML monthly database\n";
	print "  And a lot of other advanced features and options...\n";
	print "New versions and FAQ at http://www.awstats.org\n";
}
#------------------------------------------------------------------------------
# Function:     Return the string to add in html tag to include popup javascript code
# Parameters:   tooltip number
# Input:        None
# Output:       None
# Return:       string with javascript code
#------------------------------------------------------------------------------
sub Tooltip {
	my $ttnb = shift;
	return (
		$TOOLTIPON
		? " onmouseover=\"ShowTip($ttnb);\" onmouseout=\"HideTip($ttnb);\""
		: ""
	);
}
#------------------------------------------------------------------------------
# Function:     Insert a form filter
# Parameters:   Name of filter field, default for filter field, default for exclude filter field
# Input:        $StaticLinks, $QueryString, $SiteConfig, $DirConfig
# Output:       HTML Form
# Return:       None
#------------------------------------------------------------------------------
sub HTMLShowFormFilter {
	my $fieldfiltername    = shift;
	my $fieldfilterinvalue = shift;
	my $fieldfilterexvalue = shift;
	if ( !$StaticLinks ) {
		my $NewLinkParams = ${QueryString};
		$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)output(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
		$NewLinkParams =~ s/(&|&)+/&/i;
		$NewLinkParams =~ s/^&//;
		$NewLinkParams =~ s/&$//;
		if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
		print "\n\n";
		print "
\n";
		print "\n";
	}
}
#------------------------------------------------------------------------------
# Function:     Write other user info (with help of plugin)
# Parameters:   $user
# Input:        $SiteConfig
# Output:       URL link
# Return:       None
#------------------------------------------------------------------------------
sub HTMLShowUserInfo {
	my $user = shift;
	# Call to plugins' function ShowInfoUser
	foreach my $pluginname ( sort keys %{ $PluginsLoaded{'ShowInfoUser'} } ) {
		#		my $function="ShowInfoUser_$pluginname('$user')";
		#		eval("$function");
		my $function = "ShowInfoUser_$pluginname";
		&$function($user);
	}
}
#------------------------------------------------------------------------------
# Function:     Write other cluster info (with help of plugin)
# Parameters:   $clusternb
# Input:        $SiteConfig
# Output:       Cluster info
# Return:       None
#------------------------------------------------------------------------------
sub HTMLShowClusterInfo {
	my $cluster = shift;
	# Call to plugins' function ShowInfoCluster
	foreach my $pluginname ( sort keys %{ $PluginsLoaded{'ShowInfoCluster'} } )
	{
		#		my $function="ShowInfoCluster_$pluginname('$user')";
		#		eval("$function");
		my $function = "ShowInfoCluster_$pluginname";
		&$function($cluster);
	}
}
#------------------------------------------------------------------------------
# Function:     Write other host info (with help of plugin)
# Parameters:   $host
# Input:        $LinksToWhoIs $LinksToWhoIsIp
# Output:       None
# Return:       None
#------------------------------------------------------------------------------
sub HTMLShowHostInfo {
	my $host = shift;
	# Call to plugins' function ShowInfoHost
	foreach my $pluginname ( sort keys %{ $PluginsLoaded{'ShowInfoHost'} } ) {
		#		my $function="ShowInfoHost_$pluginname('$host')";
		#		eval("$function");
		my $function = "ShowInfoHost_$pluginname";
		&$function($host);
	}
}
#------------------------------------------------------------------------------
# Function:     Write other url info (with help of plugin)
# Parameters:   $url
# Input:        %Aliases $MaxLengthOfShownURL $ShowLinksOnUrl $SiteDomain $UseHTTPSLinkForUrl
# Output:       URL link
# Return:       None
#------------------------------------------------------------------------------
sub HTMLShowURLInfo {
	my $url     = shift;
	my $nompage = CleanXSS($url);
	# Call to plugins' function ShowInfoURL
	foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowInfoURL'} } ) {
		#		my $function="ShowInfoURL_$pluginname('$url')";
		#		eval("$function");
		my $function = "ShowInfoURL_$pluginname";
		&$function($url);
	}
	if ( length($nompage) > $MaxLengthOfShownURL ) {
		$nompage = substr( $nompage, 0, $MaxLengthOfShownURL ) . "...";
	}
	if ($ShowLinksOnUrl) {
		my $newkey = CleanXSS($url);
		if ( $LogType eq 'W' || $LogType eq 'S' ) {  # Web or streaming log file
			if ( $newkey =~ /^http(s|):/i )
			{    # URL seems to be extracted from a proxy log file
				print ""
				  . XMLEncode($nompage) . "";
			}
			elsif ( $newkey =~ /^\// )
			{ # URL seems to be an url extracted from a web or wap server log file
				$newkey =~ s/^\/$SiteDomain//i;
				# Define urlprot
				my $urlprot = 'http';
				if ( $UseHTTPSLinkForUrl && $newkey =~ /^$UseHTTPSLinkForUrl/ )
				{
					$urlprot = 'https';
				}
				print ""
				  . XMLEncode($nompage) . "";
			}
			else {
				print XMLEncode($nompage);
			}
		}
		elsif ( $LogType eq 'F' ) {    # Ftp log file
			print XMLEncode($nompage);
		}
		elsif ( $LogType eq 'M' ) {    # Smtp log file
			print XMLEncode($nompage);
		}
		else {                         # Other type log file
			print XMLEncode($nompage);
		}
	}
	else {
		print XMLEncode($nompage);
	}
}
#------------------------------------------------------------------------------
# Function:     Define value for PerlParsingFormat (used for regex log record parsing)
# Parameters:   $LogFormat
# Input:        -
# Output:       $pos_xxx, @pos_extra, @fieldlib, $PerlParsingFormat
# Return:       -
#------------------------------------------------------------------------------
sub DefinePerlParsingFormat {
	my $LogFormat = shift;
	$pos_vh = $pos_host = $pos_logname = $pos_date = $pos_tz = $pos_method =
	  $pos_url = $pos_code = $pos_size = -1;
	$pos_referer = $pos_agent = $pos_query = $pos_gzipin = $pos_gzipout =
	  $pos_compratio   = -1;
	$pos_cluster       = $pos_emails = $pos_emailr = $pos_hostr = -1;
	@pos_extra         = ();
	@fieldlib          = ();
	$PerlParsingFormat = '';
# Log records examples:
# Apache combined:             62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "GET / HTTP/1.1" 200 1234 "http://www.from.com/from.htm" "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"
# Apache combined (408 error): my.domain.com - user [09/Jan/2001:11:38:51 -0600] "OPTIONS /mime-tmp/xxx file.doc HTTP/1.1" 408 - "-" "-"
# Apache combined (408 error): 62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "-" 408 - "-" "-"
# Apache combined (400 error): 80.8.55.11 - - [28/Apr/2007:03:20:02 +0200] "GET /" 400 584 "-" "-"
# IIS:                         2000-07-19 14:14:14 62.161.78.73 - GET / 200 1234 HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0) http://www.from.com/from.htm
# WebStar:                     05/21/00	00:17:31	OK  	200	212.242.30.6	Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)	http://www.cover.dk/	"www.cover.dk"	:Documentation:graphics:starninelogo.white.gif	1133
# Squid extended:              12.229.91.170 - - [27/Jun/2002:03:30:50 -0700] "GET http://www.callistocms.com/images/printable.gif HTTP/1.1" 304 354 "-" "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/0" TCP_REFRESH_HIT:DIRECT
# Log formats:
# Apache common_with_mod_gzip_info1: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct.
# Apache common_with_mod_gzip_info2: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct.
# Apache deflate: %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" (%{ratio}n)
	if ($Debug) {
		debug(
"Call To DefinePerlParsingFormat (LogType='$LogType', LogFormat='$LogFormat')"
		);
	}
	if ( $LogFormat =~ /^[1-6]$/ ) {    # Pre-defined log format
		if ( $LogFormat eq '1' || $LogFormat eq '6' )
		{ # Same than "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"".
			 # %u (user) is "([^\\/\\[]+)" instead of "[^ ]+" because can contain space (Lotus Notes). referer and ua might be "".
# $PerlParsingFormat="([^ ]+) [^ ]+ ([^\\/\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) (.+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\"";
			$PerlParsingFormat =
"([^ ]+) [^ ]+ ([^\\/\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+)(?: [^\\\"]+|)\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\"";
			$pos_host    = 0;
			$pos_logname = 1;
			$pos_date    = 2;
			$pos_method  = 3;
			$pos_url     = 4;
			$pos_code    = 5;
			$pos_size    = 6;
			$pos_referer = 7;
			$pos_agent   = 8;
			@fieldlib    = (
				'host', 'logname', 'date', 'method', 'url', 'code',
				'size', 'referer', 'ua'
			);
		}
		elsif ( $LogFormat eq '2' )
		{ # Same than "date time c-ip cs-username cs-method cs-uri-stem sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)"
			$PerlParsingFormat =
"(\\S+ \\S+) (\\S+) (\\S+) (\\S+) (\\S+) ([\\d|-]+) ([\\d|-]+) \\S+ (\\S+) (\\S+)";
			$pos_date    = 0;
			$pos_host    = 1;
			$pos_logname = 2;
			$pos_method  = 3;
			$pos_url     = 4;
			$pos_code    = 5;
			$pos_size    = 6;
			$pos_agent   = 7;
			$pos_referer = 8;
			@fieldlib    = (
				'date', 'host', 'logname', 'method', 'url', 'code',
				'size', 'ua',   'referer'
			);
		}
		elsif ( $LogFormat eq '3' ) {
			$PerlParsingFormat =
"([^\\t]*\\t[^\\t]*)\\t([^\\t]*)\\t([\\d|-]*)\\t([^\\t]*)\\t([^\\t]*)\\t([^\\t]*)\\t[^\\t]*\\t([^\\t]*)\\t([\\d]*)";
			$pos_date    = 0;
			$pos_method  = 1;
			$pos_code    = 2;
			$pos_host    = 3;
			$pos_agent   = 4;
			$pos_referer = 5;
			$pos_url     = 6;
			$pos_size    = 7;
			@fieldlib    = (
				'date', 'method',  'code', 'host',
				'ua',   'referer', 'url',  'size'
			);
		}
		elsif ( $LogFormat eq '4' ) {    # Same than "%h %l %u %t \"%r\" %>s %b"
			# %u (user) is "(.+)" instead of "[^ ]+" because can contain space (Lotus Notes).
			# Sample: 10.100.10.45 - BMAA\will.smith [01/Jul/2013:07:17:28 +0200] "GET /Download/__Omnia__Aus- und Weiterbildung__Konsular- und Verwaltungskonferenz, Programm.doc HTTP/1.1" 200 9076810
#			$PerlParsingFormat = 
#"([^ ]+) [^ ]+ (.+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+)(?: [^\\\"]+|)\\\" ([\\d|-]+) ([\\d|-]+)";
			$PerlParsingFormat = 
"([^ ]+) [^ ]+ (.+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) (.+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+)";
			$pos_host    = 0;
			$pos_logname = 1;
			$pos_date    = 2;
			$pos_method  = 3;
			$pos_url     = 4;
			$pos_code    = 5;
			$pos_size    = 6;
			@fieldlib    =
			  ( 'host', 'logname', 'date', 'method', 'url', 'code', 'size' );
		}
	}
	else {    # Personalized log format
		my $LogFormatString = $LogFormat;
		# Replacement for Notes format string that are not Apache
		$LogFormatString =~ s/%vh/%virtualname/g;
		# Replacement for Apache format string
		$LogFormatString =~ s/%v(\s)/%virtualname$1/g;
		$LogFormatString =~ s/%v$/%virtualname/g;
		$LogFormatString =~ s/%h(\s)/%host$1/g;
		$LogFormatString =~ s/%h$/%host/g;
		$LogFormatString =~ s/%l(\s)/%other$1/g;
		$LogFormatString =~ s/%l$/%other/g;
		$LogFormatString =~ s/\"%u\"/%lognamequot/g;
		$LogFormatString =~ s/%u(\s)/%logname$1/g;
		$LogFormatString =~ s/%u$/%logname/g;
		$LogFormatString =~ s/%t(\s)/%time1$1/g;
		$LogFormatString =~ s/%t$/%time1/g;
		$LogFormatString =~ s/\"%r\"/%methodurl/g;
		$LogFormatString =~ s/%>s/%code/g;
		$LogFormatString =~ s/%b(\s)/%bytesd$1/g;
		$LogFormatString =~ s/%b$/%bytesd/g;
		$LogFormatString =~ s/\"%\{Referer}i\"/%refererquot/g;
		$LogFormatString =~ s/\"%\{User-Agent}i\"/%uaquot/g;
		$LogFormatString =~ s/%\{mod_gzip_input_size}n/%gzipin/g;
		$LogFormatString =~ s/%\{mod_gzip_output_size}n/%gzipout/g;
		$LogFormatString =~ s/%\{mod_gzip_compression_ratio}n/%gzipratio/g;
		$LogFormatString =~ s/\(%\{ratio}n\)/%deflateratio/g;
		# Replacement for a IIS and ISA format string
		$LogFormatString =~ s/cs-uri-query/%query/g;    # Must be before cs-uri
		$LogFormatString =~ s/date\stime/%time2/g;
		$LogFormatString =~ s/c-ip/%host/g;
		$LogFormatString =~ s/cs-username/%logname/g;
		$LogFormatString =~ s/cs-method/%method/g;  # GET, POST, SMTP, RETR STOR
		$LogFormatString =~ s/cs-uri-stem/%url/g;
		$LogFormatString =~ s/cs-uri/%url/g;
		$LogFormatString =~ s/sc-status/%code/g;
		$LogFormatString =~ s/sc-bytes/%bytesd/g;
		$LogFormatString =~ s/cs-version/%other/g;  # Protocol
		$LogFormatString =~ s/cs\(User-Agent\)/%ua/g;
		$LogFormatString =~ s/c-agent/%ua/g;
		$LogFormatString =~ s/cs\(Referer\)/%referer/g;
		$LogFormatString =~ s/cs-referred/%referer/g;
		$LogFormatString =~ s/sc-authenticated/%other/g;
		$LogFormatString =~ s/s-svcname/%other/g;
		$LogFormatString =~ s/s-computername/%other/g;
		$LogFormatString =~ s/r-host/%virtualname/g;
		$LogFormatString =~ s/cs-host/%virtualname/g;
		$LogFormatString =~ s/r-ip/%other/g;
		$LogFormatString =~ s/r-port/%other/g;
		$LogFormatString =~ s/time-taken/%other/g;
		$LogFormatString =~ s/cs-bytes/%other/g;
		$LogFormatString =~ s/cs-protocol/%other/g;
		$LogFormatString =~ s/cs-transport/%other/g;
		$LogFormatString =~
		  s/s-operation/%method/g;    # GET, POST, SMTP, RETR STOR
		$LogFormatString =~ s/cs-mime-type/%other/g;
		$LogFormatString =~ s/s-object-source/%other/g;
		$LogFormatString =~ s/s-cache-info/%other/g;
		$LogFormatString =~ s/cluster-node/%cluster/g;
		$LogFormatString =~ s/s-sitename/%other/g;
		$LogFormatString =~ s/s-ip/%other/g;
		$LogFormatString =~ s/s-port/%other/g;
		$LogFormatString =~ s/cs\(Cookie\)/%other/g;
		$LogFormatString =~ s/sc-substatus/%other/g;
		$LogFormatString =~ s/sc-win32-status/%other/g;
		# Added for MMS
		$LogFormatString =~
		  s/protocol/%protocolmms/g;    # cs-method might not be available
		$LogFormatString =~
		  s/c-status/%codemms/g;    # c-status used when sc-status not available
		if ($Debug) { debug(" LogFormatString=$LogFormatString"); }
# $LogFormatString has an AWStats format, so we can generate PerlParsingFormat variable
		my $i                       = 0;
		my $LogSeparatorWithoutStar = $LogSeparator;
		$LogSeparatorWithoutStar =~ s/[\*\+]//g;
		foreach my $f ( split( /\s+/, $LogFormatString ) ) {
			# Add separator for next field
			if ($PerlParsingFormat) { $PerlParsingFormat .= "$LogSeparator"; }
			# If field is prefixed with custom string, just push it to regex literally
			if ( $f =~ /^([^%]+)%/ ) {
				$PerlParsingFormat .= "$1"
                        }
			# Special for logname
			if ( $f =~ /%lognamequot$/ ) {
				$pos_logname = $i;
				$i++;
				push @fieldlib, 'logname';
				$PerlParsingFormat .=
				  "\\\"?([^\\\"]*)\\\"?"
				  ; # logname can be "value", "" and - in same log (Lotus notes)
			}
			elsif ( $f =~ /%logname$/ ) {
				$pos_logname = $i;
				$i++;
				push @fieldlib, 'logname';
# %u (user) is "([^\\/\\[]+)" instead of "[^$LogSeparatorWithoutStar]+" because can contain space (Lotus Notes).
				$PerlParsingFormat .= "([^\\/\\[]+)";
			}
			# Date format
			elsif ( $f =~ /%time1$/ || $f =~ /%time1b$/ )
			{ # [dd/mmm/yyyy:hh:mm:ss +0000] or [dd/mmm/yyyy:hh:mm:ss],  time1b kept for backward compatibility
				$pos_date = $i;
				$i++;
				push @fieldlib, 'date';
				$pos_tz = $i;
				$i++;
				push @fieldlib, 'tz';
				$PerlParsingFormat .=
"\\[([^$LogSeparatorWithoutStar]+)( [^$LogSeparatorWithoutStar]+)?\\]";
			}
			elsif ( $f =~ /%time2$/ ) {    # yyyy-mm-dd hh:mm:ss
				$pos_date = $i;
				$i++;
				push @fieldlib, 'date';
				$PerlParsingFormat .=
"([^$LogSeparatorWithoutStar]+\\s[^$LogSeparatorWithoutStar]+)";                        # Need \s for Exchange log files
			}
			elsif ( $f =~ /%time3$/ )
			{ # mon d hh:mm:ss  or  mon  d hh:mm:ss  or  mon dd hh:mm:ss yyyy  or  day mon dd hh:mm:ss  or  day mon dd hh:mm:ss yyyy
				$pos_date = $i;
				$i++;
				push @fieldlib, 'date';
				$PerlParsingFormat .=
"(?:\\w\\w\\w )?(\\w\\w\\w \\s?\\d+ \\d\\d:\\d\\d:\\d\\d(?: \\d\\d\\d\\d)?)";
			}
			elsif ( $f =~ /%time4$/ ) {    # ddddddddddddd
				$pos_date = $i;
				$i++;
				push @fieldlib, 'date';
				$PerlParsingFormat .= "(\\d+)";
			}
			elsif ( $f =~ /%time5$/ ) {
				# Supports the following formats:
				# - yyyy-mm-ddThh:mm:ss           (Incomplete ISO 8601)
				# - yyyy-mm-ddThh:mm:ssZ          (ISO 8601, zero meridian)
				# - yyyy-mm-ddThh:mm:ss+00:00     (ISO 8601)
				# - yyyy-mm-ddThh:mm:ss+0000      (Apache's best approximation to ISO 8601 using "%{%Y-%m-%dT%H:%M:%S%z}t" in LogFormat)
				# - yyyy-mm-ddThh:mm:ss.000000Z   (Amazon AWS log files)
				$pos_date = $i;
				$i++;
				push @fieldlib, 'date';
				$pos_tz = $i;
				$i++;
				push @fieldlib, 'tz';
				$PerlParsingFormat .=
"([^$LogSeparatorWithoutStar]+T[^$LogSeparatorWithoutStar]+)(Z|[-+\.]\\d\\d[:\\.\\dZ]*)?";
			}
			elsif ( $f =~ /%time6$/ ) {	# dd/mm/yyyy, hh:mm:ss - added additional type to format for IIS date -DWG 12/8/2008
				$pos_date = $i;	
				$i++; 
				push @fieldlib, 'date';
				$PerlParsingFormat .= "([^,]+,[^,]+)";
			}
			# Special for methodurl, methodurlprot and methodurlnoprot
			elsif ( $f =~ /%methodurl$/ ) {
				$pos_method = $i;
				$i++;
				push @fieldlib, 'method';
				$pos_url = $i;
				$i++;
				push @fieldlib, 'url';
				$PerlParsingFormat .=
#"\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+) [^\\\"]+\\\"";
"\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+)(?: [^\\\"]+|)\\\"";
			}
			elsif ( $f =~ /%methodurlprot$/ ) {
				$pos_method = $i;
				$i++;
				push @fieldlib, 'method';
				$pos_url = $i;
				$i++;
				push @fieldlib, 'url';
				$PerlParsingFormat .=
"\\\"([^$LogSeparatorWithoutStar]+) ([^\\\"]+) ([^\\\"]+)\\\"";
			}
			elsif ( $f =~ /%methodurlnoprot$/ ) {
				$pos_method = $i;
				$i++;
				push @fieldlib, 'method';
				$pos_url = $i;
				$i++;
				push @fieldlib, 'url';
				$PerlParsingFormat .=
"\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+)\\\"";
			}
			# Common command tags
			elsif ( $f =~ /%virtualnamequot$/ ) {
				$pos_vh = $i;
				$i++;
				push @fieldlib, 'vhost';
				$PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+)\\\"";
			}
			elsif ( $f =~ /%virtualname$/ ) {
				$pos_vh = $i;
				$i++;
				push @fieldlib, 'vhost';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%host_r$/ ) {
				$pos_hostr = $i;
				$i++;
				push @fieldlib, 'hostr';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%host$/ ) {
				$pos_host = $i;
				$i++;
				push @fieldlib, 'host';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%host_proxy$/ )
			{    # if host_proxy tag used, host tag must not be used
				$pos_host = $i;
				$i++;
				push @fieldlib, 'host';
				$PerlParsingFormat .= "(.+?)(?:, .*)*";
			}
			elsif ( $f =~ /%method$/ ) {
				$pos_method = $i;
				$i++;
				push @fieldlib, 'method';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%url$/ ) {
				$pos_url = $i;
				$i++;
				push @fieldlib, 'url';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%query$/ ) {
				$pos_query = $i;
				$i++;
				push @fieldlib, 'query';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%code$/ ) {
				$pos_code = $i;
				$i++;
				push @fieldlib, 'code';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%bytesd$/ ) {
				$pos_size = $i;
				$i++;
				push @fieldlib, 'size';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%refererquot$/ ) {
				$pos_referer = $i;
				$i++;
				push @fieldlib, 'referer';
				$PerlParsingFormat .=
				  "\\\"([^\\\"]*)\\\"";    # referer might be ""
			}
			elsif ( $f =~ /%referer$/ ) {
				$pos_referer = $i;
				$i++;
				push @fieldlib, 'referer';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%uaquot$/ ) {
				$pos_agent = $i;
				$i++;
				push @fieldlib, 'ua';
				$PerlParsingFormat .= "\\\"([^\\\"]*)\\\"";    # ua might be ""
			}
			elsif ( $f =~ /%uabracket$/ ) {
				$pos_agent = $i;
				$i++;
				push @fieldlib, 'ua';
				$PerlParsingFormat .= "\\\[([^\\\]]*)\\\]";    # ua might be []
			}
			elsif ( $f =~ /%ua$/ ) {
				$pos_agent = $i;
				$i++;
				push @fieldlib, 'ua';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%gzipin$/ ) {
				$pos_gzipin = $i;
				$i++;
				push @fieldlib, 'gzipin';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%gzipout/ )
			{ # Compare $f to /%gzipout/ and not to /%gzipout$/ like other fields
				$pos_gzipout = $i;
				$i++;
				push @fieldlib, 'gzipout';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%gzipratio/ )
			{ # Compare $f to /%gzipratio/ and not to /%gzipratio$/ like other fields
				$pos_compratio = $i;
				$i++;
				push @fieldlib, 'gzipratio';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%deflateratio/ )
			{ # Compare $f to /%deflateratio/ and not to /%deflateratio$/ like other fields
				$pos_compratio = $i;
				$i++;
				push @fieldlib, 'deflateratio';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%email_r$/ ) {
				$pos_emailr = $i;
				$i++;
				push @fieldlib, 'email_r';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%email$/ ) {
				$pos_emails = $i;
				$i++;
				push @fieldlib, 'email';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%cluster$/ ) {
				$pos_cluster = $i;
				$i++;
				push @fieldlib, 'clusternb';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			elsif ( $f =~ /%timetaken$/ ) {
				$pos_timetaken = $i;
				$i++;
				push @fieldlib, 'timetaken';
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
# Special for protocolmms, used for method if method not already found (for MMS)
			elsif ( $f =~ /%protocolmms$/ ) {
				if ( $pos_method < 0 ) {
					$pos_method = $i;
					$i++;
					push @fieldlib, 'method';
					$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
				}
			}
   # Special for codemms, used for code only if code not already found (for MMS)
			elsif ( $f =~ /%codemms$/ ) {
				if ( $pos_code < 0 ) {
					$pos_code = $i;
					$i++;
					push @fieldlib, 'code';
					$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
				}
			}
			# Extra tag
			elsif ( $f =~ /%extra(\d+)$/ ) {
				$pos_extra[$1] = $i;
				$i++;
				push @fieldlib, "extra$1";
				$PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
			}
			# Other tag
			elsif ( $f =~ /%other$/ ) {
				$PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+";
			}
			elsif ( $f =~ /%otherquot$/ ) {
				$PerlParsingFormat .= "\\\"[^\\\"]*\\\"";
			}
			# Unknown tag (no parenthesis)
			else {
				$PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+";
			}
		}
		if ( !$PerlParsingFormat ) {
			error("No recognized format tag in personalized LogFormat string");
		}
	}
	if ( $pos_host < 0 ) {
		error(
"Your personalized LogFormat does not include all fields required by AWStats (Add \%host in your LogFormat string)."
		);
	}
	if ( $pos_date < 0 ) {
		error(
"Your personalized LogFormat does not include all fields required by AWStats (Add \%time1 or \%time2 in your LogFormat string)."
		);
	}
	if ( $pos_method < 0 ) {
		error(
"Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%method in your LogFormat string)."
		);
	}
	if ( $pos_url < 0 ) {
		error(
"Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%url in your LogFormat string)."
		);
	}
	if ( $pos_code < 0 ) {
		error(
"Your personalized LogFormat does not include all fields required by AWStats (Add \%code in your LogFormat string)."
		);
	}
#	if ( $pos_size < 0 ) {
#		error(
#"Your personalized LogFormat does not include all fields required by AWStats (Add \%bytesd in your LogFormat string)."
#		);
#	}
	$PerlParsingFormat = qr/^$PerlParsingFormat/;
	if ($Debug) { debug(" PerlParsingFormat is $PerlParsingFormat"); }
}
#------------------------------------------------------------------------------
# Function:     Prints a menu category for the frame or static header
# Parameters:   -
# Input:        $categ, $categtext, $categicon, $frame, $targetpage, $linkanchor,
#				$NewLinkParams, $NewLinkTarget
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowMenuCateg {
	my ( $categ, $categtext, $categicon, $frame, $targetpage, $linkanchor,
		$NewLinkParams, $NewLinkTarget )
	  = ( shift, shift, shift, shift, shift, shift, shift, shift );
	$categicon = '';    # Comment this to enabme category icons
	my ( $menu, $menulink, $menutext ) = ( shift, shift, shift );
	my $linetitle = 0;
	# Call to plugins' function AddHTMLMenuLink
	foreach my $pluginname ( keys %{ $PluginsLoaded{'AddHTMLMenuLink'} } ) {
# my $function="AddHTMLMenuLink_$pluginname('$categ',\$menu,\$menulink,\$menutext)";
# eval("$function");
		my $function = "AddHTMLMenuLink_$pluginname";
		&$function( $categ, $menu, $menulink, $menutext );
	}
	foreach my $key (%$menu) {
		if ( $menu->{$key} && $menu->{$key} > 0 ) { $linetitle++; last; }
	}
	if ( !$linetitle ) { return; }
# At least one entry in menu for this category, we can show category and entries
	my $WIDTHMENU1 = ( $FrameName eq 'mainleft' ? $FRAMEWIDTH : 150 );
	print ""
	  . ( $categicon ? "  " : "" )
	  . "$categtext: | \n";
	print( $frame? "
\n" : "" );
	foreach my $key ( sort { $menu->{$a} <=> $menu->{$b} } keys %$menu ) {
		if ( $menu->{$key} == 0 )     { next; }
		if ( $menulink->{$key} == 1 ) {
			print( $frame? " | | " : "" );
			print
			  "$menutext->{$key}";
			print( $frame? " | 
\n" : "   " );
		}
		if ( $menulink->{$key} == 2 ) {
			print( $frame
				? "     "
				: ""
			);
			print "$menutext->{$key}\n";
			print( $frame? " | 
\n" : "   " );
		}
	}
	print( $frame? "" : "\n" );
}
#------------------------------------------------------------------------------
# Function:     Prints HTML to display an email senders chart
# Parameters:   -
# Input:        $NewLinkParams, NewLinkTarget
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowEmailSendersChart {
	my $NewLinkParams         = shift;
	my $NewLinkTarget         = shift;
	my $MaxLengthOfShownEMail = 48;
	my $total_p;
	my $total_h;
	my $total_k;
	my $max_p;
	my $max_h;
	my $max_k;
	my $rest_p;
	my $rest_h;
	my $rest_k;
	# Show filter form
	#&ShowFormFilter("emailsfilter",$EmailsFilter);
	# Show emails list
	print "$Center 
\n";
	my $title;
	if ( $HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'} ) {
		$title = "$Message[131]";
	}
	else {
		$title =
"$Message[131] ($Message[77] $MaxNbOf{'EMailsShown'})   -   $Message[80]";
		if ( $ShowEMailSenders =~ /L/i ) {
			$title .= "   -   $Message[9]";
		}
	}
	&tab_head( "$title", 19, 0, 'emailsenders' );
	print
"| $Message[131] : "
	  . ( scalar keys %_emails_h ) . " | ";
	if ( $ShowEMailSenders =~ /H/i ) {
		print "$Message[57] | ";
	}
	if ( $ShowEMailSenders =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowEMailSenders =~ /M/i ) {
		print
"$Message[106] | ";
	}
	if ( $ShowEMailSenders =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	print
"| Local |   | External | 
";
	$total_p = $total_h = $total_k = 0;
	$max_h = 1;
	foreach ( values %_emails_h ) {
		if ( $_ > $max_h ) { $max_h = $_; }
	}
	$max_k = 1;
	foreach ( values %_emails_k ) {
		if ( $_ > $max_k ) { $max_k = $_; }
	}
	my $count = 0;
	if ( !$HTMLOutput{'allemails'} && !$HTMLOutput{'lastemails'} ) {
		&BuildKeyList( $MaxNbOf{'EMailsShown'}, $MinHit{'EMail'}, \%_emails_h,
			\%_emails_h );
	}
	if ( $HTMLOutput{'allemails'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'EMail'}, \%_emails_h,
			\%_emails_h );
	}
	if ( $HTMLOutput{'lastemails'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'EMail'}, \%_emails_h,
			\%_emails_l );
	}
	foreach my $key (@keylist) {
		my $newkey = $key;
		if ( length($key) > $MaxLengthOfShownEMail ) {
			$newkey = substr( $key, 0, $MaxLengthOfShownEMail ) . "...";
		}
		my $bredde_h = 0;
		my $bredde_k = 0;
		if ( $max_h > 0 ) {
			$bredde_h = int( $BarWidth * $_emails_h{$key} / $max_h ) + 1;
		}
		if ( $max_k > 0 ) {
			$bredde_k = int( $BarWidth * $_emails_k{$key} / $max_k ) + 1;
		}
		print "";
		my $direction = IsLocalEMail($key);
		if ( $direction > 0 ) {
			print "| $newkey | -> |   | ";
		}
		if ( $direction == 0 ) {
			print
"$newkey | ";
		}
		if ( $direction < 0 ) {
			print "  | <- | $newkey | ";
		}
		if ( $ShowEMailSenders =~ /H/i ) { print "$_emails_h{$key} | "; }
		if ( $ShowEMailSenders =~ /B/i ) {
			print ""
			  . Format_Bytes( $_emails_k{$key} ) . " | ";
		}
		if ( $ShowEMailSenders =~ /M/i ) {
			print ""
			  . Format_Bytes( $_emails_k{$key} / ( $_emails_h{$key} || 1 ) )
			  . " | ";
		}
		if ( $ShowEMailSenders =~ /L/i ) {
			print ""
			  . ( $_emails_l{$key} ? Format_Date( $_emails_l{$key}, 1 ) : '-' )
			  . " | ";
		}
		print "
\n";
		#$total_p += $_emails_p{$key};
		$total_h += $_emails_h{$key};
		$total_k += $_emails_k{$key};
		$count++;
	}
	$rest_p = 0;                        # $rest_p=$TotalPages-$total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 ) { # All other sender emails
		print
"| $Message[2] | ";
		if ( $ShowEMailSenders =~ /H/i ) { print "$rest_h | "; }
		if ( $ShowEMailSenders =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowEMailSenders =~ /M/i ) {
			print ""
			  . Format_Bytes( $rest_k / ( $rest_h || 1 ) ) . " | ";
		}
		if ( $ShowEMailSenders =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints HTML to display an email receivers chart
# Parameters:   -
# Input:        $NewLinkParams, NewLinkTarget
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowEmailReceiversChart {
	my $NewLinkParams         = shift;
	my $NewLinkTarget         = shift;
	my $MaxLengthOfShownEMail = 48;
	my $total_p;
	my $total_h;
	my $total_k;
	my $max_p;
	my $max_h;
	my $max_k;
	my $rest_p;
	my $rest_h;
	my $rest_k;
	# Show filter form
	#&ShowFormFilter("emailrfilter",$EmailrFilter);
	# Show emails list
	print "$Center 
\n";
	my $title;
	if ( $HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'} ) {
		$title = "$Message[132]";
	}
	else {
		$title =
"$Message[132] ($Message[77] $MaxNbOf{'EMailsShown'})   -   $Message[80]";
		if ( $ShowEMailReceivers =~ /L/i ) {
			$title .= "   -   $Message[9]";
		}
	}
	&tab_head( "$title", 19, 0, 'emailreceivers' );
	print
"| $Message[132] : "
	  . ( scalar keys %_emailr_h ) . " | ";
	if ( $ShowEMailReceivers =~ /H/i ) {
		print "$Message[57] | ";
	}
	if ( $ShowEMailReceivers =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowEMailReceivers =~ /M/i ) {
		print
"$Message[106] | ";
	}
	if ( $ShowEMailReceivers =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	print
"| Local |   | External | 
";
	$total_p = $total_h = $total_k = 0;
	$max_h = 1;
	foreach ( values %_emailr_h ) {
		if ( $_ > $max_h ) { $max_h = $_; }
	}
	$max_k = 1;
	foreach ( values %_emailr_k ) {
		if ( $_ > $max_k ) { $max_k = $_; }
	}
	my $count = 0;
	if ( !$HTMLOutput{'allemailr'} && !$HTMLOutput{'lastemailr'} ) {
		&BuildKeyList( $MaxNbOf{'EMailsShown'}, $MinHit{'EMail'}, \%_emailr_h,
			\%_emailr_h );
	}
	if ( $HTMLOutput{'allemailr'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'EMail'}, \%_emailr_h,
			\%_emailr_h );
	}
	if ( $HTMLOutput{'lastemailr'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'EMail'}, \%_emailr_h,
			\%_emailr_l );
	}
	foreach my $key (@keylist) {
		my $newkey = $key;
		if ( length($key) > $MaxLengthOfShownEMail ) {
			$newkey = substr( $key, 0, $MaxLengthOfShownEMail ) . "...";
		}
		my $bredde_h = 0;
		my $bredde_k = 0;
		if ( $max_h > 0 ) {
			$bredde_h = int( $BarWidth * $_emailr_h{$key} / $max_h ) + 1;
		}
		if ( $max_k > 0 ) {
			$bredde_k = int( $BarWidth * $_emailr_k{$key} / $max_k ) + 1;
		}
		print "";
		my $direction = IsLocalEMail($key);
		if ( $direction > 0 ) {
			print "| $newkey | <- |   | ";
		}
		if ( $direction == 0 ) {
			print
"$newkey | ";
		}
		if ( $direction < 0 ) {
			print "  | -> | $newkey | ";
		}
		if ( $ShowEMailReceivers =~ /H/i ) {
			print "$_emailr_h{$key} | ";
		}
		if ( $ShowEMailReceivers =~ /B/i ) {
			print ""
			  . Format_Bytes( $_emailr_k{$key} ) . " | ";
		}
		if ( $ShowEMailReceivers =~ /M/i ) {
			print ""
			  . Format_Bytes( $_emailr_k{$key} / ( $_emailr_h{$key} || 1 ) )
			  . " | ";
		}
		if ( $ShowEMailReceivers =~ /L/i ) {
			print ""
			  . ( $_emailr_l{$key} ? Format_Date( $_emailr_l{$key}, 1 ) : '-' )
			  . " | ";
		}
		print "
\n";
		#$total_p += $_emailr_p{$key};
		$total_h += $_emailr_h{$key};
		$total_k += $_emailr_k{$key};
		$count++;
	}
	$rest_p = 0;                        # $rest_p=$TotalPages-$total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{                                   # All other receiver emails
		print
"| $Message[2] | ";
		if ( $ShowEMailReceivers =~ /H/i ) { print "$rest_h | "; }
		if ( $ShowEMailReceivers =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowEMailReceivers =~ /M/i ) {
			print ""
			  . Format_Bytes( $rest_k / ( $rest_h || 1 ) ) . " | ";
		}
		if ( $ShowEMailReceivers =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the top banner of the inner frame or static page
# Parameters:   $WIDTHMENU1
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLTopBanner{
	my $WIDTHMENU1 = shift;
	my $frame = ( $FrameName eq 'mainleft' );
	if ($Debug) { debug( "ShowTopBan", 2 ); }
	print "$Center \n";
	if ( $FrameName ne 'mainleft' ) {
		my $NewLinkParams = ${QueryString};
		$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
		$NewLinkParams =~ s/(^|&|&)year=[^&]*//i;
		$NewLinkParams =~ s/(^|&|&)month=[^&]*//i;
		$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
		$NewLinkParams =~ s/(&|&)+/&/i;
		$NewLinkParams =~ s/^&//;
		$NewLinkParams =~ s/&$//;
		my $NewLinkTarget = '';
		if ( $FrameName eq 'mainright' ) {
			$NewLinkTarget = " target=\"_parent\"";
		}
		print "
\n"; }
	else { print "
\n"; }
	print "\n";
}
#------------------------------------------------------------------------------
# Function:     Prints the menu in a frame or below the top banner
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMenu{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	my $frame = ( $FrameName eq 'mainleft' );
	if ($Debug) { debug( "ShowMenu", 2 ); }
	# Print menu links
	if ( ( $HTMLOutput{'main'} && $FrameName ne 'mainright' )
		|| $FrameName eq 'mainleft' )
	{    # If main page asked
		    # Define link anchor
		my $linkanchor =
		  ( $FrameName eq 'mainleft' ? "$AWScript${NewLinkParams}" : "" );
		if ( $linkanchor && ( $linkanchor !~ /framename=mainright/ ) ) {
			$linkanchor .= "framename=mainright";
		}
		$linkanchor =~ s/(&|&)$//;
		$linkanchor = XMLEncode("$linkanchor");
		# Define target
		my $targetpage =
		  ( $FrameName eq 'mainleft' ? " target=\"mainright\"" : "" );
		# Print Menu
		my $linetitle;    # TODO a virer
		if ( !$PluginsLoaded{'ShowMenu'}{'menuapplet'} ) {
			my $menuicon = 0;    # TODO a virer
			                     # Menu HTML
			print "\n";
			if ( $FrameName eq 'mainleft' && $ShowMonthStats ) {
				print( $frame? "| " : "" );
				print
"$Message[128]";
				print( $frame? " | 
\n" : "   " );
			}
			my %menu     = ();
			my %menulink = ();
			my %menutext = ();
			# When
			%menu = (
				'month'       => $ShowMonthStats       ? 1 : 0,
				'daysofmonth' => $ShowDaysOfMonthStats ? 2 : 0,
				'daysofweek'  => $ShowDaysOfWeekStats  ? 3 : 0,
				'hours'       => $ShowHoursStats       ? 4 : 0
			);
			%menulink = (
				'month'       => 1,
				'daysofmonth' => 1,
				'daysofweek'  => 1,
				'hours'       => 1
			);
			%menutext = (
				'month'       => $Message[162],
				'daysofmonth' => $Message[138],
				'daysofweek'  => $Message[91],
				'hours'       => $Message[20]
			);
			HTMLShowMenuCateg(
				'when',         $Message[93],
				'menu4.png',    $frame,
				$targetpage,    $linkanchor,
				$NewLinkParams, $NewLinkTarget,
				\%menu,         \%menulink,
				\%menutext
			);
			# Who
			%menu = (
				'countries'  => $ShowDomainsStats ? 1 : 0,
				'alldomains' => $ShowDomainsStats ? 2 : 0,
				'visitors'   => $ShowHostsStats   ? 3 : 0,
				'allhosts'   => $ShowHostsStats   ? 4 : 0,
				'lasthosts' => ( $ShowHostsStats =~ /L/i ) ? 5 : 0,
				'unknownip' => $ShowHostsStats         ? 6 : 0,
				'logins'    => $ShowAuthenticatedUsers ? 7 : 0,
				'alllogins' => $ShowAuthenticatedUsers ? 8 : 0,
				'lastlogins' => ( $ShowAuthenticatedUsers =~ /L/i ) ? 9 : 0,
				'emailsenders' => $ShowEMailSenders ? 10 : 0,
				'allemails'    => $ShowEMailSenders ? 11 : 0,
				'lastemails' => ( $ShowEMailSenders =~ /L/i ) ? 12 : 0,
				'emailreceivers' => $ShowEMailReceivers ? 13 : 0,
				'allemailr'      => $ShowEMailReceivers ? 14 : 0,
				'lastemailr' => ( $ShowEMailReceivers =~ /L/i ) ? 15 : 0,
				'robots'    => $ShowRobotsStats ? 16 : 0,
				'allrobots' => $ShowRobotsStats ? 17 : 0,
				'lastrobots' => ( $ShowRobotsStats =~ /L/i ) ? 18 : 0,
				'worms' => $ShowWormsStats ? 19 : 0
			);
			%menulink = (
				'countries'      => 1,
				'alldomains'     => 2,
				'visitors'       => 1,
				'allhosts'       => 2,
				'lasthosts'      => 2,
				'unknownip'      => 2,
				'logins'         => 1,
				'alllogins'      => 2,
				'lastlogins'     => 2,
				'emailsenders'   => 1,
				'allemails'      => 2,
				'lastemails'     => 2,
				'emailreceivers' => 1,
				'allemailr'      => 2,
				'lastemailr'     => 2,
				'robots'         => 1,
				'allrobots'      => 2,
				'lastrobots'     => 2,
				'worms'          => 1
			);
			%menutext = (
				'countries'      => $Message[148],
				'alldomains'     => $Message[80],
				'visitors'       => $Message[81],
				'allhosts'       => $Message[80],
				'lasthosts'      => $Message[9],
				'unknownip'      => $Message[45],
				'logins'         => $Message[94],
				'alllogins'      => $Message[80],
				'lastlogins'     => $Message[9],
				'emailsenders'   => $Message[131],
				'allemails'      => $Message[80],
				'lastemails'     => $Message[9],
				'emailreceivers' => $Message[132],
				'allemailr'      => $Message[80],
				'lastemailr'     => $Message[9],
				'robots'         => $Message[53],
				'allrobots'      => $Message[80],
				'lastrobots'     => $Message[9],
				'worms'          => $Message[136]
			);
			HTMLShowMenuCateg(
				'who',          $Message[92],
				'menu5.png',    $frame,
				$targetpage,    $linkanchor,
				$NewLinkParams, $NewLinkTarget,
				\%menu,         \%menulink,
				\%menutext
			);
			# Navigation
			$linetitle = &AtLeastOneNotNull(
				$ShowSessionsStats,  $ShowPagesStats,
				$ShowFileTypesStats, $ShowFileSizesStats,
				$ShowOSStats,        $ShowBrowsersStats,
				$ShowScreenSizeStats, $ShowDownloadsStats
			);
			if ($linetitle) {
				print ""
				  . (
					$menuicon
					? "  "
					: ""
				  )
				  . "$Message[72]: | \n";
			}
			if ($linetitle) {
				print( $frame? "
\n" : "" );
			}
			if ($ShowSessionsStats) {
				print( $frame? " | | " : "" );
				print
"$Message[117]";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowFileTypesStats && $LevelForFileTypesDetection > 0) {
				print( $frame? "| " : "" );
				print
"$Message[73]";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowDownloadsStats && $LevelForFileTypesDetection > 0) {
				print( $frame? "| " : "" );
				print
"$Message[178]";
				print( $frame? " | 
\n" : "   " );
				print( $frame
					? "     "
					: ""
				);
				print "$Message[80]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowPagesStats) {
				print( $frame? "| " : "" );
				print
"$Message[29]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowPagesStats) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[80]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ( $ShowPagesStats =~ /E/i ) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[104]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ( $ShowPagesStats =~ /X/i ) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[116]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowOSStats) {
				print( $frame? "| " : "" );
				print
				  "$Message[59]";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowOSStats) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[58]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowOSStats) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[0]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowBrowsersStats) {
				print( $frame? "| " : "" );
				print
"$Message[21]";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowBrowsersStats) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[58]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowBrowsersStats) {
				print( $frame
					? "     "
					: ""
				);
				print "$Message[0]\n";
				print( $frame? " | 
\n" : "   " );
			}
			if ($ShowScreenSizeStats) {
				print( $frame? "| " : "" );
				print
"$Message[135]";
				print( $frame? " | 
\n" : "   " );
			}
			if ($linetitle) { print( $frame? "" : "\n" ); }
			# Referers
			%menu = (
				'referer'      => $ShowOriginStats ? 1 : 0,
				'refererse'    => $ShowOriginStats ? 2 : 0,
				'refererpages' => $ShowOriginStats ? 3 : 0,
				'keys' => ( $ShowKeyphrasesStats || $ShowKeywordsStats )
				? 4
				: 0,
				'keyphrases' => $ShowKeyphrasesStats ? 5 : 0,
				'keywords'   => $ShowKeywordsStats   ? 6 : 0
			);
			%menulink = (
				'referer'      => 1,
				'refererse'    => 2,
				'refererpages' => 2,
				'keys'         => 1,
				'keyphrases'   => 2,
				'keywords'     => 2
			);
			%menutext = (
				'referer'      => $Message[37],
				'refererse'    => $Message[126],
				'refererpages' => $Message[127],
				'keys'         => $Message[14],
				'keyphrases'   => $Message[120],
				'keywords'     => $Message[121]
			);
			HTMLShowMenuCateg(
				'referers',     $Message[23],
				'menu7.png',    $frame,
				$targetpage,    $linkanchor,
				$NewLinkParams, $NewLinkTarget,
				\%menu,         \%menulink,
				\%menutext
			);
			# Others
			%menu = (
				'filetypes' => ( $ShowFileTypesStats =~ /C/i ) ? 1 : 0,
				'misc' => $ShowMiscStats ? 2 : 0,
				'errors' => ( $ShowHTTPErrorsStats || $ShowSMTPErrorsStats )
				? 3
				: 0,
				'clusters' => $ShowClusterStats ? 5 : 0
			);
			%menulink = (
				'filetypes' => 1,
				'misc'      => 1,
				'errors'    => 1,
				'clusters'  => 1
			);
			%menutext = (
				'filetypes' => $Message[98],
				'misc'      => $Message[139],
				'errors'    =>
				  ( $ShowSMTPErrorsStats ? $Message[147] : $Message[32] ),
				'clusters' => $Message[155]
			);
			my $idx = 0;
			foreach ( sort keys %TrapInfosForHTTPErrorCodes ) {
				$menu{"errors$_"}     = $ShowHTTPErrorsStats ? 4+$idx : 0;
				$menulink{"errors$_"} = 2;
				$menutext{"errors$_"} = $Message[49] . ' (' . $_ . ')';
				$idx++;
			}
			HTMLShowMenuCateg(
				'others',       $Message[2],
				'menu8.png',    $frame,
				$targetpage,    $linkanchor,
				$NewLinkParams, $NewLinkTarget,
				\%menu,         \%menulink,
				\%menutext
			);
			# Extra/Marketing
			%menu     = ();
			%menulink = ();
			%menutext = ();
			my $i = 1;
			foreach ( 1 .. @ExtraName - 1 ) {
				$menu{"extra$_"}        = $i++;
				$menulink{"extra$_"}    = 1;
				$menutext{"extra$_"}    = $ExtraName[$_];
				$menu{"allextra$_"}     = $i++;
				$menulink{"allextra$_"} = 2;
				$menutext{"allextra$_"} = $Message[80];
			}
			HTMLShowMenuCateg(
				'extra',        $Message[134],
				'',             $frame,
				$targetpage,    $linkanchor,
				$NewLinkParams, $NewLinkTarget,
				\%menu,         \%menulink,
				\%menutext
			);
			print "
\n";
		}
		else {
			# Menu Applet
			if ($frame) { }
			else { }
		}
		#print ($frame?"":"
\n");
		print "
\n";
	}
	# Print Back link
	elsif ( !$HTMLOutput{'main'} ) {
		print "\n";
		$NewLinkParams =~ s/(^|&|&)hostfilter=[^&]*//i;
		$NewLinkParams =~ s/(^|&|&)urlfilter=[^&]*//i;
		$NewLinkParams =~ s/(^|&|&)refererpagesfilter=[^&]*//i;
		$NewLinkParams =~ s/(&|&)+/&/i;
		$NewLinkParams =~ s/^&//;
		$NewLinkParams =~ s/&$//;
		if (   !$DetailedReportsOnNewWindows
			|| $FrameName eq 'mainright'
			|| $QueryString =~ /buildpdf/i )
		{
			print "| $Message[76] | 
\n";
		}
		else {
			print
"| $Message[118] | 
\n";
		}
		print "
\n";
		print "\n";
	}
}
#------------------------------------------------------------------------------
# Function:     Prints the File Type table
# Parameters:   _
# Input:        $NewLinkParams, $NewLinkTargets
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainFileType{
    my $NewLinkParams = shift;
    my $NewLinkTarget = shift;
	if (!$LevelForFileTypesDetection > 0){return;}
	if ($Debug) { debug( "ShowFileTypesStatsCompressionStats", 2 ); }
	print "$Center 
\n";
	my $Totalh = 0;
	foreach ( keys %_filetypes_h ) { $Totalh += $_filetypes_h{$_}; }
	my $Totalk = 0;
	foreach ( keys %_filetypes_k ) { $Totalk += $_filetypes_k{$_}; }
	my $title = "$Message[73]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
        # extend the title to include the added link 
        $title = "$title   -   $Message[179]");
    } 
	if ( $ShowFileTypesStats =~ /C/i ) { $title .= " - $Message[98]"; }
	
	# build keylist at top
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_filetypes_h,
		\%_filetypes_h );
		
	&tab_head( "$title", 19, 0, 'filetypes' );
		
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int( $_filetypes_h{$key} / $Totalh * 1000 ) / 10;
				push @blocklabel, "$key";
				$cnt++;
				if ($cnt > 4) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"$Message[73]",              "filetypes",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print
"| $Message[73] | ";
	if ( $ShowFileTypesStats =~ /H/i ) {
		print "$Message[57] | $Message[15] | ";
	}
	if ( $ShowFileTypesStats =~ /B/i ) {
		print "$Message[75] | $Message[15] | ";
	}
	if ( $ShowFileTypesStats =~ /C/i ) {
		print
"$Message[100] | $Message[101] | $Message[99] | ";
	}
	print "
\n";
	my $total_con = 0;
	my $total_cre = 0;
	my $count     = 0;
	foreach my $key (@keylist) {
		my $p_h = ' ';
		my $p_k = ' ';
		if ($Totalh) {
			$p_h = int( $_filetypes_h{$key} / $Totalh * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($Totalk) {
			$p_k = int( $_filetypes_k{$key} / $Totalk * 1000 ) / 10;
			$p_k = "$p_k %";
		}
		if ( $key eq 'Unknown' ) {
			print "  | $Message[0] | ";
		}
		else {
			my $nameicon = $MimeHashLib{$key}[0] || "notavailable";
			my $nametype = $MimeHashFamily{$MimeHashLib{$key}[0]} || " ";
			print "
  | $key | ";
			print "$nametype | ";
		}
		if ( $ShowFileTypesStats =~ /H/i ) {
			print "".Format_Number($_filetypes_h{$key})." | $p_h | ";
		}
		if ( $ShowFileTypesStats =~ /B/i ) {
			print ''
			  . Format_Bytes( $_filetypes_k{$key} )
			  . " | $p_k | ";
		}
		if ( $ShowFileTypesStats =~ /C/i ) {
			if ( $_filetypes_gz_in{$key} ) {
				my $percent = int(
					100 * (
						1 - $_filetypes_gz_out{$key} /
						  $_filetypes_gz_in{$key}
					)
				);
				printf(
					"%s | %s | %s (%s%) | ",
					Format_Bytes( $_filetypes_gz_in{$key} ),
					Format_Bytes( $_filetypes_gz_out{$key} ),
					Format_Bytes(
						$_filetypes_gz_in{$key} -
						  $_filetypes_gz_out{$key}
					),
					$percent
				);
				$total_con += $_filetypes_gz_in{$key};
				$total_cre += $_filetypes_gz_out{$key};
			}
			else {
				print "  |   |   | ";
			}
		}
		print "
\n";
		$count++;
	}
	# Add total (only useful if compression is enabled)
	if ( $ShowFileTypesStats =~ /C/i ) {
		my $colspan = 3;
		if ( $ShowFileTypesStats =~ /H/i ) { $colspan += 2; }
		if ( $ShowFileTypesStats =~ /B/i ) { $colspan += 2; }
		print "";
		print
"| $Message[98] | ";
		if ( $ShowFileTypesStats =~ /C/i ) {
			if ($total_con) {
				my $percent =
				  int( 100 * ( 1 - $total_cre / $total_con ) );
				printf(
					"%s | %s | %s (%s%) | ",
					Format_Bytes($total_con),
					Format_Bytes($total_cre),
					Format_Bytes( $total_con - $total_cre ),
					$percent
				);
			}
			else {
				print "  |   |   | ";
			}
		}
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Browser Detail frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowBrowserDetail{
	# Show browsers versions
	print "$Center 
";
	my $title = "$Message[21]";
	&tab_head( "$title", 19, 0, 'browsersversions' );
	print
"| $Message[58] | ";
	print
"$Message[111] | $Message[56] | $Message[15] | ";
	print
"$Message[57] | $Message[15] | ";
	print "  | ";
	print "
\n";
	my $total_h = 0;
	my $total_p = 0;
	my $count = 0;
	&BuildKeyList( MinimumButNoZero( scalar keys %_browser_h, 500 ),
		1, \%_browser_h, \%_browser_p );
	my %keysinkeylist = ();
	my $max_h = 1;
	my $max_p = 1;
	# Count total by family
	my %totalfamily_h = ();
	my %totalfamily_p = ();
	my $TotalFamily_h = 0;
	my $TotalFamily_p = 0;
  BROWSERLOOP: foreach my $key (@keylist) {
		$total_h += $_browser_h{$key};
		if ( $_browser_h{$key} > $max_h ) {
			$max_h = $_browser_h{$key};
		}
		$total_p += $_browser_p{$key};
		if ( $_browser_p{$key} > $max_p ) {
			$max_p = $_browser_p{$key};
		}
		foreach my $family ( keys %BrowsersFamily ) {
			if ( $key =~ /^$family/i ) {
				$totalfamily_h{$family} += $_browser_h{$key};
				$totalfamily_p{$family} += $_browser_p{$key};
				$TotalFamily_h          += $_browser_h{$key};
				$TotalFamily_p          += $_browser_p{$key};
				next BROWSERLOOP;
			}
		}
	}
	# Write records grouped in a browser family
	foreach my $family (
		sort { $BrowsersFamily{$a} <=> $BrowsersFamily{$b} }
		keys %BrowsersFamily
	  )
	{
		my $p_h = ' ';
		my $p_p = ' ';
		if ($total_h) {
			$p_h = int( $totalfamily_h{$family} / $total_h * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($total_p) {
			$p_p = int( $totalfamily_p{$family} / $total_p * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		my $familyheadershown = 0;
		#foreach my $key ( reverse sort keys %_browser_h ) {
		foreach my $key ( reverse sort SortBrowsers keys %_browser_h ) {
			if ( $key =~ /^$family(.*)/i ) {
				if ( !$familyheadershown ) {
					print
"| "
				  . uc($family)
				  . " | ";
				print "  | "
				  . Format_Number(int( $totalfamily_p{$family} ))
				  . " | $p_p | ";
				print ""
				  . Format_Number(int( $totalfamily_h{$family} ))
				  . " | $p_h |   | ";
				print "
\n";
				$familyheadershown = 1;
			}
			$keysinkeylist{$key} = 1;
			my $ver = $1;
			my $p_h = ' ';
			my $p_p = ' ';
			if ($total_h) {
				$p_h = 
				  int( $_browser_h{$key} / $total_h * 1000 ) / 10;
				$p_h = "$p_h %";
			}
			if ($total_p) {
				$p_p =
				  int( $_browser_p{$key} / $total_p * 1000 ) / 10;
				$p_p = "$p_p %";
			}
			print "";
			print "  | ";
			print ""
			  . ucfirst($family) . " "
			  . ( $ver ? "$ver" : "?" ) . " | ";
			print ""
			  . (
				$BrowsersHereAreGrabbers{$family}
				? "$Message[112]"
				: "$Message[113]"
			  )
			  . " | ";
			my $bredde_h = 0;
			my $bredde_p = 0;
			if ( $max_h > 0 ) {
				$bredde_h =
				  int( $BarWidth * ( $_browser_h{$key} || 0 ) /
					  $max_h ) + 1;
			}
			if ( ( $bredde_h == 1 ) && $_browser_h{$key} ) {
				$bredde_h = 2;
			}
			if ( $max_p > 0 ) {
				$bredde_p =
				  int( $BarWidth * ( $_browser_p{$key} || 0 ) /
					  $max_p ) + 1;
			}
			if ( ( $bredde_p == 1 ) && $_browser_p{$key} ) {
				$bredde_p = 2;
			}
			print "".Format_Number($_browser_p{$key})." | $p_p | ";
			print "".Format_Number($_browser_h{$key})." | $p_h | ";
			print "";
			# alt and title are not provided to reduce page size
			if ($ShowBrowsersStats) {
				print
"  ";
				print
"  ";
				}
				print " | ";
				print "
\n";
				$count++;
			}
		}
	}
	# Write other records
	my $familyheadershown = 0;
	foreach my $key (@keylist) {
		if ( $keysinkeylist{$key} ) { next; }
		if ( !$familyheadershown )  {
			my $p_h = ' ';
			my $p_p = ' ';
			if ($total_p) {
				$p_p =
				  int( ( $total_p - $TotalFamily_p ) / $total_p * 1000 ) /
				  10;
				$p_p = "$p_p %";
			}
			if ($total_h) {
				$p_h =
				  int( ( $total_h - $TotalFamily_h ) / $total_h * 1000 ) /
				  10;
				$p_h = "$p_h %";
			}
			print
"| $Message[2] | ";
			print "  | "
			  . Format_Number(( $total_p - $TotalFamily_p ))
			  . " | $p_p | ";
			print ""
			  . Format_Number(( $total_h - $TotalFamily_h ))
			  . " | $p_h |   | ";
			print "
\n";
			$familyheadershown = 1;
		}
		my $p_h = ' ';
		my $p_p = ' ';
		if ($total_h) {
			$p_h = int( $_browser_h{$key} / $total_h * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($total_p) {
			$p_p = int( $_browser_p{$key} / $total_p * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		print "";
		if ( $key eq 'Unknown' ) {
			print "  | $Message[0] | ? | ";
		}
		else {
			my $keywithoutcumul = $key;
			$keywithoutcumul =~ s/cumul$//i;
			my $libbrowser = $BrowsersHashIDLib{$keywithoutcumul}
			  || $keywithoutcumul;
			my $nameicon = $BrowsersHashIcon{$keywithoutcumul}
			  || "notavailable";
			print "  | $libbrowser | "
			  . (
				$BrowsersHereAreGrabbers{$key}
				? "$Message[112]"
				: "$Message[113]"
			  )
			  . " | ";
		}
		my $bredde_h = 0;
		my $bredde_p = 0;
		if ( $max_h > 0 ) {
			$bredde_h =
			  int( $BarWidth * ( $_browser_h{$key} || 0 ) / $max_h ) +
			  1;
		}
		if ( $max_p > 0 ) {
			$bredde_p =
			  int( $BarWidth * ( $_browser_p{$key} || 0 ) / $max_p ) +
			  1;
		}
		if ( ( $bredde_h == 1 ) && $_browser_h{$key} ) {
			$bredde_h = 2;
		}
		if ( ( $bredde_p == 1 ) && $_browser_p{$key} ) {
			$bredde_p = 2;
		}
		print "".Format_Number($_browser_p{$key})." | $p_p | ";
		print "".Format_Number($_browser_h{$key})." | $p_h | ";
		print "";
		# alt and title are not provided to reduce page size
		if ($ShowBrowsersStats) {
			print
"  ";
			print
"  ";
		}
		print " | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Unknown Browser Detail frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowBrowserUnknown{
    my $NewLinkTarget = shift;
	print "$Center 
\n";
	my $title = "$Message[50]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
	&tab_head( "$title", 19, 0, 'unknownbrowser' );
	print "| User agent ("
	  . ( scalar keys %_unknownrefererbrowser_l )
	  . ") | $Message[9] | 
\n";
	my $total_l = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_unknownrefererbrowser_l,
		\%_unknownrefererbrowser_l );
	foreach my $key (@keylist) {
		my $useragent = XMLEncode( CleanXSS($key) );
		print
		  "| $useragent | "
		  . Format_Date( $_unknownrefererbrowser_l{$key}, 1 )
		  . " | 
\n";
		$total_l += 1;
		$count++;
	}
	my $rest_l = ( scalar keys %_unknownrefererbrowser_l ) - $total_l;
	if ( $rest_l > 0 ) {
		print
"| $Message[2] | ";
		print "- | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the OS Detail frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowOSDetail{
	# Show os versions
	print "$Center 
";
	my $title = "$Message[59]";
	&tab_head( "$title", 19, 0, 'osversions' );
	print
"| $Message[58] | ";
	print
"$Message[56] | $Message[15] | ";
	print
"$Message[57] | $Message[15] | ";
	print "
\n";
	my $total_h = 0;
	my $total_p = 0;
	my $count = 0;
	&BuildKeyList( MinimumButNoZero( scalar keys %_os_h, 500 ),
		1, \%_os_h, \%_os_p );
	my %keysinkeylist = ();
	my $max_h = 1;
	my $max_p = 1;
	# Count total by family
	my %totalfamily_h = ();
	my %totalfamily_p = ();
	my $TotalFamily_h = 0;
	my $TotalFamily_p = 0;
  OSLOOP: foreach my $key (@keylist) {
		$total_h += $_os_h{$key};
		$total_p += $_os_p{$key};
		if ( $_os_h{$key} > $max_h ) { $max_h = $_os_h{$key}; }
		if ( $_os_p{$key} > $max_p ) { $max_p = $_os_p{$key}; }
		foreach my $family ( keys %OSFamily ) {
			if ( $key =~ /^$family/i ) {
				$totalfamily_h{$family} += $_os_h{$key};
				$totalfamily_p{$family} += $_os_p{$key};
				$TotalFamily_h          += $_os_h{$key};
				$TotalFamily_p          += $_os_p{$key};
				next OSLOOP;
			}
		}
	}
	# Write records grouped in a browser family
	foreach my $family ( keys %OSFamily ) {
		my $p_h = ' ';
		my $p_p = ' ';
		if ($total_h) {
			$p_h = int( $totalfamily_h{$family} / $total_h * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($total_p) {
			$p_p = int( $totalfamily_p{$family} / $total_p * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		my $familyheadershown = 0;
		foreach my $key ( reverse sort keys %_os_h ) {
			if ( $key =~ /^$family(.*)/i ) {
				if ( !$familyheadershown ) {
					my $family_name = '';
					if ( $OSFamily{$family} ) {
						$family_name = $OSFamily{$family};
					}
					print
"| $family_name | ";
					print ""
					  . Format_Number(int( $totalfamily_p{$family} ))
					  . " | $p_p | ";
					print ""
					  . Format_Number(int( $totalfamily_h{$family} ))
					  . " | $p_h |   | ";
					print "
\n";
					$familyheadershown = 1;
				}
				$keysinkeylist{$key} = 1;
				my $ver = $1;
				my $p_h = ' ';
				my $p_p = ' ';
				if ($total_h) {
					$p_h = int( $_os_h{$key} / $total_h * 1000 ) / 10;
					$p_h = "$p_h %";
				}
				if ($total_p) {
					$p_p = int( $_os_p{$key} / $total_p * 1000 ) / 10;
					$p_p = "$p_p %";
				}
				print "";
				print "  | ";
				print "$OSHashLib{$key} | ";
				my $bredde_h = 0;
				my $bredde_p = 0;
				if ( $max_h > 0 ) {
					$bredde_h =
					  int( $BarWidth * ( $_os_h{$key} || 0 ) / $max_h )
					  + 1;
				}
				if ( ( $bredde_h == 1 ) && $_os_h{$key} ) {
					$bredde_h = 2;
				}
				if ( $max_p > 0 ) {
					$bredde_p =
					  int( $BarWidth * ( $_os_p{$key} || 0 ) / $max_p )
					  + 1;
				}
				if ( ( $bredde_p == 1 ) && $_os_p{$key} ) {
					$bredde_p = 2;
				}
				print "".Format_Number($_os_p{$key})." | $p_p | ";
				print "".Format_Number($_os_h{$key})." | $p_h | ";
				print "";
				# alt and title are not provided to reduce page size
				if ($ShowOSStats) {
					print
"  ";
					print
"  ";
				}
				print " | ";
				print "
\n";
				$count++;
			}
		}
	}
	# Write other records
	my $familyheadershown = 0;
	foreach my $key (@keylist) {
		if ( $keysinkeylist{$key} ) { next; }
		if ( !$familyheadershown )  {
			my $p_h = ' ';
			my $p_p = ' ';
			if ($total_h) {
				$p_h =
				  int( ( $total_h - $TotalFamily_h ) / $total_h * 1000 ) /
				  10;
				$p_h = "$p_h %";
			}
			if ($total_p) {
				$p_p =
				  int( ( $total_p - $TotalFamily_p ) / $total_p * 1000 ) /
				  10;
				$p_p = "$p_p %";
			}
			print
"| $Message[2] | ";
			print ""
			  . Format_Number(( $total_p - $TotalFamily_p ))
			  . " | $p_p | ";
			print ""
			  . Format_Number(( $total_h - $TotalFamily_h ))
			  . " | $p_h |   | ";
			print "
\n";
			$familyheadershown = 1;
		}
		my $p_h = ' ';
		my $p_p = ' ';
		if ($total_h) {
			$p_h = int( $_os_h{$key} / $total_h * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($total_p) {
			$p_p = int( $_os_p{$key} / $total_p * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		print "";
		if ( $key eq 'Unknown' ) {
			print "  | $Message[0] | ";
		}
		else {
			my $keywithoutcumul = $key;
			$keywithoutcumul =~ s/cumul$//i;
			my $libos = $OSHashLib{$keywithoutcumul}
			  || $keywithoutcumul;
			my $nameicon = $keywithoutcumul;
			$nameicon =~ s/[^\w]//g;
			print "  | $libos | ";
		}
		my $bredde_h = 0;
		my $bredde_p = 0;
		if ( $max_h > 0 ) {
			$bredde_h =
			  int( $BarWidth * ( $_os_h{$key} || 0 ) / $max_h ) + 1;
		}
		if ( ( $bredde_h == 1 ) && $_os_h{$key} ) { $bredde_h = 2; }
		if ( $max_p > 0 ) {
			$bredde_p =
			  int( $BarWidth * ( $_os_p{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_p == 1 ) && $_os_p{$key} ) { $bredde_p = 2; }
		print "".Format_Number($_os_p{$key})." | $p_p | ";
		print "".Format_Number($_os_h{$key})." | $p_h | ";
		print "";
		# alt and title are not provided to reduce page size
		if ($ShowOSStats) {
			print
"  ";
			print
"  ";
		}
		print " | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Unknown OS Detail frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowOSUnknown{
    my $NewLinkTarget = shift;
	print "$Center 
\n";
	my $title = "$Message[46]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
    &tab_head( "$title", 19, 0, 'unknownos' );
	print "| User agent ("
	  . ( scalar keys %_unknownreferer_l )
	  . ") | $Message[9] | 
\n";
	my $total_l = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_unknownreferer_l,
		\%_unknownreferer_l );
	foreach my $key (@keylist) {
		my $useragent = XMLEncode( CleanXSS($key) );
		print "| $useragent | ";
		print ""
		  . Format_Date( $_unknownreferer_l{$key}, 1 ) . " | ";
		print "
\n";
		$total_l += 1;
		$count++;
	}
	my $rest_l = ( scalar keys %_unknownreferer_l ) - $total_l;
	if ( $rest_l > 0 ) {
		print
"| $Message[2] | ";
		print "- | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Referers frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowReferers{
    my $NewLinkTarget = shift;
	print "$Center 
\n";
	my $title = "$Message[40]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
    &tab_head( $title, 19, 0, 'refererse' );
	print
"| ".Format_Number($TotalDifferentSearchEngines)." $Message[122] | ";
	print
"$Message[56] | $Message[15] | ";
	print
"$Message[57] | $Message[15] | ";
	print "
\n";
	my $total_s = 0;
	my $total_p = 0;
	my $total_h = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $count = 0;
	&BuildKeyList(
		$MaxRowsInHTMLOutput,
		$MinHit{'Refer'},
		\%_se_referrals_h,
		(
			( scalar keys %_se_referrals_p )
			? \%_se_referrals_p
			: \%_se_referrals_h
		)
	);    # before 5.4 only hits were recorded
	foreach my $key (@keylist) {
		my $newreferer = $SearchEnginesHashLib{$key} || CleanXSS($key);
		my $p_p;
		my $p_h;
		if ($TotalSearchEnginesPages) {
			$p_p =
			  int( $_se_referrals_p{$key} / $TotalSearchEnginesPages *
				  1000 ) / 10;
		}
		if ($TotalSearchEnginesHits) {
			$p_h =
			  int( $_se_referrals_h{$key} / $TotalSearchEnginesHits *
				  1000 ) / 10;
		}
		print "| $newreferer | ";
		print ""
		  . (
			$_se_referrals_p{$key} ? $_se_referrals_p{$key} : ' ' )
		  . " | ";
		print ""
		  . ( $_se_referrals_p{$key} ? "$p_p %" : ' ' ) . " | ";
		print "".Format_Number($_se_referrals_h{$key})." | ";
		print "$p_h % | ";
		print "
\n";
		$total_p += $_se_referrals_p{$key};
		$total_h += $_se_referrals_h{$key};
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalSearchEnginesPages / $total_p - $TotalSearchEnginesHits / $total_h",
			2
		);
	}
	$rest_p = $TotalSearchEnginesPages - $total_p;
	$rest_h = $TotalSearchEnginesHits - $total_h;
	if ( $rest_p > 0 || $rest_h > 0 ) {
		my $p_p;
		my $p_h;
		if ($TotalSearchEnginesPages) {
			$p_p =
			  int( $rest_p / $TotalSearchEnginesPages * 1000 ) / 10;
		}
		if ($TotalSearchEnginesHits) {
			$p_h = int( $rest_h / $TotalSearchEnginesHits * 1000 ) / 10;
		}
		print
"| $Message[2] | ";
		print "" . ( $rest_p ? Format_Number($rest_p)  : ' ' ) . " | ";
		print "" . ( $rest_p ? "$p_p %" : ' ' ) . " | ";
		print "".Format_Number($rest_h)." | ";
		print "$p_h % | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Referer Pages frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowRefererPages{
    my $NewLinkTarget = shift;
	print "$Center 
\n";
	my $total_p = 0;
	my $total_h = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	# Show filter form
	&HTMLShowFormFilter(
		"refererpagesfilter",
		$FilterIn{'refererpages'},
		$FilterEx{'refererpages'}
	);
	my $title = "$Message[41]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    }
    my $cpt   = 0;
	$cpt = ( scalar keys %_pagesrefs_h );
	&tab_head( "$title", 19, 0, 'refererpages' );
	print "";
	if ( $FilterIn{'refererpages'} || $FilterEx{'refererpages'} ) {
		if ( $FilterIn{'refererpages'} ) {
			print "$Message[79] $FilterIn{'refererpages'}";
		}
		if ( $FilterIn{'refererpages'} && $FilterEx{'refererpages'} ) {
			print " - ";
		}
		if ( $FilterEx{'refererpages'} ) {
			print
			  "Exclude $Message[79] $FilterEx{'refererpages'}";
		}
		if ( $FilterIn{'refererpages'} || $FilterEx{'refererpages'} ) {
			print ": ";
		}
		print "$cpt $Message[28]";
		#if ($MonthRequired ne 'all') {
		#	if ($HTMLOutput{'refererpages'}) { print " $Message[102]: $TotalDifferentPages $Message[28]"; }
		#}
	}
	else { print "$Message[102]: ".Format_Number($cpt)." $Message[28]"; }
	print " | ";
	print
"$Message[56] | $Message[15] | ";
	print
"$Message[57] | $Message[15] | ";
	print "
\n";
	my $total_s = 0;
	my $count = 0;
	&BuildKeyList(
		$MaxRowsInHTMLOutput,
		$MinHit{'Refer'},
		\%_pagesrefs_h,
		(
			( scalar keys %_pagesrefs_p )
			? \%_pagesrefs_p
			: \%_pagesrefs_h
		)
	);
	foreach my $key (@keylist) {
		my $nompage = CleanXSS($key);
		if ( length($nompage) > $MaxLengthOfShownURL ) {
			$nompage =
			  substr( $nompage, 0, $MaxLengthOfShownURL ) . "...";
		}
		my $p_p;
		my $p_h;
		if ($TotalRefererPages) {
			$p_p =
			  int( $_pagesrefs_p{$key} / $TotalRefererPages * 1000 ) /
			  10;
		}
		if ($TotalRefererHits) {
			$p_h =
			  int( $_pagesrefs_h{$key} / $TotalRefererHits * 1000 ) /
			  10;
		}
		print "| ";
		&HTMLShowURLInfo($key);
		print " | ";
		print ""
		  . ( $_pagesrefs_p{$key} ? Format_Number($_pagesrefs_p{$key}) : ' ' )
		  . " | "
		  . ( $_pagesrefs_p{$key} ? "$p_p %" : ' ' ) . " | ";
		print ""
		  . ( $_pagesrefs_h{$key} ? Format_Number($_pagesrefs_h{$key}) : ' ' )
		  . " | "
		  . ( $_pagesrefs_h{$key} ? "$p_h %" : ' ' ) . " | ";
		print "
\n";
		$total_p += $_pagesrefs_p{$key};
		$total_h += $_pagesrefs_h{$key};
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",
			2
		);
	}
	$rest_p = $TotalRefererPages - $total_p;
	$rest_h = $TotalRefererHits - $total_h;
	if ( $rest_p > 0 || $rest_h > 0 ) {
		my $p_p;
		my $p_h;
		if ($TotalRefererPages) {
			$p_p = int( $rest_p / $TotalRefererPages * 1000 ) / 10;
		}
		if ($TotalRefererHits) {
			$p_h = int( $rest_h / $TotalRefererHits * 1000 ) / 10;
		}
		print
"| $Message[2] | ";
		print "" . ( $rest_p ? Format_Number($rest_p)  : ' ' ) . " | ";
		print "" . ( $rest_p ? "$p_p %" : ' ' ) . " | ";
		print "".Format_Number($rest_h)." | ";
		print "$p_h % | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Key Phrases frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowKeyPhrases{
	my $NewLinkTarget = shift;
	print "$Center 
\n";
    my $title = "$Message[43]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
	&tab_head( $title, 19, 0, 'keyphrases' );
	print "| ".Format_Number($TotalDifferentKeyphrases)." $Message[103] | $Message[14] | $Message[15] | 
\n";
	my $total_s = 0;
	my $count = 0;
	&BuildKeyList(
		$MaxRowsInHTMLOutput, $MinHit{'Keyphrase'},
		\%_keyphrases,        \%_keyphrases
	);
	foreach my $key (@keylist) {
		my $mot;
  		# Convert coded keywords (utf8,...) to be correctly reported in HTML page.
		if ( $PluginsLoaded{'DecodeKey'}{'decodeutfkeys'} ) {
			$mot = CleanXSS(
				DecodeKey_decodeutfkeys(
					$key, $PageCode || 'iso-8859-1'
				)
			);
		}
		else { $mot = CleanXSS( DecodeEncodedString($key) ); }
		my $p;
		if ($TotalKeyphrases) {
			$p =
			  int( $_keyphrases{$key} / $TotalKeyphrases * 1000 ) / 10;
		}
		print "| "
		  . XMLEncode($mot)
		  . " | $_keyphrases{$key} | $p % | 
\n";
		$total_s += $_keyphrases{$key};
		$count++;
	}
	if ($Debug) {
		debug( "Total real / shown : $TotalKeyphrases / $total_s", 2 );
	}
	my $rest_s = $TotalKeyphrases - $total_s;
	if ( $rest_s > 0 ) {
		my $p;
		if ($TotalKeyphrases) {
			$p = int( $rest_s / $TotalKeyphrases * 1000 ) / 10;
		}
		print
"| $Message[124] | ".Format_Number($rest_s)." | ";
				print "$p % | 
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Keywords frame or static page
# Parameters:   $NewLinkTarget
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowKeywords{
	my $NewLinkTarget = shift;
	print "$Center 
\n";
	my $title = "$Message[44]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
	&tab_head( $title, 19, 0, 'keywords' );
	print "| ".Format_Number($TotalDifferentKeywords)." $Message[13] | $Message[14] | $Message[15] | 
\n";
	my $total_s = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Keyword'},
		\%_keywords, \%_keywords );
	foreach my $key (@keylist) {
		my $mot;
  		# Convert coded keywords (utf8,...) to be correctly reported in HTML page.
		if ( $PluginsLoaded{'DecodeKey'}{'decodeutfkeys'} ) {
			$mot = CleanXSS(
				DecodeKey_decodeutfkeys(
					$key, $PageCode || 'iso-8859-1'
				)
			);
		}
		else { $mot = CleanXSS( DecodeEncodedString($key) ); }
		my $p;
		if ($TotalKeywords) {
			$p = int( $_keywords{$key} / $TotalKeywords * 1000 ) / 10;
		}
		print "| "
		  . XMLEncode($mot)
		  . " | $_keywords{$key} | $p % | 
\n";
		$total_s += $_keywords{$key};
		$count++;
	}
	if ($Debug) {
		debug( "Total real / shown : $TotalKeywords / $total_s", 2 );
	}
	my $rest_s = $TotalKeywords - $total_s;
	if ( $rest_s > 0 ) {
		my $p;
		if ($TotalKeywords) {
			$p = int( $rest_s / $TotalKeywords * 1000 ) / 10;
		}
		print
"| $Message[30] | ".Format_Number($rest_s)." | ";
		print "$p % | 
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the HTTP Error code frame or static page
# Parameters:   $code - the error code we're printing
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowErrorCodes{
	my $code = shift;
	my $title;
	my %customtitles = ( "404", "$Message[47]" );
	$title = $customtitles{$code} ? $customtitles{$code} :
	           (join(' ', ( ($httpcodelib{$code} ? $httpcodelib{$code} :
	           'Unknown error'), "urls (HTTP code " . $code . ")" )));
	print "$Center 
\n";
	&tab_head( $title, 19, 0, "errors$code" );
	print "| URL ("
	  . Format_Number(( scalar keys %{$_sider_h{$code}} ))
	  . ") | $Message[49] | ";
	foreach (split(//, $ShowHTTPErrorsPageDetail)) {
		if ( $_ =~ /R/i ) {
			print "$Message[23] | ";
		} elsif ( $_ =~ /H/i ) {
			print "$Message[81] | ";
		}
	}
	print "
\n";
	my $total_h = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%{$_sider_h{$code}},
		\%{$_sider_h{$code}} );
	foreach my $key (@keylist) {
		my $nompage = XMLEncode( CleanXSS($key) );
		#if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; }
		my $referer = XMLEncode( CleanXSS( $_referer_h{$code}{$key} ) );
		my $host = XMLEncode( CleanXSS( $_err_host_h{$code}{$key} ) );
		print "| $nompage | ";
		print "".Format_Number($_sider_h{$code}{$key})." | ";
		foreach (split(//, $ShowHTTPErrorsPageDetail)) {
			if ( $_ =~ /R/i ) {
				print "" . ( $referer ? "$referer" : " " ) . " | ";
			} elsif ( $_ =~ /H/i ) {
				print "" . ( $host ? "$host" : " " ) . " | ";
			}
		}
		print "
\n";
		my $total_s += $_sider_h{$code}{$key};
		$count++;
	}
# TODO Build TotalErrorHits
#			if ($Debug) { debug("Total real / shown : $TotalErrorHits / $total_h",2); }
#			$rest_h=$TotalErrorHits-$total_h;
#			if ($rest_h > 0) {
#				my $p;
#				if ($TotalErrorHits) { $p=int($rest_h/$TotalErrorHits*1000)/10; }
#				print "| $Message[30] | ";
#				print "$rest_h | ";
#				print "... | ";
#				print "
\n";
#			}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Loops through any defined extra sections and dumps the info to HTML
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowExtraSections{
	foreach my $extranum ( 1 .. @ExtraName - 1 ) {
		my $total_p = 0;
		my $total_h = 0;
		my $total_k = 0;
		
		if ( $HTMLOutput{"allextra$extranum"} ) {
			if ($Debug) { debug( "ExtraName$extranum", 2 ); }
			print "$Center 
";
			my $title = $ExtraName[$extranum];
			&tab_head( "$title ($Message[77] $MaxNbOfExtra[$extranum])", 19, 0, "extra$extranum");
			print "";
			print "| " . $ExtraFirstColumnTitle[$extranum] . " | ";
			if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
				print
"$Message[56] | ";
			}
			if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
				print
"$Message[57] | ";
			}
			if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
				print
"$Message[75] | ";
			}
			if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
				print "$Message[9] | ";
			}
			print "
\n";
			$total_p = $total_h = $total_k = 0;
 #$max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } }
 #$max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } }
			my $count = 0;
			if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
				&BuildKeyList(
					$MaxRowsInHTMLOutput,
					$MinHitExtra[$extranum],
					\%{ '_section_' . $extranum . '_h' },
					\%{ '_section_' . $extranum . '_p' }
				);
			}
			else {
				&BuildKeyList(
					$MaxRowsInHTMLOutput,
					$MinHitExtra[$extranum],
					\%{ '_section_' . $extranum . '_h' },
					\%{ '_section_' . $extranum . '_h' }
				);
			}
			my %keysinkeylist = ();
			foreach my $key (@keylist) {
				$keysinkeylist{$key} = 1;
				my $firstcol = CleanXSS( DecodeEncodedString($key) );
				$total_p += ${ '_section_' . $extranum . '_p' }{$key};
				$total_h += ${ '_section_' . $extranum . '_h' }{$key};
				$total_k += ${ '_section_' . $extranum . '_k' }{$key};
				print "";
				printf(
"| $ExtraFirstColumnFormat[$extranum] | ",
					$firstcol, $firstcol, $firstcol, $firstcol, $firstcol );
				if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
					print ""
					  . ${ '_section_' . $extranum . '_p' }{$key} . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
					print ""
					  . ${ '_section_' . $extranum . '_h' }{$key} . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
					print ""
					  . Format_Bytes(
						${ '_section_' . $extranum . '_k' }{$key} )
					  . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
					print ""
					  . (
						${ '_section_' . $extranum . '_l' }{$key}
						? Format_Date(
							${ '_section_' . $extranum . '_l' }{$key}, 1 )
						: '-'
					  )
					  . " | ";
				}
				print "
\n";
				$count++;
			}
			# If we ask average or sum, we loop on all other records
			if (   $ExtraAddAverageRow[$extranum]
				|| $ExtraAddSumRow[$extranum] )
			{
				foreach ( keys %{ '_section_' . $extranum . '_h' } ) {
					if ( $keysinkeylist{$_} ) { next; }
					$total_p += ${ '_section_' . $extranum . '_p' }{$_};
					$total_h += ${ '_section_' . $extranum . '_h' }{$_};
					$total_k += ${ '_section_' . $extranum . '_k' }{$_};
					$count++;
				}
			}
			# Add average row
			if ( $ExtraAddAverageRow[$extranum] ) {
				print "";
				print "| $Message[96] | ";
				if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
					print ""
					  . ( $count ? Format_Number(( $total_p / $count )) : " " )
					  . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
					print ""
					  . ( $count ? Format_Number(( $total_h / $count )) : " " )
					  . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
					print ""
					  . (
						$count
						? Format_Bytes( $total_k / $count )
						: " "
					  )
					  . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
					print "  | ";
				}
				print "
\n";
			}
			# Add sum row
			if ( $ExtraAddSumRow[$extranum] ) {
				print "";
				print "| $Message[102] | ";
				if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
					print "" . ($total_p) . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
					print "" . ($total_h) . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
					print "" . Format_Bytes($total_k) . " | ";
				}
				if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
					print "  | ";
				}
				print "
\n";
			}
			&tab_end();
			&html_end(1);
		}
	}
}
#------------------------------------------------------------------------------
# Function:     Prints the Robot details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowRobots{
	my $total_p = 0;
	my $total_h = 0;
	my $total_k = 0;
	my $total_r = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $rest_k = 0;
	my $rest_r = 0;
	
	print "$Center 
\n";
	my $title = '';
	if ( $HTMLOutput{'allrobots'} )  { $title .= "$Message[53]"; }
	if ( $HTMLOutput{'lastrobots'} ) { $title .= "$Message[9]"; }
	&tab_head( "$title", 19, 0, 'robots' );
	print "| "
	  . Format_Number(( scalar keys %_robot_h ))
	  . " $Message[51] | ";
	if ( $ShowRobotsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowRobotsStats =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowRobotsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	$total_p = $total_h = $total_k = $total_r = 0;
	my $count = 0;
	if ( $HTMLOutput{'allrobots'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Robot'},
			\%_robot_h, \%_robot_h );
	}
	if ( $HTMLOutput{'lastrobots'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Robot'},
			\%_robot_h, \%_robot_l );
	}
	foreach my $key (@keylist) {
		print "| "
		  . ( $RobotsHashIDLib{$key} ? $RobotsHashIDLib{$key} : $key )
		  . " | ";
		if ( $ShowRobotsStats =~ /H/i ) {
			print ""
			  . Format_Number(( $_robot_h{$key} - $_robot_r{$key} ))
			  . ( $_robot_r{$key} ? "+$_robot_r{$key}" : "" ) . " | ";
		}
		if ( $ShowRobotsStats =~ /B/i ) {
			print "" . Format_Bytes( $_robot_k{$key} ) . " | ";
		}
		if ( $ShowRobotsStats =~ /L/i ) {
			print ""
			  . (
				$_robot_l{$key}
				? Format_Date( $_robot_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		#$total_p += $_robot_p{$key}||0;
		$total_h += $_robot_h{$key};
		$total_k += $_robot_k{$key} || 0;
		$total_r += $_robot_r{$key} || 0;
		$count++;
	}
	# For bots we need to count Totals
	my $TotalPagesRobots =
	  0;    #foreach (values %_robot_p) { $TotalPagesRobots+=$_; }
	my $TotalHitsRobots = 0;
	foreach ( values %_robot_h ) { $TotalHitsRobots += $_; }
	my $TotalBytesRobots = 0;
	foreach ( values %_robot_k ) { $TotalBytesRobots += $_; }
	my $TotalRRobots = 0;
	foreach ( values %_robot_r ) { $TotalRRobots += $_; }
	$rest_p = 0;    #$rest_p=$TotalPagesRobots-$total_p;
	$rest_h = $TotalHitsRobots - $total_h;
	$rest_k = $TotalBytesRobots - $total_k;
	$rest_r = $TotalRRobots - $total_r;
	if ($Debug) {
		debug(
"Total real / shown : $TotalPagesRobots / $total_p - $TotalHitsRobots / $total_h - $TotalBytesRobots / $total_k",
			2
		);
	}
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0 )
	{               # All other robots
		print
"| $Message[2] | ";
		if ( $ShowRobotsStats =~ /H/i ) { print "".Format_Number($rest_h)." | "; }
		if ( $ShowRobotsStats =~ /B/i ) {
			print "" . ( Format_Bytes($rest_k) ) . " | ";
		}
		if ( $ShowRobotsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end(
		"* $Message[156]" . ( $TotalRRobots ? " $Message[157]" : "" ) );
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the URL, Entry or Exit details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowURLDetail{
	my $total_p = 0;
	my $total_e = 0;
	my $total_k = 0;
	my $total_x = 0;
	# Call to plugins' function ShowPagesFilter
	foreach
	  my $pluginname ( keys %{ $PluginsLoaded{'ShowPagesFilter'} } )
	{
		my $function = "ShowPagesFilter_$pluginname";
		&$function();
	}
	print "$Center 
\n";
	# Show filter form
	&HTMLShowFormFilter( "urlfilter", $FilterIn{'url'}, $FilterEx{'url'} );
	# Show URL list
	my $title = '';
	my $cpt   = 0;
	if ( $HTMLOutput{'urldetail'} ) {
		$title = $Message[19];
		$cpt   = ( scalar keys %_url_p );
	}
	if ( $HTMLOutput{'urlentry'} ) {
		$title = $Message[104];
		$cpt   = ( scalar keys %_url_e );
	}
	if ( $HTMLOutput{'urlexit'} ) {
		$title = $Message[116];
		$cpt   = ( scalar keys %_url_x );
	}
	&tab_head( "$title", 19, 0, 'urls' );
	print "";
	if ( $FilterIn{'url'} || $FilterEx{'url'} ) {
		if ( $FilterIn{'url'} ) {
			print "$Message[79] $FilterIn{'url'}";
		}
		if ( $FilterIn{'url'} && $FilterEx{'url'} ) { print " - "; }
		if ( $FilterEx{'url'} ) {
			print "Exclude $Message[79] $FilterEx{'url'}";
		}
		if ( $FilterIn{'url'} || $FilterEx{'url'} ) { print ": "; }
		print Format_Number($cpt)." $Message[28]";
		if ( $MonthRequired ne 'all' ) {
			if ( $HTMLOutput{'urldetail'} ) {
				print
" $Message[102]: ".Format_Number($TotalDifferentPages)." $Message[28]";
			}
		}
	}
	else { print "$Message[102]: ".Format_Number($cpt)." $Message[28]"; }
	print " | ";
	if ( $ShowPagesStats =~ /P/i ) {
		print
		  "$Message[29] | ";
	}
	if ( $ShowPagesStats =~ /B/i ) {
		print
"$Message[106] | ";
	}
	if ( $ShowPagesStats =~ /E/i ) {
		print
		  "$Message[104] | ";
	}
	if ( $ShowPagesStats =~ /X/i ) {
		print
		  "$Message[116] | ";
	}
	# Call to plugins' function ShowPagesAddField
	foreach
	  my $pluginname ( keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
	{
		#    			my $function="ShowPagesAddField_$pluginname('title')";
		#    			eval("$function");
		my $function = "ShowPagesAddField_$pluginname";
		&$function('title');
	}
	print "  | 
\n";
	$total_p = $total_k = $total_e = $total_x = 0;
	my $count = 0;
	if ( $HTMLOutput{'urlentry'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'File'}, \%_url_e,
			\%_url_e );
	}
	elsif ( $HTMLOutput{'urlexit'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'File'}, \%_url_x,
			\%_url_x );
	}
	else {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'File'}, \%_url_p,
			\%_url_p );
	}
	my $max_p = 1;
	my $max_k = 1;
	foreach my $key (@keylist) {
		if ( $_url_p{$key} > $max_p ) { $max_p = $_url_p{$key}; }
		if ( $_url_k{$key} / ( $_url_p{$key} || 1 ) > $max_k ) {
			$max_k = $_url_k{$key} / ( $_url_p{$key} || 1 );
		}
	}
	foreach my $key (@keylist) {
		print "| ";
		&HTMLShowURLInfo($key);
		print " | ";
		my $bredde_p = 0;
		my $bredde_e = 0;
		my $bredde_x = 0;
		my $bredde_k = 0;
		if ( $max_p > 0 ) {
			$bredde_p =
			  int( $BarWidth * ( $_url_p{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_p == 1 ) && $_url_p{$key} ) { $bredde_p = 2; }
		if ( $max_p > 0 ) {
			$bredde_e =
			  int( $BarWidth * ( $_url_e{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_e == 1 ) && $_url_e{$key} ) { $bredde_e = 2; }
		if ( $max_p > 0 ) {
			$bredde_x =
			  int( $BarWidth * ( $_url_x{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_x == 1 ) && $_url_x{$key} ) { $bredde_x = 2; }
		if ( $max_k > 0 ) {
			$bredde_k =
			  int( $BarWidth *
				  ( ( $_url_k{$key} || 0 ) / ( $_url_p{$key} || 1 ) ) /
				  $max_k ) + 1;
		}
		if ( ( $bredde_k == 1 ) && $_url_k{$key} ) { $bredde_k = 2; }
		if ( $ShowPagesStats =~ /P/i ) {
			print "".Format_Number($_url_p{$key})." | ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print ""
			  . (
				$_url_k{$key}
				? Format_Bytes(
					$_url_k{$key} / ( $_url_p{$key} || 1 )
				  )
				: " "
			  )
			  . " | ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print ""
			  . ( $_url_e{$key} ? Format_Number($_url_e{$key}) : " " ) . " | ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print ""
			  . ( $_url_x{$key} ? Format_Number($_url_x{$key}) : " " ) . " | ";
		}
		# Call to plugins' function ShowPagesAddField
		foreach my $pluginname (
			keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
		{
		  #    				my $function="ShowPagesAddField_$pluginname('$key')";
		  #    				eval("$function");
			my $function = "ShowPagesAddField_$pluginname";
			&$function($key);
		}
		print "";
		# alt and title are not provided to reduce page size
		if ( $ShowPagesStats =~ /P/i ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print
" ";
		}
		print " | 
\n";
		$total_p += $_url_p{$key};
		$total_e += $_url_e{$key};
		$total_x += $_url_x{$key};
		$total_k += $_url_k{$key};
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalPages / $total_p - $TotalEntries / $total_e - $TotalExits / $total_x - $TotalBytesPages / $total_k",
			2
		);
	}
	my $rest_p = $TotalPages - $total_p;
	my $rest_k = $TotalBytesPages - $total_k;
	my $rest_e = $TotalEntries - $total_e;
	my $rest_x = $TotalExits - $total_x;
	if ( $rest_p > 0 || $rest_e > 0 || $rest_k > 0 ) {
		print
"| $Message[2] | ";
		if ( $ShowPagesStats =~ /P/i ) {
			print "" . ( $rest_p ? Format_Number($rest_p) : " " ) . " | ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print ""
			  . (
				$rest_k
				? Format_Bytes( $rest_k / ( $rest_p || 1 ) )
				: " "
			  )
			  . " | ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print "" . ( $rest_e ? Format_Number($rest_e) : " " ) . " | ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print "" . ( $rest_x ? Format_Number($rest_x) : " " ) . " | ";
		}
		# Call to plugins' function ShowPagesAddField
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
		{
			my $function = "ShowPagesAddField_$pluginname";
			&$function('');
		}
		print "  | 
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Login details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowLogins{
	my $total_p = 0;
	my $total_h = 0;
	my $total_k = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $rest_k = 0;
	print "$Center 
\n";
	my $title = '';
	if ( $HTMLOutput{'alllogins'} )  { $title .= "$Message[94]"; }
	if ( $HTMLOutput{'lastlogins'} ) { $title .= "$Message[9]"; }
	&tab_head( "$title", 19, 0, 'logins' );
	print "| $Message[94] : "
	  . Format_Number(( scalar keys %_login_h )) . " | ";
	&HTMLShowUserInfo('__title__');
	if ( $ShowAuthenticatedUsers =~ /P/i ) {
		print
		  "$Message[56] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	$total_p = $total_h = $total_k = 0;
	my $count = 0;
	if ( $HTMLOutput{'alllogins'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Login'},
			\%_login_h, \%_login_p );
	}
	if ( $HTMLOutput{'lastlogins'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Login'},
			\%_login_h, \%_login_l );
	}
	foreach my $key (@keylist) {
		print "| $key | ";
		&HTMLShowUserInfo($key);
		if ( $ShowAuthenticatedUsers =~ /P/i ) {
			print ""
			  . ( $_login_p{$key} ? Format_Number($_login_p{$key}) : " " )
			  . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /H/i ) {
			print "".Format_Number($_login_h{$key})." | ";
		}
		if ( $ShowAuthenticatedUsers =~ /B/i ) {
			print "" . Format_Bytes( $_login_k{$key} ) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /L/i ) {
			print ""
			  . (
				$_login_l{$key}
				? Format_Date( $_login_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		$total_p += $_login_p{$key} || 0;
		$total_h += $_login_h{$key};
		$total_k += $_login_k{$key} || 0;
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",
			2
		);
	}
	$rest_p = $TotalPages - $total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{    # All other logins and/or anonymous
		print
"| $Message[125] | ";
		&HTMLShowUserInfo('');
		if ( $ShowAuthenticatedUsers =~ /P/i ) {
			print "" . ( $rest_p ? Format_Number($rest_p) : " " ) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /H/i ) {
			print "".Format_Number($rest_h)." | ";
		}
		if ( $ShowAuthenticatedUsers =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /L/i ) {
			print "  | ";
		}
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Unknown IP/Host details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowHostsUnknown{
	my $total_p = 0;
	my $total_h = 0;
	my $total_k = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $rest_k = 0;
	print "$Center 
\n";
	&tab_head( "$Message[45]", 19, 0, 'unknownwip' );
	print "| "
	  . Format_Number(( scalar keys %_host_h ))
	  . " $Message[1] | ";
	&HTMLShowHostInfo('__title__');
	if ( $ShowHostsStats =~ /P/i ) {
		print
		  "$Message[56] | ";
	}
	if ( $ShowHostsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowHostsStats =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowHostsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	$total_p = $total_h = $total_k = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Host'}, \%_host_h,
		\%_host_p );
	foreach my $key (@keylist) {
		my $host = CleanXSS($key);
		print "| $host | ";
		&HTMLShowHostInfo($key);
		if ( $ShowHostsStats =~ /P/i ) {
			print ""
			  . ( $_host_p{$key} ? Format_Number($_host_p{$key}) : " " )
			  . " | ";
		}
		if ( $ShowHostsStats =~ /H/i ) {
			print "".Format_Number($_host_h{$key})." | ";
		}
		if ( $ShowHostsStats =~ /B/i ) {
			print "" . Format_Bytes( $_host_k{$key} ) . " | ";
		}
		if ( $ShowHostsStats =~ /L/i ) {
			print ""
			  . (
				$_host_l{$key}
				? Format_Date( $_host_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		$total_p += $_host_p{$key};
		$total_h += $_host_h{$key};
		$total_k += $_host_k{$key} || 0;
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",
			2
		);
	}
	$rest_p = $TotalPages - $total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{    # All other visitors (known or not)
		print
"| $Message[82] | ";
		&HTMLShowHostInfo('');
		if ( $ShowHostsStats =~ /P/i ) {
			print "" . ( $rest_p ? Format_Number($rest_p) : " " ) . " | ";
		}
		if ( $ShowHostsStats =~ /H/i ) { print "".Format_Number($rest_h)." | "; }
		if ( $ShowHostsStats =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowHostsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Host details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowHosts{
	my $total_p = 0;
	my $total_h = 0;
	my $total_k = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $rest_k = 0;
	print "$Center 
\n";
	# Show filter form
	&HTMLShowFormFilter( "hostfilter", $FilterIn{'host'},
		$FilterEx{'host'} );
	# Show hosts list
	my $title = '';
	my $cpt   = 0;
	if ( $HTMLOutput{'allhosts'} ) {
		$title .= "$Message[81]";
		$cpt = ( scalar keys %_host_h );
	}
	if ( $HTMLOutput{'lasthosts'} ) {
		$title .= "$Message[9]";
		$cpt = ( scalar keys %_host_h );
	}
	&tab_head( "$title", 19, 0, 'hosts' );
	print "";
	if ( $FilterIn{'host'} || $FilterEx{'host'} ) {    # With filter
		if ( $FilterIn{'host'} ) {
			print "$Message[79] '$FilterIn{'host'}'";
		}
		if ( $FilterIn{'host'} && $FilterEx{'host'} ) { print " - "; }
		if ( $FilterEx{'host'} ) {
			print " Exclude $Message[79] '$FilterEx{'host'}'";
		}
		if ( $FilterIn{'host'} || $FilterEx{'host'} ) { print ": "; }
		print "$cpt $Message[81]";
		if ( $MonthRequired ne 'all' ) {
			if ( $HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'} ) {
				print
" $Message[102]: ".Format_Number($TotalHostsKnown)." $Message[82], ".Format_Number($TotalHostsUnknown)." $Message[1] - ".Format_Number($TotalUnique)." $Message[11]";
			}
		}
	}
	else {    # Without filter
		if ( $MonthRequired ne 'all' ) {
			print
"$Message[102] : ".Format_Number($TotalHostsKnown)." $Message[82], ".Format_Number($TotalHostsUnknown)." $Message[1] - ".Format_Number($TotalUnique)." $Message[11]";
		}
		else { print "$Message[102] : " . Format_Number(( scalar keys %_host_h )); }
	}
	print " | ";
	&HTMLShowHostInfo('__title__');
	if ( $ShowHostsStats =~ /P/i ) {
		print
		  "$Message[56] | ";
	}
	if ( $ShowHostsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowHostsStats =~ /B/i ) {
		print
"$Message[75] | ";
	}
	if ( $ShowHostsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	$total_p = $total_h = $total_k = 0;
	my $count = 0;
	if ( $HTMLOutput{'allhosts'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Host'}, \%_host_h,
			\%_host_p );
	}
	if ( $HTMLOutput{'lasthosts'} ) {
		&BuildKeyList( $MaxRowsInHTMLOutput, $MinHit{'Host'}, \%_host_h,
			\%_host_l );
	}
	my $regipv4=qr/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
	if ( $DynamicDNSLookup == 2 ) {
		# Use static DNS file
		&Read_DNS_Cache( \%MyDNSTable, "$DNSStaticCacheFile", "", 1 );
	}
	foreach my $key (@keylist) {
		my $host = CleanXSS($key);
		print "| "
		  . ( $_robot_l{$key} ? ''  : '' ) . "$host"
		  . ( $_robot_l{$key} ? '' : '' );
		if ($DynamicDNSLookup) {
			# Dynamic reverse DNS lookup
        	        if ($host =~ /$regipv4/o) {
                	        my $lookupresult=lc(gethostbyaddr(pack("C4",split(/\./,$host)),AF_INET));       # This may be slow
                        	if (! $lookupresult || $lookupresult =~ /$regipv4/o || ! IsAscii($lookupresult)) {
					if ( $DynamicDNSLookup == 2 ) {
						# Check static DNS file
						$lookupresult = $MyDNSTable{$host};
						if ($lookupresult) { print " ($lookupresult)"; }
						else { print ""; }
					}
					else { print ""; }
	                        }
        	                else { print " ($lookupresult)"; }
	                }
		}
		print " | ";
		&HTMLShowHostInfo($key);
		if ( $ShowHostsStats =~ /P/i ) {
			print ""
			  . ( $_host_p{$key} ? Format_Number($_host_p{$key}) : " " )
			  . " | ";
		}
		if ( $ShowHostsStats =~ /H/i ) {
			print "".Format_Number($_host_h{$key})." | ";
		}
		if ( $ShowHostsStats =~ /B/i ) {
			print "" . Format_Bytes( $_host_k{$key} ) . " | ";
		}
		if ( $ShowHostsStats =~ /L/i ) {
			print ""
			  . (
				$_host_l{$key}
				? Format_Date( $_host_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		$total_p += $_host_p{$key};
		$total_h += $_host_h{$key};
		$total_k += $_host_k{$key} || 0;
		$count++;
	}
	if ($Debug) {
		debug(
"Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",
			2
		);
	}
	$rest_p = $TotalPages - $total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{    # All other visitors (known or not)
		print
"| $Message[2] | ";
		&HTMLShowHostInfo('');
		if ( $ShowHostsStats =~ /P/i ) {
			print "" . ( $rest_p ? Format_Number($rest_p) : " " ) . " | ";
		}
		if ( $ShowHostsStats =~ /H/i ) { print "".Format_Number($rest_h)." | "; }
		if ( $ShowHostsStats =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowHostsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Domains details frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowDomains{
	my $total_p = 0;
	my $total_h = 0;
	my $total_k = 0;
	my $total_v = 0;
	my $total_u = 0;
	my $rest_p = 0;
	my $rest_h = 0;
	my $rest_k = 0;
	my $rest_v = 0;
	my $rest_u = 0;
	print "$Center 
\n";
	# Show domains list
	my $title = '';
	my $cpt   = 0;
	if ( $HTMLOutput{'alldomains'} ) {
		$title .= "$Message[25]";
		$cpt = ( scalar keys %_domener_h );
	}
	&tab_head( "$title", 19, 0, 'domains' );
	print
"|   | $Message[17] | ";
	if ( $ShowDomainsStats =~ /U/i ) {
		print
		  "$Message[11] | ";
	}
	if ( $ShowDomainsStats =~ /V/i ) {
		print
		  "$Message[10] | ";
	}
	if ( $ShowDomainsStats =~ /P/i ) {
		print
		  "$Message[56] | ";
	}
	if ( $ShowDomainsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowDomainsStats =~ /B/i ) {
		print
"$Message[75] | ";
	}
	print "  | ";
	print "
\n";
	$total_u = $total_v = $total_p = $total_h = $total_k = 0;
	my $max_h = 1;
	foreach ( values %_domener_h ) {
		if ( $_ > $max_h ) { $max_h = $_; }
	}
	my $max_k = 1;
	foreach ( values %_domener_k ) {
		if ( $_ > $max_k ) { $max_k = $_; }
	}
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_domener_h,
		\%_domener_p );
	foreach my $key (@keylist) {
		my ( $_domener_u, $_domener_v );
		my $bredde_p = 0;
		my $bredde_h = 0;
		my $bredde_k = 0;
		if ( $max_h > 0 ) {
			$bredde_p =
			  int( $BarWidth * $_domener_p{$key} / $max_h ) + 1;
		}    # use max_h to enable to compare pages with hits
		if ( $_domener_p{$key} && $bredde_p == 1 ) { $bredde_p = 2; }
		if ( $max_h > 0 ) {
			$bredde_h =
			  int( $BarWidth * $_domener_h{$key} / $max_h ) + 1;
		}
		if ( $_domener_h{$key} && $bredde_h == 1 ) { $bredde_h = 2; }
		if ( $max_k > 0 ) {
			$bredde_k =
			  int( $BarWidth * ( $_domener_k{$key} || 0 ) / $max_k ) +
			  1;
		}
		if ( $_domener_k{$key} && $bredde_k == 1 ) { $bredde_k = 2; }
		my $newkey = lc($key);
		if ( $newkey eq 'ip' || !$DomainsHashIDLib{$newkey} ) {
			print
"  | $Message[0] | $newkey | ";
		}
		else {
			print
"
  | $DomainsHashIDLib{$newkey} | $newkey | ";
		}
		## to add unique visitors and number of visits, by Josep Ruano @ CAPSiDE
		if ( $ShowDomainsStats =~ /U/i ) {
			$_domener_u = (
				  $_domener_p{$key}
				? $_domener_p{$key} / $TotalPages
				: 0
			);
			$_domener_u += ( $_domener_h{$key} / $TotalHits );
			$_domener_u =
			  sprintf( "%.0f", ( $_domener_u * $TotalUnique ) / 2 );
			print "".Format_Number($_domener_u)." ("
			  . sprintf( "%.1f%", 100 * $_domener_u / $TotalUnique )
			  . ") | ";
		}
		if ( $ShowDomainsStats =~ /V/i ) {
			$_domener_v = (
				  $_domener_p{$key}
				? $_domener_p{$key} / $TotalPages
				: 0
			);
			$_domener_v += ( $_domener_h{$key} / $TotalHits );
			$_domener_v =
			  sprintf( "%.0f", ( $_domener_v * $TotalVisits ) / 2 );
			print "".Format_Number($_domener_v)." ("
			  . sprintf( "%.1f%", 100 * $_domener_v / $TotalVisits )
			  . ") | ";
		}
		if ( $ShowDomainsStats =~ /P/i ) {
			print "".Format_Number($_domener_p{$key})." | ";
		}
		if ( $ShowDomainsStats =~ /H/i ) {
			print "".Format_Number($_domener_h{$key})." | ";
		}
		if ( $ShowDomainsStats =~ /B/i ) {
			print "" . Format_Bytes( $_domener_k{$key} ) . " | ";
		}
		print "";
		if ( $ShowDomainsStats =~ /P/i ) {
			print
"  \n";
		}
		if ( $ShowDomainsStats =~ /H/i ) {
			print
"  \n";
		}
		if ( $ShowDomainsStats =~ /B/i ) {
			print
" ";
		}
		print " | ";
		print "
\n";
		$total_u += $_domener_u;
		$total_v += $_domener_v;
		$total_p += $_domener_p{$key};
		$total_h += $_domener_h{$key};
		$total_k += $_domener_k{$key} || 0;
		$count++;
	}
	my $rest_u = $TotalUnique - $total_u;
	my $rest_v = $TotalVisits - $total_v;
	$rest_p = $TotalPages - $total_p;
	$rest_h = $TotalHits - $total_h;
	$rest_k = $TotalBytes - $total_k;
	if (   $rest_u > 0
		|| $rest_v > 0
		|| $rest_p > 0
		|| $rest_h > 0
		|| $rest_k > 0 )
	{    # All other domains (known or not)
		print
"|   | $Message[2] | ";
		if ( $ShowDomainsStats =~ /U/i ) { print "$rest_u | "; }
		if ( $ShowDomainsStats =~ /V/i ) { print "$rest_v | "; }
		if ( $ShowDomainsStats =~ /P/i ) { print "$rest_p | "; }
		if ( $ShowDomainsStats =~ /H/i ) { print "$rest_h | "; }
		if ( $ShowDomainsStats =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		print "  | ";
		print "
\n";
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Downloads code frame or static page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLShowDownloads{
	my $regext         = qr/\.(\w{1,6})$/;
	print "$Center 
\n";
	&tab_head( $Message[178], 19, 0, "downloads" );
	print "| $Message[178] | ";
	if ( $ShowFileTypesStats =~ /H/i ){print "$Message[57] | "
		."206 $Message[57] | "; }
	if ( $ShowFileTypesStats =~ /B/i ){
		print "$Message[75] | ";
		print "$Message[106] | ";
	}
	print "
\n";
	my $count = 0;
	for my $u (sort {$_downloads{$b}->{'AWSTATS_HITS'} <=> $_downloads{$a}->{'AWSTATS_HITS'}}(keys %_downloads) ){
		print "";
		my $ext = Get_Extension($regext, $u);
		if ( !$ext) {
			print "  | ";
		}
		else {
			my $nameicon = $MimeHashLib{$ext}[0] || "notavailable";
			my $nametype = $MimeHashFamily{$MimeHashLib{$ext}[0]} || " ";
			print "  | ";
		}
		print "";
		&HTMLShowURLInfo($u);
		print " | ";
		if ( $ShowFileTypesStats =~ /H/i ){
			print "".Format_Number($_downloads{$u}->{'AWSTATS_HITS'})." | ";
			print "".Format_Number($_downloads{$u}->{'AWSTATS_206'})." | ";
		}
		if ( $ShowFileTypesStats =~ /B/i ){
			print "".Format_Bytes($_downloads{$u}->{'AWSTATS_SIZE'})." | ";
			print "".Format_Bytes(($_downloads{$u}->{'AWSTATS_SIZE'}/
					($_downloads{$u}->{'AWSTATS_HITS'} + $_downloads{$u}->{'AWSTATS_206'})))." | ";
		}
		print "
\n";
		$count++;
		if ($count >= $MaxRowsInHTMLOutput){last;}
	}
	&tab_end();
	&html_end(1);
}
#------------------------------------------------------------------------------
# Function:     Prints the Summary section at the top of the main page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainSummary{
	if ($Debug) { debug( "ShowSummary", 2 ); }
	# FirstTime LastTime
	my $FirstTime = 0;
	my $LastTime  = 0;
	foreach my $key ( keys %FirstTime ) {
		my $keyqualified = 0;
		if ( $MonthRequired eq 'all' ) { $keyqualified = 1; }
		if ( $key =~ /^$YearRequired$MonthRequired/ ) { $keyqualified = 1; }
		if ($keyqualified) {
			if ( $FirstTime{$key}
				&& ( $FirstTime == 0 || $FirstTime > $FirstTime{$key} ) )
			{
				$FirstTime = $FirstTime{$key};
			}
			if ( $LastTime < ( $LastTime{$key} || 0 ) ) {
				$LastTime = $LastTime{$key};
			}
		}
	}
			
	#print "$Center 
\n";
	my $title = "$Message[128]";
	&tab_head( "$title", 0, 0, 'month' );
	my $NewLinkParams = ${QueryString};
	$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)year=[^&]*//i;
	$NewLinkParams =~ s/(^|&|&)month=[^&]*//i;
	$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
	$NewLinkParams =~ s/(&|&)+/&/i;
	$NewLinkParams =~ s/^&//;
	$NewLinkParams =~ s/&$//;
	if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
	my $NewLinkTarget = '';
	if ( $FrameName eq 'mainright' ) {
		$NewLinkTarget = " target=\"_parent\"";
	}
	# Ratio
	my $RatioVisits = 0;
	my $RatioPages  = 0;
	my $RatioHits   = 0;
	my $RatioBytes  = 0;
	if ( $TotalUnique > 0 ) {
		$RatioVisits = int( $TotalVisits / $TotalUnique * 100 ) / 100;
	}
	if ( $TotalVisits > 0 ) {
		$RatioPages = int( $TotalPages / $TotalVisits * 100 ) / 100;
	}
	if ( $TotalVisits > 0 ) {
		$RatioHits = int( $TotalHits / $TotalVisits * 100 ) / 100;
	}
	if ( $TotalVisits > 0 ) {
		$RatioBytes =
		  int( ( $TotalBytes / 1024 ) * 100 /
			  ( $LogType eq 'M' ? $TotalHits : $TotalVisits ) ) / 100;
	}
	my $colspan = 5;
	my $w       = '20';
	if ( $LogType eq 'W' || $LogType eq 'S' ) {
		$w       = '17';
		$colspan = 6;
	}
	# Show first/last
	print "";
	print
"| $Message[133] | \n";
	print( $MonthRequired eq 'all'
		? "$Message[6] $YearRequired"
		: "$Message[5] "
		  . $MonthNumLib{$MonthRequired}
		  . " $YearRequired"
	);
	print " | 
\n";
	print "";
	print "| $Message[8] | \n";
	print ""
	  . ( $FirstTime ? Format_Date( $FirstTime, 0 ) : "NA" ) . " | ";
	print "
\n";
	print "";
	print "| $Message[9] | \n";
	print ""
	  . ( $LastTime ? Format_Date( $LastTime, 0 ) : "NA" )
	  . " | \n";
	print "
\n";
	# Show main indicators title row
	print "";
	if ( $LogType eq 'W' || $LogType eq 'S' ) {
		print "|   | ";
	}
	if ( $ShowSummary =~ /U/i ) {
		print "$Message[11] | ";
	}
	else {
		print
"  | ";
	}
	if ( $ShowSummary =~ /V/i ) {
		print "$Message[10] | ";
	}
	else {
		print
"  | ";
	}
	if ( $ShowSummary =~ /P/i ) {
		print "$Message[56] | ";
	}
	else {
		print
"  | ";
	}
	if ( $ShowSummary =~ /H/i ) {
		print "$Message[57] | ";
	}
	else {
		print
"  | ";
	}
	if ( $ShowSummary =~ /B/i ) {
		print "$Message[75] | ";
	}
	else {
		print
"  | ";
	}
	print "
\n";
	# Show main indicators values for viewed traffic
	print "";
	if ( $LogType eq 'M' ) {
		print "| $Message[165] | ";
		print "    | \n";
		print "    | \n";
		if ( $ShowSummary =~ /H/i ) {
			print "".Format_Number($TotalHits).""
			  . (
				$LogType eq 'M'
				? ""
				: " ($RatioHits "
				  . lc( $Message[57] . "/" . $Message[12] ) . ")"
			  )
			  . " | ";
		}
		else { print "  | "; }
		if ( $ShowSummary =~ /B/i ) {
			print ""
			  . Format_Bytes( int($TotalBytes) )
			  . " ($RatioBytes $Message[108]/"
			  . $Message[ ( $LogType eq 'M' ? 149 : 12 ) ]
			  . ") | ";
		}
		else { print "  | "; }
	}
	else {
		if ( $LogType eq 'W' || $LogType eq 'S' ) {
			print "$Message[160] * | ";
		}
		if ( $ShowSummary =~ /U/i ) {
			print ""
			  . (
				$MonthRequired eq 'all'
				? "<= ".Format_Number($TotalUnique)." $Message[129]"
				: "".Format_Number($TotalUnique)."  "
			  )
			  . " | ";
		}
		else { print "  | "; }
		if ( $ShowSummary =~ /V/i ) {
			print
"".Format_Number($TotalVisits)." ($RatioVisits $Message[52]) | ";
		}
		else { print "  | "; }
		if ( $ShowSummary =~ /P/i ) {
			print "".Format_Number($TotalPages)." ($RatioPages "
			  . $Message[56] . "/"
			  . $Message[12]
			  . ") | ";
		}
		else { print "  | "; }
		if ( $ShowSummary =~ /H/i ) {
			print "".Format_Number($TotalHits).""
			  . (
				$LogType eq 'M'
				? ""
				: " ($RatioHits "
				  . $Message[57] . "/"
				  . $Message[12] . ")"
			  )
			  . " | ";
		}
		else { print "  | "; }
		if ( $ShowSummary =~ /B/i ) {
			print ""
			  . Format_Bytes( int($TotalBytes) )
			  . " ($RatioBytes $Message[108]/"
			  . $Message[ ( $LogType eq 'M' ? 149 : 12 ) ]
			  . ") | ";
		}
		else { print "  | "; }
	}
	print "
\n";
	# Show main indicators values for not viewed traffic values
	if ( $LogType eq 'M' || $LogType eq 'W' || $LogType eq 'S' ) {
		print "";
		if ( $LogType eq 'M' ) {
			print "| $Message[166] | ";
			print "    | \n";
			print "    | \n";
			if ( $ShowSummary =~ /H/i ) {
				print "".Format_Number($TotalNotViewedHits)." | ";
			}
			else { print "  | "; }
			if ( $ShowSummary =~ /B/i ) {
				print ""
				  . Format_Bytes( int($TotalNotViewedBytes) )
				  . " | ";
			}
			else { print "  | "; }
		}
		else {
			if ( $LogType eq 'W' || $LogType eq 'S' ) {
				print "$Message[161] * | ";
			}
			print "    | \n";
			if ( $ShowSummary =~ /P/i ) {
				print "".Format_Number($TotalNotViewedPages)." | ";
			}
			else { print "  | "; }
			if ( $ShowSummary =~ /H/i ) {
				print "".Format_Number($TotalNotViewedHits)." | ";
			}
			else { print "  | "; }
			if ( $ShowSummary =~ /B/i ) {
				print ""
				  . Format_Bytes( int($TotalNotViewedBytes) )
				  . " | ";
			}
			else { print "  | "; }
		}
		print "
\n";
	}
	&tab_end($LogType eq 'W'
		  || $LogType eq 'S' ? "* $Message[159]" : "" );
}
#------------------------------------------------------------------------------
# Function:     Prints the Monthly section on the main page
# Parameters:   _
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainMonthly{
	if ($Debug) { debug( "ShowMonthStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[162]";
	&tab_head( "$title", 0, 0, 'month' );
	print "\n";
	print "\n";
	my $average_nb = my $average_u = my $average_v = my $average_p = 0;
	my $average_h = my $average_k = 0;
	my $total_u = my $total_v = my $total_p = my $total_h = my $total_k = 0;
	my $max_v = my $max_p = my $max_h = my $max_k = 1;
	# Define total and max
	for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
		my $monthix = sprintf( "%02s", $ix );
		$total_u += $MonthUnique{ $YearRequired . $monthix } || 0;
		$total_v += $MonthVisits{ $YearRequired . $monthix } || 0;
		$total_p += $MonthPages{ $YearRequired . $monthix }  || 0;
		$total_h += $MonthHits{ $YearRequired . $monthix }   || 0;
		$total_k += $MonthBytes{ $YearRequired . $monthix }  || 0;
#if (($MonthUnique{$YearRequired.$monthix}||0) > $max_v) { $max_v=$MonthUnique{$YearRequired.$monthix}; }
		if (
			( $MonthVisits{ $YearRequired . $monthix } || 0 ) > $max_v )
		{
			$max_v = $MonthVisits{ $YearRequired . $monthix };
		}
#if (($MonthPages{$YearRequired.$monthix}||0) > $max_p)  { $max_p=$MonthPages{$YearRequired.$monthix}; }
		if ( ( $MonthHits{ $YearRequired . $monthix } || 0 ) > $max_h )
		{
			$max_h = $MonthHits{ $YearRequired . $monthix };
		}
		if ( ( $MonthBytes{ $YearRequired . $monthix } || 0 ) > $max_k )
		{
			$max_k = $MonthBytes{ $YearRequired . $monthix };
		}
	}
	# Define average
	# TODO
	# Show bars for month
	my $graphdone=0;
	foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
	{
		my @blocklabel = ();
		for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
			my $monthix = sprintf( "%02s", $ix );
			push @blocklabel,
			  "$MonthNumLib{$monthix}\n$YearRequired";
		}
		my @vallabel = (
			"$Message[11]", "$Message[10]",
			"$Message[56]", "$Message[57]",
			"$Message[75]"
		);
		my @valcolor =
		  ( "$color_u", "$color_v", "$color_p", "$color_h",
			"$color_k" );
		my @valmax = ( $max_v, $max_v, $max_h, $max_h, $max_k );
		my @valtotal =
		  ( $total_u, $total_v, $total_p, $total_h, $total_k );
		my @valaverage = ();
		#my @valaverage=($average_v,$average_p,$average_h,$average_k);
		my @valdata = ();
		my $xx      = 0;
		for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
			my $monthix = sprintf( "%02s", $ix );
			$valdata[ $xx++ ] = $MonthUnique{ $YearRequired . $monthix }
			  || 0;
			$valdata[ $xx++ ] = $MonthVisits{ $YearRequired . $monthix }
			  || 0;
			$valdata[ $xx++ ] = $MonthPages{ $YearRequired . $monthix }
			  || 0;
			$valdata[ $xx++ ] = $MonthHits{ $YearRequired . $monthix }
			  || 0;
			$valdata[ $xx++ ] = $MonthBytes{ $YearRequired . $monthix }
			  || 0;
		}
		
		my $function = "ShowGraph_$pluginname";
		&$function(
			"$title",        "month",
			$ShowMonthStats, \@blocklabel,
			\@vallabel,      \@valcolor,
			\@valmax,        \@valtotal,
			\@valaverage,    \@valdata
		);
		$graphdone=1;
	}
	if (! $graphdone)
	{
		print "\n";
		print "";
		print "|   | \n";
		for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
			my $monthix  = sprintf( "%02s", $ix );
			my $bredde_u = 0;
			my $bredde_v = 0;
			my $bredde_p = 0;
			my $bredde_h = 0;
			my $bredde_k = 0;
			if ( $max_v > 0 ) {
				$bredde_u =
				  int(
					( $MonthUnique{ $YearRequired . $monthix } || 0 ) /
					  $max_v * $BarHeight ) + 1;
			}
			if ( $max_v > 0 ) {
				$bredde_v =
				  int(
					( $MonthVisits{ $YearRequired . $monthix } || 0 ) /
					  $max_v * $BarHeight ) + 1;
			}
			if ( $max_h > 0 ) {
				$bredde_p =
				  int(
					( $MonthPages{ $YearRequired . $monthix } || 0 ) /
					  $max_h * $BarHeight ) + 1;
			}
			if ( $max_h > 0 ) {
				$bredde_h =
				  int( ( $MonthHits{ $YearRequired . $monthix } || 0 ) /
					  $max_h * $BarHeight ) + 1;
			}
			if ( $max_k > 0 ) {
				$bredde_k =
				  int(
					( $MonthBytes{ $YearRequired . $monthix } || 0 ) /
					  $max_k * $BarHeight ) + 1;
			}
			print "";
			if ( $ShowMonthStats =~ /U/i ) {
				print
" ";
			}
			if ( $ShowMonthStats =~ /V/i ) {
				print
" ";
			}
			if ( $ShowMonthStats =~ /P/i ) {
				print
" ";
			}
			if ( $ShowMonthStats =~ /H/i ) {
				print
" ";
			}
			if ( $ShowMonthStats =~ /B/i ) {
				print
" ";
			}
			print " | \n";
		}
		print "  | ";
		print " \n";
		# Show lib for month
		print "";
		#if (!$StaticLinks) {
		#	print "| << | ";
		#}
		#else {
		print "  | ";
		#				}
		for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
			my $monthix = sprintf( "%02s", $ix );
#			if (!$StaticLinks) {
#				print "$MonthNumLib{$monthix} $YearRequired | ";
#			}
#			else {
			print ""
			  . (
				!$StaticLinks
				  && $monthix == $nowmonth
				  && $YearRequired == $nowyear
				? ''
				: ''
			  );
			print "$MonthNumLib{$monthix} $YearRequired";
			print(   !$StaticLinks
				  && $monthix == $nowmonth
				  && $YearRequired == $nowyear ? '' : '' );
			print " | ";
			#					}
		}
#		if (!$StaticLinks) {
#			print ">> | ";
#		}
#		else {
		print "  | ";
		#				}
		print " \n";
		print " \n";
	}
	print " \n";
	# Show data array for month
	if ($AddDataArrayMonthStats) {
		print "\n";
		print
"| $Message[5] | ";
		if ( $ShowMonthStats =~ /U/i ) {
			print "$Message[11] | ";
		}
		if ( $ShowMonthStats =~ /V/i ) {
			print "$Message[10] | ";
		}
		if ( $ShowMonthStats =~ /P/i ) {
			print "$Message[56] | ";
		}
		if ( $ShowMonthStats =~ /H/i ) {
			print "$Message[57] | ";
		}
		if ( $ShowMonthStats =~ /B/i ) {
			print "$Message[75] | ";
		}
		print " \n";
		for ( my $ix = 1 ; $ix <= 12 ; $ix++ ) {
			my $monthix = sprintf( "%02s", $ix );
			print "";
			print "| "
			  . (
				!$StaticLinks
				  && $monthix == $nowmonth
				  && $YearRequired == $nowyear
				? ''
				: ''
			  );
			print "$MonthNumLib{$monthix} $YearRequired";
			print(   !$StaticLinks
				  && $monthix == $nowmonth
				  && $YearRequired == $nowyear ? '' : '' );
			print " | ";
			if ( $ShowMonthStats =~ /U/i ) {
				print "",
				  Format_Number($MonthUnique{ $YearRequired . $monthix }
				  ? $MonthUnique{ $YearRequired . $monthix }
				  : "0"), " | ";
			}
			if ( $ShowMonthStats =~ /V/i ) {
				print "",
				  Format_Number($MonthVisits{ $YearRequired . $monthix }
				  ? $MonthVisits{ $YearRequired . $monthix }
				  : "0"), " | ";
			}
			if ( $ShowMonthStats =~ /P/i ) {
				print "",
				  Format_Number($MonthPages{ $YearRequired . $monthix }
				  ? $MonthPages{ $YearRequired . $monthix }
				  : "0"), " | ";
			}
			if ( $ShowMonthStats =~ /H/i ) {
				print "",
				  Format_Number($MonthHits{ $YearRequired . $monthix }
				  ? $MonthHits{ $YearRequired . $monthix }
				  : "0"), " | ";
			}
			if ( $ShowMonthStats =~ /B/i ) {
				print "",
				  Format_Bytes(
					int( $MonthBytes{ $YearRequired . $monthix } || 0 )
				  ), " | ";
			}
			print " \n";
		}
		# Average row
		# TODO
		# Total row
		print
"| $Message[102] | ";
		if ( $ShowMonthStats =~ /U/i ) {
			print
			  "".Format_Number($total_u)." | ";
		}
		if ( $ShowMonthStats =~ /V/i ) {
			print
			  "".Format_Number($total_v)." | ";
		}
		if ( $ShowMonthStats =~ /P/i ) {
			print
			  "".Format_Number($total_p)." | ";
		}
		if ( $ShowMonthStats =~ /H/i ) {
			print
			  "".Format_Number($total_h)." | ";
		}
		if ( $ShowMonthStats =~ /B/i ) {
			print ""
			  . Format_Bytes($total_k) . " | ";
		}
		print " \n";
		print " \n \n";
	}
	print "\n";
	print " | 
\n";
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Daily section on the main page
# Parameters:   $firstdaytocountaverage, $lastdaytocountaverage
#				$firstdaytoshowtime, $lastdaytoshowtime
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainDaily{
	my $firstdaytocountaverage = shift;
	my $lastdaytocountaverage = shift;
	my $firstdaytoshowtime = shift;
	my $lastdaytoshowtime = shift;
	
	if ($Debug) { debug( "ShowDaysOfMonthStats", 2 ); }
	print "$Center 
\n";
	my $NewLinkParams = ${QueryString};
	$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)year=[^&]*//i;
	$NewLinkParams =~ s/(^|&|&)month=[^&]*//i;
	$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
	$NewLinkParams =~ s/(&|&)+/&/i;
	$NewLinkParams =~ s/^&//;
	$NewLinkParams =~ s/&$//;
	if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
	my $NewLinkTarget = '';
	if ( $FrameName eq 'mainright' ) {
		$NewLinkTarget = " target=\"_parent\"";
	}
	my $title = "$Message[138]";
    if ($AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
        # extend the title to include the added link
            $title = "$title   -   $Message[179]");
    }
	&tab_head( "$title", 0, 0, 'daysofmonth' );
	print "";
	print "\n";
	print "\n";
	
	my $average_v = my $average_p = 0;
	my $average_h = my $average_k = 0;
	my $total_u = my $total_v = my $total_p = my $total_h = my $total_k = 0;
	my $max_v = my $max_h = my $max_k = 0;    # Start from 0 because can be lower than 1
	foreach my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
	{
		$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
		my $year  = $1;
		my $month = $2;
		my $day   = $3;
		if ( !DateIsValid( $day, $month, $year ) ) {
			next;
		}    # If not an existing day, go to next
		$total_v += $DayVisits{ $year . $month . $day } || 0;
		$total_p += $DayPages{ $year . $month . $day }  || 0;
		$total_h += $DayHits{ $year . $month . $day }   || 0;
		$total_k += $DayBytes{ $year . $month . $day }  || 0;
		if ( ( $DayVisits{ $year . $month . $day } || 0 ) > $max_v ) {
			$max_v = $DayVisits{ $year . $month . $day };
		}
#if (($DayPages{$year.$month.$day}||0) > $max_p)  { $max_p=$DayPages{$year.$month.$day}; }
		if ( ( $DayHits{ $year . $month . $day } || 0 ) > $max_h ) {
			$max_h = $DayHits{ $year . $month . $day };
		}
		if ( ( $DayBytes{ $year . $month . $day } || 0 ) > $max_k ) {
			$max_k = $DayBytes{ $year . $month . $day };
		}
	}
    $average_v = sprintf( "%.2f", $AverageVisits );
    $average_p = sprintf( "%.2f", $AveragePages );
    $average_h = sprintf( "%.2f", $AverageHits );
    $average_k = sprintf( "%.2f", $AverageBytes );
	# Show bars for day
	my $graphdone=0;
	foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
	{
		my @blocklabel = ();
		foreach my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}    # If not an existing day, go to next
			my $bold =
			  (      $day == $nowday
				  && $month == $nowmonth
				  && $year == $nowyear ? ':' : '' );
			my $weekend =
			  ( DayOfWeek( $day, $month, $year ) =~ /[06]/ ? '!' : '' );
			push @blocklabel,
			  "$day\n$MonthNumLib{$month}$weekend$bold";
		}
		my @vallabel = (
			"$Message[10]", "$Message[56]",
			"$Message[57]", "$Message[75]"
		);
		my @valcolor =
		  ( "$color_v", "$color_p", "$color_h", "$color_k" );
		my @valmax   = ( $max_v,   $max_h,   $max_h,   $max_k );
		my @valtotal = ( $total_v, $total_p, $total_h, $total_k );
		my @valaverage =
		  ( $average_v, $average_p, $average_h, $average_k );
		my @valdata = ();
		my $xx      = 0;
		foreach my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}    # If not an existing day, go to next
			$valdata[ $xx++ ] = $DayVisits{ $year . $month . $day }
			  || 0;
			$valdata[ $xx++ ] = $DayPages{ $year . $month . $day } || 0;
			$valdata[ $xx++ ] = $DayHits{ $year . $month . $day }  || 0;
			$valdata[ $xx++ ] = $DayBytes{ $year . $month . $day } || 0;
		}
		my $function = "ShowGraph_$pluginname";
		&$function(
			"$title",              "daysofmonth",
			$ShowDaysOfMonthStats, \@blocklabel,
			\@vallabel,            \@valcolor,
			\@valmax,              \@valtotal,
			\@valaverage,          \@valdata
		);
		$graphdone=1;
	}
	# If graph was not printed by a plugin
	if (! $graphdone) {
		print "\n";
		print "\n";
		foreach my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}    # If not an existing day, go to next
			my $bredde_v = 0;
			my $bredde_p = 0;
			my $bredde_h = 0;
			my $bredde_k = 0;
			if ( $max_v > 0 ) {
				$bredde_v =
				  int( ( $DayVisits{ $year . $month . $day } || 0 ) /
					  $max_v * $BarHeight ) + 1;
			}
			if ( $max_h > 0 ) {
				$bredde_p =
				  int( ( $DayPages{ $year . $month . $day } || 0 ) /
					  $max_h * $BarHeight ) + 1;
			}
			if ( $max_h > 0 ) {
				$bredde_h =
				  int( ( $DayHits{ $year . $month . $day } || 0 ) /
					  $max_h * $BarHeight ) + 1;
			}
			if ( $max_k > 0 ) {
				$bredde_k =
				  int( ( $DayBytes{ $year . $month . $day } || 0 ) /
					  $max_k * $BarHeight ) + 1;
			}
			print "";
			if ( $ShowDaysOfMonthStats =~ /V/i ) {
				print
" ";
			}
			if ( $ShowDaysOfMonthStats =~ /P/i ) {
				print
" ";
			}
			if ( $ShowDaysOfMonthStats =~ /H/i ) {
				print
" ";
			}
			if ( $ShowDaysOfMonthStats =~ /B/i ) {
				print
" ";
			}
			print " | \n";
		}
		print "  | ";
		# Show average value bars
		print "";
		my $bredde_v = 0;
		my $bredde_p = 0;
		my $bredde_h = 0;
		my $bredde_k = 0;
		if ( $max_v > 0 ) {
			$bredde_v = int( $average_v / $max_v * $BarHeight ) + 1;
		}
		if ( $max_h > 0 ) {
			$bredde_p = int( $average_p / $max_h * $BarHeight ) + 1;
		}
		if ( $max_h > 0 ) {
			$bredde_h = int( $average_h / $max_h * $BarHeight ) + 1;
		}
		if ( $max_k > 0 ) {
			$bredde_k = int( $average_k / $max_k * $BarHeight ) + 1;
		}
		$average_v = sprintf( "%.2f", $average_v );
		$average_p = sprintf( "%.2f", $average_p );
		$average_h = sprintf( "%.2f", $average_h );
		$average_k = sprintf( "%.2f", $average_k );
		if ( $ShowDaysOfMonthStats =~ /V/i ) {
			print
" ";
		}
		if ( $ShowDaysOfMonthStats =~ /P/i ) {
			print
" ";
		}
		if ( $ShowDaysOfMonthStats =~ /H/i ) {
			print
" ";
		}
		if ( $ShowDaysOfMonthStats =~ /B/i ) {
			print
" ";
		}
		print " | \n";
		print " \n";
		# Show lib for day
		print "";
		foreach
		  my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}    # If not an existing day, go to next
			my $dayofweekcursor = DayOfWeek( $day, $month, $year );
			print "";
			print(
				!$StaticLinks
				  && $day == $nowday
				  && $month == $nowmonth
				  && $year == $nowyear
				? ''
				: ''
			);
			print "$day "
			  . $MonthNumLib{$month}
			  . "";
			print(   !$StaticLinks
				  && $day == $nowday
				  && $month == $nowmonth
				  && $year == $nowyear ? '' : '' );
			print " | \n";
		}
		print "  | ";
		print "$Message[96] | \n";
		print " \n";
		print " \n";
	}
	print " \n";
	# Show data array for days
	if ($AddDataArrayShowDaysOfMonthStats) {
		print "\n";
		print
"| $Message[4] | ";
		if ( $ShowDaysOfMonthStats =~ /V/i ) {
			print "$Message[10] | ";
		}
		if ( $ShowDaysOfMonthStats =~ /P/i ) {
			print "$Message[56] | ";
		}
		if ( $ShowDaysOfMonthStats =~ /H/i ) {
			print "$Message[57] | ";
		}
		if ( $ShowDaysOfMonthStats =~ /B/i ) {
			print "$Message[75] | ";
		}
		print " ";
		foreach
		  my $daycursor ( $firstdaytoshowtime .. $lastdaytoshowtime )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}    # If not an existing day, go to next
			my $dayofweekcursor = DayOfWeek( $day, $month, $year );
			print "";
			print "| "
			  . (
				!$StaticLinks
				  && $day == $nowday
				  && $month == $nowmonth
				  && $year == $nowyear
				? ''
				: ''
			  );
			print Format_Date( "$year$month$day" . "000000", 2 );
			print(   !$StaticLinks
				  && $day == $nowday
				  && $month == $nowmonth
				  && $year == $nowyear ? '' : '' );
			print " | ";
			if ( $ShowDaysOfMonthStats =~ /V/i ) {
				print "",
				  Format_Number($DayVisits{ $year . $month . $day }
				  ? $DayVisits{ $year . $month . $day }
				  : "0"), " | ";
			}
			if ( $ShowDaysOfMonthStats =~ /P/i ) {
				print "",
				  Format_Number($DayPages{ $year . $month . $day }
				  ? $DayPages{ $year . $month . $day }
				  : "0"), " | ";
			}
			if ( $ShowDaysOfMonthStats =~ /H/i ) {
				print "",
				  Format_Number($DayHits{ $year . $month . $day }
				  ? $DayHits{ $year . $month . $day }
				  : "0"), " | ";
			}
			if ( $ShowDaysOfMonthStats =~ /B/i ) {
				print "",
				  Format_Bytes(
					int( $DayBytes{ $year . $month . $day } || 0 ) ),
				  " | ";
			}
			print " \n";
		}
		# Average row
		print
"| $Message[96] | ";
		if ( $ShowDaysOfMonthStats =~ /V/i ) {
			print "".Format_Number(int($average_v))." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /P/i ) {
			print "".Format_Number(int($average_p))." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /H/i ) {
			print "".Format_Number(int($average_h))." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /B/i ) {
			print "".Format_Bytes(int($average_k))." | ";
		}
		print " \n";
		# Total row
		print
"| $Message[102] | ";
		if ( $ShowDaysOfMonthStats =~ /V/i ) {
			print "".Format_Number($total_v)." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /P/i ) {
			print "".Format_Number($total_p)." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /H/i ) {
			print "".Format_Number($total_h)." | ";
		}
		if ( $ShowDaysOfMonthStats =~ /B/i ) {
			print "" . Format_Bytes($total_k) . " | ";
		}
		print " \n";
		print " \n ";
	}
	print "\n";
	print " | 
\n";
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Days of the Week section on the main page
# Parameters:   $firstdaytocountaverage, $lastdaytocountaverage
# Input:        _
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainDaysofWeek{
	my $firstdaytocountaverage = shift;
	my $lastdaytocountaverage = shift;
    my $NewLinkParams = shift;
    my $NewLinkTarget = shift;	
    
	if ($Debug) { debug( "ShowDaysOfWeekStats", 2 ); }
			print "$Center 
\n";
			my $title = "$Message[91]";
			&tab_head( "$title", 18, 0, 'daysofweek' );
			print "";
			print "";
			print "\n";
			my $max_h = my $max_k = 0;    # Start from 0 because can be lower than 1
			                        # Get average value for day of week
			my @avg_dayofweek_nb = ();
			my @avg_dayofweek_p  = ();
			my @avg_dayofweek_h  = ();
			my @avg_dayofweek_k  = ();
			foreach my $daycursor (
				$firstdaytocountaverage .. $lastdaytocountaverage )
			{
				$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
				my $year  = $1;
				my $month = $2;
				my $day   = $3;
				if ( !DateIsValid( $day, $month, $year ) ) {
					next;
				}    # If not an existing day, go to next
				my $dayofweekcursor = DayOfWeek( $day, $month, $year );
				$avg_dayofweek_nb[$dayofweekcursor]
				  ++; # Increase number of day used to count for this day of week
				$avg_dayofweek_p[$dayofweekcursor] +=
				  ( $DayPages{$daycursor} || 0 );
				$avg_dayofweek_h[$dayofweekcursor] +=
				  ( $DayHits{$daycursor} || 0 );
				$avg_dayofweek_k[$dayofweekcursor] +=
				  ( $DayBytes{$daycursor} || 0 );
			}
			for (@DOWIndex) {
				if ( $avg_dayofweek_nb[$_] ) {
					$avg_dayofweek_p[$_] =
					  $avg_dayofweek_p[$_] / $avg_dayofweek_nb[$_];
					$avg_dayofweek_h[$_] =
					  $avg_dayofweek_h[$_] / $avg_dayofweek_nb[$_];
					$avg_dayofweek_k[$_] =
					  $avg_dayofweek_k[$_] / $avg_dayofweek_nb[$_];
		  #if ($avg_dayofweek_p[$_] > $max_p) { $max_p = $avg_dayofweek_p[$_]; }
					if ( $avg_dayofweek_h[$_] > $max_h ) {
						$max_h = $avg_dayofweek_h[$_];
					}
					if ( $avg_dayofweek_k[$_] > $max_k ) {
						$max_k = $avg_dayofweek_k[$_];
					}
				}
				else {
					$avg_dayofweek_p[$_] = "?";
					$avg_dayofweek_h[$_] = "?";
					$avg_dayofweek_k[$_] = "?";
				}
			}
			# Show bars for days of week
			my $graphdone=0;
			foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
			{
				my @blocklabel = ();
				for (@DOWIndex) {
					push @blocklabel,
					  ( $Message[ $_ + 84 ] . ( $_ =~ /[06]/ ? "!" : "" ) );
				}
				my @vallabel =
				  ( "$Message[56]", "$Message[57]", "$Message[75]" );
				my @valcolor = ( "$color_p", "$color_h", "$color_k" );
				my @valmax = ( int($max_h), int($max_h), int($max_k) );
				my @valtotal = ( $TotalPages, $TotalHits, $TotalBytes );
				# TEMP
				my $average_p = my $average_h = my $average_k = 0;
				$average_p = sprintf( "%.2f", $AveragePages );
				$average_h = sprintf( "%.2f", $AverageHits );
				$average_k = (
					int($average_k)
					? Format_Bytes( sprintf( "%.2f", $AverageBytes ) )
					: "0.00"
				);
				my @valaverage = ( $average_p, $average_h, $average_k );
				my @valdata    = ();
				my $xx         = 0;
				for (@DOWIndex) {
					$valdata[ $xx++ ] = $avg_dayofweek_p[$_] || 0;
					$valdata[ $xx++ ] = $avg_dayofweek_h[$_] || 0;
					$valdata[ $xx++ ] = $avg_dayofweek_k[$_] || 0;
					# Round to be ready to show array
					$avg_dayofweek_p[$_] =
					  sprintf( "%.2f", $avg_dayofweek_p[$_] );
					$avg_dayofweek_h[$_] =
					  sprintf( "%.2f", $avg_dayofweek_h[$_] );
					$avg_dayofweek_k[$_] =
					  sprintf( "%.2f", $avg_dayofweek_k[$_] );
					# Remove decimal part that are .0
					if ( $avg_dayofweek_p[$_] == int( $avg_dayofweek_p[$_] ) ) {
						$avg_dayofweek_p[$_] = int( $avg_dayofweek_p[$_] );
					}
					if ( $avg_dayofweek_h[$_] == int( $avg_dayofweek_h[$_] ) ) {
						$avg_dayofweek_h[$_] = int( $avg_dayofweek_h[$_] );
					}
				}
				my $function = "ShowGraph_$pluginname";
				&$function(
					"$title",             "daysofweek",
					$ShowDaysOfWeekStats, \@blocklabel,
					\@vallabel,           \@valcolor,
					\@valmax,             \@valtotal,
					\@valaverage,         \@valdata
				);
				$graphdone=1;
			}
			if (! $graphdone) 
			{
				print "\n";
				print "\n";
				for (@DOWIndex) {
					my $bredde_p = 0;
					my $bredde_h = 0;
					my $bredde_k = 0;
					if ( $max_h > 0 ) {
						$bredde_p = int(
							(
								  $avg_dayofweek_p[$_] ne '?'
								? $avg_dayofweek_p[$_]
								: 0
							) / $max_h * $BarHeight
						) + 1;
					}
					if ( $max_h > 0 ) {
						$bredde_h = int(
							(
								  $avg_dayofweek_h[$_] ne '?'
								? $avg_dayofweek_h[$_]
								: 0
							) / $max_h * $BarHeight
						) + 1;
					}
					if ( $max_k > 0 ) {
						$bredde_k = int(
							(
								  $avg_dayofweek_k[$_] ne '?'
								? $avg_dayofweek_k[$_]
								: 0
							) / $max_k * $BarHeight
						) + 1;
					}
					$avg_dayofweek_p[$_] = sprintf(
						"%.2f",
						(
							  $avg_dayofweek_p[$_] ne '?'
							? $avg_dayofweek_p[$_]
							: 0
						)
					);
					$avg_dayofweek_h[$_] = sprintf(
						"%.2f",
						(
							  $avg_dayofweek_h[$_] ne '?'
							? $avg_dayofweek_h[$_]
							: 0
						)
					);
					$avg_dayofweek_k[$_] = sprintf(
						"%.2f",
						(
							  $avg_dayofweek_k[$_] ne '?'
							? $avg_dayofweek_k[$_]
							: 0
						)
					);
					# Remove decimal part that are .0
					if ( $avg_dayofweek_p[$_] == int( $avg_dayofweek_p[$_] ) ) {
						$avg_dayofweek_p[$_] = int( $avg_dayofweek_p[$_] );
					}
					if ( $avg_dayofweek_h[$_] == int( $avg_dayofweek_h[$_] ) ) {
						$avg_dayofweek_h[$_] = int( $avg_dayofweek_h[$_] );
					}
					print "";
					if ( $ShowDaysOfWeekStats =~ /P/i ) {
						print
" ";
					}
					if ( $ShowDaysOfWeekStats =~ /H/i ) {
						print
" ";
					}
					if ( $ShowDaysOfWeekStats =~ /B/i ) {
						print
" ";
					}
					print " | \n";
				}
				print " \n";
				print "\n";
				for (@DOWIndex) {
					print "| "
					  . (
						!$StaticLinks
						  && $_ == ( $nowwday - 1 )
						  && $MonthRequired == $nowmonth
						  && $YearRequired == $nowyear
						? ''
						: ''
					  );
					print $Message[ $_ + 84 ];
					print(   !$StaticLinks
						  && $_ == ( $nowwday - 1 )
						  && $MonthRequired == $nowmonth
						  && $YearRequired == $nowyear ? '' : '' );
					print " | ";
				}
				print " \n \n";
			}
			print " \n";
			# Show data array for days of week
			if ($AddDataArrayShowDaysOfWeekStats) {
				print "\n";
				print
"| $Message[4] | ";
				if ( $ShowDaysOfWeekStats =~ /P/i ) {
					print "$Message[56] | ";
				}
				if ( $ShowDaysOfWeekStats =~ /H/i ) {
					print "$Message[57] | ";
				}
				if ( $ShowDaysOfWeekStats =~ /B/i ) {
					print "$Message[75] |  ";
				}
				for (@DOWIndex) {
					print "";
					print "| "
					  . (
						!$StaticLinks
						  && $_ == ( $nowwday - 1 )
						  && $MonthRequired == $nowmonth
						  && $YearRequired == $nowyear
						? ''
						: ''
					  );
					print $Message[ $_ + 84 ];
					print(   !$StaticLinks
						  && $_ == ( $nowwday - 1 )
						  && $MonthRequired == $nowmonth
						  && $YearRequired == $nowyear ? '' : '' );
					print " | ";
					if ( $ShowDaysOfWeekStats =~ /P/i ) {
						print "", Format_Number(int($avg_dayofweek_p[$_])), " | ";
					}
					if ( $ShowDaysOfWeekStats =~ /H/i ) {
						print "", Format_Number(int($avg_dayofweek_h[$_])), " | ";
					}
					if ( $ShowDaysOfWeekStats =~ /B/i ) {
						print "", Format_Bytes(int($avg_dayofweek_k[$_])),
						  " | ";
					}
					print " \n";
				}
				print " \n \n";
			}
			print " | ";
			print "
\n";
			&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Downloads chart and table
# Parameters:   -
# Input:        $NewLinkParams, $NewLinkTarget
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainDownloads{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	if (!$LevelForFileTypesDetection > 0){return;}
	if ($Debug) { debug( "ShowDownloadStats", 2 ); }
	my $regext         = qr/\.(\w{1,6})$/;
	print "$Center 
\n";
	my $Totalh = 0;
	if ($MaxNbOf{'DownloadsShown'} < 1){$MaxNbOf{'DownloadsShown'} = 10;}	# default if undefined
	my $title =
	  "$Message[178] ($Message[77] $MaxNbOf{'DownloadsShown'})   -   $Message[80]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
        # extend the title to include the added link
            $title = "$title   -   $Message[179]");
    }
	  
	&tab_head( "$title", 0, 0, 'downloads' );
	my $cnt=0;
	for my $u (sort {$_downloads{$b}->{'AWSTATS_HITS'} <=> $_downloads{$a}->{'AWSTATS_HITS'}}(keys %_downloads) ){
		$Totalh += $_downloads{$u}->{'AWSTATS_HITS'};
		$cnt++;
		if ($cnt > 4){last;}
	}
	# Graph the top five in a pie chart
	if (($Totalh > 0) and (scalar keys %_downloads > 1)){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			for my $u (sort {$_downloads{$b}->{'AWSTATS_HITS'} <=> $_downloads{$a}->{'AWSTATS_HITS'}}(keys %_downloads) ){
				push @valdata, ($_downloads{$u}->{'AWSTATS_HITS'} / $Totalh * 1000 ) / 10;
				push @blocklabel, Get_Filename($u);
				$cnt++;
				if ($cnt > 4) { last; }
			}
			my $columns = 2;
			if ($ShowDownloadsStats =~ /H/i){$columns += length($ShowDownloadsStats)+1;}
			else{$columns += length($ShowDownloadsStats);}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"$Message[80]",              "downloads",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	my $total_dls = scalar keys %_downloads;
	print "| $Message[178]: $total_dls | ";
	if ( $ShowDownloadsStats =~ /H/i ){print "$Message[57] | "
		."206 $Message[57] | "; }
	if ( $ShowDownloadsStats =~ /B/i ){
		print "$Message[75] | ";
		print "$Message[106] | "; 
	}
	print "
\n";
	my $count   = 0;
	for my $u (sort {$_downloads{$b}->{'AWSTATS_HITS'} <=> $_downloads{$a}->{'AWSTATS_HITS'}}(keys %_downloads) ){
		print "";
		my $ext = Get_Extension($regext, $u);
		if ( !$ext) {
			print "  | ";
		}
		else {
			my $nameicon = $MimeHashLib{$ext}[0] || "notavailable";
			my $nametype = $MimeHashFamily{$MimeHashLib{$ext}[0]} || " ";
			print "  | ";
		}
		print "";
		&HTMLShowURLInfo($u);
		print " | ";
		if ( $ShowDownloadsStats =~ /H/i ){
			print "".Format_Number($_downloads{$u}->{'AWSTATS_HITS'})." | ";
			print "".Format_Number($_downloads{$u}->{'AWSTATS_206'})." | ";
		}
		if ( $ShowDownloadsStats =~ /B/i ){
			print "".Format_Bytes($_downloads{$u}->{'AWSTATS_SIZE'})." | ";
			print "".Format_Bytes(($_downloads{$u}->{'AWSTATS_SIZE'}/
					($_downloads{$u}->{'AWSTATS_HITS'} + $_downloads{$u}->{'AWSTATS_206'})))." | ";
		}
		print "
\n";
		$count++;
		if ($count >= $MaxNbOf{'DownloadsShown'}){last;}
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the hours chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainHours{
    my $NewLinkParams = shift;
    my $NewLinkTarget = shift;
        
    if ($Debug) { debug( "ShowHoursStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[20]";
	
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link 
           $title = "$title   -   $Message[179]");
    } 
	
	if ( $PluginsLoaded{'GetTimeZoneTitle'}{'timezone'} ) {
		$title .= " (GMT "
		  . ( GetTimeZoneTitle_timezone() >= 0 ? "+" : "" )
		  . int( GetTimeZoneTitle_timezone() ) . ")";
	}
	&tab_head( "$title", 19, 0, 'hours' );
	print "\n";
	print "\n";
	my $max_h = my $max_k = 1;
	for ( my $ix = 0 ; $ix <= 23 ; $ix++ ) {
		#if ($_time_p[$ix]>$max_p) { $max_p=$_time_p[$ix]; }
		if ( $_time_h[$ix] > $max_h ) { $max_h = $_time_h[$ix]; }
		if ( $_time_k[$ix] > $max_k ) { $max_k = $_time_k[$ix]; }
	}
	# Show bars for hour
	my $graphdone=0;
	foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
	{
		my @blocklabel = ( 0 .. 23 );
		my @vallabel   =
		  ( "$Message[56]", "$Message[57]", "$Message[75]" );
		my @valcolor = ( "$color_p", "$color_h", "$color_k" );
		my @valmax = ( int($max_h), int($max_h), int($max_k) );
		my @valtotal   = ( $TotalPages,   $TotalHits,   $TotalBytes );
		my @valaverage = ( $AveragePages, $AverageHits, $AverageBytes );
		my @valdata    = ();
		my $xx         = 0;
		for ( 0 .. 23 ) {
			$valdata[ $xx++ ] = $_time_p[$_] || 0;
			$valdata[ $xx++ ] = $_time_h[$_] || 0;
			$valdata[ $xx++ ] = $_time_k[$_] || 0;
		}
		my $function = "ShowGraph_$pluginname";
		&$function(
			"$title",        "hours",
			$ShowHoursStats, \@blocklabel,
			\@vallabel,      \@valcolor,
			\@valmax,        \@valtotal,
			\@valaverage,    \@valdata
		);
		$graphdone=1;
	}
	if (! $graphdone) 
	{
		print "\n";
		print "\n";
		for ( my $ix = 0 ; $ix <= 23 ; $ix++ ) {
			my $bredde_p = 0;
			my $bredde_h = 0;
			my $bredde_k = 0;
			if ( $max_h > 0 ) {
				$bredde_p =
				  int( $BarHeight * $_time_p[$ix] / $max_h ) + 1;
			}
			if ( $max_h > 0 ) {
				$bredde_h =
				  int( $BarHeight * $_time_h[$ix] / $max_h ) + 1;
			}
			if ( $max_k > 0 ) {
				$bredde_k =
				  int( $BarHeight * $_time_k[$ix] / $max_k ) + 1;
			}
			print "";
			if ( $ShowHoursStats =~ /P/i ) {
				print
" ";
			}
			if ( $ShowHoursStats =~ /H/i ) {
				print
" ";
			}
			if ( $ShowHoursStats =~ /B/i ) {
				print
" ";
			}
			print " | \n";
		}
		print " \n";
		# Show hour lib
		print "";
		for ( my $ix = 0 ; $ix <= 23 ; $ix++ ) {
			print "| $ix | \n"
			  ;   # width=19 instead of 18 to avoid a MacOS browser bug.
		}
		print " \n";
		# Show clock icon
		print "\n";
		for ( my $ix = 0 ; $ix <= 23 ; $ix++ ) {
			my $hrs = ( $ix >= 12 ? $ix - 12 : $ix );
			my $hre = ( $ix >= 12 ? $ix - 11 : $ix + 1 );
			my $apm = ( $ix >= 12 ? "pm"     : "am" );
			print
"  | \n";
		}
		print " \n";
		print " \n";
	}
	print " \n";
	# Show data array for hours
	if ($AddDataArrayShowHoursStats) {
		print "\n";
		print "\n";
		print "\n";
		print
"| $Message[20] | ";
		if ( $ShowHoursStats =~ /P/i ) {
			print "$Message[56] | ";
		}
		if ( $ShowHoursStats =~ /H/i ) {
			print "$Message[57] | ";
		}
		if ( $ShowHoursStats =~ /B/i ) {
			print "$Message[75] | ";
		}
		print " ";
		for ( my $ix = 0 ; $ix <= 11 ; $ix++ ) {
			my $monthix = ( $ix < 10 ? "0$ix" : "$ix" );
			print "";
			print "| $monthix | ";
			if ( $ShowHoursStats =~ /P/i ) {
				print "",
				  Format_Number($_time_p[$monthix] ? $_time_p[$monthix] : "0"),
				  " | ";
			}
			if ( $ShowHoursStats =~ /H/i ) {
				print "",
				  Format_Number($_time_h[$monthix] ? $_time_h[$monthix] : "0"),
				  " | ";
			}
			if ( $ShowHoursStats =~ /B/i ) {
				print "", Format_Bytes( int( $_time_k[$monthix] ) ),
				  " | ";
			}
			print " \n";
		}
		print " \n";
		print " | ";
		print "  | ";
		print "\n";
		print "\n";
		print
"| $Message[20] | ";
		if ( $ShowHoursStats =~ /P/i ) {
			print "$Message[56] | ";
		}
		if ( $ShowHoursStats =~ /H/i ) {
			print "$Message[57] | ";
		}
		if ( $ShowHoursStats =~ /B/i ) {
			print "$Message[75] | ";
		}
		print " \n";
		for ( my $ix = 12 ; $ix <= 23 ; $ix++ ) {
			my $monthix = ( $ix < 10 ? "0$ix" : "$ix" );
			print "";
			print "| $monthix | ";
			if ( $ShowHoursStats =~ /P/i ) {
				print "",
				  Format_Number($_time_p[$monthix] ? $_time_p[$monthix] : "0"),
				  " | ";
			}
			if ( $ShowHoursStats =~ /H/i ) {
				print "",
				  Format_Number($_time_h[$monthix] ? $_time_h[$monthix] : "0"),
				  " | ";
			}
			if ( $ShowHoursStats =~ /B/i ) {
				print "", Format_Bytes( int( $_time_k[$monthix] ) ),
				  " | ";
			}
			print " \n";
		}
		print " \n";
		print " |   \n";
		print " \n";
	}
	print " | 
\n";
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the countries chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainCountries{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowDomainsStats", 2 ); }
	print "$Center 
\n";
	my $title =
"$Message[25] ($Message[77] $MaxNbOf{'Domain'})   -   $Message[80]";
	  
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title = "$title   -   $Message[179]");
    }
        	  
	&tab_head( "$title", 19, 0, 'countries' );
	
	my $total_u = my $total_v = my $total_p = my $total_h = my $total_k = 0;
	my $max_h = 1;
	foreach ( values %_domener_h ) {
		if ( $_ > $max_h ) { $max_h = $_; }
	}
	my $max_k = 1;
	foreach ( values %_domener_k ) {
		if ( $_ > $max_k ) { $max_k = $_; }
	}
	my $count = 0;
	
	&BuildKeyList(
		$MaxNbOf{'Domain'}, $MinHit{'Domain'},
		\%_domener_h,       \%_domener_p
	);
	
	# print the map
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int( $_domener_h{$key} );
				push @blocklabel, $DomainsHashIDLib{$key};
				$cnt++;
				if ($cnt > 99) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"AWStatsCountryMap",              "countries_map",
				0, 						\@blocklabel,
				0,           			0,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print
"|   | $Message[17] | ";
	## to add unique visitors and number of visits by calculation of average of the relation with total
	## pages and total hits, and total visits and total unique
	## by Josep Ruano @ CAPSiDE
	if ( $ShowDomainsStats =~ /U/i ) {
		print "$Message[11] | ";
	}
	if ( $ShowDomainsStats =~ /V/i ) {
		print "$Message[10] | ";
	}
	if ( $ShowDomainsStats =~ /P/i ) {
		print "$Message[56] | ";
	}
	if ( $ShowDomainsStats =~ /H/i ) {
		print "$Message[57] | ";
	}
	if ( $ShowDomainsStats =~ /B/i ) {
		print "$Message[75] | ";
	}
	print "  | ";
	print "
\n";
	
	foreach my $key (@keylist) {
		my ( $_domener_u, $_domener_v );
		my $bredde_p = 0;
		my $bredde_h = 0;
		my $bredde_k = 0;
		my $bredde_u = 0;
		my $bredde_v = 0;
		if ( $max_h > 0 ) {
			$bredde_p =
			  int( $BarWidth * $_domener_p{$key} / $max_h ) + 1;
		}    # use max_h to enable to compare pages with hits
		if ( $_domener_p{$key} && $bredde_p == 1 ) { $bredde_p = 2; }
		if ( $max_h > 0 ) {
			$bredde_h =
			  int( $BarWidth * $_domener_h{$key} / $max_h ) + 1;
		}
		if ( $_domener_h{$key} && $bredde_h == 1 ) { $bredde_h = 2; }
		if ( $max_k > 0 ) {
			$bredde_k =
			  int( $BarWidth * ( $_domener_k{$key} || 0 ) / $max_k ) +
			  1;
		}
		if ( $_domener_k{$key} && $bredde_k == 1 ) { $bredde_k = 2; }
		my $newkey = lc($key);
		if ( $newkey eq 'ip' || !$DomainsHashIDLib{$newkey} ) {
			print
"  | $Message[0] | $newkey | ";
		}
		else {
			print
"
  | $DomainsHashIDLib{$newkey} | $newkey | ";
		}
		## to add unique visitors and number of visits, by Josep Ruano @ CAPSiDE
		if ( $ShowDomainsStats =~ /U/i ) {
			$_domener_u = (
				  $_domener_p{$key}
				? $_domener_p{$key} / $TotalPages
				: 0
			);
			$_domener_u += ( $_domener_h{$key} / $TotalHits );
			$_domener_u =
			  sprintf( "%.0f", ( $_domener_u * $TotalUnique ) / 2 );
			print "".Format_Number($_domener_u)." ("
			  . sprintf( "%.1f%", 100 * $_domener_u / $TotalUnique )
			  . ") | ";
		}
		if ( $ShowDomainsStats =~ /V/i ) {
			$_domener_v = (
				  $_domener_p{$key}
				? $_domener_p{$key} / $TotalPages
				: 0
			);
			$_domener_v += ( $_domener_h{$key} / $TotalHits );
			$_domener_v =
			  sprintf( "%.0f", ( $_domener_v * $TotalVisits ) / 2 );
			print "".Format_Number($_domener_v)." ("
			  . sprintf( "%.1f%", 100 * $_domener_v / $TotalVisits )
			  . ") | ";
		}
		if ( $ShowDomainsStats =~ /P/i ) {
			print ""
			  . ( $_domener_p{$key} ? Format_Number($_domener_p{$key}) : ' ' )
			  . " | ";
		}
		if ( $ShowDomainsStats =~ /H/i ) {
			print "".Format_Number($_domener_h{$key})." | ";
		}
		if ( $ShowDomainsStats =~ /B/i ) {
			print "" . Format_Bytes( $_domener_k{$key} ) . " | ";
		}
		print "";
		if ( $ShowDomainsStats =~ /P/i ) {
			print
"  \n";
		}
		if ( $ShowDomainsStats =~ /H/i ) {
			print
"  \n";
		}
		if ( $ShowDomainsStats =~ /B/i ) {
			print
" ";
		}
		print " | ";
		print "
\n";
		$total_u += $_domener_u;
		$total_v += $_domener_v;
		$total_p += $_domener_p{$key};
		$total_h += $_domener_h{$key};
		$total_k += $_domener_k{$key} || 0;
		$count++;
	}
	my $rest_u = $TotalUnique - $total_u;
	my $rest_v = $TotalVisits - $total_v;
	my $rest_p = $TotalPages - $total_p;
	my $rest_h = $TotalHits - $total_h;
	my $rest_k = $TotalBytes - $total_k;
	if (   $rest_u > 0
		|| $rest_v > 0
		|| $rest_p > 0
		|| $rest_h > 0
		|| $rest_k > 0 )
	{    # All other domains (known or not)
		print
"|   | $Message[2] | ";
		if ( $ShowDomainsStats =~ /U/i ) { print "$rest_u | "; }
		if ( $ShowDomainsStats =~ /V/i ) { print "$rest_v | "; }
		if ( $ShowDomainsStats =~ /P/i ) { print "$rest_p | "; }
		if ( $ShowDomainsStats =~ /H/i ) { print "$rest_h | "; }
		if ( $ShowDomainsStats =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		print "  | ";
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the hosts chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainHosts{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowHostsStats", 2 ); }
	print "$Center 
\n";
	my $title =
"$Message[81] ($Message[77] $MaxNbOf{'HostsShown'})   -   $Message[80]   -   $Message[9]   -   $Message[45]";
	  
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title = "$title   -   $Message[179]");
    }
	  
	&tab_head( "$title", 19, 0, 'visitors' );
	
	&BuildKeyList( $MaxNbOf{'HostsShown'}, $MinHit{'Host'}, \%_host_h,
		\%_host_p );
		
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			my $suma = 0;
			foreach my $key (@keylist) {
               $suma=$suma + ( $_host_h{$key});
               $cnt++;
               if ($cnt > 4) { last; }
			}
			
			my $cnt = 0;
			foreach my $key (@keylist) {
               push @valdata, int( $_host_h{$key} / $suma * 1000 ) / 10;
               push @blocklabel, "$key";
               $cnt++;
               if ($cnt > 4) { last; }
			}
			
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"Hosts",              "hosts",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print "";
	print "";
	if ( $MonthRequired ne 'all' ) {
		print
"$Message[81] : ".Format_Number($TotalHostsKnown)." $Message[82], ".Format_Number($TotalHostsUnknown)." $Message[1] ".Format_Number($TotalUnique)." $Message[11] | ";
	}
	else {
		print "$Message[81] : " . ( scalar keys %_host_h ) . "";
	}
	&HTMLShowHostInfo('__title__');
	if ( $ShowHostsStats =~ /P/i ) {
		print "$Message[56] | ";
	}
	if ( $ShowHostsStats =~ /H/i ) {
		print "$Message[57] | ";
	}
	if ( $ShowHostsStats =~ /B/i ) {
		print "$Message[75] | ";
	}
	if ( $ShowHostsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = 0;
	my $count = 0;
	
	my $regipv4 = qr/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;	
        if ( $DynamicDNSLookup == 2 ) {
	        # Use static DNS file
                &Read_DNS_Cache( \%MyDNSTable, "$DNSStaticCacheFile", "", 1 );
        }
	foreach my $key (@keylist) {
		print "";
		print "| $key";
		if ($DynamicDNSLookup) {
	                # Dynamic reverse DNS lookup
	                if ($key =~ /$regipv4/o) {
		                my $lookupresult=lc(gethostbyaddr(pack("C4",split(/\./,$key)),AF_INET));	# This may be slow
                	        if (! $lookupresult || $lookupresult =~ /$regipv4/o || ! IsAscii($lookupresult)) {
                                        if ( $DynamicDNSLookup == 2 ) {
                                                # Check static DNS file
                                                $lookupresult = $MyDNSTable{$key};
                                                if ($lookupresult) { print " ($lookupresult)"; }
                                                else { print ""; }
                                        }
                                        else { print ""; }
                                }
                                else { print " ($lookupresult)"; }
                        }
                }
		print " | ";
		&HTMLShowHostInfo($key);
		if ( $ShowHostsStats =~ /P/i ) {
			print '' . ( Format_Number($_host_p{$key}) || " " ) . ' | ';
		}
		if ( $ShowHostsStats =~ /H/i ) {
			print "".Format_Number($_host_h{$key})." | ";
		}
		if ( $ShowHostsStats =~ /B/i ) {
			print '' . Format_Bytes( $_host_k{$key} ) . ' | ';
		}
		if ( $ShowHostsStats =~ /L/i ) {
			print ''
			  . (
				$_host_l{$key}
				? Format_Date( $_host_l{$key}, 1 )
				: '-'
			  )
			  . ' | ';
		}
		print "
\n";
		$total_p += $_host_p{$key};
		$total_h += $_host_h{$key};
		$total_k += $_host_k{$key} || 0;
		$count++;
	}
	my $rest_p = $TotalPages - $total_p;
	my $rest_h = $TotalHits - $total_h;
	my $rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{    # All other visitors (known or not)
		print "";
		print
"| $Message[2] | ";
		&HTMLShowHostInfo('');
		if ( $ShowHostsStats =~ /P/i ) { print "".Format_Number($rest_p)." | "; }
		if ( $ShowHostsStats =~ /H/i ) { print "".Format_Number($rest_h)." | "; }
		if ( $ShowHostsStats =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowHostsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the logins chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainLogins{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowAuthenticatedUsers", 2 ); }
	print "$Center 
\n";
	my $title =
"$Message[94] ($Message[77] $MaxNbOf{'LoginShown'})   -   $Message[80]";
	if ( $ShowAuthenticatedUsers =~ /L/i ) {
		$title .= "   -   $Message[9]";
	}
	&tab_head( "$title", 19, 0, 'logins' );
	print "| $Message[94] : "
	  . Format_Number(( scalar keys %_login_h )) . " | ";
	&HTMLShowUserInfo('__title__');
	if ( $ShowAuthenticatedUsers =~ /P/i ) {
		print "$Message[56] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /H/i ) {
		print "$Message[57] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /B/i ) {
		print "$Message[75] | ";
	}
	if ( $ShowAuthenticatedUsers =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = 0;
	my $max_h = 1;
	foreach ( values %_login_h ) {
		if ( $_ > $max_h ) { $max_h = $_; }
	}
	my $max_k = 1;
	foreach ( values %_login_k ) {
		if ( $_ > $max_k ) { $max_k = $_; }
	}
	my $count = 0;
	&BuildKeyList( $MaxNbOf{'LoginShown'}, $MinHit{'Login'}, \%_login_h,
		\%_login_p );
	foreach my $key (@keylist) {
		my $bredde_p = 0;
		my $bredde_h = 0;
		my $bredde_k = 0;
		if ( $max_h > 0 ) {
			$bredde_p = int( $BarWidth * $_login_p{$key} / $max_h ) + 1;
		}    # use max_h to enable to compare pages with hits
		if ( $max_h > 0 ) {
			$bredde_h = int( $BarWidth * $_login_h{$key} / $max_h ) + 1;
		}
		if ( $max_k > 0 ) {
			$bredde_k = int( $BarWidth * $_login_k{$key} / $max_k ) + 1;
		}
		print "| $key | ";
		&HTMLShowUserInfo($key);
		if ( $ShowAuthenticatedUsers =~ /P/i ) {
			print ""
			  . ( $_login_p{$key} ? Format_Number($_login_p{$key}) : " " )
			  . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /H/i ) {
			print "".Format_Number($_login_h{$key})." | ";
		}
		if ( $ShowAuthenticatedUsers =~ /B/i ) {
			print "" . Format_Bytes( $_login_k{$key} ) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /L/i ) {
			print ""
			  . (
				$_login_l{$key}
				? Format_Date( $_login_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		$total_p += $_login_p{$key};
		$total_h += $_login_h{$key};
		$total_k += $_login_k{$key};
		$count++;
	}
	my $rest_p = $TotalPages - $total_p;
	my $rest_h = $TotalHits - $total_h;
	my $rest_k = $TotalBytes - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 )
	{    # All other logins
		print
		  "| "
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . "$Message[125]"
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . " | ";
		&HTMLShowUserInfo('');
		if ( $ShowAuthenticatedUsers =~ /P/i ) {
			print "" . ( $rest_p ? Format_Number($rest_p) : " " ) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /H/i ) {
			print "".Format_Number($rest_h)." | ";
		}
		if ( $ShowAuthenticatedUsers =~ /B/i ) {
			print "" . Format_Bytes($rest_k) . " | ";
		}
		if ( $ShowAuthenticatedUsers =~ /L/i ) {
			print "  | ";
		}
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the robots chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainRobots{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowRobotStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[53] ($Message[77] $MaxNbOf{'RobotShown'})   -   $Message[80]   -   $Message[9]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title = "$title   -   $Message[179]");
    }
        
    &tab_head( "$title", 19, 0, 'robots');
        
    print "| "
	  . Format_Number(( scalar keys %_robot_h ))
	  . " $Message[51]* | ";
	if ( $ShowRobotsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowRobotsStats =~ /B/i ) {
		print
		  "$Message[75] | ";
	}
	if ( $ShowRobotsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = my $total_r = 0;
	my $count = 0;
	&BuildKeyList( $MaxNbOf{'RobotShown'}, $MinHit{'Robot'}, \%_robot_h,
		\%_robot_h );
	foreach my $key (@keylist) {
		print "| "
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . ( $RobotsHashIDLib{$key} ? $RobotsHashIDLib{$key} : $key )
		  . ( $PageDir eq 'rtl' ? "" : "" ) . " | ";
		if ( $ShowRobotsStats =~ /H/i ) {
			print ""
			  . Format_Number(( $_robot_h{$key} - $_robot_r{$key} ))
			  . ( $_robot_r{$key} ? "+$_robot_r{$key}" : "" ) . " | ";
		}
		if ( $ShowRobotsStats =~ /B/i ) {
			print "" . Format_Bytes( $_robot_k{$key} ) . " | ";
		}
		if ( $ShowRobotsStats =~ /L/i ) {
			print ""
			  . (
				$_robot_l{$key}
				? Format_Date( $_robot_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		#$total_p += $_robot_p{$key};
		$total_h += $_robot_h{$key};
		$total_k += $_robot_k{$key} || 0;
		$total_r += $_robot_r{$key} || 0;
		$count++;
	}
	# For bots we need to count Totals
	my $TotalPagesRobots =
	  0;    #foreach (values %_robot_p) { $TotalPagesRobots+=$_; }
	my $TotalHitsRobots = 0;
	foreach ( values %_robot_h ) { $TotalHitsRobots += $_; }
	my $TotalBytesRobots = 0;
	foreach ( values %_robot_k ) { $TotalBytesRobots += $_; }
	my $TotalRRobots = 0;
	foreach ( values %_robot_r ) { $TotalRRobots += $_; }
	my $rest_p = 0;    #$rest_p=$TotalPagesRobots-$total_p;
	my $rest_h = $TotalHitsRobots - $total_h;
	my $rest_k = $TotalBytesRobots - $total_k;
	my $rest_r = $TotalRRobots - $total_r;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0 )
	{               # All other robots
		print
"| $Message[2] | ";
		if ( $ShowRobotsStats =~ /H/i ) {
			print ""
			  . Format_Number(( $rest_h - $rest_r ))
			  . ( $rest_r ? "+$rest_r" : "" ) . " | ";
		}
		if ( $ShowRobotsStats =~ /B/i ) {
			print "" . ( Format_Bytes($rest_k) ) . " | ";
		}
		if ( $ShowRobotsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end(
		"* $Message[156]" . ( $TotalRRobots ? " $Message[157]" : "" ) );
}
#------------------------------------------------------------------------------
# Function:     Prints the worms chart and table
# Parameters:   -
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainWorms{
	if ($Debug) { debug( "ShowWormsStats", 2 ); }
	print "$Center 
\n";
	&tab_head( "$Message[163] ($Message[77] $MaxNbOf{'WormsShown'})",
		19, 0, 'worms' );
	print "";
	print "| " . Format_Number(( scalar keys %_worm_h )) . " $Message[164]* | ";
	print "$Message[167] | ";
	if ( $ShowWormsStats =~ /H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowWormsStats =~ /B/i ) {
		print
		  "$Message[75] | ";
	}
	if ( $ShowWormsStats =~ /L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = 0;
	my $count = 0;
	&BuildKeyList( $MaxNbOf{'WormsShown'}, $MinHit{'Worm'}, \%_worm_h,
		\%_worm_h );
	foreach my $key (@keylist) {
		print "";
		print "| "
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . ( $WormsHashLib{$key} ? $WormsHashLib{$key} : $key )
		  . ( $PageDir eq 'rtl' ? "" : "" ) . " | ";
		print ""
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . ( $WormsHashTarget{$key} ? $WormsHashTarget{$key} : $key )
		  . ( $PageDir eq 'rtl' ? "" : "" ) . " | ";
		if ( $ShowWormsStats =~ /H/i ) {
			print "" . Format_Number($_worm_h{$key}) . " | ";
		}
		if ( $ShowWormsStats =~ /B/i ) {
			print "" . Format_Bytes( $_worm_k{$key} ) . " | ";
		}
		if ( $ShowWormsStats =~ /L/i ) {
			print ""
			  . (
				$_worm_l{$key}
				? Format_Date( $_worm_l{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		#$total_p += $_worm_p{$key};
		$total_h += $_worm_h{$key};
		$total_k += $_worm_k{$key} || 0;
		$count++;
	}
	# For worms we need to count Totals
	my $TotalPagesWorms =
	  0;    #foreach (values %_worm_p) { $TotalPagesWorms+=$_; }
	my $TotalHitsWorms = 0;
	foreach ( values %_worm_h ) { $TotalHitsWorms += $_; }
	my $TotalBytesWorms = 0;
	foreach ( values %_worm_k ) { $TotalBytesWorms += $_; }
	my $rest_p = 0;    #$rest_p=$TotalPagesRobots-$total_p;
	my $rest_h = $TotalHitsWorms - $total_h;
	my $rest_k = $TotalBytesWorms - $total_k;
	if ( $rest_p > 0 || $rest_h > 0 || $rest_k > 0 ) { # All other worms
		print "";
		print
"| $Message[2] | ";
		print "- | ";
		if ( $ShowWormsStats =~ /H/i ) {
			print "" . Format_Number(($rest_h)) . " | ";
		}
		if ( $ShowWormsStats =~ /B/i ) {
			print "" . ( Format_Bytes($rest_k) ) . " | ";
		}
		if ( $ShowWormsStats =~ /L/i ) { print "  | "; }
		print "
\n";
	}
	&tab_end("* $Message[158]");
}
#------------------------------------------------------------------------------
# Function:     Prints the sessions chart and table
# Parameters:   -
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainSessions{
	if ($Debug) { debug( "ShowSessionsStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[117]";
	&tab_head( $title, 19, 0, 'sessions' );
	my $Totals = 0;
	my $average_s = 0;
	foreach (@SessionsRange) {
		$average_s += ( $_session{$_} || 0 ) * $SessionsAverage{$_};
		$Totals += $_session{$_} || 0;
	}
	if ($Totals) { $average_s = int( $average_s / $Totals ); }
	else { $average_s = '?'; }
	print "| $Message[10]: ".Format_Number($TotalVisits)." - $Message[96]: ".Format_Number($average_s)." s | $Message[10] | $Message[15] | 
\n";
	$average_s = 0;
	my $total_s   = 0;
	my $count = 0;
	foreach my $key (@SessionsRange) {
		my $p = 0;
		if ($TotalVisits) {
			$p = int( $_session{$key} / $TotalVisits * 1000 ) / 10;
		}
		$total_s += $_session{$key} || 0;
		print "| $key | ";
		print ""
		  . ( $_session{$key} ? Format_Number($_session{$key}) : " " ) . " | ";
		print ""
		  . ( $_session{$key} ? "$p %" : " " ) . " | ";
		print "
\n";
		$count++;
	}
	my $rest_s = $TotalVisits - $total_s;
	if ( $rest_s > 0 ) {    # All others sessions
		my $p = 0;
		if ($TotalVisits) {
			$p = int( $rest_s / $TotalVisits * 1000 ) / 10;
		}
		print "| $Message[0] | ";
		print "".Format_Number($rest_s)." | ";
		print "" . ( $rest_s ? "$p %" : " " ) . " | ";
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the pages chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainPages{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) {
		debug(
"ShowPagesStats (MaxNbOf{'PageShown'}=$MaxNbOf{'PageShown'} TotalDifferentPages=$TotalDifferentPages)",
			2
		);
	}
	my $regext         = qr/\.(\w{1,6})$/;
	print
"$Center   
\n";
	my $title =
"$Message[19] ($Message[77] $MaxNbOf{'PageShown'})   -   $Message[80]";
	if ( $ShowPagesStats =~ /E/i ) {
		$title .= "   -   $Message[104]";
	}
	if ( $ShowPagesStats =~ /X/i ) {
		$title .= "   -   $Message[116]";
	}
	
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        	
	&tab_head( "$title", 19, 0, 'urls' );
	print
"| ".Format_Number($TotalDifferentPages)." $Message[28] | ";
	if ( $ShowPagesStats =~ /P/i && $LogType ne 'F' ) {
		print
		  "$Message[29] | ";
	}
	if ( $ShowPagesStats =~ /[PH]/i && $LogType eq 'F' ) {
		print
		  "$Message[57] | ";
	}
	if ( $ShowPagesStats =~ /B/i ) {
		print
		  "$Message[106] | ";
	}
	if ( $ShowPagesStats =~ /E/i ) {
		print
		  "$Message[104] | ";
	}
	if ( $ShowPagesStats =~ /X/i ) {
		print
		  "$Message[116] | ";
	}
	# Call to plugins' function ShowPagesAddField
	foreach
	  my $pluginname ( keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
	{
		#				my $function="ShowPagesAddField_$pluginname('title')";
		#				eval("$function");
		my $function = "ShowPagesAddField_$pluginname";
		&$function('title');
	}
	print "  | 
\n";
	my $total_p = my $total_e = my $total_x = my $total_k = 0;
	my $max_p   = 1;
	my $max_k   = 1;
	my $count = 0;
	&BuildKeyList( $MaxNbOf{'PageShown'}, $MinHit{'File'}, \%_url_p,
		\%_url_p );
	foreach my $key (@keylist) {
		if ( $_url_p{$key} > $max_p ) { $max_p = $_url_p{$key}; }
		if ( $_url_k{$key} / ( $_url_p{$key} || 1 ) > $max_k ) {
			$max_k = $_url_k{$key} / ( $_url_p{$key} || 1 );
		}
	}
	foreach my $key (@keylist) {
		print "| ";
		&HTMLShowURLInfo($key);
		print " | ";
		my $bredde_p = 0;
		my $bredde_e = 0;
		my $bredde_x = 0;
		my $bredde_k = 0;
		if ( $max_p > 0 ) {
			$bredde_p =
			  int( $BarWidth * ( $_url_p{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_p == 1 ) && $_url_p{$key} ) { $bredde_p = 2; }
		if ( $max_p > 0 ) {
			$bredde_e =
			  int( $BarWidth * ( $_url_e{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_e == 1 ) && $_url_e{$key} ) { $bredde_e = 2; }
		if ( $max_p > 0 ) {
			$bredde_x =
			  int( $BarWidth * ( $_url_x{$key} || 0 ) / $max_p ) + 1;
		}
		if ( ( $bredde_x == 1 ) && $_url_x{$key} ) { $bredde_x = 2; }
		if ( $max_k > 0 ) {
			$bredde_k =
			  int( $BarWidth *
				  ( ( $_url_k{$key} || 0 ) / ( $_url_p{$key} || 1 ) ) /
				  $max_k ) + 1;
		}
		if ( ( $bredde_k == 1 ) && $_url_k{$key} ) { $bredde_k = 2; }
		if ( $ShowPagesStats =~ /P/i && $LogType ne 'F' ) {
			print "".Format_Number($_url_p{$key})." | ";
		}
		if ( $ShowPagesStats =~ /[PH]/i && $LogType eq 'F' ) {
			print "".Format_Number($_url_p{$key})." | ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print ""
			  . (
				$_url_k{$key}
				? Format_Bytes(
					$_url_k{$key} / ( $_url_p{$key} || 1 )
				  )
				: " "
			  )
			  . " | ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print ""
			  . ( $_url_e{$key} ? Format_Number($_url_e{$key}) : " " ) . " | ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print ""
			  . ( $_url_x{$key} ? Format_Number($_url_x{$key}) : " " ) . " | ";
		}
		# Call to plugins' function ShowPagesAddField
		foreach my $pluginname (
			keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
		{
			#					my $function="ShowPagesAddField_$pluginname('$key')";
			#					eval("$function");
			my $function = "ShowPagesAddField_$pluginname";
			&$function($key);
		}
		print "";
		if ( $ShowPagesStats =~ /P/i && $LogType ne 'F' ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /[PH]/i && $LogType eq 'F' ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print
"  ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print
" ";
		}
		print " | 
\n";
		$total_p += $_url_p{$key} || 0;
		$total_e += $_url_e{$key} || 0;
		$total_x += $_url_x{$key} || 0;
		$total_k += $_url_k{$key} || 0;
		$count++;
	}
	my $rest_p = $TotalPages - $total_p;
	my $rest_e = $TotalEntries - $total_e;
	my $rest_x = $TotalExits - $total_x;
	my $rest_k = $TotalBytesPages - $total_k;
	if ( $rest_p > 0 || $rest_k > 0 || $rest_e > 0 || $rest_x > 0 )
	{    # All other urls
		print
"| $Message[2] | ";
		if ( $ShowPagesStats =~ /P/i && $LogType ne 'F' ) {
			print "".Format_Number($rest_p)." | ";
		}
		if ( $ShowPagesStats =~ /[PH]/i && $LogType eq 'F' ) {
			print "".Format_Number($rest_p)." | ";
		}
		if ( $ShowPagesStats =~ /B/i ) {
			print ""
			  . (
				$rest_k
				? Format_Bytes( $rest_k / ( $rest_p || 1 ) )
				: " "
			  )
			  . " | ";
		}
		if ( $ShowPagesStats =~ /E/i ) {
			print "" . ( $rest_e ? Format_Number($rest_e) : " " ) . " | ";
		}
		if ( $ShowPagesStats =~ /X/i ) {
			print "" . ( $rest_x ? Format_Number($rest_x) : " " ) . " | ";
		}
		# Call to plugins' function ShowPagesAddField
		foreach my $pluginname (
			keys %{ $PluginsLoaded{'ShowPagesAddField'} } )
		{
			#					my $function="ShowPagesAddField_$pluginname('')";
			#					eval("$function");
			my $function = "ShowPagesAddField_$pluginname";
			&$function('');
		}
		print "  | 
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the OS chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainOS{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	if ($Debug) { debug( "ShowOSStats", 2 ); }
	print "$Center 
\n";
	my $Totalh   = 0;
	my $Totalp   = 0;
	my %new_os_h = ();
	my %new_os_p = ();
  OSLOOP: foreach my $key ( keys %_os_h ) {
		$Totalh += $_os_h{$key};
		$Totalp += $_os_p{$key};
		foreach my $family ( keys %OSFamily ) {
			if ( $key =~ /^$family/i ) {
				$new_os_h{"${family}cumul"} += $_os_h{$key};
				$new_os_p{"${family}cumul"} += $_os_p{$key};
				next OSLOOP;
			}
		}
		$new_os_h{$key} += $_os_h{$key};
		$new_os_p{$key} += $_os_p{$key};
	}
	my $title =
"$Message[59] ($Message[77] $MaxNbOf{'OsShown'})   -   $Message[80]/$Message[58]   -   $Message[0]";
	  
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        	  
	&tab_head( "$title", 19, 0, 'os' );
	
	&BuildKeyList( $MaxNbOf{'OsShown'}, $MinHit{'Os'}, \%new_os_h,
		\%new_os_p );
		
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int(  $new_os_h{$key} / $Totalh * 1000 ) / 10;
				if ($key eq 'Unknown'){push @blocklabel, "$key"; }
				else{
					my $keywithoutcumul = $key;
					$keywithoutcumul =~ s/cumul$//i;
					my $libos = $OSHashLib{$keywithoutcumul}
					  || $keywithoutcumul;
					my $nameicon = $keywithoutcumul;
					$nameicon =~ s/[^\w]//g;
					if ( $OSFamily{$keywithoutcumul} ) {
						$libos = $OSFamily{$keywithoutcumul};
					}
					push @blocklabel, "$libos";
				}
				$cnt++;
				if ($cnt > 4) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"Top 5 Operating Systems",       "oss",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print
"|   | $Message[59] | ";
	print
"$Message[56] | $Message[15] | ";
	print
"$Message[57] | $Message[15] | 
\n";
	my $total_h = 0;
	my $total_p = 0;
	my $count = 0;
	
	foreach my $key (@keylist) {
		my $p_h = ' ';
		my $p_p = ' ';
		if ($Totalh) {
			$p_h = int( $new_os_h{$key} / $Totalh * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($Totalp) {
			$p_p = int( $new_os_p{$key} / $Totalp * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		if ( $key eq 'Unknown' ) {
			print "  | $Message[0] | "
			  . "".Format_Number($_os_p{$key})." | $p_p | ".Format_Number($_os_h{$key})." | $p_h | 
\n";
		}
		else {
			my $keywithoutcumul = $key;
			$keywithoutcumul =~ s/cumul$//i;
			my $libos = $OSHashLib{$keywithoutcumul}
			  || $keywithoutcumul;
			my $nameicon = $keywithoutcumul;
			$nameicon =~ s/[^\w]//g;
			if ( $OSFamily{$keywithoutcumul} ) {
				$libos = "" . $OSFamily{$keywithoutcumul} . "";
			}
			print "  | $libos | ".Format_Number($new_os_p{$key})." | $p_p | ".Format_Number($new_os_h{$key})." | $p_h | 
\n";
		}
		$total_h += $new_os_h{$key};
		$total_p += $new_os_p{$key};
		$count++;
	}
	if ($Debug) {
		debug( "Total real / shown : $Totalh / $total_h", 2 );
	}
	my $rest_h = $Totalh - $total_h;
	my $rest_p = $Totalp - $total_p;
	if ( $rest_h > 0 ) {
		my $p_p;
		my $p_h;
		if ($Totalh) { $p_h = int( $rest_h / $Totalh * 1000 ) / 10; }
		if ($Totalp) { $p_p = int( $rest_p / $Totalp * 1000 ) / 10; }
		print "";
		print "|   | ";
		print
"$Message[2] | ".Format_Number($rest_p)." | ";
		print "$p_p % | ".Format_Number($rest_h)." | $p_h % | 
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Browsers chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainBrowsers{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowBrowsersStats", 2 ); }
	print "$Center 
\n";
	my $Totalh        = 0;
	my $Totalp        = 0;
	my %new_browser_h = ();
	my %new_browser_p = ();
  BROWSERLOOP: foreach my $key ( keys %_browser_h ) {
		$Totalh += $_browser_h{$key};
		$Totalp += $_browser_p{$key};
		foreach my $family ( keys %BrowsersFamily ) {
			if ( $key =~ /^$family/i ) {
				$new_browser_h{"${family}cumul"} += $_browser_h{$key};
				$new_browser_p{"${family}cumul"} += $_browser_p{$key};
				next BROWSERLOOP;
			}
		}
		$new_browser_h{$key} += $_browser_h{$key};
		$new_browser_p{$key} += $_browser_p{$key};
	}
	my $title =
"$Message[21] ($Message[77] $MaxNbOf{'BrowsersShown'})   -   $Message[80]/$Message[58]   -   $Message[0]";
	  
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        	  
	&tab_head( "$title", 19, 0, 'browsers' );
	
	&BuildKeyList(
		$MaxNbOf{'BrowsersShown'}, $MinHit{'Browser'},
		\%new_browser_h,           \%new_browser_p
	);
	
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int(  $new_browser_h{$key} / $TotalHits * 1000 ) / 10;
				if ($key eq 'Unknown'){push @blocklabel, "$key"; }
				else{
					my $keywithoutcumul = $key;
					$keywithoutcumul =~ s/cumul$//i;
					my $libbrowser = $BrowsersHashIDLib{$keywithoutcumul}
					  || $keywithoutcumul;
					my $nameicon = $BrowsersHashIcon{$keywithoutcumul}
					  || "notavailable";
					if ( $BrowsersFamily{$keywithoutcumul} ) {
						$libbrowser = "$libbrowser";
					}
					push @blocklabel, "$libbrowser";
				}
				$cnt++;
				if ($cnt > 4) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"Top 5 Browsers",       "browsers",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	print
"|   | $Message[21] | $Message[111] | $Message[56] | $Message[15] | $Message[57] | $Message[15] | 
\n";
	my $total_h = 0;
	my $total_p = 0;
	my $count = 0;
	foreach my $key (@keylist) {
		my $p_h = ' ';
		my $p_p = ' ';
		if ($Totalh) {
			$p_h = int( $new_browser_h{$key} / $Totalh * 1000 ) / 10;
			$p_h = "$p_h %";
		}
		if ($Totalp) {
			$p_p = int( $new_browser_p{$key} / $Totalp * 1000 ) / 10;
			$p_p = "$p_p %";
		}
		if ( $key eq 'Unknown' ) {
			print "  | $Message[0] | ? | "
			  . "".Format_Number($_browser_p{$key})." | $p_p | "
			  . "".Format_Number($_browser_h{$key})." | $p_h | 
\n";
		}
		else {
			my $keywithoutcumul = $key;
			$keywithoutcumul =~ s/cumul$//i;
			my $libbrowser = $BrowsersHashIDLib{$keywithoutcumul}
			  || $keywithoutcumul;
			my $nameicon = $BrowsersHashIcon{$keywithoutcumul}
			  || "notavailable";
			if ( $BrowsersFamily{$keywithoutcumul} ) {
				$libbrowser = "$libbrowser";
			}
			print "  | "
			  . ( $PageDir eq 'rtl' ? "" : "" )
			  . "$libbrowser"
			  . ( $PageDir eq 'rtl' ? "" : "" )
			  . " | "
			  . (
				$BrowsersHereAreGrabbers{$key}
				? "$Message[112]"
				: "$Message[113]"
			  )
			  . " | ".Format_Number($new_browser_p{$key})." | $p_p | ".Format_Number($new_browser_h{$key})." | $p_h | 
\n";
		}
		$total_h += $new_browser_h{$key};
		$total_p += $new_browser_p{$key};
		$count++;
	}
	if ($Debug) {
		debug( "Total real / shown : $Totalh / $total_h", 2 );
	}
	my $rest_h = $Totalh - $total_h;
	my $rest_p = $Totalp - $total_p;
	if ( $rest_h > 0 ) {
		my $p_p = 0.0;
		my $p_h;
		if ($Totalh) { $p_h = int( $rest_h / $Totalh * 1000 ) / 10; }
		if ($Totalp) { $p_p = int( $rest_p / $Totalp * 1000 ) / 10; }
		print "";
		print "|   | ";
		print
"$Message[2] |   | $rest_p | ";
		print "$p_p % | $rest_h | $p_h % | 
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the ScreenSize chart and table
# Parameters:   -
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainScreenSize{
	if ($Debug) { debug( "ShowScreenSizeStats", 2 ); }
	print "$Center 
\n";
	my $Totalh = 0;
	foreach ( keys %_screensize_h ) { $Totalh += $_screensize_h{$_}; }
	my $title =
	  "$Message[135] ($Message[77] $MaxNbOf{'ScreenSizesShown'})";
	&tab_head( "$title", 0, 0, 'screensizes' );
	print
"| $Message[135] | $Message[15] | 
\n";
	my $total_h = 0;
	my $count   = 0;
	&BuildKeyList( $MaxNbOf{'ScreenSizesShown'},
		$MinHit{'ScreenSize'}, \%_screensize_h, \%_screensize_h );
	foreach my $key (@keylist) {
		my $p = ' ';
		if ($Totalh) {
			$p = int( $_screensize_h{$key} / $Totalh * 1000 ) / 10;
			$p = "$p %";
		}
		$total_h += $_screensize_h{$key} || 0;
		print "";
		if ( $key eq 'Unknown' ) {
			print
"| $Message[0] | ";
			print "$p | ";
		}
		else {
			my $screensize = $key;
			print "$screensize | ";
			print "$p | ";
		}
		print "
\n";
		$count++;
	}
	my $rest_h = $Totalh - $total_h;
	if ( $rest_h > 0 ) {    # All others sessions
		my $p = 0;
		if ($Totalh) { $p = int( $rest_h / $Totalh * 1000 ) / 10; }
		print
"| $Message[2] | ";
		print "" . ( $rest_h ? "$p %" : " " ) . " | ";
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Referrers chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainReferrers{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowOriginStats", 2 ); }
	print "$Center 
\n";
	my $Totalp = 0;
	foreach ( 0 .. 5 ) {
		$Totalp +=
		  ( $_ != 4 || $IncludeInternalLinksInOriginSection )
		  ? $_from_p[$_]
		  : 0;
	}
	my $Totalh = 0;
	foreach ( 0 .. 5 ) {
		$Totalh +=
		  ( $_ != 4 || $IncludeInternalLinksInOriginSection )
		  ? $_from_h[$_]
		  : 0;
	}
    my $title = "$Message[36]";
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        
	&tab_head( $title, 19, 0, 'referer' );
	my @p_p = ( 0, 0, 0, 0, 0, 0 );
	if ( $Totalp > 0 ) {
		$p_p[0] = int( $_from_p[0] / $Totalp * 1000 ) / 10;
		$p_p[1] = int( $_from_p[1] / $Totalp * 1000 ) / 10;
		$p_p[2] = int( $_from_p[2] / $Totalp * 1000 ) / 10;
		$p_p[3] = int( $_from_p[3] / $Totalp * 1000 ) / 10;
		$p_p[4] = int( $_from_p[4] / $Totalp * 1000 ) / 10;
		$p_p[5] = int( $_from_p[5] / $Totalp * 1000 ) / 10;
	}
	my @p_h = ( 0, 0, 0, 0, 0, 0 );
	if ( $Totalh > 0 ) {
		$p_h[0] = int( $_from_h[0] / $Totalh * 1000 ) / 10;
		$p_h[1] = int( $_from_h[1] / $Totalh * 1000 ) / 10;
		$p_h[2] = int( $_from_h[2] / $Totalh * 1000 ) / 10;
		$p_h[3] = int( $_from_h[3] / $Totalh * 1000 ) / 10;
		$p_h[4] = int( $_from_h[4] / $Totalh * 1000 ) / 10;
		$p_h[5] = int( $_from_h[5] / $Totalh * 1000 ) / 10;
	}
	print
	  "| $Message[37] | ";
	if ( $ShowOriginStats =~ /P/i ) {
		print
"$Message[56] | $Message[15] | ";
	}
	if ( $ShowOriginStats =~ /H/i ) {
		print
"$Message[57] | $Message[15] | ";
	}
	print "
\n";
	#------- Referrals by direct address/bookmark/link in email/etc...
	print "| $Message[38] | ";
	if ( $ShowOriginStats =~ /P/i ) {
		print ""
		  . ( $_from_p[0] ? Format_Number($_from_p[0]) : " " )
		  . " | "
		  . ( $_from_p[0] ? "$p_p[0] %" : " " ) . " | ";
	}
	if ( $ShowOriginStats =~ /H/i ) {
		print ""
		  . ( $_from_h[0] ? Format_Number($_from_h[0]) : " " )
		  . " | "
		  . ( $_from_h[0] ? "$p_h[0] %" : " " ) . " | ";
	}
	print "
\n";
	#------- Referrals by search engines
	print "$Message[40] - $Message[80] \n";
	if ( scalar keys %_se_referrals_h ) {
		print "\n";
		my $total_p = 0;
		my $total_h = 0;
		my $count = 0;
		&BuildKeyList(
			$MaxNbOf{'RefererShown'},
			$MinHit{'Refer'},
			\%_se_referrals_h,
			(
				( scalar keys %_se_referrals_p )
				? \%_se_referrals_p
				: \%_se_referrals_h
			)
		);
		foreach my $key (@keylist) {
			my $newreferer = $SearchEnginesHashLib{$key}
			  || CleanXSS($key);
			print "| - $newreferer | ";
			print ""
			  . (
				Format_Number($_se_referrals_p{$key} ? $_se_referrals_p{$key} : '0' ))
			  . " | ";
			print " / ".Format_Number($_se_referrals_h{$key})." | ";
			print " \n";
			$total_p += $_se_referrals_p{$key};
			$total_h += $_se_referrals_h{$key};
			$count++;
		}
		if ($Debug) {
			debug(
"Total real / shown : $TotalSearchEnginesPages / $total_p -  $TotalSearchEnginesHits / $total_h",
				2
			);
		}
		my $rest_p = $TotalSearchEnginesPages - $total_p;
		my $rest_h = $TotalSearchEnginesHits - $total_h;
		if ( $rest_p > 0 || $rest_h > 0 ) {
			print
"| - $Message[2] | ";
			print "".Format_Number($rest_p)." | ";
			print " / ".Format_Number($rest_h)." | ";
			print " \n";
		}
		print " ";
	}
	print " | \n";
	if ( $ShowOriginStats =~ /P/i ) {
		print ""
		  . ( $_from_p[2] ? Format_Number($_from_p[2]) : " " )
		  . " | "
		  . ( $_from_p[2] ? "$p_p[2] %" : " " ) . " | ";
	}
	if ( $ShowOriginStats =~ /H/i ) {
		print ""
		  . ( $_from_h[2] ? Format_Number($_from_h[2]) : " " )
		  . " | "
		  . ( $_from_h[2] ? "$p_h[2] %" : " " ) . " | ";
	}
	print "
\n";
	#------- Referrals by external HTML link
	print "$Message[41] - $Message[80] \n";
	if ( scalar keys %_pagesrefs_h ) {
		print "\n";
		my $total_p = 0;
		my $total_h = 0;
		my $count = 0;
		&BuildKeyList(
			$MaxNbOf{'RefererShown'},
			$MinHit{'Refer'},
			\%_pagesrefs_h,
			(
				( scalar keys %_pagesrefs_p )
				? \%_pagesrefs_p
				: \%_pagesrefs_h
			)
		);
		foreach my $key (@keylist) {
			print "| - ";
			&HTMLShowURLInfo($key);
			print " | ";
			print ""
			  . Format_Number(( $_pagesrefs_p{$key} ? $_pagesrefs_p{$key} : '0' ))
			  . " | ";
			print "".Format_Number($_pagesrefs_h{$key})." | ";
			print " \n";
			$total_p += $_pagesrefs_p{$key};
			$total_h += $_pagesrefs_h{$key};
			$count++;
		}
		if ($Debug) {
			debug(
"Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",
				2
			);
		}
		my $rest_p = $TotalRefererPages - $total_p;
		my $rest_h = $TotalRefererHits - $total_h;
		if ( $rest_p > 0 || $rest_h > 0 ) {
			print
"| - $Message[2] | ";
			print "".Format_Number($rest_p)." | ";
			print "".Format_Number($rest_h)." | ";
			print " \n";
		}
		print " ";
	}
	print " | \n";
	if ( $ShowOriginStats =~ /P/i ) {
		print ""
		  . ( $_from_p[3] ? Format_Number($_from_p[3]) : " " )
		  . " | "
		  . ( $_from_p[3] ? "$p_p[3] %" : " " ) . " | ";
	}
	if ( $ShowOriginStats =~ /H/i ) {
		print ""
		  . ( $_from_h[3] ? Format_Number($_from_h[3]) : " " )
		  . " | "
		  . ( $_from_h[3] ? "$p_h[3] %" : " " ) . " | ";
	}
	print "
\n";
	#------- Referrals by internal HTML link
	if ($IncludeInternalLinksInOriginSection) {
		print "| $Message[42] | ";
		if ( $ShowOriginStats =~ /P/i ) {
			print ""
			  . ( $_from_p[4] ? Format_Number($_from_p[4]) : " " )
			  . " | "
			  . ( $_from_p[4] ? "$p_p[4] %" : " " ) . " | ";
		}
		if ( $ShowOriginStats =~ /H/i ) {
			print ""
			  . ( $_from_h[4] ? Format_Number($_from_h[4]) : " " )
			  . " | "
			  . ( $_from_h[4] ? "$p_h[4] %" : " " ) . " | ";
		}
		print "
\n";
	}
	#------- Referrals by news group
	#print "| $Message[107] | ";
	#if ($ShowOriginStats =~ /P/i) { print "".($_from_p[5]?$_from_p[5]:" ")." | ".($_from_p[5]?"$p_p[5] %":" ")." | "; }
	#if ($ShowOriginStats =~ /H/i) { print "".($_from_h[5]?$_from_h[5]:" ")." | ".($_from_h[5]?"$p_h[5] %":" ")." | "; }
	#print "
\n";
	
	#------- Unknown origin
	print "| $Message[39] | ";
	if ( $ShowOriginStats =~ /P/i ) {
		print ""
		  . ( $_from_p[1] ? Format_Number($_from_p[1]) : " " )
		  . " | "
		  . ( $_from_p[1] ? "$p_p[1] %" : " " ) . " | ";
	}
	if ( $ShowOriginStats =~ /H/i ) {
		print ""
		  . ( $_from_h[1] ? Format_Number($_from_h[1]) : " " )
		  . " | "
		  . ( $_from_h[1] ? "$p_h[1] %" : " " ) . " | ";
	}
	print "
\n";
	&tab_end();
	# 0: Direct
	# 1: Unknown
	# 2: SE
	# 3: External link
	# 4: Internal link
	# 5: Newsgroup (deprecated)
}
#------------------------------------------------------------------------------
# Function:     Prints the Key Phrases and Keywords chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainKeys{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($ShowKeyphrasesStats) {
		print "$Center ";
	}
	if ($ShowKeywordsStats) {
		print "$Center ";
	}
	if ( $ShowKeyphrasesStats || $ShowKeywordsStats ) { print "
\n"; }
	if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
		print
		  "";
	}
	if ($ShowKeyphrasesStats) {
		
		# By Keyphrases
		if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
			print "\n";
		}
		if ($Debug) { debug( "ShowKeyphrasesStats", 2 ); }
		&tab_head(
"$Message[120] ($Message[77] $MaxNbOf{'KeyphrasesShown'}) $Message[80]",
			19,
			( $ShowKeyphrasesStats && $ShowKeywordsStats ) ? 95 : 70,
			'keyphrases'
		);
		print " | 
| $TotalDifferentKeyphrases $Message[103] | $Message[14] | $Message[15] | 
\n";
		my $total_s = 0;
		my $count = 0;
		&BuildKeyList( $MaxNbOf{'KeyphrasesShown'},
			$MinHit{'Keyphrase'}, \%_keyphrases, \%_keyphrases );
		foreach my $key (@keylist) {
			my $mot;
  # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
			if ( $PluginsLoaded{'DecodeKey'}{'decodeutfkeys'} ) {
				$mot = CleanXSS(
					DecodeKey_decodeutfkeys(
						$key, $PageCode || 'iso-8859-1'
					)
				);
			}
			else { $mot = CleanXSS( DecodeEncodedString($key) ); }
			my $p;
			if ($TotalKeyphrases) {
				$p =
				  int( $_keyphrases{$key} / $TotalKeyphrases * 1000 ) / 10;
			}
			print "| "
			  . XMLEncode($mot)
			  . " | $_keyphrases{$key} | $p % | 
\n";
			$total_s += $_keyphrases{$key};
			$count++;
		}
		if ($Debug) {
			debug( "Total real / shown : $TotalKeyphrases / $total_s", 2 );
		}
		my $rest_s = $TotalKeyphrases - $total_s;
		if ( $rest_s > 0 ) {
			my $p;
			if ($TotalKeyphrases) {
				$p = int( $rest_s / $TotalKeyphrases * 1000 ) / 10;
			}
			print
"| $Message[124] | $rest_s | ";
			print "$p % | 
\n";
		}
		&tab_end();
		if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
			print "\n";
		}
	}
	if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
		print "    | ";
	}
	if ($ShowKeywordsStats) {
		# By Keywords
		if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
			print "\n";
		}
		if ($Debug) { debug( "ShowKeywordsStats", 2 ); }
		&tab_head(
"$Message[121] ($Message[77] $MaxNbOf{'KeywordsShown'}) $Message[80]",
			19,
			( $ShowKeyphrasesStats && $ShowKeywordsStats ) ? 95 : 70,
			'keywords'
		);
		print " | | $TotalDifferentKeywords $Message[13] | $Message[14] | $Message[15] | 
\n";
		my $total_s = 0;
		my $count = 0;
		&BuildKeyList( $MaxNbOf{'KeywordsShown'},
			$MinHit{'Keyword'}, \%_keywords, \%_keywords );
		foreach my $key (@keylist) {
			my $mot;
  # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
			if ( $PluginsLoaded{'DecodeKey'}{'decodeutfkeys'} ) {
				$mot = CleanXSS(
					DecodeKey_decodeutfkeys(
						$key, $PageCode || 'iso-8859-1'
					)
				);
			}
			else { $mot = CleanXSS( DecodeEncodedString($key) ); }
			my $p;
			if ($TotalKeywords) {
				$p = int( $_keywords{$key} / $TotalKeywords * 1000 ) / 10;
			}
			print "| "
			  . XMLEncode($mot)
			  . " | $_keywords{$key} | $p % | 
\n";
			$total_s += $_keywords{$key};
			$count++;
		}
		if ($Debug) {
			debug( "Total real / shown : $TotalKeywords / $total_s", 2 );
		}
		my $rest_s = $TotalKeywords - $total_s;
		if ( $rest_s > 0 ) {
			my $p;
			if ($TotalKeywords) {
				$p = int( $rest_s / $TotalKeywords * 1000 ) / 10;
			}
			print
"| $Message[30] | $rest_s | ";
			print "$p % | 
\n";
		}
		&tab_end();
		if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
			print "\n";
		}
	}
	if ( $ShowKeyphrasesStats && $ShowKeywordsStats ) {
		print "
\n";
	}
}
#------------------------------------------------------------------------------
# Function:     Prints the miscellaneous table
# Parameters:   -
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainMisc{
	if ($Debug) { debug( "ShowMiscStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[139]";
	&tab_head( "$title", 19, 0, 'misc' );
	print
	  "| $Message[139] | ";
	print "  | ";
	print "  | ";
	print "
\n";
	my %label = (
		'AddToFavourites'           => $Message[137],
		'JavascriptDisabled'        => $Message[168],
		'JavaEnabled'               => $Message[140],
		'DirectorSupport'           => $Message[141],
		'FlashSupport'              => $Message[142],
		'RealPlayerSupport'         => $Message[143],
		'QuickTimeSupport'          => $Message[144],
		'WindowsMediaPlayerSupport' => $Message[145],
		'PDFSupport'                => $Message[146]
	);
	foreach my $key (@MiscListOrder) {
		my $mischar = substr( $key, 0, 1 );
		if ( $ShowMiscStats !~ /$mischar/i ) { next; }
		my $total = 0;
		my $p;
		if ( $MiscListCalc{$key} eq 'v' ) { $total = $TotalVisits; }
		if ( $MiscListCalc{$key} eq 'u' ) { $total = $TotalUnique; }
		if ( $MiscListCalc{$key} eq 'hm' ) {
			$total = $_misc_h{'TotalMisc'} || 0;
		}
		if ($total) {
			$p =
			  int( ( $_misc_h{$key} ? $_misc_h{$key} : 0 ) / $total *
				  1000 ) / 10;
		}
		print "";
		print "| "
		  . ( $PageDir eq 'rtl' ? "" : "" )
		  . $label{$key}
		  . ( $PageDir eq 'rtl' ? "" : "" ) . " | ";
		if ( $MiscListCalc{$key} eq 'v' ) {
			print ""
			  . Format_Number(( $_misc_h{$key} || 0 ))
			  . " / ".Format_Number($total)." $Message[12] | ";
		}
		if ( $MiscListCalc{$key} eq 'u' ) {
			print ""
			  . Format_Number(( $_misc_h{$key} || 0 ))
			  . " / ".Format_Number($total)." $Message[18] | ";
		}
		if ( $MiscListCalc{$key} eq 'hm' ) { print "- | "; }
		print "" . ( $total ? "$p %" : " " ) . " | ";
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the Status codes chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainHTTPStatus{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowHTTPErrorsStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[32]";
	
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        	
	&tab_head( "$title", 19, 0, 'errors' );
	
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_errors_h, \%_errors_h );
		
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int( $_errors_h{$key} / $TotalHitsErrors * 1000 ) / 10;
				push @blocklabel, "$key";
				$cnt++;
				if ($cnt > 4) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"$title",              "httpstatus",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print
"| $Message[32]* | $Message[57] | $Message[15] | $Message[75] | 
\n";
	my $total_h = 0;
	my $count = 0;
	foreach my $key (@keylist) {
		my $p = int( $_errors_h{$key} / $TotalHitsErrors * 1000 ) / 10;
		print "";
		if ( $TrapInfosForHTTPErrorCodes{$key} ) {
			print "| $key | ";
		}
		else { print "$key | "; }
		print ""
		  . (
			$httpcodelib{$key} ? $httpcodelib{$key} : 'Unknown error' )
		  . " | ".Format_Number($_errors_h{$key})." | $p % | "
		  . Format_Bytes( $_errors_k{$key} ) . " | ";
		print "
\n";
		$total_h += $_errors_h{$key};
		$count++;
	}
	&tab_end("* $Message[154]");
}
#------------------------------------------------------------------------------
# Function:     Prints the Status codes chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainSMTPStatus{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowSMTPErrorsStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[147]";
	&tab_head( "$title", 19, 0, 'errors' );
	print
"| $Message[147] | $Message[57] | $Message[15] | $Message[75] | 
\n";
	my $total_h = 0;
	my $count = 0;
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_errors_h, \%_errors_h );
	foreach my $key (@keylist) {
		my $p = int( $_errors_h{$key} / $TotalHitsErrors * 1000 ) / 10;
		print "";
		print "| $key | ";
		print ""
		  . (
			$smtpcodelib{$key} ? $smtpcodelib{$key} : 'Unknown error' )
		  . " | ".Format_Number($_errors_h{$key})." | $p % | "
		  . Format_Bytes( $_errors_k{$key} ) . " | ";
		print "
\n";
		$total_h += $_errors_h{$key};
		$count++;
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints the cluster information chart and table
# Parameters:   $NewLinkParams, $NewLinkTarget
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainCluster{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	
	if ($Debug) { debug( "ShowClusterStats", 2 ); }
	print "$Center 
\n";
	my $title = "$Message[155]";
	
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
       # extend the title to include the added link
           $title .= "   -   $Message[179]");
    }
        	
	&tab_head( "$title", 19, 0, 'clusters' );
	
	&BuildKeyList( $MaxRowsInHTMLOutput, 1, \%_cluster_p, \%_cluster_p );
	
	# Graph the top five in a pie chart
	if (scalar @keylist > 1){
		foreach my $pluginname ( keys %{ $PluginsLoaded{'ShowGraph'} } )
		{
			my @blocklabel = ();
			my @valdata = ();
			my @valcolor = ($color_p);
			my $cnt = 0;
			foreach my $key (@keylist) {
				push @valdata, int( $_cluster_p{$key} / $TotalHits * 1000 ) / 10;
				push @blocklabel, "$key";
				$cnt++;
				if ($cnt > 4) { last; }
			}
			print "| ";
			my $function = "ShowGraph_$pluginname";
			&$function(
				"$title",              "cluster",
				0, 						\@blocklabel,
				0,           			\@valcolor,
				0,              		0,
				0,          			\@valdata
			);
			print " | 
";
		}
	}
	
	print
	  "| $Message[155] | ";
	&HTMLShowClusterInfo('__title__');
	if ( $ShowClusterStats =~ /P/i ) {
		print
"$Message[56] | $Message[15] | ";
	}
	if ( $ShowClusterStats =~ /H/i ) {
		print
"$Message[57] | $Message[15] | ";
	}
	if ( $ShowClusterStats =~ /B/i ) {
		print
"$Message[75] | $Message[15] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = 0;
# Cluster feature might have been enable in middle of month so we recalculate
# total for cluster section only, to calculate ratio, instead of using global total
	foreach my $key (@keylist) {
		$total_p += int( $_cluster_p{$key} || 0 );
		$total_h += int( $_cluster_h{$key} || 0 );
		$total_k += int( $_cluster_k{$key} || 0 );
	}
	my $count = 0;
	foreach my $key (@keylist) {
		my $p_p = int( $_cluster_p{$key} / $total_p * 1000 ) / 10;
		my $p_h = int( $_cluster_h{$key} / $total_h * 1000 ) / 10;
		my $p_k = int( $_cluster_k{$key} / $total_k * 1000 ) / 10;
		print "";
		print "| Computer $key | ";
		&HTMLShowClusterInfo($key);
		if ( $ShowClusterStats =~ /P/i ) {
			print ""
			  . ( $_cluster_p{$key} ? Format_Number($_cluster_p{$key}) : " " )
			  . " | $p_p % | ";
		}
		if ( $ShowClusterStats =~ /H/i ) {
			print "".Format_Number($_cluster_h{$key})." | $p_h % | ";
		}
		if ( $ShowClusterStats =~ /B/i ) {
			print ""
			  . Format_Bytes( $_cluster_k{$key} )
			  . " | $p_k % | ";
		}
		print "
\n";
		$count++;
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# Function:     Prints a chart or table for each extra section
# Parameters:   $NewLinkParams, $NewLinkTarget, $extranum
# Input:        -
# Output:       HTML
# Return:       -
#------------------------------------------------------------------------------
sub HTMLMainExtra{
	my $NewLinkParams = shift;
	my $NewLinkTarget = shift;
	my $extranum = shift;
	
	if ($Debug) { debug( "ExtraName$extranum", 2 ); }
	print "$Center 
";
	my $title = $ExtraName[$extranum];
	&tab_head( "$title ($Message[77] $MaxNbOfExtra[$extranum])", 19, 0, "extra$extranum");
	print "";
	print "| " . $ExtraFirstColumnTitle[$extranum];
	print "  -   $Message[80]";
	  
    if ( $AddLinkToExternalCGIWrapper && ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) ) {
        print "  -   $Message[179]");
    }
  
	print " | ";
	if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
		print
		  "$Message[56] | ";
	}
	if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
		print
		  "$Message[57] | ";
	}
	if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
		print
		  "$Message[75] | ";
	}
	if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
		print "$Message[9] | ";
	}
	print "
\n";
	my $total_p = my $total_h = my $total_k = 0;
	 #$max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } }
	 #$max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } }
	my $count = 0;
	if ( $MaxNbOfExtra[$extranum] ) {
		if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
			&BuildKeyList(
				$MaxNbOfExtra[$extranum],
				$MinHitExtra[$extranum],
				\%{ '_section_' . $extranum . '_h' },
				\%{ '_section_' . $extranum . '_p' }
			);
		}
		else {
			&BuildKeyList(
				$MaxNbOfExtra[$extranum],
				$MinHitExtra[$extranum],
				\%{ '_section_' . $extranum . '_h' },
				\%{ '_section_' . $extranum . '_h' }
			);
		}
	}
	else {
		@keylist = ();
	}
	my %keysinkeylist = ();
	foreach my $key (@keylist) {
		$keysinkeylist{$key} = 1;
		my $firstcol = CleanXSS( DecodeEncodedString($key) );
		$total_p += ${ '_section_' . $extranum . '_p' }{$key};
		$total_h += ${ '_section_' . $extranum . '_h' }{$key};
		$total_k += ${ '_section_' . $extranum . '_k' }{$key};
		print "";
		printf(
			"| $ExtraFirstColumnFormat[$extranum] | ",
			$firstcol, $firstcol, $firstcol, $firstcol, $firstcol );
		if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
			print ""
			  . ${ '_section_' . $extranum . '_p' }{$key} . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
			print ""
			  . ${ '_section_' . $extranum . '_h' }{$key} . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
			print ""
			  . Format_Bytes(
				${ '_section_' . $extranum . '_k' }{$key} )
			  . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
			print ""
			  . (
				${ '_section_' . $extranum . '_l' }{$key}
				? Format_Date(
					${ '_section_' . $extranum . '_l' }{$key}, 1 )
				: '-'
			  )
			  . " | ";
		}
		print "
\n";
		$count++;
	}
	# If we ask average or sum, we loop on all other records
	if ( $ExtraAddAverageRow[$extranum] || $ExtraAddSumRow[$extranum] )
	{
		foreach ( keys %{ '_section_' . $extranum . '_h' } ) {
			if ( $keysinkeylist{$_} ) { next; }
			$total_p += ${ '_section_' . $extranum . '_p' }{$_};
			$total_h += ${ '_section_' . $extranum . '_h' }{$_};
			$total_k += ${ '_section_' . $extranum . '_k' }{$_};
			$count++;
		}
	}
	# Add average row
	if ( $ExtraAddAverageRow[$extranum] ) {
		print "";
		print "| $Message[96] | ";
		if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
			print ""
			  . ( $count ? Format_Number(( $total_p / $count )) : " " ) . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
			print ""
			  . ( $count ? Format_Number(( $total_h / $count )) : " " ) . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
			print ""
			  . (
				$count ? Format_Bytes( $total_k / $count ) : " " )
			  . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
			print "  | ";
		}
		print "
\n";
	}
	# Add sum row
	if ( $ExtraAddSumRow[$extranum] ) {
		print "";
		print "| $Message[102] | ";
		if ( $ExtraStatTypes[$extranum] =~ m/P/i ) {
			print "" . Format_Number(($total_p)) . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/H/i ) {
			print "" . Format_Number(($total_h)) . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/B/i ) {
			print "" . Format_Bytes($total_k) . " | ";
		}
		if ( $ExtraStatTypes[$extranum] =~ m/L/i ) {
			print "  | ";
		}
		print "
\n";
	}
	&tab_end();
}
#------------------------------------------------------------------------------
# MAIN
#------------------------------------------------------------------------------
( $DIR  = $0 ) =~ s/([^\/\\]+)$//;
( $PROG = $1 ) =~ s/\.([^\.]*)$//;
$Extension = $1;
$DIR ||= '.';
$DIR =~ s/([^\/\\])[\\\/]+$/$1/;
$starttime = time();
# Get current time (time when AWStats was started)
( $nowsec, $nowmin, $nowhour, $nowday, $nowmonth, $nowyear, $nowwday, $nowyday )
  = localtime($starttime);
$nowweekofmonth = int( $nowday / 7 );
$nowweekofyear  =
  int( ( $nowyday - 1 + 6 - ( $nowwday == 0 ? 6 : $nowwday - 1 ) ) / 7 ) + 1;
if ( $nowweekofyear > 52 ) { $nowweekofyear = 1; }
$nowdaymod = $nowday % 7;
$nowwday++;
$nowns = Time::Local::timegm( 0, 0, 0, $nowday, $nowmonth, $nowyear );
if ( $nowdaymod <= $nowwday ) {
	if ( ( $nowwday != 7 ) || ( $nowdaymod != 0 ) ) {
		$nowweekofmonth = $nowweekofmonth + 1;
	}
}
if ( $nowdaymod > $nowwday ) { $nowweekofmonth = $nowweekofmonth + 2; }
# Change format of time variables
$nowweekofmonth = "0$nowweekofmonth";
if ( $nowweekofyear < 10 ) { $nowweekofyear = "0$nowweekofyear"; }
if ( $nowyear < 100 ) { $nowyear += 2000; }
else { $nowyear += 1900; }
$nowsmallyear = $nowyear;
$nowsmallyear =~ s/^..//;
if ( ++$nowmonth < 10 ) { $nowmonth = "0$nowmonth"; }
if ( $nowday < 10 )     { $nowday   = "0$nowday"; }
if ( $nowhour < 10 )    { $nowhour  = "0$nowhour"; }
if ( $nowmin < 10 )     { $nowmin   = "0$nowmin"; }
if ( $nowsec < 10 )     { $nowsec   = "0$nowsec"; }
$nowtime = int( $nowyear . $nowmonth . $nowday . $nowhour . $nowmin . $nowsec );
# Get tomorrow time (will be used to discard some record with corrupted date (future date))
my (
	$tomorrowsec, $tomorrowmin,   $tomorrowhour,
	$tomorrowday, $tomorrowmonth, $tomorrowyear
  )
  = localtime( $starttime + 86400 );
if ( $tomorrowyear < 100 ) { $tomorrowyear += 2000; }
else { $tomorrowyear += 1900; }
if ( ++$tomorrowmonth < 10 ) { $tomorrowmonth = "0$tomorrowmonth"; }
if ( $tomorrowday < 10 )     { $tomorrowday   = "0$tomorrowday"; }
if ( $tomorrowhour < 10 )    { $tomorrowhour  = "0$tomorrowhour"; }
if ( $tomorrowmin < 10 )     { $tomorrowmin   = "0$tomorrowmin"; }
if ( $tomorrowsec < 10 )     { $tomorrowsec   = "0$tomorrowsec"; }
$tomorrowtime =
  int(  $tomorrowyear
	  . $tomorrowmonth
	  . $tomorrowday
	  . $tomorrowhour
	  . $tomorrowmin
	  . $tomorrowsec );
# Allowed option
my @AllowedCLIArgs = (
	'migrate',            'config',
	'logfile',            'output',
	'runascli',           'update',
	'staticlinks',        'staticlinksext',
	'noloadplugin',       'loadplugin',
	'hostfilter',         'urlfilter',
	'refererpagesfilter', 'lang',
	'month',              'year',
	'framename',          'debug',
	'showsteps',          'showdropped',
	'showcorrupted',      'showunknownorigin',
	'showdirectorigin',   'limitflush',
    'nboflastupdatelookuptosave',
	'confdir',            'updatefor',
	'hostfilter',         'hostfilterex',
	'urlfilter',          'urlfilterex',
	'refererpagesfilter', 'refererpagesfilterex',
	'pluginmode',         'filterrawlog'
);
# Parse input parameters and sanitize them for security reasons
$QueryString = '';
# AWStats use GATEWAY_INTERFACE to known if ran as CLI or CGI. AWSTATS_DEL_GATEWAY_INTERFACE can
# be set to force AWStats to be ran as CLI even from a web page.
if ( $ENV{'AWSTATS_DEL_GATEWAY_INTERFACE'} ) { $ENV{'GATEWAY_INTERFACE'} = ''; }
if ( $ENV{'GATEWAY_INTERFACE'} ) {    # Run from a browser as CGI
	$DebugMessages = 0;
	# Prepare QueryString
	if ( $ENV{'CONTENT_LENGTH'} ) {
		binmode STDIN;
		read( STDIN, $QueryString, $ENV{'CONTENT_LENGTH'} );
	}
	if ( $ENV{'QUERY_STRING'} ) {
		$QueryString = $ENV{'QUERY_STRING'};
		# Set & and & to &
		$QueryString =~ s/&/&/g;
		$QueryString =~ s/&/&/g;
	}
	# Remove all XSS vulnerabilities coming from AWStats parameters
	$QueryString = CleanXSS( &DecodeEncodedString($QueryString) );
	# Security test
	if ( $QueryString =~ /LogFile=([^&]+)/i ) {
		error(
"Logfile parameter can't be overwritten when AWStats is used from a CGI"
		);
	}
	# No update but report by default when run from a browser
	$UpdateStats = ( $QueryString =~ /update=1/i ? 1 : 0 );
	if ( $QueryString =~ /config=([^&]+)/i ) { 
		$SiteConfig = &Sanitize("$1");
	}
	if ( $QueryString =~ /diricons=([^&]+)/i ) { $DirIcons = "$1"; }
	if ( $QueryString =~ /pluginmode=([^&]+)/i ) {
		$PluginMode = &Sanitize( "$1", 1 );
	}
	if ( $QueryString =~ /configdir=([^&]+)/i ) {
		$DirConfig = &Sanitize("$1");
		$DirConfig =~ s/\\{2,}/\\/g;	# This is to clean Remote URL
		$DirConfig =~ s/\/{2,}/\//g;	# This is to clean Remote URL
	}
	# All filters
	if ( $QueryString =~ /hostfilter=([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	}    # Filter on host list can also be defined with hostfilter=filter
	if ( $QueryString =~ /hostfilterex=([^&]+)/i ) {
		$FilterEx{'host'} = "$1";
	}    #
	if ( $QueryString =~ /urlfilter=([^&]+)/i ) {
		$FilterIn{'url'} = "$1";
	}    # Filter on URL list can also be defined with urlfilter=filter
	if ( $QueryString =~ /urlfilterex=([^&]+)/i ) { $FilterEx{'url'} = "$1"; } #
	if ( $QueryString =~ /refererpagesfilter=([^&]+)/i ) {
		$FilterIn{'refererpages'} = "$1";
	} # Filter on referer list can also be defined with refererpagesfilter=filter
	if ( $QueryString =~ /refererpagesfilterex=([^&]+)/i ) {
		$FilterEx{'refererpages'} = "$1";
	}    #
	     # All output
	if ( $QueryString =~ /output=allhosts:([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	} # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=lasthosts:([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	} # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=urldetail:([^&]+)/i ) {
		$FilterIn{'url'} = "$1";
	} # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=refererpages:([^&]+)/i ) {
		$FilterIn{'refererpages'} = "$1";
	} # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed
	# If migrate
	if ( $QueryString =~ /(^|-|&|&)migrate=([^&]+)/i ) {
		$MigrateStats = &Sanitize("$2");
		$MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/;
		$SiteConfig = &Sanitize($5 ? $5 : 'xxx');
		$SiteConfig =~ s/^\.//;    # SiteConfig is used to find config file
	}
	$SiteConfig =~ s/\.\.//g; 		# Avoid directory transversal
}
else {                             # Run from command line
	$DebugMessages = 1;
	# Prepare QueryString
	for ( 0 .. @ARGV - 1 ) {
		# If migrate
		if ( $ARGV[$_] =~ /(^|-|&|&)migrate=([^&]+)/i ) {
			$MigrateStats = &Sanitize("$2");
			$MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/;
			$SiteConfig = &Sanitize($5 ? $5 : 'xxx');
			$SiteConfig =~ s/^\.//;    # SiteConfig is used to find config file
			next;
		}
		# TODO Check if ARGV is in @AllowedArg
		if ($QueryString) { $QueryString .= '&'; }
		my $NewLinkParams = $ARGV[$_];
		$NewLinkParams =~ s/^-+//;
		$QueryString .= "$NewLinkParams";
	}
	# Remove all XSS vulnerabilities coming from AWStats parameters
	$QueryString = CleanXSS($QueryString);
	# Security test
	if (   $ENV{'AWSTATS_DEL_GATEWAY_INTERFACE'}
		&& $QueryString =~ /LogFile=([^&]+)/i )
	{
		error(
"Logfile parameter can't be overwritten when AWStats is used from a CGI"
		);
	}
	# Update with no report by default when run from command line
	$UpdateStats = 1;
	if ( $QueryString =~ /config=([^&]+)/i ) { 
		$SiteConfig = &Sanitize("$1"); 
	}
	if ( $QueryString =~ /diricons=([^&]+)/i ) { $DirIcons = "$1"; }
	if ( $QueryString =~ /pluginmode=([^&]+)/i ) {
		$PluginMode = &Sanitize( "$1", 1 );
	}
	if ( $QueryString =~ /configdir=([^&]+)/i ) {
		$DirConfig = &Sanitize("$1");
		$DirConfig =~ s/\\{2,}/\\/g;	# This is to clean Remote URL
		$DirConfig =~ s/\/{2,}/\//g;	# This is to clean Remote URL
	}
	# All filters
	if ( $QueryString =~ /hostfilter=([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	}    # Filter on host list can also be defined with hostfilter=filter
	if ( $QueryString =~ /hostfilterex=([^&]+)/i ) {
		$FilterEx{'host'} = "$1";
	}    #
	if ( $QueryString =~ /urlfilter=([^&]+)/i ) {
		$FilterIn{'url'} = "$1";
	}    # Filter on URL list can also be defined with urlfilter=filter
	if ( $QueryString =~ /urlfilterex=([^&]+)/i ) { $FilterEx{'url'} = "$1"; } #
	if ( $QueryString =~ /refererpagesfilter=([^&]+)/i ) {
		$FilterIn{'refererpages'} = "$1";
	} # Filter on referer list can also be defined with refererpagesfilter=filter
	if ( $QueryString =~ /refererpagesfilterex=([^&]+)/i ) {
		$FilterEx{'refererpages'} = "$1";
	}    #
	     # All output
	if ( $QueryString =~ /output=allhosts:([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	} # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=lasthosts:([^&]+)/i ) {
		$FilterIn{'host'} = "$1";
	} # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=urldetail:([^&]+)/i ) {
		$FilterIn{'url'} = "$1";
	} # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed
	if ( $QueryString =~ /output=refererpages:([^&]+)/i ) {
		$FilterIn{'refererpages'} = "$1";
	} # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed
	  # Config parameters
	if ( $QueryString =~ /LogFile=([^&]+)/i ) { $LogFile = "$1"; }
	# If show options
	if ( $QueryString =~ /showsteps/i ) {
		$ShowSteps = 1;
		$QueryString =~ s/showsteps[^&]*//i;
	}
	if ( $QueryString =~ /showcorrupted/i ) {
		$ShowCorrupted = 1;
		$QueryString =~ s/showcorrupted[^&]*//i;
	}
	if ( $QueryString =~ /showdropped/i ) {
		$ShowDropped = 1;
		$QueryString =~ s/showdropped[^&]*//i;
	}
	if ( $QueryString =~ /showunknownorigin/i ) {
		$ShowUnknownOrigin = 1;
		$QueryString =~ s/showunknownorigin[^&]*//i;
	}
	if ( $QueryString =~ /showdirectorigin/i ) {
		$ShowDirectOrigin = 1;
		$QueryString =~ s/showdirectorigin[^&]*//i;
	}
	
	$SiteConfig =~ s/\.\.//g; 
}
if ( $QueryString =~ /(^|&|&)staticlinks/i ) {
	$StaticLinks = "$PROG.$SiteConfig";
}
if ( $QueryString =~ /(^|&|&)staticlinks=([^&]+)/i ) {
	$StaticLinks = "$2";
}    # When ran from awstatsbuildstaticpages.pl
if ( $QueryString =~ /(^|&|&)staticlinksext=([^&]+)/i ) {
	$StaticExt = "$2";
}
if ( $QueryString =~ /(^|&|&)framename=([^&]+)/i ) { $FrameName = "$2"; }
if ( $QueryString =~ /(^|&|&)debug=(\d+)/i )       { $Debug     = $2; }
if ( $QueryString =~ /(^|&|&)databasebreak=(\w+)/i ) {
	$DatabaseBreak = $2;
}
if ( $QueryString =~ /(^|&|&)updatefor=(\d+)/i ) { $UpdateFor = $2; }
if ( $QueryString =~ /(^|&|&)noloadplugin=([^&]+)/i ) {
	foreach ( split( /,/, $2 ) ) { $NoLoadPlugin{ &Sanitize( "$_", 1 ) } = 1; }
}
if ( $QueryString =~ /(^|&|&)limitflush=(\d+)/i ) { $LIMITFLUSH = $2; }
if ( $QueryString =~ /(^|&|&)nboflastupdatelookuptosave=(\d+)/i ) { $NBOFLASTUPDATELOOKUPTOSAVE = $2; }
# Get/Define output
if ( $QueryString =~
	/(^|&|&)output(=[^&]*|)(.*)(&|&)output(=[^&]*|)(&|$)/i )
{
	error( "Only 1 output option is allowed", "", "", 1 );
}
if ( $QueryString =~ /(^|&|&)output(=[^&]*|)(&|$)/i ) {
	# At least one output expected. We define %HTMLOutput
	my $outputlist = "$2";
	if ($outputlist) {
		$outputlist =~ s/^=//;
		foreach my $outputparam ( split( /,/, $outputlist ) ) {
			$outputparam =~ s/:(.*)$//;
			if ($outputparam) { $HTMLOutput{ lc($outputparam) } = "$1" || 1; }
		}
	}
	# If on command line and no update
	if ( !$ENV{'GATEWAY_INTERFACE'} && $QueryString !~ /update/i ) {
		$UpdateStats = 0;
	}
	# If no output defined, used default value
	if ( !scalar keys %HTMLOutput ) { $HTMLOutput{'main'} = 1; }
}
if ( $ENV{'GATEWAY_INTERFACE'} && !scalar keys %HTMLOutput ) {
	$HTMLOutput{'main'} = 1;
}
# Remove -output option with no = from QueryString
$QueryString =~ s/(^|&|&)output(&|$)/$1$2/i;
$QueryString =~ s/&+$//;
# Check year, month, day, hour parameters
if ( $QueryString =~ /(^|&|&)month=(year)/i ) {
	error("month=year is a deprecated option. Use month=all instead.");
}
if ( $QueryString =~ /(^|&|&)year=(\d\d\d\d)/i ) {
	$YearRequired = sprintf( "%04d", $2 );
}
else { $YearRequired = "$nowyear"; }
if ( $QueryString =~ /(^|&|&)month=(\d{1,2})/i ) {
	$MonthRequired = sprintf( "%02d", $2 );
}
elsif ( $QueryString =~ /(^|&|&)month=(all)/i ) { $MonthRequired = 'all'; }
else { $MonthRequired = "$nowmonth"; }
if ( $QueryString =~ /(^|&|&)day=(\d{1,2})/i ) {
	$DayRequired = sprintf( "%02d", $2 );
} # day is a hidden option. Must not be used (Make results not understandable). Available for users that rename history files with day.
else { $DayRequired = ''; }
if ( $QueryString =~ /(^|&|&)hour=(\d{1,2})/i ) {
	$HourRequired = sprintf( "%02d", $2 );
} # hour is a hidden option. Must not be used (Make results not understandable). Available for users that rename history files with day.
else { $HourRequired = ''; }
# Check parameter validity
# TODO
# Print AWStats and Perl version
if ($Debug) {
	debug( ucfirst($PROG) . " - $VERSION - Perl $^X $]", 1 );
	debug( "DIR=$DIR PROG=$PROG Extension=$Extension",   2 );
	debug( "QUERY_STRING=$QueryString",                  2 );
	debug( "HTMLOutput=" . join( ',', keys %HTMLOutput ), 1 );
	debug( "YearRequired=$YearRequired, MonthRequired=$MonthRequired", 2 );
	debug( "DayRequired=$DayRequired, HourRequired=$HourRequired",     2 );
	debug( "UpdateFor=$UpdateFor",                                     2 );
	debug( "PluginMode=$PluginMode",                                   2 );
	debug( "DirConfig=$DirConfig",                                     2 );
}
# Force SiteConfig if AWSTATS_FORCE_CONFIG is defined
if ( $ENV{'AWSTATS_CONFIG'} ) {
	$ENV{'AWSTATS_FORCE_CONFIG'} = $ENV{'AWSTATS_CONFIG'};
}    # For backward compatibility
if ( $ENV{'AWSTATS_FORCE_CONFIG'} ) {
	if ($Debug) {
		debug(  "AWSTATS_FORCE_CONFIG parameter is defined to '"
			  . $ENV{'AWSTATS_FORCE_CONFIG'}
			  . "'. $PROG will use this as config value." );
	}
	$SiteConfig = &Sanitize( $ENV{'AWSTATS_FORCE_CONFIG'} );
}
# Display version information
if ( $QueryString =~ /(^|&|&)version/i ) {
	print "$PROG $VERSION\n";
	exit 0;
}
# Display help information
if ( ( !$ENV{'GATEWAY_INTERFACE'} ) && ( !$SiteConfig ) ) {
	&PrintCLIHelp();
	exit 2;
}
$SiteConfig ||= &Sanitize( $ENV{'SERVER_NAME'} );
#$ENV{'SERVER_NAME'}||=$SiteConfig;	# For thoose who use __SERVER_NAME__ in conf file and use CLI.
$ENV{'AWSTATS_CURRENT_CONFIG'} = $SiteConfig;
# Read config file (SiteConfig must be defined)
&Read_Config($DirConfig);
# Check language
if ( $QueryString =~ /(^|&|&)lang=([^&]+)/i ) { $Lang = "$2"; }
if ( !$Lang || $Lang eq 'auto' ) {    # If lang not defined or forced to auto
	my $langlist = $ENV{'HTTP_ACCEPT_LANGUAGE'} || '';
	$langlist =~ s/;[^,]*//g;
	if ($Debug) {
		debug(
			"Search an available language among HTTP_ACCEPT_LANGUAGE=$langlist",
			1
		);
	}
	foreach my $code ( split( /,/, $langlist ) )
	{                                 # Search for a valid lang in priority
		if ( $LangBrowserToLangAwstats{$code} ) {
			$Lang = $LangBrowserToLangAwstats{$code};
			if ($Debug) { debug( " Will try to use Lang=$Lang", 1 ); }
			last;
		}
		$code =~ s/-.*$//;
		if ( $LangBrowserToLangAwstats{$code} ) {
			$Lang = $LangBrowserToLangAwstats{$code};
			if ($Debug) { debug( " Will try to use Lang=$Lang", 1 ); }
			last;
		}
	}
}
if ( !$Lang || $Lang eq 'auto' ) {
	if ($Debug) {
		debug( " No language defined or available. Will use Lang=en", 1 );
	}
	$Lang = 'en';
}
# Check and correct bad parameters
&Check_Config();
# Now SiteDomain is defined
if ( $Debug && !$DebugMessages ) {
	error(
"Debug has not been allowed. Change DebugMessages parameter in config file to allow debug."
	);
}
# Define frame name and correct variable for frames
if ( !$FrameName ) {
	if (   $ENV{'GATEWAY_INTERFACE'}
		&& $UseFramesWhenCGI
		&& $HTMLOutput{'main'}
		&& !$PluginMode )
	{
		$FrameName = 'index';
	}
	else { $FrameName = 'main'; }
}
# Load Message files, Reference data files and Plugins
if ($Debug) { debug( "FrameName=$FrameName", 1 ); }
if ( $FrameName ne 'index' ) {
	&Read_Language_Data($Lang);
	if ( $FrameName ne 'mainleft' ) {
		my %datatoload = ();
		my (
			$filedomains, $filemime, $filerobots, $fileworms,
			$filebrowser, $fileos,   $filese
		  )
		  = (
			'domains',  'mime',
			'robots',   'worms',
			'browsers', 'operating_systems',
			'search_engines'
		  );
		my ( $filestatushttp, $filestatussmtp ) =
		  ( 'status_http', 'status_smtp' );
		if ( $LevelForBrowsersDetection eq 'allphones' ) {
			$filebrowser = 'browsers_phone';
		}
		if ($UpdateStats) {    # If update
			if ($LevelForFileTypesDetection) {
				$datatoload{$filemime} = 1;
			}                  # Only if need to filter on known extensions
			if ($LevelForRobotsDetection) {
				$datatoload{$filerobots} = 1;
			}                  # ua
			if ($LevelForWormsDetection) {
				$datatoload{$fileworms} = 1;
			}                  # url
			if ($LevelForBrowsersDetection) {
				$datatoload{$filebrowser} = 1;
			}                  # ua
			if ($LevelForOSDetection) {
				$datatoload{$fileos} = 1;
			}                  # ua
			if ($LevelForRefererAnalyze) {
				$datatoload{$filese} = 1;
			}                  # referer
			                   # if (...) { $datatoload{'referer_spam'}=1; }
		}
		if ( scalar keys %HTMLOutput ) {    # If output
			if ( $ShowDomainsStats || $ShowHostsStats ) {
				$datatoload{$filedomains} = 1;
			} # TODO Replace by test if ($ShowDomainsStats) when plugins geoip can force load of domains datafile.
			if ($ShowFileTypesStats)  { $datatoload{$filemime}       = 1; }
			if ($ShowRobotsStats)     { $datatoload{$filerobots}     = 1; }
			if ($ShowWormsStats)      { $datatoload{$fileworms}      = 1; }
			if ($ShowBrowsersStats)   { $datatoload{$filebrowser}    = 1; }
			if ($ShowOSStats)         { $datatoload{$fileos}         = 1; }
			if ($ShowOriginStats)     { $datatoload{$filese}         = 1; }
			if ($ShowHTTPErrorsStats) { $datatoload{$filestatushttp} = 1; }
			if ($ShowSMTPErrorsStats) { $datatoload{$filestatussmtp} = 1; }
		}
		&Read_Ref_Data( keys %datatoload );
	}
	&Read_Plugins();
}
# Here charset is defined, so we can send the http header (Need BuildReportFormat,PageCode)
if ( !$HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'} ) {
	http_head();
}    # Run from a browser as CGI
# Init other parameters
$NBOFLINESFORBENCHMARK--;
if ( $ENV{'GATEWAY_INTERFACE'} ) { $DirCgi = ''; }
if ( $DirCgi && !( $DirCgi =~ /\/$/ ) && !( $DirCgi =~ /\\$/ ) ) {
	$DirCgi .= '/';
}
if ( !$DirData || $DirData =~ /^\./ ) {
	if ( !$DirData || $DirData eq '.' ) {
		$DirData = "$DIR";
	}    # If not defined or chosen to '.' value then DirData is current dir
	elsif ( $DIR && $DIR ne '.' ) { $DirData = "$DIR/$DirData"; }
}
$DirData ||= '.';    # If current dir not defined then we put it to '.'
$DirData =~ s/[\\\/]+$//;
if ( $FirstDayOfWeek == 1 ) { @DOWIndex = ( 1, 2, 3, 4, 5, 6, 0 ); }
else { @DOWIndex = ( 0, 1, 2, 3, 4, 5, 6 ); }
# Should we link to ourselves or to a wrapper script
$AWScript = ( $WrapperScript ? "$WrapperScript" : "$DirCgi$PROG.$Extension" );
if (index($AWScript,'?')>-1) 
{
    $AWScript .= '&';   # $AWScript contains URL parameters
}
else 
{
    $AWScript .= '?';
}
# Print html header (Need HTMLOutput,Expires,Lang,StyleSheet,HTMLHeadSectionExpires defined by Read_Config, PageCode defined by Read_Language_Data)
if ( !$HeaderHTMLSent ) { &html_head; }
# AWStats output is replaced by a plugin output
if ($PluginMode) {
	#	my $function="BuildFullHTMLOutput_$PluginMode()";
	#	eval("$function");
	my $function = "BuildFullHTMLOutput_$PluginMode";
	&$function();
	if ( $? || $@ ) { error("$@"); }
	&html_end(0);
	exit 0;
}
# Security check
if ( $AllowAccessFromWebToAuthenticatedUsersOnly && $ENV{'GATEWAY_INTERFACE'} )
{
	if ($Debug) { debug( "REMOTE_USER=" . $ENV{"REMOTE_USER"} ); }
	if ( !$ENV{"REMOTE_USER"} ) {
		error(
"Access to statistics is only allowed from an authenticated session to authenticated users."
		);
	}
	if (@AllowAccessFromWebToFollowingAuthenticatedUsers) {
		my $userisinlist = 0;
		my $remoteuser   = quotemeta( $ENV{"REMOTE_USER"} );
		$remoteuser =~ s/\s/%20/g
		  ; # Allow authenticated user with space in name to be compared to allowed user list
		my $currentuser = qr/^$remoteuser$/i;    # Set precompiled regex
		foreach (@AllowAccessFromWebToFollowingAuthenticatedUsers) {
			if (/$currentuser/o) { $userisinlist = 1; last; }
		}
		if ( !$userisinlist ) {
			error(  "User '"
				  . $ENV{"REMOTE_USER"}
				  . "' is not allowed to access statistics of this domain/config."
			);
		}
	}
}
if ( $AllowAccessFromWebToFollowingIPAddresses && $ENV{'GATEWAY_INTERFACE'} ) {
	my $IPAddress     = $ENV{"REMOTE_ADDR"};                  # IPv4 or IPv6
	my $useripaddress = &Convert_IP_To_Decimal($IPAddress);
	my @allowaccessfromipaddresses =
	  split( /[\s,]+/, $AllowAccessFromWebToFollowingIPAddresses );
	my $allowaccess = 0;
	foreach my $ipaddressrange (@allowaccessfromipaddresses) {
		if ( $ipaddressrange !~
			/^(\d+\.\d+\.\d+\.\d+)(?:-(\d+\.\d+\.\d+\.\d+))*$/
			&& $ipaddressrange !~
			/^([0-9A-Fa-f]{1,4}:){1,7}(:|)([0-9A-Fa-f]{1,4}|\/\d)/ )
		{
			error(
"AllowAccessFromWebToFollowingIPAddresses is defined to '$AllowAccessFromWebToFollowingIPAddresses' but part of value does not match the correct syntax: IPv4AddressMin[-IPv4AddressMax] or IPv6Address[\/prefix] in \"$ipaddressrange\""
			);
		}
		# Test ip v4
		if ( $ipaddressrange =~
			/^(\d+\.\d+\.\d+\.\d+)(?:-(\d+\.\d+\.\d+\.\d+))*$/ )
		{
			my $ipmin = &Convert_IP_To_Decimal($1);
			my $ipmax = $2 ? &Convert_IP_To_Decimal($2) : $ipmin;
			# Is it an authorized ip ?
			if ( ( $useripaddress >= $ipmin ) && ( $useripaddress <= $ipmax ) )
			{
				$allowaccess = 1;
				last;
			}
		}
		# Test ip v6
		if ( $ipaddressrange =~
			/^([0-9A-Fa-f]{1,4}:){1,7}(:|)([0-9A-Fa-f]{1,4}|\/\d)/ )
		{
			if ( $ipaddressrange =~ /::\// ) {
				my @IPv6split = split( /::/, $ipaddressrange );
				if ( $IPAddress =~ /^$IPv6split[0]/ ) {
					$allowaccess = 1;
					last;
				}
			}
			elsif ( $ipaddressrange == $IPAddress ) {
				$allowaccess = 1;
				last;
			}
		}
	}
	if ( !$allowaccess ) {
		error( "Access to statistics is not allowed from your IP Address "
			  . $ENV{"REMOTE_ADDR"} );
	}
}
if (   ( $UpdateStats || $MigrateStats )
	&& ( !$AllowToUpdateStatsFromBrowser )
	&& $ENV{'GATEWAY_INTERFACE'} )
{
	error(  ""
		  . ( $UpdateStats ? "Update" : "Migrate" )
		  . " of statistics has not been allowed from a browser (AllowToUpdateStatsFromBrowser should be set to 1)."
	);
}
if ( scalar keys %HTMLOutput && $MonthRequired eq 'all' ) {
	if ( !$AllowFullYearView ) {
		error(
"Full year view has not been allowed (AllowFullYearView is set to 0)."
		);
	}
	if ( $AllowFullYearView < 3 && $ENV{'GATEWAY_INTERFACE'} ) {
		error(
"Full year view has not been allowed from a browser (AllowFullYearView should be set to 3)."
		);
	}
}
#------------------------------------------
# MIGRATE PROCESS (Must be after reading config cause we need MaxNbOf... and Min...)
#------------------------------------------
if ($MigrateStats) {
	if ($Debug) { debug( "MigrateStats is $MigrateStats", 2 ); }
	if ( $MigrateStats !~
		/^(.*)$PROG(\d\d)(\d\d\d\d)(\d{0,2})(\d{0,2})(.*)\.txt$/ )
	{
		error(
"AWStats history file name must match following syntax: ${PROG}MMYYYY[.config].txt",
			"", "", 1
		);
	}
	$DirData       = "$1";
	$MonthRequired = "$2";
	$YearRequired  = "$3";
	$DayRequired   = "$4";
	$HourRequired  = "$5";
	$FileSuffix    = "$6";
	# Correct DirData
	if ( !$DirData || $DirData =~ /^\./ ) {
		if ( !$DirData || $DirData eq '.' ) {
			$DirData = "$DIR";
		}    # If not defined or chosen to '.' value then DirData is current dir
		elsif ( $DIR && $DIR ne '.' ) { $DirData = "$DIR/$DirData"; }
	}
	$DirData ||= '.';    # If current dir not defined then we put it to '.'
	$DirData =~ s/[\\\/]+$//;
	print "Start migration for file '$MigrateStats'.";
	print $ENV{'GATEWAY_INTERFACE'} ? "
\n" : "\n";
	if ($EnableLockForUpdate) { &Lock_Update(1); }
	my $newhistory =
	  &Read_History_With_TmpUpdate( $YearRequired, $MonthRequired, $DayRequired,
		$HourRequired, 1, 0, 'all' );
	if ( rename( "$newhistory", "$MigrateStats" ) == 0 ) {
		unlink "$newhistory";
		error(
"Failed to rename \"$newhistory\" into \"$MigrateStats\".\nWrite permissions on \"$MigrateStats\" might be wrong"
			  . (
				$ENV{'GATEWAY_INTERFACE'} ? " for a 'migration from web'" : ""
			  )
			  . " or file might be opened."
		);
	}
	if ($EnableLockForUpdate) { &Lock_Update(0); }
	print "Migration for file '$MigrateStats' successful.";
	print $ENV{'GATEWAY_INTERFACE'} ? "
\n" : "\n";
	&html_end(1);
	exit 0;
}
# Output main frame page and exit. This must be after the security check.
if ( $FrameName eq 'index' ) {
	# Define the NewLinkParams for main chart
	my $NewLinkParams = ${QueryString};
	$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
	$NewLinkParams =~ s/(&|&)+/&/i;
	$NewLinkParams =~ s/^&//;
	$NewLinkParams =~ s/&$//;
	if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
	# Exit if main frame
	print "\n";
	&html_end(0);
	exit 0;
}
%MonthNumLib = (
	"01", "$Message[60]", "02", "$Message[61]", "03", "$Message[62]",
	"04", "$Message[63]", "05", "$Message[64]", "06", "$Message[65]",
	"07", "$Message[66]", "08", "$Message[67]", "09", "$Message[68]",
	"10", "$Message[69]", "11", "$Message[70]", "12", "$Message[71]"
);
# Build ListOfYears list with all existing years
(
	$lastyearbeforeupdate, $lastmonthbeforeupdate, $lastdaybeforeupdate,
	$lasthourbeforeupdate, $lastdatebeforeupdate
  )
  = ( 0, 0, 0, 0, 0 );
my $datemask = '';
if    ( $DatabaseBreak eq 'month' ) { $datemask = '(\d\d)(\d\d\d\d)'; }
elsif ( $DatabaseBreak eq 'year' )  { $datemask = '(\d\d\d\d)'; }
elsif ( $DatabaseBreak eq 'day' )   { $datemask = '(\d\d)(\d\d\d\d)(\d\d)'; }
elsif ( $DatabaseBreak eq 'hour' )  {
	$datemask = '(\d\d)(\d\d\d\d)(\d\d)(\d\d)';
}
if ($Debug) {
	debug(
"Scan for last history files into DirData='$DirData' with mask='$datemask'"
	);
}
my $retval = opendir( DIR, "$DirData" );
if(! $retval) 
{
    error( "Failed to open directory $DirData : $!");
}
my $regfilesuffix = quotemeta($FileSuffix);
foreach ( grep /^$PROG$datemask$regfilesuffix\.txt(|\.gz)$/i,
	file_filt sort readdir DIR )
{
	/^$PROG$datemask$regfilesuffix\.txt(|\.gz)$/i;
	if ( !$ListOfYears{"$2"} || "$1" gt $ListOfYears{"$2"} ) {
		# ListOfYears contains max month found
		$ListOfYears{"$2"} = "$1";
	}
	my $rangestring = ( $2 || "" ) . ( $1 || "" ) . ( $3 || "" ) . ( $4 || "" );
	if ( $rangestring gt $lastdatebeforeupdate ) {
		# We are on a new max for mask
		$lastyearbeforeupdate  = ( $2 || "" );
		$lastmonthbeforeupdate = ( $1 || "" );
		$lastdaybeforeupdate   = ( $3 || "" );
		$lasthourbeforeupdate  = ( $4 || "" );
		$lastdatebeforeupdate = $rangestring;
	}
}
close DIR;
# If at least one file found, get value for LastLine
if ($lastyearbeforeupdate) {
	# Read 'general' section of last history file for LastLine
	&Read_History_With_TmpUpdate( $lastyearbeforeupdate, $lastmonthbeforeupdate,
		$lastdaybeforeupdate, $lasthourbeforeupdate, 0, 0, "general" );
}
# Warning if lastline in future
if ( $LastLine > ( $nowtime + 20000 ) ) {
	warning(
"WARNING: LastLine parameter in history file is '$LastLine' so in future. May be you need to correct manually the line LastLine in some awstats*.$SiteConfig.conf files."
	);
}
# Force LastLine
if ( $QueryString =~ /lastline=(\d{14})/i ) {
	$LastLine = $1;
}
if ($Debug) {
	debug("Last year=$lastyearbeforeupdate - Last month=$lastmonthbeforeupdate");
	debug("Last day=$lastdaybeforeupdate - Last hour=$lasthourbeforeupdate");
	debug("LastLine=$LastLine");
	debug("LastLineNumber=$LastLineNumber");
	debug("LastLineOffset=$LastLineOffset");
	debug("LastLineChecksum=$LastLineChecksum");
}
# Init vars
&Init_HashArray();
#------------------------------------------
# UPDATE PROCESS
#------------------------------------------
my $lastlinenb         = 0;
my $lastlineoffset     = 0;
my $lastlineoffsetnext = 0;
if ($Debug) { debug( "UpdateStats is $UpdateStats", 2 ); }
if ( $UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft' )
{    # Update only on index page or when not framed to avoid update twice
	my %MonthNum = (
		"Jan", "01", "jan", "01", "Feb", "02", "feb", "02", "Mar", "03",
		"mar", "03", "Apr", "04", "apr", "04", "May", "05", "may", "05",
		"Jun", "06", "jun", "06", "Jul", "07", "jul", "07", "Aug", "08",
		"aug", "08", "Sep", "09", "sep", "09", "Oct", "10", "oct", "10",
		"Nov", "11", "nov", "11", "Dec", "12", "dec", "12"
	  )
	  ; # MonthNum must be in english because used to translate log date in apache log files
	if ( !scalar keys %HTMLOutput ) {
		print
"Create/Update database for config \"$FileConfig\" by AWStats version $VERSION\n";
		print "From data in log file \"$LogFile\"...\n";
	}
	my $lastprocessedyear  = $lastyearbeforeupdate  || 0;
	my $lastprocessedmonth = $lastmonthbeforeupdate || 0;
	my $lastprocessedday   = $lastdaybeforeupdate   || 0;
	my $lastprocessedhour  = $lasthourbeforeupdate  || 0;
	my $lastprocesseddate  = '';
	if ( $DatabaseBreak eq 'month' ) {
		$lastprocesseddate =
		  sprintf( "%04i%02i", $lastprocessedyear, $lastprocessedmonth );
	}
	elsif ( $DatabaseBreak eq 'year' ) {
		$lastprocesseddate = sprintf( "%04i%", $lastprocessedyear );
	}
	elsif ( $DatabaseBreak eq 'day' ) {
		$lastprocesseddate = sprintf( "%04i%02i%02i",
			$lastprocessedyear, $lastprocessedmonth, $lastprocessedday );
	}
	elsif ( $DatabaseBreak eq 'hour' ) {
		$lastprocesseddate = sprintf(
			"%04i%02i%02i%02i",
			$lastprocessedyear, $lastprocessedmonth,
			$lastprocessedday,  $lastprocessedhour
		);
	}
	my @list;
	# Init RobotsSearchIDOrder required for update process
	@list = ();
	if ( $LevelForRobotsDetection >= 1 ) {
		foreach ( 1 .. $LevelForRobotsDetection ) { push @list, "list$_"; }
		push @list, "listgen";    # Always added
	}
	foreach my $key (@list) {
		push @RobotsSearchIDOrder, @{"RobotsSearchIDOrder_$key"};
		if ($Debug) {
			debug(
				"Add "
				  . @{"RobotsSearchIDOrder_$key"}
				  . " elements from RobotsSearchIDOrder_$key into RobotsSearchIDOrder",
				2
			);
		}
	}
	if ($Debug) {
		debug(
			"RobotsSearchIDOrder has now " . @RobotsSearchIDOrder . " elements",
			1
		);
	}
	# Init SearchEnginesIDOrder required for update process
	@list = ();
	if ( $LevelForSearchEnginesDetection >= 1 ) {
		foreach ( 1 .. $LevelForSearchEnginesDetection ) {
			push @list, "list$_";
		}
		push @list, "listgen";    # Always added
	}
	foreach my $key (@list) {
		push @SearchEnginesSearchIDOrder, @{"SearchEnginesSearchIDOrder_$key"};
		if ($Debug) {
			debug(
				"Add "
				  . @{"SearchEnginesSearchIDOrder_$key"}
				  . " elements from SearchEnginesSearchIDOrder_$key into SearchEnginesSearchIDOrder",
				2
			);
		}
	}
	if ($Debug) {
		debug(
			"SearchEnginesSearchIDOrder has now "
			  . @SearchEnginesSearchIDOrder
			  . " elements",
			1
		);
	}
	# Complete HostAliases array
	my $sitetoanalyze = quotemeta( lc($SiteDomain) );
	if ( !@HostAliases ) {
		warning(
"Warning: HostAliases parameter is not defined, $PROG choose \"$SiteDomain localhost 127.0.0.1\"."
		);
		push @HostAliases, qr/^$sitetoanalyze$/i;
		push @HostAliases, qr/^localhost$/i;
		push @HostAliases, qr/^127\.0\.0\.1$/i;
	}
	else {
		unshift @HostAliases, qr/^$sitetoanalyze$/i;
	}    # Add SiteDomain as first value
	# Optimize arrays
	@HostAliases = &OptimizeArray( \@HostAliases, 1 );
	if ($Debug) {
		debug( "HostAliases precompiled regex list is now @HostAliases", 1 );
	}
	@SkipDNSLookupFor = &OptimizeArray( \@SkipDNSLookupFor, 1 );
	if ($Debug) {
		debug(
			"SkipDNSLookupFor precompiled regex list is now @SkipDNSLookupFor",
			1
		);
	}
	@SkipHosts = &OptimizeArray( \@SkipHosts, 1 );
	if ($Debug) {
		debug( "SkipHosts precompiled regex list is now @SkipHosts", 1 );
	}
	@SkipReferrers = &OptimizeArray( \@SkipReferrers, 1 );
	if ($Debug) {
		debug( "SkipReferrers precompiled regex list is now @SkipReferrers",
			1 );
	}
	@SkipUserAgents = &OptimizeArray( \@SkipUserAgents, 1 );
	if ($Debug) {
		debug( "SkipUserAgents precompiled regex list is now @SkipUserAgents",
			1 );
	}
	@SkipFiles = &OptimizeArray( \@SkipFiles, $URLNotCaseSensitive );
	if ($Debug) {
		debug( "SkipFiles precompiled regex list is now @SkipFiles", 1 );
	}
	@OnlyHosts = &OptimizeArray( \@OnlyHosts, 1 );
	if ($Debug) {
		debug( "OnlyHosts precompiled regex list is now @OnlyHosts", 1 );
	}
	@OnlyUsers = &OptimizeArray( \@OnlyUsers, 1 );
	if ($Debug) {
		debug( "OnlyUsers precompiled regex list is now @OnlyUsers", 1 );
	}
	@OnlyUserAgents = &OptimizeArray( \@OnlyUserAgents, 1 );
	if ($Debug) {
		debug( "OnlyUserAgents precompiled regex list is now @OnlyUserAgents",
			1 );
	}
	@OnlyFiles = &OptimizeArray( \@OnlyFiles, $URLNotCaseSensitive );
	if ($Debug) {
		debug( "OnlyFiles precompiled regex list is now @OnlyFiles", 1 );
	}
	@NotPageFiles = &OptimizeArray( \@NotPageFiles, $URLNotCaseSensitive );
	if ($Debug) {
		debug( "NotPageFiles precompiled regex list is now @NotPageFiles", 1 );
	}
	# Precompile the regex search strings with qr
	@RobotsSearchIDOrder        = map { qr/$_/i } @RobotsSearchIDOrder;
	@WormsSearchIDOrder         = map { qr/$_/i } @WormsSearchIDOrder;
	@BrowsersSearchIDOrder      = map { qr/$_/i } @BrowsersSearchIDOrder;
	@OSSearchIDOrder            = map { qr/$_/i } @OSSearchIDOrder;
	@SearchEnginesSearchIDOrder = map { qr/$_/i } @SearchEnginesSearchIDOrder;
	my $miscquoted     = quotemeta("$MiscTrackerUrl");
	my $defquoted      = quotemeta("/$DefaultFile[0]");
	my $sitewithoutwww = lc($SiteDomain);
	$sitewithoutwww =~ s/www\.//;
	$sitewithoutwww = quotemeta($sitewithoutwww);
	# Define precompiled regex
	my $regmisc        = qr/^$miscquoted/;
	my $regfavico      = qr/\/favicon\.ico$/i;
	my $regrobot       = qr/\/robots\.txt$/i;
	my $regtruncanchor = qr/#(\w*)$/;
	my $regtruncurl    = qr/([$URLQuerySeparators])(.*)$/;
	my $regext         = qr/\.(\w{1,6})$/;
	my $regdefault;
	if ($URLNotCaseSensitive) { $regdefault = qr/$defquoted$/i; }
	else { $regdefault = qr/$defquoted$/; }
	my $regipv4           = qr/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
	my $regipv4l          = qr/^::ffff:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
	my $regipv6           = qr/^[0-9A-F]*:/i;
	my $regveredge        = qr/edge\/([\d]+)/i;
	my $regvermsie        = qr/msie([+_ ]|)([\d\.]*)/i;
	#my $regvermsie11      = qr/trident\/7\.\d*\;([+_ ]|)rv:([\d\.]*)/i;
	my $regvermsie11      = qr/trident\/7\.\d*\;([a-zA-Z;+_ ]+|)rv:([\d\.]*)/i;
	my $regvernetscape    = qr/netscape.?\/([\d\.]*)/i;
	my $regverfirefox     = qr/firefox\/([\d\.]*)/i;
	# For Opera:
	# OPR/15.0.1266 means Opera 15 
	# Opera/9.80 ...... Version/12.16 means Opera 12.16
	# Mozilla/5.0 .... Opera 11.51 means Opera 11.51
	my $regveropera = qr/opera\/9\.80\s.+\sversion\/([\d\.]+)|ope?ra?[\/\s]([\d\.]+)/i;
	my $regversafari      = qr/safari\/([\d\.]*)/i;
	my $regversafariver   = qr/version\/([\d\.]*)/i;
	my $regverchrome      = qr/chrome\/([\d\.]*)/i;
	my $regverkonqueror   = qr/konqueror\/([\d\.]*)/i;
	my $regversvn         = qr/svn\/([\d\.]*)/i;
	my $regvermozilla     = qr/mozilla(\/|)([\d\.]*)/i;
	my $regnotie          = qr/webtv|omniweb|opera/i;
	my $regnotnetscape    = qr/gecko|compatible|opera|galeon|safari|charon/i;
	my $regnotfirefox     = qr/flock/i;
	my $regnotsafari      = qr/android|arora|chrome|shiira/i;
	my $regreferer        = qr/^(\w+):\/\/([^\/:]+)(:\d+|)/;
	my $regreferernoquery = qr/^([^$URLQuerySeparators]+)/;
	my $reglocal          = qr/^(www\.|)$sitewithoutwww/i;
	my $regget            = qr/get|out/i;
	my $regsent           = qr/sent|put|in/i;
	# Define value of $pos_xxx, @fieldlib, $PerlParsingFormat
	&DefinePerlParsingFormat($LogFormat);
	# Load DNS Cache Files
	#------------------------------------------
	if ($DNSLookup) {
		&Read_DNS_Cache( \%MyDNSTable, "$DNSStaticCacheFile", "", 1 )
		  ; # Load with save into a second plugin file if plugin enabled and second file not up to date. No use of FileSuffix
		if ( $DNSLookup == 1 ) {    # System DNS lookup required
			 #if (! eval("use Socket;")) { error("Failed to load perl module Socket."); }
			 #use Socket;
			&Read_DNS_Cache( \%TmpDNSLookup, "$DNSLastUpdateCacheFile",
				"$FileSuffix", 0 )
			  ;    # Load with no save into a second plugin file. Use FileSuffix
		}
	}
	# Processing log
	#------------------------------------------
	if ($EnableLockForUpdate) {
		# Trap signals to remove lock
		$SIG{INT} = \&SigHandler;    # 2
		                             #$SIG{KILL} = \&SigHandler;	# 9
		                             #$SIG{TERM} = \&SigHandler;	# 15
		                             # Set AWStats update lock
		&Lock_Update(1);
	}
	if ($Debug) {
		debug("Start Update process (lastprocesseddate=$lastprocesseddate)");
	}
	# Open log file
	if ($Debug) { debug("Open log file \"$LogFile\""); }
	open( LOG, "$LogFile" )
	  || error("Couldn't open server log file \"$LogFile\" : $!");
	binmode LOG
	  ;   # Avoid premature EOF due to log files corrupted with \cZ or bin chars
	# Define local variables for loop scan
	my @field               = ();
	my $counterforflushtest = 0;
	my $qualifdrop          = '';
	my $countedtraffic      = 0;
	# Reset chrono for benchmark (first call to GetDelaySinceStart)
	&GetDelaySinceStart(1);
	if ( !scalar keys %HTMLOutput ) {
		print "Phase 1 : First bypass old records, searching new record...\n";
	}
	# Can we try a direct seek access in log ?
	my $line;
	if ( $LastLine && $LastLineNumber && $LastLineOffset && $LastLineChecksum )
	{
		# Try a direct seek access to save time
		if ($Debug) {
			debug(
"Try a direct access to LastLine=$LastLine, LastLineNumber=$LastLineNumber, LastLineOffset=$LastLineOffset, LastLineChecksum=$LastLineChecksum"
			);
		}
		seek( LOG, $LastLineOffset, 0 );
		if ( $line =  ) {
			chomp $line;
			$line =~ s/\r$//;
			@field = map( /$PerlParsingFormat/, $line );
			if ($Debug) {
				my $string = '';
				foreach ( 0 .. @field - 1 ) {
					$string .= "$fieldlib[$_]=$field[$_] ";
				}
				if ($Debug) {
					debug( " Read line after direct access: $string", 1 );
				}
			}
			my $checksum = &CheckSum($line);
			if ($Debug) {
				debug(
" LastLineChecksum=$LastLineChecksum, Read line checksum=$checksum",
					1
				);
			}
			if ( $checksum == $LastLineChecksum ) {
				if ( !scalar keys %HTMLOutput ) {
					print
"Direct access after last parsed record (after line $LastLineNumber)\n";
				}
				$lastlinenb         = $LastLineNumber;
				$lastlineoffset     = $LastLineOffset;
				$lastlineoffsetnext = tell LOG;
				$NewLinePhase       = 1;
			}
			else {
				if ( !scalar keys %HTMLOutput ) {
					print
"Direct access to last remembered record has fallen on another record.\nSo searching new records from beginning of log file...\n";
				}
				$lastlinenb         = 0;
				$lastlineoffset     = 0;
				$lastlineoffsetnext = 0;
				seek( LOG, 0, 0 );
			}
		}
		else {
			if ( !scalar keys %HTMLOutput ) {
				print
"Direct access to last remembered record is out of file.\nSo searching it from beginning of log file...\n";
			}
			$lastlinenb         = 0;
			$lastlineoffset     = 0;
			$lastlineoffsetnext = 0;
			seek( LOG, 0, 0 );
		}
	}
	else {
		# No try of direct seek access
		if ( !scalar keys %HTMLOutput ) {
			print "Searching new records from beginning of log file...\n";
		}
		$lastlinenb         = 0;
		$lastlineoffset     = 0;
		$lastlineoffsetnext = 0;
	}
	#
	# Loop on each log line
	#
	while ( $line =  ) {
		
		# 20080525 BEGIN Patch to test if first char of $line = hex "00" then conclude corrupted with binary code
		my $FirstHexChar;
		$FirstHexChar = sprintf( "%02X", ord( substr( $line, 0, 1 ) ) );
		if ( $FirstHexChar eq '00' ) {
			$NbOfLinesCorrupted++;
			if ($ShowCorrupted) {
				print "Corrupted record line "
				  . ( $lastlinenb + $NbOfLinesParsed )
				  . " (record starts with hex 00; binary code): $line\n";
			}
			if (   $NbOfLinesParsed >= $NbOfLinesForCorruptedLog
				&& $NbOfLinesParsed == $NbOfLinesCorrupted )
			{
				error( "Format error", $line, $LogFile );
			}    # Exit with format error
			next;
		}
		# 20080525 END
		chomp $line;
		$line =~ s/\r$//;
		if ( $UpdateFor && $NbOfLinesParsed >= $UpdateFor ) { last; }
		$NbOfLinesParsed++;
		$lastlineoffset     = $lastlineoffsetnext;
		$lastlineoffsetnext = tell LOG;
		if ($ShowSteps) {
			if ( ( ++$NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK ) == 0 ) {
				my $delay = &GetDelaySinceStart(0);
				print "$NbOfLinesParsed lines processed ("
				  . ( $delay > 0 ? $delay : 1000 ) . " ms, "
				  . int(
					1000 * $NbOfLinesShowsteps / ( $delay > 0 ? $delay : 1000 )
				  )
				  . " lines/second)\n";
			}
		}
		if ( $LogFormat eq '2' && $line =~ /^#Fields:/ ) {
			my @fixField = map( /^#Fields: (.*)/, $line );
			if ( $fixField[0] !~ /s-kernel-time/ ) {
				debug( "Found new log format: '" . $fixField[0] . "'", 1 );
				&DefinePerlParsingFormat( $fixField[0] );
			}
		}
		# Parse line record to get all required fields
		if ( !( @field = map( /$PerlParsingFormat/, $line ) ) ) {
			# see if the line is a comment, blank or corrupted
 			if ( $line =~ /^#/ || $line =~ /^!/ ) {
				$NbOfLinesComment++;
				if ($ShowCorrupted){
					print "Comment record line "
					  . ( $lastlinenb + $NbOfLinesParsed )
					  . ": $line\n";
				}
 			}
 			elsif ( $line =~ /^\s*$/ ) {
 				$NbOfLinesBlank++;
				if ($ShowCorrupted){
					print "Blank record line "
					  . ( $lastlinenb + $NbOfLinesParsed )
					  . "\n";
				}
 			}else{
 				$NbOfLinesCorrupted++;
 				if ($ShowCorrupted){
 				print "Corrupted record line "
  					  . ( $lastlinenb + $NbOfLinesParsed )
  					  . " (record format does not match LogFormat parameter): $line\n";
  				}
			}
			if (   $NbOfLinesParsed >= $NbOfLinesForCorruptedLog
				&& $NbOfLinesParsed == ($NbOfLinesCorrupted + $NbOfLinesComment + $NbOfLinesBlank))
			{
				error( "Format error", $line, $LogFile );
			}    # Exit with format error
			if ( $line =~ /^__end_of_file__/i ) { last; } # For test purpose only
			next;
		}
		if ($Debug) {
			my $string = '';
			foreach ( 0 .. @field - 1 ) {
				$string .= "$fieldlib[$_]=$field[$_] ";
			}
			if ($Debug) {
				debug(
					" Correct format line "
					  . ( $lastlinenb + $NbOfLinesParsed )
					  . ": $string",
					4
				);
			}
		}
		# Drop wrong virtual host name
		#----------------------------------------------------------------------
		if ( $pos_vh >= 0 && $field[$pos_vh] !~ /^$SiteDomain$/i ) {
			my $skip = 1;
			foreach (@HostAliases) {
				if ( $field[$pos_vh] =~ /$_/ ) { $skip = 0; last; }
			}
			if ($skip) {
				$NbOfLinesDropped++;
				if ($ShowDropped) {
					print
"Dropped record (virtual hostname '$field[$pos_vh]' does not match SiteDomain='$SiteDomain' nor HostAliases parameters): $line\n";
				}
				next;
			}
		}
		# Drop wrong method/protocol
		#---------------------------
		if ( $LogType ne 'M' ) { $field[$pos_url] =~ s/\s/%20/g; }
		if (
			$LogType eq 'W'
			&& (
				   $field[$pos_method] eq 'GET'
				|| $field[$pos_method] eq 'POST'
				|| $field[$pos_method] eq 'HEAD'
				|| $field[$pos_method] eq 'PROPFIND'
				|| $field[$pos_method] eq 'CHECKOUT'
				|| $field[$pos_method] eq 'LOCK'
				|| $field[$pos_method] eq 'PROPPATCH'
				|| $field[$pos_method] eq 'OPTIONS'
				|| $field[$pos_method] eq 'MKACTIVITY'
				|| $field[$pos_method] eq 'PUT'
				|| $field[$pos_method] eq 'MERGE'
				|| $field[$pos_method] eq 'DELETE'
				|| $field[$pos_method] eq 'REPORT'
				|| $field[$pos_method] eq 'MKCOL'
				|| $field[$pos_method] eq 'COPY'
				|| $field[$pos_method] eq 'RPC_IN_DATA'
				|| $field[$pos_method] eq 'RPC_OUT_DATA'
				|| $field[$pos_method] eq 'OK'             # Webstar
				|| $field[$pos_method] eq 'ERR!'           # Webstar
				|| $field[$pos_method] eq 'PRIV'           # Webstar
			)
		  )
		{
# HTTP request.	Keep only GET, POST, HEAD, *OK* and ERR! for Webstar. Do not keep OPTIONS, TRACE
		}
		elsif (
			( $LogType eq 'W' || $LogType eq 'S' )
			&& (   uc($field[$pos_method]) eq 'GET'
				|| uc($field[$pos_method]) eq 'MMS'
				|| uc($field[$pos_method]) eq 'RTSP'
				|| uc($field[$pos_method]) eq 'HTTP'
				|| uc($field[$pos_method]) eq 'RTP' )
		  )
		{
# Streaming request (windows media server, realmedia or darwin streaming server)
		}
		elsif ( $LogType eq 'M' && $field[$pos_method] eq 'SMTP' ) {
		# Mail request ('SMTP' for mail log with maillogconvert.pl preprocessor)
		}
		elsif (
			$LogType eq 'F'
			&& (   $field[$pos_method] eq 'RETR'
				|| $field[$pos_method] eq 'D'
				|| $field[$pos_method] eq 'o'
				|| $field[$pos_method] =~ /$regget/o )
		  )
		{
			# FTP GET request
		}
		elsif (
			$LogType eq 'F'
			&& (   $field[$pos_method] eq 'STOR'
				|| $field[$pos_method] eq 'U'
				|| $field[$pos_method] eq 'i'
				|| $field[$pos_method] =~ /$regsent/o )
		  )
		{
			# FTP SENT request
		}
		elsif($line =~ m/#Fields:/){
 			# log #fields as comment
 			$NbOfLinesComment++;
 			next;			
 		}else{
			$NbOfLinesDropped++;
			if ($ShowDropped) {
				print
"Dropped record (method/protocol '$field[$pos_method]' not qualified when LogType=$LogType): $line\n";
			}
			next;
		}
		# Reformat date for IIS date -DWG 12/8/2008
		if($field[$pos_date] =~ /,/)
		{
			$field[$pos_date] =~ s/,//;
			my @split_date = split(' ',$field[$pos_date]);
			my @dateparts2= split('/',$split_date[0]);
			my @timeparts2= split(':',$split_date[1]);
			#add leading zero
			for($dateparts2[0],$dateparts2[1], $timeparts2[0], $timeparts2[1],  $timeparts2[2])			{
				if($_ =~ /^.$/)
				{
					$_ = '0'.$_;
				}
			}
			$field[$pos_date] = "$dateparts2[2]-$dateparts2[0]-$dateparts2[1] $timeparts2[0]:$timeparts2[1]:$timeparts2[2]";
		}
		
		$field[$pos_date] =~
		  tr/,-\/ \tT/::::::/s;  # " \t" is used instead of "\s" not known with tr
		my @dateparts =
		  split( /:/, $field[$pos_date] ); # tr and split faster than @dateparts=split(/[\/\-:\s]/,$field[$pos_date])
		 # Detected date format: 
		 # dddddddddd, YYYY-MM-DD HH:MM:SS (IIS), MM/DD/YY\tHH:MM:SS,
		 # DD/Month/YYYY:HH:MM:SS (Apache), DD/MM/YYYY HH:MM:SS, Mon DD HH:MM:SS,
		 # YYYY-MM-DDTHH:MM:SS (iso)
		if ( !$dateparts[1] ) {    # Unix timestamp
			(
				$dateparts[5], $dateparts[4], $dateparts[3],
				$dateparts[0], $dateparts[1], $dateparts[2]
			  )
			  = localtime( int( $field[$pos_date] ) );
			$dateparts[1]++;
			$dateparts[2] += 1900;
		}
		elsif ( $dateparts[0] =~ /^....$/ ) {
			my $tmp = $dateparts[0];
			$dateparts[0] = $dateparts[2];
			$dateparts[2] = $tmp;
		}
		elsif ( $field[$pos_date] =~ /^..:..:..:/ ) {
			$dateparts[2] += 2000;
			my $tmp = $dateparts[0];
			$dateparts[0] = $dateparts[1];
			$dateparts[1] = $tmp;
		}
		elsif ( $dateparts[0] =~ /^...$/ ) {
			my $tmp = $dateparts[0];
			$dateparts[0] = $dateparts[1];
			$dateparts[1] = $tmp;
			$tmp          = $dateparts[5];
			$dateparts[5] = $dateparts[4];
			$dateparts[4] = $dateparts[3];
			$dateparts[3] = $dateparts[2];
			$dateparts[2] = $tmp || $nowyear;
		}
		if ( exists( $MonthNum{ $dateparts[1] } ) ) {
			$dateparts[1] = $MonthNum{ $dateparts[1] };
		}    # Change lib month in num month if necessary
		if ( $dateparts[1] <= 0 )
		{ # Date corrupted (for example $dateparts[1]='dic' for december month in a spanish log file)
			$NbOfLinesCorrupted++;
			if ($ShowCorrupted) {
				print "Corrupted record line "
				  . ( $lastlinenb + $NbOfLinesParsed )
				  . " (bad date format for month, may be month are not in english ?): $line\n";
			}
			next;
		}
# Now @dateparts is (DD,MM,YYYY,HH,MM,SS) and we're going to create $timerecord=YYYYMMDDHHMMSS
		if ( $PluginsLoaded{'ChangeTime'}{'timezone'} ) {
			@dateparts = ChangeTime_timezone( \@dateparts );
		}
		my $yearrecord  = int( $dateparts[2] );
		my $monthrecord = int( $dateparts[1] );
		my $dayrecord   = int( $dateparts[0] );
		my $hourrecord  = int( $dateparts[3] );
		my $daterecord  = '';
		if ( $DatabaseBreak eq 'month' ) {
			$daterecord = sprintf( "%04i%02i", $yearrecord, $monthrecord );
		}
		elsif ( $DatabaseBreak eq 'year' ) {
			$daterecord = sprintf( "%04i%", $yearrecord );
		}
		elsif ( $DatabaseBreak eq 'day' ) {
			$daterecord =
			  sprintf( "%04i%02i%02i", $yearrecord, $monthrecord, $dayrecord );
		}
		elsif ( $DatabaseBreak eq 'hour' ) {
			$daterecord = sprintf( "%04i%02i%02i%02i",
				$yearrecord, $monthrecord, $dayrecord, $hourrecord );
		}
		# TODO essayer de virer yearmonthrecord
		my $yearmonthdayrecord =
		  sprintf( "$dateparts[2]%02i%02i", $dateparts[1], $dateparts[0] );
		my $timerecord =
		  ( ( int("$yearmonthdayrecord") * 100 + $dateparts[3] ) * 100 +
			  $dateparts[4] ) * 100 + $dateparts[5];
		# Check date
		#-----------------------
		if ( $LogType eq 'M' && $timerecord > $tomorrowtime ) {
# Postfix/Sendmail does not store year, so we assume that year is year-1 if record is in future
			$yearrecord--;
			if ( $DatabaseBreak eq 'month' ) {
				$daterecord = sprintf( "%04i%02i", $yearrecord, $monthrecord );
			}
			elsif ( $DatabaseBreak eq 'year' ) {
				$daterecord = sprintf( "%04i%", $yearrecord );
			}
			elsif ( $DatabaseBreak eq 'day' ) {
				$daterecord = sprintf( "%04i%02i%02i",
					$yearrecord, $monthrecord, $dayrecord );
			}
			elsif ( $DatabaseBreak eq 'hour' ) {
				$daterecord = sprintf( "%04i%02i%02i%02i",
					$yearrecord, $monthrecord, $dayrecord, $hourrecord );
			}
			# TODO essayer de virer yearmonthrecord
			$yearmonthdayrecord =
			  sprintf( "$yearrecord%02i%02i", $dateparts[1], $dateparts[0] );
			$timerecord =
			  ( ( int("$yearmonthdayrecord") * 100 + $dateparts[3] ) * 100 +
				  $dateparts[4] ) * 100 + $dateparts[5];
		}
		if ( $timerecord < 10000000000000 || $timerecord > $tomorrowtime ) {
			$NbOfLinesCorrupted++;
			if ($ShowCorrupted) {
				print
"Corrupted record (invalid date, timerecord=$timerecord): $line\n";
			}
			next;   # Should not happen, kept in case of parasite/corrupted line
		}
		if ($NewLinePhase) {
			# TODO NOTSORTEDRECORDTOLERANCE does not work around midnight
			if ( $timerecord < ( $LastLine - $NOTSORTEDRECORDTOLERANCE ) ) {
				# Should not happen, kept in case of parasite/corrupted old line
				$NbOfLinesCorrupted++;
				if ($ShowCorrupted) {
					print
"Corrupted record (date $timerecord lower than $LastLine-$NOTSORTEDRECORDTOLERANCE): $line\n";
				}
				next;
			}
		}
		else {
			if ( $timerecord <= $LastLine ) {    # Already processed
				$NbOfOldLines++;
				next;
			}
# We found a new line. This will replace comparison "<=" with "<" between timerecord and LastLine (we should have only new lines now)
			$NewLinePhase = 1;    # We will never enter here again
			if ($ShowSteps) {
				if ( $NbOfLinesShowsteps > 1
					&& ( $NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK ) )
				{
					my $delay = &GetDelaySinceStart(0);
					print ""
					  . ( $NbOfLinesParsed - 1 )
					  . " lines processed ("
					  . ( $delay > 0 ? $delay : 1000 ) . " ms, "
					  . int( 1000 * ( $NbOfLinesShowsteps - 1 ) /
						  ( $delay > 0 ? $delay : 1000 ) )
					  . " lines/second)\n";
				}
				&GetDelaySinceStart(1);
				$NbOfLinesShowsteps = 1;
			}
			if ( !scalar keys %HTMLOutput ) {
				print
"Phase 2 : Now process new records (Flush history on disk after "
				  . ( $LIMITFLUSH << 2 )
				  . " hosts)...\n";
#print "Phase 2 : Now process new records (Flush history on disk after ".($LIMITFLUSH<<2)." hosts or ".($LIMITFLUSH)." URLs)...\n";
			}
		}
		# Convert URL for Webstar to common URL
		if ( $LogFormat eq '3' ) {
			$field[$pos_url] =~ s/:/\//g;
			if ( $field[$pos_code] eq '-' ) { $field[$pos_code] = '200'; }
		}
# Here, field array, timerecord and yearmonthdayrecord are initialized for log record
		if ($Debug) {
			debug( "  This is a not already processed record ($timerecord)",
				4 );
		}
		# Check if there's a CloudFlare Visitor IP in the query string
		# If it does, replace the ip
		if ( $pos_query >= 0 && $field[$pos_query] && $field[$pos_query] =~ /\[CloudFlare_Visitor_IP[:](\d+[.]\d+[.]\d+[.]\d+)\]/ ) {
			$field[$pos_host] = "$1";
		}	
		# We found a new line
		#----------------------------------------
		if ( $timerecord > $LastLine ) {
			$LastLine = $timerecord;
		}    # Test should always be true except with not sorted log files
		# Skip for some client host IP addresses, some URLs, other URLs
		if (
			@SkipHosts
			&& ( &SkipHost( $field[$pos_host] )
				|| ( $pos_hostr && &SkipHost( $field[$pos_hostr] ) ) )
		  )
		{
			$qualifdrop =
			    "Dropped record (host $field[$pos_host]"
			  . ( $pos_hostr ? " and $field[$pos_hostr]" : "" )
			  . " not qualified by SkipHosts)";
		}
		elsif ( @SkipFiles && &SkipFile( $field[$pos_url] ) ) {
			$qualifdrop =
"Dropped record (URL $field[$pos_url] not qualified by SkipFiles)";
		}
		elsif (@SkipUserAgents
			&& $pos_agent >= 0
			&& &SkipUserAgent( $field[$pos_agent] ) )
		{
			$qualifdrop =
"Dropped record (user agent '$field[$pos_agent]' not qualified by SkipUserAgents)";
		}
		elsif (@SkipReferrers
			&& $pos_referer >= 0
			&& &SkipReferrer( $field[$pos_referer] ) )
		{
			$qualifdrop =
"Dropped record (URL $field[$pos_referer] not qualified by SkipReferrers)";
		}
		elsif (@OnlyHosts
			&& !&OnlyHost( $field[$pos_host] )
			&& ( !$pos_hostr || !&OnlyHost( $field[$pos_hostr] ) ) )
		{
			$qualifdrop =
			    "Dropped record (host $field[$pos_host]"
			  . ( $pos_hostr ? " and $field[$pos_hostr]" : "" )
			  . " not qualified by OnlyHosts)";
		}
		elsif ( @OnlyUsers && !&OnlyUser( $field[$pos_logname] ) ) {
			$qualifdrop =
"Dropped record (URL $field[$pos_logname] not qualified by OnlyUsers)";
		}
		elsif ( @OnlyFiles && !&OnlyFile( $field[$pos_url] ) ) {
			$qualifdrop =
"Dropped record (URL $field[$pos_url] not qualified by OnlyFiles)";
		}
		elsif ( @OnlyUserAgents && !&OnlyUserAgent( $field[$pos_agent] ) ) {
			$qualifdrop =
"Dropped record (user agent '$field[$pos_agent]' not qualified by OnlyUserAgents)";
		}
		if ($qualifdrop) {
			$NbOfLinesDropped++;
			if ($Debug) { debug( "$qualifdrop: $line", 4 ); }
			if ($ShowDropped) { print "$qualifdrop: $line\n"; }
			$qualifdrop = '';
			next;
		}
		# Record is approved
		#-------------------
		# Is it in a new break section ?
		#-------------------------------
		if ( $daterecord > $lastprocesseddate ) {
			# A new break to process
			if ( $lastprocesseddate > 0 ) {
				# We save data of previous break
				&Read_History_With_TmpUpdate(
					$lastprocessedyear, $lastprocessedmonth,
					$lastprocessedday,  $lastprocessedhour,
					1,                  1,
					"all", ( $lastlinenb + $NbOfLinesParsed ),
					$lastlineoffset, &CheckSum($line)
				);
				$counterforflushtest = 0;    # We reset counterforflushtest
			}
			$lastprocessedyear  = $yearrecord;
			$lastprocessedmonth = $monthrecord;
			$lastprocessedday   = $dayrecord;
			$lastprocessedhour  = $hourrecord;
			if ( $DatabaseBreak eq 'month' ) {
				$lastprocesseddate =
				  sprintf( "%04i%02i", $yearrecord, $monthrecord );
			}
			elsif ( $DatabaseBreak eq 'year' ) {
				$lastprocesseddate = sprintf( "%04i%", $yearrecord );
			}
			elsif ( $DatabaseBreak eq 'day' ) {
				$lastprocesseddate = sprintf( "%04i%02i%02i",
					$yearrecord, $monthrecord, $dayrecord );
			}
			elsif ( $DatabaseBreak eq 'hour' ) {
				$lastprocesseddate = sprintf( "%04i%02i%02i%02i",
					$yearrecord, $monthrecord, $dayrecord, $hourrecord );
			}
		}
		$countedtraffic = 0;
		$NbOfNewLines++;
		# Convert $field[$pos_size]
		# if ($field[$pos_size] eq '-') { $field[$pos_size]=0; }
	# Define a clean target URL and referrer URL
	# We keep a clean $field[$pos_url] and
	# we store original value for urlwithnoquery, tokenquery and standalonequery
	#---------------------------------------------------------------------------
		# Decode "unreserved characters" - URIs with common ASCII characters
		# percent-encoded are equivalent to their unencoded versions.
		#
		# See section 2.3. of RFC 3986.
		$field[$pos_url] = DecodeRFC3986UnreservedString($field[$pos_url]);
		if ($URLNotCaseSensitive) { $field[$pos_url] = lc( $field[$pos_url] ); }
# Possible URL syntax for $field[$pos_url]: /mydir/mypage.ext?param1=x¶m2=y#aaa, /mydir/mypage.ext#aaa, /
		my $urlwithnoquery;
		my $tokenquery;
		my $standalonequery;
		my $anchor = '';
		if ( $field[$pos_url] =~ s/$regtruncanchor//o ) {
			$anchor = $1;
		}    # Remove and save anchor
		if ($URLWithQuery) {
			$urlwithnoquery = $field[$pos_url];
			my $foundparam = ( $urlwithnoquery =~ s/$regtruncurl//o );
			$tokenquery      = $1 || '';
			$standalonequery = $2 || '';
# For IIS setup, if pos_query is enabled we need to combine the URL to query strings
			if (   !$foundparam
				&& $pos_query >= 0
				&& $field[$pos_query]
				&& $field[$pos_query] ne '-' )
			{
				$foundparam      = 1;
				$tokenquery      = '?';
				$standalonequery = $field[$pos_query];
				# Define query
				$field[$pos_url] .= '?' . $field[$pos_query];
			}
			if ($foundparam) {
  # Keep only params that are defined in URLWithQueryWithOnlyFollowingParameters
				my $newstandalonequery = '';
				if (@URLWithQueryWithOnly) {
					foreach (@URLWithQueryWithOnly) {
						foreach my $p ( split( /&/, $standalonequery ) ) {
							if ($URLNotCaseSensitive) {
								if ( $p =~ /^$_=/i ) {
									$newstandalonequery .= "$p&";
									last;
								}
							}
							else {
								if ( $p =~ /^$_=/ ) {
									$newstandalonequery .= "$p&";
									last;
								}
							}
						}
					}
					chop $newstandalonequery;
				}
# Remove params that are marked to be ignored in URLWithQueryWithoutFollowingParameters
				elsif (@URLWithQueryWithout) {
					foreach my $p ( split( /&/, $standalonequery ) ) {
						my $found = 0;
						foreach (@URLWithQueryWithout) {
#if ($Debug) { debug("  Check if '$_=' is param '$p' to remove it from query",5); }
							if ($URLNotCaseSensitive) {
								if ( $p =~ /^$_=/i ) { $found = 1; last; }
							}
							else {
								if ( $p =~ /^$_=/ ) { $found = 1; last; }
							}
						}
						if ( !$found ) { $newstandalonequery .= "$p&"; }
					}
					chop $newstandalonequery;
				}
				else { $newstandalonequery = $standalonequery; }
				# Define query
				$field[$pos_url] = $urlwithnoquery;
				if ($newstandalonequery) {
					$field[$pos_url] .= "$tokenquery$newstandalonequery";
				}
			}
		}
		else {
			# Trunc parameters of URL
			$field[$pos_url] =~ s/$regtruncurl//o;
			$urlwithnoquery  = $field[$pos_url];
			$tokenquery      = $1 || '';
			$standalonequery = $2 || '';
	# For IIS setup, if pos_query is enabled we need to use it for query strings
			if (   $pos_query >= 0
				&& $field[$pos_query]
				&& $field[$pos_query] ne '-' )
			{
				$tokenquery      = '?';
				$standalonequery = $field[$pos_query];
			}
		}
		if ( $URLWithAnchor && $anchor ) {
			$field[$pos_url] .= "#$anchor";
		}   # Restore anchor
		    # Here now urlwithnoquery is /mydir/mypage.ext, /mydir, /, /page#XXX
		    # Here now tokenquery is '' or '?' or ';'
		    # Here now standalonequery is '' or 'param1=x'
		# Define page and extension
		#--------------------------
		my $PageBool = 1;
		# Extension
		my $extension = Get_Extension($regext, $urlwithnoquery);
		if ( $NotPageList{$extension} || 
		($MimeHashLib{$extension}[1]) && $MimeHashLib{$extension}[1] ne 'p') { $PageBool = 0;}
		if ( @NotPageFiles && &NotPageFile( $field[$pos_url] ) ) { $PageBool = 0; }
		# Analyze: misc tracker (must be before return code)
		#---------------------------------------------------
		if ( $urlwithnoquery =~ /$regmisc/o ) {
			if ($Debug) {
				debug(
"  Found an URL that is a MiscTracker record with standalonequery=$standalonequery",
					2
				);
			}
			my $foundparam = 0;
			foreach ( split( /&/, $standalonequery ) ) {
				if ( $_ =~ /^screen=(\d+)x(\d+)/i ) {
					$foundparam++;
					$_screensize_h{"$1x$2"}++;
					next;
				}
   #if ($_ =~ /cdi=(\d+)/i) 			{ $foundparam++; $_screendepth_h{"$1"}++; next; }
				if ( $_ =~ /^nojs=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"JavascriptDisabled"}++; }
					next;
				}
				if ( $_ =~ /^java=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'true' ) { $_misc_h{"JavaEnabled"}++; }
					next;
				}
				if ( $_ =~ /^shk=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"DirectorSupport"}++; }
					next;
				}
				if ( $_ =~ /^fla=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"FlashSupport"}++; }
					next;
				}
				if ( $_ =~ /^rp=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"RealPlayerSupport"}++; }
					next;
				}
				if ( $_ =~ /^mov=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"QuickTimeSupport"}++; }
					next;
				}
				if ( $_ =~ /^wma=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) {
						$_misc_h{"WindowsMediaPlayerSupport"}++;
					}
					next;
				}
				if ( $_ =~ /^pdf=(\w+)/i ) {
					$foundparam++;
					if ( $1 eq 'y' ) { $_misc_h{"PDFSupport"}++; }
					next;
				}
			}
			if ($foundparam) { $_misc_h{"TotalMisc"}++; }
		}
		# Analyze: successful favicon (=> countedtraffic=1 if favicon)
		#--------------------------------------------------
		if ( $urlwithnoquery =~ /$regfavico/o ) {
			if ( $field[$pos_code] != 404 ) {
				$_misc_h{'AddToFavourites'}++;
			}
			$countedtraffic =
			  1;    # favicon is a case that must not be counted anywhere else
			$_time_nv_h[$hourrecord]++;
			if ( $field[$pos_code] != 404 && $pos_size>0) {
				$_time_nv_k[$hourrecord] += int( $field[$pos_size] );
			}
		}
		# Analyze: Worms (=> countedtraffic=2 if worm)
		#---------------------------------------------
		if ( !$countedtraffic ) {
			if ($LevelForWormsDetection) {
				foreach (@WormsSearchIDOrder) {
					if ( $field[$pos_url] =~ /$_/ ) {
						# It's a worm
						my $worm = &UnCompileRegex($_);
						if ($Debug) {
							debug(
" Record is a hit from a worm identified by '$worm'",
								2
							);
						}
						$worm = $WormsHashID{$worm} || 'unknown';
						$_worm_h{$worm}++;
						if ($pos_size>0){$_worm_k{$worm} += int( $field[$pos_size] );}
						$_worm_l{$worm} = $timerecord;
						$countedtraffic = 2;
						if ($PageBool) { $_time_nv_p[$hourrecord]++; }
						$_time_nv_h[$hourrecord]++;
						if ($pos_size>0){$_time_nv_k[$hourrecord] += int( $field[$pos_size] );}
						last;
					}
				}
			}
		}
		# Analyze: Status code (=> countedtraffic=3 if error)
		#----------------------------------------------------
		if ( !$countedtraffic ) {
			if ( $LogType eq 'W' || $LogType eq 'S' )
			{    # HTTP record or Stream record
				if ( $ValidHTTPCodes{ $field[$pos_code] } ) {    # Code is valid
					if ( int($field[$pos_code]) == 304 && $pos_size>0) { $field[$pos_size] = 0; }
					# track downloads
					if (int($field[$pos_code]) == 200 && $MimeHashLib{$extension}[1] eq 'd' && $urlwithnoquery !~ /robots.txt$/ )  # We track download if $MimeHashLib{$extension}[1] = 'd'
					{
						$_downloads{$urlwithnoquery}->{'AWSTATS_HITS'}++;
						$_downloads{$urlwithnoquery}->{'AWSTATS_SIZE'} += ($pos_size>0 ? int($field[$pos_size]) : 0);
						if ($Debug) { debug( " New download detected: '$urlwithnoquery'", 2 ); }
					}
				# handle 206 download continuation message IF we had a successful 200 before, otherwise it goes in errors
				}elsif(int($field[$pos_code]) == 206 
					#&& $_downloads{$urlwithnoquery}->{$field[$pos_host]}[0] > 0 
					&& ($MimeHashLib{$extension}[1] eq 'd')){
					$_downloads{$urlwithnoquery}->{'AWSTATS_SIZE'} += ($pos_size>0 ? int($field[$pos_size]) : 0);
					$_downloads{$urlwithnoquery}->{'AWSTATS_206'}++;
					#$_downloads{$urlwithnoquery}->{$field[$pos_host]}[1] = $timerecord;
					if ($pos_size>0){
						#$_downloads{$urlwithnoquery}->{$field[$pos_host]}[2] = int($field[$pos_size]);
						$DayBytes{$yearmonthdayrecord} += int($field[$pos_size]);
						$_time_k[$hourrecord] += int($field[$pos_size]);
					}
					$countedtraffic = 6; # 206 continued download, so we track bandwidth but not pages or hits
					if ($Debug) { debug( " Download continuation detected: '$urlwithnoquery'", 2 ); }
  				}else {    # Code is not valid
					if ( $field[$pos_code] !~ /^\d\d\d$/ ) {
						$field[$pos_code] = 999;
					}
					$_errors_h{ $field[$pos_code] }++;
					if ($pos_size>0){$_errors_k{ $field[$pos_code] } += int( $field[$pos_size] );}
					foreach my $code ( keys %TrapInfosForHTTPErrorCodes ) {
						if ( $field[$pos_code] == $code ) {
							# This is an error code which referrer need to be tracked
							my $newurl =
							  substr( $field[$pos_url], 0,
								$MaxLengthOfStoredURL );
							$newurl =~ s/[$URLQuerySeparators].*$//;
							$_sider_h{$code}{$newurl}++;
							if ( $pos_referer >= 0 && $ShowHTTPErrorsPageDetail =~ /R/i  ) {
								my $newreferer = $field[$pos_referer];
								if ( !$URLReferrerWithQuery ) {
									$newreferer =~ s/[$URLQuerySeparators].*$//;
								}
								$_referer_h{$code}{$newurl} = $newreferer;
							}
							if ( $pos_host >= 0 && $ShowHTTPErrorsPageDetail =~ /H/i ) {
								my $newhost = $field[$pos_host];
								if ( !$URLReferrerWithQuery ) {
									$newhost =~ s/[$URLQuerySeparators].*$//;
								}
								$_err_host_h{$code}{$newurl} = $newhost;
								last;
							}
						}
					}
					if ($Debug) {
						debug(
" Record stored in the status code chart (status code=$field[$pos_code])",
							3
						);
					}
					$countedtraffic = 3;
					if ($PageBool) { $_time_nv_p[$hourrecord]++; }
					$_time_nv_h[$hourrecord]++;
					if ($pos_size>0){$_time_nv_k[$hourrecord] += int( $field[$pos_size] );}
				}
			}
			elsif ( $LogType eq 'M' ) {    # Mail record
				if ( !$ValidSMTPCodes{ $field[$pos_code] } )
				{                          # Code is not valid
					$_errors_h{ $field[$pos_code] }++;
					if ( $field[$pos_size] ne '-' && $pos_size>0) {
						$_errors_k{ $field[$pos_code] } +=
						  int( $field[$pos_size] );
					}
					if ($Debug) {
						debug(
" Record stored in the status code chart (status code=$field[$pos_code])",
							3
						);
					}
					$countedtraffic = 3;
					if ($PageBool) { $_time_nv_p[$hourrecord]++; }
					$_time_nv_h[$hourrecord]++;
					if ( $field[$pos_size] ne '-' && $pos_size>0) {
						$_time_nv_k[$hourrecord] += int( $field[$pos_size] );
					}
				}
			}
			elsif ( $LogType eq 'F' ) {    # FTP record
			}
		}
		# Analyze: Robot from robot database (=> countedtraffic=4 if robot)
		#------------------------------------------------------------------
		if ( !$countedtraffic || $countedtraffic == 6) {
			if ( $pos_agent >= 0 ) {
				if ($DecodeUA) {
					$field[$pos_agent] =~ s/%20/_/g;
				} # This is to support servers (like Roxen) that writes user agent with %20 in it
				$UserAgent = $field[$pos_agent];
				if ( $UserAgent && $UserAgent eq '-' ) { $UserAgent = ''; }
				if ($LevelForRobotsDetection) {
					if ($UserAgent) {
						my $uarobot = $TmpRobot{$UserAgent};
						if ( !$uarobot ) {
							#study $UserAgent;		Does not increase speed
							foreach (@RobotsSearchIDOrder) {
								if ( $UserAgent =~ /$_/ ) {
									my $bot = &UnCompileRegex($_);
									$TmpRobot{$UserAgent} = $uarobot = "$bot"
									  ; # Last time, we won't search if robot or not. We know it is.
									if ($Debug) {
										debug(
"  UserAgent '$UserAgent' is added to TmpRobot with value '$bot'",
											2
										);
									}
									last;
								}
							}
							if ( !$uarobot )
							{ # Last time, we won't search if robot or not. We know it's not.
								$TmpRobot{$UserAgent} = $uarobot = '-';
							}
						}
						if ( $uarobot ne '-' ) {
							# If robot, we stop here
							if ($Debug) {
								debug(
"  UserAgent '$UserAgent' contains robot ID '$uarobot'",
									2
								);
							}
							$_robot_h{$uarobot}++;
							if ( $field[$pos_size] ne '-' && $pos_size>0) {
								$_robot_k{$uarobot} += int( $field[$pos_size] );
							}
							$_robot_l{$uarobot} = $timerecord;
							if ( $urlwithnoquery =~ /$regrobot/o ) {
								$_robot_r{$uarobot}++;
							}
							$countedtraffic = 4;
							if ($PageBool) { $_time_nv_p[$hourrecord]++; }
							$_time_nv_h[$hourrecord]++;
							if ( $field[$pos_size] ne '-' && $pos_size>0) {
								$_time_nv_k[$hourrecord] +=
								  int( $field[$pos_size] );
							}
						}
					}
					else {
						my $uarobot = 'no_user_agent';
						# It's a robot or at least a bad browser, we stop here
						if ($Debug) {
							debug(
"  UserAgent not defined so it should be a robot, saved as robot 'no_user_agent'",
								2
							);
						}
						$_robot_h{$uarobot}++;
						if ($pos_size>0){$_robot_k{$uarobot} += int( $field[$pos_size] );}
						$_robot_l{$uarobot} = $timerecord;
						if ( $urlwithnoquery =~ /$regrobot/o ) {
							$_robot_r{$uarobot}++;
						}
						$countedtraffic = 4;
						if ($PageBool) { $_time_nv_p[$hourrecord]++; }
						$_time_nv_h[$hourrecord]++;
						if ($pos_size>0){$_time_nv_k[$hourrecord] += int( $field[$pos_size] );}
					}
				}
			}
		}
   # Analyze: Robot from "hit on robots.txt" file (=> countedtraffic=5 if robot)
   # -------------------------------------------------------------------------
		if ( !$countedtraffic ) {
			if ( $urlwithnoquery =~ /$regrobot/o ) {
				if ($Debug) { debug( "  It's an unknown robot", 2 ); }
				$_robot_h{'unknown'}++;
				if ($pos_size>0){$_robot_k{'unknown'} += int( $field[$pos_size] );}
				$_robot_l{'unknown'} = $timerecord;
				$_robot_r{'unknown'}++;
				$countedtraffic = 5;    # Must not be counted somewhere else
				if ($PageBool) { $_time_nv_p[$hourrecord]++; }
				$_time_nv_h[$hourrecord]++;
				if ($pos_size>0){$_time_nv_k[$hourrecord] += int( $field[$pos_size] );}
			}
		}
		# Analyze: File type - Compression
		#---------------------------------
		if ( !$countedtraffic || $countedtraffic == 6) {
			if ($LevelForFileTypesDetection) {
				if ($countedtraffic != 6){$_filetypes_h{$extension}++;}
				if ( $field[$pos_size] ne '-' && $pos_size>0) {
					$_filetypes_k{$extension} += int( $field[$pos_size] );
				}
				# Compression
				if ( $pos_gzipin >= 0 && $field[$pos_gzipin] )
				{    # If in and out in log
					my ( $notused, $in ) = split( /:/, $field[$pos_gzipin] );
					my ( $notused1, $out, $notused2 ) =
					  split( /:/, $field[$pos_gzipout] );
					if ($out) {
						$_filetypes_gz_in{$extension}  += $in;
						$_filetypes_gz_out{$extension} += $out;
					}
				}
				elsif ( $pos_compratio >= 0
					&& ( $field[$pos_compratio] =~ /(\d+)/ ) )
				{    # Calculate in/out size from percentage
					if ( $fieldlib[$pos_compratio] eq 'gzipratio' ) {
	# with mod_gzip:    % is size (before-after)/before (low for jpg) ??????????
						$_filetypes_gz_in{$extension} +=
						  int(
							$field[$pos_size] * 100 / ( ( 100 - $1 ) || 1 ) );
					}
					else {
					   # with mod_deflate: % is size after/before (high for jpg)
						$_filetypes_gz_in{$extension} +=
						  int( $field[$pos_size] * 100 / ( $1 || 1 ) );
					}
					if ($pos_size>0){$_filetypes_gz_out{$extension} += int( $field[$pos_size] );}
				}
			}
			# Analyze: Date - Hour - Pages - Hits - Kilo
			#-------------------------------------------
			if ($PageBool) {
# Replace default page name with / only ('if' is to increase speed when only 1 value in @DefaultFile)
				if ( @DefaultFile > 1 ) {
					foreach my $elem (@DefaultFile) {
						if ( $field[$pos_url] =~ s/\/$elem$/\// ) { last; }
					}
				}
				else { $field[$pos_url] =~ s/$regdefault/\//o; }
# FirstTime and LastTime are First and Last human visits (so changed if access to a page)
				$FirstTime{$lastprocesseddate} ||= $timerecord;
				$LastTime{$lastprocesseddate} = $timerecord;
				$DayPages{$yearmonthdayrecord}++;
				$_url_p{ $field[$pos_url] }++;   #Count accesses for page (page)
				if ( $field[$pos_size] ne '-' && $pos_size>0) {
					$_url_k{ $field[$pos_url] } += int( $field[$pos_size] );
				}
				$_time_p[$hourrecord]++;    #Count accesses for hour (page)
				                            # TODO Use an id for hash key of url
				                            # $_url_t{$_url_id}
			}
			if ($countedtraffic != 6){$_time_h[$hourrecord]++;}
 			if ($countedtraffic != 6){$DayHits{$yearmonthdayrecord}++;}    #Count accesses for hour (hit)
  			if ( $field[$pos_size] ne '-' && $pos_size>0) {
  				$_time_k[$hourrecord]          += int( $field[$pos_size] );
 				$DayBytes{$yearmonthdayrecord} += int( $field[$pos_size] );     #Count accesses for hour (kb)
  			}
			# Analyze: Login
			#---------------
			if (   $pos_logname >= 0
				&& $field[$pos_logname]
				&& $field[$pos_logname] ne '-' )
			{
				$field[$pos_logname] =~
				  s/ /_/g;    # This is to allow space in logname
				if ( $LogFormat eq '6' ) {
					$field[$pos_logname] =~ s/^\"//;
					$field[$pos_logname] =~ s/\"$//;
				}             # logname field has " with Domino 6+
				if ($AuthenticatedUsersNotCaseSensitive) {
					$field[$pos_logname] = lc( $field[$pos_logname] );
				}
				# We found an authenticated user
				if ($PageBool) {
					$_login_p{ $field[$pos_logname] }++;
				}             #Count accesses for page (page)
				if ($countedtraffic != 6){$_login_h{$field[$pos_logname]}++;}         #Count accesses for page (hit)
				if ($pos_size>0){$_login_k{ $field[$pos_logname] } +=
				  int( $field[$pos_size] );}    #Count accesses for page (kb)
				$_login_l{ $field[$pos_logname] } = $timerecord;
			}
		}
		# Do DNS lookup
		#--------------
		my $Host         = $field[$pos_host];
		my $HostResolved = ''
		  ; # HostResolved will be defined in next paragraf if countedtraffic is true
		if( $Host =~ /^([^:]+):[0-9]+$/ ){ # Host may sometimes have an ip:port syntax (ex: 54.32.12.12:60321)
		    $Host = $1;
		}
		if ( !$countedtraffic || $countedtraffic == 6) {
			my $ip = 0;
			if ($DNSLookup) {    # DNS lookup is 1 or 2
				if ( $Host =~ /$regipv4l/o ) {    # IPv4 lighttpd
					$Host =~ s/^::ffff://;
					$ip = 4;
				}
				elsif ( $Host =~ /$regipv4/o ) { $ip = 4; }    # IPv4
				elsif ( $Host =~ /$regipv6/o ) { $ip = 6; }    # IPv6
				if ($ip) {
					# Check in static DNS cache file
					$HostResolved = $MyDNSTable{$Host};
					if ($HostResolved) {
						if ($Debug) {
							debug(
"  DNS lookup asked for $Host and found in static DNS cache file: $HostResolved",
								4
							);
						}
					}
					elsif ( $DNSLookup == 1 ) {
		   # Check in session cache (dynamic DNS cache file + session DNS cache)
						$HostResolved = $TmpDNSLookup{$Host};
						if ( !$HostResolved ) {
							if ( @SkipDNSLookupFor && &SkipDNSLookup($Host) ) {
								$HostResolved = $TmpDNSLookup{$Host} = '*';
								if ($Debug) {
									debug(
"  No need of reverse DNS lookup for $Host, skipped at user request.",
										4
									);
								}
							}
							else {
								if ( $ip == 4 ) {
									my $lookupresult =
									  gethostbyaddr(
										pack( "C4", split( /\./, $Host ) ),
										AF_INET )
									  ; # This is very slow, may spend 20 seconds
									if (   !$lookupresult
										|| $lookupresult =~ /$regipv4/o
										|| !IsAscii($lookupresult) )
									{
										$TmpDNSLookup{$Host} = $HostResolved =
										  '*';
									}
									else {
										$TmpDNSLookup{$Host} = $HostResolved =
										  $lookupresult;
									}
									if ($Debug) {
										debug(
"  Reverse DNS lookup for $Host done: $HostResolved",
											4
										);
									}
								}
								elsif ( $ip == 6 ) {
									if ( $PluginsLoaded{'GetResolvedIP'}
										{'ipv6'} )
									{
										my $lookupresult =
										  GetResolvedIP_ipv6($Host);
										if (   !$lookupresult
											|| !IsAscii($lookupresult) )
										{
											$TmpDNSLookup{$Host} =
											  $HostResolved = '*';
										}
										else {
											$TmpDNSLookup{$Host} =
											  $HostResolved = $lookupresult;
										}
									}
									else {
										$TmpDNSLookup{$Host} = $HostResolved =
										  '*';
										warning(
"Reverse DNS lookup for $Host not available without ipv6 plugin enabled."
										);
									}
								}
								else { error("Bad value vor ip"); }
							}
						}
					}
					else {
						$HostResolved = '*';
						if ($Debug) {
							debug(
"  DNS lookup by static DNS cache file asked for $Host but not found.",
								4
							);
						}
					}
				}
				else {
					if ($Debug) {
						debug(
"  DNS lookup asked for $Host but this is not an IP address.",
							4
						);
					}
					$DNSLookupAlreadyDone = $LogFile;
				}
			}
			else {
				if ( $Host =~ /$regipv4l/o ) {
					$Host =~ s/^::ffff://;
					$HostResolved = '*';
					$ip           = 4;
				}
				elsif ( $Host =~ /$regipv4/o ) {
					$HostResolved = '*';
					$ip           = 4;
				}    # IPv4
				elsif ( $Host =~ /$regipv6/o ) {
					$HostResolved = '*';
					$ip           = 6;
				}    # IPv6
				if ($Debug) { debug( "  No DNS lookup asked.", 4 ); }
			}
			# Analyze: Country (Top-level domain)
			#------------------------------------
			if ($Debug) {
				debug(
"  Search country (Host=$Host HostResolved=$HostResolved ip=$ip)",
					4
				);
			}
			my $Domain = 'ip';
			# Set $HostResolved to host and resolve domain
			if ( $HostResolved eq '*' ) {
# $Host is an IP address and is not resolved (failed or not asked) or resolution gives an IP address
				$HostResolved = $Host;
				# Resolve Domain
				if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip6'} ) {
					$Domain = GetCountryCodeByAddr_geoip6($HostResolved);
				}
				elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) {
					$Domain = GetCountryCodeByAddr_geoip($HostResolved);
				}
#			elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_region_maxmind($HostResolved); }
#			elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_city_maxmind'})   { $Domain=GetCountryCodeByAddr_geoip_city_maxmind($HostResolved); }
				elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'} ) {
					$Domain = GetCountryCodeByAddr_geoipfree($HostResolved);
				}
				elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip2_country'} ) {
					$Domain = GetCountryCodeByAddr_geoip2_country($HostResolved);
				}
				if ($AtLeastOneSectionPlugin) {
					foreach my $pluginname (
						keys %{ $PluginsLoaded{'SectionProcessIp'} } )
					{
						my $function = "SectionProcessIp_$pluginname";
						if ($Debug) {
							debug( "  Call to plugin function $function", 5 );
						}
						&$function($HostResolved);
					}
				}
			}
			else {
# $Host was already a host name ($ip=0, $Host=name, $HostResolved='') or has been resolved ($ip>0, $Host=ip, $HostResolved defined)
				$HostResolved = lc( $HostResolved ? $HostResolved : $Host );
				# Resolve Domain
				if ($ip)
				{    # If we have ip, we use it in priority instead of hostname
					if ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip6'} ) {
						$Domain = GetCountryCodeByAddr_geoip6($Host);
					}
					elsif ( $PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'} ) {
						$Domain = GetCountryCodeByAddr_geoip($Host);
					}
#				elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_region_maxmind($Host); }
#				elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_city_maxmind'})   { $Domain=GetCountryCodeByAddr_geoip_city_maxmind($Host); }
					elsif (
						$PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'} )
					{
						$Domain = GetCountryCodeByAddr_geoipfree($Host);
					}
					elsif (
						$PluginsLoaded{'GetCountryCodeByAddr'}{'geoip2_country'} )
					{
						$Domain = GetCountryCodeByAddr_geoip2_country($Host);
					}
					elsif ( $HostResolved =~ /\.(\w+)$/ ) { $Domain = $1; }
					if ($AtLeastOneSectionPlugin) {
						foreach my $pluginname (
							keys %{ $PluginsLoaded{'SectionProcessIp'} } )
						{
							my $function = "SectionProcessIp_$pluginname";
							if ($Debug) {
								debug( "  Call to plugin function $function",
									5 );
							}
							&$function($Host);
						}
					}
				}
				else {
					if ( $PluginsLoaded{'GetCountryCodeByName'}{'geoip6'} ) {
						$Domain = GetCountryCodeByName_geoip6($HostResolved);
					}
					elsif ( $PluginsLoaded{'GetCountryCodeByName'}{'geoip'} ) {
						$Domain = GetCountryCodeByName_geoip($HostResolved);
					}
#				elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByName_geoip_region_maxmind($HostResolved); }
#				elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoip_city_maxmind'})   { $Domain=GetCountryCodeByName_geoip_city_maxmind($HostResolved); }
					elsif (
						$PluginsLoaded{'GetCountryCodeByName'}{'geoipfree'} )
					{
						$Domain = GetCountryCodeByName_geoipfree($HostResolved);
					}
					elsif (
						$PluginsLoaded{'GetCountryCodeByName'}{'geoip2_country'} )
					{
						$Domain = GetCountryCodeByName_geoip2_country($HostResolved);
					}
					elsif ( $HostResolved =~ /\.(\w+)$/ ) { $Domain = $1; }
					if ($AtLeastOneSectionPlugin) {
						foreach my $pluginname (
							keys %{ $PluginsLoaded{'SectionProcessHostname'} } )
						{
							my $function = "SectionProcessHostname_$pluginname";
							if ($Debug) {
								debug( "  Call to plugin function $function",
									5 );
							}
							&$function($HostResolved);
						}
					}
				}
			}
			# Store country
			if ($PageBool) { $_domener_p{$Domain}++; }
			if ($countedtraffic != 6){$_domener_h{$Domain}++;}
			if ( $field[$pos_size] ne '-' && $pos_size>0) {
				$_domener_k{$Domain} += int( $field[$pos_size] );
			}
			# Analyze: Host, URL entry+exit and Session
			#------------------------------------------
			if ($PageBool) {
				my $timehostl = $_host_l{$HostResolved};
				if ($timehostl) {
# A visit for this host was already detected
# TODO everywhere there is $VISITTIMEOUT
#				$timehostl =~ /^\d\d\d\d\d\d(\d\d)/; my $daytimehostl=$1;
#				if ($timerecord > ($timehostl+$VISITTIMEOUT+($dateparts[3]>$daytimehostl?$NEWDAYVISITTIMEOUT:0))) {
					if ( $timerecord > ( $timehostl + $VISITTIMEOUT ) ) {
						# This is a second visit or more
						if ( !$_waithost_s{$HostResolved} ) {
							# This is a second visit or more
							# We count 'visit','exit','entry','DayVisits'
							if ($Debug) {
								debug(
"  This is a second visit for $HostResolved.",
									4
								);
							}
							my $timehosts = $_host_s{$HostResolved};
							my $page      = $_host_u{$HostResolved};
							if ($page) { $_url_x{$page}++; }
							$_url_e{ $field[$pos_url] }++;
							$DayVisits{$yearmonthdayrecord}++;
				 # We can't count session yet because we don't have the start so
				 # we save params of first 'wait' session
							$_waithost_l{$HostResolved} = $timehostl;
							$_waithost_s{$HostResolved} = $timehosts;
							$_waithost_u{$HostResolved} = $page;
						}
						else {
						 # This is third visit or more
						 # We count 'session','visit','exit','entry','DayVisits'
							if ($Debug) {
								debug(
"  This is a third visit or more for $HostResolved.",
									4
								);
							}
							my $timehosts = $_host_s{$HostResolved};
							my $page      = $_host_u{$HostResolved};
							if ($page) { $_url_x{$page}++; }
							$_url_e{ $field[$pos_url] }++;
							$DayVisits{$yearmonthdayrecord}++;
							if ($timehosts) {
								$_session{ GetSessionRange( $timehosts,
										$timehostl ) }++;
							}
						}
						# Save new session properties
						$_host_s{$HostResolved} = $timerecord;
						$_host_l{$HostResolved} = $timerecord;
						$_host_u{$HostResolved} = $field[$pos_url];
					}
					elsif ( $timerecord > $timehostl ) {
						# This is a same visit we can count
						if ($Debug) {
							debug(
"  This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",
								4
							);
						}
						$_host_l{$HostResolved} = $timerecord;
						$_host_u{$HostResolved} = $field[$pos_url];
					}
					elsif ( $timerecord == $timehostl ) {
						# This is a same visit we can count
						if ($Debug) {
							debug(
"  This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",
								4
							);
						}
						$_host_u{$HostResolved} = $field[$pos_url];
					}
					elsif ( $timerecord < $_host_s{$HostResolved} ) {
					   # Should happens only with not correctly sorted log files
						if ($Debug) {
							debug(
"  This is same visit still running for $HostResolved with start not in order. host_s changed to $timerecord (entry page also changed if first visit)",
								4
							);
						}
						if ( !$_waithost_s{$HostResolved} ) {
# We can reorder entry page only if it's the first visit found in this update run (The saved entry page was $_waithost_e if $_waithost_s{$HostResolved} is not defined. If second visit or more, entry was directly counted and not saved)
							$_waithost_e{$HostResolved} = $field[$pos_url];
						}
						else {
# We can't change entry counted as we dont't know what was the url counted as entry
						}
						$_host_s{$HostResolved} = $timerecord;
					}
					else {
						if ($Debug) {
							debug(
"  This is same visit still running for $HostResolved with hit between start and last hits. No change",
								4
							);
						}
					}
				}
				else {
# This is a new visit (may be). First new visit found for this host. We save in wait array the entry page to count later
					if ($Debug) {
						debug(
"  New session (may be) for $HostResolved. Save in wait array to see later",
							4
						);
					}
					$_waithost_e{$HostResolved} = $field[$pos_url];
					# Save new session properties
					$_host_u{$HostResolved} = $field[$pos_url];
					$_host_s{$HostResolved} = $timerecord;
					$_host_l{$HostResolved} = $timerecord;
				}
				$_host_p{$HostResolved}++;
			}
			$_host_h{$HostResolved}++;
			if ( $field[$pos_size] ne '-' && $pos_size>0) {
				$_host_k{$HostResolved} += int( $field[$pos_size] );
			}
			# Analyze: Browser - OS
			#----------------------
			if ( $pos_agent >= 0 ) {
				if ($LevelForBrowsersDetection) {
					# Analyze: Browser
					#-----------------
					my $uabrowser = $TmpBrowser{$UserAgent};
					if ( !$uabrowser ) {
						my $found = 1;
						# Edge (must be at beginning)
						if ($UserAgent =~ /$regveredge/o)
						{
							$_browser_h{"edge$1"}++;
							if ($PageBool) { $_browser_p{"edge$1"}++; }
							$TmpBrowser{$UserAgent} = "edge$1";
						}
						
						# Opera ?
						elsif ( $UserAgent =~ /$regveropera/o ) {	# !!!! version number in in regex $1 or $2 !!!
						    $_browser_h{"opera".($1||$2)}++;
						    if ($PageBool) { $_browser_p{"opera".($1||$2)}++; }
						    $TmpBrowser{$UserAgent} = "opera".($1||$2);
						}
						
						# Firefox ?
						elsif ( $UserAgent =~ /$regverfirefox/o
						    && $UserAgent !~ /$regnotfirefox/o )
						{
						    $_browser_h{"firefox$1"}++;
						    if ($PageBool) { $_browser_p{"firefox$1"}++; }
						    $TmpBrowser{$UserAgent} = "firefox$1";
						}
						# Chrome ?
						elsif ( $UserAgent =~ /$regverchrome/o ) {
							$_browser_h{"chrome$1"}++;
							if ($PageBool) { $_browser_p{"chrome$1"}++; }
							$TmpBrowser{$UserAgent} = "chrome$1";
						}
						# Safari ?
						elsif ($UserAgent =~ /$regversafari/o
							&& $UserAgent !~ /$regnotsafari/o )
						{
							my $safariver = $BrowsersSafariBuildToVersionHash{$1};
							if ( $UserAgent =~ /$regversafariver/o ) {
								$safariver = $1;
							}
							$_browser_h{"safari$safariver"}++;
							if ($PageBool) { $_browser_p{"safari$safariver"}++; }
							$TmpBrowser{$UserAgent} = "safari$safariver";
						}
						# Konqueror ?
						elsif ( $UserAgent =~ /$regverkonqueror/o ) {
							$_browser_h{"konqueror$1"}++;
							if ($PageBool) { $_browser_p{"konqueror$1"}++; }
							$TmpBrowser{$UserAgent} = "konqueror$1";
						}
						# Subversion ?
						elsif ( $UserAgent =~ /$regversvn/o ) {
							$_browser_h{"svn$1"}++;
							if ($PageBool) { $_browser_p{"svn$1"}++; }
							$TmpBrowser{$UserAgent} = "svn$1";
						}
						# IE < 11 ? (must be at end of test)
						elsif ($UserAgent =~ /$regvermsie/o
							&& $UserAgent !~ /$regnotie/o )
						{
							$_browser_h{"msie$2"}++;
							if ($PageBool) { $_browser_p{"msie$2"}++; }
							$TmpBrowser{$UserAgent} = "msie$2";
						}
						
						# IE >= 11
                        elsif ($UserAgent =~ /$regvermsie11/o && $UserAgent !~ /$regnotie/o)
						{
                            $_browser_h{"msie$2"}++;
                            if ($PageBool) { $_browser_p{"msie$2"}++; }
                            $TmpBrowser{$UserAgent} = "msie$2";
						}
						# Netscape 6.x, 7.x ... ? (must be at end of test)
						elsif ( $UserAgent =~ /$regvernetscape/o ) {
							$_browser_h{"netscape$1"}++;
							if ($PageBool) { $_browser_p{"netscape$1"}++; }
							$TmpBrowser{$UserAgent} = "netscape$1";
						}
						# Netscape 3.x, 4.x ... ? (must be at end of test)
						elsif ($UserAgent =~ /$regvermozilla/o
							&& $UserAgent !~ /$regnotnetscape/o )
						{
							$_browser_h{"netscape$2"}++;
							if ($PageBool) { $_browser_p{"netscape$2"}++; }
							$TmpBrowser{$UserAgent} = "netscape$2";
						}
						# Other known browsers ?
						else {
							$found = 0;
							foreach (@BrowsersSearchIDOrder)
							{    # Search ID in order of BrowsersSearchIDOrder
								if ( $UserAgent =~ /$_/ ) {
									my $browser = &UnCompileRegex($_);
								   # TODO If browser is in a family, use version
									$_browser_h{"$browser"}++;
									if ($PageBool) { $_browser_p{"$browser"}++; }
									$TmpBrowser{$UserAgent} = "$browser";
									$found = 1;
									last;
								}
							}
						}
						# Unknown browser ?
						if ( !$found ) {
							$_browser_h{'Unknown'}++;
							if ($PageBool) { $_browser_p{'Unknown'}++; }
							$TmpBrowser{$UserAgent} = 'Unknown';
							my $newua = $UserAgent;
							$newua =~ tr/\+ /__/;
							$_unknownrefererbrowser_l{$newua} = $timerecord;
						}
					}
					else {
						$_browser_h{$uabrowser}++;
						if ($PageBool) { $_browser_p{$uabrowser}++; }
						if ( $uabrowser eq 'Unknown' ) {
							my $newua = $UserAgent;
							$newua =~ tr/\+ /__/;
							$_unknownrefererbrowser_l{$newua} = $timerecord;
						}
					}
				}
				if ($LevelForOSDetection) {
					# Analyze: OS
					#------------
					my $uaos = $TmpOS{$UserAgent};
					if ( !$uaos ) {
						my $found = 0;
						# in OSHashID list ?
						foreach (@OSSearchIDOrder)
						{    # Search ID in order of OSSearchIDOrder
							if ( $UserAgent =~ /$_/ ) {
								my $osid = $OSHashID{ &UnCompileRegex($_) };
								$_os_h{"$osid"}++;
								if ($PageBool) { $_os_p{"$osid"}++; }
								$TmpOS{$UserAgent} = "$osid";
								$found = 1;
								last;
							}
						}
						# Unknown OS ?
						if ( !$found ) {
							$_os_h{'Unknown'}++;
							if ($PageBool) { $_os_p{'Unknown'}++; }
							$TmpOS{$UserAgent} = 'Unknown';
							my $newua = $UserAgent;
							$newua =~ tr/\+ /__/;
							$_unknownreferer_l{$newua} = $timerecord;
						}
					}
					else {
						$_os_h{$uaos}++;
						if ($PageBool) {
							$_os_p{$uaos}++;
						}
						if ( $uaos eq 'Unknown' ) {
							my $newua = $UserAgent;
							$newua =~ tr/\+ /__/;
							$_unknownreferer_l{$newua} = $timerecord;
						}
					}
				}
			}
			else {
				$_browser_h{'Unknown'}++;
				$_os_h{'Unknown'}++;
				if ($PageBool) {
					$_browser_p{'Unknown'}++;
					$_os_p{'Unknown'}++;
				}
			}
			# Analyze: Referer
			#-----------------
			my $found = 0;
			if (   $pos_referer >= 0
				&& $LevelForRefererAnalyze
				&& $field[$pos_referer] )
			{
				# Direct ?
				if (   $field[$pos_referer] eq '-'
					|| $field[$pos_referer] eq 'bookmarks' )
				{  # "bookmarks" is sent by Netscape, '-' by all others browsers
					    # Direct access
					if ($PageBool) {
						if ($ShowDirectOrigin) {
							print "Direct access for line $line\n";
						}
						$_from_p[0]++;
					}
					$_from_h[0]++;
					$found = 1;
				}
				else {
					$field[$pos_referer] =~ /$regreferer/o;
					my $refererprot   = $1;
					my $refererserver =
					    ( $2 || '' )
					  . ( !$3 || $3 eq ':80' ? '' : $3 )
					  ; # refererserver is www.xxx.com or www.xxx.com:81 but not www.xxx.com:80
					    # HTML link ?
					if ( $refererprot =~ /^http/i ) {
#if ($Debug) { debug("  Analyze referer refererprot=$refererprot refererserver=$refererserver",5); }
						# Kind of origin
						if ( !$TmpRefererServer{$refererserver} )
						{ # TmpRefererServer{$refererserver} is "=" if same site, "search egine key" if search engine, not defined otherwise
							if ( $refererserver =~ /$reglocal/o ) {
						  # Intern (This hit came from another page of the site)
								if ($Debug) {
									debug(
"  Server '$refererserver' is added to TmpRefererServer with value '='",
										2
									);
								}
								$TmpRefererServer{$refererserver} = '=';
								$found = 1;
							}
							else {
								foreach (@HostAliases) {
									if ( $refererserver =~ /$_/ ) {
						  # Intern (This hit came from another page of the site)
										if ($Debug) {
											debug(
"  Server '$refererserver' is added to TmpRefererServer with value '='",
												2
											);
										}
										$TmpRefererServer{$refererserver} = '=';
										$found = 1;
										last;
									}
								}
								if ( !$found ) {
							 # Extern (This hit came from an external web site).
									if ($LevelForSearchEnginesDetection) {
										foreach (@SearchEnginesSearchIDOrder)
										{ # Search ID in order of SearchEnginesSearchIDOrder
											if ( $refererserver =~ /$_/ ) {
												my $key = &UnCompileRegex($_);
												if (
													!$NotSearchEnginesKeys{$key}
													|| $refererserver !~
/$NotSearchEnginesKeys{$key}/i
												  )
												{
									 # This hit came from the search engine $key
													if ($Debug) {
														debug(
"  Server '$refererserver' is added to TmpRefererServer with value '$key'",
															2
														);
													}
													$TmpRefererServer{
														$refererserver} =
													  $SearchEnginesHashID{ $key
													  };
													$found = 1;
												}
												last;
											}
										}
									}
								}
							}
						}
						my $tmprefererserver =
						  $TmpRefererServer{$refererserver};
						if ($tmprefererserver) {
							if ( $tmprefererserver eq '=' ) {
						  # Intern (This hit came from another page of the site)
								if ($PageBool) { $_from_p[4]++; }
								$_from_h[4]++;
								$found = 1;
							}
							else {
								# This hit came from a search engine
								if ($PageBool) {
									$_from_p[2]++;
									$_se_referrals_p{$tmprefererserver}++;
								}
								$_from_h[2]++;
								$_se_referrals_h{$tmprefererserver}++;
								$found = 1;
								if ( $PageBool && $LevelForKeywordsDetection ) {
									# we will complete %_keyphrases hash array
									my @refurl =
									  split( /\?/, $field[$pos_referer], 2 )
									  ; # TODO Use \? or [$URLQuerySeparators] ?
									if ( $refurl[1] ) {
# Extract params of referer query string (q=cache:mmm:www/zzz+aaa+bbb q=aaa+bbb/ccc key=ddd%20eee lang_en ie=UTF-8 ...)
										if (
											$SearchEnginesKnownUrl{
												$tmprefererserver} )
										{  # Search engine with known URL syntax
											foreach my $param (
												split(
													/&/,
													$KeyWordsNotSensitive
													? lc( $refurl[1] )
													: $refurl[1]
												)
											  )
											{
												if ( $param =~
s/^$SearchEnginesKnownUrl{$tmprefererserver}//
												  )
												{
	 # We found good parameter
	 # Now param is keyphrase: "cache:mmm:www/zzz+aaa+bbb/ccc+ddd%20eee'fff,ggg"
													$param =~
s/^(cache|related):[^\+]+//
													  ; # Should be useless since this is for hit on 'not pages'
													&ChangeWordSeparatorsIntoSpace
													  ($param)
													  ; # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg]
													$param =~ s/^ +//;
													$param =~ s/ +$//;    # Trim
													$param =~ tr/ /\+/s;
													if ( ( ( length $param ) > 0 ) and ( ( length $param ) < 80 ) )
													{
														$_keyphrases{$param}++;
													}
													last;
												}
											}
										}
										elsif (
											$LevelForKeywordsDetection >= 2 )
										{ # Search engine with unknown URL syntax
											foreach my $param (
												split(
													/&/,
													$KeyWordsNotSensitive
													? lc( $refurl[1] )
													: $refurl[1]
												)
											  )
											{
												my $foundexcludeparam = 0;
												foreach my $paramtoexclude (
													@WordsToCleanSearchUrl)
												{
													if ( $param =~
														/$paramtoexclude/i )
													{
														$foundexcludeparam = 1;
														last;
													} # Not the param with search criteria
												}
												if ($foundexcludeparam) {
													next;
												}
												# We found good parameter
												$param =~ s/.*=//;
					   # Now param is keyphrase: "aaa+bbb/ccc+ddd%20eee'fff,ggg"
												$param =~
												  s/^(cache|related):[^\+]+//
												  ; # Should be useless since this is for hit on 'not pages'
												&ChangeWordSeparatorsIntoSpace(
													$param)
												  ; # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg ]
												$param =~ s/^ +//;
												$param =~ s/ +$//;     # Trim
												$param =~ tr/ /\+/s;
												if ( ( length $param ) > 2 ) {
													$_keyphrases{$param}++;
													last;
												}
											}
										}
									}    # End of elsif refurl[1]
									elsif (
										$SearchEnginesWithKeysNotInQuery{
											$tmprefererserver} )
									{
#										debug("xxx".$refurl[0]);
# If search engine with key inside page url like a9 (www.a9.com/searchkey1%20searchkey2)
										if ( $refurl[0] =~
/$SearchEnginesKnownUrl{$tmprefererserver}(.*)$/
										  )
										{
											my $param = $1;
											&ChangeWordSeparatorsIntoSpace(
												$param);
											$param =~ tr/ /\+/s;
											if ( ( length $param ) > 0 ) {
												$_keyphrases{$param}++;
											}
										}
									}
								}
							}
						}    # End of if ($TmpRefererServer)
						else {
						  # This hit came from a site other than a search engine
							if ($PageBool) { $_from_p[3]++; }
							$_from_h[3]++;
# http://www.mysite.com/ must be same referer than http://www.mysite.com but .../mypage/ differs of .../mypage
#if ($refurl[0] =~ /^[^\/]+\/$/) { $field[$pos_referer] =~ s/\/$//; }	# Code moved in Save_History
# TODO: lowercase the value for referer server to have refering server not case sensitive
							if ($URLReferrerWithQuery) {
								if ($PageBool) {
									$_pagesrefs_p{ $field[$pos_referer] }++;
								}
								$_pagesrefs_h{ $field[$pos_referer] }++;
							}
							else {
								# We discard query for referer
								if ( $field[$pos_referer] =~
									/$regreferernoquery/o )
								{
									if ($PageBool) { $_pagesrefs_p{"$1"}++; }
									$_pagesrefs_h{"$1"}++;
								}
								else {
									if ($PageBool) {
										$_pagesrefs_p{ $field[$pos_referer] }++;
									}
									$_pagesrefs_h{ $field[$pos_referer] }++;
								}
							}
							$found = 1;
						}
					}
					# News Link ?
					#if (! $found && $refererprot =~ /^news/i) {
					#	$found=1;
					#	if ($PageBool) { $_from_p[5]++; }
					#	$_from_h[5]++;
					#}
				}
			}
			# Origin not found
			if ( !$found ) {
				if ($ShowUnknownOrigin) {
					print "Unknown origin: $field[$pos_referer]\n";
				}
				if ($PageBool) { $_from_p[1]++; }
				$_from_h[1]++;
			}
			# Analyze: EMail
			#---------------
			if ( $pos_emails >= 0 && $field[$pos_emails] ) {
				if ( $field[$pos_emails] eq '<>' ) {
					$field[$pos_emails] = 'Unknown';
				}
				elsif ( $field[$pos_emails] !~ /\@/ ) {
					$field[$pos_emails] .= "\@$SiteDomain";
				}
				$_emails_h{ lc( $field[$pos_emails] ) }
				  ++;    #Count accesses for sender email (hit)
				if ($pos_size>0){$_emails_k{ lc( $field[$pos_emails] ) } +=
				  int( $field[$pos_size] )
				  ;}      #Count accesses for sender email (kb)
				$_emails_l{ lc( $field[$pos_emails] ) } = $timerecord;
			}
			if ( $pos_emailr >= 0 && $field[$pos_emailr] ) {
				if ( $field[$pos_emailr] !~ /\@/ ) {
					$field[$pos_emailr] .= "\@$SiteDomain";
				}
				$_emailr_h{ lc( $field[$pos_emailr] ) }
				  ++;    #Count accesses for receiver email (hit)
				if ($pos_size>0){$_emailr_k{ lc( $field[$pos_emailr] ) } +=
				  int( $field[$pos_size] )
				  ;}      #Count accesses for receiver email (kb)
				$_emailr_l{ lc( $field[$pos_emailr] ) } = $timerecord;
			}
		}
		# Check cluster
		#--------------
		if ( $pos_cluster >= 0 ) {
			if ($PageBool) {
				$_cluster_p{ $field[$pos_cluster] }++;
			}    #Count accesses for page (page)
			$_cluster_h{ $field[$pos_cluster] }
			  ++;    #Count accesses for page (hit)
			if ($pos_size>0){$_cluster_k{ $field[$pos_cluster] } +=
			  int( $field[$pos_size] );}    #Count accesses for page (kb)
		}
		# Analyze: Extra
		#---------------
		foreach my $extranum ( 1 .. @ExtraName - 1 ) {
			if ($Debug) { debug( "  Process extra analyze $extranum", 4 ); }
			# Check code
			my $conditionok = 0;
			if ( $ExtraCodeFilter[$extranum] ) {
				foreach
				  my $condnum ( 0 .. @{ $ExtraCodeFilter[$extranum] } - 1 )
				{
					if ($Debug) {
						debug(
"  Check code '$field[$pos_code]' must be '$ExtraCodeFilter[$extranum][$condnum]'",
							5
						);
					}
					if ( $field[$pos_code] eq
						"$ExtraCodeFilter[$extranum][$condnum]" )
					{
						$conditionok = 1;
						last;
					}
				}
				if ( !$conditionok && @{ $ExtraCodeFilter[$extranum] } ) {
					next;
				}    # End for this section
				if ($Debug) {
					debug(
"  No check on code or code is OK. Now we check other conditions.",
						5
					);
				}
			}
			# Check conditions
			$conditionok = 0;
			foreach my $condnum ( 0 .. @{ $ExtraConditionType[$extranum] } - 1 )
			{
				my $conditiontype    = $ExtraConditionType[$extranum][$condnum];
				my $conditiontypeval =
				  $ExtraConditionTypeVal[$extranum][$condnum];
				if ( $conditiontype eq 'URL' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$urlwithnoquery'",
							5
						);
					}
					if ( $urlwithnoquery =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'QUERY_STRING' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$standalonequery'",
							5
						);
					}
					if ( $standalonequery =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'URLWITHQUERY' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$urlwithnoquery$tokenquery$standalonequery'",
							5
						);
					}
					if ( "$urlwithnoquery$tokenquery$standalonequery" =~
						/$conditiontypeval/ )
					{
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'REFERER' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_referer]'",
							5
						);
					}
					if ( $field[$pos_referer] =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'UA' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_agent]'",
							5
						);
					}
					if ( $field[$pos_agent] =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'HOSTINLOG' ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_host]'",
							5
						);
					}
					if ( $field[$pos_host] =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'HOST' ) {
					my $hosttouse = ( $HostResolved ? $HostResolved : $Host );
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$hosttouse'",
							5
						);
					}
					if ( $hosttouse =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype eq 'VHOST' ) {
					if ($Debug) {
						debug(
"  Check condision '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_vh]'",
							5
						);
					}
					if ( $field[$pos_vh] =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				elsif ( $conditiontype =~ /extra(\d+)/i ) {
					if ($Debug) {
						debug(
"  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_extra[$1]]'",
							5
						);
					}
					if ( $field[ $pos_extra[$1] ] =~ /$conditiontypeval/ ) {
						$conditionok = 1;
						last;
					}
				}
				else {
					error(
"Wrong value of parameter ExtraSectionCondition$extranum"
					);
				}
			}
			if ( !$conditionok && @{ $ExtraConditionType[$extranum] } ) {
				next;
			}    # End for this section
			if ($Debug) {
				debug(
"  No condition or condition is OK. Now we extract value for first column of extra chart.",
					5
				);
			}
			# Determine actual column value to use.
			my $rowkeyval;
			my $rowkeyok = 0;
			foreach my $rowkeynum (
				0 .. @{ $ExtraFirstColumnValuesType[$extranum] } - 1 )
			{
				my $rowkeytype =
				  $ExtraFirstColumnValuesType[$extranum][$rowkeynum];
				my $rowkeytypeval =
				  $ExtraFirstColumnValuesTypeVal[$extranum][$rowkeynum];
				if ( $rowkeytype eq 'URL' ) {
					if ( $urlwithnoquery =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'QUERY_STRING' ) {
					if ($Debug) {
						debug(
"  Extract value from '$standalonequery' with regex '$rowkeytypeval'.",
							5
						);
					}
					if ( $standalonequery =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'URLWITHQUERY' ) {
					if ( "$urlwithnoquery$tokenquery$standalonequery" =~
						/$rowkeytypeval/ )
					{
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'REFERER' ) {
					if ( $field[$pos_referer] =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'UA' ) {
					if ( $field[$pos_agent] =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'HOSTINLOG' ) {
					if ( $field[$pos_host] =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'HOST' ) {
					my $hosttouse = ( $HostResolved ? $HostResolved : $Host );
					if ( $hosttouse =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype eq 'VHOST' ) {
					if ( $field[$pos_vh] =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				elsif ( $rowkeytype =~ /extra(\d+)/i ) {
					if ( $field[ $pos_extra[$1] ] =~ /$rowkeytypeval/ ) {
						$rowkeyval = "$1";
						$rowkeyok  = 1;
						last;
					}
				}
				else {
					error(
"Wrong value of parameter ExtraSectionFirstColumnValues$extranum"
					);
				}
			}
			if ( !$rowkeyok ) { next; }    # End for this section
			if ( !$rowkeyval ) { $rowkeyval = 'Failed to extract key'; }
			if ($Debug) { debug( "  Key val found: $rowkeyval", 5 ); }
			# Apply function on $rowkeyval
			if ( $ExtraFirstColumnFunction[$extranum] ) {
				# Todo call function on string $rowkeyval
			}
			# Here we got all values to increase counters
			if ( $PageBool && $ExtraStatTypes[$extranum] =~ /P/i ) {
				${ '_section_' . $extranum . '_p' }{$rowkeyval}++;
			}
			${ '_section_' . $extranum . '_h' }{$rowkeyval}++;    # Must be set
			if ( $ExtraStatTypes[$extranum] =~ /B/i && $pos_size>0) {
				${ '_section_' . $extranum . '_k' }{$rowkeyval} +=
				  int( $field[$pos_size] );
			}
			if ( $ExtraStatTypes[$extranum] =~ /L/i ) {
				if ( ${ '_section_' . $extranum . '_l' }{$rowkeyval}
					|| 0 < $timerecord )
				{
					${ '_section_' . $extranum . '_l' }{$rowkeyval} =
					  $timerecord;
				}
			}
			# Check to avoid too large extra sections
			if (
				scalar keys %{ '_section_' . $extranum . '_h' } >
				$ExtraTrackedRowsLimit )
			{
				error(<= 20000 ) {
			#if (++$counterforflushtest >= 1) {
			if (   ( scalar keys %_host_u ) > ( $LIMITFLUSH << 2 )
				|| ( scalar keys %_url_p ) > $LIMITFLUSH )
			{
# warning("Warning: Try to run AWStats update process more frequently to analyze smaler log files.");
				if ( $^X =~ /activestate/i || $^X =~ /activeperl/i ) {
# We don't flush if perl is activestate to avoid slowing process because of memory hole
				}
				else {
					# Clean tmp hash arrays
					#%TmpDNSLookup = ();
					%TmpOS = %TmpRefererServer = %TmpRobot = %TmpBrowser = ();
					# We flush if perl is not activestate
					print "Flush history file on disk";
					if ( ( scalar keys %_host_u ) > ( $LIMITFLUSH << 2 ) ) {
						print " (unique hosts reach flush limit of "
						  . ( $LIMITFLUSH << 2 ) . ")";
					}
					if ( ( scalar keys %_url_p ) > $LIMITFLUSH ) {
						print " (unique url reach flush limit of "
						  . ($LIMITFLUSH) . ")";
					}
					print "\n";
					if ($Debug) {
						debug(
"End of set of $counterforflushtest records: Some hash arrays are too large. We flush and clean some.",
							2
						);
						print " _host_p:"
						  . ( scalar keys %_host_p )
						  . " _host_h:"
						  . ( scalar keys %_host_h )
						  . " _host_k:"
						  . ( scalar keys %_host_k )
						  . " _host_l:"
						  . ( scalar keys %_host_l )
						  . " _host_s:"
						  . ( scalar keys %_host_s )
						  . " _host_u:"
						  . ( scalar keys %_host_u ) . "\n";
						print " _url_p:"
						  . ( scalar keys %_url_p )
						  . " _url_k:"
						  . ( scalar keys %_url_k )
						  . " _url_e:"
						  . ( scalar keys %_url_e )
						  . " _url_x:"
						  . ( scalar keys %_url_x ) . "\n";
						print " _waithost_e:"
						  . ( scalar keys %_waithost_e )
						  . " _waithost_l:"
						  . ( scalar keys %_waithost_l )
						  . " _waithost_s:"
						  . ( scalar keys %_waithost_s )
						  . " _waithost_u:"
						  . ( scalar keys %_waithost_u ) . "\n";
					}
					&Read_History_With_TmpUpdate(
						$lastprocessedyear,
						$lastprocessedmonth,
						$lastprocessedday,
						$lastprocessedhour,
						1,
						1,
						"all",
						( $lastlinenb + $NbOfLinesParsed ),
						$lastlineoffset,
						&CheckSum($_)
					);
					&GetDelaySinceStart(1);
					$NbOfLinesShowsteps = 1;
				}
			}
			$counterforflushtest = 0;
		}
	}    # End of loop for processing new record.
	if ($Debug) {
		debug(
			" _host_p:"
			  . ( scalar keys %_host_p )
			  . " _host_h:"
			  . ( scalar keys %_host_h )
			  . " _host_k:"
			  . ( scalar keys %_host_k )
			  . " _host_l:"
			  . ( scalar keys %_host_l )
			  . " _host_s:"
			  . ( scalar keys %_host_s )
			  . " _host_u:"
			  . ( scalar keys %_host_u ) . "\n",
			1
		);
		debug(
			" _url_p:"
			  . ( scalar keys %_url_p )
			  . " _url_k:"
			  . ( scalar keys %_url_k )
			  . " _url_e:"
			  . ( scalar keys %_url_e )
			  . " _url_x:"
			  . ( scalar keys %_url_x ) . "\n",
			1
		);
		debug(
			" _waithost_e:"
			  . ( scalar keys %_waithost_e )
			  . " _waithost_l:"
			  . ( scalar keys %_waithost_l )
			  . " _waithost_s:"
			  . ( scalar keys %_waithost_s )
			  . " _waithost_u:"
			  . ( scalar keys %_waithost_u ) . "\n",
			1
		);
		debug(
			"End of processing log file (AWStats memory cache is TmpDNSLookup="
			  . ( scalar keys %TmpDNSLookup )
			  . " TmpBrowser="
			  . ( scalar keys %TmpBrowser )
			  . " TmpOS="
			  . ( scalar keys %TmpOS )
			  . " TmpRefererServer="
			  . ( scalar keys %TmpRefererServer )
			  . " TmpRobot="
			  . ( scalar keys %TmpRobot ) . ")",
			1
		);
	}
# Save current processed break section
# If lastprocesseddate > 0 means there is at least one approved new record in log or at least one existing history file
	if ( $lastprocesseddate > 0 )
	{
	    # TODO: Do not save if we are sure a flush was just already done
		# Get last line
		seek( LOG, $lastlineoffset, 0 );
		my $line = ;
		chomp $line;
		$line =~ s/\r$//;
		if ( !$NbOfLinesParsed ) 
		{
            # TODO If there was no lines parsed (log was empty), we only update LastUpdate line with YYYYMMDDHHMMSS 0 0 0 0 0
			&Read_History_With_TmpUpdate(
				$lastprocessedyear, $lastprocessedmonth,
				$lastprocessedday,  $lastprocessedhour,
				1,                  1,
				"all", ( $lastlinenb + $NbOfLinesParsed ),
				$lastlineoffset, &CheckSum($line)
			);
		}
		else {
			&Read_History_With_TmpUpdate(
				$lastprocessedyear, $lastprocessedmonth,
				$lastprocessedday,  $lastprocessedhour,
				1,                  1,
				"all", ( $lastlinenb + $NbOfLinesParsed ),
				$lastlineoffset, &CheckSum($line)
			);
		}
	}
	if ($Debug) { debug("Close log file \"$LogFile\""); }
	close LOG || error("Command for pipe '$LogFile' failed");
	# Process the Rename - Archive - Purge phase
	my $renameok  = 1;
	my $archiveok = 1;
	# Open Log file for writing if PurgeLogFile is on
	if ($PurgeLogFile) {
		if ($ArchiveLogRecords) {
			if ( $ArchiveLogRecords == 1 ) {    # For backward compatibility
				$ArchiveFileName = "$DirData/${PROG}_archive$FileSuffix.log";
			}
			else {
				$ArchiveFileName =
				  "$DirData/${PROG}_archive$FileSuffix."
				  . &Substitute_Tags($ArchiveLogRecords) . ".log";
			}
			open( LOG, "+<$LogFile" )
			  || error(
"Enable to archive log records of \"$LogFile\" into \"$ArchiveFileName\" because source can't be opened for read and write: $!
\n"
			  );
		}
		else {
			open( LOG, "+<$LogFile" );
		}
		binmode LOG;
	}
	# Rename all HISTORYTMP files into HISTORYTXT
	&Rename_All_Tmp_History();
	# Purge Log file if option is on and all renaming are ok
	if ($PurgeLogFile) {
		# Archive LOG file into ARCHIVELOG
		if ($ArchiveLogRecords) {
			if ($Debug) { debug("Start of archiving log file"); }
			open( ARCHIVELOG, ">>$ArchiveFileName" )
			  || error(
				"Couldn't open file \"$ArchiveFileName\" to archive log: $!");
			binmode ARCHIVELOG;
			while () {
				if ( !print ARCHIVELOG $_ ) { $archiveok = 0; last; }
			}
			close(ARCHIVELOG)
			  || error("Archiving failed during closing archive: $!");
			if ($SaveDatabaseFilesWithPermissionsForEveryone) {
				chmod 0666, "$ArchiveFileName";
			}
			if ($Debug) { debug("End of archiving log file"); }
		}
		# If rename and archive ok
		if ( $renameok && $archiveok ) {
			if ($Debug) { debug("Purge log file"); }
			my $bold   = ( $ENV{'GATEWAY_INTERFACE'} ? ''    : '' );
			my $unbold = ( $ENV{'GATEWAY_INTERFACE'} ? ''   : '' );
			my $br     = ( $ENV{'GATEWAY_INTERFACE'} ? '
' : '' );
			truncate( LOG, 0 )
			  || warning(
"Warning: $bold$PROG$unbold couldn't purge logfile \"$bold$LogFile$unbold\".$br\nChange your logfile permissions to allow write for your web server CGI process or change PurgeLogFile=1 into PurgeLogFile=0 in configure file and think to purge sometimes manually your logfile (just after running an update process to not loose any not already processed records your log file contains)."
			  );
		}
		close(LOG);
	}
	if ( $DNSLookup == 1 && $DNSLookupAlreadyDone ) {
		# DNSLookup warning
		my $bold   = ( $ENV{'GATEWAY_INTERFACE'} ? ''    : '' );
		my $unbold = ( $ENV{'GATEWAY_INTERFACE'} ? ''   : '' );
		my $br     = ( $ENV{'GATEWAY_INTERFACE'} ? '
' : '' );
		warning(
"Warning: $bold$PROG$unbold has detected that some hosts names were already resolved in your logfile $bold$DNSLookupAlreadyDone$unbold.$br\nIf DNS lookup was already made by the logger (web server), you should change your setup DNSLookup=$DNSLookup into DNSLookup=0 to increase $PROG speed."
		);
	}
	if ( $DNSLookup == 1 && $NbOfNewLines ) {
		# Save new DNS last update cache file
		Save_DNS_Cache_File( \%TmpDNSLookup, "$DirData/$DNSLastUpdateCacheFile",
			"$FileSuffix" );    # Save into file using FileSuffix
	}
	if ($EnableLockForUpdate) {
		# Remove lock
		&Lock_Update(0);
		# Restore signals handler
		$SIG{INT} = 'DEFAULT';    # 2
		                          #$SIG{KILL} = 'DEFAULT';	# 9
		                          #$SIG{TERM} = 'DEFAULT';	# 15
	}
}
# End of log processing if ($UPdateStats)
#---------------------------------------------------------------------
# SHOW REPORT
#---------------------------------------------------------------------
if ( scalar keys %HTMLOutput ) {
	debug( "YearRequired=$YearRequired, MonthRequired=$MonthRequired", 2 );
	debug( "DayRequired=$DayRequired, HourRequired=$HourRequired",     2 );
	# Define the NewLinkParams for main chart
	my $NewLinkParams = ${QueryString};
	$NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)output(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i;
	$NewLinkParams =~ s/(^|&|&)framename=[^&]*//i;
	my $NewLinkTarget = '';
	if ($DetailedReportsOnNewWindows) {
		$NewLinkTarget = " target=\"awstatsbis\"";
	}
	if ( ( $FrameName eq 'mainleft' || $FrameName eq 'mainright' )
		&& $DetailedReportsOnNewWindows < 2 )
	{
		$NewLinkParams .= "&framename=mainright";
		$NewLinkTarget = " target=\"mainright\"";
	}
	$NewLinkParams =~ s/(&|&)+/&/i;
	$NewLinkParams =~ s/^&//;
	$NewLinkParams =~ s/&$//;
	if ($NewLinkParams) { $NewLinkParams = "${NewLinkParams}&"; }
	if ( $FrameName ne 'mainleft' ) {
		# READING DATA
		#-------------
		&Init_HashArray();
		# Lecture des fichiers history / reading history file
		if ( $DatabaseBreak eq 'month' ) {
			for ( my $ix = 12 ; $ix >= 1 ; $ix-- ) {
				my $stringforload = '';
				my $monthix = sprintf( "%02s", $ix );
				if ( $MonthRequired eq 'all' || $monthix eq $MonthRequired ) {
					$stringforload = 'all';    # Read full history file
				}
				elsif ( ( $HTMLOutput{'main'} && $ShowMonthStats )
					|| $HTMLOutput{'alldays'} )
				{
					$stringforload =
					  'general time';          # Read general and time sections.
				}
				if ($stringforload) {
					# On charge fichier / file is loaded
					&Read_History_With_TmpUpdate( $YearRequired, $monthix, '',
						'', 0, 0, $stringforload );
				}
			}
		}
		if ( $DatabaseBreak eq 'day' ) {
			my $stringforload = 'all';
			my $monthix       = sprintf( "%02s", $MonthRequired );
			my $dayix         = sprintf( "%02s", $DayRequired );
			&Read_History_With_TmpUpdate( $YearRequired, $monthix, $dayix, '',
				0, 0, $stringforload );
		}
		if ( $DatabaseBreak eq 'hour' ) {
			my $stringforload = 'all';
			my $monthix       = sprintf( "%02s", $MonthRequired );
			my $dayix         = sprintf( "%02s", $DayRequired );
			my $hourix        = sprintf( "%02s", $HourRequired );
			&Read_History_With_TmpUpdate( $YearRequired, $monthix, $dayix,
				$hourix, 0, 0, $stringforload );
		}
	}
	# HTMLHeadSection
	if ( $FrameName ne 'index' && $FrameName ne 'mainleft' ) {
		print "\n\n";
		my $newhead = $HTMLHeadSection;
		$newhead =~ s/\\n/\n/g;
		print "$newhead\n";
		print "\n";
	}
	# Call to plugins' function AddHTMLBodyHeader
	foreach my $pluginname ( keys %{ $PluginsLoaded{'AddHTMLBodyHeader'} } ) {
		my $function = "AddHTMLBodyHeader_$pluginname";
		&$function();
	}
	my $WIDTHMENU1 = ( $FrameName eq 'mainleft' ? $FRAMEWIDTH : 150 );
	# TOP BAN
	#---------------------------------------------------------------------
	if ( $ShowMenu || $FrameName eq 'mainleft' ) {
		HTMLTopBanner($WIDTHMENU1);
	}
	# Call to plugins' function AddHTMLMenuHeader
	foreach my $pluginname ( keys %{ $PluginsLoaded{'AddHTMLMenuHeader'} } ) {
		my $function = "AddHTMLMenuHeader_$pluginname";
		&$function();
	}
	# MENU (ON LEFT IF FRAME OR TOP)
	#---------------------------------------------------------------------
	if ( $ShowMenu || $FrameName eq 'mainleft' ) {
		HTMLMenu($NewLinkParams, $NewLinkTarget);
	}
	# Call to plugins' function AddHTMLMenuFooter
	foreach my $pluginname ( keys %{ $PluginsLoaded{'AddHTMLMenuFooter'} } ) {
		my $function = "AddHTMLMenuFooter_$pluginname";
		&$function();
	}
	# Exit if left frame
	if ( $FrameName eq 'mainleft' ) {
		&html_end(0);
		exit 0;
	}
	
# TotalVisits TotalUnique TotalPages TotalHits TotalBytes TotalHostsKnown TotalHostsUnknown
	$TotalUnique = $TotalVisits = $TotalPages = $TotalHits = $TotalBytes = 0;
	$TotalNotViewedPages = $TotalNotViewedHits = $TotalNotViewedBytes = 0;
	$TotalHostsKnown = $TotalHostsUnknown = 0;
	my $beginmonth = $MonthRequired;
	my $endmonth   = $MonthRequired;
	if ( $MonthRequired eq 'all' ) { $beginmonth = 1; $endmonth = 12; }
	for ( my $month = $beginmonth ; $month <= $endmonth ; $month++ ) {
		my $monthix = sprintf( "%02s", $month );
		$TotalHostsKnown += $MonthHostsKnown{ $YearRequired . $monthix }
		  || 0;    # Wrong in year view
		$TotalHostsUnknown += $MonthHostsUnknown{ $YearRequired . $monthix }
		  || 0;    # Wrong in year view
		$TotalUnique += $MonthUnique{ $YearRequired . $monthix }
		  || 0;    # Wrong in year view
		$TotalVisits += $MonthVisits{ $YearRequired . $monthix }
		  || 0;    # Not completely true
		$TotalPages += $MonthPages{ $YearRequired . $monthix } || 0;
		$TotalHits  += $MonthHits{ $YearRequired . $monthix }  || 0;
		$TotalBytes += $MonthBytes{ $YearRequired . $monthix } || 0;
		$TotalNotViewedPages += $MonthNotViewedPages{ $YearRequired . $monthix }
		  || 0;
		$TotalNotViewedHits += $MonthNotViewedHits{ $YearRequired . $monthix }
		  || 0;
		$TotalNotViewedBytes += $MonthNotViewedBytes{ $YearRequired . $monthix }
		  || 0;
	}
	# TotalHitsErrors TotalBytesErrors
	$TotalHitsErrors  = 0;
	my $TotalBytesErrors = 0;
	foreach ( keys %_errors_h ) {
		#		print "xxxx".$_." zzz".$_errors_h{$_};
		$TotalHitsErrors  += $_errors_h{$_};
		$TotalBytesErrors += $_errors_k{$_};
	}
# TotalEntries (if not already specifically counted, we init it from _url_e hash table)
	if ( !$TotalEntries ) {
		foreach ( keys %_url_e ) { $TotalEntries += $_url_e{$_}; }
	}
# TotalExits (if not already specifically counted, we init it from _url_x hash table)
	if ( !$TotalExits ) {
		foreach ( keys %_url_x ) { $TotalExits += $_url_x{$_}; }
	}
# TotalBytesPages (if not already specifically counted, we init it from _url_k hash table)
	if ( !$TotalBytesPages ) {
		foreach ( keys %_url_k ) { $TotalBytesPages += $_url_k{$_}; }
	}
# TotalKeyphrases (if not already specifically counted, we init it from _keyphrases hash table)
	if ( !$TotalKeyphrases ) {
		foreach ( keys %_keyphrases ) { $TotalKeyphrases += $_keyphrases{$_}; }
	}
# TotalKeywords (if not already specifically counted, we init it from _keywords hash table)
	if ( !$TotalKeywords ) {
		foreach ( keys %_keywords ) { $TotalKeywords += $_keywords{$_}; }
	}
# TotalSearchEnginesPages (if not already specifically counted, we init it from _se_referrals_p hash table)
	if ( !$TotalSearchEnginesPages ) {
		foreach ( keys %_se_referrals_p ) {
			$TotalSearchEnginesPages += $_se_referrals_p{$_};
		}
	}
# TotalSearchEnginesHits (if not already specifically counted, we init it from _se_referrals_h hash table)
	if ( !$TotalSearchEnginesHits ) {
		foreach ( keys %_se_referrals_h ) {
			$TotalSearchEnginesHits += $_se_referrals_h{$_};
		}
	}
# TotalRefererPages (if not already specifically counted, we init it from _pagesrefs_p hash table)
	if ( !$TotalRefererPages ) {
		foreach ( keys %_pagesrefs_p ) {
			$TotalRefererPages += $_pagesrefs_p{$_};
		}
	}
# TotalRefererHits (if not already specifically counted, we init it from _pagesrefs_h hash table)
	if ( !$TotalRefererHits ) {
		foreach ( keys %_pagesrefs_h ) {
			$TotalRefererHits += $_pagesrefs_h{$_};
		}
	}
# TotalDifferentPages (if not already specifically counted, we init it from _url_p hash table)
	$TotalDifferentPages ||= scalar keys %_url_p;
# TotalDifferentKeyphrases (if not already specifically counted, we init it from _keyphrases hash table)
	$TotalDifferentKeyphrases ||= scalar keys %_keyphrases;
# TotalDifferentKeywords (if not already specifically counted, we init it from _keywords hash table)
	$TotalDifferentKeywords ||= scalar keys %_keywords;
# TotalDifferentSearchEngines (if not already specifically counted, we init it from _se_referrals_h hash table)
	$TotalDifferentSearchEngines ||= scalar keys %_se_referrals_h;
# TotalDifferentReferer (if not already specifically counted, we init it from _pagesrefs_h hash table)
	$TotalDifferentReferer ||= scalar keys %_pagesrefs_h;
# Define firstdaytocountaverage, lastdaytocountaverage, firstdaytoshowtime, lastdaytoshowtime
	my $firstdaytocountaverage =
	  $nowyear . $nowmonth . "01";    # Set day cursor to 1st day of month
	my $firstdaytoshowtime =
	  $nowyear . $nowmonth . "01";    # Set day cursor to 1st day of month
	my $lastdaytocountaverage =
	  $nowyear . $nowmonth . $nowday;    # Set day cursor to today
	my $lastdaytoshowtime =
	  $nowyear . $nowmonth . "31";       # Set day cursor to last day of month
	if ( $MonthRequired eq 'all' ) {
		$firstdaytocountaverage =
		  $YearRequired
		  . "0101";    # Set day cursor to 1st day of the required year
	}
	if ( ( $MonthRequired ne $nowmonth && $MonthRequired ne 'all' )
		|| $YearRequired ne $nowyear )
	{
		if ( $MonthRequired eq 'all' ) {
			$firstdaytocountaverage =
			  $YearRequired
			  . "0101";    # Set day cursor to 1st day of the required year
			$firstdaytoshowtime =
			  $YearRequired . "1201"
			  ;    # Set day cursor to 1st day of last month of required year
			$lastdaytocountaverage =
			  $YearRequired
			  . "1231";    # Set day cursor to last day of the required year
			$lastdaytoshowtime =
			  $YearRequired . "1231"
			  ;    # Set day cursor to last day of last month of required year
		}
		else {
			$firstdaytocountaverage =
			    $YearRequired
			  . $MonthRequired
			  . "01";    # Set day cursor to 1st day of the required month
			$firstdaytoshowtime =
			    $YearRequired
			  . $MonthRequired
			  . "01";    # Set day cursor to 1st day of the required month
			$lastdaytocountaverage =
			    $YearRequired
			  . $MonthRequired
			  . "31";    # Set day cursor to last day of the required month
			$lastdaytoshowtime =
			    $YearRequired
			  . $MonthRequired
			  . "31";    # Set day cursor to last day of the required month
		}
	}
	if ($Debug) {
		debug(
"firstdaytocountaverage=$firstdaytocountaverage, lastdaytocountaverage=$lastdaytocountaverage",
			1
		);
		debug(
"firstdaytoshowtime=$firstdaytoshowtime, lastdaytoshowtime=$lastdaytoshowtime",
			1
		);
	}
	# Call to plugins' function AddHTMLContentHeader
	foreach my $pluginname ( keys %{ $PluginsLoaded{'AddHTMLContentHeader'} } )
	{
		# to add unique visitors & number of visits, by J Ruano @ CAPSiDE
		if ( $ShowDomainsStats =~ /U/i ) {
			print "$Message[11] | ";
		}
		if ( $ShowDomainsStats =~ /V/i ) {
			print "$Message[10] | ";
		}
		my $function = "AddHTMLContentHeader_$pluginname";
		&$function();
	}
	# Output individual frames or static pages for specific sections
	#-----------------------
	if ( scalar keys %HTMLOutput == 1 ) {
		if ( $HTMLOutput{'alldomains'} ) {
			&HTMLShowDomains();
		}
		if ( $HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'} ) {
			&HTMLShowHosts();
		}
		if ( $HTMLOutput{'unknownip'} ) {
			&HTMLShowHostsUnknown();
		}
		if ( $HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'} ) {
			&HTMLShowEmailSendersChart( $NewLinkParams, $NewLinkTarget );
			&html_end(1);
		}
		if ( $HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'} ) {
			&HTMLShowEmailReceiversChart( $NewLinkParams, $NewLinkTarget );
			&html_end(1);
		}
		if ( $HTMLOutput{'alllogins'} || $HTMLOutput{'lastlogins'} ) {
			&HTMLShowLogins();
		}
		if ( $HTMLOutput{'allrobots'} || $HTMLOutput{'lastrobots'} ) {
			&HTMLShowRobots();
		}
		if (   $HTMLOutput{'urldetail'}
			|| $HTMLOutput{'urlentry'}
			|| $HTMLOutput{'urlexit'} )
		{
			&HTMLShowURLDetail();
		}
		if ( $HTMLOutput{'unknownos'} ) {
			&HTMLShowOSUnknown($NewLinkTarget);
		}
		if ( $HTMLOutput{'unknownbrowser'} ) {
			&HTMLShowBrowserUnknown($NewLinkTarget);
		}
		if ( $HTMLOutput{'osdetail'} ) {
			&HTMLShowOSDetail();
		}
		if ( $HTMLOutput{'browserdetail'} ) {
			&HTMLShowBrowserDetail();
		}
		if ( $HTMLOutput{'refererse'} ) {
			&HTMLShowReferers($NewLinkTarget);
		}
		if ( $HTMLOutput{'refererpages'} ) {
			&HTMLShowRefererPages($NewLinkTarget);
		}
		if ( $HTMLOutput{'keyphrases'} ) {
			&HTMLShowKeyPhrases($NewLinkTarget);
		}
		if ( $HTMLOutput{'keywords'} ) {
			&HTMLShowKeywords($NewLinkTarget);
		}
		if ( $HTMLOutput{'downloads'} ) {
			&HTMLShowDownloads();
		}
		foreach my $code ( keys %TrapInfosForHTTPErrorCodes ) {
			if ( $HTMLOutput{"errors$code"} ) {
				&HTMLShowErrorCodes($code);
			}
		}
		# BY EXTRA SECTIONS
		#----------------------------
		HTMLShowExtraSections();
		
		if ( $HTMLOutput{'info'} ) {
			# TODO Not yet available
			print "$Center 
";
			&html_end(1);
		}
		# Print any plugins that have individual pages
		# TODO - change name, graph isn't so descriptive
		my $htmloutput = '';
		foreach my $key ( keys %HTMLOutput ) { $htmloutput = $key; }
		if ( $htmloutput =~ /^plugin_(\w+)$/ ) {
			my $pluginname = $1;
			print "$Center 
";
			my $function = "AddHTMLGraph_$pluginname";
			&$function();
			&html_end(1);
		}
	}
	# Output main page
	#-----------------
	if ( $HTMLOutput{'main'} ) {
		
		# Calculate averages
		my $max_p = 0;
		my $max_h = 0;
		my $max_k = 0;
		my $max_v = 0;
		my $average_nb = 0;
		foreach my $daycursor ($firstdaytocountaverage .. $lastdaytocountaverage )
		{
			$daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
			my $year  = $1;
			my $month = $2;
			my $day   = $3;
			if ( !DateIsValid( $day, $month, $year ) ) {
				next;
			}                 # If not an existing day, go to next
			$average_nb++;    # Increase number of day used to count
			$AverageVisits += ( $DayVisits{$daycursor} || 0 );
			$AveragePages += ( $DayPages{$daycursor}  || 0 );
			$AverageHits += ( $DayHits{$daycursor}   || 0 );
			$AverageBytes += ( $DayBytes{$daycursor}  || 0 );
		}
		if ($average_nb) {
			$AverageVisits = $AverageVisits / $average_nb;
			$AveragePages = $AveragePages / $average_nb;
			$AverageHits = $AverageHits / $average_nb;
			$AverageBytes = $AverageBytes / $average_nb;
			if ( $AverageVisits > $max_v ) { $max_v = $AverageVisits; }
			#if ($average_p > $max_p) { $max_p=$average_p; }
			if ( $AverageHits > $max_h ) { $max_h = $AverageHits; }
			if ( $AverageBytes > $max_k ) { $max_k = $AverageBytes; }
		}
		else {
			$AverageVisits = "?";
			$AveragePages = "?";
			$AverageHits = "?";
			$AverageBytes = "?";
		}
		# SUMMARY
		#---------------------------------------------------------------------
		if ($ShowSummary) {
			&HTMLMainSummary();
		}
		# BY MONTH
		#---------------------------------------------------------------------
		if ($ShowMonthStats) {
			&HTMLMainMonthly();
		}
		print "\n \n\n";
		# BY DAY OF MONTH
		#---------------------------------------------------------------------
		if ($ShowDaysOfMonthStats) {
			&HTMLMainDaily($firstdaytocountaverage, $lastdaytocountaverage,
						  $firstdaytoshowtime, $lastdaytoshowtime);
		}
		# BY DAY OF WEEK
		#-------------------------
		if ($ShowDaysOfWeekStats) {
			&HTMLMainDaysofWeek($firstdaytocountaverage, $lastdaytocountaverage, $NewLinkParams, $NewLinkTarget);
		}
		# BY HOUR
		#----------------------------
		if ($ShowHoursStats) {
			&HTMLMainHours($NewLinkParams, $NewLinkTarget);
		}
		print "\n \n\n";
		# BY COUNTRY/DOMAIN
		#---------------------------
		if ($ShowDomainsStats) {
			&HTMLMainCountries($NewLinkParams, $NewLinkTarget);
		}
		# BY HOST/VISITOR
		#--------------------------
		if ($ShowHostsStats) {
			&HTMLMainHosts($NewLinkParams, $NewLinkTarget);
		}
		# BY SENDER EMAIL
		#----------------------------
		if ($ShowEMailSenders) {
			&HTMLShowEmailSendersChart( $NewLinkParams, $NewLinkTarget );
		}
		# BY RECEIVER EMAIL
		#----------------------------
		if ($ShowEMailReceivers) {
			&HTMLShowEmailReceiversChart( $NewLinkParams, $NewLinkTarget );
		}
		# BY LOGIN
		#----------------------------
		if ($ShowAuthenticatedUsers) {
			&HTMLMainLogins($NewLinkParams, $NewLinkTarget);
		}
		# BY ROBOTS
		#----------------------------
		if ($ShowRobotsStats) {
			&HTMLMainRobots($NewLinkParams, $NewLinkTarget);
		}
		# BY WORMS
		#----------------------------
		if ($ShowWormsStats) {
			&HTMLMainWorms();
		}
		print "\n \n\n";
		# BY SESSION
		#----------------------------
		if ($ShowSessionsStats) {
			&HTMLMainSessions();
		}
		# BY FILE TYPE
		#-------------------------
		if ($ShowFileTypesStats) {
			&HTMLMainFileType($NewLinkParams, $NewLinkTarget);
		}
		# BY FILE SIZE
		#-------------------------
		if ($ShowFileSizesStats) {
			# TODO
		}
		
		# BY DOWNLOADS
		#-------------------------
		if ($ShowDownloadsStats) {
			&HTMLMainDownloads($NewLinkParams, $NewLinkTarget);
		}
		# BY PAGE
		#-------------------------
		if ($ShowPagesStats) {
			&HTMLMainPages($NewLinkParams, $NewLinkTarget);
		}
		# BY OS
		#----------------------------
		if ($ShowOSStats) {
			&HTMLMainOS($NewLinkParams, $NewLinkTarget);
		}
		# BY BROWSER
		#----------------------------
		if ($ShowBrowsersStats) {
			&HTMLMainBrowsers($NewLinkParams, $NewLinkTarget);
		}
		# BY SCREEN SIZE
		#----------------------------
		if ($ShowScreenSizeStats) {
			&HTMLMainScreenSize();
		}
		print "\n \n\n";
		# BY REFERENCE
		#---------------------------
		if ($ShowOriginStats) {
			&HTMLMainReferrers($NewLinkParams, $NewLinkTarget);
		}
		print "\n \n\n";
		# BY SEARCH KEYWORDS AND/OR KEYPHRASES
		#-------------------------------------
		if ($ShowKeyphrasesStats || $ShowKeywordsStats){
			&HTMLMainKeys($NewLinkParams, $NewLinkTarget);
		}	
		print "\n \n\n";
		# BY MISC
		#----------------------------
		if ($ShowMiscStats) {
			&HTMLMainMisc();
		}
		# BY HTTP STATUS
		#----------------------------
		if ($ShowHTTPErrorsStats) {
			&HTMLMainHTTPStatus($NewLinkParams, $NewLinkTarget);
		}
		# BY SMTP STATUS
		#----------------------------
		if ($ShowSMTPErrorsStats) {
			&HTMLMainSMTPStatus($NewLinkParams, $NewLinkTarget);
		}
		# BY CLUSTER
		#----------------------------
		if ($ShowClusterStats) {
			&HTMLMainCluster($NewLinkParams, $NewLinkTarget);
		}
		# BY EXTRA SECTIONS
		#----------------------------
		foreach my $extranum ( 1 .. @ExtraName - 1 ) {
			&HTMLMainExtra($NewLinkParams, $NewLinkTarget, $extranum);
		}
		# close the HTML page
		&html_end(1);
	}
}
else {
	print "Jumped lines in file: $lastlinenb\n";
	if ($lastlinenb) { print " Found $lastlinenb already parsed records.\n"; }
	print "Parsed lines in file: $NbOfLinesParsed\n";
	print " Found $NbOfLinesDropped dropped records,\n";
	print " Found $NbOfLinesComment comments,\n";
 	print " Found $NbOfLinesBlank blank records,\n";
	print " Found $NbOfLinesCorrupted corrupted records,\n";
	print " Found $NbOfOldLines old records,\n";
	print " Found $NbOfNewLines new qualified records.\n";
}
#sleep 10;
0;    # Do not remove this line
#-------------------------------------------------------
# ALGORITHM SUMMARY
#
# Read_Config();
# Check_Config() and Init variables
# if 'frame not index'
#	&Read_Language_Data($Lang);
#	if 'frame not mainleft'
#		&Read_Ref_Data();
#		&Read_Plugins();
# html_head
#
# If 'migrate'
#   We create/update tmp file with
#     &Read_History_With_TmpUpdate(year,month,day,hour,UPDATE,NOPURGE,"all");
#   Rename the tmp file
#   html_end
#   Exit
# End of 'migrate'
#
# Get last history file name
# Get value for $LastLine $LastLineNumber $LastLineOffset $LastLineChecksum with
#	&Read_History_With_TmpUpdate(lastyearbeforeupdate,lastmonthbeforeupdate,lastdaybeforeupdate,lasthourbeforeupdate,NOUPDATE,NOPURGE,"general");
#
# &Init_HashArray()
#
# If 'update'
#   Loop on each new line in log file
#     lastlineoffset=lastlineoffsetnext; lastlineoffsetnext=file pointer position
#     If line corrupted, skip --> next on loop
#	  Drop wrong virtual host --> next on loop
#     Drop wrong method/protocol --> next on loop
#     Check date --> next on loop
#     If line older than $LastLine, skip --> next on loop
#     So it's new line
#     $LastLine = time or record
#     Skip if url is /robots.txt --> next on loop
#     Skip line for @SkipHosts --> next on loop
#     Skip line for @SkipFiles --> next on loop
#     Skip line for @SkipUserAgent --> next on loop
#     Skip line for not @OnlyHosts --> next on loop
#     Skip line for not @OnlyUsers --> next on loop
#     Skip line for not @OnlyFiles --> next on loop
#     Skip line for not @OnlyUserAgent --> next on loop
#     So it's new line approved
#     If other month/year, create/update tmp file and purge data arrays with
#       &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_));
#     Define a clean Url and Query (set urlwithnoquery, tokenquery and standalonequery and $field[$pos_url])
#     Define PageBool and extension
#     Analyze: Misc tracker --> complete %misc
#     Analyze: Hit on favorite icon --> complete %_misc, countedtraffic=1 (not counted anywhere)
#     If (!countedtraffic) Analyze: Worms --> complete %_worms, countedtraffic=2
#     If (!countedtraffic) Analyze: Status code --> complete %_error_, %_sider404, %_referrer404 --> countedtraffic=3
#     If (!countedtraffic) Analyze: Robots known --> complete %_robot, countedtraffic=4
#     If (!countedtraffic) Analyze: Robots unknown on robots.txt --> complete %_robot, countedtraffic=5
#     If (!countedtraffic) Analyze: File types - Compression
#     If (!countedtraffic) Analyze: Date - Hour - Pages - Hits - Kilo
#     If (!countedtraffic) Analyze: Login
#     If (!countedtraffic) Do DNS Lookup
#     If (!countedtraffic) Analyze: Country
#     If (!countedtraffic) Analyze: Host - Url - Session
#     If (!countedtraffic) Analyze: Browser - OS
#     If (!countedtraffic) Analyze: Referer
#     If (!countedtraffic) Analyze: EMail
#     Analyze: Cluster
#     Analyze: Extra (must be after 'Define a clean Url and Query')
#     If too many records, we flush data arrays with
#       &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_));
#   End of loop
#
#   Create/update tmp file
#	  Seek to lastlineoffset in logfile to read and get last line into $_
#	  &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_))
#   Rename all created tmp files
# End of 'update'
#
# &Init_HashArray()
#
# If 'output'
#   Loop for each month of required year
#     &Read_History_With_TmpUpdate($YearRequired,$monthloop,'','',NOUPDATE,NOPURGE,'all' or 'general time' if not required month)
#   End of loop
#   Show data arrays in HTML page
#   html_end
# End of 'output'
#-------------------------------------------------------
#-------------------------------------------------------
# DNS CACHE FILE FORMATS SUPPORTED BY AWSTATS
# Format /etc/hosts     x.y.z.w hostname
# Format analog         UT/60 x.y.z.w hostname
#-------------------------------------------------------
#-------------------------------------------------------
# IP Format (d=decimal on 16 bits, x=hexadecimal on 16 bits)
#
# 13.1.68.3						IPv4 (d.d.d.d)
# 0:0:0:0:0:0:13.1.68.3 		IPv6 (x:x:x:x:x:x:d.d.d.d)
# ::13.1.68.3
# 0:0:0:0:0:FFFF:13.1.68.3 		IPv6 (x:x:x:x:x:x:d.d.d.d)
# ::FFFF:13.1.68.3 				IPv6
#
# 1070:0:0:0:0:800:200C:417B 	IPv6
# 1070:0:0:0:0:800:200C:417B 	IPv6
# 1070::800:200C:417B 			IPv6
#-------------------------------------------------------