/*
Class: Test Answers

Overview: Test Answers Overview
The Test Answers collection of functions takes values defined on each page or defaulted in the testanswers.js file as the parameters by which a page's interactive elements are analyzed and feedback is displayed.

All forms to be analyzed should be tagged with the following code

(start code)

<form action="javascript:testanswers()" class="taForm"> 

(end code)

Additionally, a script block should be included in the head, indicating the values for each of the required parameters.  See examples below.

Parameters:

	feedbackLocation - (Feedback Location Indicator) Indicated by storing a value in the feedbackLocation variable. This value indicates what feedback should appear where for a given interaction.
	pageFeedbackType - (Page Feedback Type) Indicated by storing a value in the pageFeedbackType variable. This value indicates the type of feedback that can be applied to the entire page. This is intended to supply a cummulative feedback for a page of multiple questions, however it may be possible to emulate the feedback for a single question via the page-wide feedback.
	qTypeMatrix - (Question Type Indicator) The question type for each question is stored in the qTypeMatrix array.
	feedbackMatrix - (Feedback Type Indicator) The feedback type for each question is stored in the feedbackMatrix array.
	answerStrings - (Correct Response String)The correct answers for each question are stored in the answerStrings array.

Main Functions:

	<testanswers>; <validateForm>; <resetFeedback>; <unvalidatedForm>; <allAreAnswered>; <isAnswered>; <findCorrects>; <usesValues>; <isCorrectByState>; <isCorrectByVal>; <markCorrects>; <yesChange>; <tally>; <feedback>; <testForPartial>; <pageAdvance>; <setValue>; <explore>; <flicker>; <changeClassById>; <arrayConcat>

Example Usages:
(start example)

One question with four radio buttons, with normal feedback located on the same page 
as the LA:      

      <script type="text/javascript">                                                  
         feedbackLocation = "FBOnPage";                                                
         pageFeedbackType = "none";                                                    
         qTypeMatrix = ["singlesel"];                                                  
         feedbackMatrix = ["normal"];                                                  
         answerStrings = ["1|0|0|0"];                                                  
      </script>
	  
(end)

(start example)

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:

      <script type="text/javascript">                                                  
         feedbackLocation = "FBPosNext";                                               
         pageFeedbackType = "none";                                                    
         qTypeMatrix = ["text","text"];                                                
         feedbackMatrix = ["normal","normal"];                                         
         answerStrings = ["hi,high","lo,lo"];                                          
      </script>  
	  
(end)

(start example)

A response-specific FB single-select question with normal page-wide feedback, a 
partial FB multi-select question, and a drop-down with two possible answers:

      <script type="text/javascript">                                                  
         feedbackLocation = "FBOnPage";                                                
         pageFeedbackType = "normal";                                                  
         qTypeMatrix = ["singlesel","multisel","dd"];                                  
         feedbackMatrix = ["responseSpecific","partial","normal"];                     
         answerStrings = ["0|1|0|0","1|1|0|1|0","78,80"];                              
      </script>

(end)

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.
 	2.2.04  2004.04.21  JEM - Added displayXOK variable to allow option to not call the noteCorrects() function, if not desired.  <explore()> function enhanced to allow reset of all explored elements.
 	2.2.05  2004.04.30  JEM - Modified the <resetFeedback()> function to scan for only 'div' and 'p' elements, rather than '*' elements, in order to fully support IE 5.x, which does not understand '*'. Added the <arrayConcat()> function.                                  |
 	2.2.06  2004.05.04  JEM - Recommented.  Changed logic that calculates the URL of a FB page to drop "_la" if it is present in the current URL before appending "_pf", etc.  Added support for the MultiFBOnPagePlusPageFB FB Location Indicator. 
 	2.2.07  2004.05.17  JEM - Added feedback type of none.  Added parameter for page-wide feedback, thus removing MultiFB* as a FB Location Indicator.
 	2.2.08  2004.05.28  JEM - Fixed logic flaw in <feedback()> for FBOnPage lacking break.
 	2.3.00  2004.08.27  JEM - Externalized variables so that no params are passed into <testanswers()>, rather variables are explicitly declared on the page; other variables declared, so they too can be over-ridden; added ability to declare URLs for FB pages; added functionality that only analyzes those form elements that are classed as taFormClass's value; added support for question feedback "single" and type "singleselgroup".  No longer compatable with 2.2.xx series, hence the 2.3.00.
 	2.3.01  2004.12.15  JEM - Added support for layered feedback.
	2.3.02  2005.01.21  JEM - Defined a series variables which allows the branching logic to handle different pf page URL calculations per series.
	2.3.03  2005.04.28  YB - Added <renderFeedback> function to allow a jump to element feature when neccessary 
 	2.3.04  2005.08.10  JEM - Changed renderFeedback to use scrollIntoView; ensured the responseMatrix did not contain Flash elements to fix a bug in IE.  Added TriU-specific code.
	2.3.05  2006.04.12  JEM - Modified <yesChange()> function to accurately not style radio  buttons that had values (not common).  Added question level reporting functionality via functions <feedback> and <questionLevelReporting> and the enableQuestionLevelReporting variable.  Added ability to skip elements within a form via a skipElClass variable and an update to <buildResponseMatrix> function.  Declared answerStrings to avoid JS warnings. 
	2.3.06  2006.05.23  JEM - Corrected logic flaw for partial page-wide feedback within <pageFeedback()>. 
	2.3.07	2006.06.21	ALP	- Added support for AEC in <pageAdvance>; added <msgrActivityCorrect> support for partial feedback in <feedback>.
	2.3.08	2006.07.05	JEM	- Added "feedback" as a trigger class for scrollIntoView method in <renderFeedback>.
	2.3.09	2006.08.15	JEM	- Added <msgrPageCorrect> and relevant support to <pageFeedback>; added <msgrTestAnswersComplete>.
	2.3.10	2006.09.14	JEM	- Added support for 'posOnly' feedback type.
	2.3.11	2006.10.19	ALP	-	Changed starting at line 974 of <feedback> to check whether a response specific question was answered correctly. If so, it now calls <msgrPageCorrect> appropriately.  Only works for non <usesValue> questions.


Variable: feedbackLocation 

	Feedback Location Indicator.  Indicated by storing a value in the feedbackLocation variable. This value indicates what feedback should appear where for a given interaction. 

Possible Values:

	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 learning activity 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.  URL of destination page is [URL of current page] - [file extension] - ["_la" (if present)] + ["_pf"] + [file extension] 
	FBNextPage - All feedback appears on another page.  Feedback applies to the LA as a whole.  URL of destination page is [URL of current page] - [file extension] - ["_la" (if present)] + ["_pf"|"_nf"] + [file extension]
	MultiFBOnPage - *DROPPED AS OF v2.2.07* 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 - *DROPPED AS OF v2.2.07* 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.  URL of destination page is [URL of current page] - [file extension] - ["_la" (if present)] + ["_pf"] + [file extension]   
	MultiFBOnPagePlusPageFB - *DROPPED AS OF v2.2.07* 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.  At this time, such feedback is limited to only appear when the entire page has been answered correctly.

Variable: pageFeedbackType

	Page Feedback Type. Indicated by storing a value in the pageFeedbackType variable. This value indicates the type of feedback that can be applied to the entire page. This is intended to supply a cummulative feedback for a page of multiple questions, however it may be possible to emulate the feedback for a single question via the page-wide feedback.

Possible Values:

	normal - Requires that all questions are completely correct in order to display page-wode positive feedback.  All other situations display page-wide negative feedback. 
	partial - If all aspects of all of the questions on the page  are correct or incorrect, positive or negative feedback is displayed, respectively. If any one of the questions on the page are correct, the partial feedback is displayed.
	single - The same feedback is offered regardless of the response.
	none - No page-wide feedback should appear.
	
Array: qTypeMatrix

	Question Type Indicator. The question type for each question is stored in the qTypeMatrix array.

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)
	
Array: feedbackMatrix

	Feedback Type Indicator. The feedback type for each question is stored in the feedbackMatrix array.

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 - In this case, feedback corresponding to the selected option or options is/are displayed.
	single - The same feedback is offered regardless of the response.
	none - No question-specific feedback should appear.

Array: answerStrings

	Correct Response String. The correct answers for each question are stored in the answerStrings array.

Possible Values: 

	1 - To represent that the element should be selected or checked.
	0 - To represent that the element should NOT be selected or checked.
	1,0 - To represent that the element may be checked or not.
	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).
	guard (or other text) - To represent the correct text for a text box (not case sensitive).
	guard,gaurd,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).

Note:
	When a given question has multiple options (such as a radio button group), an additional pipe (|) is added, followed by the correct state for that option.

*/

