#!/usr/bin/perl use CGI qw(:standard); use strict; ########################################################## # # event constants # my $THIS_PROGRAM_ADDRESS = url(); my $RESULT_INDEX_FILE_HEADER = "resindexhead.html"; my $RESULT_INDEX_FILE_FOOTER = "resindexfoot.html"; my $RESULT_INDEX_FILE = "../resindex.html"; my $RACE_INDEX_FILE="./availableraces.txt"; my $REDBLOCK_GIF="redblock.gif"; my $END_CREDIT_LOGO =""; my $END_CREDIT_LINK = "www.joelee.co.uk"; my $END_CREDIT_AUTHOR = ""; my $AVAILABLE_BACK_COLOR="#eeddff"; my $FORM_BACK_COLOR=="white"; my $FORM_BORDER_COLOR = "blue"; ########################################################## # # variables # my $NumberOfLinesToPrint = 200; my @MaleAgeCount = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); my @FemaleAgeCount = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); my @BaseFileContents; my ($HisPace,$DistanceMiles,$DistanceKm,$HisName,$HisClub,$HisTime,$HisAge,$HisSex,$HisCode,$AgeGroup,$AgeBand); my ($PosInRace,$PosInSelectedRange,$PosInAgeGroup,$PosInSex,$NumberInBand); my ($PosInMaleUnder40s,$PosInFemaleUnder35s,$TotalMales,$TotalFemales); my ($ResPerPage,$FromAge,$ToAge,$FirstResult,$LastResult); my ($Sex,$PrevButton,$NextButton,$PageNumber); my ($distance,$units); my ($Event); ########################################################## # # print st or nd or th or rd according to the parameter # sub PrintTh { my ($ThisNumber)=@_; my $LastDigit = $ThisNumber % 10 ; my $Teens = $ThisNumber % 100 ; if ($Teens == 11 || $Teens == 12 || $Teens == 13) { print "th"; } elsif ($LastDigit == 1) { print "st"; } elsif ($LastDigit == 2) { print "nd"; } elsif ($LastDigit == 3) { print "rd"; } else { print "th"; } } ########################################################## # # print page header # sub printHeader { print "content-type: text/html\n\n"; print <<"ENDHEADER"; Race results selection ENDHEADER } ########################################################## # # Print the top section before the result table # sub PrintTopMessages { } ########################################################## # # set up the output table # sub OutputTableHeader { print <<"ENDOFTABLEHEADER"; \n ENDOFTABLEHEADER } ########################################################## # # compute the runner's speed # sub ShowPace { my ($thistime,$secs,$mins,$hrs,$thissecs,$PaceMile,$PaceKm); if ($HisTime ne "
" && $DistanceMiles>0) { $thistime='000000'.$HisTime; # ensure it has hrs,mins,secs $thistime=~ s/://g; $thistime=~ s/\.//g; # print "thistime=$thistime\n"; $thistime=substr $thistime,-6; # print "\nthistime=$thistime\n"; $secs=$thistime % 100; # print "secs=$secs\n"; $thistime=($thistime-$secs)*0.01; # print "thistime=$thistime\n"; $mins=$thistime % 100; # print "mins=$mins\n"; $hrs=($thistime-$mins)*0.01; # print "hrs=$hrs\n"; $thissecs=$hrs * 3600 + $mins*60 + $secs; # print "thissecs=$thissecs\n"; $PaceMile=$thissecs / $DistanceMiles; $PaceKm=$thissecs / $DistanceKm; # print "pacemile=$PaceMile, pacekm=$PaceKm\n\n"; printf "%dm%02ds\n"; } ########################################################## # # close the output table # sub OutputTableFooter { print "
pos in
selected
range
pos
in
race
pos in
age group
pos in
sex
name club time mins/mile mins/km
",$PaceMile / 60, $PaceMile % 60; printf "%dm%02ds",$PaceKm / 60, $PaceKm % 60; } else { print "

