#!/usr/bin/perl
$VER='v1.5';# BeholderBoard Virtual Chess-set: www.beholder.co.uk 20-Oct-1999

# cgi: produces list of available chessboards or else the requested board
# v1.5:  fixed promotion-without-Javascript bug
#        added Resign move - and implicit "game over" state where $plyr=''
#        added flip board
# v1.41: fixed en passant bug in v1.4
# v1.4:  added "disable JavaScript" option + email notification
#        + some cosmetic/error handling changes

# *** see the readme which accompanies this script for detailed information  ***
# *** Frequently Asked Questions at http://www.beholder.co.uk/chess/faq.html ***

{
 ##------------------------------------------------------------------------------
 ##  LOCAL CONFIGURATION... edit these!    be careful: no trailing "/"s in paths!
 ##------------------------------------------------------------------------------

 $URL        = 'http://www.schaakclubkijkuit.nl';      # url of your domain
 $GRPATH     = 'Beholder/chess';          # path for graphics (from server root)
 $CGIPATH    = 'cgi-bin';                 # path to this script (from server root)
 $SCRIPT     = 'board.pl';          	  # name of this script
 $DATAPATH   = 'chessboards';             # path to data (relative to this script)
 $DATAFNAME  = 'board.txt';               # base data file name - must have one '.'
 $EMAILPROG  = '/usr/sbin/sendmail';      # your mailer program...
                                          # e.g. $EMAILPROG ='/usr/lib/sendmail';
                                          # Note: to DISABLE email notification
                                          # of moves, set $EMAILPROG = '';
 $REPLYTO = 'webmaster\@schaakclubkijkuit.nl';         # e-mail address

 # Type the full path to your Subscribe Me directory
 $memberinfo = "/var/www/vhosts/schaakclubkijkuit.nl/cgi-bin/chessboards";

 
 # If you are run the script and receive File Locking (flock)
 # errors, remove the number 2 from between the quotes.
 # Then it would appear: $LOCK_EX = "";
 $LOCK_EX = "2";


$HELPURL    = 'http://www.beholder.co.uk/chess/help.html'; # URL to help page
 
 ##------------------------------------------------------------------------------
 ##  LOCAL CONFIGURATION... that's all 
 ##------------------------------------------------------------------------------

 $BACKCOLOUR = '#115511';                 
 $BRDRCOLOUR = '#ff3333';                 # used for border and behind error message
 $TEXTCOLOUR = '#ffffff';
 $LINKCOLOUR = '#ffffff';                 # text must be visible over...
 $ALNKCOLOUR = '#ff0000';                 # ...$BACK- and $BRDR- colours

 $MAX_XY     = 26;                        # limit of deviance
 $PLAY       = 1;
 $PROBE      = 0;
 %PIECE      = qw(P pion R toren N paard B loper Q dame K koning);
 %COLOUR     = qw(b bzwart w wit);
 %PASSWD     = ('b','','w','');
 %EMAIL      = ('b','','w','');
 %KLEUR      = ('wit','wit','bzwart','zwart');
 %STUK       = (' ',' ','R','T','N','P','B','L','Q','D','K','K');

 $plyr       ='w';                        # current player white by default (new game)
					  # but may be set to null if game over

 $err        ='';                         # error (possibly benign) message
 $captives   ='';                         # list of captives (in order taken)
 $timestamp  = 0;
 $title      ='';
 $delete     = 0;			  # Delete expired board(s)? 
 $result     ='';			  # description of result if game over
 $hidden     = 0;
 $syserr     = 0;
 $xX         = 7;                         # edges of... 
 $yY         = 7;                         # ...board
 $|          = 1;
 $cr         = 0; 
 $comment    ='';                         #comment to opponent

 print "Content-Type: text/html\n\n<html>\n";
 use integer;
 foreach (qw( cr fr to pp bd hl hc hm sz pw dj fb rr )){$form{$_}=0} # initialise

 &getCGIvars;          # loads global %form and sets $err if there's a problem

 if( $form{'fr'}=~/^\s*(\w\d|R)\s*$/i ){$fr=lc($1)}else{$fr=''} # move from...
 if( $form{'to'}=~/^\s*(\w\d|R)\s*$/i ){$to=lc($1)}else{$to=''} # ...to
 if( $form{'pp'}=~/^\s*(\w)\s*$/      ){$pp=uc($1)}else{$pp=''} # pawn promotion piece 
 if( $form{'bd'}=~/^\s*(\d{1,3})\s*$/ ){$bd=$1}    else{$bd=0 } # board number
 if( $form{'hl'}                      ){$hl=1}     else{$hl=0 } # Hide Labels  (0=no, 1=yes [default=not hidden])
 if( $form{'hc'}                      ){$hc=1}     else{$hc=0 } # Hide Captives
 if( $form{'hm'}                      ){$hm=1}     else{$hm=0 } # Hide Moves
 if( $form{'pw'}=~/^\s*(\w+)\s*$/     ){$pw=$1}    else{$pw=''} # password
 if( $form{'dj'}                      ){$dj=1}     else{$dj=0 } # disable JavaScript (0=no, 1=yes)
 if( $form{'fb'}                      ){$fb=1}     else{$fb=0 } # flip board (0=no, 1=yes)
 if( $form{'rr'}=~/^(y|n)/i           ){$rr=lc($1)}else{$rr=0 } # confirm resign (y,n or not asked)
 if( $form{'sz'}=~/^\s*([1-9]\d{0,2})\s*$/){$sz=$1}else{$sz=45} # square size
 if( $form{'cr'}                      ){$cr=1}     else{$cr=0 }; # Create Board?  


 if (not $err){
  if ($cr) {&createBoard};
  if ($bd){
   if (getdata($bd)){
    if ($fr or $to){
     if (allowed($pw,$plyr)){
      ($x,$y)=an2sub($fr);
      ($x2,$y2)=an2sub($to);
      if   ( $x<0){$err="Snap niet <i>from</i> deel van zet"}
      elsif($x2<0){$err="Snap niet <i>to</i> deel van zet"}
      elsif (occupied($x,$y) and (colour($x,$y) eq $plyr)){
       $pc=type($x,$y);
       ($dx,$dy)=($x2-$x,$y2-$y);
       if ($dx or $dy){
        if(validMove($x,$y, $dx, $dy, $plyr, $PLAY)){
         if ($special[0] eq 'Opgegeven'){
          $mv=recordMove();
          if (putdata($bd)){
           notify(other($plyr), $bd, $moveno, $mv, $title); $plyr=''
          }else{$err="Systeem probleem! <font size=2>Schrijven naar data-file mislukt ($!)</font>"}
         }elsif (not collision($x,$y, $x2,$y2, $plyr)){
          state(1);
          $capture=makeMove($fr, $to);
          if (not inCheck($plyr)){
           $mv=recordMove($pc, $fr, $to, $capture);
           if ($pw and not $PASSWD{$plyr}){setpassword($pw,$plyr)}
           if (putdata($bd)){
            notify(other($plyr), $bd, $moveno, $mv, $title);
            $fr=''; $to=''; $pp=''; $plyr=other($plyr)
           }else{$err="Systeem probleem! <font size=2>Schrijven naar data-file mislukt ($!)</font>"; state(0)}
          }else{$err="Kan niet in het schaak staan"; state(0)}
         }else{$err="Zet geblokkeerd"}
        }else{$err||="Illegale zet voor ".$PIECE{uc(type($x,$y))}}
       }else{$err="Geen zet gedaan"}
      }else{$err="Geen $KLEUR{$COLOUR{$plyr}} stuk op $fr"}  
     }else{$err="Sorry, onjuist wachtwoord"}
    } # else do nothing, just lookin'
   }else{$err="Bord nu niet beschikbaar <font size=2>($!)</font>"; $syserr=1}
  } # else bd=0 so show list
 }else{$err="Sorry, kan geen schaak met je spelen...<br>$err"; $syserr=1}
 printBoard($bd);
 exit
}


