#!/usr/bin/perl -w
use strict;
print "Content-type: text/html\n\n";
print "\<HTML\>\
\<HEAD\>\
\<TITLE\>Quiz\ \#1\<\/TITLE\>\
\<\/HEAD\>\
\<BODY\>\
\<SCRIPT\ type\=\"text\/javascript\"\ src\=\"\.\.\/\.\.\/pagetop\.js\"\>\<\/SCRIPT\>\
\<B\>Connected\:\ An\ Internet\ Encyclopedia\<\/B\>\
\<BR\>\
\<EM\>Quiz\ \#1\<\/EM\>\<BR\>\
\<HR\>\<CENTER\>\
\<B\>Up\:\<\/B\>\
\<A\ HREF\=\"\.\.\/\.\.\/index\.htm\"\>Connected\:\ An\ Internet\ Encyclopedia\<\/A\>\<BR\>\
\<B\>Up\:\<\/B\>\
\<A\ HREF\=\"\.\.\/index\.htm\"\>Programmed\ Instruction\ Course\<\/A\>\<BR\>\
\<B\>Up\:\<\/B\>\
\<A\ HREF\=\"index\.htm\"\>Subnetting\ and\ CIDR\<\/A\>\<BR\>\
\<\/CENTER\>\
\<B\>Prev\:\<\/B\>\ \<A\ HREF\=\"12\.htm\"\>Power\ of\ Two\ Blocks\ \(cont\)\<\/A\>\<BR\>\
\<B\>Next\:\<\/B\>\ \<A\ HREF\=\"quiz1b\.cgi\"\>Quiz\ \#1\ \(cont\)\<\/A\>\<BR\>\
\<HR\>\<P\>\
\<H3\>Quiz\ \#1\<\/H3\>\<P\>\
";
print "\<TITLE\>";
print "Quiz\ \#1";
print "\<\/TITLE\>";
print "\
\
";


my %FORM;
my $buffer;

if (exists $ENV{"CONTENT_LENGTH"}) {
    read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
} elsif (exists $ENV{"QUERY_STRING"}) {
    $buffer = $ENV{"QUERY_STRING"};
}

# Split the name-value pairs
my @pairs = split(/&/, $buffer);

foreach my $pair (@pairs)
{
    my ($name, $value) = split(/=/, $pair);

    # Un-Webify plus signs and %-encoding
    $value =~ tr/+/ /;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    $FORM{$name} = $value;
}


my $quizType = exists $FORM{"type"} ? $FORM{"type"} : "easy";

# Play a little game here so we can tag each quiz with a unique ID value,
# to aid in recreating bugs.

my $quizseed;

if (exists $FORM{"seed"}) {
    $quizseed = $FORM{"seed"};
} else {
    srand;
    $quizseed = int rand 10000000000;
}

srand $quizseed;

