Document Home


Previous Tweaking the Interface
Previous Modifying the Menu Structure

Samples for this Section

Implementing an Actual Password Authentication System, and a Little Eye-Candy



Once I created the context in which user state information was stored on the server, I had created a viable framework to use as the basis for user authentication. In this section I am going to take the basic authentication handler from a couple of sections ago, plunk it down on top of this new structure, and then drop the actual authentication code within that structure.


One thing constraining the manner in which both authentication and database access are handled in this context relates to both the nature of Apache::DBI and to an apparent glitch at some level in the installation of mod_perl on ralphzilla. First, as I discussed in the previous section, once Apache::DBI is used all of the connections to the database must take place with the same user credentials. In a context such as this that is something I can live with. (I have some intriguing thoughts about ways to go beyond that limitation that may bear fruit in a few sections.) The second constraint is also something that I can work around. While it is true that connections must share the same user credentials, it should be possible to create additional database handles, whether implcitly in calling a library that creates its own or explicitly to address a context that requires it. As an example of the first, I had intended to incorporate an authentication implementation based on the Apache::AuthDBI module installed as part of the Apache::DBI module. This module can allow authentication against an existing database to involve nothing more than specifying the relevant table columns in the server's configuration files. The handler would not function, so I launched into upgrading the basic handler I implemented in the BB_UTIL module. However, when I tried to create a database handle in the module to use in the subroutine the application failed in a manner similar to the failure of the authentication handler using the Apache::AuthDBI module. Upon further investigation I discovered that the methods used by the routine to initiate a connection in a child session were unable to resolve the host name ralphzilla-raider, resulting in an unknown hostname message. Since a connection to the server is obviously possible, or I would still be trying to get the handler to connect.<grin> I suspect that something in the environment under which a child process is spawned is at fault. However, after removing everything from the configuration changes that I have made that could have had an impact, the problem has persisted. Numerous web searches have not revealed anything that seems to me to be on point, and from this I infer that this problem is not widespread.



Therefore, my response to the problem at this point is to simply ignore it. There are contexts in which that would not be a viable option. If I were using ralphzilla to host a number of applications, each of which required database connectivity, I would have to resolve the issue, probably starting with a fresh compile of a mod_perl-enabled apache server. I will, in fact, probably be doing that in an upcoming section as I approach database access from a slughtly different tangent. At this point, however, I just do no want to invest the time in that process. Quite simply, I am able to ignore the problem because I am only hosting one application on ralphzilla, and as a result I can drop the various elements of the application under the umbrella of the BB_STACKED module, using the $dbh database handle defined there as the source for all database access. This does, however, require that the user() authentication subroutine be moved fropm the BB_UTIL module to the BB_STACKED module, because the database handle must be accessible in the scope in which the authentication handler is running. (There are, of course, other ways of handling that, but no compelling reasons to pursue them.)


I begin the process of integrating the authentication handler by creating a new location section in the httpd.conf file.

<Location /bb_app/league>
	AuthName "System Identification"
	AuthType Basic
	PerlAuthenHandler BB_STACKED::user
	require valid-user
</Location>
As is evident, the only read difference between this version is the location itself and the fact that the PerlAuthenHandler statement now references BB_STACKED::user rather than BB_UTIL::user. Once these changes have been activated, selection of the league option from the main menu will pop a login widget. As there is no more logic at this point in the user() subroutine than there was previously, any non-blank user name and password will grant access, but operation of the rest of what is currently implemented requries that the entered user name correspond to the value in the user_id column in a row in the user_char table. Following the sample data I have used previously, valid entries would include “bsimp”, “bclin”, or “llane”. I am going to start including one or more scripts in the samples files that will load test data into pertinent tables in the database when piped into the psql utility. The first of these, user_char.scr, simply inserts three records into the user_char table corresponding to the three sample ID's I have used in the system. You may, of course, edit that file to change the ID's if you wish. (As an aside, at one point I forgot to update that structure after I had changed the code to add additional columns. The page generated as a result included the following message, nicely confirming that that part of the save_state() subroutine was functioning well. This image also tips my hat regarding some of the enhancements that will be part of this section, but whaddaya gonna do, anyway?)



This little step exists simply to affirm that the new structure is functioning appropriately with the authentication handler. I had tested each, but I had not tested them toigether. Now that I know that there are functioning appropriately, I can start adding code to the basic authentication handler structure. As all of the other elements are in place, this process is not all that involved. Near the end of the main part of BB_STACKED I prepare a statement handle on an SQL statement to retrieve the value of the password column in the row associated with a given user

  my $get_password=$dbh->prepare("select password from user_char where user_id=?");
