#!/usr/bin/perl 
# NOTE:  the above line must be changed to show the path to the
# Perl interpreter on your system!  Leave the #! as is, but
# the path may have to be changed if yours is different.
$| = 1;
#########################################################################
# QuizTest 3.0.17						      	#
# CGI quiz program for the worldwide web.  May use multiple choice or  	#
# true/false questions.  The program grades the quiz, shows students	#
# their score, then emails the results to the designated instructor.  	#
# Intended for online courses that are graded.				#
# Copyright 1996 - 2000, Kristina L. Pfaff-Harris		    	#
# All rights reserved.                                             	#
#									#
#########################################################################
##### Licensing:                                                        #
#####                                                                   #
#####  This program may be used free of charge under the following      #
#####  conditions:                                                      #
#####                                                                   #
#####  1. All instructions and Copyright lines must remain unchanged.   #
#####                                                                   #
#####  2. All pages generated by the program must contain one of the    #
#####     following pieces of HTML code:                                #
#####                                                                   #
#####     <font size=-2>This quiz engine uses QuizTest by           	#
#####     Kristina Pfaff-Harris. It can be found at:                    #
#####     <a href="http://www.tesol.net/scripts/">                      #
#####     http://www.tesol.net/scripts</a></font>                       #
#####  OR:                                                              #
#####     <!-- QuizTest is Copyright 1996-2000 Kristina Pfaff-Harris -->#
#####     <!-- Get it at http://www.tesol.net/scripts/         -->      #
#####                                                                   #
#####  3. You may not sell or distribute this program.  You may charge  #
#####     a reasonable fee for installing it for a client as long as    #
#####     you make it clear that you are not the author, and you are    #
#####     not selling the program to them: only charging for installing #
#####     it.                                                           #
#####                                                                   #
#####  4. You agree that this program is offered without warranty of    #
#####     any kind, including warranty of fitness for a particular      #
#####     purpose. You further agree that the author and all sites      #
#####     associated in any way with this program are not liable for    #
#####     any damage or loss incurred as a result of using this program.#
#########################################################################
#####                                                                   #
##### IMPORTANT INSTRUCTIONS:                                           #
#####                                                                   #
##### In this program, I have put **CHANGE** in all the places where    #
##### you will need to modify the program to run on your server, so     #
##### that you can easily find all the places where changes are         #
##### necessary.  This program must be chmod 755 or 775 in order to     #
##### work, and the directory where you want QuizTest to put its files	#
##### must be chmod 777.						#
#####                                                                   #
##### In addition, if you wish to use the option that will email you    #
##### the results every time a student takes one of the quizzes,        #
##### and your website is hosted on a Unix or Linux-based web server,	#
##### you must have the sendmail program on your web server, and your   #
##### web server must have permission to access it as well as           #
##### permission to run cgi programs.                                   #
#####                                                                   #
#########################################################################
#									#
# IMPORTANT: If you FTPed this program to your server in "binary" mode, #
# it will NOT work!  If you're not sure, please go back and FTP it	#
# to your server again and make sure you use "ascii" mode.  If you get	#
# "500 Server Error", this is almost always the cause. :)		#
#									#
# Using the program:							#
# This program requires the file "quiztest.cgi" at a minimum in order 	#
# to work.  Please read the README.quiztest file for more information.	#
#  									#
# I hope this program proves useful to you!  Please contact me  	#
# (http://tesol.net/scriptmail.html) for any bugs or feedback.		#
#########################################################################
# Special thanks to Selena Sol (http://www.extropia.com) for       	#
# MultipleChoice 2.0 which helped me get started on my very first quiz  #
# program in Perl.							#
#########################################################################
  %data = &get_data();
  print "Content-type: text/html\n\n";

#########################################################################
#####									#
#####  BEGIN SECTION WHERE YOU WILL NEED TO CHANGE THINGS:		#
#####									#
##### 	In this section, there are several places where you'll need	#
#####	to make changes.  Please read all instructions carefully	#
#####	before you make the changes.					#
#####									#
#########################################################################


# $basedir:  This is the base directory on your server where your
# 	     course materials are located.  This is used by the 
#	     program to store the results file separately for each
#	     lesson. *CHANGE* "./" to the full base system path
#            to where you want QuizTest to put all its quiz files
#	     and so forth.  Please see the README.quiztest file under
#            "Setting up Files, Directories, and Permissions" for more
#            information about $basedir, and how to set it up.
#            Please note that this is NOT a URL, and should NOT
# 	     contain "http://" 
#
#            If your web server is a Unix-type system, then this 
#            MUST begin a /,  and the folder must be writeable 
#            by the web server. For example:
#	     $basedir = "/path/to/your/files";
#
#            If your web server is a Windows-type system, then this 
#            MUST begin a "c:" or "d:" or "e:".  For example:
#	     $basedir = "c:/path/to/your/files";

$basedir = "/www/mnstats/public_html/quiznew4";

# $cgi_url is the full web address of your quiztest.cgi program.
# This MUST start with "http://" or it will not work.  Please
# **CHANGE** this to the actual web address of where you have
# installed the quiztest.cgi program.  

$cgi_url =
"http://mnstats.morris.umn.edu//cgi-bin/quiznew4/quiztest.cgi";

###################################################################
#                                                                 #
#                  Operating System Specific Stuff                #
#                      (Windows vs. Unix/Linux)                   #
#                                                                 #
###################################################################

# In this section, we're going to try to get some data that will
# help us run this script whether you're using Windows NT/95/98 as
# a web server, or a Unix/Linux-based web server.  Here, I feel
# it necessary to point out that Unix/Linux web servers tend to
# be much more flexible and robust (in my experience) than Windows
# ones.  However, if you're stuck with Windows, we'll try to get
# this working anyway. :)

# If your web server is Linux/Unix based, please set
# $opsys below to "unix" like this and go to the Unix/Linux Stuff
# Section below:
# $opsys = "unix";
# Otherwise, if it is a Windows-based platform, set $opsys to "win"
# like this and go to the Windows Stuff section:
# $opsys = "win";

$opsys = "unix";

###################################################################
#                                                                 #
#                  Unix/Linux Stuff                               #
#                                                                 #
###################################################################
# $path_to_sendmail needs to be the FULL path to sendmail on your
# server, and the name of the sendmail file itself:  You will
# probably be able to use what I have below, but sendmail
# is sometimes located in /usr/ucblib instead of /usr/lib and
# may be somewhere else altogether.  Ask your systems administrator
# where sendmail is, just to make sure, then **CHANGE** this to
# the correct path.  Note: on some systems, this is something
# totally different without the word "sendmail" at all such as
# "/var/qmail/bin/qmail-inject".

$path_to_sendmail = "/usr/sbin/sendmail";

###################################################################
#                                                                 #
#                     Windows Stuff                               #
#                                                                 #
###################################################################

# $mail_server_hostname needs to be the hostname of a mail server
# that your web server is allowed to send mail through. Generally,
# this will be something like "mail.yourdomain.com" but it may
# be something completely different, and you may not be able to
# use this at all.  If your web server is also a mail server,
# you may be able to use "localhost" (yes, just that one word,
# no ".com" or anything -- it's a special word that means "this
# machine.")  You will need to ask your local technical support
# people for your website what hostname to use for your outgoing
# mail server, then **CHANGE** this to reflect that. For example:
# $mail_server_hostname = "mail.yourdomain.com";

$mail_server_hostname = "cda.morris.umn.edu";

# $this_server_hostname needs to be the hostname of your web
# server where this script will be run.  Sometimes, just the
# "www.yourdomain.com" will work, and sometimes your web
# server has its own name like "web-01.nt.somedomain.com".
# Again, you will need to get the hostname of this machine
# from the technical support people for your web server,
# and **CHANGE** this to reflect what they say. For example:
# $this_server_hostname = "www.yourdomain.com";

$this_server_hostname = "mnstats.morris.umn.edu";

###################################################################
#                                                                 #
#  End of Operating System-Specific stuff. On to more changes:    # 
#                                                                 #
###################################################################

# $webmaster:  This is just a generic name for the "From" field
#		You'll want to *CHANGE* "WebMaster" to something 
# 		appropriate for your site.  It can be anything from your
#		real name to "Master of the Universe," whatever
# 		suits your fancy.

  $webmaster = "QuizTest v3.0.17";

# $webemail:  This is also a generic address for the "From" field
#             *CHANGE* "webmaster\@mysite.edu to the webmaster address 
#             for your website, or to your own address.

  $webemail = "levyj\@morris.umn.edu";

# $instructor: 
# This is the email address of the person who should get 
# the results of any quizzes not otherwise assigned to
# an instructor. You will need to set $instructor to the 
# email address of the person who should get the results 
# of the quizzes after they are taken.  **CHANGE** this
# to your own or other appropriate email address. NOTE:
# You must put a \ (backslash) in front of the @ sign
# like this: \@

  $instructor = "levyj\@morris.umn.edu";

# Now, you'll need to select a password of sorts.  Please note
# that this does NOT make the admin functions secure, it just
# makes it a little more secure than if the password were 
# "admin" as it is by default, or if there were no password.  
# You will use this to log into the admin screen.
# So, **CHANGE** $admin_password = "admin"; to 
# $admin_password = "something_else"; here.  The only restriction
# is it cannot contain the "|" (pipe) symbol.

$admin_password = "quiztest";


# $multiple_instructors :
# This allows you to determine whether or not you wish to have
# multiple instructors, one for each quiz.  If you **CHANGE**
# $multiple_instructors = "no"; to
# $multiple_instructors = "yes";
# then the program will create a file for the instructors in 
# whatever folder you set up as $basedir. This will keep track 
# of instructors and which quizzes they are responsible for.

$multiple_instructors = "yes";

# $show_scores_for_all_quizzes :
# If this is set to Yes, then users can click a link and see just
# the high scores for a quiz without actually taking a quiz. If this
# is set to No, then the link will not appear.

$show_scores_for_all_quizzes = "Yes";

#########################################################################
#									#
#   IMPORTANT:  The rest of these options may be changed for each 	#
#   individual quiz through the web-based quiz creation interface.	#
#   It is not necessary to change these settings here, as you may	#
#   override them when creating or editing a quiz.  However, you may	#
#   wish to read through them and make sure the default settings are 	#
#   satisfactory to you, and **CHANGE** them if you need to do so.	#
#									#
#########################################################################

# $debugging: Okay, first of all, if you're having problems with the
# script, then you will want to **CHANGE** $debugging = 0; to
# $debugging = 1;
# What this will do is print out some helpful information about why
# the script might not be working for you.  If it's not helpful to
# you, then it will definitely be helpful to me when you email me
# for help!  If you want, you can set this right off the bat to be
# sure that all the files and so forth are in the right place.  Just
# be sure to turn it back to 0 before you actually use the program,
# or your users will get all these funny messages about files and
# directories.
# This setting may be changed for each quiz when you create or
# edit a quiz.

$debugging = 0;

# Now, it is sometimes helpful to be able to turn on debugging
# without coming in here and editing this file. $remote_debugging
# lets you determine whether or not you want to be able to
# turn on debugging by calling the quiztest.cgi program like
# this: 
#
# http://www.your.site/cgi-bin/quiztest.cgi?debugging=1
#
# If you set $remote_debugging = "on"; then you will be
# able to turn debugging on by calling the script like I
# have it above.  Note: this means that anyone else can
# turn debugging on as well. It shouldn't really hurt anything,
# but some people are sensitive about outside people knowing
# where their files are and so forth. If you set
# $remote_debugging = "off"; then you will have to edit
# the script, and set $debugging = 1; if you want debugging
# information at all. **CHANGE** this to the appropriate
# setting.
# This setting may be changed for each quiz when you create or
# edit a quiz.

$remote_debugging = "off";

# This next is for purely aesthetic purposes.  Basically, you can have
# any HTML code you like appear at the top of the pages generated by
# the program, and at the bottom.  If you don't know much about HTML
# code, then I suggest you leave this alone.  If you change it, then
# all of the following characters 
#   " @ \ % $
# MUST have a backslash in front of them. For example:
#   \" \@ \\ \% \$
# If you aren't extremely careful with this, the program will not run.
# You may **CHANGE** $header = "<html>...etc to contain the appropriate
# HTML code for your site.

$header = "
<HTML><head><title>QuizTest v3.0.17</title></head>
<body bgcolor=\"#FFFFF0\">
<center><font size=+2>QuizTest!<br><BR>
<br><br>
</font></center>
<br>
<P>
";

# $footer is pretty much the same deal as $header above: this HTML
# is at the end of all pages generated by the program.

$footer ="
</body></html>
";

# $grade_quiz_button_text is so that if you would like to change
# what the "Grade Quiz" button on the quizzes says, you can do that.
# This will not affect the operation of the program, so you can leave
# it the way it is if you like.  Please make sure to put a \ (backslash)
# in front of any of the following characters:
# @ $ " % \
# like this:
# \@ \$ \" \% \\

$grade_quiz_button_text = "Grade Quiz";

# $mail_me_results lets you tell the program whether you want the
# results of the quizzes emailed to you or not.  I put this in so
# that I could turn off emailing on the demo script: otherwise,
# I'd get inundated with emailed quizzes from people trying out the
# program.  You should **CHANGE** this to 
#
# $mail_me_results = "Yes";
#
# or you will never get the results of the quizzes! NOTE: If you set
# this to Yes, it will only email you the first time someone takes the
# quiz. If you set $mail_me_results = "All"; then it will email you all
# the results any time someone takes the quiz.

$mail_me_results = "No";

# $take_quiz_over :
# If you **CHANGE** $take_quiz_over = "no"; to 
# $take_quiz_over = "yes"; 
# then students will be allowed to take any quiz more than once.

$take_quiz_over = "yes";

# $force_complete_quiz is whether or not you want to have the
# script check to make sure that all questions have been answered
# on a quiz.  If you set
# $force_complete_quiz = "yes";
# Then 	quiz takers will have to answer all questions on a quiz before
# it can be graded.  If you set 
# $force_complete_quiz = "no";
# Then quiz takers will be able to submit only partially-completed
# quizzes.

$force_complete_quiz = "yes";

# $authorized_users :
# This lets you decide whether just anyone can take the quiz,
# or only registered students.  If you **CHANGE** 
# $authorized_users = "no"; to
# $authorized_users = "yes";
# then you must add each student to the system through the
# admin interface.

$authorized_users = "no";

# $what_to_show_after_quiz is designed to let you determine whether
# or not to show the users whether their individual answers were
# correct or incorrect, and whether to show their score or not.
# The idea behind this is that if you show the score, the user could
# keep hitting the "Back" button on the browser, and changing answers
# until they got a perfect score, after which they could share the
# correct answers to those questions with all their friends.  This
# setting has 4 options:
#
# To show the Correct answer if the user got the Incorrect answer, and
# show the total score (e.g. 50%, 100%) set this to:
#
#   $what_to_show_after_quiz = "All";
#
# To tell users whether each answer was Correct or Incorrect, but not
# tell them what the correct answer actually was if they got it wrong,
# and to show the total score, set this to:
#
#   $what_to_show_after_quiz = "StatusOnly";
#
# To show only the total percentage score with no feedback about which
# answers were correct or incorrect, set this to:
#
#   $what_to_show_after_quiz = "ScoreOnly";
#
# To show no results at all, but rather the message "Thank you for 
# taking this test, <their name>. You will be notified
# of your score when this test is closed," set this to:
#
#   $what_to_show_after_quiz = "None";

$what_to_show_after_quiz = "StatusOnly";

# $show_quiz_questions tells whether or not you'd like to display
# the quiz questions, as well as the answers and/or score in the
# results as shown above.  If you would like QuizTest to display
# and email the questions along with the answers, **CHANGE**
# $show_quiz_questions = "no"; to
# $show_quiz_questions = "yes";
# If you would like QuizTest to only display/email the questions to
# the instructor, but not to the student, **CHANGE**
# $show_quiz_questions = "no"; to
# $show_quiz_questions = "instructor";
# Please note that if you have HTML code or embedded sounds, images,
# etc in your questions, this may have some very strange results.
# You may also set this "per quiz".

$show_quiz_questions = "yes";

# $show_other_scores should be "Yes" or "No".  If you set
# $show_other_scores = "Yes"; then the program will not only
# show the user his score, but will show the top scorers out
# of others who have taken the quiz.  Most people using this
# for educational purposes will leave this at "No" while
# people using this for amusement may wish to put it to "Yes"
# If you do **CHANGE** this to $show_other_scores = "Yes"; then
# you will need to tell how many scores to show in 
# $number_of_scores_to_show below.

$show_other_scores = "No";

# $number_of_scores_to_show should be the number of previous
# quiz scores you wish to show to each person who takes a quiz.

$number_of_scores_to_show = "10";

# $show_grading_scale should just be "Yes" or "No".  If it is
# "Yes", then you may wish to edit $grading_scale below to something
# appropriate for your setting.  If it is "No" then the grading
# scale will not be shown at all. **CHANGE** this to 
# $show_grading_scale = "No";
# if you don't wish to show a grading scale like the one below.

$show_grading_scale = "Yes";

# $grading_scale is just something to print out to tell students
# what their percentage score equals in terms of the A-F grading
# scale.  You may edit this as you please, or delete it entirely
# if you do not choose to show a grading scale at all.  You may
# **CHANGE** any of the text in between <!-- Grading scale starts here -->
# and <!-- Grading scale ends here -->, and may use any HTML code
# you wish to make it pretty.  However, please be aware that if you
# use any of the following characters:
# @ $ \ "
# you must put a backslash \ in front of them like this:
# \@ \$ \\ \"
# or the program will not work.

$grading_scale = "
<!-- Grading scale starts here -->
<pre>
======================
|   Score   |  Grade |
|-----------|--------|
| 100 - 93% |    A   |
|  93 - 90% |    A-  |
|  89 - 85% |    B   |
|  84 - 80% |    B-  |
|  79 - 75% |    C   |
|  74 - 70% |    C-  |
|  69 - 65% |    D   |
|  64 - 60% |    D-  |
|  59 -  0% |    F   |
----------------------
</pre>
<!-- Grading scale ends here -->
";

###################################################################
#                                                                 #
#  Options for Short-Answer scoring. PLEASE Read Carefully!!!     #
#  (These may also be changed on a per-quiz basis.)		  #
#                                                                 #
###################################################################
#
# Now, QuizTest will support "short answer" questions. However,
# being a computer program and not a person, it does not have good
# judgement about scoring, and would be extremely strict if left to
# its own devices.  For example, if the correct answer were "no." and 
# the student were to type in the answers "No." or "no" in the form,
# QuizTest would count both of those wrong. Good for a spelling test,
# rather inconvenient for an essay test. Here, we try to give you some 
# leeway. The following $sa_blahblah variables are designed to moderate
# this behavior a bit.  **CHANGE** each of these to "yes" or "no" as
# you please, after reading the description.
#
# I strongly suggest that you experiment with these settings a bit
# before working with short-answer questions. If nothing else, please
# remember that a computer program is no substitute for a human grader,
# and any short-answer questions you have should be reviewed by a person
# before counting the student out for them.
#
# $sa_ignorecase = "yes";
#   Tell QuizTest to ignore differences in case, so that "no", "No", and
#   "NO" will all be counted as correct if the answer is "No."
#   If you don't want this, **CHANGE** this to "no".

$sa_ignorecase = "yes";

# $sa_ignorepunctuation
#   Tell QuizTest to ignore punctuation, so that '"Yes," she answered.'
#   will be counted the same as 'Yes she answered' or 'Yes, she answered'
#   This is a bad idea if you plan to do Math or Science quizzes, since
#   1/4 would ignore the "punctuation" sign "/" and 14 would be counted
#   as a correct answer! 
#   If you do want this, **CHANGE** this to "yes".

$sa_ignorepunctuation = "no";

# $sa_ignorespaces 
#   Tell QuizTest to ignore differences in spaces between words, so that
#   "Yes      I do" will be the same as "Yes I do" and "YesIdo".
#   If you don't want this, **CHANGE** this to "no".

$sa_ignorespaces = "yes";

# $sa_ignorenonwords
#   Tell QuizTest to ignore spaces *and* punctuation, and basically just
#   make sure that everything else is in there.  
#   This is a bad idea if you plan to do Math or Science quizzes, since
#   1/4 would ignore the "punctuation" sign "/" and 14 would be counted
#   as a correct answer! 
#   If you do want this, **CHANGE** this to "yes".

$sa_ignorenonwords = "no";

# $sa_containsanswer
#   This tells QuizTest that if student enters anything that is part
#   of the correct answer, to score it correct.  This is pretty lenient,
#   as students entering "e" will be marked correct when the correct
#   answer is "antidisestablishmentarianism".  
#   If you DO want this, **CHANGE** this to "yes".

$sa_containsanswer = "no";

# $sa_markallcorrect
#   This tells QuizTest that if student enters anything *at all*
#   in a short answer slot, to count it as correct. This is the most
#   lenient of all.
#   If you DO want this behaviour, **CHANGE** this to "yes".

$sa_markallcorrect = "no";

# $sa_alternates = "yes";
#   When you create a quiz, you may give alternate answers for a short-
#   answer question. For example, "behavior/behaviour" or "color/colour".
#   This tells QuizTest that it is to treat each alternate as a correct
#   answer.
#   If you don't want this, **CHANGE** this to "no".

$sa_alternates = "yes";

#########################################################################
#####									#
#####  	END SECTION WHERE THINGS NEED TO BE CHANGED.			#
#####									#
#####	You should not HAVE to change anything beyond this point, 	#
#####	although you might want to read through it to see what it does. #
#####   If you're interested in how CGI programs work, then this may 	#
#####   act as its own tutorial of sorts. You definitely shouldn't 	#
#####   change anything beyond this point unless you know what you're   #
#####   doing, though. :)                                               #
#####									#
#########################################################################

# This just gives us some useful debugging information.
if($data{'debugging'} == 1){
   $data{'remote_debug'} = 1;
   }