/*
Global: answerMatrix
	array of answers for each question
	
Global: correctMatrix
	array of T/F values indiciating the correctness of each q item
	
Global: responseMatrix 
	will hold the forms[] array and its elements

Global: qTypeMatrix 
	array of question types for the page

Global: feedbackMatrix 
	array of feedback type indicators for each question

Global: pageFeedbackType 
	page-wide feedback type indicator
	
Global: feedbackLocation 
	page-wide feedback location indicator

Global: total 
	info regarding score totals

Global: total.perQPossible 
	array of possible correct per question

Global: total.perQCorrect 
	array of total correct per question

Global: totalQ 
	number of questions on the page

Global: TimeDelay 
	delay in milliseconds before fb appears

Global: FBMultiOnPage 
	class name for on state for MultiFBOnPage

Global: FBOnPage 
	class name for normal on state for FB

Global: FBOff 
	class name to hide FB

Global: myFileName 
	will hold URL up to the extension

Global: myFileExt 
	will hold the file extension

Global: skipElClass 
	class name for form elements to be ignored by testanswers

Global: enableQuestionLevelReporting 
	boolean of whether a string should be added to a "skipped" form field reflecting the correctness of each question.

Global: qlrMsgCorrect 
	Question level reporting correct message

Global: qlrMsgIncorrect 
	Question level reporting incorrect message

Global: answerStringDelimiter 
	the character that separates each answer in the answer string for each question

Global: multipleAnswerDelmiter 
	if one response can have multiple answers, this is the separator that is used
	
Global: qfbPrefix 
	the character string that begins the feedback DIVs

Global: responseIndicator 
	for response-specific feedback DIVs, this follows the the question number

Global: positiveIndicator
	positive feedback DIVs end with this

Global: partialIndicator 
	partial feedback DIVs end with this

Global: negativeIndicator 
	negative feedback DIVs end with this

Global: positiveUrlOverride 
	specify onpage to override the calculated URL for positive FB

Global: negativeUrlOverride 
	specify onpage to override the calculated URL for negative FB

Global: partialUrlOverride 
	specify onpage to override the calculated URL for partial FB

Global: pagePositiveFbId 
	ID for the page-wide positive feedback DIV

Global: pageNegativeFbId 
	ID for the page-wide negative feedback DIV

Global: pagePartialFbId 
	ID for the page-wide partial feedback DIV

Global: IDAppend 
	string to append to end of element ID that gets the style

Global: RespRight 
	class name for correct responses

Global: RespWrong 
	class name for incorrect responses

Global: taFormClass 
	class name of forms to be analyzed by testanswers

Global: feedbackTags 
	array of tags that could hold on-page feedback

Global: displayXOK 
	boolean of whether X and OK images should be applied. Default is true.  Locally override to false if desired.

Global: seriesName 
	series declaration: FitPro, PASS, Bronze, ALP, TriU are choices.

Global: answerStrings 
	2.3.05 Added to remove JS warnings.
*/

	var answerMatrix = new Array();  // 
	var correctMatrix = new Array();  // 
	var responseMatrix = new Array();  // 
	var qTypeMatrix = new Array();  // 
	var feedbackMatrix = new Array();  // 
	var pageFeedbackType;  // 
	var feedbackLocation;  // 
	var total = new Object();  // 
	total.perQPossible = new Array();  // 
	total.perQCorrect = new Array();  //
	var totalQ; // 
	var TimeDelay = 750;  // 
	var FBMultiOnPage = 'feedback'; // 
	var FBOnPage = 'feedback'; // 
	var FBOff = 'off'; // 
	var myFileName; // 
	var myFileExt; // 
	var skipElClass = "taSkip"; // 
	var enableQuestionLevelReporting = false; // 
	var qlrMsgCorrect = "Correct"; // 
	var qlrMsgIncorrect = "Incorrect"; // 
	var answerStringDelimiter = "|"; // 
	var multipleAnswerDelmiter = ","; // 
	var qfbPrefix = "fb"; // 
	var responseIndicator = "r"; // 
	var positiveIndicator = "p"; // 
	var partialIndicator = "part"; // 
	var negativeIndicator = "n"; // 
	var positiveUrlOverride = ""; // 
	var negativeUrlOverride = ""; // 
	var partialUrlOverride = ""; // 
	var pagePositiveFbId = "pagefbp"; // 
	var pageNegativeFbId = "pagefbn"; // 
	var pagePartialFbId = "pagefbpart"; // 
	var IDAppend = 'li'; // 
	var RespRight = 'RespRight'; // 
	var RespWrong = 'RespWrong'; // 
	var taFormClass = 'taForm'; // 
	var feedbackTags = ["p","div"]; // 
	var displayXOK = true; // 
	var seriesName = "aec"; // 
	var answerStrings; // 

