#! /usr/bin/perl
exit if $ENV{IP_ADDRESS} eq '89.34.244.104';
# MS-DOS users: Uncomment the following lines and put them at the start
# of the script. Rename mkt.pl to mkt.bat and run it.
# @echo off
# perl.exe -w -x -S %0.bat
# goto END_OF_BAT

# In CGI mode, the following arguments can be passed to the script:
# 	main
#		Generate index page.
#	level:<level>
#		Generate information about a level, e.g. level:e1m1
#		Use the code field in 'levels' to identify a map.
#	player:<player>:<sort>
#		Generate player information, e.g. player:ilkka
#		Use the statpage field in 'players' to identify the person.
#		Sort can be a combination of letters "mtdy", representing
#		map, time, date, and type of demo. Default is ymtd.
#	profile:<player>
#		Generates a player's profile, provided profiles are turned
#		on and the specified player's profile is available.
#		If no player is given, the list of profiles will be generated.
#	records:<table.html>
#		Generate records table, e.g. records:runs/id.html
#		Use the output field in 'tables' to identify a table.
#	stats:<num>
#		Generate player statistics page, e.g. stats:1
#		Valid values are 1..10.
#	demostats
#		Generate demo statistics page.
#	mapstats
#		Generate map statistics page.
#	oldstats
#		Generate oldest demos page.
#	unbeatable
#		Generate unbeatable demos page.
#	marathon
#		Generate page with marathon demos.

# Actually, the separator in the arguments listed above need not be
# the colon (:). The separator char is $sepchar, see below.

use Socket;
use IO::Handle;
use strict;
my $sepchar = ":";

my $self = "";
my $gfxpath = "";
my $sdabanner = "";
my $advert = 0;
my $sortedlists = 1;
my $lastcustep = "";
my $daystats = 0;
my $playerstats = 0;
my $profilepath = "";
my @directories = ("ER", "EH", "NR", "NH");

# The following lines read history.txt and the configuration file.
# You do not need to edit this unless you want to make fundamental changes.

my %playerlist = ();
my %aliaslist = ();
my %runlist = ();
my %records = ();
my %maplist = ();
my %monthstat = ();
my @tables = ();
my $nocoop = 0;
my @unbeatlist = ();
my $allwarnings = "";
my @runtype = ("er", "eh", "nr", "nh", "mt", "co");
my @runnames = ("Easy run", "Easy 100%",
	"Nightmare run", "Nightmare 100%");
my ($lastid, $lasthip, $lastrog, $lastbb, $lastmexx, $lastpse, $lastik, $lastbl, $lastzer, $lastrde, $lastrdeb, $lastjzb, $lastpg, $lastczg07, $lastterra, $lastdaz, $lastdmsp, $lastdigs, $lastdmc, $lastdmc2, $lastdmc3);
my ($lastdopa, $lastad, $lastudob, $lastdwell1, $lastdwell2, $lasteoe, $lastpun, $lastrub, $lastsmsp, $lastsmsp2e1, $lastsmsp2e2, $lastsmsp2e3, $lastalk, $lastmg, $lastsmej, $lastsmej2, $lastelder, $lastdmd, $lasttainted);
my ($lastrm, $lastgotshun1, $lastgotshun2, $lasteod, $lastrt, $lastcoffee1, $lastcoffee2, $lastcoffee3, $lastcoffee4, $lastcoffee5, $lastcoffee6, $lastcoffee7, $lastcoffee8);
my ($lastnumber, $lasta, $lastb, $lastc, $lastd, $laste, $lastf, $lastg, $lasth, $lasti, $lastj, $lastk, $lastl, $lastm, $lastn, $lasto, $lastp, $lastq, $lastr, $lasts, $lastt, $lastu, $lastv, $lastw, $lastx, $lasty, $lastz);