Within the user() subroutine itself, the first modification is the execution of that statement with the user value from the connection object as the argument supplied for the placeholder.
sub user	{
	
	my $r=shift;
	
	
	my ($res,$sent_pw)	=	$r->get_basic_auth_pw;
	return $res if $res != OK;

	##get the user id from the connection object and use that to retrieve the password 
	my $user = $r->connection->user;
	my $st_result=$get_password->execute($user);		

	##if that statement failed, the user is not in the table ... return access forbidden 
	if ($st_result != 1)	{
		
		$r->note_basic_auth_failure;
		return FORBIDDEN;
	}
	
	##get the value from the result set and trim trailing blanks
	my $pass=$get_password->fetchrow_array;

	#remove any whitespace
	$pass=trim($pass);
	$sent_pw=trim($sent_pw);
	
	
	##if password is not the same as stored, return authorization required
	unless ($pass eq $sent_pw)	{
		
		$r->note_basic_auth_failure;
		return AUTH_REQUIRED;
		}
	
		return OK;
		
}
The return value from the execution of that statement is stored in the scalar $st_result. If that value does not indicate successful execution ($st_result != 1), that must mean that the userid returned from the authentication widget was not found in the table. In that case I return the code associated with the “forbidden” message, because the user is not defined in the table of valid users. At that point the only column returned by the execution of the statement is retrieved from the result set. (As the command is returning the result to a scalar, the first element of the array returned by fetchrow_array is stored in the scalar $pass. This is just the way that fetchrow_array works, and not something inherent in calling a method in scalar context. Calling a method that returns an array in scalar context will generally result in the value representing the number of elements in the array being assigned to the scalar.)



The string now stored in the $pass scalar will now represent the password, but with a lot of whitespace behind it, which raises a point I should address. While I have assigned five characters as the size of the password column, there is no requirement that all five characters be non-whitespace, and if the string begins or ends with whitespace it is possible that either the password entered in the authentication widget or that stored in the table could have the remaining string shifted to the left or the right. Therefore, I put together a little subroutine based on recipe 1.14 from The Perl Cookbook to trim leading and trailing whitespace from strings passed into it. Now included in the BB_UTIL module, the trim() subroutine

sub trim	{
	
	my $string=@_[0];
	$string=~s/^\s+//;
	$string=~s/\s+$//;
	return $string;
}
simply matches one or more blank spaces (s+) at the beginning of the passed string and replaces them with nothing, then does the same at the end of the string.


At this point the authentication subroutine simply compares the two strings. Unless they are the same, authentication fails with the “Auth Required” message. If they are the same, the session is authenticated.


So there it is, not really all that big a change from the version that just made sure that something was entered. This is, of course, still basic authentication, but as I discussed earlier it is not a trivial matter to intercept and decode the communication between the client and the server, though certainly possible. Regardless, in a later section I will add encryption.


Now that I have a working authentication handler I decided that there were a few things that I could do to dress up the interface to make it even more spiffy. (I know, that is a difficult thing to imagine. Just trust me ... it can be done. <grin.>.)


My first step in that process was to create the environment I described at the end of the previous section. That is, since the application as it is currently constructed progressively builds menus in the first few lines that the user will use to navigate the application, it would be nice to introduce somne level of color-coding that would represent a quick visual location cue to a reasonably experienced user. One lesson I remembered very quickly as I started into this is that while one can coherently instruct the web server to return something that seems to be what will do what is intended, the browser will render that page according to its own rules. In this circumstance, the color schemes with which I originally experimented had values that were to determine the manner in which the various text lines and links were to be displayed as well as the background color on which the menu should be written. As I experimented with that, however, I came the realization that the order in which arguments are being returned to the browser in the default mod_perl configuration seems to lead to the last set of font values being applied to all of the text on the screen. I assume that this is attributable to the fact that these elements are all enclosed within tables, which must be rendered at some level "inside-out" for the resultant page to be displayed appropriately. Similarly, the body of a page will be rendered according to the last set of body characteristics defined for the page. If, for example, I paint the menus with appropriate background colors, but change the body background color in some subroutine, the resultant page will overwrite the background colors with its own and the visual separation of the menus will be lost. This sort of thing is attributable to the relatively limited nature of the communication between the browser and the client. Among the ways to deal with that are frames, in which parts of the page are generated as separately addressable, scripting interfaces built into the browser that allow more finely-grained control of the client, and cascading style sheets, which allow what are in effect style templates to be applied to dynamically-generated pages. I may adopt such implementations as I go along, but for the foreseeable future I will just work within these limitations. The material that is on the near horizon is much meatier than worrying about font colors.


