This is the last set of notes developed in class during the July 08 lecture/lab. Today is Wednesday. One intensive summer session ends today. Tomorrow is Thursday. There is no class whatsoever. But we have office hours 9-10 and 11-5pm. The new summer sessions starts on Friday with lecture. Java. So tomorrow we work out midterm grades for A202/A598 as well as final grades for one A290/A590. (Grades will be final only on July 28 though). Here's the first program that we developed:

Current balance:

Add money: and press

Bet: and press

The second one is very straightforward:

Current balance:

Add money: and press

Bet: and press

Now we convert to Perl/CGI: #!/usr/bin/perl use CGI; $q = new CGI; print $q->header, $q->start_html; $message = $q->param('message'); $balance = $q->param('balance'); $amount = $q->param('amount'); $bet = $q->param('bet'); $action = $q->param('action'); $d1 = "N/A"; $d2 = "N/A"; $d3 = "N/A"; if ($message) { if ($action eq "Deposit") { $balance += $amount; } else { $d1 = int(rand(6) + 1); $d2 = int(rand(6) + 1); $d3 = int(rand(6) + 1); if ($d1 == $d2 && $d2 == $d3) { $balance += 2 * $bet; } else { if ($d1 == $d2 || $d2 == $d3 || $d1 == $d3) { $balance += $bet; } else { $balance -= $bet; } } } } else { $balance = 0; $message = "Welcome"; } print qq{
$d1 $d2 $d3

Current balance: $balance

Add money: and press

Bet: and press

}; Now we need to convert to server-side state with Perl/CGI: The first thing that I need to do is create a table to hold the state. create table last ( session_id char(8) primary key, message varchar(240), balance int, modified timestamp ); Then I change the client-side state program to this (based on ch. 11): #!/usr/bin/perl use CGI; use DBI; use Digest::MD5 qw(md5 md5_hex md5_base64); $DB = "dbi:mysql:homeworkThree:silo.cs.indiana.edu:port=44089"; $username = "lbird"; $password = "sp00n"; $DB_TABLE = "last"; $SECRET = "something secret"; $EXPIRE = 30 * 60 * 60 * 24; # one month $MAX_TRIES = 10; $ID_LENGTH = 8; $q = new CGI; # Open the database -------------------------------------------------------- $DBH = DBI->connect($DB, $username, $password, {PrintError => 0}) || die "Couldn't open database: ", $DBI::errstr; # get the current session ID, or make one ---------------------------------- my ($session_id, $note) = &get_session_id(); # start the page ----------------------------------------------------------- print $q->header, $q->start_html(-title => 'Last Lab', -bgcolor => 'lightgrey'); my $state = &get_state($session_id); $message = $state->{'message'}; # state variables $balance = $state->{'balance'}; $amount = $q->param('amount'); # input $bet = $q->param('bet'); $action = $q->param('action'); $d1 = "N/A"; $d2 = "N/A"; $d3 = "N/A"; if ($message) { if ($action eq "Deposit") { $balance += $amount; } else { $d1 = int(rand(6) + 1); $d2 = int(rand(6) + 1); $d3 = int(rand(6) + 1); if ($d1 == $d2 && $d2 == $d3) { $balance += 2 * $bet; } else { if ($d1 == $d2 || $d2 == $d3 || $d1 == $d3) { $balance += $bet; } else { $balance -= $bet; } } } } else { $balance = 0; $message = "Welcome"; } $state->{'message'} = $message; $state->{'balance'} = $balance; &save_state($state, $session_id); print qq{
$d1 $d2 $d3

Current balance: $balance

Add money: and press

Bet: and press

}, $q->end_html; # get the state from the database ------------------------------get_state--- sub get_state { my $id = shift; my $query = "SELECT * FROM $DB_TABLE WHERE session_id = '$id'"; my $sth = $DBH->prepare($query) || die "Prepare: ", $DBH->errstr; $sth->execute || die "Execute: ", $sth->errstr; my $state = $sth->fetchrow_hashref; $sth->finish; return $state; } # retrieve the session ID from the path info. if it's -----get_session_id--- # not already there, add it to the path info (more or less) with a redirect sub get_session_id { my (@result); &expire_old_sessions(); my ($id) = $q->path_info() =~ m:^/([a-h0-9]{$ID_LENGTH}):o; return @result if $id and @result = &check_id($id); # if we get here, there's not already an ID in the path info my $session_id = &generate_id(); die "Couldn't make a new session id" unless $session_id; print $q->redirect($q->script_name() . "/$session_id"); exit 0; } # find a new unique ID and insert it into the database -------generate_id--- sub generate_id { # create a new session id my $tries = 0; my $id = &hash($SECRET . rand()); while ($tries++ < $MAX_TRIES) { last if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); $id = &hash($id); } return undef if $tries >= $MAX_TRIES; # we failed return $id; } # check to see that an old ID is valid --------------------------check_id--- sub check_id { my $id = shift; return ($id, '') if $DBH->do("SELECT 1 FROM $DB_TABLE WHERE session_id = '$id'") > 0; return ($id, 'The record of your game may have expired. Restarting.') if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); return (); } # generate a hash value ---------------------------------------------hash--- sub hash { my $value = shift; return substr(md5_hex($value), 0, $ID_LENGTH); } sub expire_old_sessions { # --------------------------expire_old_sessions--- $DBH->do(< $EXPIRE END } # save the state in the database ------------------------------save_state--- sub save_state { my ($state, $id) = @_; my $sth = $DBH->prepare(<errstr; UPDATE $DB_TABLE SET message=?,balance=? WHERE session_id='$id' END $sth->execute(@{$state}{qw(message balance)}) || die "execute: ", $DBH->errstr; $sth->finish; } So you see that if you have to emulate the class extension mechanism by hand you have to do a lot of extra work. --