var displayArrows = true;
var showPageNumber = true;
var disableBackButton = false;
var disableNextButton = false;
var MAX_LAYERS = 40;
var playaudio = false;



var ff_extension_click_AudioScriptBtn = "showInfoPopup( objEvent )";
var ff_extension_click_btnAudio = "toggleAudio( objEvent )";

if ( typeof document.body == 'undefined' ) { document.body = document.getElementsByTagName( 'body' )[0]; }

var bUseBackgroundSafeTransition = false;
// ---------------------------------------------------------------- Navigation  Functions ---------------------------------------------------------------- 


// If no arguments are passed this returns the name of the html file in the contentFrame. An optional 1st argument 
// specifies a different frame. An optional 2nd arguments specifices to retain the directory(ies) in which the page is 
// contained - e.g. getPageName( null, 1 ) will return directory/pagename. A 2 will return directory/directory/pagename, 
// etc.
function getPageName()
{
	var intNumberOfDirsUp = ( arguments[1] != null ) ? arguments[1] : 0 ;
	if(typeof parent.contentFrame != "undefined")
		return getFileName(  parent.contentFrame.document.location.href, intNumberOfDirsUp );
	else 
		return "";
}



function getPageNumber()
{
	var intPageNum = -1;	//this means page not found. If the for loop doesn't "find" something this will get returned.
	var strPageNameToFind = ( arguments[0] == null ) ? getPageName() : arguments[0];  // if no arguments are passed, getPageName is called to return the page currently in contentFrame
	for ( var i = 0; i < parent.contentFrame.localpages[parent.intTrack].length; i++ )
	{
		if ( strPageNameToFind == parent.contentFrame.localpages[parent.intTrack][i] )
		{
			intPageNum = i;
			break;
		}
	}
	return intPageNum;
}



function goPage( objEvent )
{
	if (objEvent != null)
		var intPageIncrement = ( typeof arguments[0] != 'number' ) ? objEvent.currentTarget.intPageInc : arguments[0] ;
	else
		var intPageIncrement = 1;
	if ( parent.bPageFullyLoaded )
	{
		var strPath = getPath( parent.contentFrame.location.href );
		var intCurrentPage = getPageNumber();
		var intNewPageNum =  intCurrentPage + intPageIncrement;
	}

	if ( ( intNewPageNum >= 0 ) &&  ( intNewPageNum <= parent.contentFrame.localpages[parent.intTrack].length - 1 ) )       // if we're at 1 we don't want to be able to go to "0" ("intro.html") or if at last page ( length-1) we don't want to go past it
	{
		strPath += parent.contentFrame.localpages[parent.intTrack][intNewPageNum];
		parent.contentFrame.terminatePage();
		parent.contentFrame.location.href = strPath;
	}
}


function pageComplete(strName)
{
	if((typeof parent.intTrack != "undefined")&&(parent.intTrack != null))	
	{
		if(typeof parent.aobjPageStatus=="undefined" || parent.aobjPageStatus == null || parent.aobjPageStatus.length==0)
			parent.initPageTracking();
	}
		
	if(typeof parent.aobjPageStatus!="undefined" && parent.aobjPageStatus != null)
	{
		for(nPage=0;nPage<localpages[parent.intTrack].length;nPage++)
		{
			if(parent.aobjPageStatus[nPage].strName == strName)
			{
				parent.aobjPageStatus[nPage].intStatus = 1;
				break;
			}								
		}
	}
}

function getPageCompleteNumber()
{
	var nPageCompletionCount=0;
	
	if(typeof parent.aobjPageStatus!="undefined" && parent.aobjPageStatus != null)
	{
		for(nPage=0;nPage<localpages[parent.intTrack].length;nPage++)
		{
			if(parent.aobjPageStatus[nPage].intStatus == 1) nPageCompletionCount++;
		}
	}
	
	return nPageCompletionCount;
}

function setModule(nModule)
{
	if (( typeof parent.resourceFrame != 'undefined' ) && (parent.nModule != nModule))
	{
		parent.nModule = nModule;
		if (parent.nModule > 0)
			writeCode( '<img src="images/resource_background' + nModule + '.gif" alt="" />', 'resourceCanvas', 'resourceFrame' );
		else
			writeCode( '<img src="images/resource_background0.gif" alt="" />', 'resourceCanvas', 'resourceFrame' );
	}
}

function goReplay()
{
	if ( parent.bPageFullyLoaded )
	{
		parent.contentFrame.terminatePage();
		parent.contentFrame.location.reload();
	}
}

function goPause()
{
	if ( parent.bPageFullyLoaded )
	{	
		objFramesetReference.pauseAnim_BackEnd();
		parent.navFrame.document.objPauseBtn.style.visibility = "hidden";
		parent.navFrame.document.objPlayBtn.style.visibility = "visible";						
	}
}

function goPlay()
{
	if ( parent.bPageFullyLoaded )
	{	
		objFramesetReference.resumeAnim_BackEnd();
		parent.navFrame.document.objPlayBtn.style.visibility = "hidden";
		parent.navFrame.document.objPauseBtn.style.visibility = "visible";		
	}
}


function useBackgroundSafeTransition( strState )
{
	if ( bUseBackgroundSafeTransition ) 		// I.E. versions < 5.5  have problems laying out a page when it's in a non-displayed frame
	{
		if ( typeof parent.frmSt == 'undefined' )
		{
			parent.frmSt = parent.document.getElementById( 'frmSt' );
		}	

		if ( parent.frmSt != null )
		{
			if ( navigator.appVersion.indexOf( 'MSIE' ) != -1 )
			{
				var fltVersion = parseFloat( navigator.appVersion.substring( navigator.appVersion.indexOf( 'MSIE' ) + 4, navigator.appVersion.length ) );
				if ( fltVersion <= 5.5 )
				{
					return;				// I.E. versions below 5.5 have a bug where they can't lay out a page entirely correctly into a 0 height frame	
				}	
			}			
			strFrameDimensions = ( strState == 'on' ) ? '75,0,434,36,*' : '75,434,0,36,*' ;
			parent.frmSt.rows = strFrameDimensions;
		}	
	}	
}