I chose the color "blanched almond", sort of an off-white, as the background color for the tables holding public-area menus, and the color azure, a light blue-green, as the background color for the league-area menus. This choice was dictated by the fact that the colors provide sufficient contrast without overwhelming link text. (A second option, of course, would be to simply reverse everything and develop a color scheme that involved light letters on a set of dark backgrounds. This can be done and done well; my ID at perlmonks.org is set up to use such a scheme, but most people seem to prefer darker text on lighter backgrounds.)


Now that I have chosen the background colors that I desire, I have to construct the menu using them. The first step I take is to define the scalars $la_colors and $pa_colors in the main section of the BB_STACKED module.

my $pa_colors="blanchedalmond";		
my $la_colors="azure";	
Those scalars must, of course, be defined in a scope in which they can be used when the construct_menu() subroutine is called to construct the pertinent menu. Within the construct_menu subroutine itself, the most trying part of the change lies in keeping track of all of the elements that are now used in the construction of the string representing the menu. A missed angle bracket, a single quote rather than a double quote, such typos can lead to some strange-looking pages that are very troublesome to diagnose. It is not at all inappropriate in such circumstances to copy a piece of working code, paste it in, and make appropriate modifications. Debugging can be a worthwhile learning experience, but spending a half-hour to find a missing quotation mark is of limited utility in this regard.


The new construct_menu subroutine is nowhere near as compact as the previous version, but modest attention to what is going on reveals its structure quickly enough.

sub construct_menu	{
	
	my ($file,$m_width,$pa_colors,$la_colors)=@_;	
	my $m_string;


	$m_string=("<table width=$m_width border='1' cellspacing='0' cellpadding='4'><tr>");
	open(FH,"< $file") or die "can't locate $file";
	
	if ($file=~/main/)	{
		
		while(<FH>)	{
		
			my ($item,$uri)=split /ZzZ/,$_;

			if ($item=~/Public/)	{
						
				$m_string=$m_string."<td bgcolor=$pa_colors ><center><a href=$uri /href> $item </a></center></td>";
			
			}
			elsif ($item=~/League/)	{
				
				$m_string=$m_string."<td bgcolor=$la_colors ><center><a href=$uri /href> $item </a></center></td>";
				
			}
			elsif ($item=~/Home/)	{
				
				$m_string=$m_string."<td><center><a href=$uri /href> $item </a></center></td>";
			}
		}
	}

	elsif ($file !~/main/)	{

		$m_string=("<table width=$m_width border='1' cellspacing='0' cellpadding='4'");		

		if ($file =~ /la/)	{
			
			$m_string=$m_string." bgcolor=".$la_colors."><tr>";
			
		}	
		
		elsif ($file !~ /la/)	{
			
			$m_string=$m_string." bgcolor=".$pa_colors."><tr>";
			
		}
			
		
		
		while(<FH>)	{
		
			my ($item,$uri)=split /ZzZ/,$_;
			$m_string=$m_string."<td><center><a href=$uri /href> $item </a></center></td>";
			
		}
	}

			
	$m_string=$m_string.'</tr></table>';
	return $m_string;
}
First, the main menu is the only one for which different items will be displayed with different background colors, because it is the only menu that is not either a league or a public menu. As a result, I elected to create a separate loop to construct the main menu, after the initial part of the subroutine in which the beginning of the string constructing the relevant menu is defined. Straightforward enough, the scalar representing the relevant background color is inserted into the <td> element tags depending on whether the menu item is home, public, or league. If this is not the main menu, however, the background color is established at the table level. As a result, the strategy I follow is simply to insert the scalar holding the appropriate string in the table definition tab. I have adopted the naming convention of beginning league-oriented menus with the prefix "la" and public menus with the string "pa", and as a result I simply check for the string "la" to determine which scalar to add to the string. At this point, I simply step through the file as before, constructing the menu from the lines of the file. The resultant menus look like the menus in the following images.





The background on the third image is grey, the reason for which will be apparent shortly.