"; } } ########################################################## # # send the current line to the user # sub OutputThisLine { # force table cells to contain something.... if (not $HisName) { $HisName="
"; } if (not $HisClub) { $HisClub="
"; } if (not $HisTime) { $HisTime="
"; } if ($HisAge eq 0) # we don't want to print 0 - leave the cell blank instead { $HisAge="
"; } print "
$PosInSelectedRange" ; # print race position print "$PosInRace" ; PrintTh($PosInRace); # print the position in their own 5 year age group print "$PosInAgeGroup" ; PrintTh($PosInAgeGroup); if ($HisSex eq "M" && $HisAge<40) { print " u/40M"; } elsif ($HisSex ne "M" && $HisAge<35) { print " u/35L"; } else { print " ${HisSex}$AgeBand"; } # print position in that Sex print "$PosInSex" ; PrintTh($PosInSex); print " $HisSex"; print "$HisName"; #print "$HisSex"; #print "$HisAge"; print "$HisClub"; print "$HisTime"; ShowPace(); print "
\n"; } ########################################################## # # Print the end section after the result table # sub PrintEndMessages { } ########################################################## # # print bottom of page footer # sub PrintBottom { print <<"ENDFOOTER";

$END_CREDIT_AUTHOR
$END_CREDIT_LOGO
$END_CREDIT_LINK

