/* +=============================================-===========================================+
   |                                     GLOBAL VARIABLES                                    |
   +=============================================-===========================================+ */

	var answerMatrix = new Array();  // will hold an array of answers for each question
	var correctMatrix = new Array();  // will hold an array of T/F values indiciating the
									  // correctness of each q item
	var responseMatrix = new Array();  // will hold the forms[] array and its elements
	var qTypeMatrix = new Array();  // will hold an array of question types for the page
	var feedbackMatrix = new Array();  // will hold an array of feedback type indicators for
									   // each question
	var feedbackLocation;  // will hold the page-wide feedback location indicator
	var total = new Object();  // will hold info regarding score totals
	total.perQPossible = new Array();  // will hold an array of possible correct per question
	total.perQCorrect = new Array();  // will hold an array of total correct per question
	var totalQ; // will hold the number of questions on the page
	var TimeDelay = 750;  // delay in milliseconds before fb appears
	var FBMultiOnPage = 'fboninline'; // class name for on state for MultiFBOnPage
	var FBOnPage = 'fbon'; // class name for normal on state for FB
	var FBOff = 'fboff'; // class name to hide FB
	var myURL = (window.location.toString()); // grab the current URL
	myURLParts = myURL.split('.'); // split it by the dots
	var myFileName = '';
	for (i = 0; i < (myURLParts.length-1); i++) { // put back together all but the last part
		myFileName+= myURLParts[i] + "."; // also add a dot as the split() removed them
	} // end for i loop
	myFileExt = myURLParts[i]; // the last part is the file extension
	myFileName = myFileName.substring(0,(myFileName.length-1)); // take the last dot off
															    // that we added
	var IDAppend = 'li'; // string to append to end of element ID that gets the style
	var RespRight = 'RespRight'; // class name for correct responses
	var RespWrong = 'RespWrong'; // class name for incorrect responses