print "\
\
Test\ your\ knowledge\ by\ working\ the\ following\ problems\.\
Every\ time\ you\ reload\ this\ page\,\ you\'ll\ get\ a\ new\,\ randomly\ generated\ quiz\.\
If\ you\ believe\ you\ have\ encountered\ a\ bug\ in";
print "\ the\ program\ which\ generates\
the\ quiz\,\ please\ email\ me\ at\
";
print "\<A\ HREF\=\"mailto\:baccala\@freesoft\.org\"\>";
print "baccala\@freesoft\.org";
print "\<\/A\>";
print "\,\ and\
be\ sure\ to\ include\ this\ quiz\'s\ ID\ code\:\
";
print "$quizType-$quizseed";print "\
";
print "\<P\>";
print "\
\
";
print "\<SCRIPT\>";
print "\
function\ Answer\(question\)\ \{\
\ \ \ document\.FORM\[question\]\.value\ \=\ \"\"\
\ \ \ for\ \(var\ i\=1\;\ i\<Answer\.arguments\.length\;\ i\+\+\)\ \{\
\ \ \ \ \ \ document\.FORM\[question\]\.value\ \+\=\ Answer\.arguments\[i\]\
\ \ \ \ \ \ if\ \(i\ \<\ Answer\.arguments\.length\-1\)\ \{\
\ \ \ \ \ \ \ \ \ \ document\.FORM\[question\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ \}\
\ \ \ \}\
\}\
\
function\ doQ6\(input\,\ output\,\ target_a\,\ target_b\,\ target_c\,\ target_d\)\ \{\
\ \ \ var\ userin\ \=\ document\.FORM\[input\]\.value\
\ \ \ var\ start\ \=\ 0\
\ \ \ var\ end\ \=\ \-1\
\ \ \ var\ elementsSeen\ \=\ 0\
\ \ \ var\ address\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ mask\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ target\ \=\ new\ Array\(target_a\,\ target_b\,\ target_c\,\ target_d\)\
\ \ \ var\ ordinal\ \=\ new\ Array\(\"first\"\,\ \"second\"\,\ \"third\"\,\ \"fourth\"\)\
\ \ \ var\ prefixlen\
\ \ \ var\ i\
\
\ \ \ document\.FORM\[output\]\.value\ \=\ \"\"\
\
\ \ \ while\ \(\(\(end\ \=\ userin\.indexOf\(\"\.\"\,\ end\+1\)\)\ \!\=\ \-1\)\ \|\|\
\ \ \ \ \ \ \ \ \ \ \(\(end\ \=\ userin\.indexOf\(\"\/\"\,\ end\+1\)\)\ \!\=\ \-1\)\)\ \{\
\ \ \ \ \ \ if\ \(elementsSeen\ \=\=\ 4\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ portion\ must\ contain\ no\ more\ than\ four\ numbers\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ if\ \(end\-start\ \=\=\ 0\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ address\[elementsSeen\]\ \=\ userin\.slice\(start\,end\)\
\ \ \ \ \ \ if\ \(\(address\[elementsSeen\]\ \<\ 0\)\ \|\|\ \(address\[elementsSeen\]\ \>\ 255\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ elements\ must\ be\ between\ 0\ and\ 255\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ \ \ \ if\ \(\(\!\ \(address\[elementsSeen\]\ \>\=\ 0\)\)\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\!\ \(address\[elementsSeen\]\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\(address\[elementsSeen\]\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \ \ \ \(address\[elementsSeen\]\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\!\=0\ \&\&\ address\[elementsSeen\]\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ elementsSeen\ \+\+\
\ \ \ \ \ \ start\ \=\ end\+1\
\
\ \ \ \ \ \ if\ \(userin\.charAt\(end\)\ \=\=\ \"\/\"\)\ break\
\ \ \ \}\
\
\ \ \ if\ \(end\ \=\=\ \-1\ \|\|\ userin\.charAt\(end\)\ \!\=\ \"\/\"\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Missing\ prefix\ length\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ if\ \(end\ \=\=\ userin\.length\-1\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Missing\ prefix\ length\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ prefixlen\ \=\ userin\.slice\(end\+1\)\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ if\ \(\(\!\ \(prefixlen\ \>\=\ 0\)\)\ \&\&\ \(\!\ \(prefixlen\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ if\ \(prefixlen\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \(\(prefixlen\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \(prefixlen\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(prefixlen\!\=0\ \&\&\ prefixlen\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(prefixlen\ \<\ 0\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\ else\ if\ \(prefixlen\ \<\=\ 8\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ \(255\<\<\(8\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[1\]\ \=\ 0\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 8\ \&\&\ prefixlen\ \<\=\ 16\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ \(255\<\<\(16\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 2\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ two\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 16\ \&\&\ prefixlen\ \<\=\ 24\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ \(255\<\<\(24\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 3\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ three\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 24\ \&\&\ prefixlen\ \<\=\ 32\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ 255\
\ \ \ \ \ \ mask\[3\]\ \=\ \(255\<\<\(32\-prefixlen\)\)\&255\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 4\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ four\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ for\ \(i\=0\;\ i\<4\;\ i\+\+\)\ \{\
\ \ \ \ \ \ if\ \(\(address\[i\]\ \&\ mask\[i\]\)\ \!\=\ address\[i\]\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ Trailing\ bits\ not\ zero\ in\ \"\
\	\ document\.FORM\[output\]\.value\ \+\=\ ordinal\[i\]\ \+\ \"\ byte\"\
\	\ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \}\
\
\ \ \ for\ \(i\=0\;\ i\<4\;\ i\+\+\)\ \{\
\ \ \ \ \ \ if\ \(\(address\[i\]\ \&\ mask\[i\]\)\ \!\=\ \(target\[i\]\ \&\ mask\[i\]\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ Prefix\ doesn\'t\ match\ in\ \"\
\	\ document\.FORM\[output\]\.value\ \+\=\ ordinal\[i\]\ \+\ \"\ byte\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \}\
\
\ \ \ if\ \(prefixlen\ \=\=\ 0\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Well\,\ I\ guess\ that\'s\ a\ correct\ answer\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Of\ course\,\ a\ prefix\ of\ 0\/0\ matches\ anything\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Why\ not\ try\ to\ be\ a\ little\ more\ creative\?\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Correct\!\"\
\ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\%0d\%0a\"\)\
\
\ \ \ if\ \(prefixlen\=\=8\ \|\|\ prefixlen\=\=16\ \|\|\ prefixlen\=\=24\ \|\|\ prefixlen\=\=32\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"You\ know\,\ a\ byte\-boundary\ prefix\ is\ pretty\ easy\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Try\ again\,\ and\ challenge\ yourself\ with\ something\ like\ \/14\"\
\ \ \ \}\
\}\
\
function\ doQ7\(input\,\ output\,\ target_a\,\ target_b\,\ target_c\,\ target_d\,\ prefixlen\)\ \{\
\ \ \ var\ userin\ \=\ document\.FORM\[input\]\.value\
\ \ \ var\ start\ \=\ 0\
\ \ \ var\ end\ \=\ \-1\
\ \ \ var\ elementsSeen\ \=\ 0\
\ \ \ var\ address\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ mask\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ target\ \=\ new\ Array\(target_a\,\ target_b\,\ target_c\,\ target_d\)\
\ \ \ var\ ordinal\ \=\ new\ Array\(\"first\"\,\ \"second\"\,\ \"third\"\,\ \"fourth\"\)\
\ \ \ var\ i\
\
\ \ \ document\.FORM\[output\]\.value\ \=\ \"\"\
\
\ \ \ while\ \(elementsSeen\ \<\ 3\ \&\&\ \(end\ \=\ userin\.indexOf\(\"\.\"\,\ end\+1\)\)\ \!\=\ \-1\)\ \{\
\ \ \ \ \ \ if\ \(end\-start\ \=\=\ 0\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ address\[elementsSeen\]\ \=\ userin\.slice\(start\,end\)\
\ \ \ \ \ \ if\ \(\(address\[elementsSeen\]\ \<\ 0\)\ \|\|\ \(address\[elementsSeen\]\ \>\ 255\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ elements\ must\ be\ between\ 0\ and\ 255\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ \ \ \ if\ \(\(\!\ \(address\[elementsSeen\]\ \>\=\ 0\)\)\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\!\ \(address\[elementsSeen\]\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\(address\[elementsSeen\]\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \ \ \ \(address\[elementsSeen\]\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\!\=0\ \&\&\ address\[elementsSeen\]\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ elementsSeen\ \+\+\
\ \ \ \ \ \ start\ \=\ end\+1\
\ \ \ \}\
\
\ \ \ if\ \(elementsSeen\ \!\=\ 3\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ if\ \(end\ \=\=\ userin\.length\-1\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ address\[elementsSeen\]\ \=\ userin\.slice\(end\+1\)\
\
\ \ \ if\ \(\(address\[elementsSeen\]\ \<\ 0\)\ \|\|\ \(address\[elementsSeen\]\ \>\ 255\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ elements\ must\ be\ between\ 0\ and\ 255\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ if\ \(\(\!\ \(address\[elementsSeen\]\ \>\=\ 0\)\)\ \&\&\
\ \ \ \ \ \ \ \(\!\ \(address\[elementsSeen\]\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ if\ \(address\[elementsSeen\]\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \(\(address\[elementsSeen\]\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \(address\[elementsSeen\]\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(address\[elementsSeen\]\!\=0\ \&\&\ address\[elementsSeen\]\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ elementsSeen\ \+\+\
\
\ \ \ if\ \(prefixlen\ \<\ 0\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\ else\ if\ \(prefixlen\ \<\=\ 8\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ \(255\<\<\(8\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[1\]\ \=\ 0\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 8\ \&\&\ prefixlen\ \<\=\ 16\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ \(255\<\<\(16\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 16\ \&\&\ prefixlen\ \<\=\ 24\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ \(255\<\<\(24\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 24\ \&\&\ prefixlen\ \<\=\ 32\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ 255\
\ \ \ \ \ \ mask\[3\]\ \=\ \(255\<\<\(32\-prefixlen\)\)\&255\
\ \ \ \}\ else\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ for\ \(i\=0\;\ i\<4\;\ i\+\+\)\ \{\
\ \ \ \ \ \ if\ \(\(address\[i\]\ \&\ mask\[i\]\)\ \!\=\ \(target\[i\]\ \&\ mask\[i\]\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ Address\ doesn\'t\ match\ in\ \"\
\	\ document\.FORM\[output\]\.value\ \+\=\ ordinal\[i\]\ \+\ \"\ byte\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \}\
\
\ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Correct\!\"\
\
\ \ \ if\ \(address\[0\]\ \=\=\ target\[0\]\ \&\&\ address\[1\]\ \=\=\ target\[1\]\ \&\&\
\ \ \ \ \ \ \ address\[2\]\ \=\=\ target\[2\]\ \&\&\ address\[3\]\ \=\=\ target\[3\]\ \&\&\
\ \ \ \ \ \ \ mask\[3\]\ \!\=\ 255\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Specifying\ an\ address\ exactly\ equal\ to\ the\ prefix\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"is\ a\ bit\ trivial\,\ don\'t\ you\ think\?\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Why\ not\ try\ to\ come\ up\ with\ something\ a\ bit\ different\?\"\
\ \ \ \}\
\}\
\
function\ doQ8\(input\,\ output\,\ target_a\,\ target_b\,\ target_c\,\ target_d\,\ plen\)\ \{\
\ \ \ var\ userin\ \=\ document\.FORM\[input\]\.value\
\ \ \ var\ start\ \=\ 0\
\ \ \ var\ end\ \=\ \-1\
\ \ \ var\ elementsSeen\ \=\ 0\
\ \ \ var\ address\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ mask\ \=\ new\ Array\(0\,0\,0\,0\)\
\ \ \ var\ target\ \=\ new\ Array\(target_a\,\ target_b\,\ target_c\,\ target_d\)\
\ \ \ var\ ordinal\ \=\ new\ Array\(\"first\"\,\ \"second\"\,\ \"third\"\,\ \"fourth\"\)\
\ \ \ var\ prefixlen\
\ \ \ var\ i\
\
\ \ \ document\.FORM\[output\]\.value\ \=\ \"\"\
\
\ \ \ while\ \(\(\(end\ \=\ userin\.indexOf\(\"\.\"\,\ end\+1\)\)\ \!\=\ \-1\)\ \|\|\
\ \ \ \ \ \ \ \ \ \ \(\(end\ \=\ userin\.indexOf\(\"\/\"\,\ end\+1\)\)\ \!\=\ \-1\)\)\ \{\
\ \ \ \ \ \ if\ \(elementsSeen\ \=\=\ 4\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ portion\ must\ contain\ no\ more\ than\ four\ numbers\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ if\ \(end\-start\ \=\=\ 0\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ address\[elementsSeen\]\ \=\ userin\.slice\(start\,end\)\
\ \ \ \ \ \ if\ \(\(address\[elementsSeen\]\ \<\ 0\)\ \|\|\ \(address\[elementsSeen\]\ \>\ 255\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Dotted\ quad\ elements\ must\ be\ between\ 0\ and\ 255\"\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ \ \ \ if\ \(\(\!\ \(address\[elementsSeen\]\ \>\=\ 0\)\)\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\!\ \(address\[elementsSeen\]\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \ \ \ \(\(address\[elementsSeen\]\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \ \ \ \(address\[elementsSeen\]\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ if\ \(address\[elementsSeen\]\!\=0\ \&\&\ address\[elementsSeen\]\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\	\ return\
\ \ \ \ \ \ \}\
\
\ \ \ \ \ \ elementsSeen\ \+\+\
\ \ \ \ \ \ start\ \=\ end\+1\
\
\ \ \ \ \ \ if\ \(userin\.charAt\(end\)\ \=\=\ \"\/\"\)\ break\
\ \ \ \}\
\
\ \ \ if\ \(end\ \=\=\ \-1\ \|\|\ userin\.charAt\(end\)\ \!\=\ \"\/\"\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Missing\ prefix\ length\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ if\ \(end\ \=\=\ userin\.length\-1\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Missing\ prefix\ length\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\ \ \ prefixlen\ \=\ userin\.slice\(end\+1\)\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ implement\ it\,\ but\ do\ so\ in\ a\ way\
\ \ \ \/\/\ that\ works\ on\ those\ that\ don\'t\
\ \ \ if\ \(\(\!\ \(prefixlen\ \>\=\ 0\)\)\ \&\&\ \(\!\ \(prefixlen\ \<\=\ 255\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ \/\/\ Check\ for\ NaN\ on\ systems\ that\ don\'t\ implement\ it\
\ \ \ if\ \(prefixlen\ \=\=\ 0\ \&\&\
\ \ \ \ \ \ \ \(\(prefixlen\.length\ \!\=\ 1\)\ \|\|\
\ \ \ \ \ \ \ \ \(prefixlen\.charAt\(0\)\ \!\=\ \"0\"\)\)\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Syntax\:\ A\.B\.C\.D\/N\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(prefixlen\!\=0\ \&\&\ prefixlen\.charAt\(0\)\=\=\"0\"\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"By\ convention\,\ leading\ zeros\ are\ not\ written\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(prefixlen\ \<\ 0\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\ else\ if\ \(prefixlen\ \<\=\ 8\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ \(255\<\<\(8\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[1\]\ \=\ 0\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 8\ \&\&\ prefixlen\ \<\=\ 16\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ \(255\<\<\(16\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[2\]\ \=\ 0\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 2\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ two\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 16\ \&\&\ prefixlen\ \<\=\ 24\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ \(255\<\<\(24\-prefixlen\)\)\&255\
\ \ \ \ \ \ mask\[3\]\ \=\ 0\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 3\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ three\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ if\ \(prefixlen\ \>\ 24\ \&\&\ prefixlen\ \<\=\ 32\)\ \{\
\ \ \ \ \ \ mask\[0\]\ \=\ 255\
\ \ \ \ \ \ mask\[1\]\ \=\ 255\
\ \ \ \ \ \ mask\[2\]\ \=\ 255\
\ \ \ \ \ \ mask\[3\]\ \=\ \(255\<\<\(32\-prefixlen\)\)\&255\
\ \ \ \ \ \ if\ \(elementsSeen\ \<\ 4\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Must\ specify\ four\ bytes\ of\ address\ for\ a\ prefix\ length\ of\ \"\ \+\ prefixlen\
\	\ return\
\ \ \ \ \ \ \}\
\ \ \ \}\ else\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \=\ \"Prefix\ length\ must\ be\ between\ 0\ and\ 32\"\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ for\ \(i\=0\;\ i\<4\;\ i\+\+\)\ \{\
\ \ \ \ \ \ if\ \(\(address\[i\]\ \&\ mask\[i\]\)\ \!\=\ address\[i\]\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ Trailing\ bits\ not\ zero\ in\ \"\
\	\ document\.FORM\[output\]\.value\ \+\=\ ordinal\[i\]\ \+\ \"\ byte\"\
\	\ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ \ \ \ return\
\ \ \ \ \ \ \}\
\ \ \ \}\
\
\ \ \ if\ \(plen\ \!\=\ prefixlen\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ the\ first\ \"\ \+\ plen\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"\ bits\ match\ between\ these\ addresses\"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ if\ \(target_a\ \!\=\ address\[0\]\ \|\|\ target_b\ \!\=\ address\[1\]\ \|\|\ target_c\ \!\=\ address\[2\]\ \|\|\ target_d\ \!\=\ address\[3\]\)\ \{\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Wrong\ \-\ the\ correct\ answer\ is\ \"\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ target_a\
\ \ \ \ \ \ if\ \(plen\ \>\ 8\)\ \{\
\ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"\.\"\ \+\ target_b\
\ \ \ \ \ \ \ \ \ if\ \(plen\ \>\ 16\)\ \{\
\ \ \ \ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"\.\"\ \+\ target_c\
\ \ \ \ \ \ \ \ \ \ \ \ if\ \(plen\ \>\ 24\)\ \{\
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"\.\"\ \+\ target_d\
\ \ \ \ \ \ \ \ \ \ \ \ \}\
\ \ \ \ \ \ \ \ \ \}\
\ \ \ \ \ \ \}\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ \"\/\"\ \+\ plen\
\ \ \ \ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\ \ \ \ \ \ return\
\ \ \ \}\
\
\ \ \ document\.FORM\[output\]\.value\ \+\=\ \"Correct\!\"\
\ \ \ document\.FORM\[output\]\.value\ \+\=\ unescape\(\"\%0d\%0a\"\)\
\}\
\
";
print "\<\/SCRIPT\>";
print "\
";
print "\<FORM\ NAME\=\"FORM\"\ onSubmit\=\"return\ false\"\>";
print "\
\
";