/* 
Function: testanswers
	Outlines program flow for entire testanswers functionality.

Parameters:
	None passed in.  References global objects: testanswers.arguments; <totalQ>; document.forms; <displayXOK>; TimeDelay; <feedbackLocation>; 

Depends on:
	<getFileName>; <getFileExtension>; <buildResponseMatrix>; <splitArrayElements>; <resetFeedback>; <validateForm>; <findCorrects>; <tally>; <markCorrects>; <feedback>; 

Version History:
 	2.0.00  2003.08.31  JEM   - Initial version.
 	2.2.04  2004.04.21  JEM   - Added displayXOK variable to allow option to not call the noteCorrects() function, if not desired. 
 	2.2.06  2004.05.04  JEM   - Moved principle commenting block to top of file. 
 	2.3.00  2004.08.30  JEM   - Removed passed parameters, using global variables instead. Changed processing slightly to accomodate. 

*/

function testanswers () {
	myFileName = getFileName (window.location.toString()); // get the file name
	myFileExt = getFileExtension (window.location.toString()); // get the file extension
	buildResponseMatrix (document.forms,taFormClass); // create the response Matrix
	totalQ = responseMatrix.length; // calculate how many total questions there are
	answerMatrix = splitArrayElements(answerStrings,answerStringDelimiter); // build the
																		// answer matrix
	resetFeedback(); // turn off any existing feedback
	if (!validateForm()) return; // ...quit entirely if forms do not validate
	findCorrects(); // figure out what responses are correct
	tally(); // tally the corrects
	if (displayXOK) {markCorrects();}; // mark the corrects
	setTimeout("feedback()", TimeDelay); // display appropriate feedback
} // END TEST ANSWERS FUNCTION

/*
Function: splitArrayElements

	This function takes an array and a delimiter and parses each element of the array into another array of elements as delimited by the delimiter. 

	Parameters:

	An array of strings and a delimiter found within each array element.

Depends On:

	None

Version History:

	2.3.00  2004.08.26  JEM - Remnant of buildMatricies() reserved for answer matrix 
*/

function splitArrayElements (stringArray, delimiter) {


	var theMatrix = new Array();
	var i = 0;
	for (i = 0; i < stringArray.length; i++) {
		theMatrix[i] = stringArray[i].split(delimiter);
	}
	return theMatrix;
}

/*
Function: buildResponseMatrix

	This function loops through a given collection and takes any of the elements within the collection that are classed as classFlag and adds them to the <responseMatrix> array.  NOTE: attempting to return an array of [object HTMLCollection] crashes all Netscape-compatible browsers (not sure if such is a bug or according to JS spec).

Parameters: 

	A collection of DOM elements (typically document.forms) and the class of those elements that flags for analysis by testanswers.

Depends On:

	None

Version History: 

	2.3.00  2004.08.26  JEM  - Initial version.
	2.3.04  2005.08.10  JEM  - Added removal of non-form elements reported by the browser to be in the collection to counter a bug in IE where Flash elements are counted as form elements.
	2.3.05  2006.04.11  JEM  - Added condition to skip skipElClass elements.
*/

function buildResponseMatrix (collection, classFlag) {
	responseMatrix = new Array(); // must reset Array in event of resubmission
	var tempArray = new Array();
	var i = 0, j = 0;
	for (i = 0; i < collection.length; i++) { // loop through the collection
		if (collection[i].className.indexOf(classFlag) != -1) { // if the element contains the flag
			tempArray[i] = new Array();
			for (j = 0; j < collection[i].length; j++) { // loop through all elements of current form
				if ((collection[i].elements[j].type != "") && (collection[i].elements[j].className.indexOf(skipElClass) < 0)) { // don't allow IE to include Flash objects as part of our form collection
					tempArray[i][tempArray[i].length] = collection[i].elements[j]; // add our filtered elements to a temp array
				}
			}
			responseMatrix[responseMatrix.length] = tempArray[i]; // add our filtered array to the responseMatrix
		}
	}
}