function testanswers (strAnswers) {
/* +============================================-============================================+
   |                                TEST ANSWERS VERSION 2.2                                 |
   |============================================-============================================|
   |                                     VERSION HISTORY                                     |
   | 2.0.00  2003.08.31  JEM  Reconstructed the logic of previous testAnswers() functions to |
   |                          make a solution that could be implemented with a global JS     |
   |                          library and only one line of programming per page (the Submit  |
   |                          button).                                                       |
   | 2.2.00  2004.02.03  JEM  Restructured v2.0 to simplify the LA types to the basic few by |
   |                          extracting the feedback information into their own values.     |
   |                          Also support for clickable images and multiple FBs on one page.|
   | 2.2.01  2004.02.18  JEM  Corrected logic flaw in feedback() for FBOnPage with RSFB      |
   | 2.2.02  2004.02.19  JEM  Corrected logic flaw in feedback() for MultiFBOnPage, Normal   |
   | 2.2.03  2004.02.25  JEM  Added NS6 flicker fix (may revert this if NS6 is dropped?;     |
   |                          Made FBOff a global variable; renamed calls to the change()    |
   |                          function to changeClassById() for clarity.                     |
   |                                                                                         |
   |                                         SUMMARY                                         |
   | This function accepts a string of text representing the type of question used, the type |
   | of feedback to be used, and the correct answers for that question.  Given these values  |
   | and the state of the form elements on the page, this and subsiquent functions determine |
   | if the learning activity (LA) was answered correctly and displays desired feedback,     |
   | accordingly.                                                                            |
   |                                                                                         |
   |                                FEEDBACK LOCATION INDICATOR                              |
   | The first argument indicates, for the current LA, how the feedback will be displayed.   |
   | Values forthe feedback location indicator are:                                          |
   |    FBOnPage                  All feedback (positive, negative, partial, response-       |
   |                              specific) appear on the same page as the LA, often within  |
   |                              a feedback DIV which is visually controlled by CSS.        |
   |                              Feedback applies to the LA as a whole.                     |
   |    FBPosNext                 Positive feedback is on its own page, all other feedback   |
   |                              appears on the same page as the LA.  Feedback applies to   |
   |                              the LA as a whole.                                         |
   |    FBNextPage                All feedback appears on another page.  Feedback applies to |
   |                              the LA as a whole.                                         |
   |    MultiFBOnPage             This is used when there are multiple questions on a given  |
   |                              page and there is to be separate feedback given for each   |
   |                              question.  Feedback appears on the same page as the LA.    |
   |    MultiFBOnPagePlusAdvance  This is used when there multiple questions on a given page |
   |                              and there is to be separate feedback given for each        |
   |                              question.  Such feedback appears on the same page as the   |
   |                              LA.  Additionally, when all questions are correctly        |
   |                              answered, the browser is redirected to a positive feedback |
   |                              page.                                                      |
   |  Future types to consider adapting testAnswers() to include:                            |
   |    MultiFBOnPagePlusPageFB   This is used when there multiple questions on a given page |
   |                              and there is to be separate feedback given for each        |
   |                              question.  Such feedback appears on the same page as the   |
   |                              LA.  Additionally, feedback regarding the page as a whole  |
   |                              appears.  This feedback could be strictly positive and     |
   |                              negative, or could include partial feedback.               |
   |                                                                                         |
   |                                    QUESTION DESCRIPTORS                                 |
   | Following the feedback type indicator argument, each successive argument represents     |
   | one question in the LA.  The string is structured as such:                              |
   |    '<feedback location indicator>','<question type indicator>,<feedback type indicator> |
   |    |<correct state for element 1>'                                                      |
   | When a given question has multiple options (such as radio buttons), an additional pipe  |
   | (|) is added, followed by the correct state for that option. Question type indicator    |
   | has these defined possible values:                                                      |
   |    singlesel                 single selection multiple choice (radio buttons)           |
   |    multisel                  multiple selection multiple choice (check boxes)           |
   |    text                      text responses (text boxes)                                |
   |    dd                        drop-down menus (select boxes)                             |
   |    img                       clickable images (image)                                   |
   | Feedback type indicator has these defined possible values:                              |
   |    normal                    Requires that the question is completely correct in order  |
   |                              to display positive feedback.  All other situations        |
   |                              display negative feedback.                                 |
   |    partial                   If all aspects of the question(s) are correct or incorrect,|
   |                              positive or negative feedback is displayed, respectively.  |
   |                              If only one of the multiple aspects of the question(s) are |
   |                              correct, the partial feedback is displayed.                |
   |    responseSpecific          This currently only applies to singlesel question types.   |
   |                              In this case, feedback corresponding to the selected       |
   |                              option is displayed.                                       |
   |  *IMPORTANT NOTE*: If there are multiple questions on the page, either MultiFBOnPage or |
   |  MultiFBOnPagePlusAdvance must be used as the feedback location indicator **OR** all of |
   |  the question type indicators must be the same for each question.                       |
   | Correct state indicators can take a variety of forms:                                   |
   |    1                         To represent that the element should be selected or        |
   |                              checked.                                                   |
   |    0                         To represent that the element should NOT be selected or    |
   |                              checked.                                                   |
   |    71 (or other number)      To represent the VALUE of the select option that is        |
   |                              correct.                                                   |
   |    71,75,77 (or others)      To represent the list of possible values of the select     |
   |                              option that is correct (selecting any one will correctly   |
   |                              answer the question).                                      |
   |    gaurd (or other text)     To represent the correct text for a text box (not case     |
   |                              sensitive).                                                |
   |    gaurd, guard, gard (etc.) To represent a list of possible text values for a text box |
   |                              that is correct (typing any one will correctly answer the  |
   |                              question).                                                 |
   |                                                                                         |
   |                                       EXAMPLE USAGE                                     |
   | One question with four radio buttons, with normal feedback located on the same page as  |
   | the LA:                                                                                 |
   |  javascript:testanswers('FBOnPage','singlesel,normal|1|0|0|0');                         |
   | Three questions, each with a text box and each accepting two possible answers, with     |
   | normal feedback where the positive FB is on another page but negative FB is on the same |
   | page as the LA:                                                                         |
   |  javascript:testanswers('FBPosNext','text,normal|hi,high','text,normal|lo,low');        |
   | A response-specific FB single-select question, a partial FB multi-select question, and  |
   | a drop-down with two possible answers.  Since each question is to have its own FB       |
   | displayed, the MultiFBOnPage feedback location indicator is used:                       |
   |  javascript:testanswers('MultiFBOnPage','singlesel,responseSpecific|0|1|0|0','multisel, |
   |  partial|1|1|0|1|0','dd,normal|78,80');                                                 |
   |                                                                                         |
   |                                      VERSION HISTORY                                    |
   +=============================================-===========================================+ */
	// nine sequential steps to pull the whole thing off...
	// 1) the first argument is the feedback location indicator
	feedbackLocation = testanswers.arguments[0];
	// 2) one form for each question, thus this is total num of questions
	totalQ = document.forms.length;
	// 3) Call to function to build the qType, feedback, and answer matricies
	buildMatricies();
	// 4) Turn off all feedback before continuing
	resetFeedback();
	// 5) Call to function to validate the form; if false...
	if (!validateForm()) return; // ...quit entirely
	// 6) Call to function that evaluates if each element was correct
	findCorrects();
	// 7) Call to function that marks each element as appropriate
	markCorrects();
	// 8) Get the total correct and total possible from the totals function
	tally();
	// 9) Call to function to display appropriate feedback
	setTimeout("feedback()",TimeDelay);
} // END TEST ANSWERS FUNCTION

