#!/usr/bin/perl -w use strict; print "Content-type: text/html\n\n"; print "\\ \\ \Quiz\ \#1\<\/TITLE\>\ \<\/HEAD\>\ \\ \\<\/SCRIPT\>\ \Connected\:\ An\ Internet\ Encyclopedia\<\/B\>\ \\ \Quiz\ \#1\<\/EM\>\\ \\\ \Up\:\<\/B\>\ \Connected\:\ An\ Internet\ Encyclopedia\<\/A\>\\ \Up\:\<\/B\>\ \Programmed\ Instruction\ Course\<\/A\>\\ \Up\:\<\/B\>\ \Subnetting\ and\ CIDR\<\/A\>\\ \<\/CENTER\>\ \Prev\:\<\/B\>\ \Power\ of\ Two\ Blocks\ \(cont\)\<\/A\>\\ \Next\:\<\/B\>\ \Quiz\ \#1\ \(cont\)\<\/A\>\\ \\\ \Quiz\ \#1\<\/H3\>\\ "; print "\"; 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 "\"; print "baccala\@freesoft\.org"; print "\<\/A\>"; print "\,\ and\ be\ sure\ to\ include\ this\ quiz\'s\ ID\ code\:\ "; print "$quizType-$quizseed";print "\ "; print "\"; print "\ \ "; print "\"; print "\ function\ Answer\(question\)\ \{\ \ \ \ document\.FORM\[question\]\.value\ \=\ \"\"\ \ \ \ for\ \(var\ i\=1\;\ i\\ 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 "\"; 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 ", &formatPrefix(@prefix), "?\n"; print "

\n"; foreach my $i (@order) { my $addr; if ($i == 0) { $addr = $correct; } else { $addr = $wrongs[$i-1]; } print "
", &formatAddress($addr), "\n\n"; } print "
\n"; print "\n"; print "

\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 ", &formatAddress($addr), "?\n"; print "

\n"; foreach my $i (@order) { my @answer; if ($i == 0) { @answer = @correct; } else { @answer = @{$wrongs[$i-1]}; } print "
", &formatPrefix(@answer), "\n\n"; } print "
\n"; print "\n"; print "

\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 "; print &formatAddress($addr1), " and "; print &formatAddress($addr2), "?\n"; print "

\n"; foreach my $i (@order) { my @answer; if ($i == 0) { @answer = @correct; } else { @answer = @{$wrongs[$i-1]}; } print "
", &formatPrefix(@answer), "\n\n"; } print "
\n"; print "\n"; print "

\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 ", &formatPrefix(@prefix), "?\n"; print "

\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 "
$prefix[0]) { print "'A $answer[0]-bit prefix can not contain a $prefix[0]-bit prefix',''"; } else { &explain($prefix[1], @answer); } print ")\">", &formatPrefix(@answer), "\n"; } print "
\n"; print "\n"; print "

\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 ", &formatPrefix(@prefix), "?\n"; print "

\n"; @prefixlens = &scramble(@prefixlens); foreach my $i (@prefixlens) { print "
", &formatAddress(&mask($i)), "\n"; } print "
\n"; print "\n"; print "

\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 ", &formatAddress($addr), ":\n"; print "

\n"; print "\n"; print "\n"; print "

\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 ", &formatPrefix(@prefix), ":\n"; print "

\n"; print "\n"; print "

\n"; print "

\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 ", &formatAddress($addr1), " and ", &formatAddress($addr2), ":\n"; print "

\n"; print "\n"; print "\n"; print "

\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 "\\\ \\Next\:\<\/B\>\ \Quiz\ \#1\ \(cont\)\<\/A\>\<\/CENTER\>\\ \Connected\:\ An\ Internet\ Encyclopedia\<\/B\>\ \\ \Quiz\ \#1\<\/EM\>\ \<\/BODY\>\ \<\/HTML\>\ ";