my $qnum;

my @ordinal = ("first", "second", "third", "fourth");

sub randomPrefixLength {
    my ($type) = @_;
    my $allow0 = 1;
    my $allow32 = 1;
    my $result;

    if ($type eq "easy") {
	$result = 8 * (int rand (3 + $allow0 + $allow32));
	$result += 8 if (not $allow0);
    } elsif ($type eq "medium") {
	$result = 8 * (int rand 4);
	$result += 4 + int rand 3;
    } else {
	$result = 2 + int rand 30 while ($result % 8 == 0);
    }

    return $result;
}

sub mask {
    my ($prefixLen) = @_;

    return 0 if ($prefixLen == 0);

    return (0xffffffff << (32-$prefixLen)) & 0xffffffff;
}

sub keyMask {
    my ($prefixLen) = @_;

    $prefixLen -= 8 while ($prefixLen > 8);

    return (255 << (8-$prefixLen)) & 255;
}

sub keyIndex {
    my ($prefixLen) = @_;

    return 0 if ($prefixLen == 0);
    return int (($prefixLen-1)/8);
}

sub keyByte {
    my ($prefixLen, $address) = @_;

    return ($address >> (8*(3-&keyIndex($prefixLen)))) & 255;
}

sub binary {
    my ($value) = @_;
    my $result = "";

    for (my $i=0; $i < 8; $i ++) {
	$result = (($value & 1) ? "1" : "0") . $result;
	$value >>= 1;
    }
    return $result;
}