function buildMatricies() {
/* +============================================-============================================+
   | Builds the qType, feedback, and answer Matricies.                                       |
   +============================================-============================================+ */
	var i; // counter
	var tempArray = new Array(totalQ);  // a temporary array
	var tempArray2 = new Array(totalQ);  // a temporary array

	// Loops through each of the arguments passed to testanswers()
	for (i = 0; i < totalQ; i++) {
		// For the current argument, split the string of text into separate array elements
		tempArray[i] = testanswers.arguments[i+1].split("|");
		tempArray2[i] = tempArray[i][0].split(",");
		qTypeMatrix[i] = tempArray2[i][0];  // log the question type for this question
		feedbackMatrix[i] = tempArray2[i][1];  // log the feedback type for this question
		// slice off the first element of the tempArray; the result is the answerMatrix
		answerMatrix[i] = tempArray[i].slice(1);
	};  // end for i loop
	// Grab all the forms[] array from the document and keep it in response matrix
	responseMatrix = document.forms;
} // end buildMatricies()

function validateForm() {
/* +============================================-============================================+
   | Validate the form to ensure that every question on the page has at least one selection  |
   | made on it or one value entered.  If not, trigger the unvalidatedForm function.         |
   +============================================-============================================+ */
	if (!allAreAnswered()) {
		unvalidatedForm ();
		return false;  // This ejects us from the remainder of the testanswers() function
	}; // end if
	return true;
} // end validateForm()

function resetFeedback() {
/* +=============================================-===========================================+
   | This function calls change() to reset all page elements of class FBOnPage or            |
   | FBMultiOnPage to the FBOff class.                                                       |
   +=============================================-===========================================+ */
	var els = document.getElementsByTagName('*');
	var matches = new Array();
	for (var i = 0; i < els.length; i++) {
		if ((els.item(i).className == FBOnPage) || (els.item(i).className == FBMultiOnPage)) {
			matches.push(els.item(i));
		} // end if
	} // end for i

	for (j = 0; j < matches.length; j++) {
		changeClassById (matches[j].id, FBOff);
	} // end for j
}