Now I decided to give a logged-in user some capacity to customize their own environment. I am going to skip by an intermediate step here in which I added only the ability to change the colors of the tables generated in the body() subroutine and go right ahead to the point at which I have built in the capability to select background colors for both the overall page and for the tables generated within the body of the page. As I previously indicated this functionality is now part of the preferences page. As the accompanying illustration indicates, my strategy here is simply to give the user a set of color options from which they can make a choice. The selections are implemented as two sets of radio buttons incorporated in tables within the central table on the preferences page.



The following chunk of the preferences() subroutine displays the new middle section

		$$forms->print("</td><td width='35%'><center>Select Background Color</center><br>");
		$$forms->print("<center>For Tables</center><center><table><tr><td bgcolor='coral'><input type='radio' name='back_color_tab' value='coral'>Coral</td><td bgcolor='aqua'><input type='radio' name='back_color_tab' value='aqua'>Aqua</td></tr>");
		$$forms->print("<tr><td bgcolor='chocolate'><input type='radio' name='back_color_tab' value='chocolate'>Chocolate</td><td bgcolor='moccasin'><input type='radio' name='back_color_tab' value='moccasin'>Moccasin</td>L/tr></table<>/center>");
		$$forms->print("<br><center>For Overall Page</center><center><table><tr><td bgcolor='silver'><input type='radio' name='back_color_page' value='silver'>Silver</td><td bgcolor='peru'><input type='radio' name='back_color_page' value='peru'>Peru</td></tr>");
		$$forms->print("<tr><td bgcolor='deepskyblue'><input type='radio' name='back_color_page' value='deepskyblue'>Deep Sky Blue</td><td bgcolor='goldenrod'><input type='radio' name='back_color_page' value='goldenrod'>Goldenrod</td></tr></table></center>");
The color of each selection is illustrated by setting the backgound color of the table element representing that selection to that color, naming the elements of two sets of radio buttons to back_color_tab (for tables) and back_color_page (for the page).


This information will, of course, be stored in the user_char table along with the rest of the parameters related to user information. Giving the user the opportunity to select this information, however, revealed a glitch in the implementation. The glitch lies in the fact that if a user were to select preferences, setting certain elements but leaving others unselected, a blank value would get stored in the user's row in the user_char table for any item left unselected. (Actually, I had spotted this earlier, but at that point it was only a minor annoyance. Adding color section, however, could lead a user to try out all sorts of color combinations and then become frustrated when they lost the game_id setting.) I call this a glitch rather than a bug because in and of itself it is simply the way the application currently works. Users would quickly learn to make all the selections or none at all. At the same time, this is an easy fix. The worst thing about it is that I have to pass more stuff around. (Actually, that is not strictly true. I will come back to that in a bit.) The solution I have implemented involves only storing the parameter value in the relevant scalar if there is something in the parameter in the first place.

sub save_state	{

	##this subroutine saves the selected values for $num_forms and $game_id to the logged-in user's row in the
	##user_char table
	 	
	my ($params,$r,$user_name,$num_forms,$game_id,$back_color_page,$back_color_tab)=@_;
	
	$num_forms=$$params{'num_forms'} if $$params{'num_forms'};
	$game_id=$$params{'game_id'} if $$params{'game_id'};
	$back_color_tab=$$params{'back_color_tab'} if $$params{'back_color_tab'};
	$back_color_page=$$params{'back_color_page'} if $$params{'back_color_page'};
	
	my $_store=$update_user->execute($num_forms,$game_id,$back_color_tab,$back_color_page,$user_name);
	
	
	if ($_store){
		$$r->print("<html><center><table width='60%' border='1'><tr><td><center>Preferences Saved</center></td></tr></table></center></html>");
	}
	elsif (! $_store){
		$$r->print("<html><center><table width='60%' border='1'><tr><td><font color='red'><center>There was a problem saving your preferences</center></font></td></tr></table></html>");
			
		}
} 
The first line of the subroutine reveals that I am now passing into the subroutine the existing values for each of the data elements potentially affected by modifications made on the preferences page. If those items have not bee modified, the relevant parameter will be undefined, the value in the scalar will remain unchanged, and the $update_user statement handle will execute with the previously existing values. This way I can continue to use the prepared statement handle. If circumstances somehow made this approach untenable, I would probably construct the insert statement dynamically based on which parameters held values, and execute it with a $dbh->do(). This approach would not perform as well as the one I have implemented, but it would cut the number of requisite arguments for the subroutine back to the request object and the reference to the parameters hash.


