From: Shane L. <sr...@us...> - 2001-03-02 18:57:19
|
Update of /cvsroot/formmagick/formmagick/lib/CGI In directory usw-pr-cvs1:/tmp/cvs-serv27903/formmagick/lib/CGI Modified Files: FormMagick.pm Log Message: Aaagh, I accidentally committed some code that contained 0.2.0 work. This is a fix for that. I think all the error-code stuff still works properly. There may be a bug with preserving data from page to page; testfm seems not to restore input from fields that used to be in error but aren't anymore. Index: FormMagick.pm =================================================================== RCS file: /cvsroot/formmagick/formmagick/lib/CGI/FormMagick.pm,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -r1.12 -r1.13 *** FormMagick.pm 2001/03/02 18:06:16 1.12 --- FormMagick.pm 2001/03/02 18:58:45 1.13 *************** *** 20,24 **** @EXPORT = qw(new display); ! my $VERSION = $VERSION = "0.2.0"; use strict; --- 20,24 ---- @EXPORT = qw(new display); ! my $VERSION = $VERSION = "0.3.1"; use strict; *************** *** 29,39 **** use CGI::Persistent; use CGI::FormMagick::TagMaker; - - # Figure out what language we're using - use CGI::FormMagick::L10N; - my $language = CGI::FormMagick::L10N->get_handle() - || die "Can't find an acceptable language module."; =pod --- 29,35 ---- use CGI::Persistent; use CGI::FormMagick::TagMaker; use CGI::FormMagick::L10N; + =pod *************** *** 47,53 **** my $f = new CGI::FormMagick(); - my $f = new CGI::FormMagick(TYPE => FILE, SOURCE => $myxmlfile, DEBUG => 1); - my $f = new CGI::FormMagick(TYPE => STRING, SOURCE => $data , DEBUG => 1); $f->add_lexicon("fr", { "Yes" => "Oui", "No" => "Non"}); --- 43,58 ---- my $f = new CGI::FormMagick(); + # all options available to new() + my $f = new CGI::FormMagick( + TYPE => FILE, + SOURCE => $myxmlfile, + DEBUG => 1 + SESSIONDIR = "/tmp/session-tokens" + ); + + # other types available + my $f = new CGI::FormMagick(TYPE => STRING, SOURCE => $data ); + $f->add_lexicon("fr", { "Yes" => "Oui", "No" => "Non"}); *************** *** 128,133 **** sub new { shift; ! my $self = {}; ! my %args = @_; my $p = new XML::Parser (Style => 'Tree'); --- 133,138 ---- sub new { shift; ! my $self = {}; ! my %args = @_; my $p = new XML::Parser (Style => 'Tree'); *************** *** 171,174 **** --- 176,196 ---- # print Dumper( $self->{xml}[1][0]) ; # print Dumper( $self->{current_page} ); + + # figure out what language we're using + $self->{language} = CGI::FormMagick::L10N->get_handle() + || die "Can't find an acceptable language module."; + + # use the user-defined session handling directory (or default to + # session-tokens) to store session tokens + if ($args{SESSIONDIR}) { + $self->{sessiondir} = $args{SESSIONDIR}; + } else { + require File::Basename; + + my($scriptname, $scriptdir, $extension) = + File::Basename::fileparse($0, '\.[^\.]+'); + + $self->{sessiondir} = "$scriptdir/session-tokens"; + } bless $self; *************** *** 193,204 **** sub display { my $self = shift; - - # use the session-tokens/ directory to store session tokens - use File::Basename; ! my($scriptname, $scriptdir, $extension) = ! File::Basename::fileparse($0, '\.[^\.]+'); ! ! my $cgi = new CGI::Persistent "$scriptdir/session-tokens"; print $cgi->header; --- 215,222 ---- sub display { my $self = shift; ! # use the user-defined session handling directory (or default to ! # session-tokens) to store session tokens ! my $cgi = new CGI::Persistent $self->{sessiondir}; print $cgi->header; *************** *** 230,247 **** if ($cgi->param("wherenext")) { ! # do whatever we need to with the validated results of the old page ! page_post_event($self, $cgi); ! # increment/decrement pagenum if the user clicked "Next" or "Previous" # or, if the user has explicitly set the "wherenext" param as ! # the result of a post_event or something (eg checking user ! # input to see what page to display next), find the page ! # number by passing the NAME attribute of the PAGE element to ! # the find_page_by_name() routine ! if ($cgi->param("wherenext") eq "Next") { ! $pagenum++ if $cgi->param("wherenext") eq "Next"; } elsif ($cgi->param("wherenext") eq "Previous") { ! $pagenum-- if $cgi->param("wherenext") eq "Previous"; } elsif ($cgi->param("wherenext") eq "Finish") { # nothing! (see below) --- 248,265 ---- if ($cgi->param("wherenext")) { ! # do whatever we need to with the validated results of the old page ! page_post_event($self, $cgi); ! # increment/decrement pagenum if the user clicked "Next" or "Previous" # or, if the user has explicitly set the "wherenext" param as ! # the result of a post_event or something (eg checking user ! # input to see what page to display next), find the page ! # number by passing the NAME attribute of the PAGE element to ! # the find_page_by_name() routine ! if ($cgi->param("wherenext") eq "Next") { ! $pagenum++ if $cgi->param("wherenext") eq "Next"; } elsif ($cgi->param("wherenext") eq "Previous") { ! $pagenum-- if $cgi->param("wherenext") eq "Previous"; } elsif ($cgi->param("wherenext") eq "Finish") { # nothing! (see below) *************** *** 249,258 **** $pagenum = find_page_by_name($self, $cgi->param("wherenext")); } ! ! # re-set the current page, we incremented $pagenum ! $self->{current_page} = $self->{xml}[1][ $pagenum*4 ]; ! # prepare for the new page. ! page_pre_event($self, $cgi); } } --- 267,276 ---- $pagenum = find_page_by_name($self, $cgi->param("wherenext")); } ! ! # re-set the current page, we incremented $pagenum ! $self->{current_page} = $self->{xml}[1][ $pagenum*4 ]; ! # prepare for the new page. ! page_pre_event($self, $cgi); } } *************** *** 270,277 **** print parse_template($self->{xml}[1][0]->{HEADER}); ! print "<h1>", localise($self->{xml}[1][0]->{TITLE}), "</h1>\n"; form_post_event($self, $cgi) if ($cgi->param("wherenext") && ! $cgi->param("wherenext") eq "Finish"); print_page_header($self); --- 288,295 ---- print parse_template($self->{xml}[1][0]->{HEADER}); ! print "<h1>", $self->localise($self->{xml}[1][0]->{TITLE}), "</h1>\n"; form_post_event($self, $cgi) if ($cgi->param("wherenext") && ! $cgi->param("wherenext") eq "Finish"); print_page_header($self); *************** *** 287,292 **** print "<table>\n"; ! # we iterate through the fields using the display_fields() routine ! # that's also where we display the errors if there are any. display_fields($self, $cgi, %errors); --- 305,309 ---- print "<table>\n"; ! # we iterate through the fiels using the display_fields() routine display_fields($self, $cgi, %errors); *************** *** 314,321 **** sub print_buttons { ! my ($self, $pagenum) = @_; print qq(<tr><td></td><td class="buttons">); print qq(<input type="submit" name="wherenext" value="Previous">) ! unless $pagenum == 1; # check whether it's the last page yet --- 331,338 ---- sub print_buttons { ! my ($self, $pagenum) = @_; print qq(<tr><td></td><td class="buttons">); print qq(<input type="submit" name="wherenext" value="Previous">) ! unless $pagenum == 1; # check whether it's the last page yet *************** *** 340,345 **** sub find_page_by_name { ! my $self = shift; ! my $name = shift; # $self->{xml}[1][0] is the attributes of the "form" element. --- 357,362 ---- sub find_page_by_name { ! my $self = shift; ! my $name = shift; # $self->{xml}[1][0] is the attributes of the "form" element. *************** *** 347,356 **** # $self->{xml}[1][8] is the second page. # $self->{xml}[1][8][4] is the first field of the second page. ! ! for (my $i = 4; $i < scalar($self->{xml}[1]); $i += 4) { ! debug($self, "Checking XML bit $i"); ! debug($self, "Name is $self->{xml}[1][$i][0]->{NAME}"); ! return $i/4 if $self->{xml}->[1][$i][0]->{NAME} eq "$name"; ! } } --- 364,373 ---- # $self->{xml}[1][8] is the second page. # $self->{xml}[1][8][4] is the first field of the second page. ! ! for (my $i = 4; $i < scalar($self->{xml}[1]); $i += 4) { ! debug($self, "Checking XML bit $i"); ! debug($self, "Name is $self->{xml}[1][$i][0]->{NAME}"); ! return $i/4 if $self->{xml}->[1][$i][0]->{NAME} eq "$name"; ! } } *************** *** 386,397 **** my $value = $fieldinfo->{VALUE}; my $description = $fieldinfo->{DESCRIPTION}; - - print_field_description($description) if $description; # display errors below the field description. ! my $error = $errors{$label}; ! print_field_error($error) if $error; ! ! my $inputfield; --- 403,413 ---- my $value = $fieldinfo->{VALUE}; my $description = $fieldinfo->{DESCRIPTION}; + $self->print_field_description($description) if $description; + # display errors below the field description. ! my $error = $errors{$label}; ! print_field_error($error) if $error; ! my $inputfield; *************** *** 426,461 **** $inputfield = $tagmaker->select_start( ! type => $type, ! name => $fieldname ! ) . $tagmaker->option_group( ! value => [@option_values], ! text => [@option_labels] ) . $tagmaker->select_end; } elsif ($type eq "RADIO") { ! $inputfield = $tagmaker->input_group(type => "$type", ! name => $fieldname, ! value => [@option_values], ! text => [@option_labels] ); } elsif ($type eq "CHECKBOX") { ! $inputfield = $tagmaker->input(type => "$type", ! name => $fieldname, ! value => $value, ! checked => $fieldinfo->{'CHECKED'}, ! text => $label); } else { ! my %translation_table = ( ! TEXTAREA => 'textarea', ! CHECKBOX => 'input_field', ! TEXT => 'input_field', ! ); my $function_name = $translation_table{$type}; ! $inputfield = $tagmaker->$function_name(type => "$type", ! name => "$fieldname", ! value => "$value", ! ); } ! ! print qq(<tr><td class="label">) . localise($label) . qq(</td> ! <td class="field">$inputfield</td></tr>); } --- 442,477 ---- $inputfield = $tagmaker->select_start( ! type => $type, ! name => $fieldname ! ) . $tagmaker->option_group( ! value => [@option_values], ! text => [@option_labels] ) . $tagmaker->select_end; } elsif ($type eq "RADIO") { ! $inputfield = $tagmaker->input_group(type => "$type", ! name => $fieldname, ! value => [@option_values], ! text => [@option_labels] ); } elsif ($type eq "CHECKBOX") { ! $inputfield = $tagmaker->input(type => "$type", ! name => $fieldname, ! value => $value, ! checked => $fieldinfo->{'CHECKED'}, ! text => $label); } else { ! my %translation_table = ( ! TEXTAREA => 'textarea', ! CHECKBOX => 'input_field', ! TEXT => 'input_field', ! ); my $function_name = $translation_table{$type}; ! $inputfield = $tagmaker->$function_name(type => "$type", ! name => "$fieldname", ! value => "$value", ! ); } ! ! print qq(<tr><td class="label">) . $self->localise($label) . qq(</td> ! <td class="field">$inputfield</td></tr>); } *************** *** 472,480 **** my $self = shift; # the level 2 heading is the PAGE element's TITLE heading ! print "<h2>", localise($self->{current_page}[0]->{TITLE}), "</h2>\n"; ! if ($self->{current_page}[0]->{DESCRIPTION}) { ! print '<p class="pagedescription">', localise($self->{current_page}[0]->{DESCRIPTION}), "</p>\n"; } } --- 488,499 ---- my $self = shift; + my $title = $self->{current_page}[0]->{TITLE}; + my $description = $self->{current_page}[0]->{DESCRIPTION}; + # the level 2 heading is the PAGE element's TITLE heading ! print "<h2>", $self->localise($title), "</h2>\n"; ! if ($description) { ! print '<p class="pagedescription">', $self->localise($description), "</p>\n"; } } *************** *** 487,494 **** sub print_field_description { ! my $d = shift; ! print qq(<tr><td class="fielddescription" colspan=2>$d</td></tr>); } #---------------------------------------------------------------------------- # print_field_error($error) --- 506,516 ---- sub print_field_description { ! my $self = shift; ! my $d = shift; ! $d = $self->localise($d); ! print qq(<tr><td class="fielddescription" colspan=2>$d</td></tr>); } + #---------------------------------------------------------------------------- # print_field_error($error) *************** *** 498,505 **** sub print_field_error { ! my $e = shift; ! print qq(<tr><td class="fielderror" colspan=2>$e</td></tr>); } ! #---------------------------------------------------------------------------- # parse_template($filename) --- 520,528 ---- sub print_field_error { ! my $e = shift; ! print qq(<tr><td class="fielderror" colspan=2>$e</td></tr>); } ! ! #---------------------------------------------------------------------------- # parse_template($filename) *************** *** 509,520 **** sub parse_template { ! my $filename = shift; ! carp("Template file $filename does not exist") unless -e $filename; ! my $template = new Text::Template ( ! TYPE => 'FILE', ! SOURCE => $filename ! ); ! my $output = $template->fill_in(); ! return $output; } --- 532,543 ---- sub parse_template { ! my $filename = shift; ! carp("Template file $filename does not exist") unless -e $filename; ! my $template = new Text::Template ( ! TYPE => 'FILE', ! SOURCE => $filename ! ); ! my $output = $template->fill_in(); ! return $output; } *************** *** 528,538 **** sub localise { ! my $string = shift || ""; ! if (my $localised_string = $language->maketext($string)) { ! return $localised_string; ! } else { ! warn "L10N warning: No localisation string found for '$string' for language $ENV{HTTP_ACCEPT_LANGUAGE}"; ! return $string; ! } } --- 551,562 ---- sub localise { ! my $self = shift; ! my $string = shift || ""; ! if (my $localised_string = $self->{language}->maketext($string)) { ! return $localised_string; ! } else { ! warn "L10N warning: No localisation string found for '$string' for language $ENV{HTTP_ACCEPT_LANGUAGE}"; ! return $string; ! } } *************** *** 561,583 **** sub add_lexicon { ! my $self = shift; ! my ($lang, $lex_ref) = @_; ! # much reference nastiness to point to the Lexicon we want to change ! # ... couldn't have done this without Schuyler's help. Ergh. ! no strict 'refs'; ! my $changeme = "CGI::FormMagick::L10N::${lang}::Lexicon"; ! my $hard_ref = \%$changeme; ! while (my ($a, $b) = each %$lex_ref) { ! $hard_ref->{$a} = $b; ! } ! use strict 'refs'; ! #debug($self, "Our two refs are $hard_ref and $lex_ref"); ! #debug($self, "foo is " . localise("foo")); ! #debug($self, "Error is " . localise("Error")); } --- 585,607 ---- sub add_lexicon { ! my $self = shift; ! my ($lang, $lex_ref) = @_; ! # much reference nastiness to point to the Lexicon we want to change ! # ... couldn't have done this without Schuyler's help. Ergh. ! no strict 'refs'; ! my $changeme = "CGI::FormMagick::L10N::${lang}::Lexicon"; ! my $hard_ref = \%$changeme; ! while (my ($a, $b) = each %$lex_ref) { ! $hard_ref->{$a} = $b; ! } ! use strict 'refs'; ! #debug($self, "Our two refs are $hard_ref and $lex_ref"); ! #debug($self, "foo is " . $self->localise("foo")); ! #debug($self, "Error is " . $self->localise("Error")); } *************** *** 599,605 **** sub debug { ! my $self = shift; ! my $msg = shift; ! print qq(<p class="debug">$msg</p>) if $self->{debug}; } --- 623,629 ---- sub debug { ! my $self = shift; ! my $msg = shift; ! print qq(<p class="debug">$msg</p>) if $self->{debug}; } *************** *** 612,631 **** sub check_l10n { ! my $self = shift; ! print qq( <p>Your choice of language: $ENV{HTTP_ACCEPT_LANGUAGE}</p>); ! my @langs = split(/, /, $ENV{HTTP_ACCEPT_LANGUAGE}); ! foreach my $lang (@langs) { ! print qq(<h2>Language: $lang</h2>); ! ! no strict 'refs'; ! my $lex= "CGI::FormMagick::L10N::${lang}::Lexicon"; ! debug($self, "Lexicon name is $lex"); ! debug($self, scalar(keys %$lex) . " keys in lexicon"); ! foreach my $term (keys %$lex) { ! print qq(<p>$term<br> ! <i>$lex->{$term}</i></p>); ! } ! use strict 'refs'; ! } } --- 636,655 ---- sub check_l10n { ! my $self = shift; ! print qq( <p>Your choice of language: $ENV{HTTP_ACCEPT_LANGUAGE}</p>); ! my @langs = split(/, /, $ENV{HTTP_ACCEPT_LANGUAGE}); ! foreach my $lang (@langs) { ! print qq(<h2>Language: $lang</h2>); ! ! no strict 'refs'; ! my $lex= "CGI::FormMagick::L10N::${lang}::Lexicon"; ! debug($self, "Lexicon name is $lex"); ! debug($self, scalar(keys %$lex) . " keys in lexicon"); ! foreach my $term (keys %$lex) { ! print qq(<p>$term<br> ! <i>$lex->{$term}</i></p>); ! } ! use strict 'refs'; ! } } *************** *** 681,726 **** foreach my $v (@validation_routines) { ! my ($validator, $arg) = ($v =~ ! m/ ! ^ # start of string ! (\w+) # a word (--> $validator) ! (?: # non-capturing (to group the (.*)) ! \( # literal paren ! (.*) # whatever's inside the paren (--> $arg) ! \) # literal close paren ! )? # (.*) is optional (zero or one of them) ! $ # end of string ! /x ); ! ! $self->debug("Validator is $validator"); my $result; ! if ($arg) { $self->debug("Args found: $arg"); ! if ($result = (eval "&${calling_package}::" . ! "$validator('$fielddata', $arg)")) { ! $self->debug("Called user validation routine"); } elsif ($result = (eval "&CGI::FormMagick::Validator::" . ! "$validator('$fielddata', $arg)")) { $self->debug("Called builtin validation routine"); } else { ! $self->debug("Eval failed: $@"); } ! } else { $self->debug("No args found"); ! if ($result = (eval "&${calling_package}::" . ! "$validator('$fielddata')")) { ! $self->debug("Called user validation routine"); } elsif ($result = (eval "&CGI::FormMagick::Validator::" . ! "$validator('$fielddata')")) { $self->debug("Called builtin validation routine"); } else { ! $self->debug("Eval failed: $@"); } } ! $self->debug("Result is $result"); ! push (@results, localise($result)) if ($result ne "OK"); } --- 705,750 ---- foreach my $v (@validation_routines) { + + my ($validator, $arg) = ($v =~ + m/ + ^ # start of string + (\w+) # a word (--> $validator) + (?: # non-capturing (to group the (.*)) + \( # literal paren + (.*) # whatever's inside the paren (--> $arg) + \) # literal close paren + )? # (.*) is optional (zero or one of them) + $ # end of string + /x ); ! $self->debug("Validator is $validator"); my $result; ! if ($arg) { $self->debug("Args found: $arg"); ! if ($result = (eval "&${calling_package}::" . ! "$validator('$fielddata', $arg)")) { ! $self->debug("Called user validation routine"); } elsif ($result = (eval "&CGI::FormMagick::Validator::" . ! "$validator('$fielddata', $arg)")) { $self->debug("Called builtin validation routine"); } else { ! $self->debug("Eval failed: $@"); } ! } else { $self->debug("No args found"); ! if ($result = (eval "&${calling_package}::" . ! "$validator('$fielddata')")) { ! $self->debug("Called user validation routine"); } elsif ($result = (eval "&CGI::FormMagick::Validator::" . ! "$validator('$fielddata')")) { $self->debug("Called builtin validation routine"); } else { ! $self->debug("Eval failed: $@"); } } ! $self->debug("Result is $result"); ! push (@results, $self->localise($result)) if ($result ne "OK"); } *************** *** 729,733 **** if (@results) { ! my $formatted_result = join("; ", @results) . "." ; $errors{$fieldlabel} = $formatted_result if ($formatted_result ne "."); } --- 753,757 ---- if (@results) { ! my $formatted_result = join("; ", @results) . "." ; $errors{$fieldlabel} = $formatted_result if ($formatted_result ne "."); } *************** *** 745,757 **** sub list_error_messages { ! my %errors = @_; ! print qq(<div class="error">\n); ! print qq(<h3>Errors</h3>\n); ! print "<ul>"; ! ! foreach my $field (keys %errors) { ! print "<li>$field: $errors{$field}\n"; ! } ! print "</ul></div>\n"; } --- 769,781 ---- sub list_error_messages { ! my %errors = @_; ! print qq(<div class="error">\n); ! print qq(<h3>Errors</h3>\n); ! print "<ul>"; ! ! foreach my $field (keys %errors) { ! print "<li>$field: $errors{$field}\n"; ! } ! print "</ul></div>\n"; } *************** *** 776,785 **** my $options_ref; ! if ($options_field =~ /=>/) { # user supplied a hash $options_ref = { eval $options_field }; # make options_ref a hashref ! } elsif ($options_field =~ /,/) { # user supplied an array $options_ref = [ eval $options_field ]; # make options_ref an arrayref ! } else { # user supplied a sub name ! $options_field =~ s/\(.*\)$//; # strip parens $options_ref = call_options_routine($self, $cgi, $options_field); } --- 800,809 ---- my $options_ref; ! if ($options_field =~ /=>/) { # user supplied a hash $options_ref = { eval $options_field }; # make options_ref a hashref ! } elsif ($options_field =~ /,/) { # user supplied an array $options_ref = [ eval $options_field ]; # make options_ref an arrayref ! } else { # user supplied a sub name ! $options_field =~ s/\(.*\)$//; # strip parens $options_ref = call_options_routine($self, $cgi, $options_field); } *************** *** 834,838 **** sub calling_info { my $calling_file = (caller(2))[1]; ! $calling_file =~ s!.*/!!; # strip leading directories return $calling_file; --- 858,862 ---- sub calling_info { my $calling_file = (caller(2))[1]; ! $calling_file =~ s!.*/!!; # strip leading directories return $calling_file; *************** *** 859,863 **** unless (eval $voodoo) { ! debug($self, "<p>There was no pre-form routine.</p>\n") } --- 883,887 ---- unless (eval $voodoo) { ! debug($self, "<p>There was no pre-form routine.</p>\n") } *************** *** 882,893 **** unless (do_external_routine($self, $cgi, $post_form_routine)) { ! print "The following data was submitted:\n"; ! print "<ul>\n"; my @params = $cgi->param; ! foreach my $param (@params) { ! my $value = $cgi->param($param); ! print "<li>$param: $value\n"; ! } ! print "</ul>\n"; } --- 906,917 ---- unless (do_external_routine($self, $cgi, $post_form_routine)) { ! print "The following data was submitted:\n"; ! print "<ul>\n"; my @params = $cgi->param; ! foreach my $param (@params) { ! my $value = $cgi->param($param); ! print "<li>$param: $value\n"; ! } ! print "</ul>\n"; } *************** *** 910,930 **** sub do_external_routine { ! my $self = shift; ! my $cgi = shift; ! my $routine = shift || ""; ! ! my $calling_package = (caller(2))[0]; ! #debug($self, "Calling package is $calling_package"); ! ! my $voodoo = "\&$calling_package\:\:$routine(\$cgi)"; ! ! debug($self, "Voodoo is $voodoo"); ! ! if (eval $voodoo) { ! return 1; ! } else { ! debug($self, "There was no routine defined."); ! return 0; ! } } --- 934,954 ---- sub do_external_routine { ! my $self = shift; ! my $cgi = shift; ! my $routine = shift || ""; ! ! my $calling_package = (caller(2))[0]; ! #debug($self, "Calling package is $calling_package"); ! ! my $voodoo = "\&$calling_package\:\:$routine(\$cgi)"; ! ! debug($self, "Voodoo is $voodoo"); ! ! if (eval $voodoo) { ! return 1; ! } else { ! debug($self, "There was no routine defined."); ! return 0; ! } } *************** *** 951,956 **** <FIELD ID="username" LABEL="Choose a username" TYPE="TEXT" VALIDATION="username" DESCRIPTION="Your username must ! be between 3 and 8 characters in length and contain only letters ! and numbers."/> </PAGE> <PAGE NAME="Payment" TITLE="Payment details" --- 975,980 ---- <FIELD ID="username" LABEL="Choose a username" TYPE="TEXT" VALIDATION="username" DESCRIPTION="Your username must ! be between 3 and 8 characters in length and contain only letters ! and numbers."/> </PAGE> <PAGE NAME="Payment" TITLE="Payment details" |