function resetFeedbackOLD(feedbackLocation) { // abandoned
/* +=============================================-===========================================+
   | This function calls changeClassById() to reset the appropriate feedback DIVs to the     |
   | FBOff class. Requires feedbackLocation.                                                 |
   +=============================================-===========================================+ */
	var i;  // counter
	var j;  // counter
	var k;  // counter
	for (i=0; i<totalQ; i++) { // loop through each question
		// except in these situations where one does not exist, a positive fb should be turned off
		if ((feedbackLocation != 'FBPosNext') && (feedbackLocation != 'FBNextPage') && (feedbackMatrix[i] != 'responseSpecific')) {
			changeClassById ('fb' + i + 'p', FBOff);
		} // end if
		switch (feedbackMatrix[i]) { // depending on the type of fb, turn off appropriate fb
			case ('normal'):
				changeClassById ('fb' + i + 'n', FBOff);
				break; // end case normal
			case ('partial'):
				changeClassById ('fb' + i + 'n', FBOff);
				changeClassById ('fb' + i + 'part', FBOff);
				break; // end case partial
			case ('responseSpecific'):
				for (j=0; j<responseMatrix[i].length; j++) { // loop through each element
					if (usesValue(i) && (qTypeMatrix[i] == 'dd')) { // if it is a dropdown
						// hide fb corresponding to each value, ignoring any options with no value
						for (k = 0; k < responseMatrix[i][j].length; k++) {
							if (responseMatrix[i][j][k].value != '') { 
								changeClassById ('fb' + i + 'resp' + responseMatrix[i][j].value, FBOff);
							} // end if value
						} // end for k
					} else { // otherwise assume 
						changeClassById ('fb' + i + 'resp' + j, FBOff);
					} // end if usesValue
				} // end for j loop
				break; // end case responseSpecific
		}; // end switch
	} // end for i
} // end function resetFeedback()

function unvalidatedForm() {
/* +=============================================-===========================================+
   | This function displays the appropriate alert informing the learner that the form did    |
   | not validate (one or more questions on the page were not answered).                     |
   +=============================================-===========================================+ */
	if (totalQ == 1) { // singular question
		alert ("Please answer this question.");
	} else { // multiple questions
		alert ("Please answer all questions on this page.");
	} // end if
} // end function unvalidatedForm()

function allAreAnswered() {
/* +=============================================-===========================================+
   | This function loops through each question, asking the isAnswered() function to analyze  |
   | each one. Should each question return from isAnswered() with true, then the entire page |
   | is completed.                                                                           |
   +=============================================-===========================================+ */
	var i; // counter
	for (i = 0; i<totalQ; i++) {  // Loop through each question stored in the array
		if (isAnswered(i) == false) {	// if any one is not answered...
			return false; // ...they are not all answered
		};	// end if	
	}; // end for
	return true; // if you get this far, they were all answered
} // end allAreAnswered

function isAnswered(currentQ) {
/* +=============================================-===========================================+
   | Given the current question number, loop through all of the elements within that         |
   | question's form element and ensure that at least one element per form is either checked |
   | or has a value.                                                                         |
   +=============================================-===========================================+ */
	var i; // counter
	// Loop through each option within the question
	for (i = 0; i < responseMatrix[currentQ].length; i++) {
		// for those LA types that are value-based
		if ((qTypeMatrix[currentQ] == 'text') || (qTypeMatrix[currentQ] == 'dd') || (qTypeMatrix[currentQ] == 'img')) {
			if (responseMatrix[currentQ][i].value !== '') {
				// if any are selected or a text value provided, the question was answered
				return true;
			 }; // end if responseMatrix.value
		} else { // for the rest of the LA types that are indicated by selected states
			if (responseMatrix[currentQ][i].checked) {
				return true;  // if any are checked, the question was answered
			 }; // end if responseMatrix.checked
		}; // end if qTypeMatrix
	}; // end for
	return false; // if you get this far, the question was not answered
} // end isAnswered

function findCorrects () {
/* +=============================================-===========================================+
   | Given an array of question elements and an array of the appropriate responses, record   |
   | which items were correctly answered.                                                    |
   +=============================================-===========================================+ */
	var j; // counter
	var k; // counter

	//Loop through all of the responses and check against the answers provided to testanswers()
	for (j = 0; j < totalQ; j++) {  // Loop through all of the questions; j tracks current question
		// Each time we come to a new question, rebuild the currQCorrects temporary array so
		// that it is of same size as the total number of options on this item
		var currQCorrects = new Array(responseMatrix[j].length);
		// Loop through all of the options of the current question
		for (k = 0; k < responseMatrix[j].length; k++) {
			// Go check to see if the current option of the current question was answered
			// correctly.  currQCorrects then holds the result for all the options of the
			// current question.
			possAns = answerMatrix[j][k].split(","); // parse possible answers
			if (usesValue(j)) {
				// evaluate the elements based on their value
				currQCorrects[k] = isCorrectByVal(j,k,possAns);
			} else {
				// evaluate the elements based on their state
				currQCorrects[k] = isCorrectByState(j,k,possAns);
			} // end if qTypeMatrix[j]
		} // end for k loop
		// Now take all of the item results and store them in the correctMatrix
		// that will house all of the results from all of the questions
		correctMatrix[j] = currQCorrects;
	} // end for j loop
	return;
} // end findCorrects()