sub randomAddress {
    return ((1+(int rand 239)) << 24) | (int rand 1<<24);
}

sub randomPrefix {
    my ($type) = @_;
    my $prefixLen = &randomPrefixLength($type);
    my $prefixAddr = &randomAddress;

    $prefixAddr &= &mask($prefixLen);

    # If this is a "medium" difficult quiz, then make sure the
    # "key byte" - the one being manipulated in binary - doesn't
    # exceed 64.  We mask it, strip it off, whittle it down, and put it back

    if ($type eq "medium") {
	my $keyMask = 255 << (8 * (3 - &keyIndex($prefixLen)));
	my $keyByte = $prefixAddr & $keyMask;
	$prefixAddr &= ~ $keyMask;
	$prefixAddr |= $keyByte & (63 << (8 * (3 - &keyIndex($prefixLen))));
    }

    return ($prefixLen, $prefixAddr);
}

sub formatPrefixNoLen {
    my ($prefixLen, $prefixAddr) = @_;
    my $result = "";

    return "0" if ($prefixLen == 0);

    my $limit = 3 - int(($prefixLen-1)/8);

    for (my $i=3; $i >= $limit; $i--) {
	$result .= ($prefixAddr >> (8*$i)) & 255;
	$result .= "." unless ($i == $limit);
    }

    return $result;
}