/*
Function: getFileName

	This function analyzes the passed URL to parse it to return the extension. 

Parameters:

	theURL - array to hold parts of URL

Depends On:

	None

Version History:

	2.3.00  2004.08.26  JEM - Extracted from anonymous function to its own function. 
*/
function getFileName (theURL) {
	var theFileName = "";
	var theURLParts = new Array(); // array to hold parts of URL
	theURLParts = theURL.split('.'); // split it by the dots
	for (var i = 0; i < (theURLParts.length-1); i++) { // put back all but the last part
		theFileName += theURLParts[i] + "."; // also add a dot as the split() removed them
	} // end for i loop
	theFileName = theFileName.substring(0,(theFileName.length-1)); // take the last dot off
															    // that we added
	return theFileName;
}

/*
Function: getFileExtension
	This function analyzes the passed URL to parse it to return all but the extension. 

Parameters:
	theURL - array to hold parts of URL

Depends On:
	None

Version History:
	2.3.00  2004.08.26  JEM - Extracted from anonymous function to its own function.
*/
function getFileExtension (theURL) {
	var theFileExtension;
	var theURLParts = new Array(); // array to hold parts of URL
	theURLParts = theURL.split('.'); // split it by the dots
	theFileExtension = theURLParts[theURLParts.length-1]; // the last part is the file extension
	return theFileExtension;
} // end getFileExtension()

/*
Function: validateForm

	Calls a function that validates the form and calls another function if it is not.

Parameters:

	None

Depends On:

	<allAreAnswered>; <unvalidatedForm>;

Version History:

2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date. 
*/

function validateForm() {
	if (!allAreAnswered()) {
		unvalidatedForm ();
		return false;  // This ejects us from the remainder of the testanswers() function
	}; // end if
	return true;
} // end validateForm()

/*
Function: resetFeedback

	Finds all elements using reserved 'on' classes and turns them off.

Parameters:

	None passed in.  References global objects: document.elements; <FBOnPage>; <FBOff>; <FBMultiOnPage>;

Depends On:

	<changeClassById>;

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
 	2.2.05  2004.04.30  JEM - Replaced getting all elements for getting 'div' and 'p' elements as IE 5.5 did not support the '*' selector.
 	2.2.06  2004.05.04  JEM - Streamlined the code a bit.
 	2.3.00  2004.08.30  JEM - Restructured code to loop through array of elements, instead.
*/

function resetFeedback() {
	var els = new Array();
	var i = 0;
	var j = 0;
	for (i = 0; i < feedbackTags.length; i++) { // loop through possible feedback tags
		els = new Array(); // reset the els array
		els = document.getElementsByTagName(feedbackTags[i]); // grab the current els
		for (j = 0; j < els.length; j++) { // loop through the captured elements
		    // test to see if they are currently classed using reserved 'on' classes
			if ((els[j].className == FBOnPage) || (els[j].className == FBMultiOnPage)) {
				changeClassById (els[j].id, FBOff); // if so, turn them off			
			} // end if
		} // end for j
	}
}

/*
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). This function can be locally added to a page to customize these messages.

Parameters:

	None.  References global object: <totalQ>;

Depends On:

	None

Version History:
	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/

function unvalidatedForm() {
	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

	Loops through each question, calls <isAnswered> to analyze it.  Returns false if any question returns from <isAnswered> as false.  Otherwise returns true.

Parameters:

	None passed in.  References global objects: <totalQ>;

Depends On:

	<isAnswered>;
	
Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/

function allAreAnswered() {
	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

	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.

Parameters:

	currentQ - index of current question.  References global objects: <responseMatrix>; <qTypeMatrix>

Depends On:

	<usesValue>;
	
Version History

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	2.2.07  2004.05.18  JEM - Streamlined code by calling <usesValue> instead of evaluating such itself.
*/
function isAnswered(currentQ) {
	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 (usesValue(currentQ)) {
			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.

Parameters:

	None passed in.  References global objects: <totalQ>; <responseMatrix>; <answerMatrix>; <correctMatrix>;

Depends On:

	<isCorrectByVal>; <isCorrectByState>; <usesValue>;

Version History:
	
	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	2.3.00  2004.08.30  JEM - Forced currQCorrects to reinitalize each time this is run.
*/
function findCorrects () {
	var j; // counter
	var k; // counter
	var possAns = new Array(); // will hold possible answers
	//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(multipleAnswerDelmiter); // 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

	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. 

Parameters:

	None passed in.  References global objects: <qTypeMatrix>;

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	2.3.00  2004.08.30  JEM - Restructured to loop through array of value-type els.
*/

function usesValue(currentQ) {
	var boolUsesValue = false;
	var usesValueEls = ["text","dd","img"];
	for (var i = 0; i < usesValueEls.length; i++) {
		boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == usesValueEls[i]));
	}
	return boolUsesValue;
} // end usesValue

/* 
Function: isCorrectByState

	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 state was correct.

Parameters:

	None passed in.  References global objects: <responseMatrix>; possAns;

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function isCorrectByState(qNumber, eNumber, possAns) {
   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

	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 value was correct.

Parameters:

	None passed in.  References global objects: <responseMatrix>; possAns;

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function isCorrectByVal(qNumber, eNumber, possAns) {
	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: qCorrect

	Given the number of a question, return whether it was correctly answered or not.

Parameters:

	Question number.  References global objects: <total.perQPossible>; <total.perQCorrect>

Depends On:

	None

Version History:

	2.3.00  2004.08.30  JEM - Initial version.
*/
function qCorrect(qNum) {
	var boolQIsCorrect = false; // default to incorrect
	if (total.perQPossible[qNum] == total.perQCorrect[qNum]) { 
		boolQIsCorrect = true;
	}
	return boolQIsCorrect;
} // end qCorrect()

/* 
Function: markCorrects

	Given a matrix of what elements were correctly answered, mark the appropriate ones by changing the class of a corresponding element. 

Parameters:

	None passed in.  References global objects: <responseMatrix>; <qTypeMatrix>; <IDAppend>; <RespRight>; <RespWrong>; <correctMatrix>; <qCorrect>;

Depends On:

	<yesChange>; <changeClassById>;

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date. 
	2.3.00  2004.08.30  JEM - Replaced strings with variables; reorganized logics; added support for "singleselgroup". 
*/
function markCorrects() {
	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]; // set shortcut var
			if (yesChange(thisEl)) { // if one of the above was true
				switch (qTypeMatrix[i]) {
					case ('singleselgroup'):
						idToChange = thisEl.id.substring(0,thisEl.id.length - 1) + IDAppend;
						if (qCorrect(i)) {
							changeClassById(idToChange, RespRight);  // Change an element to the RespRight class
						} else {
							changeClassById(idToChange, RespWrong);  // Change an element to the RespWrong class
						}
						break;
					case ('img'):
						idToChange = thisEl.id + "r" + thisEl.value; // Special ID for image fb
						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
						break;
					default:
						idToChange = thisEl.id + IDAppend;  // Append to match the ID of the container LI
						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
						break;
				}
			}; // end if checked
		}; // end for j
	}; // end for i	
} // end markCorrects()