ENDFOOTER } ########################################################## # # use the current line we've read from the result file # sub UseThisLineOrNot { $AgeGroup = int (($HisAge +0.1) / 5); # which element of the AgeGroup list, add 0.1 to force real division to err on the high side $AgeBand = $HisAge - ($HisAge % 5); # convert eg 44 to 40 and 61 to 60 (round down to nearest 5 year band if ($HisSex eq "M") { $PosInSex = ++$TotalMales ; @MaleAgeCount[$AgeGroup] ++; if ($HisAge<40) { $PosInAgeGroup = ++$PosInMaleUnder40s; } else { $PosInAgeGroup = @MaleAgeCount[$AgeGroup]; } } else { $PosInSex = ++$TotalFemales ; @FemaleAgeCount[$AgeGroup] ++; if ($HisAge<35) { $PosInAgeGroup = ++$PosInFemaleUnder35s; } else { $PosInAgeGroup = @FemaleAgeCount[$AgeGroup]; } } # now count position in the selected sex and age range if ($HisAge >= $FromAge && $HisAge <=$ToAge && ($HisSex eq $Sex || $Sex eq "B" ) ) { $PosInSelectedRange ++ ; if ($PosInSelectedRange>=$FirstResult && $NumberOfLinesToPrint-- > 0) { OutputThisLine(); } } } ########################################################## # # Read the file and process each line # sub PrintResultFile { $NumberOfLinesToPrint = $ResPerPage; my ($FileName) = @_; my (@ResultFile); if (not open (RESULT_FILE, "<$FileName")) { print "Sorry, the file you requested cannot be found\n"; } else { @ResultFile = ; # load in all records OutputTableHeader(); foreach my $thisline (@ResultFile) { ($PosInRace,$HisName,$HisSex,$HisAge,$HisClub,$HisTime,$HisCode)=split(/,/ , $thisline); # split out the line if ($PosInRace==0) { $distance=$HisName; $units=$HisSex; if ($distance eq "M"){$distance=26.2;} if ($distance eq "H"){$distance=13.1;} if ($units eq "M") { $DistanceMiles=$distance; $DistanceKm=$distance * 1.609; } else { $DistanceKm=$distance; $DistanceMiles=$distance/1.609; } # print "Distance=$DistanceMiles miles, $DistanceKm km
\n"; } else { # lines may not have sex or age embedded in them so set them to default values if (not $HisSex) { $HisSex="M"; # default is always Male unless specifically told it's a Lady } if (not ($HisSex eq "M")) # deal with sex=F { $HisSex="L"; } if (not $HisAge) { $HisAge=0; } UseThisLineOrNot(); } } OutputTableFooter(); } } ########################################################## # # Open a file, and print everything in it either to the # OutFileName, or to STDOUT if no OutFileName. # # If $EndPoint exists, stop printing when a line # is reached. sub PrintFile { my ($EndPoint,$InFileName,$OutFileName)=@_; # load in the parameters $EndPoint = "\n"; # add in the newline and comments which will be read from the file if (not open(BASEFILE, "<$InFileName")) { print "\nSorry, I cannot find the file $InFileName\n"; @BaseFileContents = (""); } else { @BaseFileContents = ; # read all the input file close (BASEFILE); if ($OutFileName) { if (not open(OUTPUTFILE, ">$OutFileName")) { print "\nSorry, there is a problem creating the file $OutFileName\n"; print "Contents are listed here...\n"; } else { select OUTPUTFILE; } } # print either to the OutFileName or to STDERR foreach my $ThisLine (@BaseFileContents) { $ThisLine =~ s/raceresults.cgi/raceresults.pl/; print $ThisLine; last if ($ThisLine eq $EndPoint); # finish when the end marker is reached } # close the output and return to STDOUT if we were writing to a file if ($OutFileName) { close(OUTPUTFILE); select STDOUT; # return to default print mode } } } ########################################################## # # print out the available race result calendar by looking # at the index file which is in the form: # # selectable,filelocation,Month,Race Description # # print it to the OutFileName if this exists, otherwise print # it to the STDERR # sub PrintAvailableRaces { my ($OutFileName) = @_; # load in the parameter if it exists if ($OutFileName) # we want to append to the file if we are writing to a file { if (not open(OUTPUTFILE, ">>$OutFileName")) { print "Sorry, there is a problem appending to the file $OutFileName\n"; } else { select OUTPUTFILE; } } my $Nraces = 0; if (not open(AVAILABLE_RACE_FILE, "$RACE_INDEX_FILE") ) { print "Sorry, there are no available races to search through\n"; } else { print <<"ENDAVAILTABLETOP"; \n
Select the race to view ENDAVAILTABLETOP my @AvailableRaces = ; # read all the entries in the index my $LastMonth="nomonth"; # force the first entry to print the month my $LastYear="noyear"; foreach my $ThisRace (@AvailableRaces) { my ($Selectable, $ThisLocation, $ThisDay, $ThisMonth, $ThisYear, $ThisTitle) = split (/,/ , $ThisRace) ; # extract each field of the current index line if (($ThisMonth ne $LastMonth)or($ThisYear ne $LastYear)) # start a new table heading { print <<"ENDRACEINFO";
$ThisMonth $ThisYear ENDRACEINFO $LastMonth = $ThisMonth; $LastYear = $ThisYear; } # print "$ThisDay : "; if ($Selectable ne "Y") # just print the normal link address to the file { print <<"ENDLINKPRINT"; $ThisTitle
ENDLINKPRINT } else # run the results cgi program and pass the link address into it as a parameter { # the dot before $ThisLocation ensures that we come out of the CGI-LOCAL directory back to the root # since all locations in the index are relative to the root www.joelee.co.uk/ and the CGI runtime # program is in www.joelee.co.uk/cgi-local/ print <<"ENDSELECTPRINT"; $ThisTitle
ENDSELECTPRINT } } print "
\n"; } if ($OutFileName) { sele2ct STDOUT; close(OUTPUTFILE); } } ########################################################## # # Recreate the results index file from the available races # by adding the race calendar to the standard index file # sub CreateAndSendResultsIndex { print "content-type: text/html\n\n"; PrintFile("noend",$RESULT_INDEX_FILE_HEADER, $RESULT_INDEX_FILE); # load the basic index information PrintAvailableRaces($RESULT_INDEX_FILE); # add in the race calendar PrintFile("noend",$RESULT_INDEX_FILE_FOOTER, ">".$RESULT_INDEX_FILE); # append the footer (the function already has one > ) PrintFile("noend",$RESULT_INDEX_FILE); # send the new file contents to STDOUT } ########################################################## # # print out the option and select it if the value is the # the selected value # sub PrintSelectedSex { my ($ThisSexLetter,$ThisSex,$SelectedSex)=@_; print "\n"; } ########################################################## # # print out the option and select it if the value is the # the selected value # sub PrintSelectedNumber { my ($ThisAge,$SelectedAge)=@_; print "$ThisAge\n"; } ########################################################## # # print out the form # sub PrintSelectionForm { my $ThisAgeBand; print <<"ENDOPTIONSLIST1";
Choose which results to view
which sex from age to age
How many results per page
jump to the end to select further pages
ENDOPTIONSLIST5 } ########################################################## # # print the header to show which results are being displayed # sub PrintResultHeader { my ($SexHeader, $AgeHeader); if ($Sex eq "M") { $SexHeader="Results for Men"; } elsif ($Sex eq "B") { $SexHeader="All Results"; } else { $SexHeader="Results for Ladies"; } if ($FromAge == 0 && $ToAge >= 99) { $AgeHeader = "- All Ages"; } elsif ($FromAge >0 && $ToAge >=99) { $AgeHeader = "over $FromAge"; } elsif ($FromAge == 0 && $ToAge < 99) { $AgeHeader = "under $ToAge"; } else { $AgeHeader = "age $FromAge to $ToAge"; } print <<"ENDRESULTHEADER";