#---------------------------------------------------
# datafile returns data filename for this board
#---------------------------------------------------
sub datafile{
 my $bd=shift;
 my $datname=$DATAFNAME;
 $datname=~/(.*)(\.\w+)$/;
 if ($DATAPATH){$datname= $DATAPATH.'/'.$1.substr($bd+1000,-3).$2}
 else {$datname= $1.substr($bd+1000,-3).$2}
}


#---------------------------------------------------
# getdata
# reads the data file and sets everything up
# side-effect: initialises all the global variables
# returns true if everything was OK
#---------------------------------------------------
sub getdata{
 my $bd = shift;
 my ($x,$y,@raw);
 my $datname=datafile($bd);
 open(DAT, "<$datname") or return 0;
 while(<DAT>){
  if   (/^(b|w)\w* aan zet/i){$plyr=lc($1)}
  elsif(/^(b|w|-)/){unshift @raw, [split]}
  elsif(/^result:\s*(.+)/i){$result=$1; $plyr=''}
  elsif(/^captives:(.*)/i){$captives=$1}
  elsif(/^passwd:\s*(b|w)\w*\s+(\S+)/i){$PASSWD{$1}=$2}
  elsif(/^timestamp:\s*(\d+)/i){$timestamp=$1}
  elsif(/^title:(.*)/i){
   $title=$1; $title=~s/^\s*(.*?)\s*$/$1/;
   if ($title=~/^\((.*)\)$/){$hidden++; $title=$1}
  }
  elsif(/^e\-?mail:\s*(b|w)\w*\s([-~\w.]+(\@\w+[-\w.]+\w)?)\s*$/i){$EMAIL{$1}=$2}
  elsif(/^\d+\.\s/){chop; push @moves,$_}
 }
 $moveno=$#moves+1;
 if (not @raw){while (<DATA>){if(/^(b|w|-)/){unshift @raw, [split]}}}
 if(( $xX = $#{$raw[0]}) > $MAX_XY ){$xX=$MAX_XY};
 if(( $yY = $#raw      ) > $MAX_XY ){$yY=$MAX_XY};
 for $x (0..$yY){
  for $y (0..$xX){
   $_=$raw[$x][$y];
   if (/^((--)|(-\+)|((b|w)[prnbqk]))$/i){$board[$y][$x]=$_}
   else {$board[$y][$x]='--'}
  }
 }
 close DAT; 1
}


#---------------------------------------------------
# an2sub
# converts algebraic notation to subscripts e.g. a1 -> (0,0)
# cheekily allows deviant boards bigger than 8 x 8
# returns -ve x coord if either are bad
#---------------------------------------------------
sub an2sub{
 my $n = shift;
 my ($x,$y);
 $n=~/^(\w)(\w)$/;
 if(not ($1 and $2)){return (-1,-1)}
 else{
  $_=lc($1); $x=-ord('a')+ord;
  $_=lc($2); $y=/^\d/?$_-1:10-ord('a')+ord;
 }
 if ( $x<0 or $x>$xX or $y<0 or $y>$yY){return (-1,-1)}
 else {return ($x,$y)}
}


#---------------------------------------------------
# allowed
# checks password against the Right Word
# returns true if OK
# fails if no player (i.e. game over)
#---------------------------------------------------
sub allowed{
 my($pw, $plyr)=@_;
 $plyr and (not $PASSWD{$plyr} or (crypt($pw, 'bw') eq $PASSWD{$plyr}))
}


#---------------------------------------------------
# setpassword
# sets password provided for given player
#---------------------------------------------------
sub setpassword{
 my ($pw, $plyr)=@_;
 $PASSWD{$plyr}=crypt($pw, 'bw');
 if ($err){$err.='<br>'}
 $err.="Onthoud dit wachtwoord voor $KLEUR{$COLOUR{$plyr}} vanaf nu!"
}


#---------------------------------------------------
# board
# returns contents of square eg wK
#---------------------------------------------------
sub board{
 my ($x,$y)=@_;
 if ($x<0 or $x>$xX or $y<0 or $y>$yY){return '--'}
 $board[$x][$y]
}


#--------------------------------------------------
# other returns other colour of argument
#--------------------------------------------------
sub other{ $_[0]eq'b'?'w':'b' }


#--------------------------------------------------
# sqcol  returns colour of given square
#--------------------------------------------------
sub sqcol{my ($x,$y)=@_; (($x+$y)%2-1?'b':'w')}


#--------------------------------------------------
# type  returns type of piece at x,y  eg wB -> B
#--------------------------------------------------
sub type{my ($x, $y)=@_; my $p=board($x,$y); $p=~/^.(.)/; $1}


#--------------------------------------------------
# colour  returns colour of piece at x,y eg wB -> w
#--------------------------------------------------
sub colour{my ($x, $y)=@_; my $p=board($x,$y); $p=~/^(.)./; $1}


#--------------------------------------------------
# occupied returns true if there is a piece at x,y
#--------------------------------------------------
sub occupied{ my ($x, $y)=@_; type($x,$y)=~/\w/}


#--------------------------------------------------
# pl  returns 's' if plural, else nothing
#--------------------------------------------------
sub pl{$_[0]==1?'':'en'}


#---------------------------------------------------
# biggest  returns max of absolute pair
#---------------------------------------------------
sub biggest{my($a,$b)=@_;(($a=abs($a))>($b=abs($b)))?$a:$b}


#---------------------------------------------------
# smallest  returns min of absolute pair
#---------------------------------------------------
sub smallest{my($a,$b)=@_;(($a=abs($a))<($b=abs($b)))?$a:$b}


#---------------------------------------------------
# html
# strips out leading tabs (\t) and prints it
# (just to make Perl source a bit more readable)
#---------------------------------------------------
sub html{ $_=shift; s/\t//gm; print}


#---------------------------------------------------
# validMove
# checks proposed move against type of piece
# consider "special" moves only if this is a player's move
# returns true if OK
#---------------------------------------------------
sub validMove{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 my $x2=$x+$dx;
 my $y2=$y+$dy;
 my $Pc=type($x,$y);
 my $pc=lc($Pc);
 if (($pc eq 'k') and (lc(board($x2,$y2)) eq other($plyr).'k')){
  return unless confirmResign(@_)
 }
 elsif ($Pc eq'K' and (abs($dx)==2) and not $dy){
  return unless castling(@_)
 }
 elsif ($pc eq 'k'){
  return unless (biggest($dx,$dy)==1)
 }
 elsif ($pc eq 'q'){
  return unless (not $dx or not $dy or abs($dx)==abs($dy))
 }
 elsif ($pc eq 'b'){
  return unless (abs($dx)==abs($dy))
 }
 elsif ($pc eq 'n'){
  return unless ((abs($dx)==2 and abs($dy)==1)
             or  (abs($dx)==1 and abs($dy)==2))
 }
 elsif ($pc eq 'r'){
  return unless (not($dx and $dy))
 }
 elsif ($pc eq 'p'){
  return unless ((($plyr eq 'w') and ($dy>0))
             or  (($plyr eq 'b') and ($dy<0))); # advance only
  if (($Pc eq 'P') and (abs($dy)==2)){
   return unless pawnFirstMove(@_);
  }else{
   return unless ((biggest($dx,$dy)==1));
   if ($dx){ # must capture
    return unless (occupied($x2,$y2) or enpassant(@_))
   }else{ # mustn't capture
    return if (colour($x2,$y2) eq other($plyr))
   }
   if ($playmv and $y2==($plyr eq 'b'?0:$yY)){return 0 unless promotion(@_)}
  }
 }
 1 # ...a valid move
}


#---------------------------------------------------
# collision
# walks between (x,y) and (x2,y2) seeking collision
#  -checks intermediate squares for any
#  -checks the end square for friendly
# returns true if hit something
#---------------------------------------------------
sub collision{
 my($x,$y, $x2,$y2, $plyr)=@_;
 my $dx=($x2-$x); $dx=$dx?$dx/abs($dx):0;
 my $dy=($y2-$y); $dy=$dy?$dy/abs($dy):0;
 my $hit=0;
 if (lc(type($x,$y)) eq 'n'){ # knights don't collide
  $x=$x2; $y=$y2
 }else{
  $x+=$dx; $y+=$dy;
  while(not ($x==$x2 and $y==$y2)){
   if ($hit=occupied($x,$y)){last}
   $x+=$dx; $y+=$dy;
  }
 }
 if (not $hit and occupied($x,$y)){ # target square
  $hit=(colour($x,$y) eq $plyr)
 }
 return $hit
}


#---------------------------------------------------
# sub castling
# returns true if castling move was OK
# side-effect: loads the @special array
#---------------------------------------------------
sub castling{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 return if not $playmv;
 my $x2=$x+$dx;
 my $y2=$y+$dy;
 my $rx=$dx<0?0:$xX;
 my $obstructed=0;
 my $xx;
 $dx=$rx?1:-1;
 if ((type($rx,$y) eq 'R')
 and (colour($rx,$y) eq $plyr)){
  for (smallest($rx-$dx, $x2)..biggest($rx-$dx, $x2)){
   if (occupied($_,$y2)){$obstructed=1; last}
  }
  if (not $obstructed){
   if (inCheck($plyr)){$err="Kan niet rokeren door schaak";  return}
   state(1);
   $board[$x+$dx][$y]=lc($board[$x][$y]);
   $board[$x][$y]='--';
   if (inCheck($plyr)){$err="Kan niet rokeren door schaak"; state(0); return}
   state(0);
   # other collison/checks carried out as normal
   @special=($rx?'O-O':'O-O-O', 0, $x2-$dx,$y,$plyr.'r', $x2,$y2,$plyr.'k', $rx,$y,'--', $x,$y,'--');
   return 1
  }else{$err="Rokeren niet mogelijk"}
 }else{$err="Kan niet rokeren: toren heeft bewogen"}
 0 # castling illegal
}


#----------------------------------------------------
# pawnFirstMove
# returns true if 2-square pawn move was OK
# side-effect: sets @special (marks en passant target with *)
#----------------------------------------------------
sub pawnFirstMove{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 return if not $playmv;
 if (not $dx and not (colour($x2,$y2) eq other($plyr))){
  @special=(' ', 0, $x, $y+($dy/2), '-*');
  return 1
 }
 0 # pawn 2-sq move illegal
}


#----------------------------------------------------
# promotion
# returns true if OK (ie we have a promote-to type)
# side effect: set $err (to request promote-to)
#              or load @special array with new piece
# NB! this uses global $pp
#----------------------------------------------------
sub promotion{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 return if not $playmv;
 if ($pp!~/^([RNBQ])$/){
  $err=qq|Pawn promotion: select<br>&nbsp;R<input name='pp' type=radio value='R'>&nbsp;N<input name='pp' type=radio value='N'>&nbsp;B<input name='pp' type=radio value='B'>&nbsp;Q<input name='pp' type=radio value='Q' checked>|;
  return 0
 }else{@special=("+=$1", 0, $x+$dx, $y+$dy, $plyr.$1)}
 1 # promotion OK
}


#----------------------------------------------------
# confirmResign
# returns true if OK (ie we a confirmation)
# side effect: set $err (to request confirmation)
#              or load @special array with RESIGN
# NB! this uses global $rr
#----------------------------------------------------
sub confirmResign{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 return if not $playmv;
 if (not $rr){
  $err=qq|Geef je echt op?<br>&nbsp;ja<input name='rr' type=radio value='y'>&nbsp;nee<input name='rr' type=radio value='n' checked>|;
  return
 }elsif($rr eq 'y'){@special=('Opgegeven')}
 else{$fr=''; $to=''; $err='OK, niet opgegeven'; return}
 1 # resignation accepted
}


#----------------------------------------------------
# enpassant
# returns true if en passant move was OK
# side-effect: sets @special
#----------------------------------------------------
sub enpassant{
 my ($x,$y,$dx,$dy,$plyr,$playmv) = @_;
 return if not $playmv;
 if ($board[$x+$dx][$y+$dy]=~/\+/){ # +sign marks ep target
  @special=('+ e.p.', 'p', $x+$dx, $y, '--');
  return 1
 }
 0 # en passant illegal
}


#---------------------------------------------------
# inCheck
# returns true if player's king is threatenned
# (actually tests *all* player's kings!)
#---------------------------------------------------
sub inCheck{
 my ($plyr)=shift;
 my ($x, $y);
 my @kings=findPiece($plyr, 'k');
 while (@kings){
  $x=shift(@kings);
  $y=shift(@kings);
  if (inCheckTest($plyr, $x, $y)){return 1}
 }
 0 # not in check
}


#---------------------------------------------------
# inCheckTest
# returns true if player's king is threatenned
# Looks in all straight directions for a collision,
# and sees if that collision is enemy and can take
# If that doesn't work, test for attacking knights
#---------------------------------------------------
sub inCheckTest{
 my ($plyr, $x, $y)=@_;
 my ($dx,$dy,$dz, $x1,$y1);
 for $dy (-1,0,1){
  for $dx (-1,0,1){
   ($x1,$y1)=($x,$y);
   if ($dx or $dy){
    while( $x1>=0 and $x1<=$xX and $y1>=0 and $y1<=$yY ){
     $x1+=$dx; $y1+=$dy;
     if (occupied($x1,$y1)){
      if ((colour($x1,$y1) eq other($plyr))
      and validMove($x1, $y1, $x-$x1, $y-$y1, other($plyr),$PROBE))
       {return 1} # check!
      last
     }
    }
   }
  }
 }
 # test for Knights - look for a knight everywhere it could take from
 for $dy (-1,1){
  for $dx (-1,1){
   for $dz (2,3){
    $x1=$x+$dx*(4-$dz);
    $y1=$y+$dy*($dz-1);
    if ((lc(type($x1,$y1)) eq 'n')
    and (colour($x1,$y1) eq other($plyr)))
     {return 1} # check!
   }
  }
 }
 0 # not in check
}


#----------------------------------------------------
# findPiece
# returns ([x,y , [x1, y1, [x2, y2, [...]]]]) of all
# pieces matching specified colour and type
#----------------------------------------------------
sub findPiece{
 my $pc=lc($_[0].$_[1]);
 my @ret;
 my($x,$y);
 for $y (0..$yY){
  for $x (0..$xX){
   if (lc(board($x,$y)) eq $pc){push @ret, ($x,$y)}
  }
 }
 return @ret
}


#---------------------------------------------------
# state   saves board state (snapshot)
# argument 1 = store, 0 = restore (i.e. revert)
#---------------------------------------------------
sub state{
 my ($x,$y);
 for $y (0..$yY){
  for $x (0..$xX){
   if ($_[0]){$snapshot[$x][$y]=$board[$x][$y]}
   else      {$board[$x][$y]=$snapshot[$x][$y]}
  }
 }
}


#---------------------------------------------------
# makeMove
# makes the move in board data structure from $fr to $to
# returns type of piece taken, or null if no capture
#---------------------------------------------------
sub makeMove {
 my($from,$to)=@_;
 my($x,$y)=an2sub($from);
 my($xt,$yt)=an2sub($to);
 my ($sq, $ret, $capt);
 $ret = occupied($xt,$yt)?lc(type($xt,$yt)):'';
 $board[$xt][$yt]=lc($board[$x][$y]);
 $board[$x][$y]='--';
 if (@special){
  $_=shift @special;
  if ($capt = shift @special){$ret=$capt}
  while(@special){
   ($x,$y,$sq)=splice(@special,0,3);
   $board[$x][$y]=$sq
  }
  @special=$_; # put special move back
 }
 $timestamp=time;
 $ret
}


#---------------------------------------------------
# recordMove  update the list of moves
# use SAN short-form notation
# returns the move string
#---------------------------------------------------
sub recordMove{
 my ($pc, $from, $to, $took)=@_;
 my ($mv, $x1, $y1);
 my ($ambig, $same)=(0,0);
 my $sp=@special?$special[0]:'';
 if ($sp eq'Opgegeven'){ $mv=$sp }
 else{
  if ($took){$captives.=' '.other($plyr).$took}
  if ($sp=~/O-O/){$mv=$sp}
  else{ # SAN comliance: short-form ambiguity detector
   my ($x,$y)=an2sub($from);
   my ($x2,$y2)=an2sub($to);
   if ($pc=~/P/i){
    if ($took){ $from=~s/\d//; $from.='x' } else { $from='' }
   }else{ 
    my @similar=findPiece($plyr, $pc);
    while (@similar) {
     $x1=shift @similar;
     $y1=shift @similar;
      if(($x1!=$x2 or $y1!=$y2) # ignore piece itself
     and validMove($x1, $y1, $x2-$x1, $y2-$y1, $plyr, $PROBE)
     and not collision($x1,$y1, $x2,$y2, other($plyr))){
      $ambig++;
      if($x1==$x){ $same++; last }
     }
    }
    $from=~/^(.)(.)/;
    $from=uc($pc);
# Translate to dutch notation - Andre
    $from=$STUK{uc($pc)};
    if ($ambig){$from.=$1 }
    if ($same){ $from.=$2 }
    if ($took){ $from.='x'} elsif ($ambig){ $from.='-' }
   }
   $mv = "$from$to";
   if ($sp=~/^\+(.*)/){$mv.=$1}
  }
  if (inCheck(other($plyr))){$mv.='+'}
 }
 if ($plyr eq 'b'){
  if (not @moves){push(@moves, ++$moveno.".\t ...")}
  $moves[$#moves].="\t $mv"
 }
 else{push(@moves, ++$moveno.".\t $mv")}
 return $mv
}


#---------------------------------------------------
# putdata
# writes the data to file ready for next move
# returns true if write was OK
#---------------------------------------------------
sub putdata{
 my $bd=shift;
 my $datname=datafile($bd);
 if (not open(DAT, ">$datname")){return 0}
 else{
  if ($special[0] eq 'Opgegeven'){print DAT "result: ".$KLEUR{$COLOUR{other($plyr)}}." won\n"}
  else{print DAT $COLOUR{other($plyr)}." aan zet\n"}
  
  for $y(0..$yY){
   for $x(0..$xX){
    $_=board($x,$yY-$y); tr/*+/+-/;
    print DAT "$_ "
   }
   print DAT "\n"
  }
  print DAT "\n";
  foreach $_ (@moves){print DAT $_."\n"};
  print DAT "\n";
  if ($hidden){ $title="($title)" }
  print DAT "title: $title\n" if $title;
  print DAT "captives: $captives\n" if $captives;
  print DAT "passwd: w $PASSWD{'w'} \n" if $PASSWD{'w'};
  print DAT "passwd: b $PASSWD{'b'} \n" if $PASSWD{'b'};
  print DAT "email: w $EMAIL{'w'} \n" if $EMAIL{'w'};
  print DAT "email: b $EMAIL{'b'} \n" if $EMAIL{'b'};
  print DAT "timestamp: ".time."\n";
  close DAT;
  return 1 # write OK
 }
}


#---------------------------------------------------
# timelapse
# returns time since last move ("Last move...ago")
# blank if no timestamp or just seconds ago
#---------------------------------------------------
sub timelapse{
 my $timestamp = shift;
 my $timelapse='';
 if ($timestamp and ($t=int((time-$timestamp)/60))){
  if ($_=int($t/43200)){$delete=1};
  $timelapse="<font size=2>Laatste zet ";
  if ($_=int($t/1440)){$timelapse.=" $_ dag".pl($_);$t-=($_*1440)};
  if ($_=int($t/60))  {$timelapse.=" $_ uur";$t-=($_*60)};
  $_=$t; $timelapse.=" $_ minuten"." geleden</font>"
 }
 $timelapse
}


#---------------------------------------------------
# notify
# sends email notice to the other player
# note: does nothing if $EMAILPROG is null (disabled)
#---------------------------------------------------
sub notify{
 $comment = $form{'comment'};
 my ($plyr, $bd, $mvno, $mv, $title)=@_;
 if ($EMAILPROG and $EMAIL{$plyr}){
  if ($plyr eq 'w'){$mv=" ... $mv"}
  $_=$title; s/<[^>]*>/ /g; s/\s+/ /g; s/(^ | $)//g; # strip out html
  $title=$_?qq! "$_"!:'';
  if (open (MAIL, "|$EMAILPROG -t $EMAIL{$plyr}")){
   print MAIL "From: $REPLYTO\n";
   print MAIL "Reply-To: $REPLYTO\n";	
   print MAIL "Subject: Kijk Uit e-mail schaak bord $bd:  $mvno. $mv\n";
   print MAIL "Je tegenstander (".$KLEUR{$COLOUR{other($plyr)}}.") heeft zojuist een zet gedaan op bord $bd\n$title:\n\n";
   print MAIL "Commentaar van je tegenstander: [ ";
   print MAIL "$comment ]\n\n";
   foreach (@moves){ print MAIL "$_\n" }
   print MAIL "\n$URL/$CGIPATH/$SCRIPT?bd=$bd\n\n";
   print MAIL "Vragen of commentaar? - Stuur ze naar de webmaster\nmailto:webmaster\@schaakclubkijkuit.nl.\n";
   print MAIL "\n-----------------------------------------\nJe bent automatisch geinformeerd door\nde BeholderBoard Virtual Chess-set $VER\n-----------------------------------------\n\n";
#   print MAIL "Hosted by Reboot Support & Design Aust. Pty. Ltd.  http://www.reboot.com.au\n\n";
#   print MAIL "Reboot your Business - or just play a game!!\n\n";
   close (MAIL);
   $err="Je zet is verzonden naar $KLEUR{$COLOUR{$plyr}}. $err"
  }
  else{ $err="Waarschuwing: probleem met e-mail versturen naar $KLEUR{$COLOUR{$plyr}}. $err" }
 }
}


#---------------------------------------------------------
# getCGIvars
# gets the variables passed over the web
# two important side-effects:
#   loads up the global %form
#   sets $err if there was a problem
#---------------------------------------------------------
sub getCGIvars {
 my ($in, $name, $value);
 if (($ENV{'REQUEST_METHOD'} eq 'GET')
  or ($ENV{'REQUEST_METHOD'} eq 'HEAD') ){
   $in=$ENV{'QUERY_STRING'}
 }
 elsif ($ENV{'REQUEST_METHOD'} eq 'POST'){
  if ($ENV{'CONTENT_TYPE'}=~ m#^application/x-www-form-urlencoded$#i){
   if(length($ENV{'CONTENT_LENGTH'})){
    read(STDIN, $in, $ENV{'CONTENT_LENGTH'})
   }else{$err='POST request'}
  }else{$err='Content-Type: '.$ENV{'CONTENT_TYPE'}}
 }else{$err='REQUEST_METHOD'}
 if ($err){$err="<font size=2>Je browser stuurde een fout $err</font>"; return}
 foreach (split('&', $in)) {
  s/\+/ /g ;
  ($name, $value)= split('=', $_, 2) ;
  $name=~ s/%(..)/chr(hex($1))/ge ;
  $value=~ s/%(..)/chr(hex($1))/ge ;
  $form{$name}=$value ;
 }
}

#---------------------------------------------------
# createBoard
# Used passed vars to create board
# --added by ian c rogers, not to be blamed on original author
#---------------------------------------------------
sub createBoard{
my @boards=();
my $here=$DATAPATH?$DATAPATH:'.';
$DATAFNAME=~/^(.*)(\.\w+)$/;
my ($prefix,$suffix)=($1,$2);

if (opendir DATADIR, $here){
@boards = sort grep/^$prefix\d\d\d$suffix$/, readdir DATADIR;
closedir DATADIR;
}

$_=0;
while(++$_<1000){last if $boards[$_-1]!~/^$prefix0?0?$_$suffix$/}
$free=$_<1000?$_:0;

if (! $free) { $err = "No free boards! "; }

my $NEWBOARDFILE = sprintf ">$here/$prefix%03d$suffix" , $free;

my $title = $form{'title'};
my $whitename = $form{'whitename'};
my $whiteemail = $form{'whiteemail'};
my $blackname = $form{'blackname'};
my $blackemail = $form{'blackemail'};

if ( ! ( $title && $whitename && $whiteemail && $blackname &&
$blackemail ) ){$err = "Je hebt niet alle velden ingevuld. Geen bord gecreëerd.";
}

if ( ! $err ) {
$player{'email'} = $form{'whiteemail'};
&checkaddress;
if ($legalemail !~ 1) {$err ="Ongeldig e-mail adres! Geen bord gecreëerd.";
}
}

if ( ! $err ) {
&subscribe;
}

if ( ! $err ) {
$player{'email'} = $form{'blackemail'};
&checkaddress;
if ($legalemail !~ 1) {$err ="Ongeldig e-mail adres! Geen bord gecreëerd.";
}
}

if ( ! $err ) {
&subscribe;
}

if ( ! $err ) {
# throw e-mail addresses in DB
# $dbh = DBI->connect($dsn, $user, $password) || die $DBI::errstr;
# $sth = $dbh->prepare( "INSERT fistusers_db VALUES ('$whiteemail')");
# $sth->execute;
# $sth->finish;
# $sth = $dbh->prepare( "INSERT fistusers_db VALUES ('$blackemail')");
# $sth->execute;
# $sth->finish;
# $dbh->disconnect;

open ( NEWBOARDFILE, $NEWBOARDFILE) or die "Error: Can't open $NEWBOARDFILE: $!\n";
print NEWBOARDFILE "title: $title<br><font size=2>$whitename - $blackname</font>\n";
print NEWBOARDFILE "email: w $whiteemail\n";
print NEWBOARDFILE "email: b $blackemail\n";
close NEWBOARDFILE;
$err = "Bord gecreëerd! - [ Bord Nr $free ]";
}
}

#---------------------------------------------------
# checkaddress
# Checks validity of email addresses
#---------------------------------------------------
sub checkaddress {

$player{'email'} =~ s/\s//g;

unless ($player{'email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)|(,)/
	  || $player{'email'} !~
	  /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/)
	  {
         $legalemail = 1;
        } else {
         $legalemail = 0;
        }
}
#---------------------------------------------------
# subscribe
# Add e-mail addresses to database
#---------------------------------------------------
sub subscribe {

##&checkaddress;

open (DAT,"$memberinfo/address.txt");
if ($LOCK_EX){ 
      flock(DAT, $LOCK_EX); #Locks the file
	}
@database_array = <DAT>;
close(DAT);

        foreach $lines(@database_array) {
         chomp($lines);            


&parseemail;

if ($existing eq $email) {return};

}

###### add address to database #########
open (DAT,">>$memberinfo/address.txt") || die print"Permissions Error - Can't open address.txt file.";
      if ($LOCK_EX){ 
      flock(DAT, $LOCK_EX); #Locks the file
	}
         print DAT "$player{'email'}\n" || die print"Permissions Error - can't write to address.txt file.";
              close (DAT);
}

#---------------------------------------------------
# parseemail
# break apart email address for checking
#---------------------------------------------------
sub parseemail {

$email = $player{'email'};
$existing = $lines;
$existing =~ tr/A-Z/a-z/;
$email =~ tr/A-Z/a-z/;

}



#---------------------------------------------------
# printListOfBoards
# produces the html output for the list of available boards
# print summary move info; don't print hidden boards
#---------------------------------------------------
sub printListOfBoards{
 my @boards=();
 my ($board, $bd, $plyr, $timestamp, $title, $status);
 my $here=$DATAPATH?$DATAPATH:'.';
 $DATAFNAME=~/^(.*)(\.\w+)$/;
 my ($prefix,$suffix)=($1,$2);
 
 if (opendir DATADIR, $here){
  @boards = sort grep/^$prefix\d\d\d$suffix$/, readdir DATADIR;
  closedir DATADIR
 }
 if (not @boards){push @moves, "Er zijn momenteel geen borden opgezet."}
 else{
  foreach $board (@boards){
   $delete=0;
   $board=~/^$prefix(\d\d\d)$suffix$/; $bd=$1+0;
   if ($bd){ 
    if (open DAT, "$here/$board"){
     $plyr='w'; $timestamp=$title=$status='';
     while(<DAT>){
      if (/^(b|w)\w* aan zet/i){$plyr=lc($1)}
      elsif (/^timestamp:\s*(.*)/i){$timestamp=$1}
      elsif(/^title:\s*(.*)/i){$title=$1}
      elsif(/^result:\s*(.+)/i){$status=$1}
     }
     close DAT;
     if ($title=~/^\(/){next} # hidden board; skip it
     $status||="$KLEUR{$COLOUR{$plyr}} aan zet";
     $timelapse=timelapse($timestamp);
     if ($delete){unlink ("$here/$board");next || die "Error: $!\n"};
     push @moves, qq!<a href="$URL/$CGIPATH/$SCRIPT?bd=$bd&dj=$dj">Bord $bd</a></td><td>$title</td><td>$status<br>$timelapse!;
    }
    else{push @moves, "</td><td colspan=2>Problem <font size=2>$here/$board: $!</font>"}
   }
  }
 }
 html(<<HTML
	<head>
	<title>Schaakborden</title>
	</head>
	<body bgcolor="$BACKCOLOUR" text="$TEXTCOLOUR" link="$LINKCOLOUR" vlink="$LINKCOLOUR" alink="$ALNKCOLOUR">
	<center>

	<table border=0 cellpadding=10>
	<tr>
	 <td valign=top align=right><img src="/$GRPATH/wqb.gif"></td>
	 <td valign=top align=center><FONT FACE="Arial"><b>E-mail Schaak</b><p><a href="#choose">Kies je bord...</a><br>of creëer een nieuw bord</p></FONT></td>
	 <td valign=top align=left><img src="/$GRPATH/bqb.gif"></td>
	</tr>
	</table>
	
	<p align="center">
          <font face="Arial"><b>Creëer een nieuw bord</b></font></a><br>
 <form method="post" action="http://www.schaakclubkijkuit.nl/cgi-bin/board.pl">
 <INPUT TYPE="hidden" name="cr" value="1">
 <center>
 <table>
         <tr><td><font face="Arial">Titel van de partij</font></td>
     <td><INPUT SIZE="20" name="title"></td></tr>
         <tr><td><font face="Arial">Jouw naam</font></td> <td><INPUT SIZE="20" name="whitename"></td></tr>
         <tr><td><font face="Arial">Jouw e-mail adres</font></td>
     <td><INPUT SIZE="20" name="whiteemail"></td></tr>
         <tr><td><font face="Arial">Tegenstander's naam</font></td>
     <td><INPUT SIZE="20" name="blackname"></td></tr>
         <tr><td><font face="Arial">Tegenstander's e-mail adres</font></td>
             <td><INPUT SIZE="20" name="blackemail"></td></tr>
         <tr><td colspan=2 align="center"><font face="Arial"><INPUT TYPE="SUBMIT" VALUE="Creëer bord"></font></td></tr>
         </table>
         </center>
         </form>

 <p align=center>
         <font face="Arial">
         Let op: Jouw bord is NIET noodzakelijkerwijs het LAATSTE bord!<br><br>
         Je tegenstander ontvangt een e-mailtje wanneer je je eerste zet hebt gedaan.<br>
         Als je niet wilt dat anderen zetten voor jou doen,<br>
         vul dan een wachtwoord in wanneer je je eerste zet doet.<br><br>
         Let op: Partijen worden automatisch verwijderd<br>
         als er binnen 30 dagen geen zet is gedaan.
<table border=1 cellpadding=4 cellspacing=3>
<a name="choose">
<br>
HTML
);
 if ($err){$err="<tr><td colspan=3 bgcolor=\"$BRDRCOLOUR\">".$err."</td></tr>"}
  else {$err=''};
 print "$err\n";
 foreach (@moves){
  print "<tr><td>\n$_\n</td></tr>\n"
 }
 print "</table>\n</center>\n";
}


#---------------------------------------------------
# printBoard
# produces the html output for the board
#
# note: suppress move/password boxes if not $plyr (game over)
#---------------------------------------------------
sub printBoard{
 my $bd=shift;
 my ($y,$x,$isz,$timelapse,$t,$hlch,$hcch,$hmch,$fbch,$form,$status);
 my $onUnload='';

 if (not ($bd or $syserr)){printListOfBoards}
 else{
  if ($err){$err="<tr><td bgcolor=\"$BRDRCOLOUR\">".$err."</td></tr>"}
  else {$err=''};
  $timelapse=timelapse($timestamp);
  $hlch=$hl?'checked':'';
  $hcch=$hc?'checked':'';
  $hmch=$hm?'checked':'';
  $fbch=$fb?'checked':'';
  $isz=$sz<=50?$sz:50;  # images shrink but never grow > 50 
  if ($plyr){
   $status="$KLEUR{$COLOUR{$plyr}}&nbsp;aan&nbsp;zet<br><font size=2>b.v.&nbsp;e2-e4</font>";
   $fromToBoxes=qq!<input name="fr" value="$fr" size=2 maxlength=2>&nbsp;-&nbsp;<input name="to" value="$to" size=2 maxlength=2>!;
   $passwordLabel='zet vereist<br>wachtwoord';
   $passwordBox='<input name="pw" type="password" size=8 maxlength=16>';
  }
  else{
   $status=$result;
   $fromToBoxes='';
   $passwordLabel='';
   $passwordBox='';
  }
  $form=<<HTML_Form
	<table border=0 cellpadding=2 cellspacing=2>
	 $err
	 <tr>
	  <td align=center>
	   <table border=0 cellpadding=2 cellspacing=2>
	    <tr>
	     <td align=right valign=bottom>
	      $status
	     </td> 
	     <td valign=bottom>
	      $fromToBoxes
	     </td>
	     <td rowspan=3 align=right><font size=2>
	      verberg&nbsp;labels&nbsp;<input name="hl" type="checkbox" value="1" $hlch>&nbsp;<br>
	      verberg&nbsp;materiaal&nbsp;<input name="hc" type="checkbox" value="1" $hcch>&nbsp;<br>
	      verberg&nbsp;zetten&nbsp;<input name="hm" type="checkbox" value="1" $hmch>&nbsp;<br>
	      draai&nbsp;bord&nbsp;om<input name="fb" type="checkbox" value="1" $fbch>&nbsp;<br>
	      &nbsp;&nbsp;&nbsp;&nbsp;veld&nbsp;grootte&nbsp;<input name="sz" value=$isz size=3 maxlength=3>&nbsp;</font>
	     </td>
	    </tr>
	    <tr>
	     <td align=right valign=top><font size=2>$passwordLabel</font></td>
	     <td valign=top>$passwordBox</td>
	    </tr>
	    <tr>
	     <td valign=middle>
	      <font size=2><a href="$HELPURL" target="new">help...</a></font>
	     </td>
	     <td valign=middle>
	      <input name="bd" value="$bd" type=hidden>
	      <input name="dj" value="$dj" type=hidden>
	      <input type="submit" value="Update">
	     </td>
	    </tr>
	    <tr>
	     <td colspan=3 align=center>$timelapse</td>
          </tr>
          <tr> 
	   <td align=left><font size=2>Commentaar:</font></td>\n <td colspan=2><input name="comment" size=32 maxlength=55></td>
         </tr>  
	   </table>
	  </td>
	 </tr>
	</table>
HTML_Form
 ;

  print "<head>\n<title>Schaakborden</title>\n";

  if (not ($syserr or $dj)){
   $onUnload=qq!onUnload="killw()"!;
   $form=~s/\t//g;
   $form=~s/\n/\\n/g;
   $form=~s/'/\\'/g;
   html(<<HTML
	<script language="javascript">
	<!--

	 window.name="chessboard";

	 var w = window.open("", "w", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=450,height=200")
	 w.document.open()
	 var m = '<html><head><title>Chess Options</title></head>\\n<body bgcolor="$BACKCOLOUR" text="$TEXTCOLOUR" link="$LINKCOLOUR" vlink="$LINKCOLOUR" alink="ALNKCOLOUR">\\n'
	 m+='<form method="post" action="$URL/$CGIPATH/$SCRIPT" target="chessboard">\\n'
	 m+='<center>\\n$form\\n</center>\\n</form>\\n'
	 m+='</body>\\n</html>\\n'
	 w.document.write(m)
	 w.document.close()
	 w.focus()

	function killw() {
	 if (window.w){
	  w = window.open("", "w", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=350,height=200")
	  w.document.open()
	  w.document.write("<html><head></head><body bgcolor='$BACKCOLOUR' onLoad='self.blur();setTimeout(\\"self.close()\\",500)'></body></html>")
	  w.document.close()
	 } 
	}
	//-->
	</script>
HTML
)}
 
  html(<<HTML
	</head>
	<!-- HTML autogenerated by  board.pl $VER (c) Beholder 1999 -->
	<body bgcolor="$BACKCOLOUR" text="$TEXTCOLOUR" link="$LINKCOLOUR" vlink="$LINKCOLOUR" alink="$ALNKCOLOUR" $onUnload>
	<h3>$title</h3></b>
	<pre>


	</pre>
	<center>
	<table cellpadding=0 cellspacing=0 border=0>
	<tr>
	 <td valign=top align=center>

	<table cellpadding=0 cellspacing=0 border=0>
	<tr>
	 <td valign=center align=center>
HTML
   );
    if (not $hl){
    html(<<HTML
	  <table bgcolor="$BACKCOLOUR" border=0 cellspacing=0 cellpadding=2>
	   <tr>
	    <td valign=center align=center>
	     <table border=0 cellspacing=1 cellpadding=0>
	      <tr><td width=$sz height=3></td></tr>
HTML
   );
   for $yLoop (0..$yY){
    $y=$fb? $yLoop:$yY-$yLoop;
    $_=$y<9?$y+1:chr(ord('a')+$y-9); 
    print  qq!      <tr><td align=center valign=center width=$sz height=$sz>$_</td></tr>\n!
   }
   html(<<HTML
	      <tr><td width=$sz height=3></td></tr>
	     </table>
	    </td>
	   </tr>
	  </table>
HTML
   )}
   html(<<HTML
	 </td>
	 <td>
	  <table bgcolor="$BRDRCOLOUR" border=2 cellspacing=0 cellpadding=2>
	   <tr>
	    <td valign=center align=center>
	     <table border=1 cellspacing=0 cellpadding=0>
HTML
   );
   for $yLoop (0..$yY){
    $y=$fb? $yY-$yLoop:$yLoop;
    print  "      <tr>\n";
    for $xLoop (0..$xX){
     $x=$fb? $xX-$xLoop:$xLoop;
     $sq=sqcol($x,$yY-$y);
     print  "       <td width=$sz height=$sz bgcolor=\"#", ($sq eq'b'?'5':'f')x 6, '"';
     $_=$syserr?'':lc(board($x,$yY-$y));
     if (/\w/){print qq!align=center valign=center><img src="/$GRPATH/$_$sq.gif" width=$isz height=$isz>!}
     else{print '><font size=1>&nbsp;</font>'}
     print  "</td>\n"
    }
    print  "      </tr>\n";
   }
   html(<<HTML
	     </table>
	    </td>
	   </tr>
	  </table>
	 </td>
	 <td width=$sz>&nbsp;</td>
	</tr>
	<tr>
	<td></td>
	<td>
HTML
   );
   if (not $hl){
    html(<<HTML
	 <table bgcolor="$BACKCOLOUR" border=0 cellspacing=0 cellpadding=2>
	  <tr>
	   <td valign=center align=center>
	    <table border=0 cellspacing=2 cellpadding=0>
	     <tr>
	      <td width=2 height=$sz></td>
HTML
   ); 
   for $xLoop (0..$xX){
    $x=$fb? $xX-$xLoop:$xLoop;
    $_=chr(ord('a')+$x); 
    print qq!      <td align=center valign=center width=$sz height=$sz>$_</td>\n!
   }
   html(<<HTML
	      <td width=2 height=$sz></td>
	     </tr>
	    </table>
	   </td>
	  </tr>
	 </table>
HTML
   )}

  html(<<HTML
	</td>
	</tr>
	<tr>
	 <td colspan=3 align=left>
HTML
  );
  if (not $hc){
   print "  <br><br>\n";
   while ( $captives=~/\s+w(\w)/g ){
    print  qq!  <img src="/$GRPATH/w$1b.gif" width=$sz height=$sz>\n!
   }
  }
  html(<<HTML
	 </td>
	</tr>
	<tr>
	 <td colspan=3 align=left>
HTML
  );
  if (not $hc){
   while ( $captives=~/\s+b(\w)/g ){
    print  qq!  <img src="/$GRPATH/b$1b.gif" width=$sz height=$sz>\n!
   }
  }
  html(<<HTML
	 </td>
	</tr>
	</table>
	</td>
	<td valign=top align=center>
HTML
  );
  if ((not $hm) and $moves[0]){
   print  " <table cellpadding=5 cellspacing=0 border=1>\n";
   foreach $_ (@moves){
    /(\d+.)\s+([^\t]+)*(?:\Z|\t(.*))/;
    print  "  <tr><td>$1</td><td>$2</td><td>$3</td></tr>\n"
   }
   print  " </table>\n"
  }
  print "</td>\n</tr>\n</table>\n</center>\n<br>\n<br>\n";

  if ($syserr){
   print "<center><table border=0 cellpadding=2 cellspacing=2>$err</table></center>\n"
  }
  elsif ($dj){
   html(<<HTML
	<br><br>
	<center>
        <form method="post" action="$URL/$CGIPATH/$SCRIPT">
	<table border=1 cellspacing=0 cellpadding=4>
	 <tr>
	  <td valign=center align=center>
	   $form
	  </td>
	 </tr>
	</table>
	</center>
        </form>
HTML
   );
  }
 }
 &printFooter
}


#---------------------------------------------------
# printFooter
# slaps HTML footer onto bottom of page
#---------------------------------------------------
sub printFooter{
 my $listOption=$bd?qq!| <a href="$URL/$CGIPATH/$SCRIPT?bd=0&dj=$dj">List Boards</a>!:'';
 my $js;
 if ($dj){$js='0">Enable'}
 else    {$js='1">Disable'}
 html(<<HTML
	<pre>\n\n\n\n\n</pre>\n
	<font size=2>
	<a href="$URL/$CGIPATH/$SCRIPT?bd=$bd&hm=$hm&hc=$hc&hl=$hl&sz=$sz&dj=$js Javascript</a>
	$listOption
	<br>
	<hr>
	<b>Gebaseerd op de BeholderBoard Virtual Chess-set</b><br>
	Programmeerfouten of instemmend gebrom naar <a href="mailto:cartoons\@beholder.co.uk">cartoons\@beholder.co.uk</a><br>
	<a href="http://www.beholder.co.uk">www.beholder.co.uk</a><br>
      Gemodificeerd, verbeterd of vernield door <a href="mailto:Ross\@reboot.com.au">Ross\@reboot.com.au</a><br>
      <a href="http://www.reboot.com.au">www.reboot.com.au</a><br>
      Vertaald naar het Nederlands door <a href="mailto:andre.kunst\@GEENSPAMschaakclubkijkuit.nl">andre.kunst\@GEENSPAMschaakclubkijkuit.nl</a><br>
      <a href="http://www.schaakclubkijkuit.nl">www.schaakclubkijkuit.nl</a>
	</font>
	</body>
	</html>
HTML
)
}


# start position data follows:

__END__
bR bN bB bQ bK bB bN bR
bP bP bP bP bP bP bP bP
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
wP wP wP wP wP wP wP wP
wR wN wB wQ wK wB wN wR