sub formatPrefix {
    my ($prefixLen, $prefixAddr) = @_;

    return &formatPrefixNoLen($prefixLen, $prefixAddr) . "/$prefixLen";
}

sub formatAddress {
    my ($addr) = @_;
    my $result = "";

    for (my $i=3; $i>=0; $i--) {
	$result .= ($addr >> (8*$i)) & 255;
	$result .= "." if ($i);
    }
    return $result;
}

sub randomMatchingAddress {
    my ($prefixLen, $prefixAddr) = @_;
    my $mask = &mask($prefixLen);

    return $prefixAddr | (&randomAddress & (~ $mask));
}

sub prefixPermutation {
    my ($prefixLen) = @_;
    my @changes = (1, 2, 3, 4, 5, 6);
    my $change = 0;

    while ($change == 0) {
	$change = $changes[int rand @changes];

	$change <<= (32 - $prefixLen);
	$change &= 0xffffffff;
    }

    return $change;
}

sub randomNonMatchingAddress {
    my ($prefixLen, $prefixAddr) = @_;
    my $result = &randomMatchingAddress($prefixLen, $prefixAddr);

    return $result ^ &prefixPermutation($prefixLen);
}

# Permute a prefix so it no longer matches what it used to

sub permutePrefix {
    my ($prefixLen, $prefixAddr) = @_;

    if (rand() < 0.5 and $prefixLen < 29) {
	if ($quizType eq "easy" and $prefixLen <= 24) {
	    $prefixLen += 8;
	    $prefixAddr |= int(rand 256) << (32 - $prefixLen);
	} else {
	    $prefixLen += 1 + int rand 2;
	    $prefixAddr ^= &prefixPermutation($prefixLen);
	}
    } elsif (rand() < 0.5 and $prefixLen > 3) {
	if ($quizType eq "easy" and $prefixLen >= 8) {
	    $prefixLen -= 8;
	} else {
	    $prefixLen -= 1 + int rand 2;
	    $prefixAddr &= &mask($prefixLen);
	}
	$prefixAddr ^= &prefixPermutation($prefixLen);
    } else {
	$prefixAddr ^= &prefixPermutation($prefixLen);
    }

    return ($prefixLen, $prefixAddr);
}