function usesValue(currentQ) {
/* +=============================================-===========================================+
   | Given a question, check it for a set of possible conditions that would qualify it as an |
   | element that should be dealt with by using its value.                                   |
   +=============================================-===========================================+ */
	var boolUsesValue;
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'text'));
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'dd'));
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'img'));
	return boolUsesValue;
} // end usesValue

function isCorrectByState(qNumber, eNumber, possAns) {
/* +=============================================-===========================================+
   | Given the state of an option from a single question and the desired state of the        |
   | corresponding option from the same question, see if the selection was correct.          |
   +=============================================-===========================================+ */
   var k; // counter
   for (k = 0; k < possAns.length; k++) { // loop through each possible answer
		// if the control matches the answer key...
		if (responseMatrix[qNumber][eNumber].checked == possAns[k]) {
			return true; // the option is correct
		}; // end if
   } // end for k
	return false; // if you get this far, it was wrong
} // end isCorrect()

function isCorrectByVal(qNumber, eNumber, possAns) {
/* +=============================================-===========================================+
   | Given the value of an option from a single question and the desired value of the        |
   | corresponding option from the same question, see if the selection was correct.          |
   +=============================================-===========================================+ */
	var k; // counter
	for (k = 0; k < possAns.length; k++) {  // Loop through all of the acceptable answers
		// if the control matches the answer key... (drop all caps to make it not case sensitive)
		if (responseMatrix[qNumber][eNumber].value.toLowerCase() == possAns[k].toLowerCase()) {
			return true; // the option is correct
		}; // end if
	} // end for k
	return false; // if you get this far, it was wrong
} // end isCorrect()

function markCorrects() {
/* +=============================================-===========================================+
   | Given a matrix of what elements were correctly answered, mark them as such with classes.|
   +=============================================-===========================================+ */
	var i; // counter
	var j; // counter
	var thisEl; // shortcut var
	var idToChange; // holds the final id of the element to adopt the class
	for (i = 0; i < totalQ; i++) { // loop through each question
		for (j = 0; j < responseMatrix[i].length; j++) {
			thisEl = responseMatrix[i][j]; // shortcut var
			if (yesChange(thisEl)) { // if one of the above was true
				if (qTypeMatrix[i] == 'img') {
					idToChange = thisEl.id + "r" + thisEl.value; // Special ID for image fb
				} else {
					idToChange = thisEl.id + IDAppend;  // Append to match the ID of the container LI
				} // end if qTypeMatrix
				if (correctMatrix[i][j] == true) { // If they got the current item right
					changeClassById(idToChange, RespRight);  // Change an element to the RespRight class
				} else { // else they got it wrong
					changeClassById(idToChange, RespWrong);  // Change an element to the RespWrong class
				}; // end if true # 2
			}; // end if checked
		}; // end for j
	}; // end for i	
} // end markCorrects()

function yesChange(thisEl) {
/* +=============================================-===========================================+
   | Given the element in question, check it for a set of possible conditions that would     |
   | qualify it as an element that should have local feedback (X and OK) applied to it.      |
   +=============================================-===========================================+ */
	var boolToChange = false; // holds true if the current element should by styled
	// only mark feedback on the element if it...
	// ...is checked
	boolToChange = ((thisEl.checked));
	// ...has a value but isn't 'on' (value of radio buttons and check boxes)
	boolToChange = (boolToChange || ((thisEl.value != '') && (thisEl.value != 'on')));
	// ...it a textbox
	boolToChange = (boolToChange || thisEl.type == 'text');
	return boolToChange;
} // end yesChange()