Generating the following pages appropriately, however, requires that the background color for the page as a whole be set early, so that when the tables are drawn their background color overwrites the page background color. As I mentioned earlier, if the page background color is set after any of the tables are drawn their background color will be overwritten with the page background. To set that color before the first menu is drawn, of course, I have to do it in the header() subroutine. The method employed here to fetch stored back_color_page values is the same as that employed in the body() subroutine, with the exeception that in this context I am only using one element of the returned array. As I am only accessing one column in the table, I could use the $dbh->selectcol_arrayref method and thus cut a step off the process, but at this point I want both to stay away from the proliferation of statement handles, because I would have to create a statement handle on a statement returning only back_color_page, and to allow for expanded use of this statement. Once I have the value, of course, it is a simple matter to set the background color for the generated page.
sub header	{

	##display the main menu
	my $r=shift;
	my $user_name=$r->connection->user;	
	my $back_color_page;
	if ($user_name)	{
		$get_user->execute($user_name);
		my @user_settings=$get_user->fetchrow_array;
		$back_color_page=$user_settings[6];
		}

	$r->content_type('text/html');
	$r->print('<html>');
	$r->print("<body bgcolor=$back_color_page>");
	$r->print("<center>$main_menu</center>");
	OK;
}


The value for the backgound color for tables is retrieved, on the other hand, as part of the mechanism through which state information is retrieved in the body() subroutine.
		$back_color_tab=$user_settings[5];
The $back_color_tab scalar is then folded into the $colors scalar, which holds the full "bgcolor=whatever" string, and that scalar is passed into the various subroutines that draw tables.


So now the background colors can be set for an authenticated user, and as a result pages like the following can be drawn ...




Pretty cool, eh? But that's not all! I got to thinking that it would be handy for users to have some indication of who they are logged in as, and what game they are recorded as entering. Since I have that information available, I might as well make use of it. Therefore, I dropped the following snippet at the end of the body() subroutine ...

	$r->print('<center>');	
	if ($user_name)	{
		
			$r->print("User:$full_name ...Game:$game_id");
			
		}
		
	elsif (! $user_name)	{
		
			$r->print("Public Area");
			
		}	
	$r->print('</center>');	
			
While there are fancier ways of expressing that, I cannot think of any that are any more efficient. In its position at the end of the body() subroutine, this little snippet will center the displayed text at the very end of the material generated by body(). The value of game_id is not the most descriptive information, but it does provide sufficient information to allow for verification. I have been working on an implementation that includes the game description rather than the game ID, and will drop that in at a later point, at which time I will probably also move this to a cell within the main menu. In its current version, this produces pages that have the following text just above the footer when the user is logged in and in the league area, and the following when accessing a function incorporated in the public menu:.


But wait, there's more! That's right, folks, in this section you get not just password authentication, not just color-coded menus, not just the ability to set background colors, not just on-page display of user information, but now the ability to select the colors used to display the menus. All for three easy payments of ... nothing!<grin>


I have waited until now to set up customization of menu colors because the implementation of such will inevitably result in a performance hit. In previous versions I have constructed all of the menus in the main part of the BB_STACKED module. As a result they are created at server startup and available to the processing of any request. If users were to set menu colors, however, that construction would have to happen within the context of the processing of any request, for the simple reason that the request holds whatever information is used to determine how the menu will be constructed. For that reason, my initial thought was to build the menus with the default colors at server startup and let it go at that. After incorporating the changes that allow users to set the body and table background colors, however, I decided to allow users to make the choice between menus in the default colors or custom colors with a slight performance hit. So that's what I did.