/* 
Function: yesChange

	Given the element in question, check a set of possible conditions that would qualify it as an element that should have local feedback (X and OK) applied to it.

Parameters:

	thisEl - a DOM reference to a form element on the page.

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	2.3.05  2006.04.11  JEM - Modified <yesChange()> function to accurately not style radio buttons that had values (not common).
*/
function yesChange(thisEl) {
	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.type != 'radio')) && (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.

Parameters:

	None passed in.  References global objects: <totalQ>; total.possible; total.correct; <total.perQPossible>; <total.perQCorrect>; <responseMatrix>; <correctMatrix>;  

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function tally() {
	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.  This function displays feedback per per question, with the exception of when the feedback location is set to FBNextPage, in which, if a question is also given a feedback type other than none, the page will advance.

Parameters:

	None passed in.  References global objects: <feedbackLocation>; total.correct; total.possible; <total.perQCorrect>; <total.perQPossible>; <FBOnPage>; <FBMultiOnPage>; <feedbackMatrix>; <responseMatrix>;

Depends On:

	<pageAdvance>; <changeClassById>; <yesChange>; <testForPartial>; <flicker>; <usesValue>; <pageFeedback>;

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
 	2.2.06  2004.05.04  JEM - Added support for MultiFBOnPagePlusPageFB feedbackLocation.
	2.3.00  2004.08.30  JEM - Replaced strings with variables; added support for 'single' feedback type;                                               |
	2.3.01  2004.12.15  JEM - Added support for layered feedback.
	2.3.03  2005.04.28  YB - Added <renderFeedback> function to allow a jump to element feature when neccessary
	2.3.04  2005.09.29  LBH - Added function <msgrActivityCorrect> function to allow tracking of question correctness simultaneous with feedback presentation.												
	2.3.05  2006.04.11  JEM - Added call to <questionLevelReporting>. 
	2.3.07	2006.06.21	ALP	- Added <msgrActivityCorrect> for partial feedback.
	2.3.10	2006.09.14	JEM	- Added support for posOnly feedback.
	2.3.12	2007.01.16	ALP - Added call to <msgrActivityCorrect> on posOnly FB when answer is incorrect.
	2.3.13	2007.01.16	ALP - Added call to <msgrActivityCorrect> when there is no feedback
*/
function feedback() {
	var i; // counter
	var j; // counter
	var eligibleForPartial; // boolean to indicate if current q qualifies for partial FB
	var fbStyleToUse = (totalQ == 1) ? FBOnPage : FBMultiOnPage; // If it is the only one, give it standard FB styles;
															// else styles for multiple questions on the page
	//for (i = 0; i < totalQ; i++) { // loop through each question to display fb per question
	for (i = (totalQ-1); i >= 0; i--) { // loop BACKWARDS through each question to display fb per question
		switch (feedbackLocation) {
			case ('FBPosNext'):
				if (total.correct == total.possible) {
					pageAdvance(positiveIndicator);  // all correct and next page
					break;
				}
				// *NO* break; (we also want the following to happen)
			case ('FBOnPage'):
				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
									renderFeedback (qfbPrefix + i + responseIndicator + responseMatrix[i][j].value, fbStyleToUse); 
									msgrActivityCorrect(true); 
								} else {
									renderFeedback (qfbPrefix + i + responseIndicator + j, fbStyleToUse);
									var myQuestion = answerStrings[i];
									var myQArray = myQuestion.split('|');
									if (myQArray[j] == '1' || myQArray[j] == '1,0' || myQArray[j] == '0,1') {
										msgrActivityCorrect(true);
									} else {
										msgrActivityCorrect(false);
									}
								} // 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
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
							msgrActivityCorrect(true);
						} else if (eligibleForPartial == true) {  // partially correct
							renderFeedback (qfbPrefix + i + partialIndicator, fbStyleToUse);
							msgrActivityCorrect(false);
						} else {  // must be wrong
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
							msgrActivityCorrect(false);
						}; // end if
						break;  // end case partial
					case ('posOnly'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
							msgrActivityCorrect(true);
						} else {
							msgrActivityCorrect(false);
						}
						break;
					case ('normal'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
							msgrActivityCorrect(true);
						} else {  // simply wrong
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
							msgrActivityCorrect(false);
						}  // end if correct
						break;  // end case normal
					case ('single'):
						renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
						break;
					case ('none'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							msgrActivityCorrect(true);
						} else {  // simply wrong
							msgrActivityCorrect(false);
						}  // end if correct
						break;
					case ('layered'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
						} else if ((testForPartial(i)) && (numChecked(i) > 1)) {  // partially correct
							renderFeedback (qfbPrefix + i + partialIndicator, fbStyleToUse);
						} else if (firstOneChecked(i) != -1) { // response specific for only one
							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
										renderFeedback (qfbPrefix + i + responseIndicator + responseMatrix[i][j].value, fbStyleToUse);  
									} else {
										renderFeedback (qfbPrefix + i + responseIndicator + j, fbStyleToUse);
									} // end if usesValue
								} // end if checked
							} // end for j loop
						} else { // negative fb
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
						}
						break;
				}; // end switch feedbackMatrix[i]
			break;  // end case FBOnPage and FBPosNext
		case ('FBNextPage'):
			switch (feedbackMatrix[i]) {
				case ('responseSpecific'): // this can only apply when there is only 1 question on the page, so assume as such
					for (j = 0; j < responseMatrix[0].length; i++) {
						if (yesChange(responseMatrix[0][j])) { // whichever is checked...
							pageAdvance(j); // triggers the fb
						}  // end if checked
					}  // end if i
					break; // end case responseSpecific
				case ('partial'): // this can only apply when there is only 1 question on the page, so assume as such
					eligibleForPartial = testForPartial(0);
					// This is the partially correct allowed approach to displaying feedback
					if (eligibleForPartial == true) { // all correct already handled
						pageAdvance(partialIndicator);
					} else {
						pageAdvance(negativeIndicator);
					} // end false condition; end of if
					break; // end case partial
				case ('normal'): // this can only apply when there is only 1 question on the page, so assume as such
					if (total.correct == total.possible) {
						pageAdvance(positiveIndicator);
					} else {
						pageAdvance(negativeIndicator);
					}; // end false condition; end of if
					break; // end case partial
				case ('single'):
					pageAdvance(positiveIndicator);
					break;
				case ('none'): // only when the question-specific feedback is set to none is the page allowed to evaluate it's feedback
					break;
				case ('layered'):
					if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
						pageAdvance(positiveIndicator);
					} else if ((testForPartial(i)) && (numChecked(i) > 1)) {  // partially correct
						pageAdvance(partialIndicator);
					} else if (firstOneChecked(i) != -1) { // response specific for only one
						for (j = 0; j < responseMatrix[i].length; j++) {  // Loop through each item within the current question
							if (yesChange(responseMatrix[i][j])) {  // for selected responses...
								pageAdvance(j); // triggers the fb
							} // end if checked
						} // end for j loop
					} else { // negative fb
						pageAdvance(negativeIndicator);
					}
					break;
			} // end switch feedbackMatrix[0]
		}; // end switch feedbackLocation
	}; // end for i
		
	if (enableQuestionLevelReporting) {questionLevelReporting();}; // 2006.04.11
	pageFeedback(); // call to handle page-wide feedback, if any
	msgrTestAnswersComplete(); // event at end of testanswers
	
} // end feedback()