$SexHeader $AgeHeader : position $FirstResult to $LastResult

ENDRESULTHEADER } ########################################################## # # # sub PrintPageButtons { my $NoOfPages=int($PosInSelectedRange/$ResPerPage); my $i; if ($PosInSelectedRange%$ResPerPage) { $NoOfPages += 1; } if ($NoOfPages>1) { print <<"ENDOFOPENTABLE";
Select Page Number
ENDOFOPENTABLE for ($i=1;$i<=$NoOfPages;$i++) { print <<"ENDOFPAGEBUTTONS"; ENDOFPAGEBUTTONS } print <<"ENDOFCLOSETABLE";
ENDOFCLOSETABLE } } ########################################################## #- # print the graph of the number of competitors in each # age group # sub PrintAgeGroupGraph { my $TotNotVets; my $TotalInRace; my $BandIndex; my $BandWidth; my ($BandLowAge,$BandHighAge); my $LastNonZeroBand; $TotalInRace = $TotalMales + $TotalFemales; if ($TotalInRace >0) { print "
Number finishing in each age group out of the $TotalInRace finishers in the race
\n"; print "\n"; #************************************************ # draw the graph for the men #************************************************ $TotNotVets =0; for ($BandIndex=0; $BandIndex<=7; $BandIndex++) { $TotNotVets += $MaleAgeCount[$BandIndex]; } $BandWidth = int ($TotNotVets / $TotalInRace * 500); # 100% is 500 pixels wide print "\n"; # find the last band with anyone in it $LastNonZeroBand = 19; while ($LastNonZeroBand>8 && $MaleAgeCount[$LastNonZeroBand] == 0) { $LastNonZeroBand--; } # now do 5year bands from 40 to 95 for ($BandIndex=8; $BandIndex<=$LastNonZeroBand; $BandIndex++) { $BandLowAge = ($BandIndex-8)*5 + 40; $BandHighAge = $BandLowAge + 4; $NumberInBand = $MaleAgeCount[$BandIndex]; $BandWidth = int ($NumberInBand / $TotalInRace * 500); # 100% is 500 pixels wide print "\n"; } } #************************************************ # draw the graph for the ladies #************************************************ $TotNotVets =0; for ($BandIndex=0; $BandIndex<=6; $BandIndex++) { $TotNotVets += $FemaleAgeCount[$BandIndex]; } $BandWidth = int ($TotNotVets / $TotalInRace * 500); # 100% is 500 pixels wide print "\n"; # find the last band with anyone in it $LastNonZeroBand = 19; while ($LastNonZeroBand>7 && $FemaleAgeCount[$LastNonZeroBand] == 0) { $LastNonZeroBand--; } # now do 5year bands from 35 to 95 for ($BandIndex=7; $BandIndex<=$LastNonZeroBand; $BandIndex++) { $BandLowAge = ($BandIndex-7)*5 + 35; $BandHighAge = $BandLowAge + 4; $NumberInBand = $FemaleAgeCount[$BandIndex]; $BandWidth = int ($NumberInBand / $TotalInRace * 500); # 100% is 500 pixels wide print "\n"; } } print "
Men under 40 $TotNotVets
Men $BandLowAge to $BandHighAge"; if ($NumberInBand >0) { print " $NumberInBand
Ladies under 35 $TotNotVets
Ladies $BandLowAge to $BandHighAge"; if ($NumberInBand >0) { print " $NumberInBand
\n"; } } ########################################################## # # # sub PrintSelectedEvent { $Event= CheckParam("event",35); #print "event=$Event
\n\r"; $FromAge=CheckParam("fromage",2); if (not $FromAge) { $FromAge = 0; # default to all ages } $ToAge=CheckParam("toage",2); if (not $ToAge) { $ToAge = 99; # default to all ages } $Sex=CheckParam("sex",1); if (not $Sex) { $Sex="B"; #default to both sexes } $Sex = substr ($Sex,0,1); # keep the first letter only $ResPerPage=CheckParam("ResPerPage",3); if (not $ResPerPage) { $ResPerPage=200; # default display 200 results per page } $FirstResult=CheckParam("FirstResult",4); if (not $FirstResult) { $FirstResult=1; } # $LastResult=param("LastResult"); # if (not $LastResult) # { # $LastResult= $FirstResult + ($ResPerPage-1); # } # one of these must be there $PrevButton=CheckParam("prev",4); $NextButton=CheckParam("next",4); $PageNumber=CheckParam("pagebutton",3); if ($PrevButton) { $FirstResult -= $ResPerPage; if ($FirstResult <= 0) { $FirstResult = 1; } # print "GOT PREV BUTTON : FirstResult=$FirstResult\n"; } elsif ($NextButton) { $FirstResult = $FirstResult + ($ResPerPage); # print "GOT NEXT BUTTON : FirstResult=$FirstResult\n"; } else { if (not $PageNumber) { $PageNumber=1; } $FirstResult=(($PageNumber-1) * ($ResPerPage) + 1); # print "GOT BUTTON : PageNumber=$PageNumber, FirstResult=$FirstResult\n"; } $LastResult= $FirstResult + ($ResPerPage-1); # print "lastresult=$LastResult\n"; # print "**********************************\n"; PrintFile("ENDHEADER",$Event); # print the event header file to STDOUT, up to the line print "
\n"; print <<"ENDHIDDEN1"; \n ENDHIDDEN1 PrintSelectionForm(); PrintResultHeader(); $Event =~ s/.html/.txt/ ; # substitue the .html file extension to look at the results .txt file PrintResultFile($Event); # print the text file print "\n\n"; # marker for 'jump to page selection buttons link' PrintPageButtons(); print "
\n"; PrintAgeGroupGraph(); PrintBottom(); } ########################################################## # # remove invalid chars and truncate as required # sub CheckParam { my ($field,$maxlen,$sqlquoted)=@_; my $fieldvalue; #print "checking $field: "; if (not param($field)) { return undef;} $fieldvalue=param($field); #print "$fieldvalue
"; if (length($fieldvalue) > $maxlen) {$fieldvalue="";} $fieldvalue =~ s//./g; #remove > # if ($sqlquoted) # { # return $dbh->quote($fieldvalue); # } $fieldvalue =~ s/"/./g; #remove " $fieldvalue =~ s/\|/./g; #remove | # $fieldvalue =~ s/\'/ /g; #remove ' return $fieldvalue; } ########################################################## # # main program # print header(); print "\n"; #print "content-type: text/html\n\n"; $DistanceMiles=0; $DistanceKm=0; $units="M"; if (CheckParam("event",35)) { PrintSelectedEvent(); } else # first time in the program, so print the results index { CreateAndSendResultsIndex(); }