function tally() {
/* +=============================================-===========================================+
   | Given a matrix of what elements were correctly answered, record total possible and      |
   | total correct for each question and for all questions.                                  |
   +=============================================-===========================================+ */
	var i; // counter
	var j; // counter
	total.possible = totalQ; // initalize total possible to zero
	total.correct = 0; // initalize total correct to zero
	
	for (i = 0; i < totalQ; i++) { // loop through each question
		total.perQPossible[i] = 0; // initalize possible for the current question to zero
		total.perQCorrect[i] = 0; // initalize correct for the current questiont to zero
		for (j = 0; j < responseMatrix[i].length; j++) { // loop through the elements in the question
			total.perQPossible[i]++; // add one to total possible for this question
			if (correctMatrix[i][j] == true) { // If they got the current item right
				total.perQCorrect[i]++; // note it
			}; // end if true # 2
		}; // end for j
		// If all elements in this question were correct ...
		if (total.perQPossible[i] == total.perQCorrect[i]) {
				total.correct++; // ...then the entire question was correct
		} // end if correct
	}; // end for i
}  // end tally()

function feedback() {
/* +=============================================-===========================================+
   | Based upon both the feedbackLocation and feedbackMatrix, display the appropriate        |
   | feedback or advance to the appropriate page.                                            |
   +=============================================-===========================================+ */
	switch (feedbackLocation) {
		case ('MultiFBOnPagePlusAdvance'):
			if (total.correct == total.possible) {
				pageAdvance('p');
			} // end if
			// *NO* break; (we also want the following to happen)
		case ('MultiFBOnPage'):
			for (i = 0; i < totalQ; i++) { // loop through each question to display fb per question
				switch (feedbackMatrix[i]) {
					case ('responseSpecific'):
						for (j = 0; j < responseMatrix[i].length; j++) {  // Loop through each item within the current question
							if (yesChange(responseMatrix[i][j])) {  // for selected responses...
								if (usesValue(i)) { // ...display appropriate feedback
									changeClassById ("fb" + i + "r" + responseMatrix[i][j].value, FBMultiOnPage);  
								} else {
									changeClassById ("fb" + i + "r" + j, FBMultiOnPage);
								} // end if usesValue
							} // end if checked
						} // end for j loop
						break; // end case responseSpecific
					case ('partial'):
						eligibleForPartial = testForPartial(i);  // check if partially correct or better
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							flicker ("fb" + i + "p", FBMultiOnPage, FBOff);
						} else if (eligibleForPartial == true) {  // partially correct
							flicker ("fb" + i + "part", FBMultiOnPage, FBOff);
						} else {  // must be wrong
							flicker ("fb" + i + "n", FBMultiOnPage, FBOff);
						}; // end if
						break;  // end case partial
					case ('normal'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							flicker ("fb" + i + "p", FBMultiOnPage, FBOff);
						} else {  // simply wrong
							flicker ("fb" + i + "n", FBMultiOnPage, FBOff);
						}  // end if correct
						break;  // end case normal
				}; // end switch feedbackMatrix[i]
			}; // end for i
			break;  // end case MultiFBOnPage and MultiFBOnPagePlusAdvance
		case ('FBOnPage'):
		case ('FBPosNext'):
			switch (feedbackMatrix[0]) {
				case ('responseSpecific'):
					if ((total.correct == total.possible) && (feedbackLocation == 'FBPosNext')) {
						pageAdvance('p');  // all correct and next page
					} else { // fb on current page
						// Loop through each item within the current question
						for (j = 0; j < responseMatrix[0].length; j++) {
							// only display feedback for selected responses
							if (yesChange(responseMatrix[0][j])) {
								if (usesValue(0)) { // ...display appropriate feedback
									flicker ("fb0r" + responseMatrix[0][j].value, FBOnPage, FBOff);
								} else {
									flicker ("fb0r" + j, FBOnPage, FBOff);
								} // end if usesValue
							} // end if checked
						} // end for j loop
					} // end if
					break; // end case responseSpecific
				case ('partial'):
					eligibleForPartial = testForPartial(0);  // check if partially correct or better
					if (total.correct == total.possible) {  // all correct...
						if (feedbackLocation == 'FBPosNext') {  // ...and fb on next page
							pageAdvance('p');
						} else { // ...and fb on current page
							flicker ("fb0p", FBOnPage, FBOff);
						} // end if feedbackLocation
					} else if (eligibleForPartial == true) {  // partially correct
						flicker ("fb0part", FBOnPage, FBOff);
					} else {  // simply wrong
						flicker ("fb0n", FBOnPage, FBOff);
					}; // end if
					break; // end case partial
				case ('normal'):
					if (total.correct == total.possible) {  // all correct...
						if (feedbackLocation == 'FBPosNext') {  // ...and fb on next page
							pageAdvance('p');
						} else {  // ...and fb on current page
							flicker ("fb0p", FBOnPage, FBOff);
						} // end if feedbackLocation
					} else { // simply wrong
						flicker ("fb0n", FBOnPage, FBOff);
					} // end if correct
					break; // end case normal
			}; // end switch feedbackMatrix[0]
			break;  // end case FBOnPage and FBPosNext
		case ('FBNextPage'):
			switch (feedbackMatrix[0]) {
				case ('responseSpecific'):
					for (i = 0; i < responseMatrix[0].length; i++) {
						if (yesChange(responseMatrix[0][i])) { // whichever is checked...
							pageAdvance(i); // triggers the fb
						}  // end if checked
					}  // end if i
					break; // end case responseSpecific
				case ('partial'):
					eligibleForPartial = testForPartial(0);
					// This is the partially correct allowed approach to displaying feedback
					if (total.correct == total.possible) {
						pageAdvance('p');
					} else if (eligibleForPartial == true) {
						pageAdvance('part');
					} else {
						pageAdvance('n');
					}; // end false condition; end of if
					break; // end case partial
				case ('normal'):
					if (total.correct == total.possible) {
						pageAdvance('p');
					} else {
						pageAdvance('n');
					}; // end false condition; end of if
					break; // end case partial
			} // end switch feedbackMatrix[0]
	}; // end switch feedbackLocation
} // end feedback()