// strips off the end of a string up to the last forward slash. Optional argument repeats the process 
// x number of times.
function getPath( strLocation )
{
	var intNumberOfDirsUp = ( arguments[1] != null ) ? arguments[1] + 1 : 1 ;
	if ( intNumberOfDirsUp > 0 )
	{
		for ( var i = 0; i < intNumberOfDirsUp; i++ )
		{
			strLocation = strLocation.substring( 0, strLocation.lastIndexOf( '/' ) );
		}
	}
	return strLocation +  '/';
}



// An optional argument[1] specifices to retain the directory(ies) in which the file is 
// contained - e.g. getFileName( null, 1 ) will return directory/filename. A 2 will return 
// directory/directory/filename, etc.
function getFileName( strPath )
{
	if ( typeof strPath != 'undefined' )
	{
		var intNumberOfDirsUp = ( arguments[1] != null ) ? arguments[1] + 1 : 1 ;
		var strPath = stripUrlEndings( strPath );
		var strName = '';
		
		if ( intNumberOfDirsUp > 0 )
		{
			for ( var i = 0; i < intNumberOfDirsUp; i++ )
			{
				strName = strPath.substring(  strPath.lastIndexOf( '/' ), strPath.length ) + strName;
				strPath = strPath.substring( 0,  strPath.lastIndexOf( '/' ) );
			}
    			strName = strName.substring( strName.indexOf( '/' ) + 1, strName.length )	// strip the first slash
		}
	}   
	else
	{
		strName = 'undefined';
	}

	return strName;
}



function countDirsUp( strRelativePath )
{
	var intNumberOfDirsUp = 0;
	
	while ( strRelativePath.indexOf( '../' ) != -1 )
	{
		strRelativePath = strRelativePath.substring( strRelativePath.indexOf( '../' ) + 3, strRelativePath.length );
		intNumberOfDirsUp++;
	}	
	return intNumberOfDirsUp;
}	

// ==================================  Helper Functions =============================================