sub longestCommonPrefix {
    my @addrs = @_;
    my $prefixAddr;
    my $prefixLen;
    my $mask;

    for ($prefixLen=1; $prefixLen<=33; $prefixLen++) {
	last if ($prefixLen == 33);
	$mask = &mask($prefixLen);
	$prefixAddr = $addrs[0] & $mask;

	last if ((grep { ($prefixAddr & $mask) == ($_ & $mask) } @addrs)
		  != (scalar @addrs));
    }
    $prefixLen --;

    return ($prefixLen, $addrs[0] & &mask($prefixLen));
}

sub scramble {
    my @array = @_;

    for (my $i=0; $i < scalar @array; $i++) {
	my $j = int rand scalar @array;
	my $item = $array[$i];
	$array[$i] = $array[$j];
	$array[$j] = $item;
    }
    return @array;
}

sub match {
    my ($addr, @prefix) = @_;

    return ((&mask($prefix[0]) & $addr) == (&mask($prefix[0]) & $prefix[1]));
}

sub contains {
    my ($len1, $addr1, $len2, $addr2) = @_;

    return 0 if ($len1 > $len2);
    return ((&mask($len1) & $addr1) == (&mask($len1) & $addr2));
}

sub explain {
    my ($addr, @prefix) = @_;
    my $prefix1 = 8 * int($prefix[0]/8);

    if ($prefix[0] == 32) {
	print "'32 is the length of an IP address in bits',\n";
	print "'so ", &formatPrefix(@prefix), " is an exact match for ";
	print &formatAddress($prefix[1]), "'";
    } elsif ($prefix[0] == 0) {
	print "'0/0 matches any address'";
    } elsif ($prefix[0]%8 == 0) {
	print "'The prefix length of $prefix[0] is a multiple of eight',\n";
	print "'so the first ", $prefix[0], "/8=", $prefix[0]/8;
	print $prefix[0]==8 ? " byte" : " bytes";
	print " must match ", &formatPrefixNoLen(@prefix), " exactly.'";
    } elsif ((&mask($prefix1) & $addr) != (&mask($prefix1) & $prefix[1])) {
	print "'The prefix length of $prefix[0] is greater than $prefix1',\n";
	print "'so the first ", int($prefix[0]/8);
	print $prefix[0]==8 ? " byte" : " bytes";
	print " must match ", &formatPrefixNoLen($prefix1, $prefix[1]);
	print " exactly.'";
    } else {
	my $binarycorrect = &binary(&keyByte(@prefix));
	print "'", &keyByte(@prefix), " in binary is ", $binarycorrect;
	print " so the ", $ordinal[$prefix1/8], " byte\\'s',\n'first ";
	print "$prefix[0]-$prefix1=" if ($prefix1 != 0);
	print $prefix[0]-$prefix1;
	print (($prefix[0]-$prefix1)==1 ? " bit must be ":" bits must be ");
	print substr($binarycorrect, 0, $prefix[0]-$prefix1), "',\n'";
	print &keyByte($prefix[0], $addr), " in binary is ";
	print &binary(&keyByte($prefix[0], $addr)), "'";
    }
}

sub problem1 {

    # Pick a random prefix; anything other than 0/0 will work

    my @prefix = &randomPrefix($quizType);
    @prefix = &randomPrefix($quizType) while ($prefix[1] == 0);

    # Pick a correct answer - a matching address

    my $correct = &randomMatchingAddress(@prefix);

    # Pick three non-matching address; take care to make them all different

    my @wrongs;
    wrongs: while (@wrongs < 3) {
	my $addr = &randomNonMatchingAddress(@prefix);
	for my $others (@wrongs) {
	    next wrongs if ($others == $addr);
	}
	push @wrongs, $addr;
    }

    my @order = &scramble(0,1,2,3);

    print "Which one of the following addresses matches <TT>", &formatPrefix(@prefix), "</TT>?\n";
    print "<P><CENTER><TABLE>\n";
    foreach my $i (@order) {
	my $addr;
	if ($i == 0) {
	    $addr = $correct;
	} else {
	    $addr = $wrongs[$i-1];
	}
	print "<TR><TD><INPUT TYPE=\"Radio\" NAME=\"ChoiceQ$qnum\" onClick=\"Answer('Q$qnum',\n";
	if ($i == 0) {
	    print "'Correct!";
	} else {
	    print "'Wrong";
	}
	print " - ", &formatAddress($addr);
	if ($i == 0) {
	    print " matches ";
	} else {
	    print " doesn\\'t match ";
	}
	print &formatPrefix(@prefix), "','',\n";

	&explain($addr, @prefix);

	print ")\"><TT>", &formatAddress($addr), "</TT>\n\n";
    }
    print "</TABLE>\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n\n";
}