function testForPartial(qNumber) {
/* +=============================================-===========================================+
   | Given a matrix of what elements were correctly answered, record total possible and      |
   | total correct for each question and for all questions.                                  |
   +=============================================-===========================================+ */
	// Loop through each item within the current question
	for (j = 0; j < responseMatrix[qNumber].length; j++) {
		// If they got the current item right and it was checked
		if ((correctMatrix[qNumber][j] == true) && (responseMatrix[qNumber][j].checked)) {
				return true; // they are eligible for partial correct credit.
		}; // end if true # 1
	}; // end for j loop
	return false; // must not be eligible for partial
} // end testForPartial

function pageAdvance(fileNameSuffix) {
/* +=============================================-===========================================+
   | Given the text that should be added to the filename, go to the URL by the new name.     |
   +=============================================-===========================================+ */
	window.location = (myFileName + "_" + fileNameSuffix + "f." + myFileExt);
} // end pageAdvance

function change(id, newClass) {
/* +=============================================-===========================================+
   | Given the ID attribute of the desired HTML element and the newClass to which the        |
   | element should change, do just that and assign newClass to the class property of the    |
   | the element ID.                                                                         |
   +=============================================-===========================================+ */
	//alert (id + " to class " + newClass); // good for debugging
	identity=document.getElementById(id);  // This is required for Mozilla-based browsers
	identity.className=newClass;  // Change the element's class to newClass
} // end change()

function setValue(elementID, newVal) {
/* +=============================================-===========================================+
   | Given the ID of the desired element and the new value for that element, apply the new   |
   | value to the element.                                                                   |
   +=============================================-===========================================+ */
	identity=document.getElementById(elementID);
	identity.value =  newVal;
} // end setValue
function newWindow(url) {
	window.open(url);
}
function explore (prefix, myNum, total, onClass, offClass) {
/* +=============================================-===========================================+
   | Given the ID attribute of the desired HTML element and the newClass to which the        |
   | element should change, do just that and assign newClass to the class property of the    |
   | the element ID.                                                                         |
   +=============================================-===========================================+ */
	for (i=0;i<total;i++) {
		currEl = prefix + i;
		changeClassById (currEl, offClass);
	}
	currEl = prefix + myNum;
	flicker (currEl, onClass, offClass);
} // end explore