$ENV{'QUERY_STRING'} =~ s/&debugging=\d//g;
$ENV{'QUERY_STRING'} =~ s/debugging=\d//g;
# We need to keep track of the real, hard-coded admin so we can let her
# edit or delete others' students if necessary.
$overall_admin = $instructor;
$quizresultsemail = $instructor;   
&debug("<font size=+1>IMPORTANT: If you need help with setting this up,
        Please copy and paste all of this debug output into an email and
        send it to me. It will make helping much easier! <br><br>
        When the script is set up, and functioning properly, set
        \$debugging = 0; in the script and you will no longer see
        these messages. </font><br>");

&debug("Looks like your operating system is '$^O' <br>");

&debug("Your web server is running $ENV{'SERVER_SOFTWARE'}");

if($ENV{'SCRIPT_FILENAME'} ne ""){
  $sfn = $ENV{'SCRIPT_FILENAME'};
  &debug("The server says that the 'full system path' to this script is $sfn");
  }
elsif($ENV{'PATH_TRANSLATED'} ne ""){
  $sfn = $ENV{'PATH_TRANSLATED'};
  &debug("The server says that the 'full system path' to this script is $sfn");
  }

################## Define the variables to be used #####################

# $basedir should not end with a "/", so we'll take it off in case they
# put one on.

$basedir =~ s/\/$//g;

# $Name: you must have an input field on your form that says name="name"
# This is generated by the program if you use it to make quizzes.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0
  $Name =$data{"name"};

# $Email: one input field on your form must say name="email"
# This is also generated on the form by the program.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0
  $Email =$data{"email"};

# $soc: On mine, this was intended for the students' social security
# 	number.  Your form must have an input field with name="SSN"
#	on it for this to work, so the program just sets this to N/A
#       if you decide you don't want it or need it.  
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

  $soc =$data{"SSN"};


# $url: This makes sure that you can have several different quizzes
#	in different directories, and that the program will refer 
# 	the student to the correct quiz form if they need to go back
# 	and try again.  For example, if they forget to enter their
#	name and email address, the program will print a page that
#	tells them so and makes them go back again.

  $url =$ENV{'HTTP_REFERER'};


# $lessondir: This is the name of the directory where the quiz files
#	      are kept.  There should be a hidden field in your form
#	      with this information. eg:
#
#   <input type=hidden name="Lessondir" value="lesson1">
#
#	      When the program looks for the answerfile, it will
# 	      look in the directory $basedir$lessondir/, or, in 
# 	      this case /path/to/my/files/lesson1/ .
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0
  
  $lessondir =$data{"Lessondir"}; 
  $data{'Lessondir'} =~ s/\W+//g; $data{'Lessondir'} =~ tr/[A-Z]/[a-z]/;
  $lessondir =~ s/\W+//g; $lessondir =~ tr/[A-Z]/[a-z]/;

# $lesson:  This is the name of the lesson.  It is used by the program 
#	    when it prints the results of the quiz.  For example, if
#	    I had one quiz for Grammar and another one for Arithmetic,
#	    I would put a hidden field in each separate quiz with a 
#	    name="Lesson" tag. (<input type=hidden name="Lesson" value=
#	    "Grammar">) and the student would see: "Results of the
#	    Grammar quiz for Student's Name:" and I would also be told
# 	    that it was the Grammar quiz when the results were mailed
#	    to me.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

  $lesson =$data{"Lesson"};

# $answerfile:  This is very important. For each quiz, you must have an
# 		HTML form AND a text file containing the answers to 
#		the questions for the quiz.  Using the "$basedir"
#		variable which we defined above means that you can
#		have a different answerfile for each quiz.  (I put
#		my quizzes each in a separate directory so that I
#		don't have to have different names for each answerfile.)
#		The answer file must be a "pipe delimited database".  
#		All that means is that you have to have the question
#		number, a "pipe" | and the answer.  Like this:
#		
#		1|true
#		2|false
#		3|false
#
#		And so on.  You'll need a separate one for each quiz, so 
# 		they and the quizzes should be kept together in separate
#		directories.  These are generated by the program.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

  $answer_file = "$basedir/$lessondir/answerfile";

# $instructors_file :
# This is the full system path to a file where you'd like to
# keep track of instructors' email addresses and which quizzes
# each one is responsible for.  On Unix-based systems, it will
# look something like this: "/home/users/public_html/instructors".
# On Windows-based systems, it will probably look like this:
# "C:/inetpub/wwwroot/yourname/instructors". **CHANGE** this
# to the real path to that file (including the filename). This
# file must be chmod 766 or otherwise set up so that the web
# server can write to it.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

$instructors_file = "$basedir/instructors";

# $authorized_users_file :
# This is the full system path and name of the file that you
# want to use to keep track of authorized students. 
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

$authorized_users_file = "$basedir/auth_users";

# $results_database:  This is the file where the results for all people
#		      taking the quiz will be stored.  You can pick it up
#		      and sort through it later if you'd like to compare
#		      students' scores. This will be generated by the 
#		      program.  All you really need to do is remember
#		      its name so you know what to look for.
#  This is generated automatically by quiztest.cgi as of QuizTest v3.0

  $results_database = "$basedir/$lessondir/results.data";

# WHEW!  Glad that's over!  Now let's get into the program itself.
# First, we will spit out some debugging info in case people are
# having problems with the script.  The filenames can be a problem, so
# let's make sure that everything is readable, writable, and where we
# expect it to be. :)  You won't see this unless you've set "$debugging = 1"
# earlier, but it should be very helpful if you need it.

&debug("I'm checking your base directory \"$basedir\"...");

# Check to see if $basedir is really a directory...

 if(-d $basedir){
   &debug("Good: \$basedir ($basedir) is really a directory.");
   }
 else {
   &debug("Uh oh, I couldn't find that directory. Are you sure it exists?");
   }

# We don't need sendmail if we're not using windows...
if($opsys ne "win"){
 &debug("Okay. You said sendmail is in \"$path_to_sendmail\". Checking...");

 if(-x $path_to_sendmail){
   &debug("Looks like that might work. At least, $path_to_sendmail exists
	   and appears to be some sort of program.");
   }
 else {
   &debug("Whoops, it looks like I can't use that sendmail. (Either it
   doesn't exist, or is not executable, meaning I can't run it. Check with 
   your system administrator and make sure you're pointing to the right one.");
   }
}
$admformtop = " <form method=POST action=$cgi_url>
               <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
               <input type=hidden name=admlogin value=\"$data{'admlogin'}\">
               <input type=hidden name=admpass value=\"$data{'admpass'}\">
	       ";
# Well, that should do for debugging. Now, on to the program.
#
# $data{'FA'} is just what we use to keep track of what commands
# we want the program to do. To make the buttons look nice, sometimes
# we add spaces before and behind the words, so we need to get rid
# of those first.
$data{'FA'} =~ s/^\s+//g; $data{'FA'} =~ s/\s+$//g;

# If you remove this link, without replacing it with a similar
# HTML comment (as above in the License section) you are in violation
# of the license for this program. No, I don't have the resources to
# enforce this, and I know that some people will remove it anyway.
# But honestly, since you didn't have to pay for this, is the link
# really too much to ask? :)

$footer = "<br><font size=-2>Powered by QuizTest v3.0.17 (Quiz Engine
           Copyright &copy; 1997-2000 
           Kristina Pfaff-Harris and can be found at 
	   <a href=\"http://www.tesol.net/scripts/\">
           http://www.tesol.net/scripts</a></font>)<br>
	   $footer" if $footer !~ /http:\/\/www.tesol.net\/scripts/i;

# We sometimes save results so we can mail them to the person.
# This is so that someone can't arbitrarily send any message using
# this program.  In case the students decide not to mail the results,
# that leaves all these temporary files lying around, so let's check
# and delete any of them that are over 10 minutes old.

opendir(DIR, "$basedir"); @mres = readdir(DIR); closedir(DIR);
foreach $file (@mres){
  ($mresults,$timestamp) = split(/\./, $file);
   $timestamp =~ s/\D+//g;
   if(-f "$basedir/$file" && 
      $mresults eq "mresults" && 
      time - $timestamp > 600){
      unlink("$basedir/$file");
      }
   }

# Get the header/footer for the quiz if there is one
if(-f "$basedir/$lessondir/header"){
  undef $/;
  open(HEADER, "<$basedir/$lessondir/header");
  if($opsys ne "unix"){ binmode(HEADER); }
  $header = <HEADER>;
  close(HEADER);
  $/ = "\n";
  }
if(-f "$basedir/$lessondir/footer"){
  undef $/;
  open(FOOTER, "<$basedir/$lessondir/footer");
  if($opsys ne "unix"){ binmode(FOOTER); }
  $footer = <FOOTER>;
  close(FOOTER);
  $/ = "\n";
  }
# If you're calling this script as http://whatever/quiztest.cgi?something
# then make sure "something" matches the admin password, and show the
# quiz generation screen if it does.

 if($ENV{'QUERY_STRING'} eq "admin"){
    &admin_login;
    exit();
    }

# Only the quiz generation screens will send a value for $data{'formaction'}
# so we check to see what we're supposed to be doing, whether it's showing
# the first form,
 elsif($data{'FA'} eq "Log In"){
    &check_auth;
    &show_menu;
    exit();
    }

 elsif($data{'FA'} eq "MailResults"){
    &mail_student_results;
    exit();
    }
 elsif($data{'FA'} eq "Add Quiz"){
    &check_auth;
    &create_quiz_one;
    exit();
    }
 elsif($data{'FA'} eq "ShowForm"){
    &check_auth;
    &showform;
    exit();
    }
# or actually creating the quiz and all associated files.
 elsif($data{'formaction'} eq "CreateQuiz"){
    &check_auth;
    &createquiz;
    exit();
    }
 elsif($data{'formaction'} eq "ConfigQuiz"){
    &check_auth;
    &config_quiz;
    exit();
    }
 elsif($data{'FA'} eq "Copy Quiz"){
    &check_auth;
    &copy_quiz;
    exit();
    }
 elsif($data{'FA'} eq "Delete Quiz"){
    &check_auth;
    &deletequiz;
    exit();
    }

 elsif ($data{'FA'} eq "Add Student") {
   &check_auth;
   &add_student;
   exit();
   }
 elsif ($data{'FA'} eq "Edit Student") {
   &check_auth;
   &edit_student;
   exit();
   }
 elsif ($data{'FA'} eq "Delete Student") {
   &check_auth;
   &delete_student;
   exit();
   }
 elsif ($data{'FA'} eq "Add Instructor") {
   &check_auth;
   &add_instructor;
   exit();
   }
 elsif ($data{'FA'} eq "Edit Instructor") {
   &check_auth;
   &edit_instructor;
   exit();
   }
 elsif ($data{'FA'} eq "Delete Instructor") {
   &check_auth;
   &delete_instructor;
   exit();
   }
 elsif($data{'FA'} eq "Get Statistics"){
   &check_auth;
   &results_stats;
   exit();
   }
 elsif ($data{'FA'} eq "View/Edit/Delete Results" || 
	$data{'FA'} eq "View Results") {
   &check_auth;
   &view_results;
   exit();
   }
 elsif ($data{'FA'} eq "Delete Results") {
   &check_auth;
   &delete_results;
   exit();
   }
 elsif ($data{'FA'} eq "Edit Results") {
   &check_auth;
   &edit_results;
   exit();
   }
 elsif ($data{'FA'} eq "Edit Quiz") {
   &check_auth;
   &edit_quiz;
   exit();
   }
 elsif ($data{'FA'} eq "Reset Quiz") {
   &check_auth;
   &reset_quiz;
   exit();
   }
 elsif ($data{'FA'} eq "View Quiz") {
   &check_auth;
   &view_quiz;
   exit();
   }

# If there are no admin things to do, we'll just assume that someone
# was taking the quiz and try to find something to grade.
 elsif ($data{'FA'} eq "Grade Quiz") {
   &grade_quiz;
   exit();
   }
 elsif ($data{'FA'} eq "ShowScores") {
   &show_high_scores_only;
   exit();
   }
 elsif($ENV{'QUERY_STRING'} ne ""){
   &show_quiz
   }
 else {
   &no_args_error;
   exit();
   }

sub no_args_error {

   if($error eq ""){
      $error = "<br><br>
	       Welcome! Please choose from one of the links below:";
      }
   print "$header
	  <b>$error</b><br><br>
	  <b>Quizzes:</b><br><br>";
   open(F, "<$instructors_file") || 
    &debug("Could not open instructors file: $! (This may be okay if you
	    have not yet set up any quizzes.)");
    print "<table border=1><tr><th>Quiz</th><th>Instructor</th></tr>\n";
    foreach $line (<F>){
       ($id,$pw,$name,$quizname) = split(/\|/, $line);
       @quizzes = split(/%/,$quizname);

       foreach $quiz (@quizzes){
          $q2 = $quiz; $q2 =~ tr/[A-Z]/[a-z]/; $q2 =~ s/\W+//g;
	  if($remote_debugging eq "on" && $data{'debugging'} == 1){
	    $remdbg = "&debugging=1";
	    }
          if($show_scores_for_all_quizzes eq "Yes"){
              
             $high_scores_ln = " (<a href=$cgi_url?FA=ShowScores&Quiz=$q2>Scores</a>)";
             }
	  print "<tr><td><a href=$cgi_url?$q2$remdbg>$quiz</a> $high_scores_ln</td>
		 <td>($name)</td></tr>" if($q2 ne "" && $quiz !~ /Another Sample Quiz/i);
	  $foundquiz = 1 if($q2 ne "");

	  }
       }
   close(F);
   if($foundquiz != 1){ print "<tr><td colspan=2>(No Quizzes Found)</td></tr>";}
	  if($remote_debugging eq "on" && $data{'debugging'} == 1){
	    $remdbg = "&debugging=1";
	    }
   print "</table><br><br>
	  <a href=$cgi_url?admin$remdbg>QuizTest Administration</a>
	  $footer";
   exit();
}

sub edit_quiz {

 $html = &find_quizzes("option");
 $qstudents = &get_students_as_checkboxes(&unpipe($data{'Quiz'}));
 if($data{'FA2'} eq "Show"){
   if($data{'Quiz'} =~ /NO QUIZZES FOUND/ || $data{'Quiz'} eq ""){
     print "$header
	    <b>Error: No quizzes found.</b>
	    $footer";
     exit();
     }
   $quiz = &unpipe($data{'Quiz'});
   $quiz =~ tr/[A-Z]/[a-z]/;
   $quiz =~ s/\W+//g;
   $quizfile = "$basedir/$quiz/quizdb";
   open(FILE, "<$quizfile") || &debug("Could not open $quizfile: $!");
   if($opsys ne "unix"){binmode(FILE);}
    ($title,$instr,$fn,$ea,$id,@qs) = split(/\|/, <FILE>);
   close(FILE);
   $quizdir = $title;
   $quizdir =~ tr/[A-Z]/[a-z]/;
   $quizdir =~ s/\W+//g;
   if(-f "$basedir/$quizdir/header"){
      undef $/; 
      open(F, "<$basedir/$quizdir/header") || 
       &debug("Could not open quiz header file $basedir/$quizdir/header: $!");
      if($opsys ne "unix"){binmode(F);}
      $qheader = <F>; close(F); $/ = "\n";
      }
   if(-f "$basedir/$quizdir/footer"){
      undef $/; 
      open(F, "<$basedir/$quizdir/footer") ||
       &debug("Could not open quiz footer file $basedir/$quizdir/footer: $!");
      if($opsys ne "unix"){binmode(F);}
      $qfooter = <F>; close(F); $/ = "\n";
      }
   $qheader = repipe($qheader); $qheader = unpipe_for_html($qheader);
   $qfooter = repipe($qfooter); $qfooter = unpipe_for_html($qfooter);
   $instr = repipe($instr); $instr = unpipe_for_html($instr);
   print "$header
	  <br>
	  $admformtop
          <b>Instructions for Quiz Editing:</b> You may edit any portion
	  of the quiz by replacing the existing text with any changes or
	  additions you would like to make. NOTE: You may not change the
	  title of the quiz, but anything else may be modified. To edit
	  a question or answer, simply change the text in those fields.
	  To delete a question, simply clear out the text box with that
	  question.  You may add a question using the blank question/answer
	  fields at the bottom.  Or, click the <b>Copy Quiz</b> button
	  to copy this quiz and/or assign it to a different instructor.
	  <input type=hidden name=FA value=\"Copy Quiz\">
	  <input type=hidden name=OldTitle value=\"$title\">
	  <input type=submit value=\"Copy Quiz\"><br>
	  </form>
	  <hr>
	  $admformtop
	  <table border=0>
	  <tr><th align=center colspan=2>
	  Title Of this quiz: \"$title\" (Sorry, Quiz
	  Titles may not be changed.)</th>
	  </tr>
	<tr><td align=center colspan=2 bgcolor=\"#E4D8E2\">
	<b>If you'd like any custom HTML
	code to be printed at the top of each quiz page, enter it here</b>
	</td></tr>
	<tr><td colspan=2 align=center>
	<textarea wrap=soft name=Header rows=3 cols=60>$qheader</textarea></td></tr>
	<tr><td align=center colspan=2 bgcolor=\"#E4D8E2\">
	<b>If you'd like any custom HTML
	code to be printed at the bottom of each quiz page, enter it here</b>
	</td></tr>
	<tr><td colspan=2 align=center>
	<textarea wrap=soft name=Footer rows=3 cols=60>$qfooter</textarea></td></tr>
	  <tr><th align=center colspan=2 bgcolor=\"#E4D8E2\">
	  <b>Please enter instructions for
	  the quiz takers.</b></b></th></tr>
	  <tr><td colspan=2>
	  In the area below, enter any instructions or other text
	  which you would like to have appear at the top of the page for
	  this quiz.</td></tr>
	  <tr>
	  <th colspan=2><textarea name=instr rows=5 cols=60 wrap=soft>$instr</textarea>
	  </th>
	  </tr>
	  <tr><th align=center colspan=2 bgcolor=\"#E4D8E2\">
	  <b>Modify the form fields</b></th></tr>
	  <tr><td colspan=2>
	  Each quiz has three blanks for the user to fill
	  in.  By default, these are \"Full Name,\" \"Email Address,\"
	  and \"ID Number\".  Here, you will see the default messages
	  that will appear on the quiz form for each quiz. If you
	  would like different messages to appear, please take out
	  what is below, and enter your own messages.  HINT: If you are using
	  the \"authorized users\" feature, you may blank these out, and the
	  program will use the values from the student databases instead.
	  </td></tr>
	  <tr><td colspan=2 align=center>
	   <table border=0>
	    <tr><th>Name</th><th>Email</th><th>ID</th></tr>
	    <tr>
	     <td><input type=text name=fn value=\"$fn\" size=30></td>
	     <td><input type=text name=ea value=\"$ea\"></td>
	     <td><input type=text name=id value=\"$id\" size=29></td>
	     </tr>
	    </table>
	    </td></tr>
	  <tr><th align=center colspan=2 bgcolor=\"#E4D8E2\">
	  <b>Quiz and Quiz Takers</b>
	  </th></tr>
	  <tr><td colspan=3>
	  On the left, enter the questions and the possible answers. 
	  Hint: To enter a Short-Answer question, type the question as usual, 
	  but make sure to select the check box for whether you want students
	  to see a single-line text field or a multi-line text field for
	  filling in their answer.
	  <br><br>
	  To give multiple
	  options for a Short-Answer field, separate the options with two
	  forward slashes (//), e.g.: \"Yes//Yep//Yeah//Yessir\".
	  Be sure to mark it as correct. 
	  If you are using the \"authorized users\" function, select or unselect
	  the
	  checkboxes next to the students who are allowed to take this quiz.
	  <hr>
	  </td></tr>
	  <tr><th>QuestionsAnswers</th>
	  <th>Authorized Students</th></tr>
	  <tr><td>
	  <table border=0>
	   <tr><th rowspan=2>Question</th><th rowspan=2>Possible Answers</th>
	   <th colspan=2>Short-answer questions</th></tr>
	   <tr><th><font size=2>Single-line text field</font></th>
		 <th><font size=2>Multi-line text field</font></th></tr>";
       foreach $q (@qs){
	   $i++; $j=0;
           ($ques,$ans) = split(/ # /, $q);
	   # get the original correct answers
	   open(AF, "<$basedir/$quizdir/answerfile");
	    @realanswers = grep(/^\d+/, <AF>);
	   close(AF);
	   $ques =~ s/\"/&quot;/g;
	   print "<tr><th valign=top><b>$i.</b>
		  <input type=text name=$i-q value=\"$ques\"></th>
		  <td><table border=0>";
           $ans = &repipe($ans);
	   if($ans =~ /%SAT%/){ $satck = " CHECKED"; $saqck = ""; $ans =~ s/%SAT%//; }
	   elsif($ans =~ /%SAQ%/){ $saqck = " CHECKED"; $satck = ""; $ans =~ s/%SAQ%//; }
	   else{ $saqck = ""; $satck = "";}
           foreach $a (split(/%%/, $ans)){
	       my ($n,$t) = split(/\|/, $realanswers[$i - 1]);
	       $a =~ s/\s+$//;
	       $a =~ s/^\s+//;
	       $t =~ s/\s+$//;
	       $t =~ s/^\s+//;
	       if($a eq $t || ($a eq "" && $t ne "")){
		  $ck = " CHECKED";
		  }
	       $j++;
	       if($a eq ""){$a = $t;}
	       $a =~ s/\"/&quot;/g;
               print "<tr><td><input type=text name=$i-$j-a value=\"$a\"></td>
		      <td><input type=radio name=\"$i-c\" value=\"$i-$j-a\"$ck></td><td>(Correct)</td></tr>";
	       $ck = "";
	       $numqedit++;
	      }
	     $n = $numqedit + 1;
	     # kph
             print "<tr><td><input type=text name=$i-$n-a value=\"$a\"></td>
	            <td><input type=radio name=\"$i-c\" value=\"$i-$n-a\"$ck></td>
		    <td>(Correct)</td></tr></table>";

           print "</td>
		  <th valign=top><input type=radio name=SA-$i value=\"SAQ\"$saqck></td>
		  <th valign=top><input type=radio name=SA-$i value=\"SAT\"$satck></td></tr>
		  <tr><td colspan=2><hr></td></tr>\n";
	  }
      # Maybe let them add one more question...
      $i++; $j=0;
      $saqck = ""; $satck = "";
      print "<tr><th valign=top><b>$i.</b>
	     <input type=text name=$i-q value=\"\"></th>
		  <td>";
      for($j = 1; $j < 8; $j++){
          print "<input type=text name=$i-$j-a value=\"\">
	         <input type=radio name=\"$i-c\" value=\"$i-$j-a\"$ck>
		 (Correct)<br>";
	  }
      print "</td>
	     <th valign=top><input type=radio name=SA-$i value=\"SAQ\"$saqck></td>
	     <th valign=top><input type=radio name=SA-$i value=\"SAT\"$satck></td></tr>
	     </table>\n</td><td valign=top>$qstudents</td></tr>\n";
      print "<tr><td colspan=2><input type=hidden name=qtitle value=\"$title\">
	     <input type=hidden name=FA value=\"Edit Quiz\">
	     <input type=hidden name=numquestions value=\"$i\">
	     <input type=submit name=FA2 value=\"Edit Configuration\">
	     </td></tr>
             </table></form>
	     $footer";

    exit();
    }
 elsif($data{'FA2'} eq "Edit Configuration"){
    print "$header";
    $quizdir = &unpipe($data{'qtitle'}); 
    $quizdir =~ tr/[A-Z]/[a-z]/; $quizdir =~ s/\W+//g;
    print &quiz_options_form("$basedir/$quizdir/config");
    foreach $key (keys(%data)){
       if($key ne "formaction" && $key ne "admlogin" && $key ne "admpass" &&
          $key ne "FA" && $key ne "FA2" && $key ne "Student"){
       $pval = &unpipe($data{$key});
       print "<input type=hidden name=\"$key\" value=\"$pval\">\n";
       }
       }
    @stu = split(/\0/, $data{'Student'});
    foreach $stu (@stu){
       print "<input type=hidden name=Student value=\"$stu\">\n";
       }
    print "<input type=hidden name=FA value=\"Edit Quiz\">
	<input type=submit name=FA2 value=\"Make Changes\">
	</form>
	$footer";
    exit();
    }
 elsif($data{'FA2'} eq "Make Changes"){
   foreach $key (keys(%data)){$data{$key} = &repipe($data{$key});}
   $num = $data{'numquestions'};
   $title = &unpipe($data{'qtitle'});
   $fn = &unpipe($data{'fn'}); 
   $ea = &unpipe($data{'ea'}); 
   $id = &unpipe($data{'id'});
   $instr = &unpipe($data{'instr'});
   @qstudents = split(/\0/, $data{'Student'});
   if($qstudents[0] eq ""){
      $qstudents[0] = $data{'Student'};
      }
   # Add this quiz to any student who doesn't already
   # have it.
    
   &add_quiz_to_students($title,@qstudents);

   # Get rid of newlines if any
   $instr =~ s/\r\n/ /g;
   $instr =~ s/\n/ /g;
   $quizdir = $title; $quizdir =~ tr/[A-Z]/[a-z]/; $quizdir =~ s/\W+//g;

   # Set up the header/footer if any
   if($data{'Header'} ne ""){
     open(F, ">$basedir/$quizdir/header") || &debug("could not open header $!");
     $data{'Header'} =~ s/\r\n/\n/g;
     $data{'Header'} =~ s/\n+/\n/g;
     if($opsys ne "unix"){binmode(F);}
     print F "$data{'Header'}"; close(F);
     }
   else {
	if(-f "$basedir/$quizdir/header"){unlink("$basedir/$quizdir/header");}
	 }
   if($data{'Footer'} ne ""){
     $data{'Footer'} =~ s/\r\n/\n/g;
     $data{'Footer'} =~ s/\n+/\n/g;
     open(F, ">$basedir/$quizdir/footer") || &debug("could not open footer $!");
     if($opsys ne "unix"){binmode(F);}
     print F "$data{'Footer'}"; close(F);
     }
   else {
	if(-f "$basedir/$quizdir/footer"){unlink("$basedir/$quizdir/footer");}
	 }

   # Create quiz configuration section
   $quizdir =~ tr/[A-Z]/[a-z]/; $quizdir =~ s/\W+//g;
   open(QCONFIG, ">$basedir/$quizdir/config") ||
     &debug("Could not create quiz configuration options file: $!");
   if($opsys ne "unix"){binmode(QCONFIG);}
   foreach $key (keys(%data)){
      if($key =~ /^opt_/){
          $var = $key; $var =~ s/^opt_//; $var =~ s/\W+//g;
	  $config_value = &perl_escape($data{$key});
          print QCONFIG "$var = $config_value;\n";
       }
    }
    $key = ""; $var = "";
    close(QCONFIG);

   # Whew! now, to figure out the question/answers..
   $k = 1;
   for ($i = 1; $i <= $num; $i++){
      &unpipe($data{"$i-q"});
      &unpipe($data{"$i-c"});
      if($data{"$i-q"} ne ""){
         $answerfile .= "$k|"; # the question number
	 $q = "$i-q";
	 $qline .= "|$data{$q} # ";
	 $j = 1; $k++;
	 # kph 01/20/01
	 $cor = &unpipe($data{$data{"$i-c"}});
	 # If it's a short answer question, log which one it is.
	 if($data{"SA-$i"} ne ""){
	    $saval = "SA-$i";
	    $qline .= "%$data{$saval}% $cor %%";
	    }
	 $answerfile .= "$cor\n";
         &unpipe($data{"$i-j-a"});
	 while($data{"$i-$j-a"} ne ""){
	    $ans = &unpipe($data{"$i-$j-a"});
	    if($data{"SA-$i"} eq ""){
              $qline .= "$ans %% ";
	      }
	    $j++;
	    if($j > 100){last;}
	 }
      $qline =~ s/\s+$//;
      }

    }
    $qline = "$title|$instr|$fn|$ea|$id$qline";
    $k--;
    &get_date;
    $answerfile = "REM: Quiz edited on $date by $data{'admlogin'}\nREM: $k questions\n$answerfile";
    $quizdir =~ tr/[A-Z]/[a-z]/; $quizdir =~ s/\W+//g;
    unless(-f "$basedir/$quizdir/answerfile" && -f "$basedir/$quizdir/quizdb"){
      print "$header
	     <b>ERROR: Cannot write to quizdb or answerfile. Please check
	     that '$basedir/$quizdir/answerfile' and 
	     '$basedir/$quizdir/quizdb' exist and are writeable by the
	     server!</b>
	     $footer";
      exit();
      }
    # Change the quiz file
    open(QF, "+<$basedir/$quizdir/quizdb") || 
    &debug("Could not write to quiz file $basedir/$quizdir/quizdb! $!");

    if($opsys eq "unix"){ flock(QF, 2); }
    else { binmode(QF); }

    $oldfile = <QF>;
    if(length($oldfile) > length($qline)){
      truncate(QF, length($qline));
      seek(QF, 0,0);
      }
     else {
      seek(QF, 0, 0);
      }
    print QF $qline;
    close(QF);

    # Change the answerfile
    undef $/;
    open(AF, "+<$basedir/$quizdir/answerfile") || 
    &debug("Could not write to answerfile $basedir/$quizdir/answerfile: $!");

    if($opsys eq "unix"){ flock(AF, 2); }
    else { binmode(AF); }

    $oldfile = <AF>;
    if(length($oldfile) > length($answerfile)){
      truncate(AF, length($answerfile));
      seek(AF, 0,0);
      }
     else {
      seek(AF,0,0);
      }
    print AF $answerfile;
    close(AF);
    $/ = "\n";
    $data{'FA2'} = "";
    $message = "<b>Quiz successfully modified.</b>
	        <br><BR>
	        $admformtop
	        You may view your newly edited quiz here:
	        <a target=\"_blank\" href=$cgi_url?$quizdir>
	        $cgi_url?$quizdir
	        </a>
	        <br><br>You may also try out the quiz right
                now to make sure that it works:
	        <input type=hidden name=QuizName value=\"$quizdir\">
	        <input type=submit name=FA value=\"View Quiz\">
	        </form><hr>";
    $another = "another";
    &edit_quiz;
 exit();
 }
 $another = "a" if $another eq "";
 print "$header
	$message
	$admformtop
	Please choose $another quiz to edit:
	<select name=Quiz>
	$html
	</select>
	<input type=hidden name=FA2 value=\"Show\">
	<input type=submit name=FA value=\"Edit Quiz\">
	</form>
	$footer";
	exit();


}

sub add_student {

 $quizopts = &find_quizzes("checkbox");
 if($data{'FA2'} ne "Add"){
    print "$header
	   $message
	   <table border=1>
	   <tr><th>Student Info</th><th>Quiz(zes) for this Student</th></tr>
	   <tr><td valign=top>
	   $admformtop
	   <font color=#FF0000>$error</font><br>
	   <table border=0>
	   <tr><th align=left>
	   Student Name:
	   </th><th>
	   <input type=text name=Name value=\"$data{'Name'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student ID/Email:
	   </th><th>
	   <input type=text name=ID value=\"$data{'ID'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student Password:
	   </th><th>
	   <input type=password name=Password value=\"$data{'Password'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student Password again:
	   </th><th>
	   <input type=password name=Password2 value=\"$data{'Password2'}\">
	   </th></tr>
	   </table>
	   <input type=hidden name=FA2 value=\"Add\">
	   <input type=submit name=FA value=\"Add Student\">
           </td>
	   <td valign=top><br>$quizopts</td></tr></form></table>
	   $footer";
	   exit();
    }
     if($data{'Password'} eq "" ||
       $data{'Password2'} eq "" ||
       $data{'ID'} eq ""){
	$error = "Error: All fields must be filled in.";
	$data{'FA2'} = "";
	&add_student;
	}
     open(FILE, "<$authorized_users_file");
     ($student,$pw) = split(/\|/, (grep(/^$data{'ID'}\|/, <FILE>))[0,1]);
     if($student eq $data{'ID'}){
	$error = "Error: Student $data{'ID'} exists.";
	$data{'FA2'} = "";
	&add_student;
	}
     if($data{'Password'} ne $data{'Password2'}){
	$error = "Error: Passwords do not match.";
	$data{'FA2'} = "";
	&add_student;
	}
   
   @quizzes = split(/\0/, &unpipe($data{'QuizName'}));
   foreach $quiz (@quizzes){
    $student_quizzes .= "$quiz%";
    }
   $student_quizzes =~ s/%$//;
   $data{'ID'} = &unpipe($data{'ID'});
   $data{'Name'} = &unpipe($data{'Name'});
   $data{'Password'} = &unpipe($data{'Password'});
   open(FILE, ">>$authorized_users_file") ||
    &debug("Could not open authorized users file ($authorized_users_file):$!"); 

    if($opsys eq "unix"){ flock(FILE, 2); }
    else { binmode(FILE); }

   seek(FILE, 0, 2);
   # 06/28/02 added admlogin so that we know who added it.
   print FILE "$data{'ID'}|$data{'Password'}|$data{'Name'}|$student_quizzes|$data{'admlogin'}\n";
   close(FILE);
   $message = "<b>Student $data{'ID'} added. Add another student:</b><br><br>";
   $data{'FA2'} = "";
   $data{'ID'} = ""; $data{'Password'} = ""; $data{'Password2'} = "";
   $data{'Name'} = "";
   &add_student;
   exit();
}

sub add_quiz_to_students{

 my($title,@qstudents) = @_;
 $title = &unpipe($title);
 my($qstudent,$line,$newfile,@lines);
 open(AU, "+<$authorized_users_file") ||
  &debug("Could not open authorized users file ($authorized_users_file):$!"); 
    
    if($opsys eq "unix"){ flock(AU, 2); }
    else { binmode(AU); }

 @lines = <AU>;
 foreach $line (@lines){
    $found_student = 0;
    foreach $qstudent (@qstudents){
      if($line =~ /^$qstudent\|/ && $line !~ /\%$title/){
         $found_student = 1; 
         chomp($line);
         ($sid,$spw,$sname,$squizzes,$sins) = split(/\|/, $line);
         if($sins eq ""){ $sins = $overall_admin;}
	 if($squizzes =~ /%$/){
	    $squizzes = "$squizzes$title";
	    }
	 else {
            $squizzes = "$squizzes%$title";
	    }
         $line = "$sid|$spw|$sname|$squizzes|$sins\n";
         }
      elsif($line =~ /^$qstudent\|/ && $line =~ /$title/){
         $found_student = 1; 
	 }
      }
      if($found_student != 1){
	 $line =~ s/$title//g;
	 $line =~ s/%%/%/g;
	 }
      $newfile .= $line;
   }
   truncate(AU, length($newfile));
   seek(AU,0,0);
   print AU $newfile;
   close(AU);

}
sub delete_results {

$quiz = $data{'Quiz'};
$quiz =~ s/\W+//g; $quiz =~ tr/[A-Z]/[a-z]/;
$oldline = $data{'Old'};
$fa2 = $data{'FA2'};
 $quizfile = "$basedir/$quiz/results.data";
 &debug("Deleting from $quizfile");
 open(FILE, "+<$quizfile") ||
   &debug("could not open results file $quizfile");
    
    if($opsys eq "unix"){ flock(FILE, 2); }
    else { binmode(FILE); }
 
 @lines = <FILE>;
 foreach $line (@lines){
    $line =~ s/\s+$//g;$line =~ s/^\s+//g;
    $oldline =~ s/\s+$//g;$oldline =~ s/^\s+//g;
    if($line ne $oldline){
       $newfile .= "$line\n";
       }
    }
 truncate(FILE, length($newfile));
 seek(FILE,0,0);
 print FILE $newfile;
 close(FILE);
 $data{'FA2'} = "View";
 &view_results;

}

sub edit_results {

$quiz = $data{'Quiz'};
$oldline = $data{'Old'};
$fa2 = $data{'FA2'};

 if($fa2 ne "Edit Now"){
   print "$header
	 <center><strong>Edit Results Entry</strong></center>
	 <br><br>
	 Please modify whichever information you like in the
	 fields below. When you are finished, press the
	 \"Edit Results\" button. (<b>Note:</b> \"Name\", \"Password\", and
	 \"Email\" are what the student entered into the \"Name,\"
	 \"SSN,\" and \"Email\" fields on the quiz form, respectively and
	 may not have been checked for validity.)
	 $admformtop
	 <table border=1 cellpadding=0 cellspacing=0>
	 <tr><th>Score</th><th>Name</th><th>Password</th><th>Email/ID</th>
	     <th>Quiz Name</th><th>Date/Time Taken</th>
	 </tr><tr>";
    foreach $old (split(/\|/, $oldline)){
       $i++;
       $len = length($old) + 1;
       if($len > 25){ $len = 25;}
       print "<td align=center><input type=text name=$i size=$len value=\"$old\"></td>";

       }
    print "</tr></table>
	   <input type=hidden name=Quiz value=\"$data{'Quiz'}\">
	   <input type=hidden name=Old value=\"$data{'Old'}\">
	   <input type=hidden name=FA2 value=\"Edit Now\">
	   <input type=submit name=FA value=\"Edit Results\">
	   </form>
	   $footer";
    exit();

 } # end if
 $quiz =~ s/\W+//g; $quiz =~ tr/[A-Z]/[a-z]/;
 $quizfile = "$basedir/$quiz/results.data";
 $newline = "$data{'1'}|$data{'2'}|$data{'3'}|$data{'4'}|";
 $newline .= "$data{'5'}|$data{'6'}|$data{'7'}\n";
 open(FILE, "+<$quizfile") || 
  &debug("Could not open $quizfile for read/write: $!");
    
    if($opsys eq "unix"){ flock(FILE, 2); }
    else { binmode(FILE); }
 
 @lines = <FILE>;
 foreach $line (@lines){
   $line =~ s/\s+$//sg;
   $oldline =~ s/\s+$//sg;
    if($line ne $oldline){
       $newfile .= $line . "\n";
       }
    else {
       $newfile .= "$newline";
       }
    }
 truncate(FILE, length($newfile));
 seek(FILE,0,0);
 print FILE $newfile;
 $data{'FA2'} = "View";
 &view_results;

}

sub perl_escape {
 
 my($stuff) = $_[0];
 # Just a quick routine to get rid of things that could hurt
 # our program...
 $stuff =~ s/\%/&#37;/g;
 $stuff =~ s/\|/&#124;/g;
 $stuff =~ s/\"/&quot;/g;
 $stuff =~ s/</&lt;/g;
 $stuff =~ s/>/&gt;/g;
 $stuff =~ s/\$/\\\$/g;
 $stuff =~ s/\@/\\\@/g;

 $stuff;


}

sub perl_unescape {
 
 my($stuff) = $_[0];
 # Just a quick routine to translate the stuff back to what it was before
 $stuff =~ s/&#37;/\%/g;
 $stuff =~ s/&#124;/\|/g;
 $stuff =~ s/&quot;/\"/g;
 $stuff =~ s/&lt;/</g;
 $stuff =~ s/&gt;/>/g;
 $stuff =~ s/\\\$/\$/g;
 $stuff =~ s/\\\@/\@/g;

 $stuff;


}

sub unpipe_for_html {

 my($stuff) = $_[0];
 # Just a quick routine to get rid of things that could hurt
 # our program...
 $stuff =~ s/\%/&#37;/g;
 $stuff =~ s/\|/&#124;/g;
 $stuff =~ s/\"/&quot;/g;
 $stuff =~ s/</&lt;/g;
 $stuff =~ s/>/&gt;/g;
 $stuff =~ s/#/&#35;/g;

 $stuff;

}

sub unpipe {

 my($stuff) = $_[0];
 # Just a quick routine to get rid of things that could hurt
 # our program...
 $stuff =~ s/\%/&#37;/g;
 $stuff =~ s/\|/&#124;/g;
 $stuff =~ s/\"/&quot;/g;
 $stuff =~ s/</&lt;/g;
 $stuff =~ s/>/&gt;/g;
 $stuff =~ s/#/KPHHASH/g;

 $stuff;

}

sub repipe {

 my($stuff) = $_[0];
 # Just a quick routine to put things back to normal for mail
 $stuff =~ s/KPHHASH/#/g;
 $stuff =~ s/&#37;/\%/g;
 $stuff =~ s/&#166;/\|/g;
 $stuff =~ s/&quot;/\"/g;
 $stuff =~ s/&lt;/</g;
 $stuff =~ s/&gt;/>/g;
 $stuff =~ s/&#35;/#/g;

 $stuff;

}

sub view_results {

 $html = &find_quizzes("option");
 if($data{'FA2'} ne "View"){
 print "$header
	<center><strong>Please choose a quiz to view results:</strong>
	</center><br><br>
	$admformtop
	<select name=Quiz>
	$html
	</select>
	<input type=hidden name=FA2 value=View>
	<input type=submit name=FA value=\"View Results\">
	</form>
	$footer";
	exit();
  }
  if($data{'Quiz'} =~ /NO QUIZZES FOUND/ || $data{'Quiz'} eq ""){
    print "$header <b>Error: No quizzes found.</b> $footer";
    exit();
    }

  $quiz = &unpipe($data{'Quiz'});
  $quiz =~ s/\W+//g; $quiz =~ tr/[A-Z]/[a-z]/;
  $quizdir = "$basedir/$quiz";
  if(-f "$quizdir/results.data"){
     open(FILE, "<$quizdir/results.data");
     if($opsys ne "unix"){ binmode(FILE); }
      @lines = <FILE>;
     close(FILE);
     }
   print "$header<table border=1>
	  <tr><th>Score</th>
	      <th>Name</th>
	      <th>Password</th>
	      <th>Email/ID</th>
	      <th>Quiz</th>
	      <th>Date Taken</th>
	  </tr>";

   foreach $line (@lines){
      ($score,$name,$pw,$id,$qname,$date) =
	split(/\|/, $line);
      print "<tr><td>$score</td><td>$name</td>
	      <td>$pw</td>
	      <td>$id</td>
	      <td>$qname</td>
	      <td>$date</td>
	      $admformtop
	      <input type=hidden name=FA value=\"Delete Results\">
	      <input type=hidden name=Quiz value=\"$quiz\">
	      <input type=hidden name=Old value=\"$line\">
	      <td><input type=submit name=FA2 value=Delete></td>
	      </form>
	      $admformtop
	      <input type=hidden name=FA value=\"Edit Results\">
	      <input type=hidden name=Quiz value=\"$quiz\">
	      <input type=hidden name=Old value=\"$line\">
	      <td><input type=submit name=FA2 value=Edit></td>
	      </tr></form>\n";
      }
      print "</table>$footer";
      exit();
}
sub deletequiz {

 if($data{'FA2'} eq "GetConfirm"){
   if($data{'DeleteQuiz'} =~ /NO QUIZZES FOUND/ || $data{'DeleteQuiz'} eq ""){
     print "$header
	    <b>Error: No quizzes found.</b>
	    $footer";
     exit();
     }
    $data{'DeleteQuiz'} = &unpipe($data{'DeleteQuiz'});
    print "$header
	   <center><strong>WARNING! You are about to 
	   delete a Quiz!</strong></center><br><br>
	   If you delete this quiz ($data{'DeleteQuiz'}),
	   it will remove the quiz, the answers, and all
	   the student scores and results. You may wish to 
	   \"Get Statistics\" first, so that you may print out the
	   results of this quiz for your records before deleting it,
	   or \"View Quiz\" to make sure this is the quiz you wish to
	   delete. Please confirm
	   that you wish to delete this quiz:
	   $admformtop
	   <input type=hidden name=DeleteQuiz value=\"$data{'DeleteQuiz'}\">
	   <input type=hidden name=QuizName value=\"$data{'DeleteQuiz'}\">
	   <input type=hidden name=FA2 value=\"Confirm\">
	   <input type=submit name=FA value=\"Delete Quiz\">
	   <input type=submit name=FA value=\"Get Statistics\">
	   <input type=submit name=FA value=\"View Quiz\">
	   </form>
	   $footer";
	   exit();
    }
 if($data{'FA2'} eq "Confirm"){

   # Really delete the quiz.
   $quiz = &unpipe($data{'DeleteQuiz'});
   $quiz =~ tr/[A-Z]/[a-z]/; $quiz =~ s/\W+//g;
   $quizdir = "$basedir/$quiz";
   
   opendir(DIR, $quizdir);
    @files = readdir(DIR);
   closedir(DIR);
   if(-f "$quizdir/quizdb"){ unlink("$quizdir/quizdb"); }
   if(-f "$quizdir/header"){ unlink("$quizdir/header"); }
   if(-f "$quizdir/footer"){ unlink("$quizdir/footer"); }
   if(-f "$quizdir/config"){ unlink("$quizdir/config"); }
   if(-f "$quizdir/timing"){ unlink("$quizdir/timing"); }
   if(-f "$quizdir/results.data"){ unlink("$quizdir/results.data"); }
   if(-f "$quizdir/results.data-detailed"){ unlink("$quizdir/results.data-detailed"); }
   if(-f "$quizdir/answerfile"){ unlink("$quizdir/answerfile"); }
   rmdir($quizdir) || &debug("Could not remove $quizdir: $!");
   # Remove from users file
   &remove_quiz_from_users("$data{'DeleteQuiz'}");
   # Remove from instructor file
   open(FILE, "+<$instructors_file") ||
    &debug("Could not open $instructors_file (instructors file): $!");
    if($opsys eq "unix"){ flock(FILE, 2); }
    else { binmode(FILE); }
 
    @lines = <FILE>;
    foreach $line (@lines){
      chomp($line);
      # split up all the quizzes.
      ($dinsid,$dinspw,$dinsna,$dinsquizzes) = split(/\|/, $line);

      # Go through each quiz and compare it to the one to delete.
      # if it matches, then just don't put it back. Otherwise, tack
      # it on to the list of stuff to put back in the file.

      foreach $dinsq (split(/\%/, $dinsquizzes)){
	 if($dinsq ne $data{'DeleteQuiz'} && $dinsq ne "" &&
            $dinsq ne &unpipe($data{'DeleteQuiz'})){
	    $quizzes .= "%$dinsq";
	    }
	 }
      $line = "$dinsid|$dinspw|$dinsna|$quizzes";
      $line =~ s/%%/%/g;
      $newfile .= "$line\n";
      $quizzes = "";
      }
    truncate(FILE, length($newfile));
    seek(FILE,0,0);
    print FILE $newfile;
    $data{'FA2'} = "";
    $message = "<b>$data{'DeleteQuiz'} Deleted. Delete another quiz:</b>
	       <br><br>";
    &deletequiz; 
    exit();


    }
 # Find all the quizzes for this instructor.
 # or, if it's the main instructor, find all
 # quizzes.
 $html = &find_quizzes("option");
   print "$header
	  $message
	  Select a quiz to delete:
	  $admformtop
	  <select name=DeleteQuiz>
	  $html
	  </select>
	  <input type=hidden name=FA2 value=\"GetConfirm\">
	  <input type=submit name=FA value=\"Delete Quiz\">
	  </form>
	  $footer";
          exit();
}

sub find_quizzes {

 my($html,$quizzes,$file,@files,$title,$instr,@stuff);
 my($opt) = $_[0];
 if($auth == 1){
   opendir(DIR, "$basedir");
    @files = readdir(DIR);
   closedir(DIR);
   foreach $file (@files){
     if(-d "$basedir/$file" && -f "$basedir/$file/quizdb"
        && $file !~ /\W/){
        $quizzes .= "$basedir/$file/quizdb\n";
        }
      }
   if($quizzes eq ""){
      $html = "---NO QUIZZES FOUND--\n" if $opt eq "checkbox";
      $html = "<option value=\"\">---NO QUIZZES FOUND--</option>\n" 
      if $opt eq "option";
      }
   else {
      foreach $quiz (split(/\n/, $quizzes)){
      open(FILE, "<$quiz");
       ($title,$instr,@stuff) = split(/\|/, <FILE>);
      close(FILE);
      $html .="<input type=checkbox name=QuizName value=\"$title\">$title<br>\n"
      if $title ne "" && $opt eq "checkbox";
      $html .= "<option value=\"$title\">$title</option>\n" 
      if $title ne "" && $opt eq "option";
         }
     }
  }

  else {

  open(FILE, "$instructors_file");
   $insline = (grep(/^$data{'admlogin'}\|/, <FILE>))[0];
  close(FILE);
  ($ins,$pw,$name,$quizzes) = split(/\|/, $insline);
   chomp($quizzes);
   foreach $quiz (split(/%/,$quizzes)){
      $html .= "<input type=checkbox name=QuizName value=\"$quiz\">$quiz<br>\n"
      if $quiz ne "" && $opt eq "checkbox";
      $html .= "<option value=\"$quiz\">$quiz</option>\n" 
      if $quiz ne "" && $opt eq "option";
      }

      }

  $html;


}
sub show_student_login {
  print "$header
	 $error
	 Please Login to take the quiz:<br>
	 <form method=POST action=$cgi_url?$ENV{'QUERY_STRING'}>
         <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
	 <table border=0>";
  if($authorized_users eq "yes" && $overall_quiz_password ne "yes"){
    print "	 <tr><th align=right>Login:</th>
	 <td><input type=text name=student value=\"$data{'student'}\">
	 </td></tr>
	 <tr><th align=right>Password:</th>
	 <td><input type=password name=studpass value=\"$data{'studpass'}\">
	 </td></tr>";
	 }
   if($overall_quiz_password eq "yes"){
   print "<tr><th align=right>Quiz Password:</th>
	 <td><input type=password name=overall_quiz_password_text 
	 value=\"$data{'overall_quiz_password_text'}\">
	 </td></tr>";
       }
    print "</table>
	 <input type=hidden name=QuizName value=\"$ENV{'QUERY_STRING'}\">
	 <input type=submit name=FA2 value=Login>
	 </form>
	 $footer";
	 exit();

 }
sub check_student_auth {

 # If there is no authorized users setting, then they are just
 # authorized by default.
  if($authorized_users eq "no" && $overall_quiz_password eq "no"){
     $auth = 1;
     return $auth;
     }
  elsif($data{'student'} eq "" || $data{'studpass'} eq ""){ $auth = 0; }
  else {
  open(FILE, "<$authorized_users_file");
   ($student,$studpass,$studname,$studquizzes) = 
    split(/\|/, (grep(/^$data{'student'}\|/, <FILE>))[0]);
  close(FILE);
  chomp($studpass);
  if($student eq &unpipe($data{'student'}) &&
     $studpass eq &unpipe($data{'studpass'})){
     # Check to see if they can take this particular quiz
     chomp($studquizzes);
     @s_quizzes = split(/%/, $studquizzes);
     # They are authorized for no quizzes. 
     if($#s_quizzes < 0){
	$auth = -1;
	}
     elsif(-f "$basedir/$quizdir/quizdb"){
        open(FILE, "<$basedir/$quizdir/quizdb");
          $quiztitle = (split(/\|/, <FILE>))[0];
        close(FILE);
	}
     foreach $s_quiz (@s_quizzes){
	if ($quiz eq $s_quiz || $quiztitle eq $s_quiz){ $auth = 1; last; }
	else { $auth = -1; }
         }
      }
   }
   if($auth != 1){
      # First, check to see if global pw is enabled.
      if($overall_quiz_password eq "yes" &&
         $data{'overall_quiz_password_text'} eq $overall_quiz_password_text &&
	 $overall_quiz_password_text ne ""){
	 $auth = 1;
	 }
      else {
         # Check to see if it's an instructor trying out the quiz.
         $data{'admlogin'} = &unpipe($data{'admlogin'});
         $data{'admpass'} = &unpipe($data{'admpass'});
         open(FILE, "<$instructors_file");
          ($instructor,$inspass) = 
          (split(/\|/, (grep(/^$data{'admlogin'}\|/, <FILE>))[0]))[0,1];
         close(FILE);
         chomp($inspass);
         if($instructor eq $data{'admlogin'} && $inspass eq $data{'admpass'}
	    && $data{'admlogin'} ne "" && $data{'admpass'} ne ""){
            $auth = 2;
            }
         }
      }
   $auth;

}
sub show_quiz {

 $data{'QuizName'} = &unpipe($data{'QuizName'});
 if($ENV{'QUERY_STRING'} eq ""){
    $quiz = $data{'QuizName'};
    $quizdir = $quiz;
    $quizdir =~ s/\W+//g; $quizdir =~ tr/[A-Z]/[a-z]/;
    }
 else {
    $quiz = $ENV{'QUERY_STRING'};
    $quizdir = $quiz;
    $quizdir =~ s/\W+//g; $quizdir =~ tr/[A-Z]/[a-z]/;
    }
 &get_quiz_config("$basedir/$quizdir/config");
 if(-f "$basedir/$quizdir/header"){
   undef $/; open(F, "<$basedir/$quizdir/header"); 
   if($opsys ne "unix"){ binmode(F); }
   $header = <F>; close(F);
   $/ = "\n";
   }
 if(-f "$basedir/$quizdir/footer"){
   undef $/; open(F, "<$basedir/$quizdir/footer"); 
   if($opsys ne "unix"){ binmode(F); }
   $footer = <F>; close(F);
   $/ = "\n";
   }
 $header .= "<META HTTP-EQUIV=Pragma Content=\"No-Cache\">";
 $formtop = "<form name=\"QuizTest\" method=POST action=$cgi_url>";
 $student_auth = &check_student_auth;
 if($student_auth == 1){

   # Check if there is a time limit. If so, add to the time limit file
   # for this student.
   &start_time($data{'student'},$quizdir);

   $formtop .= "<input type=hidden name=student value=\"$data{'student'}\">
               <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
	       <input type=hidden name=autosub value=\"\">
	     <input type=hidden name=studpass value=\"$data{'studpass'}\">
	     <input type=hidden name=overall_quiz_password_text value=\"$data{'overall_quiz_password_text'}\">
	     ";
   }
  elsif($student_auth == 2){
   $formtop = $admformtop;
   }
 else {
   $formtop .= "<input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">";
   }
 # First, let's check and see if we are using registered users, and
 # if so, can they take the quiz:
 if(($authorized_users eq "yes" || $overall_quiz_password eq "yes") 
    && $student_auth != 1 && $student_auth != 2){
    if($student_auth == -1){
       $error = "Error: your login and password are correct, but you
		 have not been authorized to take this quiz. ($quiztitle).";
       &no_args_error;
       }
    elsif($student_auth == 0 && $overall_quiz_password eq "yes"){
       $error = "Error: Incorrect quiz password" if $data{'overall_quiz_password_text'} ne "";
       &show_student_login;
       }
    $error = "Error: Incorrect Login or Password.<br>" if $data{'student'} ne ""
    && $data{'studpass'} ne "";
    &show_student_login;
    }
 unless((-d "$basedir/$quizdir") || (-f "$basedir/$quizdir/quizdb")){
   $error = "<br><b>Error: No such quiz found.</b><br><br>";
   &no_args_error;
   exit();
   }
 $returndup = &check_duplicate_quiz_triers;
 if(($take_quiz_over eq "no" && $returndup != 1) && $student_auth != 2){
    print $returndup;
    exit();
    }

  # Let's not save the results if they've already taken it.
  if($returndup != 1){ $do_not_save_results = 1; }

  open(FILE, "<$basedir/$quizdir/quizdb") || &debug("could not open quizdb for reading: $!");
   if($opsys ne "unix"){ binmode(FILE); }
    ($title,$instr,$fn,$ea,$id,@qs) = split(/\|/, <FILE>);
   close(FILE);
   $instr = &repipe($instr);
   if($_[0] ne "refresh"){
   print "$header
	  <center><font size=+3>$title</font></center><br><br>";
   }
   print "$error $instr $formtop <table border=0>";
   if($fn ne ""){
      print "<tr><th align=right>$fn</th>
	      <th><input type=text name=Name value=\"$data{'Name'}\"></th></tr>";
	     
      }
   else {
      print "<input type=hidden name=Name value=\"N/A\">";
      }
      print "<input type=hidden name=fn value=\"$fn\">";
   if($ea ne ""){
      print "<tr><th align=right>$ea</th>
	      <th><input type=text name=Email value=\"$data{'Email'}\"></th></tr>";
      }
   else {
      print "<input type=hidden name=Email value=\"N/A\">";
      }
      print "<input type=hidden name=ea value=\"$ea\">";
   if($id ne ""){
      print "<tr><th align=right>$id</th>
	      <th><input type=text name=SSN value=\"$data{'SSN'}\"></th></tr>";
      }
   else {
      print "<input type=hidden name=SSN value=\"N/A\">";
      }
      print "<input type=hidden name=id value=\"$id\">";
   print  $timeoutfield;
      print "</table><P>\n<dl>\n";

      for ($i = 0; $i <= $#qs; $i++){
         $num = $i + 1;
         $q = $qs[$i];
	 ($ques,$ans) = split(/ # /, $q);
	  $ques = &repipe($ques);
	  @ans = split(/%%/, $ans);
	  print "<dt><b>$num: $ques</b>\n<dd>\n";
	  ANS:
	  foreach $ans (@ans){
	     $ans =~ s/^\s+//g; $ans =~ s/\s+$//g;
	     $ans2 = &repipe($ans);
	     if($ans ne "" && $ans2 =~ /^%SAQ%/){
                print "<input type=text name=$num value=\"$data{$num}\"><br>\n";
		last ANS;
	        }
	     elsif($ans ne "" && $ans2 =~ /^%SAT%/){
                print "<textarea name=$num rows=5 cols=40>$data{$num}</textarea><br>\n";
		last ANS;
	        }
	     elsif($ans ne "") {
                 if($data{$num} eq $ans){ $ck = " CHECKED";}
                 else{ $ck = ""; }
                 print "<input type=radio name=$num value=\"$ans\"$ck>$ans2<br>\n";
	        } 
	     }

	 }
      $btitle = $title;
      $btitle =~ tr/[A-Z]/[a-z]/;
      $btitle =~ s/\W+//g;
      if($footer !~ /tesol.net\/scripts/i){
          $footer = "<br><font size=-2>Powered by QuizTest v3.0.17 (Quiz Engine
           Copyright &copy; 1997-2000 
           Kristina Pfaff-Harris and can be found at
	   <a href=\"http://www.tesol.net/scripts/\">
           http://www.tesol.net/scripts</a></font>)<br>
	   $footer";
      }
      print "</dl>
	     <input type=hidden name=\"Lesson\" value=\"$title\">
	     <input type=hidden name=\"Lessondir\" value=\"$btitle\">
	     <input type=hidden name=FA value=\"Grade Quiz\">
	     <input type=submit value=\"$grade_quiz_button_text\">
	     </form>
             $footer";
      exit();

    


}

sub grade_quiz {

# See if they're allowed to take it...
 $quiz = $data{'Lessondir'};
 $quizdir = $quiz;
 $quizdir =~ s/\W+//g; $quizdir =~ tr/[A-Z]/[a-z]/;
 #kph get quiz config
 &get_quiz_config("$basedir/$quiz/config");
 $student_auth = &check_student_auth;
if(($authorized_users eq "yes" || $overall_quiz_password eq "yes")
    && $student_auth != 1 &&
    $student_auth != 2){
    &show_student_login;
    }
 $returndup = &check_duplicate_quiz_triers;
 if(($take_quiz_over eq "no" && $returndup != 1) && $student_auth != 2){
    print $returndup;
    exit();
    }
  
  # Let's not save the results if they've already taken it.
  if($returndup != 1){ $do_not_save_results = 1; }

  if($authorized_users eq "yes"){
     $quiz_time = &end_time($data{'student'},$quiz);
     if($quiz_time ne ""){
	$d_quiz_time = "Time to take this quiz: $quiz_time minutes.<br>
		      Time limit was: $time_limit minutes.";
	$m_quiz_time = "Time to take this quiz: $quiz_time minutes.\n";
        $m_quiz_time .="Time limit was: $time_limit minutes.\n";
	}
     }
  &debug("Answer file is \"$answer_file\"");
   if(-r $answer_file){
      &debug("I can see the answer file. It's at $answer_file. Right on!");
      }
   else {
      &debug("Ack! I don't see the answer file or I just can't read it.
      Check and make sure it's in the right place...I'm trying to find
      it at \"$answer_file\". You might check your \$basedir setting to
      make sure it's correct if you're getting this message.");
      }

   &debug("Results database is in \"$results_database\"");
      if(-w $results_database){
         &debug("I can write to the Results Database. This is good!");
         }
      else {
         &debug("I can't write to the Results Database. If this is the first
	 time a student is taking the quiz, this is okay. If not, then there
	 may be a problem. If you are taking this as the instructor for
	 testing purposes, you'll probably get this message until you (or
	 a student) logs in and takes the quiz. If you get this message
	 after that time, then there may be a problem.");
        }
   &debug("Detailed Results database is in \"$results_database-detailed\"");
      if(-w "$results_database-detailed"){
         &debug("I can write to the Detailed Results Database. This is good!");
         }
      else {
         &debug("I can't write to the Detailed Results Database. If this is
	 the first time a student is taking the quiz, this is okay. If not,
	 then there may be a problem. If you are taking this as the
	 instructor, then you'll probably get this message until you log
	 in as a student and take it. If you get this message after that,
	 there may be a problem.");
        }
   
# This starts us off with an "either/or" choice.  In plain English,
# it says "If the name or email field of the form was blank, send
# the student a page with this message (The HTML stuff you see)
# and give them the opportunity to go back to the quiz again.
# otherwise ("else"), run the rest of the program.  You can edit
# the HTML code, but beware!  If you use " marks or @ signs, you
# MUST put a \ (backslash) in front of each as I have below.  Otherwise,
# Perl gets quite annoyed with you and can do very strange things.
#
# You can change the HTML code to the message you'd like the student to
#  see if she forgets to enter required information.
$Name = $data{'Name'};
$Email = $data{'Email'};
$SSN = $data{'SSN'};

if($data{'student'} ne ""){ $Email = $data{'student'}; }

if(($Name eq "" || $Email eq "" || $SSN eq "") &&
    ($time_quiz eq "no" || 
     ($time_quiz eq "yes" && $auto_submit_timed_quiz ne "yes"))){
   $error = "<b>Error: Not Enough Information: 
   You need to fill out all fields on the form before your quiz can
   be processed.</b><br><br>";
   $ENV{'QUERY_STRING'} = $quizdir;
   &show_quiz;
   exit();
   }

# Extract the "keys" from the associative array %data and dump them 
# into the array @form_submitted_question_numbers.  Thus, for every 
# question number coming in from the form, we will have a list element in 
# the array. 

  @form_question_numbers = keys(%data);

# Get the questions so that we can match them with the answers.

if($show_quiz_questions ne "no"){
  open(QDB, "<$basedir/$quizdir/quizdb") || &debug("could not open quizdb for reading: $!");
    ($t_title,$t_instr,$t_fn,$t_ea,$t_id,@qs) = split(/\|/, <QDB>);
  close(QDB);
  }
else { undef (@qs);}

# Now print up the HTML header information for the response.
# See, we're using that $title variable.  We've already saved some
# typing!  We also don't have to type in the Lesson number, or the
# student's name or email address, since we get that right from the 
# form with $Name and $Email. 

  print "$header
         <center><strong>$lesson Results for $Name 
	 ($Email)<br>$d_quiz_time</center></strong><P>";
  $detailedresults = "$Email|";
# Now we're going to have the program look up the answers. We
# already told the program where to look when we defined 
# $answer_file above, so that's where it will look. 

  open (ANSWERS, "$answer_file");
   @answer_file_lines = <ANSWERS>;
  close(ANSWERS);
  # get rid of remarks by ignoring lines that start with REM:
  $j = 0;
  foreach $line (@answer_file_lines){
     if($line !~ /^REM/){
       chomp($line);
       $line =~ s/^\s+//;
       $line =~ s/\s+$//;
       $afl[$j] = $line;
       $j++;
     }
  }

# Now, the answers are in the array @afl

  open(QDB, "<$basedir/$quizdir/quizdb") || &debug("could not open quizdb for reading: $!");
    ($t_title,$t_instr,$t_fn,$t_ea,$t_id,@realqs) = split(/\|/, <QDB>);
  close(QDB);
# If $force_complete_quiz
  if($force_complete_quiz eq "yes"){
     &validate_quiz;
     }
  for($i = 0; $i <= $#afl; $i++){

  # $afl[$i] contains the correct answer.
  $data{$i + 1} = &unpipe($data{$i + 1});
  $total_number_of_questions = $i + 1;
# Split on |, this is #5
#Write InforNet, please. # %SAQ% InforNet// %%|2x7=? # %SAQ% 14
  # Don't bother with the questions unless "show_quiz_questions" is
  # yes.
  if ($show_quiz_questions eq "yes"){
     ($real_q,@real_a) = split(/ \# /, $qs[$i]);
      $show_q = &repipe($real_q);
      $mail_q = &repipe($real_q);
      $insshow_q = &repipe($real_q);
      $insmail_q = &repipe($real_q);
      }
   elsif($show_quiz_questions eq "instructor"){
     ($real_q,@real_a) = split(/ \# /, $qs[$i]);
      $insshow_q = &repipe($real_q);
      $insmail_q = &repipe($real_q);
      }
       
  ($q_num, $correct_answer) = split (/\|/, $afl[$i]);
   $correct_answer = &repipe($correct_answer);
# &score_short_answer(Answerentered,CorrectAnswer);
# Returns 1 on success, undef otherwise.
   $iscorrect = 0;

   if($correct_answer =~ /\/\// || $correct_answer =~ /%SAQ%/ ||
      $correct_answer =~ /%SAT%/ || $realqs[$i] =~ /%SAT%/ ||
      $realqs[$i] =~ /%SAQ%/){
       $correct_answer =~ s/%SAQ%//;
       $correct_answer =~ s/%SAT%//;
       $iscorrect = &score_short_answer($data{$i + 1},$correct_answer);
       }
   #$iscorrect = &score_short_answer($data{$i + 1},$correct_answer);
   $correct_answer = &unpipe($correct_answer);

    &debug("$q_num Correct Answer \"$correct_answer\"<br>
    Submitted answer \"$data{$i + 1}\"<BR>");
# Append the student's answer to the detailed results db text.
    $detailedresults .= "$data{$i + 1}|";
  if("$data{$i + 1}" eq "$correct_answer" || $iscorrect == 1){
  # kph 01/20/01 
    $showres .= "$q_num. $show_q<br>".&repipe($data{$i + 1}). " ... CORRECT<BR>\n";
    $mailres .= "$q_num. $mail_q\n    ".&repipe($data{$i + 1}). " ... CORRECT\n";

# Append that to what we're going to mail the instructor...
    
    $instrres .= "$q_num. $insmail_q\n    ".&repipe($data{$i + 1})." ... CORRECT\n";
    $instrres .= "    (Correct answer on file: '$correct_answer')\n\n";

    $number_of_correct_answers++;
    }

    else {
       $showres .= "$q_num. $show_q<br>". &repipe($data{$i + 1}) . " ... INCORRECT\n";
       $mailres .= "$q_num. $mail_q\n    ". &repipe($data{$i + 1}) . " ... INCORRECT\n";
  # kph 01/20/01 
       if ($what_to_show_after_quiz =~ /All/i){
       $showres .= "<br>(<i>The correct answer was ". &repipe($correct_answer)."</i>)\n";
       $mailres .= "  (The correct answer was ". &repipe($correct_answer).")\n";
       }

# We'll also append any incorrect answers along with information about
# the correct answer to the temporary file to be emailed ...

       $instrres .= "$q_num. $insshow_q\n    '$data{$i + 1}' ... INCORRECT\n";
       $instrres .= "    (Correct answer on file: '$correct_answer')\n\n";
       $showres .= "\n<BR>";   

    } #End of else
 } #End of foreach

# Use the get_date subroutine to get the current date and time.

  &get_date;

# Here's another little if/else routine.  This divides the number of
# correct answers by the total number of questions, and multiplies
# it by 100 to get their percentage score (that's the "else" part). 
# The "if" part ensures that if there's some mistake and total 
# number of questions equals zero, we won't crash the program with a
# "divide by zero" error, and it will just print "unknown %."  If 
# you've entered the wrong path for your answerfile, the 
# number of questions will equal 0 or null, confusing the program.

if ($total_number_of_questions eq "0" || $total_number_of_questions eq ""){
  $percent ="0";}
else{
  $percent = ($number_of_correct_answers / $total_number_of_questions) * 100; 
  $r_percent = sprintf("%03d", int($percent + 0.5));
  $f_percent = sprintf("%0.2f", $percent);
}

# We really want to have the actual student login and name if
# possible.
  if($authorized_users eq "yes" && $data{'student'} ne ""){
     $Email = $data{'student'};
     }
  if($Name ne $studname && $studname ne ""){
     $Name = $studname;
     }
# Open the results data file for "appending" (>>)

if($student_auth != 2){
  open (RESULTS, ">>$results_database") || 
    &debug("I cannot open the results database for writing: $!"); 
  open (DRESULTS, ">>$results_database-detailed") || 
    &debug("I cannot open the detailed results database for writing: $!");
  if($opsys eq "unix"){
     flock(RESULTS, 2) || 
       &debug("I can't lock the detailed results database. 
       Your operating system is $^O and may not support file locking.");
     flock(DRESULTS, 2) || 
       &debug("I can't lock the detailed results database. 
       Your operating system is $^O and may not support file locking.");
     }
  else {
     binmode(RESULTS);
     binmode(DRESULTS);
     }

  seek(RESULTS, 0, 2);
  seek(DRESULTS, 0, 2);

# Print a new line in the results database representing the new 
# information.  The new line will look like...
# Number of correct answers|Name|Soc. Sec. #|Email|Name of quiz|Date taken|
# IP address
# and each line will be a separate entry (\n).  Then close up the results 
# file.

  print RESULTS "$r_percent\|" if $do_not_save_results != 1;
  $lesson = &unpipe($lesson);
  print RESULTS "$Name\|$soc\|$Email\|$lesson\|$date\|$ENV{'REMOTE_ADDR'}\n" 
   if $do_not_save_results != 1;
  close (RESULTS);

# Write out the detailed results file
  $detailedresults =~ s/\|$//;
  print DRESULTS "$detailedresults\n" if $do_not_save_results != 1;
  close(DRESULTS);
  }
# However, we want the results file sorted so that when we display, we 
# will see which students scored the highest scores.  So reopen the 
# results file and suck the whole file into an array, one line per
# array element.

  if($student_auth != 2){
     open (RESULTS, "+<$results_database") ||
      &debug("Could not open results database $results_database: $!");
     
     if($opsys eq "unix"){ flock(RESULTS, 2); }
     else { binmode(RESULTS); }
    
     @rows = <RESULTS>;

# And sort the rows from highest to lowest.
     @rows = reverse(sort(@rows));

# Now we are going to overwrite the old results file with the newly 
# sorted rows. and then release the lock on the results file.
     foreach (@rows){
        $newfile .= "$_";
        }
     seek(RESULTS,0,0);
     print RESULTS $newfile;
     close (RESULTS);
  }
 $total_number_of_questions *= 1;
 $f_percent *=  1;
#  Now that we have a way of printing the percentage score, print the
# rest of the page so that the student can see how she did.
  $number_of_correct_answers *= 1;
  $showres .= "<P>You got $number_of_correct_answers out of 
         $total_number_of_questions correct, or $f_percent %\n";
  $mailres = "You got $number_of_correct_answers out of $total_number_of_questions correct, or $f_percent %\nQuiz: $data{'Lesson'}\n\n$mailres";
   
  if($multiple_instructors eq "yes"){
      open(INS, "<$instructors_file") ||
	&debug("Could not open $instructors_file (instructors file) for reading: $!");
	
      $insline = (split(/\|/, (grep(/\b$data{'Lesson'}\b/, <INS>))[0] ) )[0]; 
      close(INS);
      chomp($insline);
      if($insline ne ""){
	 $instructor = $insline;
	 &debug("Found instructor $instructor for $data{'Lesson'}.");
	 }
      }

  if($what_to_show_after_quiz =~ /scoreonly/i){
     $showres = "<P>You got $number_of_correct_answers out of 
         $total_number_of_questions correct, or $f_percent %\n";
     $mailres = "You got $number_of_correct_answers out of 
         $total_number_of_questions correct, or $f_percent %\n";
	 }
  if($what_to_show_after_quiz =~ /none/i){
     $showres = "Thank you for taking this Quiz.  You will
     be notified of your score after the quiz has been closed.\n";
     $mailres = "Thank you for taking this Quiz.  You will
     be notified of your score after the quiz has been closed.\n";
     }
  if($cc_score_to_student eq "Yes" || $mail_score_only eq "Yes"){
     $mailres = &unpipe($mailres);
     $time = time;
     open(TMP, ">$basedir/mresults.$time");
      print TMP "$mailres";
     close($mailres);
     $mailform = "<form method=post action=$cgi_url>
		  <b>Enter your email address if you would like to 
		  be sent your results:
		  <input type=text name=StudEmail>
		  <input type=hidden name=InsEmail value=\"$instructor\">
		  <input type=hidden name=FA value=\"MailResults\">
		  <input type=hidden name=mailres value=\"$time\">
		  <input type=submit value=\"Mail Me\">
		  </form>";

     }
# This prints a page that lets the student go back and try the quiz 
# again if he got less than 100%, or a page that says "Good Job!" if
# the student got 100%.  You can *CHANGE* this message to suit your
# needs.
  if($student_auth == 2){
    $admmessage = "<b>*** Admin Test -- Results not Saved. ***</b><br><br>";
    }
  if($returndup == 1 && $mail_me_results !~ /no/i){
    $mailedornot = "Your results have been mailed to your instructor along
		    with the date and time you took the quiz.";
    }
  else {
    $mailedornot = "Since it appears you've taken this quiz before, your
		    results have not been emailed to the instructor.";
      }
  if($mail_me_results =~ /no/i){
    $mailedornot = "Results of this quiz are not mailed to the instructor. ";
    }
  if($take_quiz_over =~ /yes/){
     $takeoverornot = "You may go back and try it again as many times
		       as you like, but only the first attempt will be
		       accepted for grading.";
     }
  else {
     $takeoverornot = "You may not take this quiz over again.";
     }
  if($mail_score_only eq "Yes"){
     print "$admmessage This instructor does not allow web-based score viewing
     for this quiz. $mailform <hr> $mailedornot $takeoverornot<hr>\n\n";
     }
  elsif($percent < 100 || $what_to_show_after_quiz =~ /none/i){
  print "$admmessage $mailform $showres <hr> $mailedornot $takeoverornot <hr>\n\n";
      }
  else{
  print "$admmessage $mailform $showres
	 <hr> Great Job!!! $mailedornot $takeoverornot <hr>\n\n";
     }
# Show high scorers if we want to:

  if($show_other_scores =~ /Yes/i){
     print "<br><center><table border=1 cellpadding=5>
	    <tr><th colspan=3><font size=+1>High Scorers</font></th></tr>
	    <tr><th>Score</th><th>Name</th><th>Date</th></tr>\n";
     for($i = 0; $i < $number_of_scores_to_show; $i++){
        # cope with both the old and new format. New format has the
        # addition of REMOTE_ADDR, while old format does not.
        @score_data = split(/\|/, $rows[$i]);
        if($#score_data == 6){
           ($sc,$fn,$sn,$em,$ln,$da,$rh) = @score_data;
           }
        else {
           ($sc,$fn,$sn,$em,$ln,$da) = @score_data;
           }
	if($sc ne ""){
	   $sc =~ s/^0+//g;
           print "<tr><td align=center>$sc</td><td>$fn</td><td>$da</td></tr>";
	   }
	}
     print "</table></center><br>\n";
    }

 
# Finally, print out the grading scale. 
  if($show_grading_scale !~ /no/i){
   
     print "<center><B>The Grading Scale</B><P>";
     print &repipe($grading_scale);
     }
   if($footer !~ /tesol.net\/scripts/i){
          $footer = "<br><font size=-2>Powered by QuizTest v3.0.17 (Quiz Engine
           Copyright &copy; 1997-2000
           Kristina Pfaff-Harris and can be found at
           <a href=\"http://www.tesol.net/scripts/\">
           http://www.tesol.net/scripts</a></font>)<br>
           $footer";
      }
  print "$footer";

if($mail_me_results !~ /no/i){

   if($time_quiz eq "yes" && $m_quiz_time eq ""){
      $timetaken = $data{'TimeTaken'};
      $mintaken = int($timetaken / 60);
      $sectaken = $timetaken % 60;
      $time_results = "\nTime allowed: $time_limit minutes\n";
      $time_results .= "Time taken: $mintaken minutes $sectaken seconds.\n\n";
      }
   elsif($time_quiz eq "yes" && $m_quiz_time ne ""){
      $time_results = $m_quiz_time;
      }
   # Then open a pipe to our mail program, so we can send the results
   # off to the instructor:
    if($instructor eq ""){$instructor = $quizresultsemail;}  
    $toname = "$instructor";
    $toemail = "$instructor";
    $fromname= "$webmaster"; $fromemail="$webemail";
    $replytoname= "$webmaster"; $replytoemail="$webemail";
    $subject ="$lesson Quiz Results: $Name";
    if($student_auth == 2){
       $message =  " *** Administrative test by $data{'admlogin'} ***\n";
       $message .= " *** Results not saved to database            ***\n\n";
    }
    $message .= "$Name got $f_percent \% on the $lesson Quiz\n";
    $message .= "on $date. Any further quiz\n";
    $message .= "submissions for this lesson should be ignored.\n\n";
    $message .= "$time_results\n";
    $message .= "Data Entered: \n\n";
    if($data{'fn'} eq ""){$data{'fn'} = "Name";}
    if($data{'ea'} eq ""){$data{'ea'} = "Email";}
    if($data{'id'} eq ""){$data{'id'} = "SSN";}
    $message .=  sprintf("%25s", $data{'fn'}) . ": $data{'Name'}\n";
    $message .=  sprintf("%25s", $data{'ea'}) . ": $data{'Email'}\n";
    $message .=  sprintf("%25s", $data{'id'}) . ": $data{'SSN'}\n";
    if($Name ne $studname && $studname ne ""){
       $message .= "(Real Student name: $studname)\n";
       }
    if($Email ne $student && $student ne ""){
       $message .= "(Real Student ID/Email: $student)\n";
       }
    $message .= "\nYou may review the score statistics by logging in to the\n";
    $message .= "Admin interface here:\n\n";
    $message .= "     $cgi_url?admin\n\n";
    $message .= "Here is a complete summary of $Name\'s $lesson quiz:\n";
    $message .= "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n";
    $message .= "$instrres";
    $message .= "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n";
    $message .= "Logged in from: $ENV{'REMOTE_HOST'} $ENV{'REMOTE_ADDR'}\n";
    $message = &repipe($message);
    &send_mail($toemail,$toname,$fromemail,$fromname,
		$replytoemail,$replytoname,$subject,
		$message,$mail_server_hostname,
		$this_server_hostname) if $returndup == 1 || 
		$student_auth == 2 || $mail_me_results eq "All";
  
 exit();

}


# The get_date subroutine. Eventually, this routine defines a variable
# $date as being the Day, Month, Year, and time.  E.gMonday, Oct 31, 1996 
# at 07:30.

sub get_date {

   @days = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
   @months = ('January','February','March','April','May','June','July',
              'August','September','October','November','December');

   ($min,$hour,$mday,$mon,$year,$wday) = (localtime(time))[1,2,3,4,5,6];
   if ($hour < 10) { $hour = "0$hour"; }
   if ($min < 10) { $min = "0$min"; }
   $year += 1900;
   $date = "$days[$wday], $months[$mon] $mday, $year at $hour\:$min";
   }
}

sub debug {
# if($ENV{'REMOTE_ADDR'} eq "207.228.31.47"){ $debugging = 1; }
 local($msg) = $_[0];
 local($die) = $_[1];
 if($remote_debugging eq "on"){
    if($data{'debugging'} == 1 || $data{'remote_debug'} == 1){
       $debugging = 1;
       }
    }
 if($debugging == 1){
    print "DEBUG: $msg<br>\n";
    if($die eq "die"){ exit(); }
    }
}

sub admin_login {

  print "$header
	 <strong>Please login to Quiz Administration</strong><br><br>
	 <font color=#FF0000>$error</font><br>
	 <form method=POST action=$cgi_url>
         <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
	 <table border=0>
	 <tr><th align=right>Login:</th>
	 <td><input type=text name=admlogin value=\"$data{'admlogin'}\"></td>
	 </tr>
	 <tr><th align=right>Password:</th>
	 <td><input type=password name=admpass value=\"$data{'admpass'}\"></td>
	 </tr>
	 <tr><td>&nbsp;</td>
	  <td><input type=submit name=FA value=\"Log In\"></td></tr>
	 </table>
	 </form>
	 $footer";
  exit();
}

sub show_menu {

 if($auth == 1){
    $option = "<tr>
	       <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"Add Instructor\"></td>
               <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"Delete Instructor\"></td>
               <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"Edit Instructor\"></td></tr>";
   }
    $option2 = "<tr>
	       <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"  Reset Quiz  \"></td>
               <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"    View Quiz     \"></td>
               <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"Get Statistics\"></td></tr>";
    
 print "$header
	<strong>Welcome, Administrator!</strong><br><br>
	Please choose from one of the following options:
        <center>
	$admformtop
	<table border=1>
	$option
	<tr>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\" Add Student \"></td>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\" Delete Student \"></td>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\" Edit Student \"></td>
	</tr>
	<tr>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"    Add Quiz   \"></td>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"   Delete Quiz    \"></td>
	 <td bgcolor=#C0C0C0 align=center><input type=submit name=FA value=\"   Edit Quiz    \"></td>
	</tr>
	$option2
	<tr>
	 <td colspan=3 bgcolor=#C0C0C0 align=center>
	 <input type=submit name=FA value=\"                  View/Edit/Delete Results              \"></td><td bgcolor=#C0C0C0 align=center>
	 </td>
	</tr>
	</form>
	</table>
        </center>
	$footer";
 exit();

}

sub create_quiz_one {

 print "$header <center><strong>Welcome to Quiz Creation</strong></center>
	<BR><br>
        $admformtop
	<table border=0 cellpadding=10>
	<tr><td colspan=2 bgcolor=\"#E4D8E2\"><b>
	Quiz Creation will take you through a series of steps to create
	your quiz. Please read all the instructions carefully, and feel
	free to experiment with the various options.</td></tr>
	<tr>
	 <td>First, how many questions do you want on this quiz?</td>
	 <td><input type=text name=a_num size=4></td></tr>
  	<tr>
	 <td>Now, for each question, what is the maximum number
	of possible answers that you might have? If the entire
	test will be true/false, then you would put \"2\" here.
	On the other hand, if you will be doing multiple choice
	questions, and one of your questions has 7 possible 
	answers, you would put \"7\" here.</td>
	<td><input type=text name=a_anum size=4></td></tr>
        </table> 
	<input type=hidden name=FA value=ShowForm>
	<input type=submit value=\"Take me to the next step!\">
	</form>
	$footer";
	exit();
}

sub check_auth {

 my $login = &unpipe($data{'admlogin'});
 my $pass = &unpipe($data{'admpass'});
 # First, check for the main email & password
 if($login eq $instructor && $pass eq $admin_password &&
    ($login ne "" && $pass ne "")){
    $auth = "1";
    }
 if($multiple_instructors eq "yes"){
    # Create the instructors file if it does not exist.
    unless(-f $instructors_file){
      open(INS, ">>$instructors_file") || &debug("Could not write to instructors file $instructors_file: $!");
       print INS "";
      close(INS);
      }
    open(INS, "<$instructors_file") ||
     &debug("2771: Could not read instructors file: $!");
   if($opsys ne "unix"){ binmode(INS); }
      ($instructor,$inspass) = (split(/\|/, (grep(/^$login\|/, <INS>))[0] ) )[0,1]; 
    close(INS);
    if(($instructor eq $login && $inspass eq $pass) && $auth != 1 &&
    ($login ne "" && $pass ne "")){
       $auth = 2;
       }
    }
 if($auth != 1 && $auth != 2){
   if($multiple_instructors ne "yes"){
      $error = "Error: Multiple Instructors not enabled by QuizTest
                administrator.";
      }
    else {
      $error = "Error: Incorrect login or password. ($auth)";
      }
   &admin_login;
   exit();
   }
   $footer = "<hr><center>
              <br><font size=2>
              <b>(You are logged in as $data{'admlogin'}.
              <a href=\"$cgi_url?admin\">Log Out.</a>)</b></font><br>
              $admformtop
	      <input type=hidden name=FA value=\"Log In\">
	      <input type=submit value=\"Go to Administration Main Menu\">
	      </form></center><hr>$footer";
   
}
sub showform {

local($title,$num,$brieftitle,$anum);
$title = $data{'a_qtitle'};
$num = $data{'a_num'};
$anum = $data{'a_anum'};
$brieftitle = $title; $brieftitle =~ tr/[A-Z]/[a-z]/;
$brieftitle =~ s/\W//g;
$nf = $data{'namefield'};
$ef = $data{'emailfield'};
$sf = $data{'ssnfield'};
$instr = $data{'instr'};
 $instr =~ s/\"/&quot;/g;
 $instr =~ s/\>/&gt;/g;
 $instr =~ s/\>/&lt;/g;
$student_checkboxes = &get_students_as_checkboxes;

if($num eq "" || $anum eq ""){
  print "$header <center><strong>Error: Insufficient Data</strong></center>
	 <br><br> Sorry, but you must enter the number of questions that
	 you'd like to have on this quiz, a title for the quiz, and
	 the maximum number of choices that you wish to enter for answers
	 to quiz questions or
	 I can't set the quiz up for you.  Please <a href=$ENV{'HTTP_REFERER'}>
	 go back and fill in those fields.$footer";
  exit();
  }
else {

    print "$header <center><strong>Step Two: Quiz Page Creation</strong>
	   </center>
	   <br><br><b>Below, you will see a form to fill out for
	   this quiz, including fields to fill in all
	   $num questions on this quiz.  
	   For each question, fill in the question in the question
	   slot, and the answers in the answer slot.  Make SURE you
	   mark the \"Correct\" slot for the correct answer, or
	   no one will be able to get the question right! Any blank
	   question or answer fields will be ignored.
	   <table border=0>
	   $admformtop 
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>If you'd like any custom HTML
	code to be printed at the top of each quiz page, enter it here:</b>
	</td></tr>
	<tr><td colspan=2 align=center>
	<textarea wrap=soft name=Header rows=3 cols=60></textarea></td></tr>
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>If you'd like any custom HTML
	code to be printed at the bottom of each quiz page, enter it here:</b>
	</td></tr>
	<tr><td colspan=2 align=center>
	<textarea wrap=soft name=Footer rows=3 cols=60></textarea></td></tr>
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>Please enter a short title for this 
	Quiz.</b></td></tr>
	<tr><td align=center colspan=2>For
	example, \"Math 101 Quiz 2\" or \"Joe's Cool Trivia Quiz\"
	or even \"The Quizzard of Oz\":</th></tr>
	<tr><td colspan=2 align=center>
	<input type=text name=q_title size=25></td></tr>
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>Please enter instructions for
	the quiz takers.</b></td></tr>
	<tr><td colspan=2 align=center>
	In the area below, enter any instructions or other text
	which you would like to have appear at the top of the page for
	this quiz. This can be detailed instructions, or something simple
	such as \"Take the quiz.\"</td></tr>
	<tr><td colspan=2 align=center>
	<textarea wrap=soft name=instr rows=3 cols=60></textarea></td></tr>
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>Modify the form fields</b></td></tr>
	<tr><td colspan=2 align=center>
	Each quiz has three blanks for the user to fill
	in.  By default, these are \"Full Name,\" \"Email Address,\"
	and \"ID Number\".  Here, you will see the default messages
	that will appear on the quiz form for each quiz. If you
	would like different messages to appear, please take out
	what is below, and enter your own messages.  HINT: If you are using
	the \"authorized users\" feature, you may blank these out, and the
	program will use the values from the student databases instead.</td>
	</tr>
	<tr><td align=center colspan=2>
	<table border=0>
	 <tr><th>Name</th><th>Email</th><th>ID</th></tr>
	 <tr><td>
	<input type=text name=namefield value=\"Please enter your Full Name:\" 
	size=30></td>
	<td><input type=text name=emailfield value=\"Your Email Address:\" 
	size=25></td>
	<td><input type=text name=ssnfield value=\"Your ID Number or Password:\"
	size=28></td>
	  </tr>
	 </table></td>
	</tr>
	<tr><td align=center bgcolor=\"#E4D8E2\" colspan=2>
	<b>Quiz and Quiz Takers</b></td></tr>
	<tr><td align=left colspan=2>
	  On the left, enter the questions and the possible answers. 
	  Hint: To enter a Short-Answer question, type the question as usual, 
	  make sure to check the box for whether you want the student to
	  have a single-line text field or a multi-line text field for
	  filling in their answers.
	  <br><br>To give multiple
	  options for a Short-Answer field, separate the options with two
	  forward slashes (//), e.g.: \"Yes//Yep//Yeah//Yessir\".
	  Be sure to mark it as correct. 
	  If you are using the \"authorized users\" function, select 
	  the
	  checkboxes next to the students who are allowed to take this quiz.
	  <hr>
	   </td></tr>
	   <tr><th>Quiz Info</th><th>Authorized Students</th></tr>
	   <tr><td valign=top>
	   <table border=0>
	   <tr><th rowspan=2>Question</th><th rowspan=2>Possible Answers</th>
	   <th colspan=2>Short-answer questions</th></tr>
	   <tr><th><font size=2>Single-line text field</font></th>
		 <th><font size=2>Multi-line text field</font></th></tr>";

    for($i = 1; $i <= $num; $i++){

       print "<tr>
	      <td valign=top>Question $i<br>
	      <input type=text name=q$i size=25></td><td>
	      <table border=0>";

       for($j = 1; $j <= $anum; $j++){
           print "<tr><td><input type=text name=a-$i-$j size=25></td>
		  <td><input type=radio name=correct$i value=a-$i-$j></td><td>(Correct)</td>
		  </tr>\n";
       }
       print "</table></td><th><input type=radio name=SA-$i value=\"SAQ\"></th>
	      <th><input type=radio name=SA-$i value=\"SAT\"></th>";
    }
       print "</tr>";

    print "</table>
	   <input type=hidden name=q_num value=$num>
	   <input type=hidden name=a_num value=$anum>
	   <input type=hidden name=formaction value=ConfigQuiz>
	   </td><td valign=top>$student_checkboxes</td></tr>
	   </table>
           <input type=submit value=\"Configure quiz options\"></form>
	   $footer";
  exit();
  }
}

sub config_quiz {

$q_title = &unpipe($data{'q_title'});
$q_brieftitle = $q_title; 
 $q_brieftitle =~ s/\W+//g; $q_brieftitle =~ tr/[A-Z]/[a-z]/;
if($q_brieftitle eq ""){
   print "$header
	 <center><strong>Error: No name for quiz</strong></center><br><br>
	 You must select a name for this quiz. <a onClick=\"javascript:history.back();\" href=$ENV{'HTTP_REFERER'}>Please go back and try again. $footer";
   exit();
  
  }
  if(-d "$basedir/$q_brieftitle"){
   print "$header
	 <center><strong>Error: Quiz $data{'q_title'} already exists. 
         Please choose a different title for your quiz. </strong></center>
         <br><br>
	 <a onClick=\"javascript:history.back();\" href=$ENV{'HTTP_REFERER'}>
         Please go back and try again.</a> $footer";
   exit();
   } 
 print $header;
 print &quiz_options_form;
 foreach $key (keys(%data)){
    if ($key ne "formaction" && $key ne "admlogin" && $key ne "admpass" 
    && $key ne "Student"){
       $pval = &unpipe($data{$key});
       print "<input type=hidden name=\"$key\" value=\"$pval\">\n"
       }
    }
 @stu = split(/\0/, $data{'Student'});
 foreach $stu (@stu){
    print "<input type=hidden name=Student value=\"$stu\">\n";
    }
 print "<input type=hidden name=formaction value=\"CreateQuiz\">
	<input type=submit value=\"Create Quiz\">
	</form>
	$footer";
 exit();

}
sub createquiz {

foreach $key (keys(%data)){$data{$key} = &repipe($data{$key});}
$q_num = $data{'q_num'};
$a_num = $data{'a_num'}; 
$q_title = &unpipe($data{'q_title'});
$q_brieftitle = $q_title; 
 $q_brieftitle =~ s/\W+//g; $q_brieftitle =~ tr/[A-Z]/[a-z]/;
 $q_brieftitle =~ s/^(.*)$/$1/;
$nf = &unpipe($data{'namefield'});
 $nff = "N/A" if $nf eq "";
$ef = &unpipe($data{'emailfield'});
 $eff = "N/A" if $ef eq "";
$sf = &unpipe($data{'ssnfield'});
 $sff = "N/A" if $sf eq "";

if($q_brieftitle eq ""){
   print "$header
	 <center><strong>Error: No name for quiz</strong></center><br><br>
	 You must select a name for this quiz. <a onClick=\"javascript:history.back();\" href=$ENV{'HTTP_REFERER'}>Please go back and try again.</a> $footer";
   exit();
  
  }
$instr = &unpipe($data{'instr'});
  if(-d "$basedir/$q_brieftitle"){
   print "$header
	 <center><strong>Error: Quiz $data{'q_title'} already exists. 
         Please choose a different title for your quiz. </strong></center>
         <br><br>
	 <a onClick=\"javascript:history.back();\" href=$ENV{'HTTP_REFERER'}>
         Please go back and try again.</a> $footer";
   exit();
  
  }

  mkdir("$basedir/$q_brieftitle", 0755) || 
  &debug("$header Could not create directory for quiz: $! I'm trying to 
	  create a directory with a name that is based on the title of 
	  your quiz \"$q_title\" but I can't do that if the directory 
	  already exists. The directory $basedir must be writeable by the web 
	  server in order for this to work.  Please chmod 777 $basedir, then 
	  hit the \"Reload\" button on your browser to try again. $footer",
	  "die");

# Create quiz configuration section
open(QCONFIG, ">$basedir/$q_brieftitle/config") ||
   &debug("Could not create quiz configuration options file: $!");
  if($opsys ne "unix"){binmode(QCONFIG);}
  # You must enable authorized users for the timing to work. 
  # Unfortunately, some people apparently don't read the part of
  # the instructions where it says "you must enable authorized users"
  # in the menu for setting up quiz timing. Therefore, we'll just
  # force it to do the right thing. :-)
  if($data{'opt_time_quiz'} eq "yes" && 
     $data{'opt_auto_submit_timed_quiz'} eq "yes"){
  	$data{'opt_force_complete_quiz'} = "no";
  	}
  foreach $key (keys(%data)){
    if($key =~ /^opt_/){
       # Make sure the variable name has no non-word characters in it
       # in case someone pulls a slicky. Also, unpipe the variable
       # value as well.
       $var = $key; $var =~ s/^opt_//; $var =~ s/\W+//g;
       $config_value = &perl_escape($data{$key});
       print QCONFIG "$var = $config_value;\n";
       }
    }
$key = ""; $var = "";
close(QCONFIG);

open(QDB, ">$basedir/$q_brieftitle/quizdb") || 
  &debug("$header Could not create quiz file $basedir$q_brieftitle/quizdb: 
          $! . It's possible that your web server will not let me 
	  create files on this server. If you have chmodded 
	  $basedir/$q_brieftitle/ to 777 and you are still getting 
	  this message, then you may not be able to use this 
	  program. :( $footer","die");

     
     if($opsys eq "unix"){ flock(QDB, 2); }
     else { binmode(QDB); }
    
  $instr =~ s/\r\n/\n/g;
  $instr =~ s/\n/ /g;
  print QDB "$q_title|$instr|$nf|$ef|$sf";

# Create HTML...
  $k = 1;
  for($i = 1; $i <= $q_num; $i++){
     $q = &unpipe($data{"q$i"});
     if($q ne ""){
	print QDB "|$q #";
        QUIZDB: 
        for($j = 1; $j <= $a_num; $j++){
           $an = &unpipe($data{"a-$i-$j"});
	   if($data{"SA-$i"} eq "SAQ"){
	      print QDB " %SAQ% $an %%";
              last QUIZDB;
	      }
	   elsif($data{"SA-$i"} eq "SAT"){
	      print QDB " %SAT% $an %%";
              last QUIZDB;
	      }
           elsif($an ne ""){
	      print QDB " $an %%";
           }
        }
     $k++;
     }
  }
  close(QDB);

# If there are any students selected, let's assign this quiz to
# all of them at a whack.
if($data{'Student'} =~ /\0/){
  @authstudents = split(/\0/, &unpipe($data{'Student'}));
  }
else {
  $authstudents[0] = &unpipe($data{'Student'});
  }
&add_quiz_to_students($q_title,@authstudents);

# Add this quiz to the instructors file
if(-f "$instructors_file"){
open(FILE, "+<$instructors_file") ||
 &debug("Could not open $instructors_file for read/write: $!");
     
     if($opsys eq "unix"){ flock(FILE, 2); }
     else { binmode(FILE); }
     
 @lines = <FILE>;
 foreach $line (@lines){
   if($line =~ /^$data{'admlogin'}\|/){
      chomp($line);
      $newfile .= "$line%$q_title\n"
      }
   else {
      $newfile .= $line;
      }
   }
  truncate(FILE, length($newfile));
  seek(FILE,0,0);
  if($newfile !~ /$data{'admlogin'}\|/){
     $newfile .= "$data{'admlogin'}|$data{'admpass'}|Admin|$q_title";
     }
  print FILE $newfile;
close(FILE);
}
else {
  open(FILE, ">$instructors_file") || 
   &debug("Could not create instructors file $instructors_file: $!");
     
     if($opsys eq "unix"){ flock(FILE, 2); }
     else { binmode(FILE); }
     
   print FILE "$data{'admlogin'}|$data{'admpass'}|Admin|$q_title\n";
  close(FILE);
  }

      
# Create answerfile...
open(FILE, ">$basedir/$q_brieftitle/answerfile") || 
   &debug("$header Could not create answer file 
	   $basedir/$q_brieftitle/answerfile: $! . It's possible that 
	   your web server will not let me create files on the server
	   at all. If you have chmodded $basedir to 777 
	   and you are still getting this message, then you may not
	   be able to use this program. :-( $footer","die");
     
     if($opsys eq "unix"){ flock(FILE, 2); }
     else { binmode(FILE); }
     
  &get_date;
  print FILE "REM: $title: $q_num questions\n";
  print FILE "REM: Created on $date by $instructor\n";
  $j = 1;
  for($i = 1; $i <= $q_num; $i++){
     $cor = $data{"correct$i"}; 
     $cor =~ s/%SAQ%//g;
     $cor =~ s/%SAT%//g;
     $cor =~ s/^\s+//g;
     $cor =~ s/\s+$//g;
     $cor = &unpipe($data{$cor});
     if($cor ne ""){
        print FILE "$j|$cor\n";
        $j++;
     }
     else {
        print FILE "$j|".$data{"a-$j-1"}."\n";
        $j++;
     }
  }

close(FILE);

if($data{'Header'} ne ""){
  open(F, ">$basedir/$q_brieftitle/header") ||
   &debug("Could not open header file $basedir/$q_brieftitle/header: $!");
   if($opsys ne "unix"){binmode(F);}
   print F "$data{'Header'}";
  close(F);
  }
if($data{'Footer'} ne ""){
  open(F, ">$basedir/$q_brieftitle/footer") ||
   &debug("Could not open footer file $basedir/$q_brieftitle/footer: $!");
   if($opsys ne "unix"){binmode(F);}
   print F "$data{'Footer'}";
  close(F);
  }
 
 $quiz_url = "$cgi_url?$q_brieftitle";

 print "$header <center><strong>Success! Quiz Created!</strong></center>
	<br><br>
	$admformtop
	Your quiz has been created and can be found at
	<b><a target=new href=$quiz_url>$quiz_url</a></b>.
	Please make a note of the location of this quiz so that
	you can put a link to it. <br><br>You may also try out the quiz right
	now to make sure that it works:
	<input type=hidden name=QuizName value=\"$q_title\">
	<input type=submit name=FA value=\"View Quiz\">
	</form>
	$footer";


exit();

}


sub get_data {
    local($string);

    # get data
    if ($ENV{'REQUEST_METHOD'} eq 'GET') {
        $string = $ENV{'QUERY_STRING'};
    }				
    else { read(STDIN, $string, $ENV{'CONTENT_LENGTH'}); }

    # split data into name=value pairs
    @data = split(/&/, $string);
   
    # split into name=value pairs in associative array
    foreach (@data) {
	split(/=/, $_);
	$_[0] =~ s/\+/ /g; # plus to space
	$_[0] =~ s/%00//g; # We don' need no steenking nulls :)
        $_[0] =~ s/%0a/newline/g;
	$_[0] =~ s/%(..)/pack("c", hex($1))/ge; # hex to alphanumeric

	# For checkboxes and multiple selects
	if(defined($data{$_[0]})){ 
	   $data{$_[0]} .= "\0";
	   $data{$_[0]} .= "$_[1]";
	   }
	else {
	$data{"$_[0]"} = $_[1];
	  }
    }
    # translate special characters
    foreach (keys %data) {
	$data{"$_"} =~ s/\+/ /g; # plus to space
	$data{"$_"} =~ s/%00//g; # We don' need no steenking nulls :)
        $data{"$_"} =~ s/%0a/newline/g;
	$data{"$_"} =~ s/%(..)/pack("c", hex($1))/ge; # hex to alphanumeric
    }

    %data;			# return associative array of name=value
}

#&send_mail("to_email","to_name","from_email","from_name","replyto_email",
#               "replyto_name","subject","message","mail_server_hostname",
#              "this_server_hostname");
sub send_mail {

   local($toemail,$toname,$fromemail,$fromname,
         $replytoemail,$replytoname,$subject,
         $message,$mail_server_hostname,$this_server_hostname) = @_;
  &debug("Attempting to send message \"$subject\" to $toemail");
  if($toemail =~ /tesol.net/i){ return; }
if($opsys eq "win"){
   $port = 25;
   $them = "$mail_server_hostname";
   $AF_INET = 2; $SOCK_STREAM = 1;

   $SIG{'INT'} = 'dokill';
   sub dokill {
       kill 9,$child if $child;
   }

   $sockaddr = 'S n a4 x8';

   $hostname = "$this_server_hostname";

   ($name,$aliases,$proto) = getprotobyname('tcp');
   ($name,$aliases,$port) = getservbyname($port,'tcp')
       unless $port =~ /^\d+$/;;
   ($name,$aliases,$type,$len,$thisaddr) =
        gethostbyname($hostname);
   ($name,$aliases,$type,$len,$thataddr) = gethostbyname($them);

   $this = pack($sockaddr, $AF_INET, 0, $thisaddr);
   $that = pack($sockaddr, $AF_INET, $port, $thataddr);

   if (socket(S, $AF_INET, $SOCK_STREAM, $proto)) {
   }
   else { &debug("Could not create socket for mail: $!"); }

   if (bind(S, $this)) {
   }
   else { &debug("Could not bind to socket (this may be okay anyway): $!"); }

   if (connect(S,$that)) {
   }
    else { &debug("Could not connect to socket: $!"); }

   select(S); $| = 1; select(STDOUT);

   $a=<S>; 
   print S "HELO $this_server_hostname\n";
   $a=<S>;  &debug("Mail server responded: $a");
   print S "MAIL FROM:<$fromemail>\r\n";
   $a=<S>;  &debug("Mail server responded: $a");
   print S "RCPT TO:<$toemail>\r\n";
   $a=<S>;  &debug("Mail server responded: $a");
   print S "DATA \r\n";
   $a=<S>;  &debug("Mail server responded: $a");
   print S "To: $toname <$toemail>\n";
   print S "From: $fromname <$fromemail>\n";
   if($replytoemail ne ""){
      print S "Reply-to: $replytoname <$replytoemail>\n";
      }
   print S "Subject: $subject\n\n";
   print S "$message\n";
   print S ".\n";
   $a=<S>; &debug("Mail server responded: $a");
   print S "QUIT";
   &debug("Sending mail done.");

   }

elsif($opsys eq "unix"){

   # Allow for qmail-inject ~sigh~
   # Most other mailer thingies do use the -t option like
   # sendmail in order to be compatible, but apparently
   # qmail-inject does not. Oh well...

   if($path_to_sendmail !~ /qmail-inject/){
      $path_to_sendmail = "$path_to_sendmail -t";
      }

   open(MAIL, "|$path_to_sendmail") || 
     &debug("Could not open sendmail: $!");
     print MAIL "To: \"$toname\" <$toemail>\n";
     print MAIL "From: \"$fromname\" <$fromemail>\n";
     if($replytoemail ne ""){
       print MAIL "Reply-to: \"$replytoname\" <$replytoemail>\n";
       }
     print MAIL "Subject: $subject\n\n";
     print MAIL "$message\n";
     close(MAIL) || &debug("Sending mail got an error: $! $?");
     &debug("Sending mail done.");
   }

else {

   &debug("Cannot send mail. '$opsys' is not a valid operating sytem.
           Please set \$opsys to either 'unix' or 'win' in the script
           and try this again.");
    }
}

sub check_duplicate_quiz_triers {

 open(FILE, "<$basedir/$quiz/results.data") ||
   &debug("could not open results.data for reading: $!");
 if($opsys ne "unix"){ binmode(FILE); }
 if($data{'student'} eq ""){$data{'student'} = $data{'Email'};}
 my $student = $data{'student'};
    foreach (grep(/\|$data{'student'}\|/, <FILE>)){
       $tookonce = (split(/\|/))[3];
       chomp($tookonce);
       $tookonce =~ tr/[A-Z]/[a-z]/;$student =~ tr/[A-Z]/[a-z]/;
       if($tookonce eq $student){
           $returndup = "$header
           <center><strong>Quiz Already Taken</strong></center><br><br>
           Error: This quiz has already been taken by $data{'student'}
           and the instructor does not allow quizzes to be taken more
           than once.
           $footer";
          }
       }

 if($returndup eq ""){
    $returndup = 1;
    }
 $returndup;

}

sub results_stats {
 
 $html = &find_quizzes("option");
 if($data{'QuizName'} ne ""){
   # find the quiz correct answers
   $quizdir = &unpipe($data{'QuizName'});
   $quizdir =~ tr/[A-Z]/[a-z]/; $quizdir =~ s/\W+//g;
   undef $/; 
   open(RS, "<$basedir/$quizdir/results.data") ||
    &debug("Could not read $basedir/$quizdir/results.data: $!");
   if($opsys ne "unix"){ binmode(RS); }
   $testres = <RS>;
   close(RS);
   $/ = "\n";
   if(length($testres) < 10){
       print "$header
	      <b>No results available for $data{'QuizName'}.</b>
	      $footer";
       exit();


       }
   # Let's get the mean, median, and mode scores:
   open(RS, "<$basedir/$quizdir/results.data") ||
    &debug("Could not read $basedir/$quizdir/results.data: $!");
    if($opsys ne "unix"){ binmode(RS); }
    while(<RS>){
     $scores[$n] = (split(/\|/, $_))[0];
     $n++;
    }
   close(RS);
   # Now we should have an array of scores for this quiz.
   # The median is found like this: 
   # sort lowest to highest:
   @scores = sort(@scores);
   $lowest = $scores[0] * 1;
   $highest = $scores[$#scores] * 1;
   $studentstakingquiz = $#scores + 1;

   # Find if the number of elements is even or odd
   $numelements = $#scores + 1;
   if(int($numelements / 2) == $numelements / 2){
     # it's even
     $mediannum = $numelements / 2; 
     $median = (($scores[$mediannum] + $scores[$mediannum - 1]) / 2) * 1;
     }
   else {
     $mediannum = int($numelements / 2) + 1;
     $median = $scores[$mediannum - 1] * 1;
     }

   # Now get the mean:
   foreach $elem (@scores){
	$total = $total + $elem;
	}
   $mean = sprintf("%0.2f", $total / $numelements);

   # Mode is a little harder -- gaaaahhh. I hate it when there's no
   # tidy formula! :)

   # Okay, so we will go through every score in the list. Every time
   # we find one, we will increment the number of times we've found it.
  
   foreach $elem (@scores){

   # For example, in case of a score of 2, $mode{2} gets incremented 
   # every time it finds it. This creates the associative array %mode.

     $mode{$elem}++;
     }

   # Now, %mode contains Score,Frequency,Score,Frequency with the
   # frequency of each score. $mode{Score} = Frequency of that Score
   # values of %mode are the frequencies
   # keys of %mode are the scores

   # okay, so we'll sort the keys (scores) so we can give a list of
   # scores and frequencies of those scores.

   @scorekeys = reverse(sort(keys(%mode)));
   $totalscores = $#scorekeys + 1;

   # And print a frequency table.
   $scorefreqtable = "<table border=1 cellpadding=5 cellspacing=0>
	  <tr><th colspan=2>Frequency of Scores</th></tr>
	  <tr><th>Score</th><th>Number of Students</th></tr>";
   foreach $key (@scorekeys){
    $sc = $key * 1;
    $scorefreqtable .= "<tr><th>$sc%</th><th>$mode{$key}</th></tr>";
    }
    $scorefreqtable .= "</table>";

   @fscores = keys(%mode);
   @freq = values(%mode);
   for($i = 0; $i <= $#freq; $i++){
      $newsort[$i] = sprintf("%.5d", $freq[$i])."-$fscores[$i]";
      }
   # Okay, now we have frequency-score in a sorted array
   @sort = sort(@newsort);
   for($i = 0; $i <= $#sort; $i++){
     $sort[$i] = (split(/-/, $sort[$i]))[0];
    }
   @newsort = sort(@newsort);
   
   # There is no mode if there are three of the same
   # if the last, next to last, and nextto next to last are the same
   if(($sort[$#sort] == $sort[$#sort - 1] &&
      $sort[$#sort] == $sort[$#sort - 2]) &&
      $#sort > 1){
      $mode = "(No conventional mode. See Frequency Table.)";
      }
    elsif($#sort == 0){
       ($num1,$mode1) = split(/-/, $newsort[$#newsort]);
	$num1 = $num1 * 1; 
	$mode1 = $mode1 * 1;
	$mode = "$mode1% ($num1)";
        }
    elsif($sort[$#sort] == $sort[$#sort - 1]){
       ($num1,$mode1) = split(/-/, $newsort[$#newsort]);
       ($num2,$mode2) = split(/-/, $newsort[$#newsort - 1]);
	$num1 = $num1 * 1; $num2 = $num2 * 1;
	$mode1 = $mode1 * 1; $mode2 = $mode2 * 1;
	$mode = "$mode1% ($num1), $mode2% ($num2)";

       }
     else {
       ($num1,$mode1) = split(/-/, $newsort[$#newsort]);
	$num1 = $num1 * 1; 
	$mode1 = $mode1 * 1;
	$mode = "$mode1% ($num1)";
	}
	
   open(DR, "<$basedir/$quizdir/results.data-detailed") ||
     &debug("Could not read detailed results file: $!");
   if($opsys ne "unix"){ binmode(DR); }
    @lines = <DR>;
   close(DR);
    
    # Now, let's get the average time for this quiz, if there is
    # a time limit.
    
    if(-f "$basedir/$quizdir/timing"){
      open(TF, "<$basedir/$quizdir/timing") || 
	&debug("Could not open quiz timing file: $!");
	while(<TF>){
	   ($stu,$start,$stop) = split(/\|/);
	    if($start ne "" && $stop ne ""){
	       $time += ($stop - $start);
               $qt++;
	       }
	   }
	$avg_time = $time / $qt;
	$avg_time = sprintf("%.2f", $avg_time / 60);
	$avg_time = "Average time spent on this quiz: $avg_time minutes.
		    <br><br>";
      close(TF);
      }

    print "$header<br>
	   <center>
	   [ <a href=#dqas>Detailed Question/Answer Statistics</a> ]
	   [ <a href=#sft>Score Frequency Table</a> ]
	   [ <a href=#drbs>Detailed Results by Student</a> ]
	   </center><br><br>
	   <b>Note: Statistical results may be approximate, and may be
	   rounded up (or down, as the case may be) to the nearest whole
	   number.  In Detailed Question/Answer Statistics, percentages 
	   which do not add up to 100% may be due to students skipping
	   questions, questions which were added or modified after a quiz 
	   or test was already in progress, or answers/distractors which
	   were added or modified after a quiz was already in progress. The
	   Question/Answer statistics reflect the current state of a
	   particular quiz, and thus may not be exact for quizzes which
	   have been modified after someone has taken them.  
	   <br><br>$avg_time
	   <b>Students taking the quiz:
           $studentstakingquiz\n<table border=1 cellpadding=10>
	   <tr><th colspan=5>Overall Score Statistics:</th></tr>
	   <tr><th>Mean </th> <th>Median</th> <th>Mode</th>
	   <th>Lowest</th><th>Highest</th></tr>
	   <tr><th>$mean%</th>
	   <th>$median%</th>
	   <th>$mode</th>
	   <th>$lowest%</th>
	   <th>$highest%</th>
	   </tr></table><hr>
	   <b><a name=sft>Score Frequency Table</a></b><br>
	   $scorefreqtable<hr>
	   <b><a name=dqas>Detailed Question/Answer Statistics:</a></b><br>";
   unless(-f "$basedir/$quizdir/results.data-detailed" &&
	  -f "$basedir/$quizdir/answerfile"){
      print "<b>Detailed results not available for \"$data{'QuizName'}\".
	     </b>
	     $footer";
      exit();
      }
   open(AF, "<$basedir/$quizdir/answerfile") ||
    &debug("Could not open answer file $basedir/$quizdir/answerfile: $!");
   if($opsys ne "unix"){ binmode(AF); }
    @aflines = grep(/^\d+/, <AF>);
   close(AF);
   # Get the distractors for each question
   open(QDB, "<$basedir/$quizdir/quizdb") ||
    &debug("Could not open quizdb $basedir/$quizdir/quizdb: $!");
   if($opsys ne "unix"){ binmode(QDB); }

    $quizline = <QDB>;
   close(QDB);
   ($qt,$instr,$fn,$em,$id,@qs) = split(/\|/, $quizline);
    $i = 0;
    foreach $q (@qs){
     ($question,$distractors) = split(/ # /, $q);
     $questions[$i] = $question;
     $distractors[$i] = $distractors;
     $i++;
     }
   $html = "<tr><th>QUIZ:</th>";
   $i = 0;
   $html2 = "<form method=POST action=$cgi_url#drbs>
             <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
		 <input type=hidden name=admlogin value=\"$data{'admlogin'}\">
		 <input type=hidden name=admpass value=\"$data{'admpass'}\">
		 <input type=hidden name=FA value=\"Get Statistics\">
		 <input type=hidden name=QuizName value=\"$data{'QuizName'}\">
		 <input type=hidden name=SortBy value=\"$i\">
		 <th><input type=submit value=\"Sort Field\"></th></form>\n";
   foreach $line (@aflines){
      chomp($line);
     ($num,$correct) = split(/\|/, $line);
      $html .= "<th>$correct</th>\n";
      @corrans[$i] = $correct;
      $i++;
      $html2 .= "<form method=POST action=$cgi_url#drbs>
                 <input type=hidden name=remote_debug value=\"$data{'remote_debug'}\">
		 <input type=hidden name=admlogin value=\"$data{'admlogin'}\">
		 <input type=hidden name=admpass value=\"$data{'admpass'}\">
		 <input type=hidden name=FA value=\"Get Statistics\">
		 <input type=hidden name=QuizName value=\"$data{'QuizName'}\">
		 <input type=hidden name=SortBy value=\"$i\">
		 <th><input type=submit value=\"Sort Field\"></th></form>\n";
      }
   $html .= "</tr>";
   $html = "$html2</tr>$html";
   $sortby = $data{'SortBy'};
   @lines = sort {
      (split(/\|/, $a))[$sortby] cmp (split(/\|/, $b))[$sortby];
       } @lines;
   foreach $line (@lines){
      $students++;
      ($student,@ans) = split(/\|/, $line);
       
      $html .= "<tr>
		 <td>$student</td>\n";
      $i = 0;
      foreach $ans (@ans){
	 $q = "q-$i";
	 $$q .= "$ans|";
         $html .= "<td>$ans</td>\n";
	 $i++;
	 }
       $html .= "</tr>\n";
      }
    # Now $q-0 has all the answers for the first question,
    # $q-1 has them for the second, etc. So...let's grab 'em.
    print "<table border=1 cellpadding=5>";
    for ($j = 0; $j < $i; $j++){
       # get question
       $q = "q-$j";
       $q = $$q;
       $answernum = 1;
       foreach $dist (split(/ %%/, $distractors[$j])){
          $pdist .= "$answernum. $dist ";
	  $answernum++;
	  }
       $pdist = &repipe($pdist);
       $testcor = &repipe($corrans[$j]);
       $testcor =~ s/%SAQ%/Short Answer Question:/;
       $testcor =~ s/%SAT%/Short Answer Question:/;
       $testcor = &unpipe($testcor);
       $isshortanswer = $pdist;
       $pdist =~ s/%SAQ%//g;
       $pdist =~ s/%SAT%//g;
       print "<tr><th colspan=4>Question: $questions[$j]<br>
	       Answers: $pdist</th></tr>
	      <tr><th>Type</th><th>Answer</th><th>Responses</th><th>Percent</th>
	      </tr>
	      <tr><td>Correct:</td><td>$testcor</td>";
	 if($isshortanswer =~ /%SAQ%/ || $isshortanswer =~ /%SAT%/){
	    $count = "N/A";
	    $percent = "N/A";
	    print "<td>$count</td><td>$percent%</td></tr>";
	    $pdist = "";
	    next;
	    }
	 $pdist = "";
         $count = 0;
          @q = split(/\|/, $q);
          foreach $t (@q){
	     $t =~ s/^\s+//g; $t =~ s/\s+$//g;
	     $corrans[$j]=~ s/^\s+//g; $corrans[$j] =~ s/\s+$//g;
	     if($t eq $corrans[$j]){
	        $count++;
	     }
          $percent = int((($count / $students) * 100) + 0.5);
          }
	    print "<td>$count</td><td>$percent%</td></tr>";
       
       foreach $distractor (split(/ %%/, $distractors[$j])){

	 $distractor =~ s/^\s+//;
	 $distractor =~ s/\s+$//;
	 if($distractor eq $corrans[$j]){next;}
         $count = 0;
	 print "<tr><td>Distractor:</td><td>$distractor</td>";
         @q = split(/\|/, $q);
         foreach $t (@q){
	    $t =~ s/^\s+//g; $t =~ s/\s+$//g;
	    $distractor =~ s/^\s+//g; $distractor =~ s/\s+$//g;
	    if($t eq $distractor){

	       $count++;
	       }
            }
         $percent = int((($count / $students) * 100) + 0.5);
	 print "<td>$count</td><td>$percent%</td></tr>";
	} 
    }
    print "</table><hr>";
    print "<b><a name=drbs>Detailed Results by Student</a></b><br><br>
	   <table border=1 cellpadding=5>$html</table>$footer";
    exit();
 }
 print "$header
	$admformtop
	Select a quiz to analyze:
	<select name=QuizName>
	$html
	</select>
	<input type=submit name=FA value=\"Get Statistics\">
	</form>
	$footer";
  exit();


}
sub get_students_as_options {

 my($students);
 if(-f "$authorized_users_file"){
   open(AU, "<$authorized_users_file") || 
    &debug("could not read authorized users file: $!");
   if($opsys ne "unix"){ binmode(AU); }
    while(<AU>){
      ($studentid,$pw,$name,$squizzes) = split(/\|/, $_);
      $students .= "<option value=\"$studentid\">$name ($studentid)</option>\n"
      if $studentid ne "";
      }
   close(AU);
  }
 else {

  $students .= "<option>ERROR: No Students Found</option>\n";

  }
  $students;

}

sub get_students_as_checkboxes {
 my($editq) = $_[0];
 my($students);
 if(-f "$authorized_users_file"){
   open(AU, "<$authorized_users_file") ||
    &debug("could not read authorized users file: $!");
   if($opsys ne "unix"){ binmode(AU); }
    while(<AU>){
      ($studentid,$pw,$name,$squizzes) = split(/\|/, $_);
      if($editq ne "" && $squizzes =~ /$editq/){
	 $ck = " CHECKED";
	 }
      else{
	 $ck = "";
	 }
      $students .= "<input name=Student type=checkbox value=\"$studentid\"$ck>
		    $name ($studentid)<br>\n" if $studentid ne "";
      }
   close(AU);
  }
 else {

  $students .= "ERROR: No students found.\n";

  }
  $students;

}

sub get_instructors_as_options {

 my($instructors);
 if(-f "$instructors_file"){
   open(AU, "<$instructors_file") ||
    &debug("2801: Could not read instructors file: $!");
   if($opsys ne "unix"){ binmode(AU); }
    while(<AU>){
      chomp($_);
      ($instructor,$pw,$name,$quizzes) = split(/\|/, $_);
      $instructors .= "<option value=\"$instructor\">$name ($instructor)</option>\n" unless $instructor eq "";
      }
   close(AU);
  }
 if($instructors eq ""){

  $instructors .= "<option>ERROR: No Instructors Found</option>\n";

  }
  $instructors;

}
sub delete_student {

$students = &get_students_as_options;
if($data{'FA2'} eq "Delete"){
  # Print the delete confirm form for that student...
  if($data{'ID'} eq "" || $data{'ID'} =~ /ERROR: No Students Found/){
    print "$header <b>Error: no students found.</b> $footer";
    exit();
    }
  print "$header
	  <b>WARNING!</b> You are about to delete student \"$data{'ID'}\".
	  This is the final confirmation. Are you sure you want to 
	  delete this student?
	   $admformtop
	   <input type=hidden name=FA2 value=\"Really Delete\">
	   <input type=hidden name=ID value=\"$data{'ID'}\">
	   <input type=hidden name=FA value=\"Delete Student\">
	   <input type=submit value=\"Yes, delete $data{'ID'}\">
           </form>$footer";
  }
elsif($data{'FA2'} eq "Really Delete"){
  # Do the delete
  open(AU, "+<$authorized_users_file") || 
   &debug("Could not open $authorized_users_file (authorized users file): $!"); 
     
     if($opsys eq "unix"){ flock(AU, 2); }
     else { binmode(AU); }
     
  @lines = <AU>;
  foreach $line (@lines){
    if($line !~ /^$data{'ID'}\|/){
       $newfile .= $line;
       }
    # If it's this student but not the instructor who added him/her, and
    # if it's not admin, refuse to delete it.
    elsif($line =~ /^$data{'ID'}\|/ && $line !~ /$data{'admlogin'}$/ &&
          $data{'admlogin'} ne $overall_admin){
       $newfile .= $line;
       $delmsg = "Sorry, only the instructor who added this student or the
                  overall administrator $overall_admin may delete a student. 
                  If you added
                  this student, and are getting this message, it probably
                  means you added the student before this safety check was
                  written into this software. Please ask the administrator
                  to delete the student for you.";
        }
     }
   truncate(AU, length($newfile));
   seek(AU,0,0);
   print AU $newfile;
   close(AU);
   # Get rid of file if no more students.
   if(length($newfile) == 0){ unlink($authorized_users_file); }
   $data{'FA2'} = "";
   if($delmsg){$message = "<b>$delmsg</b><br><br>";}
   elsif($!){ $message = "<b>Possible error: The system said $!. Student may
              not have been deleted.</b><br><br>";
        }
   else {
      $message = "<b>Student \"$data{'ID'}\" successfully deleted. 
	       Delete another student:</b><br><br>";
      }
   &delete_student;
   exit();
 }
else {
print "$header
       $message
       $admformtop
       <select name=ID>$students</select>
       <input type=hidden name=FA2 value=\"Delete\">
       <input type=submit name=FA value=\"Delete Student\">
       </form>
       $footer";

 }
exit();
}


sub edit_student {

$students = &get_students_as_options;
if($data{'FA2'} eq "Edit"){
  # Print the edit form for that student...
  if($data{'OldID'} ne ""){ $oldid = $data{'OldID'}; }
  else { $oldid = $data{'ID'}; }
  if($oldid eq "" || $oldid =~ /ERROR: No Students Found/){
    print "$header <b>Error: no students found.</b> $footer";
    exit();
    }
  open(INS, "<$authorized_users_file") ||
   &debug("Could not open $authorized_users_file for reading: $!");
  if($opsys ne "unix"){
     binmode(INS);
     }
  if($data{'Name'} eq ""){
      ($id,$s_pw,$name,$s_quizzes,$s_ins) = split(/\|/,(grep(/^$oldid\|/, <INS>))[0]); 
     $data{'Name'} = &repipe($name);
     }
  else {
      ($id,$s_pw,$name,$s_quizzes,$s_ins) = split(/\|/,(grep(/^$oldid\|/, <INS>))[0]); 
      }
  if($s_ins eq ""){$s_ins = $overall_admin; }
  close(INS);
  chomp($s_quizzes);
  $quizopts = &find_quizzes("checkbox");
  @quizopts = split(/\n/, $quizopts);
  @s_quizzes = split(/\%/, $s_quizzes);
  $html = "";

      
  foreach $q (@quizopts){
     foreach $s (@s_quizzes){
        if($q =~ /<input type=checkbox name=QuizName value=\"$s\">/){
           $qscomp = "<input type=checkbox name=QuizName value=\"$s\" CHECKED>$s <br>\n";
	   last;

	   }
	else {
           $qscomp = "$q\n";
	   }

	}
      $html .= $qscomp;

     }
  if($html eq ""){$html = $quizopts;}
  if($data{'SPassword'} eq ""){$data{'SPassword'} = &repipe($s_pw);}
  if($data{'SPassword2'} eq ""){$data{'SPassword2'} = &repipe($s_pw);}
  print "$header
	 $admformtop
	 <table border=1>
	 <tr><th>Student Info</th><th>Quiz(zes) for this Student)</th></tr>
	 <tr><td valign=top>
	   <font color=#FF0000>$error</font><br>
	   <table border=0>
	   <tr><th align=left>
	   Student Name:
	   </th><th>
	   <input type=text name=Name value=\"$data{'Name'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student ID/Email:
	   </th><th>
	   <input type=text name=ID value=\"$data{'ID'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student Password:
	   </th><th>
	   <input type=password name=SPassword value=\"$data{'SPassword'}\">
	   </th></tr>
	   <tr><th align=left>
	   Student Password again:
	   </th><th>
	   <input type=password name=SPassword2 value=\"$data{'SPassword2'}\">
	   </th></tr>
	   </table>
	   <input type=hidden name=FA2 value=\"Really Edit\">
	   <input type=hidden name=OldID value=\"$oldid\">
	   <input type=submit name=FA value=\"Edit Student\">
	   </td><td valign=top><br>$html</td></tr></form></table>
	   $footer";
  }
elsif($data{'FA2'} eq "Really Edit"){
  # Do the edit
  if(($data{'SPassword'} ne $data{'SPassword2'}) ||
      $data{'SPassword'} eq "" || $data{'SPassword2'} eq ""){
      $error = "Error: Passwords do not match or are blank.";
      $data{'FA2'} = "Edit";
      &edit_student;
      }
  $data{'ID'} = &unpipe($data{'ID'});
  $data{'Name'} = &unpipe($data{'Name'});
  $data{'SPassword'} = &unpipe($data{'SPassword'});
  
  # First, get quizzes associated with this instructor, so we don't
  # take them away from a previous instructor. Only the instructor who
  # "owns" the quiz can add it or take it away. Otherwise, everything
  # in the student's list should stay exactly the same. Unless of
  # course, this is admin. In which case, we do whatever they want. :-)

  open(INS, "<$instructors_file") ||
    &debug("3981: Could not read instructors file: $!");
    if($opsys ne "unix"){binmode(INS);}
    @otherins = <INS>;
  close(INS);
 
 # Now, we saved the student's old login (in case the instructor
 # modified it) in OldID.  So let's get the quizzes from that as well
 # so that we have a list of all quizzes the student was allowed to 
 # take.
  open(AU, "<$authorized_users_file") ||
    &debug("Could not read authorized users file: $!");
    if($opsys ne "unix"){binmode(AU);}
    ($oid,$opw,$oname,$oquizzes,$o_sins) = 
       split(/\|/, (grep(/^$data{'OldID'}\|/, <AU>))[0]);
    if($o_ins eq ""){$o_ins = $overall_admin; }
  close(AU);
  $oquizzes =~ s/%%/%/g; 
  @oquizzes = split(/\%/, $oquizzes);

  # Go through each instructor line unless this is our admin person...
  if($data{'admlogin'} ne $quizresultsemail){
  foreach $ins (@otherins){
     chomp($ins);
     ($oin,$oipw,$oina,$oiqs) = split(/\|/, $ins);
      # If this is a different instructor, than the one who is
      # currently doing the edit...
      if($oin ne $data{'admlogin'}){
         
         # We need to check and see if other instructors had authorized
         # this student to take their quiz(zes) so we need to
         # go through each of the student's previous quizzes. If one of
         # them belongs to a different instructor, pre-add it to their
         # list of quizzes so they don't get removed from the file.
        
         foreach $oq (@oquizzes){
            chomp($oq);
            if($oq ne "" && 
               ($oiqs =~ /\b$oq\b/)){
                $quizzes .= "%$oq";
                }
            }
         }

     }
  } 
  # Now we'll add the old quizzes and the new ones to the
  # authorized users file.
  open(AU, "+<$authorized_users_file") ||
   &debug("Could not open $authorized_users_file (authorized users): $!"); 
     
     if($opsys eq "unix"){ flock(AU, 2); }
     else { binmode(AU); }
     
  @lines = <AU>;
  foreach $line (@lines){

  
    if($line =~ /^$data{'OldID'}\|/){
       @s_quizzes = split(/\0/, $data{'QuizName'});
       foreach $s (@s_quizzes){ $quizzes .= "%$s"; }
       $quizzes =~ s/%$//;
       $quizzes =~ s/%%/%/g;
       # Just to make sure we didn't duplicate a quiz. This needs
       # to be rewritten and done better eventually.
       @quizzes = sort(split(/%/, $quizzes));
       $quizzes = "";
       foreach $sortquiz (@quizzes){
          chomp($sortquiz);         
          if($sortquiz ne $lastquiz && $sortquiz ne ""){
              $quizzes .= "$sortquiz%";
              }
           $lastquiz = $sortquiz;
          }
       $quizzes =~ s/%$//;
       # The instructor that does not own this student can add/subtract quizzes
       # but cannot change the username or password.
       if($data{admlogin} ne $o_sins && $data{admlogin} ne $overall_admin){
          $newfile .= "$oid|$opw|$oname|$quizzes|$o_sins";
          $edmsg = "<b>NOTE:</b>
                    Student ID, password, and name can only be changed by
                    the instructor who added the student, or by the overall
                    admin, $overall_admin . If you are getting this message
                    and you did add this student, it's probably because you
                    added the student before the software added this safety
                    feature. Please ask the administrator to associate you
                    with this student as his/her instructor, or to make the
                    changes for you.</b>";
          }
       else {
       $newfile .= "$data{'ID'}|$data{'SPassword'}|$data{'Name'}|$quizzes|$o_sins";
         }
       }
    else {
       $newfile .= $line;
       }
     }
   truncate(AU, length($newfile));
   seek(AU,0,0);
   print AU $newfile;
   close(AU);
   $data{'FA2'} = "";
   if($edmsg){ $message = "$edmsg<br><br>"; }
   else {$message = "<b>Student Successfully updated. Edit another student:</b>
	       <br><br>";
        }
   &edit_student;
   exit();

 }
else {
print "$header
       $message
       $admformtop
       <select name=ID>$students</select>
       <input type=hidden name=FA2 value=\"Edit\">
       <input type=submit name=FA value=\"Edit Student\">
       </form>
       $footer";

 }
exit();
}

sub add_instructor {

 if($data{'FA2'} ne "Add"){
    print "$header
	   $message
	   $admformtop
	   <font color=#FF0000>$error</font><br>
	   <table border=0>
	   <tr><th align=left>
	   Instructor Name:
	   </th><th>
	   <input type=text name=Name value=\"$data{'Name'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor ID/Email:
	   </th><th>
	   <input type=text name=ID value=\"$data{'ID'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor Password:
	   </th><th>
	   <input type=password name=Password value=\"$data{'Password'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor Password again:
	   </th><th>
	   <input type=password name=Password2 value=\"$data{'Password2'}\">
	   </th></tr>
	   </table>
	   <input type=hidden name=FA2 value=\"Add\">
	   <input type=submit name=FA value=\"Add Instructor\">
           </form>
	   $footer";
	   exit();
    }
     if($data{'Password'} eq "" ||
       $data{'Password2'} eq "" ||
       $data{'ID'} eq ""){
	$error = "Error: All fields must be filled in.";
	$data{'FA2'} = "";
	&add_instructor;
	}
     $data{'ID'} = &unpipe($data{'ID'});
     $data{'Name'} = &unpipe($data{'Name'});
     $data{'Password'} = &unpipe($data{'Password'});
     open(FILE, "<$instructors_file") || 
      &debug("4131: Could not read instructors file $instructors_file: $!");
     if($opsys ne "unix"){
	binmode(FILE);
	}
     ($instructor,$pw,$name,$quizzes) = split(/\|/, (grep(/^$data{'ID'}\|/, <FILE>))[0]);
     if($instructor eq $data{'ID'}){
	$error = "Error: Instructor $data{'ID'} exists.";
	$data{'FA2'} = "";
	&add_instructor;
	}
     if($data{'Password'} ne $data{'Password2'}){
	$error = "Error: Passwords do not match.";
	$data{'FA2'} = "";
	&add_instructor;
	}
   open(FILE, ">>$instructors_file") ||
    &debug("Could not open $instructors_file (instructors file): $!");
     
     if($opsys eq "unix"){ flock(FILE, 2); }
     else { binmode(FILE); }
     
   seek(FILE, 0, 2);
   print FILE "$data{'ID'}|$data{'Password'}|$data{'Name'}|\n";
   close(FILE);
   $message = "<b>Instructor $data{'Name'} ($data{'ID'}) added.
	       Add another instructor:</b><br><br>";
   $data{'FA2'} = ""; $data{'ID'} = ""; $data{'Password'} = "";
   $data{'Password2'} = "";$data{'Name'} = "";
   &add_instructor;
   exit();

}

sub delete_instructor {

  if($data{'Name'} eq ""){
     open(INS, "<$instructors_file") || 
      &debug("4168: Could not read instructors file $instructors_file: $!");
     if($opsys ne "unix"){
	binmode(INS);
	}
      $name = (split(/\|/,(grep(/^$data{'ID'}\|/, <INS>))[0]))[2]; 
     close(INS);
     $data{'Name'} = $name;
     }
$instructors = &get_instructors_as_options;
if($data{'FA2'} eq "Delete"){
  # Print the delete confirm form for that student...
  if($data{'ID'} eq "ERROR: No Instructors Found"){
    print "$header
	   <b>Error: No instructors found</b>
	   $footer";
    exit();
    }

  print "$header
	  <b>WARNING!</b> You are about to delete instructors $data{'Name'}
	  (\"$data{'ID'}\").
	  This is the final confirmation. Are you sure you want to 
	  delete this instructor?
	   $admformtop
	   <input type=hidden name=FA2 value=\"Really Delete\">
	   <input type=hidden name=ID value=\"$data{'ID'}\">
	   <input type=hidden name=Name value=\"$data{'Name'}\">
	   <input type=hidden name=FA value=\"Delete Instructor\">
	   <input type=submit value=\"Yes, delete $data{'Name'}\">
           </form>$footer";
  }
elsif($data{'FA2'} eq "Really Delete"){
  # Do the delete
  open(AU, "+<$instructors_file") || 
   &debug("Could not open instructors file $instructors_file: $!");
     
     if($opsys eq "unix"){ flock(AU, 2); }
     else { binmode(AU); }
     
  @lines = <AU>;
  foreach $line (@lines){
    if($line !~ /^$data{'ID'}\|/){
       $newfile .= $line;
       }
     }
   truncate(AU, length($newfile));
   seek(AU,0,0);
   print AU $newfile;
   close(AU);
   # Be tidy and get rid of the file if there are no more instructors.
   if(length($newfile) == 0){ unlink($instructors_file); }
   $data{'FA2'} = "";
   $message = "<b>Instructor $data{'Name'} (\"$data{'ID'}\") successfully 
	       deleted. Delete another instructor:</b><br><br>";
   &delete_instructor;
   exit();

 }
else {
print "$header
       $message
       $admformtop
       <select name=ID>$instructors</select>
       <input type=hidden name=FA2 value=\"Delete\">
       <input type=submit name=FA value=\"Delete Instructor\">
       </form>
       $footer";

 }
exit();

}

sub edit_instructor {

$instructors = &get_instructors_as_options;
if($data{'FA2'} eq "Edit"){
  # Print the edit form for that instructor...
  if($data{'ID'} eq "ERROR: No Instructors Found"){
    print "$header
	   <b>Error: No instructors found</b>
	   $footer";
    exit();
    }
  if($data{'OldID'} ne ""){ $oldid = $data{'OldID'}; }
  else { $oldid = $data{'ID'}; }
  open(INS, "<$instructors_file") ||
   &debug("could not read instructors file $instructors_file: $!");
  if($opsys ne "unix"){
     binmode(INS);
     }
  if($data{'Name'} eq ""){
      ($id,$pw,$name,$quizzes) = split(/\|/,(grep(/^$oldid\|/, <INS>))[0]); 
     $data{'Name'} = &repipe($name);
     }
  else {
      ($id,$pw,$name,$quizzes) = split(/\|/,(grep(/^$oldid\|/, <INS>))[0]); 
      }
  close(INS);
  if($data{'Password'} eq ""){$data{'Password'} = &repipe($pw);}
  if($data{'Password2'} eq ""){$data{'Password2'} = &repipe($pw);}
  print "$header
	 $message
         <br>
         <b>NOTES:<br>
           To assign a student to this instructor, check the box to the left
           of the
           student ID.</b><br>
           Students with an [X] are already assigned to this
           instructor.
           Students with a <b>*</b> to the right of the student ID are assigned
           to another instructor. Checking their box  will reassign the student 
           away from their current instructor!</b><br>
	   <font color=#FF0000>$error</font><br>
           <table border=1>
	   $admformtop
           <tr><th>Instructor Information</th><th>Student List</th></tr>
           <tr><td valign=top>
	   <table border=0>
	   <tr><th align=left>
	   Instructor Name:
	   </th><th>
	   <input type=text name=Name value=\"$data{'Name'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor ID/Email:
	   </th><th>
	   <input type=text name=ID value=\"$data{'ID'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor Password:
	   </th><th>
	   <input type=password name=Password value=\"$data{'Password'}\">
	   </th></tr>
	   <tr><th align=left>
	   Instructor Password again:
	   </th><th>
	   <input type=password name=Password2 value=\"$data{'Password2'}\">
	   </th></tr>
	   </table>
           </td><td valign=top>";
   # Get the list of all students
   open(F, "<$authorized_users_file") ||
     &debug("Could not open authorized_users_file to find students! $!");
     while(<F>){
       ($oid,$oins) = (split(/\|/, $_))[0,4];
        # If this instructor already has this student, ignore.
        chomp($oins);
        if($oins ne $oldid){
           if($oins ne $overall_admin){ $star = "<b>*</b>"; }
           print "<input type=checkbox name=AssignStudent value=\"$oid\">&nbsp;$oid$star ";
           } 
        else {
           print "[X]$oid ";
           }
        } # end of while(<F>)
   print " </td></tr></table>
	   <input type=hidden name=FA2 value=\"Really Edit\">
	   <input type=hidden name=OldID value=\"$oldid\">
	   <input type=hidden name=FA value=\"Edit Instructor\">
	   <input type=submit value=\"Save Changes\">
           
           </form>$footer";
	   exit();
  }
elsif($data{'FA2'} eq "Really Edit"){
  # Do the edit
  if(($data{'Password'} ne $data{'Password2'}) ||
      $data{'Password'} eq "" || $data{'Password2'} eq ""){
      $error = "Error: Passwords do not match or are blank.";
      $data{'FA2'} = "Edit";
      &edit_instructor;
      }
  $data{'ID'} = &unpipe($data{'ID'});
  $data{'Name'} = &unpipe($data{'Name'});
  $data{'Password'} = &unpipe($data{'Password'});
  open(AU, "+<$instructors_file") ||
   &debug("Could not read/write to instructors file ($instructors_file): $!"); 
     
     if($opsys eq "unix"){ flock(AU, 2); }
     else { binmode(AU); }
     
  @lines = <AU>;
  foreach $line (@lines){
    
    if($line =~ /^$data{'OldID'}\|/){
       ($oldid,$oldpw,$oldname,$quizzes) = split(/\|/, $line); 
       $quizzes =~ s/%%/%/g; @quizzes = sort(split(/%/, $quizzes));
       $quizzes = "";
       foreach $oldquiz (@quizzes){
          chomp($oldquiz);
          if($lastquiz ne $oldquiz){
             $quizzes .= "%$oldquiz";
             }
          $lastquiz = $oldquiz;
          }
       $newfile .= "$data{'ID'}|$data{'Password'}|$data{'Name'}|$quizzes\n";
       }
    else {
       $newfile .= $line;
       }
     }
   truncate(AU, length($newfile));
   seek(AU,0,0);
   print AU $newfile;
   close(AU);
   if($data{'AssignStudent'} =~ /\0/){ 
      @a_stu = split(/\0/, $data{'AssignStudent'}); 
      }
   else {
      @a_stu = ($data{'AssignStudent'});
      }
   # Assign the students to this instructor
   $assignmsg = &assign_students_to_instructor($data{'ID'},@a_stu);
   # 1 is success so we don't need to show it. Anything else is an
   # error.
   if($assignmsg == 1){ $assignmsg = ""; }
   $message = "<b>Instructor $data{'Name'} ($data{'ID'}) updated. $assignmsg
	       Edit another instructor:</b><br><br>";
   $data{'FA2'} = ""; $data{'ID'} = ""; $data{'Password'} = "";
   $data{'Password2'} = "";$data{'Name'} = "";
   &edit_instructor;
   exit();

 }
else {
print "$header
       $message
       $admformtop
       <select name=ID>$instructors</select>
       <input type=hidden name=FA2 value=\"Edit\">
       <input type=submit name=FA value=\"Edit Instructor\">
       </form>
       $footer";

 }
exit();


}
sub reset_quiz {

if($data{'FA2'} eq "Reset"){
  if($data{'QuizName'} =~ /NO QUIZZES FOUND/ || $data{'QuizName'} eq ""){
    print "$header <b>Error: No quizzes found.</b> $footer";
    exit();
    }

  # Confirm
  print "$header
	 $admformtop
	 <b>Please confirm that you wish to delete the results
	 databases for this quiz ($data{'QuizName'}) and start over.  
	 This will also remove this quiz from any students who are
	 currently allowed to take it.
	 You may wish to run \"Get Statistics\",
	 and print that page first, so that you may have a record
	 of this quiz's results.</b><br>
	 <input type=hidden name=FA2 value=\"Really Reset\">
	 <input type=hidden name=QuizName value=\"$data{'QuizName'}\">
	 <input type=submit name=FA value=\"Reset Quiz\">
	 <input type=submit name=FA value=\"Get Statistics\">
	 <input type=submit name=FA value=\"View Quiz\">
	 </form>
	 $footer";
  exit();
  }
elsif($data{'FA2'} eq "Really Reset"){

  # Truncate results.data and results.data-detailed
  $quizdir = $data{'QuizName'};
  $quizdir =~ s/\W+//g; $quizdir =~ tr/[A-Z]/[a-z]/;
  if(-d "$basedir/$quizdir"){
    open(RD, ">$basedir/$quizdir/results.data") ||
     &debug("Could not reset results file $basedir/$quizdir/results.data: $!");
     print RD "";
    close(RD);
    }
  if(-d "$basedir/$quizdir"){
    open(RD, ">$basedir/$quizdir/results.data-detailed") ||
     &debug("Could not reset detailed
     results file $basedir/$quizdir/results.data-detailed: $!");
     print RD "";
    close(RD);
    }
  &remove_quiz_from_users("$data{'QuizName'}");
  print "$header
	 <b>Results Reset for quiz $data{'QuizName'}</b>
	 $footer";
  exit();
  }
else {
   # Get quizzes.
   $html = &find_quizzes("option");
   print "$header
	  <b>Please choose a quiz to reset. This will remove all the
	  results for this quiz, so that you can start over with a new
	  class or group of students.</b>
	  $admformtop
	  <select name=QuizName>
	  $html
	  </select>
	  <input type=hidden name=FA2 value=\"Reset\">
	  <input type=hidden name=FA value=\"Reset Quiz\">
	  <input type=submit value=\"Select Quiz\">
	  </form>
	  $footer";
   exit();
   }

}

sub remove_quiz_from_users {

 my ($line,@lines,$sid,$spw,$sname,$quizzes,$squiz,$squizzes,@quizzes,$newfile);
 my ($quiz_to_find) = $_[0];
  open(AU, "+<$authorized_users_file") ||
   &debug("Could not open authorized users file ($authorized_users_file): $!");
     
     if($opsys eq "unix"){ flock(AU, 2); }
     else { binmode(AU); }
     
   @lines = <AU>;
   foreach $line (@lines){
      chomp($line);
      if($line =~ /$quiz_to_find/){
         ($sid,$spw,$sname,$quizzes,$sins) = split(/\|/, $line);
         if($sins eq ""){$sins = $overall_admin; }
	 @quizzes = split(/%/, $quizzes);
	 foreach $squiz (@quizzes){
            if($squiz ne $quiz_to_find){ 
	       $squizzes .= "$squiz%";
               }
	    }
	 $squizzes =~ s/%$//;
	 $squizzes =~ s/%%/%/g;
         @squizzes = sort(split(/%/, $squizzes));
         $squizzes = "";
         foreach $squiz (@squizzes){
             if($lastquiz ne $squiz){
                $squizzes .= "%$squiz";
                }
             $lastquiz = $squiz;
             }
	 $newfile .= "$sid|$spw|$sname|$squizzes|$sins\n";

	 }
       else {
         $newfile .= "$line\n";
	  }
      }
 truncate(AU, length($newfile));
 seek(AU,0,0);
 print AU $newfile;
 close(AU);
}

sub view_quiz {

 if($data{'QuizName'} eq ""){

   $html = &find_quizzes("option");
   print "$header
	  $admformtop
	  <b>Please choose a quiz to view:</b>
	  <select name=QuizName>
	  $html
	  </select>
	  <input type=submit name=FA value=\"View Quiz\">
	  </form>
	  $footer";
   exit();
   }
 $data{'FA2'} = "Show";
 &show_quiz;
}

sub validate_quiz {

 my $i;
# kph
 for($i = 0; $i <= $#afl; $i++){
     #@afl 
     # We make them allow incomplete quizzes if $time_quiz is on.
     if($data{$i + 1} eq "" && ($auto_submit_timed_quiz eq "no" || $time_quiz eq "no")){
        $error = "<b>Error! Incomplete Quiz</b><br><br>";
        $ENV{'QUERY_STRING'} = $quizdir;
	if($data{'autosub'} eq "Yes"){
           print "Sorry, you have exceeded the time limit for this quiz.";
	   print "$footer";
	   exit();
	   }
        &show_quiz("refresh");
	exit();
         }
     }
}

# &score_short_answer(Answerentered,CorrectAnswer);
# Returns 1 on success, undef otherwise.
sub score_short_answer {

 &debug("<b>Detected short answer question. 
 Attempting to figure it out...</b>");
 my @punc_chars = ('~','`','!','@','#','$','%','^','&','*','(',
	          ')','-','_','=','+','[','{','\\',']','}','|',';',':',
	          "'",'"','<','.','>','/','?');

 my($entered,$correct) = @_;
 my(@checkcor,$checkcor,$iscor);
 if($sa_alternates eq "yes"){
    # check for alternates
    @checkcor = split(/\/\//, $correct);
    }
 else {
    $checkcor[0] = $correct;
    }
 # Now we have @checkcor array of possible answers.
 foreach $checkcor (@checkcor){
   if($sa_markallcorrect =~ /^yes$/i){
      $iscor = 1;
      last;
      }
   if($sa_ignorecase eq "yes"){
      $entered =~ tr/[A-Z]/[a-z]/;
      $checkcor =~ tr/[A-Z]/[a-z]/;
      &debug("Ignoring case. Checking '$entered' against '$checkcor'");
      }
   if($sa_ignorepunctuation eq "yes"){
      foreach $char (@punc_chars){
	$entered =~ s/\Q$char\E//g; $checkcor =~ s/\Q$char\E//g;
	}
      &debug("Ignoring punctuation. Checking '$entered' against '$checkcor'");
      }
   if($sa_ignorespaces eq "yes"){
      $entered =~ s/\s+//g;
      $checkcor =~ s/\s+//g;
      &debug("Ignoring spaces. Checking '$entered' against '$checkcor'");
      }
   if($sa_ignorenonwords eq "yes"){
      foreach $char (@punc_chars){
	$entered =~ s/\Q$char\E//g; $checkcor =~ s/\Q$char\E//g;
	}
      $entered =~ s/\s+//g;
      $checkcor =~ s/\s+//g;
      &debug("Ignoring non-word characters. 
      Checking '$entered' against '$checkcor'");
      }
   if($sa_containsanswer eq "yes"){
      &debug("Checking to see if '$entered' is contained within '$checkcor'");
      if($checkcor =~ /$entered/){
	 $iscor = 1;
	 last;
	 }
      }
   if($entered eq $checkcor){
      $iscor = 1;
      last;
      }
   } 
   $iscor;
}

# &get_quiz_config("quiz config file");
sub get_quiz_config {

 my($quiz) = $_[0];
 @variables = ('sa_ignorespaces','sa_containsanswer','mail_score_only',
               'remote_debugging','show_other_scores',
               'number_of_scores_to_show', 'overall_quiz_password',
               'debugging','show_grading_scale','sa_alternates',
               'grade_quiz_button_text','sa_ignorecase','mail_me_results',
               'overall_quiz_password_text','sa_ignorenonwords',
               'force_complete_quiz','what_to_show_after_quiz',
               'grading_scale','take_quiz_over','authorized_users',
               'cc_score_to_student','sa_ignorepunctuation',
               'show_quiz_questions','time_quiz','time_limit',
	       'auto_submit_timed_quiz','sa_markallcorrect');

 if(-f "$quiz"){
  undef $/;
  open(QC, "<$quiz") ||
    &debug("Could not open quiz config file $quiz: $!");
  if($opsys ne "unix"){binmode(QC);}
    $bits = <QC>;
  close(QC);
  # Reset all these variables to no value.
  foreach $var (@variables){ $$var = "" unless $var eq "show_quiz_questions";}
  $/ = "\n";
  $bits = &repipe($bits);
  $bits = &perl_unescape($bits); 
  @bits = split(/;/, $bits);
  foreach $config_string (@bits){
  $config_string =~ s/^\s+//;
  if($config_string =~ /grading_scale =/ && $config_string !~ /show_grading_scale/){
     $grading_scale = $config_string;
     $grading_scale =~ s/grading_scale =//;
     $grading_scale =~ s/^\$//g;
     $grading_scale =~ s/;//g;
     $grading_scale =~ s/^\s+//;
     $grading_scale =~ s/\s+$//;
     $grading_scale =~ s/\"$//;
     $grading_scale =~ s/^\"//;
     }
  else {
    $config_string =~ s/\"//g;
    }

  # This enormous pain in the behind is due to trying to figure out
  # what the config values are, since some may be left over from
  # previous versions of QuizTest and some might not.  Egggh.
  
  if($sa_ignorespaces eq "" && $config_string =~ /sa_ignorespaces/){
     if($config_string =~ /sa_ignorespaces = no/){$sa_ignorespaces = "no";}
     else {$sa_ignorespaces = "yes";}
     }
  if($sa_containsanswer eq "" && $config_string =~ /sa_containsanswer/){
     if($config_string =~ /sa_containsanswer = no/){$sa_containsanswer = "no";}
     else {$sa_containsanswer = "yes";}
     }
  if($sa_markallcorrect eq "" && $config_string =~ /sa_markallcorrect/){
    if($config_string =~ /sa_markallcorrect = yes/i){$sa_markallcorrect = "yes";}
    else {$sa_markallcorrect = "no";}
    }
  if($mail_score_only eq "" && $config_string =~ /mail_score_only/){
     if($config_string =~ /mail_score_only = No/){$mail_score_only = "No";}
     else {$mail_score_only = "Yes";}
     }
  if($remote_debugging eq "" && $config_string =~ /remote_debugging/){
     if($config_string =~ /remote_debugging = on/){$remote_debugging = "on";}
     else {$remote_debugging = "off";}
     }
  if($show_quiz_questions eq "" && $config_string =~ /show_quiz_questions/){
     if($config_string =~ /show_quiz_questions = yes/){$show_quiz_questions = "yes";}
     elsif($config_string =~ /show_quiz_questions = no/){$show_quiz_questions = "no";}
     else {$show_quiz_questions = "instructor";}
     }
  if($show_other_scores eq "" && $config_string =~ /show_other_scores/){
     if($config_string =~ /show_other_scores = Yes/){$show_other_scores = "Yes";}
     else {$show_other_scores = "No";}
     }
  if($config_string =~ /number_of_scores_to_show = (\d+)/){
     $number_of_scores_to_show = $1;
     $number_of_scores_to_show =~ s/\D+//g;
     }
  if($overall_quiz_password eq "" && $config_string =~ /overall_quiz_password/ &&
     $config_string !~ /overall_quiz_password_text/){
     if($config_string =~ /overall_quiz_password = yes/){$overall_quiz_password = "yes";}
     else {$overall_quiz_password = "no";}
     }
  if($debugging eq ""){
     if($config_string =~ /debugging = 1/){$debugging = 1;}
     else {$debugging = 0;}
     }
  
  if($show_grading_scale eq "" && $config_string =~ /show_grading_scale/){
     if($config_string =~ /show_grading_scale = Yes/){$show_grading_scale = "Yes";}
     else {$show_grading_scale = "No";}
     }
  if($sa_alternates eq "" && $config_string =~ /sa_alternates/){
     if($config_string =~ /sa_alternates = no/){$sa_alternates = "no";}
     else {$sa_alternates = "yes";}
     }
  if($config_string =~ /grade_quiz_button_text = (.*?)$/){
    $grade_quiz_button_text = $1;
    $grade_quiz_button_text =~ s/\"/&quot/g;
    $grade_quiz_button_text =~ s/</&lt;/g;
    $grade_quiz_button_text =~ s/>/&gt;/g;
    }
  if($sa_ignorecase eq "" && $config_string =~ /sa_ignorecase/){
     if($config_string =~ /sa_ignorecase = yes/){$sa_ignorecase = "yes";}
     else {$sa_ignorecase = "no";}
     }
  if($mail_me_results eq "" && $config_string =~ /mail_me_results/){
     if($config_string =~ /mail_me_results = No/){$mail_me_results = "No";}
     elsif($config_string =~ /mail_me_results = All/){$mail_me_results = "All";}
     else {$mail_me_results = "Yes";}
     }
  if($config_string =~ /overall_quiz_password_text = (.*?)$/){
      #KKK
     $overall_quiz_password_text = $1;
     }
  if($sa_ignorenonwords eq "" && $config_string =~ /sa_ignorenonwords/){
     if($config_string =~ /sa_ignorenonwords = yes/){$sa_ignorenonwords = "yes";}
     else {$sa_ignorenonwords = "no";}
     }
  if($force_complete_quiz eq "" && $config_string =~ /force_complete_quiz/){
     if($config_string =~ /force_complete_quiz = no/){$force_complete_quiz = "no";}
     else {$force_complete_quiz = "yes";}
     }
  if($what_to_show_after_quiz eq "" && $config_string =~ /what_to_show_after_quiz/){
     if($config_string =~ /what_to_show_after_quiz = All/){$what_to_show_after_quiz = "All";}
     elsif($config_string =~ /what_to_show_after_quiz = StatusOnly/){$what_to_show_after_quiz = "StatusOnly";}
     elsif($config_string =~ /what_to_show_after_quiz = None/){$what_to_show_after_quiz = "None";}
     else{ $what_to_show_after_quiz = "ScoreOnly";}
     }
  if($take_quiz_over eq "" && $config_string =~ /take_quiz_over/){
     if($config_string =~ /take_quiz_over = no/){$take_quiz_over = "no";}
     elsif($config_string =~ /take_quiz_over = nomail/){$take_quiz_over = "nomail";}
     else {$take_quiz_over = "yes";}
     }
  if($authorized_users eq "" && $config_string =~ /authorized_users/){
     if($config_string =~ /authorized_users = yes/){$authorized_users = "yes";}
     else {$authorized_users = "no";}
     }
  if($cc_score_to_student eq "" && $config_string =~ /cc_score_to_student/){
     if($config_string =~ /cc_score_to_student = Yes/i){$cc_score_to_student = "Yes";}
     else {$cc_score_to_student = "No";}
     }
  if($time_quiz eq "" && $config_string =~ /time_quiz/){
     if($config_string =~ /time_quiz = yes/i){$time_quiz = "yes";}
     else {$time_quiz = "no";}
     }
  if($auto_submit_timed_quiz eq "" && $config_string =~ /auto_submit_timed_quiz/){
     if($config_string =~ /auto_submit_timed_quiz = yes/i){$auto_submit_timed_quiz = "yes";}
     else {$auto_submit_times_quiz = "no";}
     }
  if($config_string =~ /time_limit = (.*?)$/){
     $time_limit = $1;
     }
  if($sa_ignorepunctuation eq "" && $config_string =~ /sa_ignorepunctuation/){
     if($config_string =~ /sa_ignorepunctuation = yes/){$sa_ignorepunctuation = "yes";}
     else {$sa_ignorepunctuation = "no";}
     }
    
    } 
  }
# This is only here for convenience if I want to troubleshoot the config.
# $debugging = 1;
# foreach $var (@variables){
#  &debug("Configuration: <b>$var</b> $$var<br><br>");
#  }
}

sub quiz_options_form {

my $config_string;
if(-f "$_[0]"){
  &debug("checking $_[0] quiz config for options.");
  &get_quiz_config($_[0]);
  }
else {
  &debug("$_[0] quiz config not found: using default.");
  }
$quizoptform = "$admformtop<table border=0>
         <tr><td colspan=2 bgcolor=#E4D8E2><b>General Configuration Options</b>
	 </td></tr>
	<tr><td><b>Turn on debugging:</b></td>
	    <td><select name=opt_debugging>";
        if($debugging == 1){$ck1 = " SELECTED";} else{$ck2 = " SELECTED";}
        $quizoptform .= "	<option value=\"1\"$ck1>Yes</option>
		<option value=\"0\"$ck2>No</option>
		</select>
            </td>
	    </tr>
	<tr><td><b>Allow remote debugging:</b></td>
	    <td><select name=opt_remote_debugging>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($remote_debugging eq "off"){$ck1 = " SELECTED";} 
	else{$ck2 = " SELECTED";}
       $quizoptform .= "	<option value=\"off\"$ck1>No</option>
		<option value=\"on\"$ck2>Yes</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Email results of quiz to instructor:</b></td>
	    <td><select name=opt_mail_me_results>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($mail_me_results eq "Yes"){$ck1 = " SELECTED";} 
	elsif($mail_me_results eq "All"){$ck2 = " SELECTED";}
	else{$ck3 = " SELECTED";}
        $quizoptform .= "	
		<option value=\"Yes\"$ck1>Yes, but only the first.</option>
		<option value=\"No\"$ck3>No</option>
		<option value=\"All\"$ck2>Email me all results.</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Allow students to take this quiz more than once?:</b></td>
	    <td><select name=opt_take_quiz_over>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($take_quiz_over eq "yes"){$ck1 = " SELECTED";} 
	else{$ck2 = " SELECTED";}
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
		<option value=\"no\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Accept *only* fully completed quizzes?</b></td>
	    <td><select name=opt_force_complete_quiz>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($force_complete_quiz eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
		<option value=\"no\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Only authorized users can take quiz:</b></td>
	    <td><select name=opt_authorized_users>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($authorized_users eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
		<option value=\"no\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Use single password for this quiz:</b><br>(Allows anyone
	to take the quiz without logging in as long as they have 
	the password.)</td>
	    <td><select name=opt_overall_quiz_password>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($overall_quiz_password eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
		<option value=\"no\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Password:</b><br>(If you chose \"Yes\" above, enter the
	password for this quiz.)</td>
	    <td><input type=password name=opt_overall_quiz_password_text 
		value=\"$overall_quiz_password_text\">
	     </td>
	     </tr>
	<tr><td><b>Use a time limit on this quiz?</b></td>
	    <td><select name=opt_time_quiz>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($time_quiz eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
		<option value=\"no\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
       <tr><td><b>Auto-submit quiz when time is up?</b></td>
	<td><select name=\"opt_auto_submit_timed_quiz\">\n";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($auto_submit_timed_quiz eq "no"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"no\"$ck1>No</option>
				<option value=\"yes\"$ck2>Yes</option>
				</select>
				</td></tr>
       <tr><td><b>Time limit (in minutes):</b></td>
	<td><input type=text name=opt_time_limit value=\"$time_limit\"></td>
	</tr>
	<tr><td colspan=2 bgcolor=#E4D8E2><b>Score Display Options</b>
	</td></tr>
	<tr><td><b>What should I show after quiz completion?</b><br>
	       <table border=1>
	       <tr><td>
	       <b>All:</b></td><td> Shows the student's score and displays the
	       correct answer if the student got an incorrect answer.</td></tr><tr><td>
	       <b>StatusOnly:</b></td><td> Shows the score, and whether each answer was correct or incorrect, but does not show the correct answer if the student was incorrect.</td></tr><tr><td>
	       <b>ScoreOnly:</b></td><td> Shows only the total percentage score with no feedback about which answers were correct or incorrect.</td></tr><tr><td>
	       <b>None:</b></td><td> Shows no score and no results: just a message saying \"Thank you for taking this test. You will be notified of your score when the test is closed.\"</td></tr></table>
	       </td>
	    <td><select name=opt_what_to_show_after_quiz>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($what_to_show_after_quiz eq "All"){$ck1 = " SELECTED";} 
        elsif($what_to_show_after_quiz eq "StatusOnly"){$ck2 = " SELECTED";} 
        elsif($what_to_show_after_quiz eq "ScoreOnly"){$ck3 = " SELECTED";} 
        else{$ck4 = " SELECTED";} 
        $quizoptform .= "	<option value=\"All\"$ck1>All</option>
		<option value=\"StatusOnly\"$ck2>StatusOnly</option>
		<option value=\"ScoreOnly\"$ck3>ScoreOnly</option>
		<option value=\"None\"$ck4>None</option>
		</select>
	     </td>
	     </tr>
        <tr><td><b>Display the questions as well as the answers in the 
        results?</b><br>Note: May have an odd effect if there is HTML
        in the questions.</td>
        <td><select name=opt_show_quiz_questions>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($show_quiz_questions eq "yes"){$ck1 = " SELECTED";} 
        elsif($show_quiz_questions eq "no"){$ck2 = " SELECTED";} 
        else{$ck3 = " SELECTED";} 
        $quizoptform .= "	<option value=\"yes\"$ck1>Yes</option>
                               <option value=\"no\"$ck2>No</option>
                               <option value=\"instructor\"$ck3>Only for the Instructor</option>
                </select>
              </td>
              </tr>
	<tr><td><b>Mail Score to student as above, 
	but do not show on the web:</b><br>
	</td>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($mail_score_only eq "No"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= " <td><select name=opt_mail_score_only>
		<option value=\"No\"$ck1>No</option>
		<option value=\"Yes\"$ck2>Yes</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Show scores of other students:</b></td>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($show_other_scores eq "No"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= " <td><select name=opt_show_other_scores>
		<option value=\"No\"$ck1>No</option>
		<option value=\"Yes\"$ck2>Yes</option>
		</select>
	     </td>
	     </tr>
	<tr><td><b>Number of scores to show (if the above is \"Yes\"):</b></td>
	    <td><input type=text name=\"opt_number_of_scores_to_show\" size=3
		value=\"$number_of_scores_to_show\">
	     </td>
	     </tr>
	<tr><td><b>Allow students to receive score by email:</b></td>
	<td><select name=opt_cc_score_to_student>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($cc_score_to_student eq "No"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= " <option value=\"No\"$ck1>No</option>
			  <option value=\"Yes\"$ck2>Yes</option>
			  </select>
			  </td></tr>
	<tr><td><b>Show the Grading Scale:</b></td>
	    <td><select name=opt_show_grading_scale>";
	$ck1 = ""; $ck2 = ""; $ck3 = ""; $ck4 = "";
        if($show_grading_scale eq "Yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"Yes\"$ck1>Yes</option>
		<option value=\"No\"$ck2>No</option>
		</select>
	     </td>
	     </tr>
	<tr><td valign=top><b>
	In the textarea, you may modify the grading scale:</b></td>
	    <td><textarea name=opt_grading_scale rows=15 cols=30>
		$grading_scale
		</textarea></td>
             </tr>
	     <tr><td><b>Text for the \"Grade Quiz\" button on the quiz:</b></td>
	     <td><input type=text name=opt_grade_quiz_button_text value=\"$grade_quiz_button_text\">
	     </td></tr>
	<tr><td colspan=2 bgcolor=#E4D8E2><b>Short-Answer Question Scoring
	options</b></td></tr>
	<tr><td><b>Ignore case?</b><br>NOTE: If you enable this, then \"No,\" \"no,\" and \"NO\" will all be counted as the same thing.</td>
	  <td><select name=opt_sa_ignorecase>";
	$ck1 = ""; $ck2 = "";
        if($sa_ignorecase eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "      <option value=\"yes\"$ck1>Yes</option>
	      <option value=\"no\"$ck2>No</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Ignore punctuation?</b><br>NOTE: Don't enable this for math
	quizzes, since 1/4 and 14 will both be viewed as correct.</td>
	  <td><select name=opt_sa_ignorepunctuation>";
	$ck1 = ""; $ck2 = "";
        if($sa_ignorepunctuation eq "no"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"no\"$ck1>No</option>
	      <option value=\"yes\"$ck2>Yes</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Ignore spaces?</b><br>NOTE: This will allow students to enter
	extra spaces but will also count \"Internet\" and \"Inter net\" or
	\"allright\" and \"all right\" as
	the same answer.</td>
	  <td><select name=opt_sa_ignorespaces>";
	$ck1 = ""; $ck2 = "";
        if($sa_ignorepunctuation eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "<option value=\"yes\"$ck1>Yes</option>
	      <option value=\"no\"$ck2>No</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Ignore non-word characters?</b><br>NOTE: This will ignore both punctuation and spaces.
	</td>
	  <td><select name=opt_sa_ignorenonwords>";
	$ck1 = ""; $ck2 = "";
        if($sa_ignorenonwords eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "<option value=\"yes\"$ck1>Yes</option>
	      <option value=\"no\"$ck2>No</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Use multiple answers?</b><br>NOTE: This will allow you to enter
	multiple possible correct answers, and the students will be marked
	correct if they enter any of them.</td>
	  <td><select name=opt_sa_alternates>";
	$ck1 = ""; $ck2 = "";
        if($sa_alternates eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "<option value=\"yes\"$ck1>Yes</option>
	      <option value=\"no\"$ck2>No</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Accept partially correct answer?</b><br>NOTE: For example, if the correct answer is \"there are four people\" and the student types \"four\" or \"four people\" or \"there are four\" (or even \"there\" or \"there are\"), that will be counted as correct.
	</td>
	  <td><select name=opt_sa_containsanswer>";
	$ck1 = ""; $ck2 = "";
        if($sa_containsanswer eq "yes"){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= " <option value=\"yes\"$ck1>Yes</option>
	      <option value=\"no\"$ck2>No</option>
	      </select>
	  </td>
	  </tr>
	<tr><td><b>Mark ALL short answers as correct?</b><br>NOTE: this will
	simply count all short answers as correct.</td>
	  <td><select name=opt_sa_markallcorrect>";
	$ck1 = ""; $ck2 = "";# KKK
        if($sa_markallcorrect =~ /^yes$/i){$ck1 = " SELECTED";} 
        else{$ck2 = " SELECTED";} 
        $quizoptform .= "	<option value=\"no\"$ck1>No</option>
	      <option value=\"yes\"$ck2>Yes</option>
	      </select>
	  </td>
	  </tr>
        </table> ";
  $quizoptform;
}

sub mail_student_results {
    my $message = &repipe($data{'mailres'});
    $message =~ s/\D+//g;
    if(-f "$basedir/mresults.$message"){
        (open(MSG, "<$basedir/mresults.$message")) ||
           &debug("could not open results file: $!");
        while(<MSG>){
            $msg .= $_;
            }
         close(MSG);
         unlink("$basedir/mresults.$message");
        }
    my $toemail = $data{'StudEmail'};
    my $fromemail = $data{'InsEmail'};
    my $subject = "Results of Quiz";
    my $message =  &repipe($msg);
    $toemail =~ s/[^A-Za-z0-9\.\@\-_]//g;
    $fromemail =~ s/[^A-Za-z0-9\.\@\-_]//g;
    if($msg eq ""){
       $error = "<br><b>Sorry, your results could not be found for
                 mailing. Please contact your instructor
                 for the results of this quiz. </b><br><br>";
        }
    elsif(&bad_email($toemail) != 1){
       &send_mail($toemail,$toemail,$fromemail,$fromemail,
		$replytoemail,$replytoname,$subject,
		$message,$mail_server_hostname,
		$this_server_hostname);
       $error = "<br><b>Your results have been emailed to $toemail.
                </b><br>";
       }
     else {
       $error = "<br><b>Sorry, the email address you entered does not
                 appear to be correct. Please contact your instructor
                 for the results, hit the \"Back\" button on your
                 browser and correct the address, or <a 
                 onClick=\"javascript:history.back()\" 
                 href=\"$ENV{'HTTP_REFERER'}\">Try this
                 link if you have JavaScript enabled</a>.</b><br><br>";
       }
       &no_args_error;

}

# &bad_email("Email address to check");
# Checks for various characters and combinations that should
# not be in an email address. Returns 1 if the email address
# is bad, otherwise, returns undef.

sub bad_email {
 my $email = $_[0];
 my $bad_email;
 if($email !~ /(.{1,})(\@)(.{1,})(\.)(.{2,})/ ||
    $email =~ /,/ || $email =~ /.*\@.*\@/ || $email =~ /\@\@/ || 
    $email =~ /\s/ || $email =~ /\.$/ || $email =~ /\@\./){
    $bad_email = 1;
    }
  $bad_email;
}

# &copy_quiz();
# Reads in data from a quiz's files and copies it to a new
# quiz assigned to a new instructor. Does not preserve student
# authorization information, but preserves results data.

sub copy_quiz {

 if($data{'FA2'} eq "DoCopy"){
     # do copy
     # mkdir new title
     $title = $data{'NewTitle'};
     $dir = $title;
     $dir =~ s/\W+//g;
     $dir =~ tr/[A-Z]/[a-z]/;
     # Don't let them
     if(-e "$basedir/$dir"){
	$error = "Error: a quiz entitled $data{'NewTitle'} (or a quiz
                  with a very similar title) already exists.
		  Please choose another title for the quiz.";
	$data{'FA2'} = "";
	&copy_quiz;
	exit();
	}
     $oldtitle = $data{'OldTitle'};
     $olddir = $oldtitle;
     $olddir =~ s/\W+//g;
     $olddir =~ tr/[A-Z]/[a-z]/;

     # Make sure the old quiz exists, and that they're not just
     # going to be looking for files in plain old $basedir

     unless(-d "$basedir/$olddir" && $olddir ne ""){
	print  "$header
		  Error: a quiz entitled $data{'OldTitle'} ($basedir/$olddir)
		  could not be
		  found, and so, cannot be copied.
                  Please return to the Administration main menu
		  and choose \"Edit Quiz\" to copy a quiz.$footer";
	exit();
	}
     # Add to instructors file
     open(FILE, "+<$instructors_file") ||
       &debug("Could not open $instructors_file for read/write: $!");

     if($opsys ne "unix"){binmode(FILE);}
     else{flock(FILE, 2);}

       @lines = <FILE>;
       foreach $line (@lines){
	  if($line =~ /^$data{'Instructor'}\|/){
	     chomp($line);
	     $newfile .= "$line%$data{'NewTitle'}\n";
	     }
	  else{
	     $newfile .= $line;
	     }
	  }
     $newfile =~ s/%%/%/gs;
     truncate(FILE, length($newfile));
     seek(FILE, 0, 0);
     print FILE $newfile;
     close(FILE);
     mkdir("$basedir/$dir", 0755) ||
      &debug("Could not make directory for new quiz: $!");
     foreach $file ('config','header','footer','results.data','results.data-detailed','quizdb','answerfile'){
	&debug("Copying $basedir/$olddir/$file to $basedir/$dir/$file");
	open(OLD, "<$basedir/$olddir/$file") ||
	  &debug("could not open old quiz $file for reading! $!");
	open(NEW, ">$basedir/$dir/$file") ||
	  &debug("could not open new quiz $file for writing! $!");
          if($opsys eq "unix"){ flock(NEW, 2);}
          else{ binmode(NEW);}

	while(<OLD>){
	  $oldt = &unpipe($data{'OldTitle'}); 
	  $newt = &unpipe($data{'NewTitle'}); 
	  s/^$oldt/$newt/;
	  print NEW;
	  }
        close(OLD);
        close(NEW);
	}
     &debug("Done copying quiz files.");
     print "$header
	    <b><center>Quiz Copied</center></b><br><br>
	    $data{'OldTitle'} has been copied to $data{'NewTitle'} along
	    with all the student results data, but <b>without</b> a list
	    of authorized students.  If you are using the authorized students
	    feature, you (or the new instructor), must login to the \"Edit
	    Quiz\" screen and select the students to authorize.
	    $footer";
     exit();
     }
 else {
# Need new title
# Copy for which instructor
  print "$header
       <center><b>Copying Quiz</b></center><br><br>
       <font color=#FF0000><b>$error</b></font><br>
       $admformtop
       <table border=0>
       <tr><td><b>Title for New Quiz</b></td>
	   <td><input type=text name=NewTitle value=\"$data{'OldTitle'}\">
	   </td></tr>
       <tr><td><b>Assign copy to Instructor:</b></td>
	   <td><select name=Instructor>";
     print &get_instructors_as_options;
     print "</select></td></tr></table>
	    <input type=hidden name=OldTitle value=\"$data{'OldTitle'}\">
	    <input type=hidden name=FA2 value=\"DoCopy\">
	    <input type=hidden name=FA value=\"Copy Quiz\">
	    <input type=submit value=\"Copy Quiz\">
	    </form>$footer";
     exit();
     }



}

sub start_time {

# &start_time($data{'student'},$quizdir);
my($stu,$quiz) = @_;
if($time_quiz eq "yes"){

   if($time_limit eq "" || $time_limit <= 0){$time_limit = 1;}
   $force_complete_quiz = "no";
   if($auto_submit_timed_quiz eq "yes"){
      $scode = "if(sec <= 0 && min <= 0){   
		document.QuizTest.submit();
		}\n";
      }
   else {
      $scode = "
      if(sec <= 0 && min <= 0){
	 if(stoptime !=1){
	    alert(\"Your time is up!\");
	    stoptime = 1;
	    stuff = setTimeout(\"CountDown();\", 0);
	    }
	 else {
	    stuff = setTimeout(\"CountDown();\", 0);
	    }
	 }\n";
      }
   $timesofar = $data{'TimeTaken'};
   $timetakenfield = "<input type=hidden name=\"TimeTaken\" value=\"$timesofar\">\n";
   # Get the time limit for the Javascript countdown...
   if($time_limit =~ /\./){
      ($min,$sec) = split(/\./, $time_limit);
      }
   else {
      $min = $time_limit;
      $sec = 0;
      }
   # Only if we are using authorized students.
   if($authorized_users eq "yes"){
   unless(-f "$basedir/$quiz/timing") {
    open(FILE, ">>$basedir/$quiz/timing");
     print FILE "";
    close(FILE);
    }
   # First, see if this student has already started the quiz,
   # such as, if they're trying to reload the page. We don't want
   # to update the time unless they have had the quiz graded.

   open(FILE, "+<$basedir/$quiz/timing") ||
    &debug("Could not read quiz timing file '$basedir/$quiz/timing': $!");
   if($opsys eq "unix"){ flock(FILE, 2); }
   else { binmode(FILE); }

    @started = <FILE>;

   # A completed time record is student|start|stop. If there is
   # only student|start, do not update. If there is no student,
   # add the start time.

   foreach $rec (@started){
     if($rec =~ /^$stu\|\d+$/){
	($r_stu,$r_start) = split(/\|/, $rec);
	 chomp($r_start);
	 $min = int((($time_limit * 60) - (time - $r_start)) / 60);
	 if($min < 0){ $min = 0; }
	 $sec = (($time_limit * 60) - (time - $r_start)) % 60;
	 if($sec < 0){ $sec = 0; }
	$newrecs .= $rec;
	$nostart = 1;
	}
     else {
	$newrecs .= $rec;
        }
     }
   if($nostart != 1){
      $newrecs .= "$stu|" . time . "\n";
      }
   truncate(FILE, length($newrecs));
   seek(FILE, 0, 0);
   print FILE $newrecs;
   close(FILE);
   } # end if authorized users 

   $min = sprintf("%0.2d", $min);
   $sec = sprintf("%0.2d", $sec);

   $header =~ s/<body/<body onLoad=\"CountDown();\"/i;
   
   $javascript = "
<script language=\"Javascript\">
 min = $min;
 sec = $sec;
 taken = 0;
 stoptime = 0;

function CountUpTime () {
  taken++;
  document.QuizTest.TimeTaken.value = taken;
  }

function CountDown (){
  stuff = setTimeout(\"blah()\", 1000);
  }

function blah () {
 sec--;
 if (sec < 0){ sec = 59; min--; }
 if(sec < 10 && sec >= 0){ sec1 = \"0\"+sec;}
 else { sec1 = sec;}
 if(min < 10 && $min >= 0){ min1 = \"0\"+min;}
 else { min1 = min;}
 if(min < 0 || sec < 0){
    document.QuizTest.time.value = \"00:00\";
    }
 else {
    document.forms[0].time.value = min1 + \":\" + sec1;
    }
 CountUpTime();
 $scode
 else { stuff = setTimeout(\"CountDown()\",0); }

}

</script>\n\n";
  $header .= $javascript;
  $timeoutfield = "<tr><td><b>Time Remaining:</b></td><td><input type=text name=time size=6 value=\"$min:$sec\"></td></tr>$timetakenfield";

   }
#   $time_allowed = time + ($time_limit * 60);
}

sub end_time {

# &start_time($data{'student'},$quizdir);
my($stu,$quiz) = @_;
if($time_quiz eq "yes"){

   # First, see if this student has already started the quiz,
   # such as, if they're trying to reload the page. We don't want
   # to update the time unless they have had the quiz graded.
   if($authorized_users eq "yes"){
   open(FILE, "+<$basedir/$quiz/timing") ||
    &debug("Could not read quiz timing file: $!");
   if($opsys eq "unix"){ flock(FILE, 2); }
   else { binmode(FILE); }

    @started = <FILE>;

   # A completed time record is student|start|stop. If there is
   # only student|start, update.

   foreach $rec (@started){
     if($rec =~ /^$stu\|\d+$/){
	chomp($rec);
	($r_stu,$r_start) = split(/\|/, $rec);
	$e_time = time;
	$totaltime = sprintf("%.2f", ($e_time - $r_start) / 60);
	$newrecs .= "$rec|$e_time\n";
	$nostart = 1;
	}
     else {
	$newrecs .= $rec;
        }
     }
   truncate(FILE, length($newrecs));
   seek(FILE, 0, 0);
   print FILE $newrecs;
   close(FILE);
   $totaltime;
   }
 }
#   $time_allowed = time + ($time_limit * 60);
}

sub show_high_scores_only {

my($quiz,$path_to_results_dat,$sc,$fn,$sn,$em,$ln,$da,$quiz_friendly_name);
my($qconfig);
$quiz = $data{'Quiz'};
$quiz =~ s/\W+//g;
$quiz = lc($quiz);
$path_to_results_dat = "$basedir/$quiz/results.data";
$quiz_friendly_name = $data{'QuizFname'};
$qconfig = "$basedir/$quiz/config";
# Get the config to see if the instructor wants the scores shown:
open(QC, "<$qconfig") ||
  &debug("Could not open quiz config $qconfig to show scores $!");
  while(<QC>){
   if($_ =~ /show_other_scores/ &&
      $_ !~ /show_other_scores = Yes/){
      print "$header<br>
             <center><b>Sorry, Not Authorized</b></center><br><br>
             The instructor of this quiz has set it to not show
             the high scores list. 
             $footer";
       close(QC);
       exit();
       }
   }
close(QC);

      
# Show high scorers if we want to:
 open(FILE, "<$path_to_results_dat");
 print "$header<br><center><table border=1 cellpadding=5>
        <tr><th colspan=3><font size=+1>
         High Scorers</font></th></tr>
        <tr><th>Score</th><th>Name</th><th>Date</th></tr>\n";
 while(<FILE>){
        @score_data = split(/\|/, $_);
        if($#score_data == 6){
           ($sc,$fn,$sn,$em,$ln,$da,$rh) = @score_data;
           }
        else {
           ($sc,$fn,$sn,$em,$ln,$da) = @score_data;
           }
    if($sc ne ""){
       $sc = $sc * 1;
       print "<tr><td align=center>$sc</td><td>$fn</td><td>$da</td></tr>";
       }
    $i++;
    if($i >= $number_of_scores_to_show){close(FILE); last;}
    }
  if($sc eq ""){
    print "<tr><td colspan=3> -- No Scores Found -- </td></tr>";
    }
 print "</table></center><br>$footer\n";
 exit();
}

# Okay. Let's do this like "add_quiz_to_students." We'll take
# instructor_id,@students as arguments like this:
# &assign_students_to_instructor($instructor,@students);
sub assign_students_to_instructor {
 my($nins,@students) = @_;
 my($newfile,$oid,$opw,$oname,$quizzes,$oins,$student,$n_student);
 my(@all_students);
 # First, get the student file
 open(F, "+<$authorized_users_file") || 
  &debug("Could not open authorized users file to assign students to $instructor.
          The server returned: $!");
 if($!){ return "Error: Could not open students file to assign instructor."; }
 if($opsys eq "unix"){ flock(F, 2); }
 else { binmode(F); }
 @all_students = <F>;
 foreach $student (@all_students){
   chomp($student);
   ($oid,$opw,$oname,$quizzes,$oins) = split(/\|/, $student);
   foreach $n_student (@students){
        # Reassign the instructor to the new one.
        if(&unpipe($oid) eq $n_student){ $oins = $nins; }
        }
    $newfile .= "$oid|$opw|$oname|$quizzes|$oins\n";
    }
  truncate(F, length($newfile));
  seek(F, 0, 0);
  print F $newfile;
  close(F);
  return 1;
}