/* 
Function: questionLevelReporting

	Adds correct/incorrect messages to reporter textboxes for display

To Do: 

	Flexibility to update innerHTML rather than only form fields; auto numbering of elements or even better dynamic insertion of elements

Parameters:

	None

Depends On:

	None

Version History:

	2006.04.12   JEM - Created.
*/
function questionLevelReporting() {
	var qlrEl, qlrMessage, j;
	for (var i=0; i<totalQ; i++) {
		j = i+1;
		if (document.getElementById("qlr"+j)) {
			if (total.perQCorrect[i] == total.perQPossible[i]) {
				qlrMessage = qlrMsgCorrect;
			} else {
				qlrMessage = qlrMsgIncorrect;
			}
			qlrEl = document.getElementById("qlr"+j);
			qlrEl.value = qlrMessage;
		}
	}
}

/* 
Function: numChecked

	Given an index to the matrix of what elements were correctly answered, return the total number checked. 

Parameters:

	qNumber - index for current question number.  References global objects: <responseMatrix>; <correctMatrix>;

Depends On:

	None

Version History:

	2.3.01  2004.12.15  JEM - Initial version and any changes undocumented to date. 
*/
function numChecked(qNumber) {
	var totalChecked = 0;
	// Loop through each item within the current question
	for (var j = 0; j < responseMatrix[qNumber].length; j++) {
		// If it was checked
		if ((responseMatrix[qNumber][j].checked)) {
				totalChecked++; // increment the total counter
		}; // end if checked
	}; // end for j loop
	return totalChecked;
} // end numChecked

/* 
Function: firstOneChecked

	Given an index to the matrix of what elements were correctly answered, return the first correctly checked item.  May consolidate with <isAnswered> in future.

Parameters:

	qNumber - index for current question number.  
	References global objects: <responseMatrix>; <correctMatrix>;

Depends On:

	None

Version History:

	2.3.01  2004.12.15  JEM - Initial version and any changes undocumented to date.
*/
function firstOneChecked(qNumber) {
	// Loop through each item within the current question
	for (var j = 0; j < responseMatrix[qNumber].length; j++) {
		// If it was checked
		if ((responseMatrix[qNumber][j].checked)) {
				return j; // return its index
		}; // end if true checked
	}; // end for j loop
	return -1; // none must have been checked
} // end firstOneChecked