function flicker (id, onClass, offClass) {
/* +=============================================-===========================================+
   | A fix for Netscape 6 in which content changing from display:none; to display:block;     |
   | does not appear.  The solution is to display the content, hide it, then display it      |
   | again, hence the name flicker.                                                          |
   +=============================================-===========================================+ */
	changeClassById (id, onClass);
	changeClassById (id, offClass);
	changeClassById (id, onClass);
} // end flicker
		
		
function changeClassById(id, newClass) {
/* +=============================================-===========================================+
   | Given the ID attribute of the desired HTML element and the newClass to which the        |
   | element should change, do just that and assign newClass to the class property of the    |
   | the element ID.                                                                         |
   +=============================================-===========================================+ */
	//alert (id + " to class " + newClass); // good for debugging
	identity=document.getElementById(id);  // This is required for Mozilla-based browsers
	identity.className=newClass;  // Change the element's class to newClass
} // end changeClassById()



function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_findObj(n, d) { //v4.0
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && document.getElementById) x=document.getElementById(n); return x;
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}


function MM_openBrWindow(theURL,winName,features) { //v2.0
  sample=window.open(theURL,winName,features); sample.window.focus();
}



function MM_goToURL() { //v3.0
  var i, args=MM_goToURL.arguments; document.MM_returnValue = false;
  for (i=0; i<(args.length-1); i+=2) eval(args[i]+".location='"+args[i+1]+"'");
}

function construction () {
     alert("This feature is currently under construction.");
}

function actionNotice() {
     alert("Click the SUBMIT button to see your feedback.");
}


function windowSize () {

var targetheight=460;
var targetwidth=775;

function winWid(){ return (ns4||ns6) ? window.innerWidth : document.body.clientWidth; }
function winHei(){ return (ns4||ns6) ? window.innerHeight : document.body.clientHeight; }
function centerX(){ return (ns4||ns6) ? parseInt((screen.width/2)-(width/2)) : parseInt((screen.availWidth/2)-(width/2)); }
function centerY(){ return (ns4||ns6) ? parseInt((screen.height/2)-(height/2)) : parseInt((screen.availHeight/2)-(height/2)); }
var ns4 = (document.layers) ? 1 : 0;
var ie4 = (document.all) ? 1 : 0;
var ns6 = (document.getElementById && !document.all) ? 1 : 0;
top.resizeTo(targetwidth,targetheight);
var width=winWid();
var height=winHei();
var difx=targetwidth-winWid();
var dify=targetheight-winHei();
width+=(difx*2);
height+=(dify*2);
top.resizeTo(width,height);
top.moveTo(centerX(),centerY());

}




function glossaryplatformDetect()
{
  if(navigator.appVersion.indexOf("Win") != -1)
  {
    MM_openBrWindow('glossary/index.cfm','whatever1','toolbar=no,location=no,status=no,menubar=no,resizable=no,width=550,height=375');
  }
  else if(navigator.appVersion.indexOf("Mac") != -1)
  {
    MM_openBrWindow('glossary/index.cfm','whatever1','toolbar=no,location=no,status=no,menubar=no,resizable=no,width=535 ,height=375');
  }
  else alert("Other");
}


function libraryplatformDetect()
{
  if(navigator.appVersion.indexOf("Win") != -1)
  {
    MM_openBrWindow('library/index.cfm','whatever1','toolbar=no,location=no,status=no,menubar=no,resizable=no,width=550,height=375');
  }
  else if(navigator.appVersion.indexOf("Mac") != -1)
  {
    MM_openBrWindow('library/index.cfm','whatever1','toolbar=no,location=no,status=no,menubar=no,resizable=no,width=535 ,height=375');
  }
  else alert("Other");
}