function stripUrlEndings( strURI )
{
	strURI = strURI.replace( /\?.*/, '' );	// ? followed by any characters
	strURI = strURI.replace( /\#.*/, '' );	// # followed by any characters
	return strURI;
}


function getSearchString()
{
	var strLocation = ( arguments[0] != null ) ? arguments[0] : document.location.href;
	return strLocation.replace( /.*\?/, '' );	// any characters that end with ?
}



function removeSearchString()
{
	var strLocation = ( arguments[0] != null ) ? arguments[0] : document.location.href;
	return strLocation.replace( /\?.*/, '' );	// ? followed by any characters
}



function updateSubPageName( strName )
{
	parent.strSubPageName = strName;	
}	



function menuLink( strPathFromCourseToFile )
{
	parent.contentFrame.terminatePage();
	document.location.href = pathToCourseRoot + strPathFromCourseToFile;
}	


// ------------------------------------------------------------------------------------------------------------------------------------------------------

function init()
{
	legacyInit();

	setBookMark();

	changeTitle( xml_UnitTitleText, xml_LessonTitleText );
	
	if(!disableNextButton) pageComplete(getPageName());
	
	showArrows();
	showPageNum();
	makeCustomButtons( 'click', true, false );
	makeCustomPopups( 'click' );
	

		// See if transcript exists
	if ((typeof parent != 'undefined') && (parent.contentFrame))
	{
		var objAnimControl = parent.contentFrame.document.getElementById( 'anim' );
		var objTranscript  = parent.contentFrame.document.getElementById( 'transcript' );
		if ( objTranscript == null )
		{
			disableTranscriptBtn();
			disableAudioBtn();
			disablePauseBtn();
		}
		else if ((!parent.audioEnabled) && ( objAnimControl == null ))
		{
			disablePauseBtn();
		}
		else
		{		
			setTranscriptVisibility();
			enableTranscriptBtn();
			enableAudioBtn();
			enablePauseBtn();
		}
	
	
		if (( typeof parent != 'undefined' ) && ( typeof parent.resourceFrame != 'undefined' ))
		{			
			parent.resourceFrame.writeMenuToFrame();
		}


		if ( playaudio )		
		{
			if(typeof audioBegin!="undefined" || audioBegin!=null)
			{
				loadAndPlayAudio( audioBegin );
			}
			else 
			{
				audioBegin="";					
			}
		}
		else
		{
			audioBegin="";
			//stopAudio();
		}
	}
}




function pageFullyLoaded()
{
	parent.bPageFullyLoaded = true;
	useBackgroundSafeTransition( 'off' );
}




function terminatePage()
{
	closeResources();
	stopAudio();

	useBackgroundSafeTransition( 'on' );
	parent.bPageFullyLoaded = false;
}


// --------------------------------------------  Dynamic content writing functions ---------------------------------

// If the course is not using a frameset, writeCode will ignore the framename passed to it
function changeTitle( strUnitTitleText, strLessonTitleText )
{
	if ( parent.resourceFrame )
	{
		writeCode( strUnitTitleText, 'UnitTitle', 'resourceFrame' );
	   //writeCode( strLessonTitleText, 'LessonTitle', 'resourceFrame' );
	}
}



// If the course is not using a frameset, writeCode will ignore the framename passed to it
function showPageNum()
{
	if ( parent.navFrame )
	{
		var intPageNumber = getPageNumber() + 1;
		var intTotalPages = localpages[parent.intTrack].length;

		if (localpages[parent.intTrack].length == 0)
		{
			var strText = "";
		}
		else
		{
			if ( localpages[parent.intTrack][0].indexOf( '/' ) != -1 )		// if the first page has ../
			{
				intTotalPages--;
				intPageNumber--;
			}
			if ( localpages[parent.intTrack][localpages[parent.intTrack].length-1].indexOf( '/' ) != -1 )	// if the last page has ../
			{
				intTotalPages--;
			}
			var strText = ( showPageNumber ) ? intPageNumber + ' of ' +intTotalPages : ' ';
		}
		writeCode( strText, 'PageNum', 'navFrame' );
	}
}





// ------------------------------------------- nagivation button functions --------------------------------------

function showArrows()
{
	if ( typeof parent.navFrame != 'undefined' )   // This allows the page to be run on it's own without being "in" the gui
	{
		var intCurrentPage = getPageNumber();
		if ( intCurrentPage < 1 )
		{
			parent.navFrame.document.objBackBtn.style.visibility = 'hidden';
			parent.resourceFrame.document.objDevBack.style.visibility = 'hidden';
		}
		else
		{
			parent.navFrame.document.objBackBtn.style.visibility = ( disableBackButton ) ? 'hidden' : 'visible';
			parent.resourceFrame.document.objDevBack.style.visibility = 'visible';
		}

		if ( intCurrentPage >= localpages[parent.intTrack].length - 1 )
		{
			parent.navFrame.document.objNextBtn.style.visibility = 'hidden';
			parent.resourceFrame.document.objDevNext.style.visibility = 'hidden';
		}
		else
		{
			parent.navFrame.document.objNextBtn.style.visibility = ( disableNextButton ) ? 'hidden' : 'visible';
			parent.resourceFrame.document.objDevNext.style.visibility = 'visible';
		}
	}
	else if  ( typeof parent.navFrame != 'undefined' )		   // This allows the arrows to be turned off on an individual screen basis
	{
			parent.navFrame.document.objBackBtn.style.visibility = 'hidden';
			parent.resourceFrame.document.objDevBack.style.visibility = 'hidden';
			parent.navFrame.document.objNextBtn.style.visibility = 'hidden';
			parent.resourceFrame.document.objDevNext.style.visibility = 'hidden';
	}
	if ( typeof parent.navFrame != 'undefined' )   // This allows the page to be run on it's own without being "in" the gui
	{
			parent.navFrame.document.objMenuBtn.style.visibility	  = 'visible';
			parent.navFrame.document.objCloseMenuBtn.style.visibility = 'hidden';
	}
}



function enableBackButton()
{
	disableBackButton = false;
	showArrows();
}



function enableNextButton()
{
	disableNextButton = false;
	showArrows();
}




function setBookMark()
{
	if ( typeof parent.strBookmark != 'undefined' )
	{
		parent.strBookmark = getPageName( null, countDirsUp( pathToCourseRoot ) );
	}

	if ( typeof parent.strSubPageName  != 'undefined' )
	{
		parent.strSubPageName = '';
	}
//	alert( 'parent.strBookmark = ' + parent.strBookmark );
}


function setTranscriptVisibility()
{
	//if (( parent.bTranscriptVisible != null ) && ( parent.bTranscriptVisible ))
	//{
	//	var objTranscript = document.getElementById( 'transcript' );
	//	objTranscript.style.display = 'block';
	//}
}

function disableTranscriptBtn()
{
	//parent.navFrame.document.objTranscriptBtn.style.visibility = "hidden";
}


function enableTranscriptBtn()
{
	//parent.navFrame.document.objTranscriptBtn.style.visibility = "visible";
}

function disableAudioBtn()
{
	parent.navFrame.document.objAudioBtn.style.visibility = "hidden";
}

function enableAudioBtn()
{
	parent.navFrame.document.objAudioBtn.style.visibility = "visible";
}


function disablePauseBtn()
{
	//parent.navFrame.document.objPauseBtn.style.visibility = "hidden";
	//parent.navFrame.document.objPlayBtn.style.visibility = "hidden";
}

function enablePauseBtn()
{
	//parent.navFrame.document.objPauseBtn.style.visibility = "visible";
	//parent.navFrame.document.objPlayBtn.style.visibility = "hidden";
}

// --------------------------------------------  audio related functions ----------------------------------

if (( typeof parent != 'undefined' ) && ( typeof parent.resourceFrame != 'undefined' ))
{
	var objFramesetReference = parent.resourceFrame;					// page in the contentFrame
}
else if (( opener != null ) && ( !opener.closed ) && ( typeof opener.parent != 'undefined' ) && ( typeof opener.parent.resourceFrame != 'undefined' ))
{
	var objFramesetReference = opener.parent.resourceFrame;					// page in a popup
}
else if (( typeof parent != 'undefined' ) && ( parent.opener != null ) && ( !parent.opener.closed ) && ( typeof parent.opener.parent != 'undefined' ) && ( typeof parent.opener.parent.resourceFrame != 'undefined' ))
{
	var objFramesetReference = parent.opener.parent.resourceFrame;			// page in a popup frameset
}
else
{
	var objFramesetReference = window;	// page on it's own (being previewed)
	document.write( '<script type="text/javascript">function toggleAudio_BackEnd() {}   function stopAudio_BackEnd() {}   function loadAndPlayAudio_BackEnd( ) {}   function getAudioFileName_BackEnd() {}</script>' );
	useCourseAudio = false;
}



function toggleAudio( objEvent )
{
//	var strUrlOfFile = ( arguments[0] != null ) ? arguments[0] : 'empty' ;	// make this passable as an argument if it's null, toggleAudio_BackEnd will know what to do
	var objImage = (( objEvent != null ) && ( typeof objEvent.currentTarget.src != 'undefined' )) ? objEvent.currentTarget : null ;
	
//	objFramesetReference.toggleAudio_BackEnd( strUrlOfFile, objImage );


	objFramesetReference.toggleAudio_BackEnd( arguments[1], objImage );
	//parent.audioEnabled = !parent.audioEnabled;
}



function stopAudio()
{
	objFramesetReference.stopAudio_BackEnd();
}



function loadAndPlayAudio( strNameOfFile )
{
	objFramesetReference.loadAndPlayAudio_BackEnd( strNameOfFile);
}



function getAudioName()
{
	objFramesetReference.getAudioFileName_BackEnd();
}


function flashLoaded()
{

}


function flashStarted()
{

}


function flashCompleted()
{

}


// -------------------------------------------- window related functions ---------------------------------


function popupWin( strURL )
{
	// We will open a window and save a pointer to it -attached to the resourceFrame if we're in the frameset, else to the current document
	// Before we open a window we will see if there is already a window open - using the pointer
	var objDocAttachedTo = ( typeof parent.resourceFrame != 'undefined' ) ? parent.resourceFrame.document : document ;
	// test to see if there is a reference to an existing window (document.hwinPopup) and if it is closed or not
	if (( typeof objDocAttachedTo.hwinPopup != 'undefined' ) && ( !objDocAttachedTo.hwinPopup.closed ))
	{

		var strCurrentUrl = objDocAttachedTo.hwinPopup.location.href;
		// if strUrl is relative, we need to compare against only part of the URL of the page currently open in the window

		var intNumberOfDirsUp = countDirsUp( strURL );
		if (( intNumberOfDirsUp > 0 ) || ( strURL.indexOf( '/' ) == -1 ))		// if there are no / then it is also relative and in the same directory
		{
			var strPartialPath = getPath( strCurrentUrl, intNumberOfDirsUp );
			strCurrentUrl = strCurrentUrl.substring( strPartialPath.length, strCurrentUrl.length );
		}
		var strPassedUrl = ( intNumberOfDirsUp > 0 ) ? strURL.substring( strURL.lastIndexOf( '../' ) + 3, strURL.length ) : strURL ;
		if ( unescape( strCurrentUrl ) == strPassedUrl )
		{
			objDocAttachedTo.hwinPopup.focus();
			return;
		}
		else
		{
			objDocAttachedTo.hwinPopup.close();
		}
	}

	var intScreenWidth = screen.width;
	var intScreenHeight = screen.height;

	var intZeroX = getScreenPositionX();
	var intZeroY = getScreenPositionY();

	var intStandardXOffset = 90;	// a nice default amount to have the popup offset from the main course window
	var intStandardYOffset = 80;	// a nice default amount to have the popup offset from the main course window


	var strWidth  = ( arguments[1] != null ) ? 'width=' + arguments[1] : 'width=500px' ;
	var strHeight = ( arguments[2] != null ) ? 'height=' + arguments[2] : 'height=405px' ;
	var strLeft  = ( arguments[3] != null ) ? 'left=' + ( intZeroX + arguments[3] ) + 'px' : 'left=' + ( intZeroX + intStandardXOffset ) +  'px' ;
	var strTop = ( arguments[4] != null ) ? 'top=' + ( intZeroY + arguments[4] ) + 'px': 'top=' + ( intZeroY + intStandardYOffset ) + 'px' ;
	var strResize = ( arguments[5] ) ? "yes" : "no";
	
//  With scrollbars=no it doesn't matter what you have applied css-wise, it won't have scrollbars. With scrollbars=yes then the css html{overflow:XXXX} will over-ride
	var options = 'toolbar=no,location=no,status=no,menubar=no,resizable=' + strResize + ',scrollbars=yes,' + strWidth + ',' + strHeight + ',' + strLeft + ',' + strTop ;

	objDocAttachedTo.hwinPopup = window.open( strURL, 'popup', options );
	objDocAttachedTo.hwinPopup.focus();
}



function closeWindow()
{
//	stopAudio();
	self.close();
}



function exitCourse()
{
	if ( confirm( 'Are you sure you want to exit the course?' ))
	{
		parent.ExitCoursetoLMS();
	}
}



// ------------------------------ Activity related functions ----------------------------------------------

function getActItemByNumber( intItemNumber )
{
	// loop through until we find the activity item with the right button number to start
	for ( var i = 0; i < aobjActivityItems.length; i++ )
	{
		if ( aobjActivityItems[i].intItemNumber == intItemNumber )
		{
			return aobjActivityItems[i];
		}
	}
	return null;
}



function createArrayOfObjectsByPartialId( strElementID )
{
	var arrobjLayers = new Array();
	var j = 0;

	for ( var i = 0; i < MAX_LAYERS; i++ )
	{
		var objElement = document.getElementById( strElementID + i );
		if ( objElement != null )
		{
			arrobjLayers[j] = objElement;
			arrobjLayers[j].intArrayIndex = [j];
			j++;
		}
	}
	return arrobjLayers;
}



function createArrayOfActivityItems( strElementID, strClass )
{
	if ( strClass != null )
	{
		var nlClassItems = getElementsByClassName( strClass );
	}

	var arrobjLayers = new Array();
	var j = 0;

	for ( var i = 0; i < MAX_LAYERS; i++ )
	{
		for (  ; j < MAX_LAYERS; j++ )
		{
			var bHasContents = false;
			var objTempObject = new Object();

			var objUnknownElement = document.getElementById( strElementID + ( j + 1 ) );		// there are no btn0's
			if (( objUnknownElement != null ) && ( objUnknownElement.tagName.toLowerCase() == 'div' ))		// if it's a div it contains the "link"
			{
				objTempObject = objUnknownElement;
				bHasContents = false;
				var objImageArray = objUnknownElement.getElementsByTagName( 'img' );

				if (( objImageArray != null ) && ( typeof objImageArray != 'undefined' ) &&  ( objImageArray[0] != null ) && ( typeof objImageArray[0] != 'undefined' ))
				{
					objTempObject.objBtnImage = objImageArray[0];
					objTempObject.intItemNumber = objUnknownElement.id.substring( strElementID.length, objUnknownElement.id.length );
					objTempObject.objBtnImage.objActItem = objTempObject;
					bHasContents = true;
				}
			}
			else if ( objUnknownElement != null )	// assume its the image
			{
					objTempObject.objBtnImage = objUnknownElement;
					objTempObject.intItemNumber = objUnknownElement.id.substring( strElementID.length, objUnknownElement.id.length );
					objTempObject.objBtnImage.objActItem = objTempObject;
					bHasContents = true;
			}
			if ( strClass != null )
			{
//				objTempObject = objUnknownElement;
				var objTempLink = ( j < nlClassItems.length ) ? nlClassItems[j] : null;

				if (( objTempLink != null ) && ( typeof objTempLink != 'undefined' ))		//the null is for Opera
				{
					objTempObject.objLink = objTempLink;
					objTempObject.intItemNumber = ( j + 1 );			// the first link should hve an itemnumber of 1
					objTempObject.objLink.objActItem = objTempObject;
					bHasContents = true;
				}
			}

			if ( bHasContents )
			{
//				arrobjLayers[i] = new Object();
				objTempObject.intArrayIndex = i;
				objTempObject.bCompleted = false;
				arrobjLayers[i] = objTempObject;
				j++;
				break;
			}
			else if ( j == MAX_LAYERS - 1 )
			{
				return arrobjLayers;
			}
		}
	}
}



function getElementsByClassName( strClassNameToSearchFor )
{
	var arrNodes = new Array();
//	var nlAllNodes = document.getElementsByTagName( "*" );		unfortunately the * parameter does not appear to be supported by version 6 and 7 browsers
	var arrAllNodes = new Array();
	arrAllNodes = getAllNodes( document, arrAllNodes);

	var i = 0;
	for ( var j = 0; j < arrAllNodes.length; j++ )
	{
		if (( typeof arrAllNodes[j].className != 'undefined' ) && ( arrAllNodes[j].className.indexOf( strClassNameToSearchFor ) != -1 ))
		{
			arrNodes[i] = arrAllNodes[j];
			i++;
		}
	}
	return arrNodes;
}



function getAllNodes( thisNode, nlAllNodes )
{
	for ( var i = 0; i < thisNode.childNodes.length; i++ )
	{
		if ( thisNode.childNodes[i].childNodes.length != 0 )	// would have used hasChildNodes but both I.E. and Opera incorrectly expect hasChildNodes to be a function call hasChildNodes(), rather than a property.
		{
			var intNewIndex = nlAllNodes.length;
			nlAllNodes[intNewIndex] = thisNode.childNodes[i];
			nlAllNodes = getAllNodes( thisNode.childNodes[i], nlAllNodes );
		}
		else
		{
			var intNewIndex = nlAllNodes.length;
			nlAllNodes[intNewIndex] = thisNode.childNodes[i];
		}
	}
	return nlAllNodes;
}



function runExtensions( strEventType )
{
	strElementID = ( arguments[1] != null ) ? arguments[1] : '';
	if ( eval( "typeof ff_extension_" + strEventType + strElementID + " != 'undefined' " ) )
	{
		eval( eval( 'ff_extension_' + strEventType + strElementID ));
	}
}


// ------------------------------------- button/image related functions -------------------------------------------

// find any customPopup divs, activate their close buttons, and make the popup draggable
function makeCustomPopups( strEventType )  
{
	var arrAIPopupDivs = getElementsByClassName( 'customPopup' );	
	for ( var i = 0; i < arrAIPopupDivs.length; i++ )
	{
		var nlTemp = arrAIPopupDivs[i].getElementsByTagName( 'div' );
		for ( var j = 0; j < nlTemp.length; j++ )
		{
			if ( nlTemp[j].className == 'CPCloser' )
			{
				makeDraggable( nlTemp[j], null , null, arrAIPopupDivs[i] );
				var objCloserSpan = nlTemp[j].getElementsByTagName( 'span' )[0];
				objCloserSpan.addEventListener( strEventType, hideInfoPopup, false );
				break;
			}
		}
	}
}



function makeCustomButtons( strEventType, bUseRollover, bUseVisited )
{
	var bCustomBtnPresent = false;
	var nlCustomBtnElements = getElementsByClassName( 'customBtn' );	// probably container divs but might be the images themselves

	for ( var i = 0; i < nlCustomBtnElements.length; i++ )
	{	
		if ( eval( "typeof ff_extension_" + strEventType + "_" + nlCustomBtnElements[i].id  + " != 'undefined' " ) )
		{
			makeButton( nlCustomBtnElements[i], strEventType, runCustomButton, bUseRollover, bUseVisited );
			nlCustomBtnElements[i].strExtension = eval( 'ff_extension_' + strEventType + "_" + nlCustomBtnElements[i].id );
		}
	}
}


function runCustomButton( objEvent )
{
	if ( typeof objEvent.currentTarget.strExtension != 'undefined' )
	{
		eval( objEvent.currentTarget.strExtension );
	}
	else
	{
		eval( objEvent.currentTarget.parentNode.strExtension );
	}
}



// function makeButton
// uContainingDivOrObj can be a div object, an id for a div, or an image object. If it is a div or id for a div,
// it will be searched and the first img found will be the img that is button-ized
function makeButton( uContainingDivOrObj, strEventType, objFunction )
{
	bUseRollover = ( arguments[3] != null ) ? arguments[3]: true;
	bUseVisited = ( arguments[4] != null ) ? arguments[4]: false;
	strBtnFileName = ( arguments[5] != null ) ? arguments[5]: 'empty';

	if (( typeof uContainingDivOrObj == 'object' ) && ( uContainingDivOrObj.nodeName.toLowerCase() == 'img' ))
	{
		objBtn = uContainingDivOrObj;
	}
	else
	{
		if ( typeof uContainingDivOrObj == 'string' )
		{
			uContainingDivOrObj = document.getElementById( uContainingDivOrObj ); // make uContainingDivOrObj be the div object
		}
		if ( uContainingDivOrObj != null )
		{
			objBtn = uContainingDivOrObj.getElementsByTagName( 'img' )[0];
		}
		else
		{
			return;			// the item doesn't exist
		}
	}

	if ( typeof objBtn != 'undefined' )
	{
		objBtn.addEventListener( strEventType, objFunction, false );
		if ( bUseRollover )
		{
			initializeBtnRollover( objBtn, strBtnFileName );
		}
		if ( bUseVisited )
		{
			initializeBtnVisited( objBtn, strBtnFileName );
		}
		
		objBtn.className += ' active';
		return objBtn;
	}
}



function initializeBtnRollover( objBtn )
{
	objBtn.addEventListener( 'mouseover', rolloverBtn, false );
	objBtn.addEventListener( 'mouseout', rolloutBtn, false );

	if ( typeof objBtn.strInitialSrc == 'undefined' )	// it almost always will - except if the image is a png and we're in I.E. then the fixpng.htc needs to set this
	{
		objBtn.strInitialSrc = objBtn.src;
	}

	var strBtnName = (( arguments[1] != null ) && ( arguments[1] != 'empty' )) ? arguments[1] : objBtn.strInitialSrc.substring( objBtn.strInitialSrc.lastIndexOf( '/' ) + 1, objBtn.strInitialSrc.length ).replace( '_up', '_down' );
	objBtn.strInitial_HighlightSrc = objBtn.strInitialSrc.substring( 0, objBtn.strInitialSrc.lastIndexOf( '/' ) + 1 ) +  strBtnName;
}



function initializeBtnVisited( objBtn )
{
	objBtn.addEventListener( 'click', visitBtn, false );
	if ( typeof objBtn.strInitialSrc == 'undefined' )	// it almost always will - except if the image is a png and we're in I.E. then the fixpng.htc needs to set this
	{
		objBtn.strInitialSrc = objBtn.src;
	}

	var strBtnName = (( arguments[1] != null ) && ( arguments[1] != 'empty' )) ? arguments[1] : objBtn.strInitialSrc.substring( objBtn.strInitialSrc.lastIndexOf( '/' ) + 1, objBtn.strInitialSrc.length ).replace( '_up', '_visited' );
	objBtn.strVisitedSrc = objBtn.strInitialSrc.substring( 0, objBtn.strInitialSrc.lastIndexOf( '/' ) + 1 ) +  strBtnName;
}



function rolloverBtn( objEvent )
{
	objEvent.currentTarget.src = objEvent.currentTarget.strInitial_HighlightSrc;
}



function rolloutBtn( objEvent )
{
	objEvent.currentTarget.src = objEvent.currentTarget.strInitialSrc;
}



function visitBtn( objEvent )
{
	objEvent.currentTarget.strInitialSrc = objEvent.currentTarget.strVisitedSrc;		// in case we're also using rollovers
	objEvent.currentTarget.src = objEvent.currentTarget.strVisitedSrc;
}



// ---------------------------------- start DragNDrop ---------------------------------------------------

function makeDraggable( objObjectToDrag )
{
	objObjectToDrag.addEventListener( 'mousedown', startDrag, false );

	if ( arguments[3] != null )
	{
		objObjectToDrag.objDragObjectRef = arguments[3];
		objObjectToDrag = arguments[3];
	}
	else
	{
		objObjectToDrag.objDragObjectRef = objObjectToDrag;
	}

	objObjectToDrag.bIsDraggable = true;

	// for some of the functions we will need to have top, left, width, and zIndex directly in the style object, as opposed to accessing them through getComputedStyle
	objObjectToDrag.style.top = document.defaultView.getComputedStyle( objObjectToDrag, null ).top;
	objObjectToDrag.intOriginalTop = objObjectToDrag.style.top;
	objObjectToDrag.style.left = document.defaultView.getComputedStyle( objObjectToDrag, null ).left;
	objObjectToDrag.intOriginalLeft = objObjectToDrag.style.left;
	objObjectToDrag.style.width = document.defaultView.getComputedStyle( objObjectToDrag, null ).width;
	objObjectToDrag.style.zIndex = document.defaultView.getComputedStyle( objObjectToDrag, null ).zIndex;

	if ( arguments[1] != null )
	{
		objObjectToDrag.objStartDragExtendFunction = arguments[1];		// a function ref that startDrag will call
	}
	if ( arguments[2] != null )
	{
		objObjectToDrag.objEndDragExtendFunction = arguments[2];		// a function ref that startDrag will call
	}

	if ( typeof document.bListenersAdded == 'undefined' )	// so if there are multiple draggable objects on a page, these will only be added once (I.E. has performance problems otherwise)
	{
		document.addEventListener( 'mousemove', drag, false );
		document.addEventListener( 'mouseup', endDrag, false );
		document.onselectstart = function()
		{
			if ( document.objDrag != null )
			{
				return false;
			}
		};
		document.bListenersAdded = true;
	}
	document.objDrag = null;
}



function startDrag( objEvent )
{
	objDrag = objEvent.currentTarget.objDragObjectRef;
	runExtensions( 'mousedown', objDrag.intItemNumber );
	if (( typeof objDrag.bIsDraggable != 'undefined' ) && ( objDrag.bIsDraggable ))
	{
		objDrag.x = objEvent.clientX - parseInt( objDrag.style.left )
		objDrag.y = objEvent.clientY - parseInt( objDrag.style.top );
		objDrag.intOrigZIndex = objDrag.style.zIndex;

		if ( typeof objDrag.objStartDragExtendFunction != 'undefined' )
		{
			objDrag.objStartDragExtendFunction( objDrag );
		}
		document.objDrag = objDrag;
	}
}



function drag( objEvent )
{
	objDrag = document.objDrag;
	if ( objDrag )
	{
		objDrag.style.left = objEvent.clientX - objDrag.x + 'px';
		objDrag.style.top = objEvent.clientY - objDrag.y + 'px';
		objDrag.style.zIndex = "100";
	}
	return false;
}



function endDrag( objEvent )
{
	objDrag = document.objDrag;
	if ( objDrag )
	{
		objDrag.style.zIndex = objDrag.intOrigZIndex;

		if ( typeof objDrag.objEndDragExtendFunction != 'undefined' )
		{
			objDrag.objEndDragExtendFunction( objDrag );
		}
	}

	document.objDrag = null;
}

// ---------------------------------- end DragNDrop ---------------------------------------------------




function preloadActivityItemImages()
{
	var aObjImage1 = new Array();
	var aObjImage2 = new Array();
	var aObjImage3 = new Array();
	var aObjImage4 = new Array();
	var aObjImage5 = new Array();

	for ( var i = 0; i < aobjActivityItems.length; i++ )
	{
		if (( typeof useSwapGraphic != "undefined" ) && ( useSwapGraphic )  && ( eval( 'swapGraphic' + aobjActivityItems[i].intItemNumber != null )) && ( eval( 'typeof  swapGraphic' + aobjActivityItems[i].intItemNumber + ' != "undefined"' )) )
		{
			aObjImage1[i] = new Image();
			aObjImage1[i].src = eval( 'swapGraphic' + aobjActivityItems[i].intItemNumber );
		}

		if (( typeof useBtnInitial_MouseOver_Graphic != "undefined" ) && ( useBtnInitial_MouseOver_Graphic )  && ( eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Initial_MouseOver_Graphic' != null )) && ( eval( 'typeof btn' + aobjActivityItems[i].intItemNumber + '_Initial_MouseOver_Graphic  != "undefined"' )) )
		{
			aObjImage2[i] = new Image();
			aObjImage2[i].src = eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Initial_MouseOver_Graphic' );
		}

		if (( typeof useBtnVisited_Graphic != "undefined" ) && ( useBtnVisited_Graphic )  && ( eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Visited_Graphic' != null )) && ( eval( 'typeof btn' + aobjActivityItems[i].intItemNumber + '_Visited_Graphic != "undefined"' )) )
		{
			aObjImage3[i] = new Image();
			aObjImage3[i].src = eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Visited_Graphic' );
		}

		if (( typeof useBtnCurrent_Graphic != "undefined" ) && ( useBtnCurrent_Graphic ) && ( eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Current_Graphic' != null )) && ( eval( 'typeof btn' + aobjActivityItems[i].intItemNumber + '_Current_Graphic != "undefined"' )) )
		{
			aObjImage3[i] = new Image();
			aObjImage3[i].src = eval( 'btn' + aobjActivityItems[i].intItemNumber + '_Current_Graphic' );
		}
	}
}



function getTime()
{
	var dtStart = new Date();
	var StartSecs = dtStart.getTime();
	for ( var i = 0; i < 100000; i++ );
	var dtEnd = new Date();
	var EndSecs = dtEnd.getTime();
	waitTime = 10000 / ( EndSecs - StartSecs );
	
	return waitTime;
}



function checkTotalActivityCompletion()
{
	var bIsComplete = true;

	for ( var i = 0; i < aobjActivityItems.length; i++ )
	{
		if ( !aobjActivityItems[i].bCompleted )	// there is an item not finished
		{
			bIsComplete = false;	// activity is not done
			break;
		}
	}

	return bIsComplete;
}



function activityCompleted()
{
	pageComplete(getPageName());
	enableBackButton();
	enableNextButton();
}



// ===================================  course progress functions ==================================


function topicComplete( strName )
{
	if ( typeof parent.aobjCompletionStatus != 'undefined' )
	{
		for ( var i = 0; i < parent.aobjCompletionStatus.length; i++ )
		{
			if ( parent.aobjCompletionStatus[i].strName == strName )
			{
				parent.aobjCompletionStatus[i].intStatus = 1;
				break;
			}
		}
	}
	checkParentCompletion( strName );
	setCurrentMenuItem( strName );
	updateMenu();
}



function checkParentCompletion( strName )
{
	if (( strName.indexOf( 'Sub' ) != -1 ) && ( typeof parent.aobjCompletionStatus != 'undefined' ))		// parent.aobjCompletionStatus is check to see if running in frameset
	{
		strParentName = strName.substring( 0, strName.indexOf( 'Sub' ) );
		var bAllCompleted = true;
		
		for ( var i = 0; i < parent.aobjCompletionStatus.length; i++ )
		{
//alert( 'parent.aobjCompletionStatus['+i+'].strName = ' + parent.aobjCompletionStatus[i].strName + '\nparent.aobjCompletionStatus['+i+'].intStatus = ' + parent.aobjCompletionStatus[i].intStatus );						
			if (( parent.aobjCompletionStatus[i].strName.indexOf( strParentName + 'Sub' ) == 0 ) && ( parent.aobjCompletionStatus[i].intStatus == 0 )) 
			{
				bAllCompleted = false;
				break;				
			}
		}
//alert( 'so bAllCompleted = ' + bAllCompleted );
		if ( bAllCompleted )                                                                                                   
		{
			for ( var i = 0; i < parent.aobjCompletionStatus.length; i++ )
			{
				if ( parent.aobjCompletionStatus[i].strName == strParentName )
				{
					parent.aobjCompletionStatus[i].intStatus = 1;
//alert( 'parent.aobjCompletionStatus['+i+'].intStatus = ' + parent.aobjCompletionStatus[i].intStatus );					
					break;
				}
			}
		}	
	}
}


function setCurrentMenuItem( strSegmentName )
{
	intIndex =  strSegmentName.indexOf( 'Sub' );
	parent.strCurrentItem = ( intIndex != -1 ) ? strSegmentName.substring( 0, intIndex ) : strSegmentName;
	parent.strCurrentSubItem = strSegmentName;
}


function updateMenu()
{

	objMenu = parent.contentFrame.document.getElementById( 'menu' );
	if(typeof objMenu!="undefined" && objMenu != null)
	{
		//alert("updateMenu");

		var strCompletionCode = '';
		for ( var i = 0; i < parent.aobjCompletionStatus.length; i++ )
		{
			//if (parent.aobjCompletionStatus[i].nModule == parent.nModule)
			{
				objVar = 'v_' + parent.aobjCompletionStatus[i].strName;
				objValue = parent.aobjCompletionStatus[i].intStatus;
				//alert(objVar+"="+objValue);
				objMenu.SetVariable(objVar,objValue);
			}
		}

		//alert("Current Items:"+ parent.strCurrentItem + "," + parent.strCurrentSubItem + "," + strCompletionCode);
		objMenu.SetVariable("curItem",parent.strCurrentItem);
		objMenu.SetVariable("curSub",parent.strCurrentSubItem + strCompletionCode);
		objMenu.SetVariable("bStatusUpdate",true);
	}	
}


           
// =========================================================================================

function showInfoPopup( objEvent )
{
	var objBtn = objEvent.currentTarget;
	var strBtnID =  (( typeof objBtn.id != 'undefined' ) && ( objBtn.id != '' )) ? objBtn.id : objBtn.parentNode.id ; 	// if the img itself has the id or if it's containing div has the id
	var strLayerID = strBtnID.replace( 'Btn', 'Popup' );
	document.getElementById( strLayerID ).style.visibility = 'visible';
}
       

function hideInfoPopup( objEvent )
{
	objEvent.currentTarget.parentNode.parentNode.style.visibility = 'hidden';
}


// ----------------  resource popups -------------------------------------------

function showBlocker()
{
	if (( typeof document.objBlocker == 'undefined' )  || ( document.getElementById( 'blocker' ) == null ))
	{
		// create the blocker div and an image inside it - this div appears behind the resource 'popup' layer
		// and in front of the content.  When clicked, it closes (hides) the 'popup' layer.
		document.objBlocker = document.createElement( 'div' );
		document.objBlocker.id = 'blocker';
		document.objBlocker.onclick = closeResources;
		objBlockerImage = document.createElement('img');
		objBlockerImage.src = pathToCourseRoot + 'foundations/images/clearsmall.gif';
		objBlockerImage.className = 'blocker';
		document.objBlocker.appendChild( objBlockerImage );
		document.body.appendChild( document.objBlocker );
	}
	document.objBlocker.style.visibility = 'visible';
}



function hideBlocker()
{
	if (( document.objBlocker == null ) || ( typeof document.objBlocker == 'undefined' ))
	{
		document.objBlocker = document.getElementById( 'blocker' );
		if ( document.objBlocker != null )
		{
			document.objBlocker.style.visibility = 'hidden';
		}
	}
	else
	{
		document.objBlocker.style.visibility = 'hidden';
	}
}



function createResourceCloser( objResource )
{
	var objSpanCloser = document.createElement( 'span' );
	objResource.appendChild( objSpanCloser );
	objSpanCloser.innerHTML = 'X';
	objSpanCloser.className = 'resourceCloser popupclose'
	objSpanCloser.onclick = closeResources;
}



function closeResources()
{
	var objCourseMenu = parent.contentFrame.document.getElementById( 'coursemenu' )
	if (( objCourseMenu != null ) && ( objCourseMenu.style.visibility == 'visible' ))
	{
		toggleResourceButton( 'navFrame', 'Menu', 'closed' );		// if we can work out timing for animateFlashMenuClosed we can remove this, as animateFlashMenuClosed calls hideCourseMenu which contains this call
		animateFlashMenuClosed();
	}
	hideHelp();
}



function toggleResourceButton( strFrame, strBtnName, strState )
{

	strFrame = eval("parent." + strFrame);
	if ( strState == 'open' )
	{
		strFrame.document.getElementById( 'btnClose' + strBtnName ).style.visibility = 'visible';
		strFrame.document.getElementById( 'btn' + strBtnName ).style.visibility = 'hidden';
	}
	else
	{
		strFrame.document.getElementById( 'btn' + strBtnName ).style.visibility = 'visible';
		strFrame.document.getElementById( 'btnClose' + strBtnName ).style.visibility = 'hidden';
	}
}


// ------------------------  Help ---------------------------------------------------------------------------------------

function showHelp()
{
	closeResources();

	var objHelpDiv = document.getElementById( 'help' );
	if ( objHelpDiv == null )
	{
		objHelpDiv = document.createElement( 'div' );
		objHelpDiv.id = 'help';
		document.body.appendChild( objHelpDiv );
		objHelpDiv.innerHTML = 'A review of the course navigation will appear here.<br><br>';

		createResourceCloser( objHelpDiv );
	}

	showBlocker();
	objHelpDiv.style.visibility = 'visible';
	toggleResourceButton( 'navFrame', 'Help', 'open' );
}



function hideHelp()
{
	var objHelpDiv = document.getElementById( 'help' );
	if ( objHelpDiv == null )
	{
		return;		// the menu has not been created yet for this page
	}

	hideBlocker();
	objHelpDiv.style.visibility = 'hidden';
	toggleResourceButton( 'navFrame', 'Help', 'closed' );
}

// ----------------------------------  flash menu related ----------------------------------

function animateFlashMenuOpen()
{
	closeResources();
	showCourseMenu();
	var objFlashMenu = parent.contentFrame.document.getElementById( 'menu' );
	if ( objFlashMenu != null )
	{
		objFlashMenu.Play();
	}
}

function showCourseMenu()
{
	var objCourseMenu = document.getElementById( 'coursemenu' );
	if ( objCourseMenu != null )
	{
		showBlocker();
		objCourseMenu.style.visibility = 'visible';
		toggleResourceButton( 'navFrame', 'Menu', 'open' )
		//parent.navFrame.objCloseMenuBtn.style.visibility = "hidden";
	}
}



function animateFlashMenuClosed()
{
	var objFlashMenu = parent.contentFrame.document.getElementById( 'menu' );
	if ( objFlashMenu != null )
	{
		objFlashMenu.TGotoLabel( '/', 'closeMenu');
		objFlashMenu.Play();
	}
	// The flash will call hideCourseMenu()
}

function menuReady()
{
	updateMenu();
}


function hideCourseMenu()
{
	objCourseMenu = parent.contentFrame.document.getElementById( 'coursemenu' );
	if ( objCourseMenu != null )
	{
		objCourseMenu.style.visibility = 'hidden';
		hideBlocker();
			
		strFrame = eval("parent.navFrame");
		strFrame.document.objCloseMenuBtn.style.visibility = 'hidden';
		strFrame.document.objMenuBtn.style.visibility = 'visible';
	}
}


// ----------------------------------------    FF Extensions -------------------------------------

function showLayer( strElementID )
{
	strFramePart = ( arguments[1] != null ) ? 'parent.' + arguments[1] + '.' : '';
	var objElement = eval( strFramePart + "document.getElementById( '" + strElementID + "' )");
	objElement.style.visibility = 'visible';
}



function hideLayer( strElementID )
{
	strFramePart = ( arguments[1] != null ) ? 'parent.' + arguments[1] + '.' : '';
	var objElement = eval( strFramePart + "document.getElementById( '" + strElementID + "' )");
	objElement.style.visibility = 'hidden';
}

// --------------------------------------  qc/debug   -----------------------------------------------------

function showCheatSheet()
{
	if ( typeof bCheatSheet != 'undefined' )
	{
		bCheatSheet = ( typeof parent.bCheatSheet != 'undefined' ) ? parent.bCheatSheet : bCheatSheet ;
		if ( bCheatSheet )
		{
			if ( typeof objCheatSheet == 'undefined' )
			{
				document.objCheatSheet = document.createElement( 'div' );
				document.objCheatSheet.id = 'cheatsheet';
				document.body.appendChild( document.objCheatSheet );
				var strAnswers = '<strong>Answers:</strong><br>';
				strAnswers += createActivitySpecificCheatSheetAnswers();
				document.objCheatSheet.innerHTML = strAnswers;
			}
			else
			{
				document.objCheatSheet.style.visibility = 'visible';
			}
		}
	}
}

function showAudioScript()
{
	var objScript = document.getElementById( 'audioScript' );
	if ( objScript != null )
	{
		objScript.style.visibility = 'visible';
	}
}


function hideAudioScript()
{
	var objScript = document.getElementById( 'audioScript' );
	if ( objScript != null )
	{
		objScript.style.visibility = 'hidden';
	}
}