Most of the modifications associated with this change are essentially the same as those associated with setting the background colors for the body and non-menu tables, involving defining the radio buttons that make that selection in the preferences subroutine and selecting a set of colors that provide some variety.

		$$forms->print("</td><td width='35%'><center>Select Background Colors for Menus</br>(this will result in slightly slower performance, make no selection if you wish to use defaults)<br></center><br>");
		$$forms->print("<center>For Public Area</center><center><table><tr><td bgcolor='gold'><input type='radio' name='pa_colors' value='gold'>Gold</td><td bgcolor='ghostwhite'><input type='radio' name='pa_colors' value='ghostwhite'>Ghost White</td></tr>");
		$$forms->print("<tr><td bgcolor='lightsteelblue'><input type='radio' name='pa_colors' value='lightsteelblue'>Light Steel Blue</td><td bgcolor='mistyrose'><input type='radio' name='pa_colors' value='mistyrose'>Misty Rose</td></tr></table></center>");
		$$forms->print("<br><center>For League Area</center><center><table><tr><td bgcolor='skyblue'><input type='radio' name='la_colors' value='skyblue'>Sky Blue</td><td bgcolor='papayawhip'><input type='radio' name='la_colors' value='papayawhip'>Papaya Whip</td></tr>");
		$$forms->print("<tr><td bgcolor='lightsalmon'><input type='radio' name='la_colors' value='lightsalmon'>Light Salmon</td><td bgcolor='tomato'><input type='radio' name='la_colors' value='tomato'>Tomato</td></tr></table></center><br><br>");


The selection dialogue they generate looks like the image to the right. (When, of course, that set of colors is selected.)


Just as when I added other customizations, the save_state() subroutine now must retrieve those parameters and store them in the database. The first substantive difference between previous customizations and this one lies in how the changes are implemented. Obviously, if I want to display those menus in a different color I have to construct them again, and just as obviously this has to happen in the header() subroutine.

sub header	{

	##display the main menu
	my $r=shift;
	my $user_name=$r->connection->user;	
	my ($back_color_page,@user_settings);
	if ($user_name)	{
		$get_user->execute($user_name);
		@user_settings=$get_user->fetchrow_array;
		$back_color_page=$user_settings[6];
		$pa_colors=$user_settings[8] if $user_settings[8];
		$la_colors=$user_settings[7] if $user_settings[7];
		}

	if ($user_settings[7] or $user_settings[8])	{
		
		$main_menu=construct_menu($menu_file,"100%",$pa_colors,$la_colors);
		$league_menu=construct_menu($league_menu_file,"97%",$pa_colors,$la_colors);
		$public_menu=construct_menu($public_menu_file,"97%",$pa_colors,$la_colors);
		$game_menu=construct_menu($game_menu_file,"99%",$pa_colors,$la_colors);
		
	}
	
	$r->content_type('text/html');
	$r->print('<html>');
	$r->print("<body bgcolor=$back_color_page>");
	$r->print("<center>$main_menu</center>");
	OK;
}
Obviously, I have extended the state retrieval that I initiated just a few paragraphs ago. In this context, however, I do not want to mess with the default settings of $pa_colors or $la_colors if they have not specifically been set, another way of saying that if the user has not selected to customize I do not want to reconstruct the menus. Therefore, the scalars are only modified if the relevant array element is defined, and the menus are only reconstructed if one or the other element is defined.


BUT. I'm now going to back all of that out, and go back to the default color setup for the menus. The reasons for that are instructive in themselves, and is why I have left in the above discussion. The $la_colors and $pa_colors global scalars create menus which are themselves global scalars that are passed to each child. When one client modifies those menus, it is impossible to predict whether the next client will get a copy of the modified menu or an original. When several clients are running, each modifying menus held in global scalars, any client could get any of the defined copies.


The way to get around a problem like this is to use the global scalars to populate a local scalar scoped to the relevant subroutine. In that fashion the global values can be used ot not, but the source value is never modified and whatever modifications are made to a local copy will not affect the menus used by other clients. I have worked up a solution for this circumstance that I will further develop in a later section, but the way it works should better illustrate the manner in which this problem is often addressed. First, I prefaced the names of the versions of the global scalars I create in the main part of BB_STACKED with g to symbolize their status as global variables; as in $g_la_colors and $g_main_menu. Second, I establish a condition that determines whether menu customization has been turned on. On following iterations, the state of that condition determines whether local copies of the menus are created using values stored in the user_char table, and also determines whether the menu scalars are populated with the global version or by the customized local versions. This should produce the desired page while leaving global values unaffected. Unfortunately, it does not, and after reviewing the html returned to the browser my current conjecture is that that is a reflection of the limitations of drawing a complex page in basic html as I discussed above. As this section is lengthy enough, and I no longer wish to delay moving forward with the substantive issues that will be part of the sections to come, I have moved back to generating the menus with the default colors. In a later section, however, I intend to use this topic as a starting point for the implementation of frames, so those disappointed should rather feel anticipation.<grin>


In the next major section I am going to implement an interface by which the game records can be modified, including adding records to the sequence and changing the recorded order of records.