sub problem2 {
    my @correct = &randomPrefix($quizType);

    my $addr = &randomMatchingAddress(@correct);

    # Pick three non-matching prefixes; take care to make them all different

    my @wrongs;
    wrongs: while (@wrongs < 3) {
	my @wrong = &permutePrefix(@correct);
	next wrongs if (&match($addr, @wrong));
	for my $others (@wrongs) {
	    next wrongs if ($$others[0] == $wrong[0] and $$others[1] == $wrong[1]);
	}
	push @wrongs, \@wrong;
    }

    my @order = &scramble(0,1,2,3);

    print "Which one of the following prefixes matches <TT>", &formatAddress($addr), "</TT>?\n";
    print "<P><CENTER><TABLE>\n";
    foreach my $i (@order) {
	my @answer;
	if ($i == 0) {
	    @answer = @correct;
	} else {
	    @answer = @{$wrongs[$i-1]};
	}
	print "<TR><TD><INPUT TYPE=\"Radio\" NAME=\"ChoiceQ$qnum\" onClick=\"Answer('Q$qnum',\n";
	if ($i == 0) {
	    print "'Correct!";
	} else {
	    print "'Wrong";
	}
	print " - ", &formatPrefix(@answer);
	if ($i == 0) {
	    print " matches ";
	} else {
	    print " doesn\\'t match ";
	}
	print &formatAddress($addr), "','',\n";

	&explain($addr, @answer);

	print ")\"><TT>", &formatPrefix(@answer), "</TT>\n\n";
    }
    print "</TABLE>\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n\n";
}

sub problem3 {
    my @prefix1;
    my $addr1;
    my @prefix2;
    my $addr2;
    my @correct;

    do {
	@prefix1 = &randomPrefix($quizType);
	$addr1 = &randomMatchingAddress(@prefix1);

	do {
	    @prefix2 = &permutePrefix(@prefix1);
	    $addr2 = &randomMatchingAddress(@prefix2);
	} while ($addr2 == $addr1);

	@correct = &longestCommonPrefix($addr1, $addr2);
    } while ($quizType ne "easy" and $correct[0] % 8 == 0);

    # Pick three non-matching prefixes; take care to make them all different

    my @wrongs;
    wrongs: while (@wrongs < 3) {
	my @wrong = &permutePrefix(@correct);

	next wrongs if (&match($addr1, @wrong) and &match($addr2, @wrong));
	next wrongs if ($quizType ne "easy" and ($addr1 == $wrong[1] or $addr2 == $wrong[1]));
	for my $others (@wrongs) {
	    next wrongs if ($$others[0] == $wrong[0] and $$others[1] == $wrong[1]);
	}
	push @wrongs, \@wrong;
    }

    my @order = &scramble(0,1,2,3);

    print "Which one of the following prefixes matches both <TT>";
    print &formatAddress($addr1), "</TT> and <TT>";
    print &formatAddress($addr2), "</TT>?\n";
    print "<P><CENTER><TABLE>\n";
    foreach my $i (@order) {
	my @answer;
	if ($i == 0) {
	    @answer = @correct;
	} else {
	    @answer = @{$wrongs[$i-1]};
	}
	print "<TR><TD><INPUT TYPE=\"Radio\" NAME=\"ChoiceQ$qnum\" onClick=\"Answer('Q$qnum',\n";
	if ($i == 0) {
	    print "'Correct!";
	} else {
	    print "'Wrong";
	}
	print " - ", &formatPrefix(@answer);
	if ($i == 0) {
	    print " matches both addresses'";
	} else {
	    print " doesn\\'t match ";

	    for my $addr ($addr1, $addr2) {
		if (not &match($addr, @answer)) {
		    print &formatAddress($addr), "','',\n";
		    &explain($addr, @answer);
		    last;
		}
	    }
	}
	print ")\"><TT>", &formatPrefix(@answer), "</TT>\n\n";
    }
    print "</TABLE>\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n\n";
}

sub problem4 {
    # Pick a random prefix

    my @prefix;
    my @correct;
    do {
	@prefix = &randomPrefix($quizType);

	@correct = @prefix;

	if ($quizType eq "easy") {
	    $correct[0] -= 8;
	} else {
	    $correct[0] -= 1 + int rand 3;
	}
    } while ($correct[0] < 0 or ($quizType ne "easy" and $correct[0]==0));

    $correct[1] &= &mask($correct[0]);

    # Pick three non-matching prefixes; take care to make them all different

    my @wrongs;
    wrongs: while (@wrongs < 3) {
	my @wrong = &permutePrefix(@correct);
	next wrongs if (&contains(@wrong, @prefix));
	for my $others (@wrongs) {
	    next wrongs if ($$others[0] == $wrong[0] and $$others[1] == $wrong[1]);
	}
	push @wrongs, \@wrong;
    }
    print "Which one of the following address prefixes contains <TT>", &formatPrefix(@prefix), "</TT>?\n";
    print "<P><CENTER><TABLE>\n";

    my @order = &scramble(0,1,2,3);

    foreach my $i (@order) {
	my @answer;
	if ($i == 0) {
	    @answer = @correct;
	} else {
	    @answer = @{$wrongs[$i-1]};
	}
	print "<TR><TD><INPUT TYPE=\"Radio\" NAME=\"ChoiceQ$qnum\" onClick=\"Answer('Q$qnum',\n";
	if ($i == 0) {
	    print "'Correct!";
	} else {
	    print "'Wrong";
	}
	print " - ", &formatPrefix(@answer);
	if ($i == 0) {
	    print " contains ";
	} else {
	    print " doesn\\'t contain ";
	}
	print &formatPrefix(@prefix), "','',\n";

	if ($answer[0] > $prefix[0]) {
	    print "'A $answer[0]-bit prefix can not contain a $prefix[0]-bit prefix',''";
	} else {
	    &explain($prefix[1], @answer);
	}
	print ")\"><TT>", &formatPrefix(@answer), "</TT>\n";
    }
    print "</TABLE>\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n\n";
}