/* 
Function: pageFeedback

	Based upon the feedback location and the page-wide feedback type indicator, display page-wide feedback or advance the page as appropriate.  

Parameters:

	None passed in.  References to global objects: <feedbackLocation>; total.correct; total.possible; <FBOnPage>; <FBOff>;

Depends On:

	<pageAdvance>; <flicker>; 

Version History:

	2.2.07  2004.05.17  JEM - Introduced.
	2.3.00  2004.08.30  JEM - Replaced strings with variables; added support for 'single' feedback type;
	2.3.06  2006.05.23  JEM - Corrected logic flaw for partial correct.
	2.3.09	2006.08.15	JEM	- Added <msgrPageCorrect> methods.
	2.3.10	2006.09.14	JEM	- Added support for posOnly feedback.
*/
function pageFeedback() {
	switch (feedbackLocation) {
		case ('FBPosNext'):
			if (total.correct == total.possible) {
				pageAdvance(positiveIndicator);  // all correct and next page
				break; // break now so other fb does not appear
			}
			// *NO* break; (we also want the following to happen)
		case ('FBOnPage'):
			switch (pageFeedbackType) {
				case ('partial'):
					if (total.correct == total.possible) {  // all correct
						renderFeedback (pagePositiveFbId, FBOnPage);
						msgrPageCorrect(true);
					} else if (total.correct > 0) {  // partially correct
						renderFeedback (pagePartialFbId, FBOnPage);
						msgrPageCorrect(false);
					} else {  // must be wrong
						renderFeedback (pageNegativeFbId, FBOnPage);
						msgrPageCorrect(false);
					}; // end if
					break;  // end case partial
				case ('posOnly'):
					if (total.correct == total.possible) {
						renderFeedback (pagePositiveFbId, FBOnPage);
						msgrPageCorrect(true);
					}
					break;
				case ('normal'):
					if (total.correct == total.possible) {
						renderFeedback (pagePositiveFbId, FBOnPage);
						msgrPageCorrect(true);
					} else {
						renderFeedback (pageNegativeFbId, FBOnPage);
						msgrPageCorrect(false);
					}
					break;
				case ('single'):
					renderFeedback (pagePositiveFbId, FBOnPage);
					msgrPageCorrect(true);
					break;
				case ('none'):
					break;
			} // end switch
			break;
		case ('FBNextPage'):
			switch (pageFeedbackType) {
				case ('partial'):
					if (total.correct > 1) {
						pageAdvance(partialIndicator);
					}
					// *NOTE* No break, we want the case for normal to ensue if we get this far
				case ('normal'):
					if (total.correct == total.possible) {
						pageAdvance(positiveIndicator);  // all correct and next page
					} else {
						pageAdvance(negativeIndicator); // if they are not all correct, it must be wrong
					}
					break;
				case ('single'):
					pageAdvance(positiveIndicator);
					break;
				case ('none'):
					break;
			} // end switch
			break;
	}
} // end pageFeedback()

/* 
Function: testForPartial

	Given an index to the matrix of what elements were correctly answered, record total possible and total correct for each question and for all questions.

Parameters:

	qNumber - index for current question number.  References global objects: <responseMatrix>; <correctMatrix>; 

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function testForPartial(qNumber) {
	// Loop through each item within the current question
	for (var 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

	Given the string that should be added to the filename, go to the URL by the new name.

Parameters:

		advanceType - determines course of action.  
		References global objects <myFileName>; window.location; <myFileExt>; <positiveIndicator>; <negativeIndicator>; <partialIndicator>; <positiveUrlOverride>; <negativeUrlOverride>; <partialUrlOverride>;

Depends On:

	<modifyUrlString>

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	2.2.06  2004.05.04  JEM - Added logic to strip "_la" from the current URL, if present.
	2.3.00  2004.08.30  JEM - Completely revamped logic; function now parses parameter to determine action; added support for custom URLs.
	2.3.07	2006.06.21	ALP	- Added support for AEC courses.
*/
function pageAdvance(advanceType) {
	var urlToGoTo = window.location.toString();
	if ((seriesName == "FitPro") || (seriesName == "PASS") || (seriesName == "ALP") || (seriesName == "TriU") || (seriesName == "aec")) {
		var temp = new Array();
		temp = urlToGoTo.split("_");
		var lastpiece = temp[temp.length-1];
		tempNew = lastpiece.split(".");
		var myPageNumber = tempNew[0];
		pfPageNumber = myPageNumber*1 + 1;
		pfPageNumber = pfPageNumber + "";
		if (pfPageNumber.length == 1) {
			pfPageNumber = "0" + pfPageNumber;
		}
	} else {
		pfPageNumber = "_pf";
		myPageNumber = "_la";
	}
	switch (advanceType) {
		case (positiveIndicator) :
				if (positiveUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, pfPageNumber, myPageNumber);
				} else {
					urlToGoTo = positiveUrlOverride;
				}
			break;
		case (negativeIndicator) :
				if (negativeUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, "_nf", "");
				} else {
					urlToGoTo = negativeUrlOverride;
				}
			break;
		case (partialIndicator) :
				if (partialUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, "_pf", "");
				} else {
					urlToGoTo = partialUrlOverride;
				}
			break;
		default:
			alert ("Unable to advance to feedback.");
			break;
	}
	if (urlToGoTo != window.location) {
		window.location = (urlToGoTo);
	}
} // end pageAdvance

/* 
Function: modifyUrlString

	Given a file name, some characters to trim off the end, some characters to add to the end, and the file extension to tack back on, return a modified URL string.

Parameters:

	currentFileName - the name of the file name to modify
	currentExtension - the extension of the file name to modify
	fileAddOn - the text to append to the file name
	charsToTrim - the text to trim off the end of the file name

Depends On:

	None

Version History:

	2.3.00  2004.08.30  JEM - Initial version.
*/
function modifyUrlString (currentFileName, currentExtension, fileAddOn, charsToTrim) {
	if (currentFileName.substring((currentFileName.length-charsToTrim.length),(currentFileName.length)) == charsToTrim) {
		currentFileName = currentFileName.substring(0,(currentFileName.length-charsToTrim.length));
	}
	var theNewUrl = currentFileName + fileAddOn + "." + currentExtension;
	return theNewUrl;
}

/* 
Function: setValue

	Given the ID of the desired element and the new value for that element, assign the new value to the element. 

Parameters:

	elementID - the ID of the desired element
	newVal - the new value for that element

Depends On:

	None

Version History:

	2.2.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function setValue(elementID, newVal) {
	identity = document.getElementById(elementID);
	identity.value = newVal;
} // end setValue

/* 
Function: explore

	Turns off all elements with an id within a specified sequence, then turns on the desired element out of that sequence.

Parameters:

	prefix - the initial portion of the id's for a series of desired elements.
	myNum - of all of the elements within the series, the specific one to turn on.
	total - the total (upperBound) of the elements in the series.
	onClass - the class to assign to the element that should remain on.
	offClass - the class to assign to the elements to be turned off.

Depends On:

	<changeClassById>;
	
Example Usage:

(start code)

In the HTML: <div id="els1">...</div><div id="els2">...</div><div id="els3">...</div>

The JS call: explore('els',2,3,'fbon','fboff');     

assuming the second div is desired, and 'fbon' and 'fboff' were appropriately defined
in the CSS.

(end)

Version History:

	1.0.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
	1.0.01  2004.05.04  JEM - Added functionality to not turn any element back on (reset).
*/
function explore (prefix, myNum, total, onClass, offClass) {
	for (i = 1; i <= total; i++) {
		currEl = prefix + i;
		changeClassById (currEl, offClass);
	}
	if (myNum != '') {
		currEl = prefix + myNum;
		changeClassById (currEl, onClass);
	}
} // end explore