chdir('/home/sda/quake');
open (FD, "config");
while (<FD>)
{
	next if (/^#/ || /^$/);
	last if (/\[players\]/);
	tr/\012\015//d;
	my ($var, $val) = split(/ *= */);
	if ($var eq "self") { $self = $val; $playerstats = 2 if ($self ne ""); }
	elsif ($var eq "gfxpath") { $gfxpath = $val; }
	elsif ($var eq "sdabanner") { $sdabanner = $val; }
	elsif ($var eq "advert") { $advert = $val; }
	elsif ($var eq "sortedlists") { $sortedlists = $val; }
	elsif ($var eq "lastcustep") { $lastcustep = $val; }
	elsif ($var eq "daystats") { $daystats = $val; }
	elsif ($var eq "playerstats") { $playerstats = $val; }
	elsif ($var eq "profilepath") { $profilepath = $val; }
	else { do_warn("unknown variable: $var"); }
}

do_warn("profilepath variable has unknown format")
	if ($profilepath !~ /^$|^http:|^file:/);

my $playercounter = 0;

# read players
while (<FD>)
{
	next if (/^#/ || /^$/);
	last if (/\[levels\]/);
	tr/\012\015//d;
	my ($name, $al, $page) = split(/:/);
	$page = "" . ++$playercounter if ($page eq "" && $playerstats > 0);
	my @alias = split(',',$al);
	my $entry = {name => $name, page => $page, runs => []};
#	do_die("doubly defined alias: $name") if (defined(%aliaslist->{$name}));
	$aliaslist{$name} = $entry;
	for my $al (@alias) {
		do_die("doubly defined alias: $al")
			if (defined($aliaslist{$al}));
		$aliaslist{$al} = $entry;
	}
	$playerlist{$name} = $entry;
}

my $mapcounter = 0;
my $custeplimit;

# read levels
while (<FD>)
{
	next if (/^#/ || /^$/);
	last if (/\[tables\]/);
	tr/\012\015//d;
	my $mapno;
	my $ma = 0;
	my $refmap = "";
	my ($name, $title, $file, $author, $url) = split(/:/,$_,5);
	if ($name =~ /%/) {
		$name =~ tr/%//d;
		$ma = 1;
	}
	do_die("doubly defined mapname: $name") if (defined($maplist{$name}));
	$file = $name if ($file eq "");
	if ($url =~ /^#(.*)/) {
		$url = "";
		$refmap = $1;
		do_die("unknown map reference: $refmap")
			if (!defined($maplist{$refmap}));
		my $list = $maplist{$refmap}->{vars};
		push @$list, ($name);
		my $len = scalar(@$list);
		$mapno = $maplist{$refmap}->{mapno} + $len/($len+1);
	} else {
		$mapno = $mapcounter++;
	}
	
	if ($name eq "id1") {
		$lastid = $mapno;
	} elsif ($name eq "hip") {
		$lasthip = $mapno;
	} elsif ($name eq "doe") {
		$lastrog = $mapno;
	} elsif ($name eq "bb") {
		$lastbb = $mapno;
	} elsif ($name eq "mexx10b") {
		$lastmexx = $mapno;
	} elsif ($name eq "pse") {
		$lastpse = $mapno;
	} elsif ($name eq "ik") {
		$lastik = $mapno;
	} elsif ($name eq "bl") {
		$lastbl = $mapno;
	} elsif ($name eq "zer") {
		$lastzer = $mapno;
	} elsif ($name eq "rde") {
		$lastrde = $mapno;
	} elsif ($name eq "rdeb") {
		$lastrdeb = $mapno;
	} elsif ($name eq "jzblue") {
		$lastjzb = $mapno;
	} elsif ($name eq "pg") {
		$lastpg = $mapno;
	} elsif ($name eq "czg07") {
		$lastczg07 = $mapno;
	} elsif ($name eq "terra") {
		$lastterra = $mapno;
	} elsif ($name eq "daz") {
		$lastdaz = $mapno;
	} elsif ($name eq "dmsp") {
		$lastdmsp = $mapno;
	} elsif ($name eq "digs01") {
		$lastdigs = $mapno;
	} elsif ($name eq "dmc") {
		$lastdmc = $mapno;
	} elsif ($name eq "dmc2") {
		$lastdmc2 = $mapno;
	} elsif ($name eq "dmc3") {
		$lastdmc3 = $mapno;
	} elsif ($name eq "dopa") {
		$lastdopa = $mapno;
	} elsif ($name eq "ad_zendar") {
		$lastad = $mapno;
	} elsif ($name eq "udob") {
		$lastudob = $mapno;
	} elsif ($name eq "dwell1") {
		$lastdwell1 = $mapno;
	} elsif ($name eq "d2end") {
		$lastdwell2 = $mapno;
	} elsif ($name eq "eoe") {
		$lasteoe = $mapno;
	} elsif ($name eq "pun") {
		$lastpun = $mapno;
	} elsif ($name eq "rub2m3") {
		$lastrub = $mapno;
	} elsif ($name eq "smsp") {
		$lastsmsp = $mapno;
	} elsif ($name eq "smsp2e1") {
		$lastsmsp2e1 = $mapno;
	} elsif ($name eq "smsp2e2") {
		$lastsmsp2e2 = $mapno;
	} elsif ($name eq "smsp2e3") {
		$lastsmsp2e3 = $mapno;
	} elsif ($name eq "alk_undead") {
		$lastalk = $mapno;
	} elsif ($name eq "mg") {
		$lastmg = $mapno;
	} elsif ($name eq "w1s1") {
		$lastsmej = $mapno;
	} elsif ($name eq "smej2s1") {
		$lastsmej2 = $mapno;
	} elsif ($name eq "eldersend") {
		$lastelder = $mapno;
	} elsif ($name eq "dmd9") {
		$lastdmd = $mapno;
	} elsif ($name eq "tainted7") {
		$lasttainted = $mapno;
	} elsif ($name eq "rm_yawning") {
		$lastrm = $mapno;
	} elsif ($name eq "gotshun1") {
		$lastgotshun1 = $mapno;
	} elsif ($name eq "gotshun2") {
		$lastgotshun2 = $mapno;
	} elsif ($name eq "eod_8") {
		$lasteod = $mapno;
	} elsif ($name eq "rt_alk3") {
		$lastrt = $mapno;
	} elsif ($name eq "coffee1") {
		$lastcoffee1 = $mapno;
	} elsif ($name eq "coffee2") {
		$lastcoffee2 = $mapno;
	} elsif ($name eq "coffee3") {
		$lastcoffee3 = $mapno;
	} elsif ($name eq "coffee4") {
		$lastcoffee4 = $mapno;
	} elsif ($name eq "e1m27_yoder2") {
		$lastcoffee5 = $mapno;
	} elsif ($name eq "e2m35_ish") {
		$lastcoffee6 = $mapno;
	} elsif ($name eq "e3m32_colossus") {
		$lastcoffee7 = $mapno;
	} elsif ($name eq "end_fw") {
		$lastcoffee8 = $mapno;
	} elsif ($name eq "4fiffy3") {
		$lastnumber = $mapno;
	} elsif ($name eq "azurette") {
		$lasta = $mapno;
	} elsif ($name eq "butcher") {
		$lastb = $mapno;
	} elsif ($name eq "czgtoxic") {
		$lastc = $mapno;
	} elsif ($name eq "dxm") {
		$lastd = $mapno;
	} elsif ($name eq "eyesock") {
		$laste = $mapno;
	} elsif ($name eq "funrun") {
		$lastf = $mapno;
	} elsif ($name eq "guard") {
		$lastg = $mapno;
	} elsif ($name eq "hwjam2_here") {
		$lasth = $mapno;
	} elsif ($name eq "ivory") {
		$lasti = $mapno;
	} elsif ($name eq "jzdoom") {
		$lastj = $mapno;
	} elsif ($name eq "ksp1") {
		$lastk = $mapno;
	} elsif ($name eq "lostwrld") {
		$lastl = $mapno;
	} elsif ($name eq "mymap") {
		$lastm = $mapno;
	} elsif ($name eq "nmth_machinery") {
		$lastn = $mapno;
	} elsif ($name eq "ouver") {
		$lasto = $mapno;
	} elsif ($name eq "pushcoag") {
		$lastp = $mapno;
	} elsif ($name eq "quakebhop2") {
		$lastq = $mapno;
	} elsif ($name eq "rwa1") {
		$lastr = $mapno;
	} elsif ($name eq "suzyhrt") {
		$lasts = $mapno;
	} elsif ($name eq "tyrcoag") {
		$lastt = $mapno;
	} elsif ($name eq "urantia") {
		$lastu = $mapno;
	} elsif ($name eq "village") {
		$lastv = $mapno;
	} elsif ($name eq "wrld11") {
		$lastw = $mapno;
	} elsif ($name eq "xnq1002") {
		$lastx = $mapno;
	} elsif ($name eq "yerass") {
		$lasty = $mapno;
	} elsif ($name eq "zooloo") {
		$lastz = $mapno;
	}

	$maplist{$name} = { title => $title, file => $file, url => $url,
		marathon => $ma, mapno => $mapno, mapinfo => "", author => $author,
		vars => [], refmap => $refmap };
	$custeplimit = $mapno if ($name eq $lastcustep);
}

# read tables
while (<FD>)
{
	next if (/^#/ || /^$/);
	last if (/\[comments\]/);
	tr/\012\015//d;
	my ($type, $title, $template, $output) = split(/:/);
	push @tables, ({type => $type, title => $title,
			template => $template, output => $output});
}

#read comments
my $comlevel = "";
my $comstr = "";
while (<FD>)
{
	next if (/^#/ || /^$/);
	tr/\015//d;
	if (s/(.*)::(.*)/$2/) {
		$maplist{$comlevel}->{mapinfo} = $comstr if ($comlevel ne "");
		$comlevel = $1;
		$comstr = "<p>";
	}
	$comstr = $comstr . $_
}

$maplist{$comlevel}->{mapinfo} = $comstr if ($comlevel ne "");
close FD;

open (FD, "history.txt");
while (<FD>)
{
	last if /^\*\*/;
}

sub typenum {
	if ($_[0] eq "er") { return 0; }
	elsif ($_[0] eq "eh") { return 1; }
	elsif ($_[0] eq "nr") { return 2; }
	elsif ($_[0] eq "nh") { return 3; }
	else {
		if ($_[0] !~ /^([en][rh])(\d)$/) {
			do_warn("unknown demo type: ".$_[0]);
			return 0;
		}
		my ($pre,$num) = ($1,$2);
		return $num*4+typenum($pre)-4;
	}
}

sub dateval {
	my $date = $_[0];
	$date =~ /(..)\.(..)\.(..)/;
	my $retval = $3*10000 + $2*100 + $1;
	$retval += 1000000 if ($3 < 90);
	return $retval;
}

my $lastlev;
my $lasttype;
my $sec = 0;
while (<FD>)
{
	my $type;
	tr/\012\015//d;
	$sec++ if /^\*/;
	next if /^$|^\*/;

	if (/\/$/)
	{
		my $lastline = $_;
		$_ = <FD>;
		tr/\012\015//d;
		$_ =~ s/[ 	]*([A-Za-z].*)/$1/;
		$_ = "$lastline$_";
	}
	my ($level, $date, $runners, $time, $other)
		= split(/  [ 	]*|	[ 	]*/);
	my $vid_link;
	if (!defined($other)) {
		$other = "";
	}
	elsif ($other =~ s/(http.*)//)
	{
		$vid_link = $1;
	}
	$level = $lastlev if ($level eq "");
	$lastlev = $level;
	if ($sec == 4 && $level !~ /^$/)
	{
		my ($skill,$maps,$subtype) = split(' ',$level);
		$subtype = "" unless (defined($subtype));
		$type = "er" if ($skill eq "Easy" && $subtype eq "");
		$type = "eh" if ($skill eq "Easy" && $subtype eq "100");
		$type = "nr" if ($skill eq "Nightmare" && $subtype eq "");
		$type = "nh" if ($skill eq "Night" && $subtype eq "100");
		$level = $maps;
	}
	next if ($other =~ /\*\*/);

	my $kills = 0;
	if ($other =~ s/\[(\d+)\]//) {
		$kills = $1;
	}

	my $unbeatable = ($other =~ s/\+\+//);

	$type = $runtype[$sec] unless ($sec == 4);
	if ($sec == 5) {
		if ($other =~ /(.*)({.*})/) {
			$type = $1;
			$other = $2;
		} else {
			$type = $other;
		}
		$type =~ tr/ *//d;
		$type = $lasttype if ($type eq "");
	}
	$lasttype = $type;
	$type =~ tr [A-Z] [a-z];

	my @names = split('/',$runners);
	for my $i (0..$#names) {
		my $al = $names[$i];

		if (!defined($aliaslist{$al})) {
			do_warn("unknown player: $al");
			my $entry = {name => $al, page => "", runs => []};
			$entry->{page} = "" . ++$playercounter
				if ($playerstats > 0);
			$aliaslist{$al} = $entry;
			$playerlist{$al} = $entry;
		}
		$names[$i] = $aliaslist{$al};
	}

	my $filename;
	my $timesecs;
	my ($min,$secs) = split(':',$time);
	$timesecs = $min*60+$secs;
	if (!defined($maplist{$level})) {
		do_warn("unknown map: $level");
		$maplist{$level} = { name => "", file => $level };
	}

	if ($other =~ /\*/) {
		$filename = "";
	} else {
		$filename = sprintf("%s_%u%02u",
				$maplist{$level}->{file},$min,$secs);
	}

	$filename .= ".dz" if ($filename);
	
	$date =~ /(..)\.(..)\.(..)/;
	my $year = ($3 ge "95" ? "19" : "20").$3;
	my $month = $2 + 0;
	if (!defined($monthstat{$year}->{$month})) {
		$monthstat{$year}->{$month} = 1;
	} else {
		$monthstat{$year}->{$month}++;
	}
	
	if (!defined($runlist{$level}->{$type})) {
		$runlist{$level}->{$type} = [];
	}

	my $ref = $runlist{$level}->{$type};
	push @$ref,({level => $level, type => $type, date => $date, record => 0,
		     filename => $filename, time => $time, seconds => $timesecs,
		     mapno => $maplist{$level}->{mapno}, kills => $kills,
		     dateval => dateval($date), unbeatable => $unbeatable,
		     typenum => typenum($type), names => \@names,
	     	     vid_link => $vid_link});
}

close FD;

foreach my $level (keys %runlist) {
	my $ref = $runlist{$level};
	my %lowest = ();
	foreach my $code (sort keys %$ref) {	
		my $list = $ref->{$code};
		my $min = 0;
		my $maxkills = 0;
		my $minrun;
		for my $run (@$list) {
			my $time = $run->{seconds};
			my $kills = $run->{kills};
			if ($min == 0 || $kills > $maxkills
				|| ($time < $min && $kills == $maxkills)) {
				($min,$maxkills) = ($time,$kills);
				$minrun = $run if ($min == $time);
			}
			my $runners = $run->{names};
			for my $player (@$runners) {
				my $ref = $player->{runs};
				push @$ref,($run);
			}
			push @unbeatlist,$run if ($run->{unbeatable});
		}

		my $normcode = $code;
		$normcode =~ tr/[0-9]//d;
		if (!defined($lowest{$normcode})
		    || $min < $lowest{$normcode}->{seconds}
		    || ($min == $lowest{$normcode}->{seconds}
		    && $minrun->{dateval} < $lowest{$normcode}->{dateval}))
		{
			$lowest{$normcode} = $minrun;	# this keeps track of fastest er/eh/nr/nh for any players, for coop comparison
			$lowest{".$code"} = $minrun;  # this keeps track of fastest in each category for 100/run comparison
			$minrun->{record} = 1;
			if ($normcode =~ /.r/)
			{	# see if the corresponding 100% is equal to or faster than this run!
				my $hcode = ".$code";
				$hcode =~ s/r/h/;
				if (defined($lowest{$hcode}) && (
					$min > $lowest{$hcode}->{seconds} ||
					($min == $lowest{$hcode}->{seconds}
					 && $minrun->{dateval} < $lowest{$hcode}->{dateval})))
				{
					$minrun->{record} = 0;
				}
			}
		}

		$records{$level}->{$code} = $minrun;
	}
}

my $fontinfo = '<font face=verdana,helvetica,arial size=2>';

my @sortedlevels = sort { $maplist{$a}->{mapno} <=>
			  $maplist{$b}->{mapno} } keys %records;

# Main program is here. Output routines are below.

if ($self ne "") {
	my @args = split($sepchar,$ENV{'QUERY_STRING'});
	my $found = 0;

	print "Content-type: text/html\n\n";

	if ($args[0] eq "main" || $args[0] eq "") {
		printmainpage();
		$found++;
	} elsif ($args[0] eq "level") {
		foreach my $level (keys %records) {
			next if ($level ne $args[1]);
			printleveltable($level);
			$found++;
		}
	} elsif ($args[0] eq "player") {
		foreach my $ref (keys %playerlist) {
		    my $runner = $playerlist{$ref};
		    next if ($runner->{page} ne $args[1]);
		    printplayerpage($runner,$args[2]);
		    $found++;
		}
	} elsif ($args[0] eq "profile" && $profilepath ne "") {
		if (scalar(@args) == 1) {
		    printprofilelist();
		    $found++;
		} else {
		    foreach my $ref (keys %playerlist) {
			my $runner = $playerlist{$ref};
			next if ($runner->{page} ne $args[1]);
			next if !-e "profiles/$runner->{page}.txt";
			printprofilepage($runner);
			$found++;
		    }
		}
	} elsif ($args[0] eq "records") {
		for my $table (@tables) {
		    next if ($table->{output} ne $args[1]);
		    printrecordtable($table);
		    $found++;
		}
	} elsif ($args[0] eq "stats") {
		next if ($args[1] < 1 || $args[1] > 10);
		if ($args[1] > 5) {
			$nocoop = 1;
			$args[1] -= 5;
		}
		computestats();
		printstats($args[1]);
		$found++;
	} elsif ($args[0] eq "demostats") {
		demostats();
		$found++;
	} elsif ($args[0] eq "mapstats") {
		mapstats();
		$found++;
	} elsif ($args[0] eq "oldstats") {
		oldestdemos();
		$found++;
	} elsif ($args[0] eq "unbeatable") {
		unbeatable();
		$found++;
	} elsif ($args[0] eq "marathon") {
		printmarathons();
		$found++;
	} elsif ($args[0] eq "daterange") {
		printdaterange($args[1]);
		$found++;
	} elsif ($args[0] eq "maplist") {
		printmaplistpage($args[1]);
		$found++;
	} elsif ($args[0] eq "warnings") {
		printwarnings();
		$found++;
	}

	if (!$found) {
		do_die("$self was called with invalid arguments.");
	}

} else {

	open(STDOUT,">index.html");
	printmainpage();

	for my $table (@tables) {
		open(STDOUT,">$table->{output}");
		printrecordtable($table);
	}
	    
	foreach my $ref (keys %playerlist) {
		my $runner = $playerlist{$ref};
		next if ($runner->{page} eq "");
		open(STDOUT,">playerinfo/$runner->{page}.html");
		printplayerpage($runner,"ymtd");
		next if (!$sortedlists);
		open(STDOUT,">playerinfo/$runner->{page}-map.html");
		printplayerpage($runner,"mytd");
		open(STDOUT,">playerinfo/$runner->{page}-date.html");
		printplayerpage($runner,"dymt");
		open(STDOUT,">playerinfo/$runner->{page}-time.html");
		printplayerpage($runner,"tymd");
	}

	if ($profilepath ne "") {
	    open(STDOUT,">profiles/index.html");
	    printprofilelist();
	    foreach my $ref (keys %playerlist) {
		my $runner = $playerlist{$ref};
		next if ($runner->{page} eq "");
		next if !-e "profiles/$runner->{page}.txt";
		open(STDOUT,">profiles/$runner->{page}.html");
		printprofilepage($runner);
	    }
	}

	foreach my $level (keys %records) {
		next if ($maplist{$level}->{refmap} ne "");
		open(STDOUT,">levelinfo/$level.html");
		printleveltable($level);
	}

	for ($nocoop = 0; $nocoop <= 1; $nocoop++) {
		computestats();
		for (my $i = 1; $i <= 5; $i++) {
		    open(STDOUT,">stats/playerstats".($i+5*$nocoop).".html");
		    printstats($i);
		}
	}
	$nocoop = 0;

	open(STDOUT,">stats/demostats.html");
	demostats();

	open(STDOUT,">stats/mapstats.html");
	mapstats();

	open(STDOUT,">stats/oldstats.html");
	oldestdemos();

	open(STDOUT,">runs/marathon.html");
	printmarathons();
}

exit 0;

# Start of output routines.
# If you want to tweak the look of the pages that mktable produces,
# here's where you should start looking.

sub do_die {
	my $msg = $_[0];

	die $msg if ($self eq "");

	my @args = split($sepchar,$ENV{'QUERY_STRING'});
	my $found = 0;

	print "<html>$msg</html>\n";
	exit 1;
}

sub do_warn {
	my $msg = $_[0];

#	warn $msg;
	$allwarnings .= $msg . "<br>\n";
}

sub printwarnings {
	print "<html>\n$allwarnings</html>\n";
}

sub printadcode {
	while (<FD>) {
		last if /<\/advert>/;
		print $_ if ($advert);
	}
	print "\n<img src=\"$sdabanner\">\n" if ($sdabanner ne "");
}

sub printlevel {
	my $levelname = $_[0];
	my $mapinfo = $_[1];
	my $linkflag = $_[2];

	if ($linkflag) {
	    print "<td>$fontinfo";
	    printlevellink($levelname,"../");
	}
	my $name = $mapinfo->{refmap};
	$name = $levelname if ($name eq "");
	print "$name";
	print "</a>" if ($linkflag);
	print " - $mapinfo->{title}"
	    if ($mapinfo->{title} ne "");
	print "</td>" if ($linkflag);
	print "\n";
}

sub printfilename {
	my $run = $_[0];
	my $mapinfo = $_[1];
	my $td = $_[2];
	my $tn = $run->{typenum};
	my $np = int($tn/4) + 1;

	print "<td>$fontinfo" if $td;
	if ($run->{filename} ne "") {
		print qq{<a href="demos/$directories[$tn&3]};
		print $np if ($np > 1);
		print qq{/$run->{filename}">$run->{time}</a>};
                if ($run->{vid_link}) {
			print qq[ <a href="$run->{vid_link}" target="_new">Video</a>];
		}

	} else {
	    print "$run->{time}";
	}
	print "</td>\n" if $td;
}

sub printplayers {
	my $run = $_[0];
	my $i = 0;
        my $runners = $run->{names};
	print "<td>$fontinfo";
	for my $player (@$runners) {
		print ", " if ($i++);
		if ($player->{page} ne "") {
		    printplayerlink($player,"../");
		} else {
		    print "$player->{name}";
		}
	}
	print "</td>\n";
}

sub printrun {
	my $lev = $_[0];
	my $type = $_[1];

	if (!defined($records{$lev}->{$type})) {
		print "<td><font color=#aaaaaa>$fontinfo--</td>\n";
		print "<td><font color=#aaaaaa>$fontinfo"."Free Space</td>\n";
	} else {
		my $run = $records{$lev}->{$type};
		printfilename($run, $maplist{$run->{level}}, 1);
		printplayers $run;
	}
}

sub printruntype {
	my $run = $_[0];
	my $mapinfo = $_[1];
	my $tn = $run->{typenum};

	if ($tn >= 4) {
		my $tmp = int($tn/4)+1;
		print "$tmp-player ";
	}
	print $runnames[$tn % 4];
	print " (Marathon)" if ($mapinfo->{marathon});
}

sub printprofilelink {
	my $player = $_[0];
	my $title = $_[1];
	return if ($profilepath eq "" || $player->{page} eq ""
			    || !-e "profiles/$player->{page}.txt");
	if ($self ne "") {
	    print "<a href=\"$self?profile$sepchar$player->{page}\">";
	} else {
	    print "<a href=\"../profiles/$player->{page}.html\">";
	}
	print "$title</a>";
}

my $sortmethod = "";
my @sortarray = ();

sub sortbykey {
	my $a = $_[0];
	my $b = $_[1];
	my $type = $_[2];

	return $a->{mapno} <=> $b->{mapno} if ($type eq "m");
	return $b->{seconds} <=> $a->{seconds} if ($type eq "t");
	return $a->{dateval} <=> $b->{dateval} if ($type eq "d");
	return $a->{typenum} <=> $b->{typenum} if ($type eq "y");
}

sub sortruns {
	sortbykey($a,$b,$sortarray[0])
	|| sortbykey($a,$b,$sortarray[1])
	|| sortbykey($a,$b,$sortarray[2])
	|| sortbykey($a,$b,$sortarray[3]);
}

sub printplayerrecs {
	my $list = $_[0];
	my $flag = $_[1];
	foreach my $run (@$list) {
		next if ($run->{record} != $flag);
		my $mapinfo = $maplist{$run->{level}};
		print "<tr>\n";
		printlevel $run->{level},$mapinfo,1;

		printfilename($run, $mapinfo, 1);

		my ($day, $month, $year) = split (/\./, $run->{date});
		$year += ($year > 95 ? 1900 : 2000);

		print "<td>$fontinfo$year-$month-$day</td>\n<td>$fontinfo";
		printruntype($run,$mapinfo);
		print "</td>\n</tr>\n";
	}
}

sub printrunbylevel {
	my $run = $_[0];
	my $mapinfo = $_[1];
	my $recordflag = $_[2];

	my ($recbeg,$recend) = ("","");
	($recbeg,$recend) = ("<b>","</b>") if ($recordflag);
	print "<tr>\n";
	printfilename($run, $mapinfo, 1);
	my ($day, $month, $year) = split (/\./, $run->{date});
	$year += ($year > 95 ? 1900 : 2000);
	print "<td>$fontinfo$recbeg$year-$month-$day";
	printf " &nbsp; (%d kills)",$run->{kills} if ($run->{kills} > 0);
	print "$recend</td>\n";
	printplayers $run;
	print "</tr>\n";
}

sub printtable {
	my $level = $_[0];
	my $type = $_[1];
	my $mapinfo = $_[2];

	my $run = $records{$level}->{$type};

	print "<br><br>\n<font face=verdana,helvetica,arial size=\"3\">\n";
	printruntype $run,$mapinfo;
	print "</font>\n";
	
	open(FF,"templates/leveltable.html");
	while (<FF>) {
		print $_
	}
	close FF;

	my $runlist = $runlist{$level}->{$type};
	for $run (reverse @$runlist) {
	    printrunbylevel($run,$mapinfo,$run->{record});
	}
	print "</table>\n";
}

sub printrecordtable {
	my $table = $_[0];

	if ($table->{type} !~ /coop/) {
		printnormaltable($table);
	} elsif ($table->{type} =~ /^coop/) {
		printcooptable($table);
	} else {
		printmadcoops($table);
	}
}

# Output runs/100 tables.

sub printnormaltable {
	my $table = $_[0];

	open(FD,"templates/$table->{template}");
	while (<FD>)
	{
	    if (/<levels/) {
		s/.*"(.*)".*/$1/;
		tr/\012\015//d;
		my @levs = split(/,/);
		for my $lev (@levs) {
		    if ($lev =~ /\*/) {
			print "\n<tr>\n<td>&nbsp;</td>\n<td>&nbsp;</td>\n";
			print "<td>&nbsp;</td>\n<td>&nbsp;</td>\n";
			print "<td>&nbsp;</td>\n</tr>\n\n";
			next;
		    }
		    if (!defined($maplist{$lev})) {
			do_warn("unknown level in table: $lev; skipping");
			next;
		    }
		    my $mapinfo = $maplist{$lev};
		    print "<tr>\n";
		    printlevel $lev,$mapinfo,1;
		    printrun($lev,{"runs"=>"er","100"=>"eh"}->{$table->{type}});
		    printrun($lev,{"runs"=>"nr","100"=>"nh"}->{$table->{type}});
		    print "</tr>\n";
	    	}
	    } elsif (/<advert>/) {
		printadcode;
	    } else {
		print $_
	    }
	}
	close FD;
}

# Output coop tables (other than madcoop).

sub printcooptable {
	my $table = $_[0];

	my $type = $table->{type};
	$type =~ s/coop-(..)/$1/;
	$type =~ s/$/2/;

	open(FD,"templates/$table->{template}");
	while (<FD>) {
		if (/<typeofruns>/) {
			print "2-player $table->{title}\n";
		} elsif (/<listofruns>/) {
		    foreach my $level (@sortedlevels) {
			next if (!defined($records{$level}->{$type}));
			next if (!$records{$level}->{$type}->{record});
			my $ref = $records{$level}->{$type};
			my $mapinfo = $maplist{$level};
			print "<tr>\n";
			printlevel $level,$mapinfo,1;
			printrun($level,$type);
			print "</tr>\n";
		    }
		} elsif (/<advert>/) {
			printadcode;
		} else {
			print $_
		}
	}
	close FD;
}

# Output madcoop table.

sub printmadcoops {
	my $table = $_[0];
	my @runtypes = ("er", "nr", "eh", "nh");

	open(FD,"templates/$table->{template}");
	while (<FD>) {
	    if (/<listofruns>/) {
		for my $i (3 .. 8) {
		    my $found = 0;
		    foreach my $level (@sortedlevels) {
		      my $ref = $records{$level};
		      for my $j (0 .. 3) {
			my $type = "$runtypes[$j]$i";
			next if (!defined($ref->{$type}));
			next if (!$ref->{$type}->{record});

			if (!$found) {
				print "<font face=verdana,helvetica,arial ";
				print "size=\"4\">$i-player runs</font>\n";
				print "<br><br>\n";
				open(FF,"templates/mctable.html");
				while (<FF>) {
					print $_
				}
			}
			$found++;
			my $mapinfo = $maplist{$level};
			print "<tr>\n";
			printlevel $level,$mapinfo,1;
			my $tcopy = $type;
			$tcopy =~ tr/[0-9]//d;
			$tcopy =~ tr [a-z] [A-Z];
			print "<td>$fontinfo$tcopy</td>\n";
			printrun($level,$type);
			print "</tr>\n";
		    } }
		    print "</table>\n<br><br><br>\n" if ($found);
		}
	    } elsif (/<advert>/) {
		printadcode;
	    } else {
	    	print $_
	    }
	}
	close FD;
}

sub printsortlink {
	my $player = $_[0];
	my $key = $_[1];

	return if (!$sortedlists || $sortmethod =~ /^\Q$key\E/);

	my $newsort = $sortmethod;
	$newsort =~ s/(.*)\Q$key\E(.*)/\Q$key\E$1$2/;
	$newsort = "" if ($self eq "" && $key eq "y");
	$newsort = "-map" if ($self eq "" && $key eq "m");
	$newsort = "-time" if ($self eq "" && $key eq "t");
	$newsort = "-date" if ($self eq "" && $key eq "d");

	if ($self ne "") {
	    print "<a href=\"$self?player$sepchar$player->{page}:$newsort\">";
	} else {
	    print "<a href=\"$player->{page}$newsort.html\">";
	}
}

sub printsortlinkend {
	my $key = $_[0];

	return if (!$sortedlists || $sortmethod =~ /^\Q$key\E/);
	print "</a>";
}

# print all demos made within a certain date range

sub printdaterange {
	my $range = $_[0];
	my ($syr, $smo, $sdy, $eyr, $emo, $edy, $day, $month, $year);
	my @demlist = (
		[[], [], [], []],	# id demos
		[[], [], [], []],	# hip demos
		[[], [], [], []],	# rog demos
		[[], [], [], []],	# custep demos
		[[], [], [], []],	# custom demos
		[[], [], [], [], []],	# marathon demos (5th type is coops)
		[[], [], [], []],	# coop demos
		[[], [], [], [], [], []],	# madcoop demos, 3-8 player
	);
	my @headlines = ("ID LEVELS", "HIPNOTIC LEVELS", "ROGUE LEVELS",
		"CUSTOM EPISODES", "CUSTOM LEVELS", "MARATHONS", "COOPS", "MAD COOPS");
	my @runtypes = ("Easy runs", "Easy 100%s", "Nightmare runs", "Nightmare 100%s", "Coops");
	my ($level, $mapinfo, $ref, $tn, $i, $runners, $player, $np, $line, $type, $run);

	if ($range =~ /^(\d\d)([01]\d)([0-3]\d)(\d\d)([01]\d)([0-3]\d)$/) {
		$syr = $1; $smo = $2; $sdy = $3;
		$eyr = $4; $emo = $5; $edy = $6;
		$syr += 100 if $syr < 90;
		$eyr += 100 if $eyr < 90;
	} else {
		do_die("invalid date range");
	}

# the @sortedlevels is just a list of the levels in the order of entry in config
# make a list that's the same except that for custom episodes, it is sorted alpha by bsp name
	my @drlevels = sort {
		($maplist{$a}->{mapno} >= $maplist{bbelief1}->{mapno} && $maplist{$a}->{mapno} <= $custeplimit &&
		$maplist{$b}->{mapno} >= $maplist{bbelief1}->{mapno} && $maplist{$b}->{mapno} <= $custeplimit) ?
			$a cmp $b : $maplist{$a}->{mapno} <=> $maplist{$b}->{mapno}
	} @sortedlevels;

	for $level (@drlevels) {
		$ref = $runlist{$level};
		foreach my $code (keys %$ref) {
			for $run (@{$ref->{$code}}) {
				($day, $month, $year) = split (/\./, $run->{date});
				$year += 100 if $year < 90;
				next if $year < $syr || $year > $eyr;
				next if $year == $syr && ($month < $smo || ($month == $smo && $day < $sdy));
				next if $year == $eyr && ($month > $emo || ($month == $emo && $day > $edy));

				$type = $run->{typenum};
				$mapinfo = $maplist{$level};
				if ($mapinfo->{marathon}) {
					push @{$demlist[5][$type > 4 ? 4 : $type]},$run;
				} elsif ($type > 7) {
					push @{$demlist[7][int($type/4) - 2]},$run;
				} elsif ($type > 3) {
					push @{$demlist[6][$type - 4]},$run;
				} elsif ($mapinfo->{mapno} > $custeplimit) {
					push @{$demlist[4][$type]},$run;
				} elsif ($mapinfo->{mapno} > $lastrog) {
					push @{$demlist[3][$type]},$run;
				} elsif ($mapinfo->{mapno} > $lasthip) {
					push @{$demlist[2][$type]},$run;
				} elsif ($mapinfo->{mapno} > $lastid) {
					push @{$demlist[1][$type]},$run;
				} else {
					push @{$demlist[0][$type]},$run;
				}
			}
		}
	}

	open(FD,"templates/daterange.html");
	while (<FD>) {
		if (/<daterange>/) {
			print '<table border=0 width="100%" cellpadding=2 cellspacing=0>';
			for $line (0 .. 7) {
				print '<tr><td bgcolor="#DBD9D9"><font face="Verdana, Arial, Helvetica" color="#212121" size=2><strong>';
				print $headlines[$line], '</strong></td></tr><tr><td><font face="Verdana, Arial, Helvetica" size=2 color="#C0C0C0"><ul>';
				for $type (0 .. $#{$demlist[$line]}) {
					if ($line == 7) {
						next if -1 == $#{$demlist[7][$type]};
						print '<li>'. (3 + $type). " player\n<ul>\n";
					} else {
						print "<li>$runtypes[$type]\n<ul>\n";
					}
					for $run (@{$demlist[$line][$type]}) {
						$level = $run->{level};
						$mapinfo = $maplist{$level};
						$ref = $mapinfo->{refmap}; 
						$tn = $run->{typenum};
						$runners = $run->{names};
						$np = (int($tn/4)+1);

						print '<li>', $run->{date}, ': ';
						printlevellink($level,"..");

						if ($ref eq "") {
							print "$level</a>";
						} else {
							print "$ref</a>";
						}

						if (($mapinfo->{marathon} && $np > 1) || $np > 2) {
							print ' (', uc $runtype[$tn%4], ')';
						}
						print ' in ';
						printfilename($run, $mapinfo, 0);
						print ' by <font color="#fdfd77">';

						$i = 0;
						for $player (@$runners) {
							if ($i++) {
								print (($i == $np ? ' &' : ','), ' <font color="#fdfd77">');
							}
							print $player->{name}, '</font>';
						}
						if ($ref ne "") {
							print ' (', lc $maplist{$level}->{title} . ')';
						}
						print "\n";
					}
					print "</ul><p>\n";
				}
			}
			print "</ul></td></tr></table>\n";
		} else {
			print;
		}
	}
	close FD;
}

# Output player information.

sub printplayerpage {
	my $runner = $_[0];
	my $records = 0;
	my $others = 0;

	open(FD,"templates/playerinfo.html");

	$sortmethod = $_[1];
	$sortmethod = "ymtd" if ($sortmethod eq "");
	$sortmethod =~ /(.)(.)(.)(.)/;
	@sortarray = ($1,$2,$3,$4);

	my $runs = $runner->{runs};
	my @list = sort sortruns @$runs;

	foreach my $run (@list) {
		$records++ if ($run->{record});
		$others++ if (!$run->{record});
	}

	while (<FD>)
	{
	    if (/<playername>/) {
		print "$runner->{name}\n";
	    } elsif (/<profile>/) {
		printprofilelink $runner, "Profile";
	    } elsif (/<records>/) {
		printplayerrecs(\@list,1);
	    } elsif (/<oldruns>/) {
		printplayerrecs(\@list,0);
	    } elsif (/<recstart>/) {
		print "<!--" if (!$records);
	    } elsif (/<recend>/) {
		print "-->" if (!$records);
	    } elsif (/<oldstart>/) {
		print "<!--" if (!$others);
	    } elsif (/<oldend>/) {
		print "-->" if (!$others);
	    } elsif (/<stats>/) {
		printf "%u record%s, %u old run%s\n",
			$records, ($records == 1)? "" : "s",
			$others, ($others == 1)? "" : "s";
	    } elsif (/<sort=(.)>/) {
		printsortlink($runner,$1);
	    } elsif (/(.*)<\/sort=(.)>/) {
		print $1;
		printsortlinkend($2);
	    } elsif (/<advert>/) {
		printadcode;
	    } else {
		print $_
	    }
	}
	close FD;
}

# Output level information.

sub printvartable  {
	my $level = $_[0];

	my $ref = $records{$level};
	my $mapinfo = $maplist{$level};
	
	open(FV,"templates/levelvar.html");
	print "<a name=\"$level\">\n";
	while (<FV>) {
	    if (/<levelname>/) {
		print $mapinfo->{title}."\n";
	    } elsif (/<comments>/) {
		print $mapinfo->{mapinfo}
	    } elsif (/<records>/) {
		foreach my $code (sort {typenum($a)<=>typenum($b)} keys %$ref) {
			printtable $level,$code,$mapinfo;
		}
	    } else {
		print $_
	    }
	}
	close FV;
}

sub printleveltable  {
	my $level = $_[0];

	my $ref = $records{$level};
	my $mapinfo = $maplist{$level};
	
	open(FD,"templates/levelinfo.html");
	while (<FD>) {
	    if (/<levelname>/) {
		printlevel $level,$mapinfo,0;
	    } elsif (/<levelauthor>/) {
		print "</font><br>by $mapinfo->{author}";
	    } elsif (/<url>/) {
if (-e "maps/$_[0].zip") { $mapinfo->{url} = "maps/$_[0].zip"; }
		next if ($mapinfo->{url} eq "");
		print "$fontinfo\n";
		print "<a href=\"$mapinfo->{url}\">Download</a>\n";
		print "</font>\n";
	    } elsif (/<comments>/) {
		print $mapinfo->{mapinfo}
	    } elsif (/<records>/) {
		foreach my $code (sort {typenum($a)<=>typenum($b)} keys %$ref) {
			printtable $level,$code,$mapinfo;
		}
	    } elsif (/<variants>/) {
		my $list = $mapinfo->{vars};
		foreach my $var (@$list) {
			printvartable $var;
		}
	    } elsif (/<advert>/) {
		printadcode;
	    } else {
		print $_
	    }
	}
	close FD;
}

# Print main index page.

sub printtablelink {
	my $tablename = $_[0];
	my $title = $_[1];

	print "[<a href=\"";
	if ($self ne "") {
		print "$self?records$sepchar$tablename"
	} else {
		print "$tablename";
	}
	print "\">$title</a>]\n";
}

sub printplayerlink {
	my $player = $_[0];
	my $prefix = $_[1];

	print "<a href=\"";
	if ($self ne "") {
		print "$self?player$sepchar$player->{page}";
	} else {
		print "${prefix}playerinfo/$player->{page}.html";
	}
	print "\">$player->{name}</a>";
}

sub printlevellink {
	my $code = $_[0];
	my $prefix = $_[1];
	my $anchor = "";

	if ($maplist{$code}->{refmap} ne "") {
		$anchor = "#".$code;
		$code = $maplist{$code}->{refmap};
	}

	print "<a href=\"";
	if ($self ne "") {
		print "$self?level$sepchar$code$anchor";
	} else {
		print "${prefix}levelinfo/$code.html$anchor";
	}
	print "\">";
}

sub printmaplistpage {
	my $sort = $_[0];
	my @sorttype = ("type", "filename", "map title", "author");
	open(FD,"templates/maplist.html");
	while (<FD>) {
		if (/<sort>/) {
			print $sorttype[$sort];
		} elsif (/<list>/) {
			my $list;
			if ($sort == 0) {
				$list = \@sortedlevels;
			} else {
				my @temp;
				if ($sort == 1) {
					@temp = sort { $a cmp $b } @sortedlevels;
				} elsif ($sort == 2) {
					@temp = sort { $maplist{$a}->{title} cmp $maplist{$b}->{title} } @sortedlevels;
				} else {
					@temp = sort { $maplist{$a}->{author} cmp $maplist{$b}->{author} } @sortedlevels;
				}
				$list = \@temp;
			}			
			foreach my $level (@$list) {
				my $mapinfo = $maplist{$level};
				next if ($mapinfo->{refmap} ne "");
				print "<tr><td>";
				printlevellink $level,"";
				print "$level</a></td><td>$mapinfo->{title}</td><td>$mapinfo->{author}</td></tr>\n";
			}
		} else {
			print;
		}
	}
	close FD;
}

sub printmainpage {

my $linecount = 0;
    open(FD,"templates/main.html");
    while (<FD>) {
	
	$linecount++;

	if (/<listoftables>/) {
	    print "<h3>Runs demos</h3>\n";
	    for my $table (@tables) {
		next if ($table->{type} ne "runs");
		printtablelink $table->{output}, $table->{title};
	    }
	    print "<br><br><br>\n";
	    print "<h3>100% demos</h3>\n";
	    for my $table (@tables) {
		next if ($table->{type} ne "100");
		printtablelink $table->{output}, $table->{title};
	    }
	    print "<br><br><br>\n";
	    print "<h3>Cooperative demos</h3>\n";
	    for my $table (@tables) {
		next if ($table->{type} !~ /coop/);
		printtablelink $table->{output}, $table->{title};
	    }
	    print "<br><br><br>\n";
	    print "<h4><a href=\"";
	    if ($self ne "") {
		print "$self?marathon";
	    } else {
		print "runs/marathon.html";
	    }
	    print "\">Marathon demos</a></h4>\n";
	    print "<br>\n";
	} elsif (/Player/ && $playerstats == 2) {
	    while (<FD>) {
		    last if /<p>/;
	    }
	} elsif (/<listofplayers>/) {
	    foreach my $ref (sort keys %playerlist) {
		my $runner = $playerlist{$ref};
		next if ($runner->{page} eq "");
		print "[";
		printplayerlink $runner,"";
		print "]\n";
	    }
	    print "<br><br><br>\n";
	} elsif (/<listofmaps>/) {
	    foreach my $level (@sortedlevels) {
		    next if ($maplist{$level}->{refmap} ne "");
		    print "[";
		    printlevellink $level,"";
		    print "$level</a>]\n";
		    print '<center><font face=verdana,helvetica,arial size="5">Custom Episodes</font></center>'
			if ($maplist{$level}->{mapno} == $lastrog);
		    print '<center><font face=verdana,helvetica,arial size="5">Custom Levels</font></center>'
			if ($maplist{$level}->{mapno} == $lastcoffee8);
		    print '<p>'
			if ($maplist{$level}->{mapno} == $lastid ||
				$maplist{$level}->{mapno} == $lasthip ||
				$maplist{$level}->{mapno} == $lastrog ||
				$maplist{$level}->{mapno} == $lastbb ||
				$maplist{$level}->{mapno} == $lastmexx ||
				$maplist{$level}->{mapno} == $lastpse ||
				$maplist{$level}->{mapno} == $lastik ||
				$maplist{$level}->{mapno} == $lastbl ||
				$maplist{$level}->{mapno} == $lastzer ||
				$maplist{$level}->{mapno} == $lastrde ||
				$maplist{$level}->{mapno} == $lastrdeb ||
				$maplist{$level}->{mapno} == $lastjzb ||
				$maplist{$level}->{mapno} == $lastpg ||
				$maplist{$level}->{mapno} == $lastczg07 ||
				$maplist{$level}->{mapno} == $lastterra ||
				$maplist{$level}->{mapno} == $lastdaz ||
				$maplist{$level}->{mapno} == $lastdmsp ||
				$maplist{$level}->{mapno} == $lastdigs ||
				$maplist{$level}->{mapno} == $lastdmc ||
				$maplist{$level}->{mapno} == $lastdmc2 ||
				$maplist{$level}->{mapno} == $lastdmc3 ||
				$maplist{$level}->{mapno} == $lastdopa ||
				$maplist{$level}->{mapno} == $lastad ||
				$maplist{$level}->{mapno} == $lastudob ||
				$maplist{$level}->{mapno} == $lastdwell1 ||
				$maplist{$level}->{mapno} == $lastdwell2 ||
				$maplist{$level}->{mapno} == $lasteoe ||
				$maplist{$level}->{mapno} == $lastpun ||
				$maplist{$level}->{mapno} == $lastrub ||
				$maplist{$level}->{mapno} == $lastsmsp ||
				$maplist{$level}->{mapno} == $lastsmsp2e1 ||
				$maplist{$level}->{mapno} == $lastsmsp2e2 ||
				$maplist{$level}->{mapno} == $lastsmsp2e3 ||
				$maplist{$level}->{mapno} == $lastalk ||
				$maplist{$level}->{mapno} == $lastmg ||
				$maplist{$level}->{mapno} == $lastsmej ||
				$maplist{$level}->{mapno} == $lastsmej2 ||
				$maplist{$level}->{mapno} == $lastelder ||
				$maplist{$level}->{mapno} == $lastdmd ||
				$maplist{$level}->{mapno} == $lasttainted ||
				$maplist{$level}->{mapno} == $lastrm ||
				$maplist{$level}->{mapno} == $lastgotshun1 ||
				$maplist{$level}->{mapno} == $lastgotshun2 ||
				$maplist{$level}->{mapno} == $lasteod ||
				$maplist{$level}->{mapno} == $lastrt ||
				$maplist{$level}->{mapno} == $lastcoffee1 ||
				$maplist{$level}->{mapno} == $lastcoffee2 ||
				$maplist{$level}->{mapno} == $lastcoffee3 ||
				$maplist{$level}->{mapno} == $lastcoffee4 ||
				$maplist{$level}->{mapno} == $lastcoffee5 ||
				$maplist{$level}->{mapno} == $lastcoffee6 ||
				$maplist{$level}->{mapno} == $lastcoffee7 ||
				$maplist{$level}->{mapno} == $lastcoffee8 ||
				$maplist{$level}->{mapno} == $lastnumber||
				$maplist{$level}->{mapno} == $lasta ||
				$maplist{$level}->{mapno} == $lastb ||
				$maplist{$level}->{mapno} == $lastc ||
				$maplist{$level}->{mapno} == $lastd ||
				$maplist{$level}->{mapno} == $laste ||
				$maplist{$level}->{mapno} == $lastf ||
				$maplist{$level}->{mapno} == $lastg ||
				$maplist{$level}->{mapno} == $lasth ||
				$maplist{$level}->{mapno} == $lasti ||
				$maplist{$level}->{mapno} == $lastj ||
				$maplist{$level}->{mapno} == $lastk ||
				$maplist{$level}->{mapno} == $lastl ||
				$maplist{$level}->{mapno} == $lastm ||
				$maplist{$level}->{mapno} == $lastn ||
				$maplist{$level}->{mapno} == $lasto ||
				$maplist{$level}->{mapno} == $lastp ||
				$maplist{$level}->{mapno} == $lastq ||
				$maplist{$level}->{mapno} == $lastr ||
				$maplist{$level}->{mapno} == $lasts ||
				$maplist{$level}->{mapno} == $lastt ||
				$maplist{$level}->{mapno} == $lastu ||
				$maplist{$level}->{mapno} == $lastv ||
				$maplist{$level}->{mapno} == $lastw ||
				$maplist{$level}->{mapno} == $lastx ||
				$maplist{$level}->{mapno} == $lasty ||
				$maplist{$level}->{mapno} == $lastz);
	    }
	    print "<br><br><br>\n";
	} elsif (/<listofstats>/) {
	    print "<h3>Player comparison with coop demos, sorted by</h3>\n[";
	    printplayerstatslink("name","",1); print "]\n[";
	    printplayerstatslink("records","",2); print "]\n[";
	    printplayerstatslink("date of first demo","",3); print "]\n[";
	    printplayerstatslink("date of last demo","",4); print "]\n[";
	    printplayerstatslink("number of demos","",5); print "]\n";
	    print "<h4>Player comparison without coop demos, sorted by</h4>\n[";
	    printplayerstatslink("name","",6); print "]\n[";
	    printplayerstatslink("records","",7); print "]\n[";
	    printplayerstatslink("date of first demo","",8); print "]\n[";
	    printplayerstatslink("date of last demo","",9); print "]\n[";
	    printplayerstatslink("number of demos","",10); print "]\n";
	    print "<br><br><br>\n<h3>Other</h3>\n[";
	    if ($profilepath ne "") {
		printf "<a href=\"%s\">Player profiles</a>]\n[",
			($self ne "")? "$self?profile" : "profiles/index.html";
	    }
	    printstatslink("Demo statistics", "", "demo");
	    print "]\n[";
	    if ($profilepath ne "") {
		printf "<a href=\"%s\">Unbeatable demos</a>]\n[",
			($self ne "")? "$self?unbeatable" : "profiles/index.html";
	    }
	    printstatslink("Oldest demos", "", "old");
	    print "]\n<br>\n";
	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_
	}
    }
    close FD;
}

# Print player statistics pages

my %statlist;
my $stat_overall_records;
my $stat_overall_total;

sub computestats {

    %statlist = ();
    $stat_overall_records = 0;
    $stat_overall_total = 0;

    foreach my $ref (sort keys %playerlist)
    {
	my $runner = $playerlist{$ref};
	my $runs = $runner->{runs};
	my @list = sort sortruns @$runs;

	my ($records, $total) = (0, 0);
	my ($er, $eh, $nr, $nh) = (0, 0, 0, 0); 
	my ($id, $hip, $rog, $cep, $cus) = (0, 0, 0, 0, 0);
	my ($normal, $coop, $mad) = (0, 0, 0);
	my $mindate = "2222-12-31"; my $maxdate = "1990-01-01";

	foreach my $run (@list) {

		my $type = $run->{type};
		if ($type =~ /(\d)/) {
			next if ($nocoop);
			($1 > 2) ? $mad++ : $coop++;
		} else {
			$normal++
		}

		$total++;
		$records++ if ($run->{record});
		if ($runner == $run->{names}[0]) {
			$stat_overall_total++;
			$stat_overall_records++ if ($run->{record});
		}

		my ($day, $month, $year) = split (/\./, $run->{date});
		$year = ($year ge "90"? "19" : "20").$year;
		my $cdate = "$year-$month-$day";
		$mindate = $cdate if ($cdate lt $mindate);
		$maxdate = $cdate if ($cdate gt $maxdate);

		my $map = $maplist{$run->{level}}->{mapno};
		if ($map <= $lastid) { $id++ }
		elsif ($map <= $lasthip) { $hip++ }
		elsif ($map <= $lastrog) { $rog++ }
		elsif ($map <= $custeplimit) { $cep++ }
		else { $cus++ }

		if ($type =~ /er/) { $er++ }
		elsif ($type =~ /eh/) { $eh++ }
		elsif ($type =~ /nr/) { $nr++ }
		elsif ($type =~ /nh/) { $nh++ }
	}

	next if ($total == 0);

	my $entry = { name => $runner->{name}, records => $records,
		      mindate => $mindate, maxdate => $maxdate, total => $total,
		      er => $er, eh => $eh, nr => $nr, nh => $nh, id => $id,
		      hip => $hip, rog => $rog, cep => $cep, cus => $cus,
		      normal => $normal, mad => $mad, coop => $coop };
	$statlist{$runner->{name}} = $entry;
    }

}

sub printgraphic {
	my $name = $_[1];
	my $width = int ($_[2] * 100 / $_[3]) || 1;

	return if !$_[2];
	print "<img src=\"";
	if ($self ne "") {
		print "$gfxpath";
	} else {
		print "../graphics/"
	}
	print "$name.gif\" width=$width height=15 alt=\"";
	print "$_[0]: " unless ($_[0] eq "");
	print "$width% ($_[2] demo";
	if ($_[2] > 1) { print "s)\">" } else { print ")\">" }
}

sub printplayerstatslink {
	my $name = $_[0];
	my $prefix = $_[1];
	my $i = $_[2];

	print "<a href=\"";
	if ($self ne "") {
		print "$self?stats$sepchar$i";
	} else {
		print "${prefix}stats/playerstats$i.html";
	}
	print "\">$name</a>";
}

sub printstats {
	my $sorttype = $_[0];
	my @columns = ( "<br>Rank", "<br>Playername", "Current<br>records",
			"First<br>demo", "Last<br>demo", "Total<br>demos", 
			"<font color=\"0033CC\">ER</font> " .
			"<font color=\"003399\">EH</font> " .
			"<font color=\"b20000\">NR</font> " .
			"<font color=\"8b0000\">NH</font>",
			"<font color=\"e0dc00\">id</font> "  .
			"<font color=\"e38d02\">Hip</font> " .
			"<font color=\"b20000\">Rog</font><br> " .
			"<font color=\"811d53\">CustEp</font> "  .
			"<font color=\"52009b\">Cust</font>",
			"<font color=\"0033cc\">Norm</font> " .
			"<font color=\"52009b\">Coop</font> "  .
			"<font color=\"811d53\">Mad</font>" );
	my @sortstring = ( "playername", "number of current records",
			   "date of first demo", "date of last demo",
			   "number of total demos" );
	my $sublen = $daystats? 10 : 7;

	open(FD,"templates/playerstats.html");
	while (<FD>) {
	    if (/<type>/) {
		print "Sorted by $sortstring[$sorttype-1]";
	    }
	    elsif (/<header>/) {
		for (my $i = 0; $i <= $#columns; $i++) {
			next if (($i == 8) && $nocoop);
			print "<td";
			print " align=left" if ($i == 1);
			print " width=115" if ($i > 5);
			print ">$fontinfo<b>";
			if ($i == $sorttype || $i == 0 || $i > 5) {
				print "$columns[$i]";
			} elsif ($nocoop) {
				printplayerstatslink($columns[$i],"../",$i+5);
			} else {
				printplayerstatslink($columns[$i],"../",$i);
			}
			print "</b></td>\n";
		}
	    }
	    elsif (/<stats>/)
	    {
		my @sortedstats;
		if ($sorttype == 1)
		{
		    @sortedstats = sort {
			$statlist{$a}->{name} cmp $statlist{$b}->{name}
		    } keys %statlist;
		}
		elsif ($sorttype == 2)
		{
		    @sortedstats = sort {
		       $statlist{$b}->{records} <=> $statlist{$a}->{records}
			|| $statlist{$a}->{name} cmp $statlist{$b}->{name}
		    } keys %statlist;
		}
		elsif ($sorttype == 3)
		{
		    @sortedstats = sort {
		       $statlist{$a}->{mindate} cmp $statlist{$b}->{mindate}
			|| $statlist{$a}->{name} cmp $statlist{$b}->{name}
		    } keys %statlist;
		}
		elsif ($sorttype == 4)
		{
		    @sortedstats = sort {
		       $statlist{$b}->{maxdate} cmp $statlist{$a}->{maxdate}
			|| $statlist{$a}->{name} cmp $statlist{$b}->{name}
		    } keys %statlist;
		}
		elsif ($sorttype == 5)
		{
		    @sortedstats = sort {
			$statlist{$b}->{total} <=> $statlist{$a}->{total}
			 || $statlist{$a}->{name} cmp $statlist{$b}->{name}
		    } keys %statlist;
		}

		my $rank;
		my $prevrow = 0;
		for (my $i=0; $i <= $#sortedstats; $i++) {
		    my $entry = $statlist{$sortedstats[$i]};
		    my $name = $entry->{name};

			next if ($name  =~ /Too many people/);

			if ($sorttype == 2) {
				$rank = $i + 1 if ($entry->{records} != $prevrow);
				$prevrow = $entry->{records};
			} elsif ($sorttype == 5) {
				$rank = $i + 1 if ($entry->{total} != $prevrow);
				$prevrow = $entry->{total};
			} else { $rank = $i + 1; }

		    print "<tr bgcolor=\"505050\" align=center>\n<td>$rank</td>\n<td align=left>";
		    if ($playerlist{$name}->{page} eq "") {
			print $name;
		    } else {
			printplayerlink($playerlist{$name}, "../");
		    }

		    print "</td>\n";
		    print "<td>".$entry->{records}."</td>\n";
		    printf "<td>%s</td>\n",substr($entry->{mindate},0,$sublen);
		    printf "<td>%s</td>\n",substr($entry->{maxdate},0,$sublen);
		    print "<td>".$entry->{total}."</td>\n<td>";

		    my $total = $entry->{total};
		    printgraphic("ER","blue",$entry->{er},$total);
		    printgraphic("EH","darkblue", $entry->{eh}, $total);
		    printgraphic("NR","red", $entry->{nr}, $total);
		    printgraphic("NH","darkred", $entry->{nh}, $total);
		    print "</td>\n<td>";

		    printgraphic("id","yellow",$entry->{id},$total);
		    printgraphic("Hipnotic","orange",$entry->{hip},$total);
		    printgraphic("Rogue","red",$entry->{rog},$total);
		    printgraphic("Custom Ep","purple",$entry->{cep},$total);
		    printgraphic("Custom","purple2",$entry->{cus},$total);

		    if (!($nocoop)) {
			print "</td>\n<td>";
			printgraphic("Normal","blue",$entry->{normal},$total);
			printgraphic("Coop","purple2",$entry->{coop},$total);
			printgraphic("MadCoop","purple",$entry->{mad},$total);
		    }
		    print "</td>\n</tr>\n\n";
		}	
		print "<tr align=center bgcolor=\"808080\">\n";
		print "<td><b>Sum</b></td>\n";
		print "<td>&nbsp;</td>\n";
		print "<td><b>$stat_overall_records</b></td>\n";
		print "<td>&nbsp;</td>\n<td>&nbsp;</td>\n";
		print "<td><b>$stat_overall_total";
		print "</b></td>\n<td>&nbsp;</td>\n<td>&nbsp;</td>\n";
		print "<td>&nbsp;</td>" unless $nocoop;
		print "</tr>\n\n";

	    } elsif (/<advert>/) {
		printadcode;
	    } else {
		print $_
	    }
	}
	close FD;

}

sub printstatslink {
	my $name = $_[0];
	my $prefix = $_[1];
	my $i = $_[2];

	print "<a href=\"";
	if ($self ne "") {
		print "$self?$i"."stats";
	} else {
		print "${prefix}stats/$i"."stats.html";
	}
	print "\">$name</a>";
}

sub printnumber {
	my $number = $_[0];
	my $str = $_[1];
	my $bgcolor = $_[2];

	print $bgcolor? "<td bgcolor=\"$bgcolor\"" : "<td";
	print " title=\"$str\"" if ($number && !$bgcolor);
	print $number? ">$fontinfo<b>$number</b>" : ">$fontinfo 0";
	print "</td>\n";
}

sub printgraphic2 {
	my $name = $_[0];
	my $width = int($_[1]*100/$_[2]);
	my $min = int($_[1]/60);
	my $sec = $_[1]%60;

	print "<td><img src=\"";
	if ($self ne "") {
		print "$gfxpath"
	} else {
		print "../graphics/"
	}
	print "$name.gif\" width=$width height=15 ";
	printf "alt=\"%u:%02u (%u%%)\"></td>\n", $min, $sec, $width;
}

sub demostats {
    my @runtypes = ("er", "eh", "nr", "nh", "er2", "eh2", "nr2", "nh2");

    open(FD,"templates/demostats.html");
    while (<FD>) {
	if (/<emptyslots>/) {
	    my @empty = ();
	    my @estr = ();
	    foreach my $level (sort keys %maplist) {
		my $ref = $records{$level};
		next if (($maplist{$level}->{marathon} == 1)
		  || ($level =~ /^e1m7|^hipend|^pgexit|^shafted|^dmc3m8|^udobend|^finale|^end_ionous|^sm215_riktoi|^sm215_scythe|^explorejam2_pulsar|^e4m36_spoot3|^jokejam_ssw|^ej3_iyago|^ej3_madscientist|^ej3_colossus/)
		  || ($level =~ /^e1m3_chocohearts|^e3m2_grashuriza|^e4m10_chocohearts|^e1m21_spoot3|^e2m2_4lt2|^e3m11_riktoi2|^e4m1_newhouse|^e4m7_4lt|^end_fw|^ej3_brain|^rgcastle|^ej3_recycledoj|^ej3_bizz|^rmx_rj/)
		  || ($level =~ /^explorejam1_pulsar|^explorejam1_sock|^ej3_cc|^tcj_iyago|^ej3_aesop/)
		  || ($maplist{$level}->{refmap} ne ""));
		for my $i (0 .. 7) {
		    if (!defined($ref->{$runtypes[$i]})) {
			my $cat;
			if ($i < 4) {
				$cat = 0
			} elsif ($maplist{$level}->{mapno} <= $lastid) {
				$cat = 1
			} elsif ($maplist{$level}->{mapno} <= $lasthip) {
				$cat = 2
			} else {
				next
			}
			$empty[$cat][$i%4]++;
			if (!defined($estr[$cat][$i%4])) {
				$estr[$cat][$i%4] = $level
			} else {
				$estr[$cat][$i%4] .= ", ".$level
			}
		   }
		}
	    }

	    #my @rows = ("Single", "Coop id1", "Coop Hip");
	    my @rows = ("Total");
	    my @total = ();
	    for my $i (0 .. 0) {
		print '<tr align=center bgcolor="505050">';
		print '<td align=center bgcolor="808080">';
		print "$fontinfo<b>$rows[$i]</b></td>\n";

		my $total = 0;
		for my $j (0 .. 3) {
		    if (!defined($empty[$i][$j])) { $empty[$i][$j] = 0 }
		    if (!defined($estr[$i][$j])) { $estr[$i][$j] = "" }
		    $total += $empty[$i][$j];
		    $total[$j] += $empty[$i][$j];
		    printnumber($empty[$i][$j], $estr[$i][$j], 0); 
		}

		printnumber ($total, "", "770000");
		print "</tr>\n\n";
	    }    

	} elsif (/<development>/) {

	    my @levels = qw/e1m1 e1m2 e1m3 e1m4 e1m5 e1m6 e1m7 e1m8
		e2m1 e2m2 e2m3 e2m4 e2m5 e2m6 e2m7 e3m1 e3m2 e3m3
		e3m4 e3m5 e3m6 e3m7 e4m1 e4m2 e4m3 e4m4 e4m5 e4m6
		e4m7 e4m8 end/;
	    my @counter = ();
	    my @seconds = ();
	    my @date = ();

	    for my $i (0 .. 3) {
		for (my $j = 0; $j < @levels; $j++) {
		    $counter[$j][$i] = 0;
		    my $level = $levels[$j];
		    my $runlist = $runlist{$level}->{$runtype[$i]};

		    foreach my $run (@$runlist) {
			$counter[$j][$i]++;
			$seconds[$j][$i][$counter[$j][$i]] = $run->{seconds};
			my ($day, $month, $year) = split (/\./,$run->{date});
			$year = (($year ge "90")? "19" : "20").$year;
			my $date = ($year*12) + $month - 1;
			$date[$j][$i][$counter[$j][$i]] = $date;
		    }
		} 
	    }

	    my @timesum = ();
	    my @first = ();
	    my ($month, $year) = (localtime)[4,5];
	    my $currentdate = (($year+1900)*12) + $month;

	    for (my $date = $currentdate; $date > 23970; $date--) {
		for my $i (0 .. 3) {
		    next if (defined($first[$i]));

		    for (my $j = 0; $j < @levels; $j++) {
			next if (($i == 1 || $i == 3) && $j == 6);

			while ($date[$j][$i][$counter[$j][$i]] > $date) {
			    $counter[$j][$i]--;
			    if ($counter[$j][$i] <= 0) {
				$first[$i] = $date | 1;
				goto label;
			    }
            }
			$timesum[$date][$i] += $seconds[$j][$i][$counter[$j][$i]];
		    }
		    label:
		}
	    } 

	    my @colors = ("blue", "darkblue", "red", "darkred");
	    for (my $i = 23984; $i <= $currentdate; $i += 12) {
		my $year = int ($i/12);
		my $month = $i%12 + 4; 
		print '<tr bgcolor="505050">';
		printf "<td align=center>$fontinfo$year</td>\n";

		for my $j (0 .. 3) {
		    if ($first[$j] < $i) {
			printgraphic2($colors[$j], $timesum[$i][$j],
						   $timesum[$first[$j]+25][$j]);
		    } else {
			print "<td></td>\n";  
		    }
		}
		print "</tr>\n";
	    }

	} elsif (/<permonth>/) {

	    my @mnames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
			  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");

	    for my $year (sort keys %monthstat) {
		my $yeartotal = 0;
		my $yearmax = 0;
		for my $month (1 .. 12) {
		    $monthstat{$year}->{$month} = 0
			    if (!defined($monthstat{$year}->{$month}));
		    my $number = $monthstat{$year}->{$month};
		    $yeartotal += $number;
		    $yearmax = $number if ($number > $yearmax);
		}

		print "<table width=420>\n";
		print '<tr bgcolor="808080">';
		print "<td colspan=12>Year: $year ($yeartotal demos)</tr>\n";

		print "<tr bgcolor=\"505050\" align=center>\n";
		for my $month (1 .. 12) {
		    print "<td>$fontinfo$mnames[$month-1]</td>\n"
		}
		print "</tr>";

		print "<tr bgcolor=\"505050\" align=center valign=bottom>\n";
		for my $month (1 .. 12) {
		    my $number = $monthstat{$year}->{$month};
		    if (!$number) { printf("<td>&nbsp;</td>\n"); next; }
		    printf "<td height=%u><img src=\"", $yearmax/2+5;
		    print (($self eq "")? "../graphics/" : "$gfxpath");
		    printf "darkred.gif\" width=20 height=%u>", ($number+1)/2;
		    print "</td>\n";
		}

		print "</tr>\n<tr bgcolor=\"505050\" align=center>\n";
		for my $month (1 .. 12) {
		    my $number = $monthstat{$year}->{$month};
		    print "<td width=35>$fontinfo$number</td>\n"
		}
		print "</tr>\n</table><br>\n";
	    }

	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_;
	}
    }
    close FD;
}

sub mapstats {
    my %levellist = ();
    foreach my $level (keys %maplist) {
	next if ($maplist{$level}->{marathon});
	next if $level eq "pgexit";
	next if $level eq "udobend";
	next if $level eq "finale";
	next if $level eq "end_ionous";
	next if $level eq "sm215_riktoi";
	next if $level eq "sm215_scythe";
	next if $level eq "explorejam2_pulsar";
	next if $level eq "e1m3_chocohearts";
	next if $level eq "e3m2_grashuriza";
	next if $level eq "e4m10_chocohearts";
	next if $level eq "e1m21_spoot3";
	next if $level eq "e2m2_4lt2";
	next if $level eq "e3m11_riktoi2";
	next if $level eq "e4m1_newhouse";
	next if $level eq "e4m7_4lt";
	next if $level eq "e4m36_spoot3";
	next if $level eq "end_fw";
	next if $level eq "jokejam_ssw";\
	next if $level eq "ej3_brain";
	next if $level eq "rgcastle";
	next if $level eq "ej3_iyago";
	next if $level eq "ej3_recycledoj";
	next if $level eq "ej3_bizz";
	next if $level eq "ej3_madscientist";
	next if $level eq "ej3_colossus";
	next if $level eq "explorejam1_pulsar";
	next if $level eq "explorejam1_sock";
	next if $level eq "ej3_cc";
	next if $level eq "tcj_iyago";
	next if $level eq "ej3_aesop";
	next if $level eq "rmx_rj";
	my $code;
	my $number = 0;
	for my $i (0 .. 3) {
	    my $runlist = $runlist{$level}->{$runtype[$i]};
	    if (defined($runlist)) {$number += @$runlist;}
	    for (my $j = 2; $j <= 8; $j++) {
		my $runlist = $runlist{$level}->{"$runtype[$i]$j"};
		if (defined($runlist)) { $number += @$runlist; }
	    }
	}
	$code = $maplist{$level}->{refmap};
	$code = $level if ($code eq "");
	$levellist{$code} = {level => $code, number => 0}
		if (!defined($levellist{$code}));
	$levellist{$code}->{number} += $number;
    }

    my @sortedlevels = sort {
	$levellist{$a}->{number} <=> $levellist{$b}->{number}
    } keys %levellist;

    open(FD,"templates/mapstats.html");
    while (<FD>) {
	if (/<most>/) {
	    for (my $i = $#sortedlevels; $i > $#sortedlevels-15; $i--) {
		my $ref = $levellist{$sortedlevels[$i]};
		my $mapinfo = $maplist{$ref->{level}};

		print "<tr bgcolor=\"505050\">\n";
		print "<td align=center>$fontinfo";
		print "".($#sortedlevels-$i+1).".</td>\n";
		printlevel ($ref->{level}, $mapinfo, 1);
		print "<td align=center>$fontinfo$ref->{number}</td>\n";
		print "</td>\n</tr>\n\n";
	    }
	} elsif (/<nonid>/) {
	    my $j;
	    for (my $i = $#sortedlevels, $j = 0 ; $j < 15; $i--) {
		my $ref = $levellist{$sortedlevels[$i]};
		my $mapinfo = $maplist{$ref->{level}};

		next if ($maplist{$ref->{level}}->{mapno} <= $lastid);
		print "<tr bgcolor=\"505050\">\n";
		print "<td align=center>$fontinfo";
		print "".($#sortedlevels-$i+1).".</td>\n";
		printlevel ($ref->{level}, $mapinfo, 1);
		print "<td align=center>$fontinfo$ref->{number}</td>\n";
		print "</td>\n</tr>\n\n";
		$j++;
	    }
	} elsif (/<least>/) {
	    for (my $i = 0; $i < 15; $i++) {
		my $ref = $levellist{$sortedlevels[$i]};
		my $mapinfo = $maplist{$ref->{level}};

		print "<tr bgcolor=\"505050\">\n";
		print "<td align=center>$fontinfo".($i+1).".</td>\n";
		printlevel ($ref->{level}, $mapinfo, 1);
		print "<td align=center>$fontinfo$ref->{number}</td>\n";
		print "</td>\n</tr>\n\n";
	    }
	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_;
	}
    }
    close FD;
}

sub printmarathondemo {
	my $lev = $_[0];
	my $type = $_[1];
	my $printall = $_[2];
	my $isdefined = defined($records{$lev}->{$type});

	return if ((!$isdefined || !$records{$lev}->{$type}->{record}) && !$printall);

	my $mapinfo = $maplist{$lev};
	print "<tr>\n";

	if ($type =~ /er/ || !$printall) {
		printlevel $lev,$mapinfo,1;
	} else {
		print "<td>&nbsp;</td>\n";
	}
	print "<td>$fontinfo" . uc $type . "</td>\n";
	printrun $lev,$type;
	print "</tr>\n";
}

sub printmarathons {
	open(FD,"templates/marathon.html");
	while (<FD>)
	{
	    if (/<levels/) {
		s/.*levels(.*) "(.*)".*/$2/;
		my $suffix = $1;
		tr/\012\015//d;
		my @levs = split(/,/);

		for my $lev (@levs) {
		    my $printall = 0;
		    if ($lev =~ /(.*)\*/) {
			$lev = $1;
			$printall = 1;
		    }
		    if (!defined($maplist{$lev})) {
			do_warn("unknown level in table: $lev; skipping");
			next;
		    }
		    printmarathondemo $lev, "er$suffix", $printall;
		    printmarathondemo $lev, "eh$suffix", $printall;
		    printmarathondemo $lev, "nr$suffix", $printall;
		    printmarathondemo $lev, "nh$suffix", $printall;
		    print "<tr><td colspan=4>&nbsp;</td></tr>" if $printall;
	    	}

	    } elsif (/<advert>/) {
		printadcode;
	    } else {
		print $_
	    }
	}
	close FD;
}

sub oldestdemos {

    my %datelist = ();
    foreach my $level (keys %maplist) {
	my $ref = $records{$level};
	next if ($maplist{$level}->{marathon} == 1);
	next if ($maplist{$level}->{refmap} ne "");

	for (my $i = 0; $i < 4; $i++) {
	    next if (!defined($ref->{$runtype[$i]}));
	    next if ($ref->{$runtype[$i]}->{unbeatable});
	    next if (!$ref->{$runtype[$i]}->{record});
	    my $date = $ref->{$runtype[$i]}->{date};
	    my ($day, $month, $year) = split (/\./, $date);

	    $year = (($year ge "90")? "19" : "20").$year;
	    $date = "$year-$month-$day";
	    my $no = 0; 
	    my $date2;

	    do {
		$no++;
		$date2 = $date."0"x(3 - length ($no)).$no;
	    } until (!(defined($datelist{$date2})));
	    $datelist{$date2} = $ref->{$runtype[$i]};
	}
    }

    my @sorteddates = sort keys %datelist;

    open(FD,"templates/oldest.html");

    while (<FD>) {
	if (/<oldestrecords>/) {

	    for (my $i = 0; $i < 100; $i++) {	# adjust length of output here
		my $run = $datelist{$sorteddates[$i]};
		my $mapinfo = $maplist{$run->{level}};

		print "<tr>\n";
		print "<td align=center>$fontinfo".($i+1).".</td>\n";
		printlevel $run->{level},$mapinfo,1;
		printfilename($run, $mapinfo, 1);
		my ($day, $month, $year) = split (/\./, $run->{date});
		$year += ($year > 95 ? 1900 : 2000);
		print "<td>$fontinfo$year-$month-$day</td>\n";
		printplayers ($run);
		print "<td>$fontinfo";
		printruntype ($run, $mapinfo);
		print "</td>\n</tr>\n\n";
	    }

	} elsif (/<oldestidrecords>/) {

	    my $j = 0;
	   
	    for (my $i = 0; $j < 20; $i++) {	# adjust length of output here
		my $run = $datelist{$sorteddates[$i]};

		my $map = $run->{level};
		next if ($map !~ /^e\dm\d|^end\b|^ep\d|id1/);
		next if $map =~ /^e\dm\drmx/;
		next if $map eq 'e4m7u';
		next if $map eq 'e2m10';
		next if $map =~ /^e5/;

		$j++;
		my $mapinfo = $maplist{$run->{level}};
		print "<tr>\n";
		print "<td align=center>$fontinfo".($j).".</td>\n";
		printlevel $run->{level},$mapinfo,1;
		printfilename($run, $mapinfo, 1);
		my ($day, $month, $year) = split (/\./, $run->{date});
		$year += ($year > 95 ? 1900 : 2000);
		print "<td>$fontinfo$year-$month-$day</td>\n";
		printplayers ($run);
		print "<td>$fontinfo";
		printruntype ($run, $mapinfo);
		print "</td>\n</tr>\n\n";
	    }

	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_;
	}
    }
    close FD;
}

sub unbeatable {

    my %datelist = ();
    foreach my $level (keys %maplist) {
	my $ref = $records{$level};
	next if ($maplist{$level}->{marathon} == 1);
	next if ($maplist{$level}->{refmap} ne "");

	for (my $i = 0; $i < 4; $i++) {
	    next if (!defined($ref->{$runtype[$i]}));
	    next if ($ref->{$runtype[$i]}->{unbeatable});
	    next if (!$ref->{$runtype[$i]}->{record});
	    my $date = $ref->{$runtype[$i]}->{date};
	    my ($day, $month, $year) = split (/\./, $date);

	    $year = (($year ge "90")? "19" : "20").$year;
	    $date = "$year-$month-$day";
	    my $no = 0; 
	    my $date2;

	    do {
		$no++;
		$date2 = $date."0"x(3 - length ($no)).$no;
	    } until (!(defined($datelist{$date2})));
	    $datelist{$date2} = $ref->{$runtype[$i]};
	}
    }

    my @sorteddates = sort keys %datelist;

    open(FD,"templates/unbeatable.html");

    while (<FD>) {
	if (/<unbeatable>/) {

	    my $i = 0;
	    @sortarray = ("d","m","y","t");

	    for my $run (sort sortruns @unbeatlist) {
		my $mapinfo = $maplist{$run->{level}};

		print "<tr>\n";
		print "<td align=center>$fontinfo".(++$i).".</td>\n";
		printlevel $run->{level},$mapinfo,1;
		printfilename($run, $mapinfo, 1);
		my ($day, $month, $year) = split (/\./, $run->{date});
		$year += ($year > 95 ? 1900 : 2000);
		print "<td>$fontinfo$year-$month-$day</td>\n";
		printplayers ($run);
		print "<td>$fontinfo";
		printruntype ($run, $mapinfo);
		print "</td>\n</tr>\n\n";
	    }

	} elsif (/<unbeatableidrecords>/) {

	    my $i = 0;
	    @sortarray = ("d","m","y","t");

	    for my $run (sort sortruns @unbeatlist) {
		my $map = $run->{level};
		next if ($map !~ /^e\dm\d$|^end\b|^ep\d|id1/);
		next if $map =~ /^e5/;

		my $mapinfo = $maplist{$run->{level}};

		print "<tr>\n";
		print "<td align=center>$fontinfo".(++$i).".</td>\n";
		printlevel $run->{level},$mapinfo,1;
		printfilename($run, $mapinfo, 1);
		my ($day, $month, $year) = split (/\./, $run->{date});
		$year += ($year > 95 ? 1900 : 2000);
		print "<td>$fontinfo$year-$month-$day</td>\n";
		printplayers ($run);
		print "<td>$fontinfo";
		printruntype ($run, $mapinfo);
		print "</td>\n</tr>\n\n";
	    }

	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_;
	}
    }
    close FD;
}

sub printprofilelist {

    open(FD,"templates/profilelist.html");
    while (<FD>) {
	if (/<listofprofiles>/) {
	    my $found = 0;
	    print "<table width=100%><tr>";
	    foreach my $ref (sort keys %playerlist) {
		my $runner = $playerlist{$ref};
		next if !-e "profiles/$runner->{page}.txt";
		print "<td width=50%><center><font face=verdana,helvetica,arial size=2>";
		printprofilelink $runner, $runner->{name};
		print "</td>\n";
		$found++;
	      print "</tr><tr>" if ($found % 2 == 0)
	    }
	    print "</tr></table></ul>\n";
	    print "no profiles found\n" if !$found;
	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_
	}
    }
    close FD;
}

sub picurl {
	my $filename = $_[0];
	my $exists = 0;




	if ($profilepath =~ /^file:/) {
		my $retname = "profiles/$filename.jpg";
		return (-e $retname)? "$retname" : "";
	} elsif ($profilepath =~ /^http:\/\/([^\/]*)\/(.*)/) {
		socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname("tcp"));
		connect(SOCK, sockaddr_in(80,inet_aton($1)));
		SOCK->autoflush(1);
		print SOCK "HEAD /$2/$filename.jpg HTTP/1.0\r\n\r\n";
		while (<SOCK>) {
			$exists = 1 if (/200 OK/);
		}
		close (SOCK);
		return $exists? "$profilepath/$filename.jpg" : "";
	}

	return "";
}

sub printprofilepage {
    my $ignore = 1;
    my $acode = "";
    my %answers = ();
    my $runner = $_[0];

    open(FD,"profiles/$runner->{page}.txt");
    while (<FD>) {
	next if /^\/\//;
	$ignore = 1 if /^Q[\w]+:/;
	if (s/^A([\w]+)://) {
	    $ignore = 0;
	    $acode = $1;
	    $answers{$acode} = $_;
	    next;
	}
	next if $ignore;
	$answers{$acode} .= "<br>$_";
    }
    close FD;

    open(FD,"templates/playerprofile.html");
    while (<FD>) {
	if (/(.*)<playername>(.*)/) {
	    print "$1$runner->{name}$2";
	} elsif (/<playerimage>/) {
	    my $pic = picurl($runner->{page});
	    while (<FD>) {
		last if /<\/playerimage>/;
		next if $pic eq "";
		if (/(.*)<imagefile>(.*)/) {
		   printf "%s%s%s", $1, $pic, $2;
		} else {
		    print $_
		}
	    }
	} elsif (/<playerlink>/) {
 	    print "<a href=\"";
	    if ($self ne "") {
		print "$self?player$sepchar$runner->{page}";
	    } else {
		print "../playerinfo/$runner->{page}.html";
	    }
	    print "\">Demos</a>\n";
	} elsif (/(.*)<answer A([\w]+)>(.*)/) {
	    $answers{$2} = "" if !defined($answers{$2});
	    printf "%s%s%s", $1, $answers{$2}, $3;
	} elsif (/<advert>/) {
	    printadcode;
	} else {
	    print $_
	}
    }
    close FD;
}

__END__
:END_OF_BAT