sub problem5 {
    my @prefix = &randomPrefix("difficult");
    my @prefixlens = ($prefix[0]);

    wrongs: while (@prefixlens < 4) {
	my $prefixlen = int rand 33;
	for my $others (@prefixlens) {
	    next wrongs if ($others == $prefixlen);
	}
	push @prefixlens, $prefixlen;
    }

    print "Which mask corresponds to <TT>", &formatPrefix(@prefix), "</TT>?\n";
    print "<P><CENTER><TABLE>\n";

    @prefixlens = &scramble(@prefixlens);

    foreach my $i (@prefixlens) {
	print "<TR><TD><INPUT TYPE=\"Radio\" NAME=\"ChoiceQ$qnum\" onClick=\"Answer('Q$qnum',\n";
	if ($i == $prefix[0]) {
	    print "'Correct!'";
	} else {
	    print "'Wrong.','','", &formatAddress(&mask($i)), " corresponds to a prefix length of $i, not $prefix[0]'";
	}
	print ")\"><TT>", &formatAddress(&mask($i)), "</TT>\n";
    }
    print "</TABLE>\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n\n";
}

sub problem6 {
    my $addr = &randomAddress();
    my $a1 = ($addr>>24) & 255;
    my $a2 = ($addr>>16) & 255;
    my $a3 = ($addr>>8) & 255;
    my $a4 = $addr & 255;
    print "Enter an address prefix that matches <TT>", &formatAddress($addr), "</TT>:\n";
    print "<CENTER>\n";
    print "<INPUT SIZE=25 NAME=\"Input$qnum\" onChange=\"doQ6('Input$qnum','Q$qnum',$a1,$a2,$a3,$a4)\">\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n";
}

sub problem7 {
    my @prefix = &randomPrefix($quizType);
    my $a1 = ($prefix[1]>>24) & 255;
    my $a2 = ($prefix[1]>>16) & 255;
    my $a3 = ($prefix[1]>>8) & 255;
    my $a4 = $prefix[1] & 255;
    print "Enter an address that matches <TT>", &formatPrefix(@prefix), "</TT>:\n";
    print "<CENTER>\n";
    print "<INPUT SIZE=25 NAME=\"Input$qnum\" onChange=\"doQ7('Input$qnum','Q$qnum',$a1,$a2,$a3,$a4,$prefix[0])\">\n";
    print "<P><TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n";
}

sub problem8 {
    my @prefix1 = &randomPrefix($quizType);
    my @prefix2 = &permutePrefix(@prefix1);
    my $addr1 = &randomMatchingAddress(@prefix1);
    my $addr2 = &randomMatchingAddress(@prefix2);
    my @prefix = &longestCommonPrefix($addr1, $addr2);
    my $a1 = ($prefix[1]>>24) & 255;
    my $a2 = ($prefix[1]>>16) & 255;
    my $a3 = ($prefix[1]>>8) & 255;
    my $a4 = $prefix[1] & 255;
    print "Enter the longest prefix that matches both <TT>", &formatAddress($addr1), "</TT> and <TT>", &formatAddress($addr2), "</TT>:\n";
    print "<CENTER>\n";
    print "<INPUT SIZE=25 NAME=\"Input$qnum\" onChange=\"doQ8('Input$qnum','Q$qnum',$a1,$a2,$a3,$a4,$prefix[0])\">\n";
    print "<TEXTAREA NAME=\"Q$qnum\" COLS=64 ROWS=6></TEXTAREA>\n";
    print "</CENTER><P>\n";
}

$qnum=1;
&problem1;

$qnum=2;
&problem2;

if ($quizType ne "easy") {
    $qnum=3;
    &problem3;
}

$qnum=4;
&problem4;

if ($quizType ne "easy") {
    $qnum=6;
    &problem6;
}

$qnum=7;
&problem7;

if ($quizType eq "difficult") {
    $qnum=8;
    &problem8;
}

print "\
\
";
print "\<\/FORM\>";
print "\
";
print "\<P\>\<HR\>\
\<CENTER\>\<B\>Next\:\<\/B\>\ \<A\ HREF\=\"quiz1b\.cgi\"\>Quiz\ \#1\ \(cont\)\<\/A\>\<\/CENTER\>\<HR\>\
\<B\>Connected\:\ An\ Internet\ Encyclopedia\<\/B\>\
\<BR\>\
\<EM\>Quiz\ \#1\<\/EM\>\
\<\/BODY\>\
\<\/HTML\>\
";