/* 
Function: flicker

	Is called in place of <changeClassById> as a preface to that function in order to fix a slight bug in 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.  Not necessary if not supporting NS6.

Parameters:

	id - id of the element in question. 
	onClass - the class to assign to the element to hide it.
	offClass - the class to assign to the elements to show it. 

Depends On:

	<changeClassById>; 
	
Example Usage:

(start code)

In the HTML: <div id="els1">...</div> 

The JS call: flicker ('els1','fbon','fboff'); 

assuming 'fbon' and 'fboff' were appropriatly defined in the CSS. 

(end)

Version History:

	1.0.00  2004.05.04  JEM - Initial version and any changes undocumented to date. 
*/
function flicker (id, onClass, offClass) {
	changeClassById (id, onClass);
	changeClassById (id, offClass);
	changeClassById (id, onClass);
} // end flicker

/* 
Function: changeClassById

	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. Rename of the change() function. 

Parameters:

	id - id of the element in question.
	newClass - the desired class to assign to the element. 

Depends On:

	None
	
Example Usage:

(start code)

In the HTML: <div id="els1">...</div> 

The JS call: changeClassById ('els1','fbon');

...asigns the class 'fbon' to the element with an id of 'els1'.

(end)

Version History:

	1.0.00  2004.05.04  JEM - Initial version and any changes undocumented to date. 
*/
function changeClassById(id, newClass) {
	//alert (id + " to class " + newClass); // good for debugging
	try {
		var identity=document.getElementById(id);
		identity.className=newClass;
	} catch (e) {
		alert ("changeClassById error: Error attempting to change the class of '" + id + "' to '" + newClass + "'. \n Error: " + e);
	}
} // end changeClassById()

/* 
Function: arrayConcat

	Given two arrays, returns one array containing the elements of the first followed by the elements of the second. Suggested enhancements: allow n arrays to be passed in and loop through the arguments and concatenate them all together; test for m-dimensions and concatenate across each.

Parameters:

	array1, array2 - two single-dimensional arrays.

Depends On:

	None
	
Example Usage:

(start code)

The JS call: foodArray = arrayConcat(fruitsArray, vegetablesArray);

(end)

Version History:

	1.0.00  2004.05.04  JEM - Initial version and any changes undocumented to date.
*/
function arrayConcat(array1, array2) {
	var returnArray = new Array();
	for (var i=0; i<array1.length; i++) {
		returnArray[returnArray.length] = array1[i];
	}
	for (var j=0; j<array2.length; j++) {
		returnArray[returnArray.length] = array2[j];
	}
	return returnArray;
}

function attachSubmitOnChange(){
	for (i=0; i < document.forms.length; i++){
		for (j=0; j < document.forms[i].elements.length; j++){
			document.forms[i].elements[j].onclick = function(){document.forms[0].submit();}
		}
	}
}

/* 
Function: renderFeedback

	Renders feedback by calling changeClassById and jumpToDiv only when neccessary. 

Parameters:

	elID - the ID of the element in question
	elClass - the class the element should adopt

Depends On:

	<changeClassById>; <jumpToDiv>

Version History:

	2.3.03  2005.04.28  YB - Initial version. 
	2.3.04  2005.08.10  JEM - Added 'barBox' to detection list for TriU.
	2.3.08	2006.07.05	JEM	- Added 'feedback' to detection list for Standardized Shell.
*/
function renderFeedback(elId,elClass){
	changeClassById(elId,elClass);
	if ((FBOnPage == 'on') || (FBOnPage == 'barBox') || (FBOnPage == 'layeron') || (FBOnPage == 'feedback')){
		jumpToDiv(elId);
	}
}

/* 
Function: jumpToDiv

	Ensures the selected element is within the view of the browser window.  

Parameters:

	elID - the ID of the element in question 

Depends On:

	None

Version History:

	2.3.03  2005.04.28  YB - Initial version.
	2.3.04  2005.08.10  JEM - Changed method to scrollIntoView to avoid URL manipulation, which interferes with the back button.
*/
function jumpToDiv(elId){
	document.getElementById(elId).scrollIntoView();
	//window.location='#'+elId;
}

/* 
Function: msgrActivityCorrect

	Designated "msgr" or messenger function to alert any necessary page elements of activity correctness. This messenger is sent during "normal" feedback calculations. Function will be further defined on page if it's information is needed.	

Parameters:

	arg - true/false argument to signify correctness of activity.
	
Depends On:

	None

Version History:

	2.3.04  2005.29.09  LBH - Initial version.
*/
function msgrActivityCorrect(arg){
}

/* 
Function: msgrPageCorrect

	Designated "msgr" or messenger function to alert any necessary page elements of page correctness. This messenger is sent during "normal" feedback calculations. Function will be further defined on page if it's information is needed.	

Parameters:

	arg - true/false argument to signify correctness of page.
	
Depends On:

	None

Version History:

	2.3.09  2006.08.15	JEM	- Initial version.
*/
function msgrPageCorrect(arg){
}

/* 
Function: msgrTestAnswersComplete

	Designated "msgr" or messenger function triggered upon the completion of testanswers' functions. Function will be further defined on page if it's information is needed.	

Parameters:

	arg - true/false argument to signify correctness of page.
	
Depends On:

	None

Version History:

	2.3.09  2006.08.15	JEM	- Initial version.
*/
function msgrTestAnswersComplete(){
}