var isCurrentlyDragging = false;
var ZDRG_Target;
var ZDRG_restoreProgressTracker;
var ZDBG_isCurrentlyDragging = false;
var ZDBG_diffX;
var ZDBG_diffY;

/**
 * @id ZENXMLHTTPObject
 * @param {Object} ZENXMLHTTPObject
 */
function ZENXMLHTTP(ZENXMLHTTPObject) {
	
	ZENDebug();
	
	// Public methods, variables.
	this.sendRequest = sendRequest;
	
	// Private Methods, variables.
	var requestObject	= false;
	var anURI			= ZENXMLHTTPObject.fragmentWithContentsOfFile;
	var aTargetID		= ZENXMLHTTPObject.loadsInto;
	var eventOnLoad		= ZENXMLHTTPObject.executesFunctionOnLoad;
	
	// Constructor method.
	if (typeof anURI != 'undefined' && anURI != null && typeof aTargetID != 'undefined' && aTargetID != null)
		sendRequest();

	/**
	 * Initiates a request for [anURI] to be inserted into [aTargetID] with [eventOnLoad] to be executed on success.
	 * @id sendRequest
	 * @constructor
	 * @param {String} anURIRequest
	 * @param {String} aTargetIDRequest
	 * @param {String} eventOnLoadRequest
	 * @method
	 */
	function sendRequest(anURIRequest,aTargetIDRequest,eventOnLoadRequest) {
		
		if (typeof anURIRequest != 'undefined' && anURIRequest != null)
			anURI = anURIRequest;

		if (typeof aTargetIDRequest != 'undefined' && aTargetIDRequest != null)
			aTargetID = aTargetIDRequest;

		if (typeof eventOnLoadRequest != 'undefined' && eventOnLoadRequest != null)
			eventOnLoad	= eventOnLoadRequest;

		if (window.XMLHttpRequest) {
			
			try {
				requestObject = new XMLHttpRequest();
			} catch(e) {
				requestObject = false;
			}
	
		} else if (window.ActiveXObject) {
			
			try {
				requestObject = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
	
				try {
					requestObject = new ActiveXObject("Microsoft.XMLHTTP");
				} catch(e) {
					requestObject = false;
				}
				
			}
			
		}
				
		if (requestObject) {
			requestObject.onreadystatechange = connectionStateChange;
			requestObject.open("GET", anURI, true);
			requestObject.send("");
		}
			
	}

	/**
	 * Handles changes in connection state
	 * @id connectionStateChange
	 * @method
	 */
	function connectionStateChange() {
				
		this.connectionState = requestObject.readyState;
		
		if (requestObject.readyState == 4) {

			ZENDebug("Loaded '" + anURI + "' into '" + aTargetID.id + "'");

			// When using the file:// protocol we can't rely on .status to check if we actually have acquired the requested data.
			if (document.location.toString().substr(0,4) == "file") {

					aTargetID.innerHTML = requestObject.responseText;
					if (typeof eventOnLoad != 'undefined' && eventOnLoad != null)
						setTimeout(eventOnLoad,100);
					
			} else if (document.location.toString().substr(0,4) == "http") {

				if (requestObject.status == 200) {
					
					aTargetID.innerHTML = requestObject.responseText;
					if (typeof eventOnLoad != 'undefined' && eventOnLoad != null)
						setTimeout(eventOnLoad,100);
				}

			}
			
		} else {
			
			aTargetID.innerHTML = "loading...";
			
		}

	}
		
}



function ZENInitDebug() {

	if (DEBUG_ENABLE) {

		var debugConsoleDiv = document.createElement("div");
		debugConsoleDiv.id = "debugConsole";
		debugConsoleDiv.className = "debugConsole";

		var dragBarDiv = document.createElement("div")
		dragBarDiv.id = "dragBar";
		dragBarDiv.className = "dragBar";

		var dragBarTextNode = document.createTextNode("dragme");
		dragBarDiv.appendChild(dragBarTextNode);

		var debugConsoleContentsDiv = document.createElement("div")
		debugConsoleContentsDiv.id = "debugConsoleContents";
		debugConsoleContentsDiv.className = "debugConsoleContents";

		debugConsoleDiv.appendChild(dragBarDiv);
		debugConsoleDiv.appendChild(debugConsoleContentsDiv);
		document.getElementById("bodyContainer").appendChild(debugConsoleDiv);

		var obj = document.getElementById('debugConsole').style;
		document.getElementById('debugConsole').style.width = "1px";
		document.getElementById('debugConsole').style.height = "1px";

		_initDebugResize("600","120");

	}

}

function _initDebugResize(dstW,dstH) {

	var w = document.getElementById('debugConsole').style.width.substr(0,document.getElementById('debugConsole').style.width.toString().length - 2);
	var h = document.getElementById('debugConsole').style.height.substr(0,document.getElementById('debugConsole').style.height.toString().length - 2);
	
	var ratio = dstW / dstH;

	if (w < dstW || h < dstH) {
		
		w = (w < dstW) ? parseInt(w) + (10 * ratio) : dstW;
		h = (h < dstH) ? parseInt(h) + 10 : dstH;

		document.getElementById('debugConsole').style.width = w + "px";
		document.getElementById('debugConsole').style.height = h + "px";

		setTimeout("_initDebugResize(" + dstW + "," + dstH + ");",10);
		
	}
	
}



function ZENDebug(aParam,e) {
	
/*	if (!e)
		var e = window.event;

	if (typeof top.frames != 'undefined' && typeof top.frames['content'] != 'undefined' && typeof top.frames['content'].document != 'undefined ' && typeof top.frames['content'].document.getElementById('debugConsole') != 'undefined' && top.frames['content'].document.getElementById('debugConsole') != null) {


		if (typeof ZENDebug.caller != 'undefined' && ZENDebug.caller != null)
			var caller = ZENDebug.caller.toString().substring(ZENDebug.caller.toString().indexOf(" ") + 1,ZENDebug.caller.toString().indexOf("(")) + "();";
		else
			if (navigator.appName.indexOf("Netscape") == -1)
				var caller = "(void caller)";
			else
				var caller = "(FF void caller)";

		var timeStamp = new Date();
		var debugString = "[" + timeStamp.getHours() + ":" + timeStamp.getMinutes() + ":" + timeStamp.getSeconds() + "." + timeStamp.getMilliseconds() + "] ";

		var messageColor = (aParam != "") ? "blue" : "green";

		debugString += "<span style=\"color: blue;\"><a href=\"Javascript:alert(" + caller.substr(0,caller.indexOf("(")) + ");\">" + caller + "</a></span>";

		debugString += (typeof aParam != 'undefined' && aParam != "") ? " <span style=\"color: green;\">" + aParam + "</span>" : "";
		
		if (DEBUG_EVENT_TYPES && typeof event != 'undefined' && event != null && typeof event.type != 'undefined' && event.type != null)
			debugString += " [<span style=\"color: orange;\">" + event.type + "</span> event]";

		if (DEBUG_FUNCTION_OWNERS && typeof e != 'undefined' && e != null && typeof e.id != 'undefined' && e.id != null)
			debugString += " [owner id: " + " <span style=\"color: red;\"><a href=\"Javascript:ZENDebugIndicateElement('" + e.id + "');\">" + e.id + "</a></span>]";
		
		debugString += "<br>";

		if (DEBUG_LOG_CRONOLOGICALLY)
			top.frames['content'].document.getElementById('debugConsoleContents').innerHTML += debugString;
		else
			top.frames['content'].document.getElementById('debugConsoleContents').innerHTML = debugString + top.frames['content'].document.getElementById('debugConsoleContents').innerHTML;

		if (top.frames['content'].document.getElementById('debugConsoleContents').innerHTML.length > 1200)
			top.frames['content'].document.getElementById('debugConsoleContents').innerHTML = top.frames['content'].document.getElementById('debugConsoleContents').innerHTML.substr(0,1200);;


	}
	*/
}



function ZENDebugIndicateElement(anObjectId) {
		
	flashState = !flashState;
	
	if (flashState)
		top.document.getElementById(anObjectId).className = 'DEBUG_HILITE';
	else
		top.document.getElementById(anObjectId).className = 'DEBUG_LOLITE';
		
	if (flashes < 3)
		setTimeout("ZENDebugIndicateElement('" + anObjectId + "');",100);
	else
		flashes = 0;
	
	if (flashState)
		flashes++;

}


function ZENDebugClearConsole() {
		
	if (CLEAR_CONSOLE_ON_PAGELOAD && typeof top.document.getElementById('debugConsole') != 'undefined' && top.document.getElementById('debugConsoleContents') != null) {
		top.document.getElementById('debugConsoleContents').innerHTML += DEBUG_CONSOLE_INIT_MESSAGE;
	}
	
	ZENDebug();

}

function ZENDebugInitDrag(e) {
		
	if (typeof document.getElementById('dragBar') != 'undefined' && document.getElementById('dragBar') != null)
		document.getElementById('dragBar').onmousedown = ZENDebugStartDrag;
	
}

function ZENDebugStartDrag(e) {

	if (!e)
		var e = window.event;

	if (ZDBG_isCurrentlyDragging == false) {

		ZDBG_isCurrentlyDragging = true;

		ZDBG_diffX = e.clientX - document.getElementById('debugConsole').style.left.substr(0,document.getElementById('debugConsole').style.left.toString().length - 2);
		ZDBG_diffY = e.clientY - document.getElementById('debugConsole').style.top.substr(0,document.getElementById('debugConsole').style.top.toString().length - 2);

		document.onmousemove	= ZENDebugDrag;
		document.onmouseup		= ZENDebugEndDrag;
		
	}
	
}

function ZENDebugDrag(e) {
				
	if (ZDBG_isCurrentlyDragging == true) {
				
		if (!e)
			var e = window.event;
		
		document.getElementById('debugConsole').style.left = e.clientX - ZDBG_diffX;
		document.getElementById('debugConsole').style.top = e.clientY - 10;


	}

}

function ZENDebugEndDrag(e) {

	if (ZDBG_isCurrentlyDragging == true) {

		if (!e)
			var e = window.event;
	
		document.getElementById('debugConsole').style.left = e.clientX - ZDBG_diffX;
		document.getElementById('debugConsole').style.top = e.clientY - 10;
	
		ZDBG_isCurrentlyDragging = false;

	}

}

/**
 * Initializes automatic handling of mouseover and mouseout events on image tags
 * @id ZENInitEventHandling
 */
function ZENInitEventHandling() {

	ZENDebug();

	// Prevent unintended user drag events in HTA's
	var theLinksArray = document.getElementsByTagName('a');			// This to prevent unintended drags of links
	for (i = 0; i < theLinksArray.length; i++) {
		
		theLinksArray[i].ondrag			= ZENCancelDrag;
		theLinksArray[i].ondragend		= ZENCancelDrag;
		theLinksArray[i].ondragenter	= ZENCancelDrag;
		theLinksArray[i].ondragleave	= ZENCancelDrag;
		theLinksArray[i].ondragover		= ZENCancelDrag;
		theLinksArray[i].ondragstart	= ZENCancelDrag;
		theLinksArray[i].ondrop			= ZENCancelDrag;

	}

	var theImagesArray = document.getElementsByTagName('img');		// This to prevent unintended drags of images (imagemaps in particular).
	for (i = 0; i < theImagesArray.length; i++) {
		
		theImagesArray[i].ondrag		= ZENCancelDrag;
		theImagesArray[i].ondragend		= ZENCancelDrag;
		theImagesArray[i].ondragenter	= ZENCancelDrag;
		theImagesArray[i].ondragleave	= ZENCancelDrag;
		theImagesArray[i].ondragover	= ZENCancelDrag;
		theImagesArray[i].ondragstart	= ZENCancelDrag;
		theImagesArray[i].ondrop		= ZENCancelDrag;

	}

	var theImageArray = document.images;
	var anImageStateArray = new Array("reg", "over","dis");			// define states that each button can enter

	for (i = 0; i < theImageArray.length; i++) {

		if (document.images[i].name.substring(0,4) == "ZBTN") {
	
			var theImageName = document.images[i].name;	

			for (j = 0; j < anImageStateArray.length; j++) {

				eval(theImageName + "_" + anImageStateArray[j] + " = new Image()");
				eval(theImageName + "_" + anImageStateArray[j] + ".src = '" + document.images[i].src.substring(0,document.images[i].src.lastIndexOf("/")) + "/" + theImageName.substring(5,theImageName.length) + "_" + anImageStateArray[j] + "." + document.images[i].src.substring(document.images[i].src.lastIndexOf(".") + 1,document.images[i].src.length) + "';");

			}

			document.getElementById(theImageName).onmouseover	= ZENImageStateHandler;
			document.getElementById(theImageName).onmouseout	= ZENImageStateHandler;
			document.getElementById(theImageName).onclick 		= ZENImageStateHandler;
	
			if (eval("typeof " + theImageName + "_RetainsHighlitedState") != 'undefined') {
				eval("document." + theImageName + ".src = " + theImageName + "_over.src;");
			} else {
				eval(theImageName + "_RetainsHighlitedState = false;");
			}

		}
				
	}

}

/**
 * Used by ZENInitEventHandling to cancel (unintended user initiated) drag and drop events in .hta files
 * @id ZENCancelDrag
 * @param {Object} e
 * @see ZENInitEventHandling
 */
function ZENCancelDrag(e) {

	if (!e)
		e = window.event;
	
	e.returnValue = false;
	
}

/**
 * Handles user initiated keyboard events
 * @id ZENKeyboardEventHandler
 * @param {Object} aConstructorEventObject
 */
function ZENKeyboardEventHandler(aConstructorEventObject) {

	var kbdEventObject = {attachTo:null, executesFunction:null, withKeyCode:null };

	var eventStack = new Array();
	var numberOfEvents = 0;

	this.registerEvent = registerEvent;

	// Conditional constructor method
	if (typeof aConstructorEventObject != 'undefined' && aConstructorEventObject != null)
		registerEvent(aConstructorEventObject);

	/**
	 * Registers a keyboard event
	 * @id registerEvent
	 * @param {Object} anEventObject
	 * @constructor
	 * @method
	 */
	function registerEvent(anEventObject) {
		
		eventStack[anEventObject.withKeyCode.toString()] = anEventObject.executesFunction;
				
		anEventObject.attachTo.onkeydown = delegate;

		try {
			anEventObject.attachTo.focus();			
		} catch(e) {
			ZENDebug(e);
		}

	}

	/**
	 * Delegates a previously registered event to a handler
	 * 
	 * This is a simple trampoline pattern which delegates the captured event to the handler previously registered in the eventStack array
	 * @id delegate
	 * @param {Object} e
	 * @method
	 */
	function delegate(e) {
		
		var aKeyPress = (!e) ? window.event.keyCode.toString() : e.which.toString();

		if (typeof eventStack[aKeyPress] != 'undefined' && eventStack[aKeyPress] != null) {
			
			eval(eventStack[aKeyPress]);
			ZENDebug("Delegated " + eventStack[aKeyPress]);

		}
		
	}

}

/**
 * Handles automatic handling of mouseover and mouseout events on image tags
 * @id ZENImageStateHandler
 * @param {Object} e
 * @method
 */
function ZENImageStateHandler(e) {

	if (!e)
		var e = window.event;

	ZENDebug("",e.type);

	var target = ZENGetTargetElement(e);

	if (e.type == "mouseout") {

		if (typeof eval(target.name + '_RetainsHighlitedState') == 'undefined' || eval(target.name + '_RetainsHighlitedState') == false) {
	
			imageStateDescription = "_reg";

		} else {

			imageStateDescription = "_over";

		}

	} else if (e.type == "mouseover") {

		imageStateDescription = "_over";

	} else if (e.type == "click") {

		// This space non intentionally left non blank

	}

	try {

		document.getElementById(target.name).src = eval(target.name + imageStateDescription + ".src");

	} catch(err) {
		
		// Raising this exception is a good thing(tm) since it would otherwise result in an error with a popup.
		// There is currently no other way to circumvent it.
		ZENDebug("exception raised: " + err);
		
	}

}

/**
 * Returns the object that recieved an event (ie. onclick or likewise).
 * @id ZENGetTargetElement
 * @param {Object} e
 * @return {Object}
 * @method
 */
function ZENGetTargetElement(e) {
	
//	ZENDebug("",e);

	var target;

	if (e.target)
		target = e.target;
	else if (e.srcElement)
		target = e.srcElement;

	if (typeof target != 'undefined' && target != null && typeof target.nodeType != 'undefined' && target.nodeType != null)
		if (target.nodeType == 3) // defeat Safari bug
			target = target.parentNode;

	return target;
	
}

/**
 * Cross-browser return of Flash Object or embed tag
 * @id ZENGetFlashObject
 * @param {Object} aFlashObject
 * @return {Object}
 * @method
 */
function ZENGetFlashObject(aFlashObject) {
	
	if (typeof document.embeds != 'undefined' && document.embeds != null && eval("typeof document.embeds." + aFlashObject) != 'undefined' && eval("document.embeds." + aFlashObject) != null)
		return eval("document.embeds." + aFlashObject);
	else if (typeof document.getElementById(aFlashObject) != 'undefined' && document.getElementById(aFlashObject) != null)
		return document.getElementById(aFlashObject);
	
}


/**
 * Convenience getter method that returns the current progress of a flash movie
 * @id ZENGetFlashPreloadProgress
 * @param {Object} aFlashId
 * @return {Object}
 * @method
 */
function ZENGetFlashPreloadProgress(aFlashId) {
	
	return parseInt((ZENGetFlashLoadedFrames(aFlashId) * 100) / ZENGetFlashTotalFrames(aFlashId) - 1);
	
}


/**
 * Convenience getter method that returns the total number of frames in a flash movie
 * @id ZENGetFlashTotalFrames
 * @param {Object} aFlashId
 * @return {Object}
 * @method
 */
function ZENGetFlashTotalFrames(aFlashId) {
	
	return ZENGetFlashObject(aFlashId).TGetProperty("/",5);

}


/**
 * Convenience getter method that returns the total number of loaded frames in a flash movie
 * @id ZENGetFlashLoadedFrames
 * @param {Object} aFlashId
 * @return {Object}
 * @method
 */
function ZENGetFlashLoadedFrames(aFlashId) {
	
	return ZENGetFlashObject(aFlashId).TGetProperty("/",12);
	
}



/**
 * @id ZENApplyMediaController
 * @classDescription Convenience class that sets up a media controller object and loads a flash into it.
 * @param {Object} constructor
 * @return {Object} media controller instance
 */
function ZENApplyMediaController(constructor) {
	
	// constructor
	// .controllerPrefix
	// .loadsInto
	// .loadSWF
	// .behaviour
	// .width
	// .height

	var so = new SWFObject("swf/dummy.swf", constructor.controllerPrefix + "_object", constructor.width.toString(), constructor.height.toString(), "5");
	so.addParam("wmode","transparent");
	so.addParam("base","");
	so.write(constructor.loadsInto);
	
	vc = new ZENMediaController({controllerWithPrefix: constructor.controllerPrefix, withAutoPlayBehaviour: constructor.behaviour});
	vc.LoadMedia(constructor.loadSWF);

	var foo = new ZENKeyboardEventHandler({attachTo: document, executesFunction: "vc.TogglePlayBack();", withKeyCode: 32});
	
}

/**
 * @classDescription initializes an handles a mediacontroller object throughout the lifetime of the current page.
 * @id ZENMediaController
 * @param {Object} ZENMediaControllerConstructor
 */
function ZENMediaController(ZENMediaControllerConstructor) {
		
	// ZENMediaControllerConstructor
	// .controllerWithPrefix: (string) four letter unique identifier (ie. "ZVID")
	// .withAutoPlayBehaviour: (int, const) refer to config.js for valid entries
	// .withParentForControls: (Optional, DOM Object) Specify a parent DOM object for the controls. If null then document.body is used.
	
	ZENDebug();
	
	// Public methods
	this.LoadMedia			= LoadMedia;
	this.UnloadMedia		= UnloadMedia;
	this.PlayMedia			= PlayMedia;
	this.PauseMedia			= PauseMedia;
	this.RewindMedia		= RewindMedia;
	this.ForwardMedia		= ForwardMedia;
	this.TrackMedia			= TrackMedia;
	this.PlayBackProgress	= PlayBackProgress;
	this.PreloadProgress	= PreloadProgress;
	this.TogglePlayBack		= TogglePlayBack;
	this.IsPlaying			= IsPlaying;

	this.AutoPlayBehaviour	= ZENMediaControllerConstructor.withAutoPlayBehaviour;

	// Private variables
	var FileName;
	var ProgressTracker;
	var controllerPrefix = ZENMediaControllerConstructor.controllerWithPrefix;
	var controllerObjectId = controllerPrefix + "_object";
	var theImageArray = document.images;
	var anImageStateArray = new Array("reg", "over", "dis");			// define states that each button can enter
	var isCurrentlyDragging = false;
	
	// Constructor
	DeployControls();

	for (i = 0; i < theImageArray.length; i++) {

		if (theImageArray[i].name.substring(0,4) == controllerPrefix) {
						
			var theImageName = document.images[i].name;	

			for (j = 0; j < anImageStateArray.length; j++) {

				eval(theImageName + "_" + anImageStateArray[j] + " = new Image()");
				eval(theImageName + "_" + anImageStateArray[j] + ".src = '" + MAIN_GFX_DIR + "/" + theImageName.substring(5,theImageName.length) + "_" + anImageStateArray[j] + "." + document.images[i].src.substring(document.images[i].src.lastIndexOf(".") + 1,document.images[i].src.length) + "';");

				document.getElementById(theImageName).onmouseover	= ImageStateHandler;
				document.getElementById(theImageName).onmouseout	= ImageStateHandler;

				document.getElementById(theImageName).onclick = function(e) { MediaStateHandler(e); ImageStateHandler(e); }

				if (eval("typeof " + theImageName + "_RetainsHighlitedState") != 'undefined' && eval(theImageName + "_RetainsHighlitedState") != null  && eval(theImageName + "_RetainsHighlitedState") == true) {
					document.getElementById(theImageName).src = eval(theImageName + "_over.src");
					alert(document.getElementById(theImageName).src);
				} else {
					eval(theImageName + "_RetainsHighlitedState = false;");
				}

			}

		}
		
	}

	if (SHOW_DRAG_BAR)
		document.getElementById(controllerPrefix + "_dragArea").onmousedown = DragHandler;
		document.getElementById(controllerPrefix + "_dragArea").style.width = (DRAGBAR_WIDTH - 4) + "px";
		document.getElementById(controllerPrefix + "_progressBarContainer").style.width = (DRAGBAR_WIDTH) + "px";

	function DeployControls() {
		
		var mediaControllerControls = document.createElement("div");
		mediaControllerControls.id = "mediaControllerControls";
		mediaControllerControls.className = "mediaControllerControls";
	
		var videoPlayerBackground = document.createElement("div");
		videoPlayerBackground.className = "videoPlayerBackground";
		mediaControllerControls.appendChild(videoPlayerBackground);
		
		var mcRewind = document.createElement("img");
		mcRewind.id					= controllerPrefix + "_Rewind";
		mcRewind.name				= mcRewind.id;
		mcRewind.className			= mcRewind.id;
		mcRewind.src				= "gfx/Rewind_reg.jpg";
		mediaControllerControls.appendChild(mcRewind);
		
		var mcPlay = document.createElement("img");
		mcPlay.id					= controllerPrefix + "_Play";
		mcPlay.name					= mcPlay.id;
		mcPlay.className			= mcPlay.id;
		mcPlay.src					= "gfx/Play_reg.jpg";
		mediaControllerControls.appendChild(mcPlay);
	
		var mcPause = document.createElement("img");
		mcPause.id					= controllerPrefix + "_Pause";
		mcPause.name				= mcPause.id;
		mcPause.className			= mcPause.id;
		mcPause.src					= "gfx/Pause_reg.jpg";
		mediaControllerControls.appendChild(mcPause);
	
		var mcForward = document.createElement("img");
		mcForward.id				= controllerPrefix + "_Forward";
		mcForward.name				= mcForward.id;
		mcForward.className			= mcForward.id;
		mcForward.src				= "gfx/Forward_reg.jpg";
		mediaControllerControls.appendChild(mcForward);
	
		var progressBarPlaceholder			= document.createElement("div");
		progressBarPlaceholder.id			= controllerPrefix + "_progressBarPlaceholder";
		progressBarPlaceholder.className	= progressBarPlaceholder.id;
		
			var progressBarContainer				= document.createElement("div");
			progressBarContainer.id					= controllerPrefix + "_progressBarContainer";
			progressBarContainer.className			= "hidden";
			progressBarPlaceholder.appendChild(progressBarContainer);
	
			var progressBarBackground				= document.createElement("div");
			progressBarBackground.id				= controllerPrefix + "_progressBarBackground";
			progressBarBackground.className			= "hidden";
			progressBarPlaceholder.appendChild(progressBarBackground);
	
			var progressBar							= document.createElement("div");
			progressBar.id							= controllerPrefix + "_progressBar";
			progressBar.className					= "hidden";
			progressBarPlaceholder.appendChild(progressBar);
	
			var percentLoaded						= document.createElement("div");
			percentLoaded.id						= controllerPrefix + "_percentLoaded";
			percentLoaded.className					= "hidden";
			progressBarPlaceholder.appendChild(percentLoaded);
	
			var numericalProgressContainer			= document.createElement("div");
			numericalProgressContainer.id			= controllerPrefix + "_numericalProgressContainer";
			numericalProgressContainer.className	= "hidden";
			progressBarPlaceholder.appendChild(numericalProgressContainer);
	
			var progressMarker			= document.createElement("div");
			progressMarker.id			= controllerPrefix + "_progressMarker";
			progressMarker.name			= controllerPrefix + "_progressMarker";
			progressMarker.className	= "hidden";
			progressBarPlaceholder.appendChild(progressMarker);
	
			var dragArea				= document.createElement("div");
			dragArea.id					= controllerPrefix + "_dragArea";
			dragArea.name				= controllerPrefix + "_dragArea";
			dragArea.className			= controllerPrefix + "_dragArea";
			progressBarPlaceholder.appendChild(dragArea);
	
		mediaControllerControls.appendChild(progressBarPlaceholder);

		// Handle optional .withParentForControls constructor parameter 
		((typeof ZENMediaControllerConstructor.withParentForControls != 'undefined' && ZENMediaControllerConstructor.withParentForControls != null) ? ZENMediaControllerConstructor.withParentForControls : document.body).appendChild(mediaControllerControls)
		
	}

	

	/**
	 * Handles the initial stage of a drag-bar / scrubber event
	 * @id DragHandler
	 * @param {Object} e
	 */
	function DragHandler(e) {

		if (!e)
			var e = window.event;

		clearInterval(ProgressTracker);
		ProgressTracker = null;
		
		ZENGetFlashObject(controllerObjectId).StopPlay();

		if (!isCurrentlyDragging) {
			
			isCurrentlyDragging		= true;
			document.onmousemove	= PerformDrag;
			document.onmouseup		= EndDrag;
	
		}
	
	}
	
	
	/**
	 * Handles the actual dragging of a drag-bar / scrubber event
	 * @id PerformDrag
	 * @param {Object} e
	 * @return {BOOL}
	 */
	function PerformDrag(e) {
	
		// Note: only include ZENDebug(); here when absolutely necessary as it *will* hog 100% cpu time.
		// ZENDebug();
	
		if (isCurrentlyDragging) {
			
			if (!e)
				var e = window.event;
					
			var theXPos = e.clientX - parseInt(document.getElementById(controllerPrefix + "_progressMarker").style.width / 2);
	
			if (navigator.appName == "Microsoft Internet Explorer")
				theXPos -= 6;
			else if (navigator.appName == "Netscape")
				theXPos -= 6;
	
			theXPos = (theXPos < (DRAGBAR_MIN_X)) ? (DRAGBAR_MIN_X) : theXPos;
			theXPos = (theXPos > (DRAGBAR_MIN_X) + DRAGBAR_WIDTH) ? (DRAGBAR_MIN_X) + (DRAGBAR_WIDTH - 4) : theXPos;

			document.getElementById(controllerPrefix + "_progressMarker").style.left = theXPos - (DRAGBAR_MIN_X) + "px";

			// BEGIN live tracking

			var theProgressAfterDragging		= (theXPos - DRAGBAR_MIN_X) / DRAGBAR_WIDTH;
			var theTotalFrames					= ZENGetFlashTotalFrames(controllerObjectId);
			var theCurrentFrameAfterDragging	= parseInt(theTotalFrames * theProgressAfterDragging);
	
			ZENGetFlashObject(controllerObjectId).TGotoFrame("/",theCurrentFrameAfterDragging);

			// END live tracking
			
			return false;
	
		}

	}


	function EndDrag(e) {
		
		ZENDebug();
	
		if (!e)
			var e = window.event;
	
		if (isCurrentlyDragging) {
	
			var theXPos = e.clientX - parseInt(document.getElementById(controllerPrefix + "_progressMarker").style.width / 2);
	
			if (navigator.appName == "Microsoft Internet Explorer")
				theXPos -= 0;
			else if (navigator.appName == "Netscape")
				theXPos -= 6;

			document.getElementById(controllerPrefix + "_progressMarker").style.left = theXPos + "px";
	
			var theProgressAfterDragging		= (theXPos - DRAGBAR_MIN_X) / DRAGBAR_WIDTH;
			var theTotalFrames					= ZENGetFlashTotalFrames(controllerObjectId);
			var theCurrentFrameAfterDragging	= parseInt(theTotalFrames * theProgressAfterDragging);
	
			ZENGetFlashObject(controllerObjectId).TGotoFrame("/",theCurrentFrameAfterDragging);

			TrackMedia();

//			_launchMediaTracker();		
		
			if (typeof eval(controllerPrefix + "_Play_RetainsHighlitedState") != 'undefined' && eval(controllerPrefix + "_Play_RetainsHighlitedState"))
				PlayMedia();
					
			isCurrentlyDragging=false;
	
		}
	
	}

	
	
	
	function MediaStateHandler(e) {
	
		if (!e)
			var e = window.event;
	
		ZENDebug("",e.type);
	
		var target = ZENGetTargetElement(e);
	
		if (target.name.indexOf("Rewind") != -1) {
	
			RewindMedia();
	
		} else if (target.name.indexOf("Play") != -1) {
	
			PlayMedia();
	
		} else if (target.name.indexOf("Pause") != -1) {
	
			PauseMedia();
	
		} else if (target.name.indexOf("Forward") != -1) {
	
			ForwardMedia();
	
		}
	
	}


	function ImageStateHandler(e) {
	
		if (!e)
			var e = window.event;
	
		ZENDebug("",e.type);
	
		var target = ZENGetTargetElement(e);
		
		var thePreloadProgress = parseInt((ZENGetFlashLoadedFrames(controllerObjectId) * 100) / ZENGetFlashTotalFrames(controllerObjectId));
	
		if (e.type == "mouseout") {
	
			if (typeof eval(target.name + '_RetainsHighlitedState') == 'undefined' || eval(target.name + '_RetainsHighlitedState') == false) {
	
				if (target.name.indexOf("Forward") != -1) {
		
					imageStateDescription = (thePreloadProgress < 100) ?  "_dis" :  "_reg";
		
				} else {
		
					imageStateDescription = "_reg";
		
				}
	
			} else {
	
				imageStateDescription = "_over";
	
			}
	
		} else if (e.type == "mouseover") {
	
			if (target.name.indexOf("Forward") != -1) {
	
				imageStateDescription = (thePreloadProgress < 100) ? "_dis" : "_over";
	
			} else {
	
				imageStateDescription = "_over";
	
			}
	
		} else if (e.type == "click") {
	
			// This space non intentionally left non blank
	
		}
	
		document.getElementById(target.name).src = eval(target.name + imageStateDescription + ".src");
	
	}



	function LoadMedia(aFilename) {
		
		ZENDebug();

		try {
					
			ZENGetFlashObject(controllerObjectId).LoadMovie(0,aFilename + ((FORCE_FLASH_RECACHE) ? "?time=" + new Date().getTime() : ""));

			// Exception: PauseMedia() is too slow we call StopPlay() directly
			ZENGetFlashObject(controllerObjectId).StopPlay();
			PauseMedia();

		} catch(e) {
			
			ZENDebug("Exception raised in LoadMedia(): " + e);
			setTimeout("LoadMedia('" + aFilename + "');",500);
			return;
	
		}

		FileName = aFilename;

		if (SHOW_PROGRESS_BAR) {
			
			document.getElementById(controllerPrefix + "_progressBarContainer").className	= controllerPrefix + "_progressBarContainer";
			document.getElementById(controllerPrefix + "_progressBar").className			= controllerPrefix + "_progressBar";
			document.getElementById(controllerPrefix + "_percentLoaded").className			= controllerPrefix + "_percentLoaded";
			
			if (SHOW_DRAG_BAR)
				document.getElementById(controllerPrefix + "_progressMarker").className		= controllerPrefix + "_progressMarker";
			else
				document.getElementById(controllerPrefix + "_progressMarker").className		= "hidden";
			
		} else if (!SHOW_PROGRESS_BAR) {
	
			document.getElementById(controllerPrefix + "_progressBarContainer").className	= "hidden";
			document.getElementById(controllerPrefix + "_progressBar").className			= "hidden";
			document.getElementById(controllerPrefix + "_percentLoaded").className			= "hidden";
			document.getElementById(controllerPrefix + "_progressMarker").className			= "hidden";

		}

		if (SHOW_NUMERICAL_PROGRESS)
			document.getElementById(controllerPrefix + "_numericalProgressContainer").className = controllerPrefix + "_numericalProgressContainer";

		_launchMediaTracker();

		switch (this.AutoPlayBehaviour) {
			
			case AUTOPLAY_ALWAYS:
				PlayMedia();
				break;
				
			case AUTOPLAY_ON_FIRST_ENTRY:
				var start		= (aFilename.lastIndexOf("/") != -1) ? aFilename.lastIndexOf("/") + 1 : 0 ;
				var end			= (aFilename.lastIndexOf(".") != -1) ? aFilename.lastIndexOf(".") : aFilename.length();
				var mediaId		= aFilename.substring(start,end);

				if (typeof eval("parent.performAutoSpeak_" + mediaId) == 'undefined' || eval("parent.performAutoSpeak_" + mediaId) == null) {
					eval("parent.performAutoSpeak_" + mediaId + " = false;");
					PlayMedia();
				} else if (typeof eval("parent.performAutoSpeak_" + mediaId) != 'undefined' && eval("parent.performAutoSpeak_" + mediaId) != null && eval("parent.performAutoSpeak_" + mediaId) == true) {
					eval("parent.performAutoSpeak_" + mediaId + " = false;");
					PauseMedia();
				} else if (typeof eval("parent.performAutoSpeak_" + mediaId) != 'undefined' && eval("parent.performAutoSpeak_" + mediaId) != null && eval("parent.performAutoSpeak_" + mediaId) == false) {
					PauseMedia();					
				}
				break;
			
			case AUTOPLAY_NEVER:
				PauseMedia();					
				eval("parent.performAutoSpeak_" + mediaId + " = false;");
				break;

			default:
				PlayMedia();
				

		}

	}


	function UnloadMedia() {
		
		ZENDebug();

		try {

			ZENGetFlashObject(controllerObjectId).LoadMovie(0,"swf/dummy.swf" + ((FORCE_FLASH_RECACHE) ? "?time=" + new Date().getTime() : ""));

		} catch(e) {
			
			ZENDebug("Exception raised in LoadMedia(): " + e);
			setTimeout("UnloadMedia();",500);
			return;
	
		}

		FileName = null;

		if (ProgressTracker != null) {
			clearTimeout(ProgressTracker);
			ProgressTracker == null;
		}
	}

	
	function _launchMediaTracker() {

		ZENDebug();
		
		if (typeof ProgressTracker == 'undefined' || ProgressTracker == null) {

			ProgressTracker = setInterval( function() { TrackMedia(); },500);
			TrackMedia();

		}

	}


	function PlayMedia() {
		
		ZENDebug();
	
		try {

			var thePreloadProgress = PreloadProgress(controllerObjectId);
			
		} catch(e) {
			
			ZENDebug("Exception raised in PlayMedia(): " + e);
			setTimeout(function() { PlayMedia(); },500);
			return;
	
		}
				
		eval(controllerPrefix + "_Play_RetainsHighlitedState = true;");
		eval(controllerPrefix + "_Pause_RetainsHighlitedState = false;");
		eval(controllerPrefix + "_Rewind_RetainsHighlitedState = false;");
		eval(controllerPrefix + "_Forward_RetainsHighlitedState = false;");

		try {

			document.getElementById(controllerPrefix + "_Rewind").src = eval(controllerPrefix + "_Rewind_reg.src");
			document.getElementById(controllerPrefix + "_Forward").src = eval((thePreloadProgress < 100) ? controllerPrefix + "_Forward_dis.src" : controllerPrefix + "_Forward_reg.src");
			document.getElementById(controllerPrefix + "_Play").src = eval(controllerPrefix + "_Play_over.src");
			document.getElementById(controllerPrefix + "_Pause").src = eval(controllerPrefix + "_Pause_reg.src");

		} catch (e) {  };


		ZENGetFlashObject(controllerObjectId).Play();
		
		if (typeof ProgressTracker == 'undefined' || ProgressTracker == null)
			ProgressTracker = setInterval( function() { TrackMedia(); },500);
		
	}

	
	function PauseMedia() {
			
		ZENDebug();
	
		try {
					
			var thePreloadProgress = PreloadProgress(controllerObjectId);
			
		} catch(e) {
			
			ZENDebug("Exception raised in PauseMedia(): " + e);
			setTimeout(function() { PauseMedia(); },500);
			return;
	
		}

		ZENGetFlashObject(controllerObjectId).StopPlay();

		eval(controllerPrefix + "_Play_RetainsHighlitedState = false;");
		eval(controllerPrefix + "_Pause_RetainsHighlitedState = true;");


		try {

			document.getElementById(controllerPrefix + "_Rewind").src = eval(controllerPrefix + "_Rewind_reg.src");
			document.getElementById(controllerPrefix + "_Forward").src = eval((thePreloadProgress < 100) ? controllerPrefix + "_Forward_dis.src" : controllerPrefix + "_Forward_reg.src");
			document.getElementById(controllerPrefix + "_Play").src = eval(controllerPrefix + "_Play_reg.src");
			document.getElementById(controllerPrefix + "_Pause").src = eval(controllerPrefix + "_Pause_over.src");

		} catch (e) {};
	
	}


	function RewindMedia() {
		
		ZENDebug();
	
		try {
					
			var thePreloadProgress = PreloadProgress(controllerObjectId);
			
		} catch(e) {
			
			ZENDebug("Exception raised in RewindMedia(): " + e);
			setTimeout(function() { RewindMedia(); },500);
			return;
	
		}
	
		eval(controllerPrefix + "_Play_RetainsHighlitedState = false;");
		eval(controllerPrefix + "_Pause_RetainsHighlitedState = true;");
		eval(controllerPrefix + "_Rewind_RetainsHighlitedState = false;");
		eval(controllerPrefix + "_Forward_RetainsHighlitedState = false;");

		try {

			document.getElementById(controllerPrefix + "_Rewind").src = eval(controllerPrefix + "_Rewind_reg.src");
			document.getElementById(controllerPrefix + "_Forward").src = eval((thePreloadProgress < 100) ? controllerPrefix + "_Forward_dis.src" : controllerPrefix + "_Forward_reg.src");
			document.getElementById(controllerPrefix + "_Play").src = eval(controllerPrefix + "_Play_reg.src");
			document.getElementById(controllerPrefix + "_Pause").src = eval(controllerPrefix + "_Pause_over.src");

		} catch (e) {};

		ZENGetFlashObject(controllerObjectId).StopPlay();
		ZENGetFlashObject(controllerObjectId).Rewind();
	
		TrackMedia(controllerObjectId);
	
	}


	function ForwardMedia() {
		
		ZENDebug();
	
		try {
					
			var thePreloadProgress = PreloadProgress(controllerObjectId);
			var theTotalFrames = ZENGetFlashTotalFrames(controllerObjectId) - 1;
	
		} catch(e) {
			
			ZENDebug("Exception raised in ForwardMedia(): " + e);
			setTimeout(function() { ForwardMedia(); },500);
			return;
			
		}

		if (thePreloadProgress == 100) {
	
			eval(controllerPrefix + "_Play_RetainsHighlitedState = false;");
			eval(controllerPrefix + "_Pause_RetainsHighlitedState = true;");
			eval(controllerPrefix + "_Rewind_RetainsHighlitedState = false;");
			eval(controllerPrefix + "_Forward_RetainsHighlitedState = false;");
		
			try {

				document.getElementById(controllerPrefix + "_Rewind").src = eval(controllerPrefix + "_Rewind_reg.src");
				document.getElementById(controllerPrefix + "_Forward").src = eval((thePreloadProgress < 100) ? controllerPrefix + "_Forward_dis.src" : controllerPrefix + "_Forward_reg.src");
				document.getElementById(controllerPrefix + "_Play").src = eval(controllerPrefix + "_Play_reg.src");
				document.getElementById(controllerPrefix + "_Pause").src = eval(controllerPrefix + "_Pause_over.src");

			} catch (e) {};

			ZENGetFlashObject(controllerObjectId).TGotoFrame("/",theTotalFrames);
			ZENGetFlashObject(controllerObjectId).StopPlay();
					
			TrackMedia(controllerObjectId);
	
		}
	
	}



	function TrackMedia() {
				
		try {
					
			var thePreloadProgress = PreloadProgress(controllerObjectId);
			var theCurrentFrame		= ZENGetFlashObject(controllerObjectId).CurrentFrame();
			var theTotalFrames		= ZENGetFlashTotalFrames(controllerObjectId);
			var theFramesLoaded		= ZENGetFlashLoadedFrames(controllerObjectId);
			var currentProgress 	= PlayBackProgress();
			
		} catch(e) {
			
			ZENDebug("Exception raised in TrackMedia(): " + e);

			if (typeof ProgressTracker != 'undefined' || ProgressTracker != null) {
				clearInterval(ProgressTracker);
				ProgressTracker = null;
			}

			setTimeout( function() { TrackMedia(); },500);
			return;
	
		}
	
		if ((typeof ProgressTracker == 'undefined' || ProgressTracker == null) && eval(controllerPrefix + "_Play_RetainsHighlitedState") == true) {
			ProgressTracker = setInterval(function() { TrackMedia(); },500);
		}

		if (SHOW_PROGRESS_BAR) {
			document.getElementById(controllerPrefix + "_progressBar").style.width = (parseInt((DRAGBAR_WIDTH - 4) * currentProgress / 100)) + 'px';
		}

		if (SHOW_PERCENT_LOADED_IN_PROGRESS_BAR)
			document.getElementById(controllerPrefix + "_percentLoaded").style.width = (parseInt((DRAGBAR_WIDTH - 4) * (thePreloadProgress / 100))) + 'px';
	

		if (document.getElementById(controllerPrefix + "_Forward").src == eval(controllerPrefix + "_Forward_dis.src")) {

			if (thePreloadProgress >= 99)
				document.getElementById(controllerPrefix + "_Forward").src = eval(controllerPrefix + "_Forward_reg.src");

		}

		var adjustmentValue = -2;
	
		if (SHOW_PROGRESS_BAR)
			document.getElementById(controllerPrefix + "_progressMarker").style.left = adjustmentValue + (parseInt((DRAGBAR_WIDTH - 4) * currentProgress / 100)) + 'px';
	 
		if (SHOW_NUMERICAL_PROGRESS) {
			
			var theTotalSeconds = parseInt(theTotalFrames / 25);
			var theCurrentNumericalProgress = parseInt(theCurrentFrame / 25);
			
			document.getElementById(controllerPrefix + "_numericalProgressContainer").innerHTML = (parseInt(theCurrentNumericalProgress / 60)) + ":" + ((parseInt(theCurrentNumericalProgress % 60) < 10) ? "0" : "") + (parseInt(theCurrentNumericalProgress % 60)) + " / " + (parseInt(theTotalSeconds / 60)) + ":" + ((parseInt(theTotalSeconds % 60) < 10) ? "0" : "") + (parseInt(theTotalSeconds % 60));
			
		}


		if (currentProgress == 100) {
	
			ZENDebug("Media ended");
	
			if (typeof ProgressTracker != 'undefined' || ProgressTracker != null) {
				clearInterval(ProgressTracker);
				ProgressTracker = null;
			}
	
			eval("parent.performVideo_" + controllerObjectId + " = false;");
	
			eval(controllerPrefix + "_Rewind_RetainsHighlitedState = false;");
			eval(controllerPrefix + "_Play_RetainsHighlitedState = false;");
			eval(controllerPrefix + "_Pause_RetainsHighlitedState = true;");
			eval(controllerPrefix + "_Forward_RetainsHighlitedState = false;");

			try {

				document.getElementById(controllerPrefix + "_Rewind").src = eval(controllerPrefix + "_Rewind_reg.src");
				document.getElementById(controllerPrefix + "_Forward").src = eval(controllerPrefix + "_Forward_reg.src");
				document.getElementById(controllerPrefix + "_Play").src = eval(controllerPrefix + "_Play_reg.src");
				document.getElementById(controllerPrefix + "_Pause").src = eval(controllerPrefix + "_Pause_over.src");

			} catch (e) {};

		}

	}

	// Convenience Getter Methods
	function PlayBackProgress() {

		return parseInt((ZENGetFlashObject(controllerObjectId).CurrentFrame() * 100) / (ZENGetFlashTotalFrames(controllerObjectId) - 1));
		
	}

	function PreloadProgress() {
		
		return parseInt((ZENGetFlashLoadedFrames(controllerObjectId) * 100) / ZENGetFlashTotalFrames(controllerObjectId));
		
	}
	
	function TogglePlayBack() {

		ZENDebug();

		if (eval("typeof " + controllerPrefix + "_Pause_RetainsHighlitedState") != 'undefined' && eval(controllerPrefix + "_Pause_RetainsHighlitedState") != null && eval(controllerPrefix + "_Pause_RetainsHighlitedState") == false) {

			PauseMedia();

		} else if (typeof eval("typeof " + controllerPrefix + "_Play_RetainsHighlitedState") != 'undefined' && eval(controllerPrefix + "_Play_RetainsHighlitedState") != null && eval(controllerPrefix + "_Play_RetainsHighlitedState") == false) {
			
			PlayMedia();
			
		}
		
	}

	function IsPlaying() {
		
		var returnValue;
		
		if (eval("typeof " + controllerPrefix + "_Pause_RetainsHighlitedState") != 'undefined' && eval(controllerPrefix + "_Pause_RetainsHighlitedState") != null  && eval("typeof " + controllerPrefix + "_Play_RetainsHighlitedState") != 'undefined' && eval("typeof " + controllerPrefix + "_Play_RetainsHighlitedState") != null) {

			playButtonState = eval(controllerPrefix + "_Play_RetainsHighlitedState");
			pauseButtonState = eval(controllerPrefix + "_Pause_RetainsHighlitedState")

			if (playButtonState && !pauseButtonState) {

				returnValue = true;

			} else if (!playButtonState && pauseButtonState) {

				returnValue = false;

			} else if (!playButtonState && !pauseButtonState) {
				
				returnValue = false;

			} else {

				returnValue = false;

			}

		} else {
			
			returnValue = null;
			
		}
		
		return returnValue;
		
	}

}


var ZPS_EFFECT_ZOOM_STATE = false;
function ZENEffectController(constructorObject) {
	
	/*
	Constructor
	duration: [int] millisecs, duration of effect
	starttime: [int] init with 0
	to: [int or float] depending on effect
	now: [int or float] init with 0
	from: [int or float] depending on effect
	withElement: [html element id] (retrieve with document.getElementById)
	timer: [null] init with null
	withEffect: [constant as defined in config.js] for instance EFFECT_SLIDE_HORIZONTALLY
	
	Sample usage (with delayed execution):
	setTimeout("var fadeIn = new ZPSEffectController({duration: 500, starttime:0, to:100, now:0.0, from:0, withElement:document.getElementById('foo'), timer:null, withEffect: EFFECT_FADE });",100);

	*/

	var origWidth;
	var origHeight;
	var origTop;
	var origLeft;
	var aspectRatio;
	var objRef;
	
	init();
	
	function init() {
		
		if (constructorObject.timer != null) {
		
			clearInterval (constructorObject.timer);
			intervalTimer = null;
			
		}

		constructorObject.withElement.className = constructorObject.withElement.id + " shown";

		constructorObject.starttime = (new Date).getTime() - 13;
		
		switch (constructorObject.withEffect) {
			
			case EFFECT_FADE:
				constructorObject.timer = setInterval (function () { fade(constructorObject); }, 13);
				fade(constructorObject);
				break;
				
			case EFFECT_SLIDE_VERTICALLY:
				constructorObject.timer = setInterval (function () { slideVertically(constructorObject); }, 13);
				slideVertically(constructorObject);
				break;			

			case EFFECT_SLIDE_HORIZONTALLY:
				constructorObject.timer = setInterval (function () { slideHorizontally(constructorObject); }, 13);
				slideHorizontally(constructorObject);
				break;			

			case EFFECT_WIDTH:
				constructorObject.timer = setInterval (function () { width(constructorObject); }, 13);
				width(constructorObject);
				break;

			case EFFECT_HEIGHT:
				constructorObject.timer = setInterval (function () { height(constructorObject); }, 13);
				setTimeout(function() { constructorObject.withElement.style.overflow = "auto"; },constructorObject.duration);
				height(constructorObject);
				break;

			case EFFECT_PUFF:
				if (typeof constructorObject.withElement != 'undefined' && constructorObject.withElement != null) {
					var foo = constructorObject.withElement.cloneNode(true);
					foo.id = "foo2";
					foo.style.zIndex = 100000;
					document.body.appendChild(foo);
					constructorObject.withElement = foo;
					
					aspectRatio = constructorObject.withElement.offsetWidth / constructorObject.withElement.offsetHeight;
					origWidth	= constructorObject.withElement.offsetWidth;
					origHeight	= constructorObject.withElement.offsetHeight;
					origTop		= constructorObject.withElement.offsetTop;
					origLeft	= constructorObject.withElement.offsetLeft;
					constructorObject.timer = setInterval (function () { puff(constructorObject); }, 13);
					puff(constructorObject);
					setTimeout(function() { document.body.removeChild(constructorObject.withElement); },constructorObject.duration);
				}
				break;

			case EFFECT_REVERSED_PUFF:
				if (typeof constructorObject.withElement != 'undefined' && constructorObject.withElement != null) {

					ZENChangeOpac(0, constructorObject.withElement.id);
					constructorObject.withElement.className = constructorObject.withElement.id + " shown";

					aspectRatio = constructorObject.withElement.offsetWidth / constructorObject.withElement.offsetHeight;
					origWidth	= constructorObject.withElement.offsetWidth;
					origHeight	= constructorObject.withElement.offsetHeight;
					origTop		= constructorObject.withElement.offsetTop;
					origLeft	= constructorObject.withElement.offsetLeft;
					constructorObject.timer = setInterval (function () { reversedpuff(constructorObject); }, 13);
					reversedpuff(constructorObject);

				}
				break;

			case EFFECT_ZOOM:
				if (!APP_IS_BUSY) {
					
					if ((constructorObject.from < constructorObject.to && ZPS_EFFECT_ZOOM_STATE == false) || (constructorObject.from > constructorObject.to && ZPS_EFFECT_ZOOM_STATE == true)) {
						
						ZPS_EFFECT_ZOOM_STATE = !ZPS_EFFECT_ZOOM_STATE;
												
						APP_IS_BUSY = true;
						aspectRatio = constructorObject.withElement.offsetWidth / constructorObject.withElement.offsetHeight;
						origWidth	= constructorObject.withElement.offsetWidth;
						origHeight	= constructorObject.withElement.offsetHeight;
						origTop		= constructorObject.withElement.offsetTop;
						origLeft	= constructorObject.withElement.offsetLeft;
						constructorObject.timer = setInterval (function () { zoom(constructorObject); }, 13);
						setTimeout("APP_IS_BUSY = false;",constructorObject.duration);
						zoom(constructorObject);

					}

				}
				break;

		}
				
	}


	function fade() {
		
		ZENInterpolate(constructorObject);
		ZENChangeOpac(parseInt(constructorObject.now),constructorObject.withElement.id);
		
	}


	function slideVertically() {

		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.top = parseInt(constructorObject.now) + "px";

	}


	function slideHorizontally() {

		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.left = parseInt(constructorObject.now) + "px";

	}
	
	
	function puff() {

		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.width	= origWidth		+ (parseInt(constructorObject.now) * aspectRatio) + "px";
		constructorObject.withElement.style.height	= origHeight	+ parseInt(constructorObject.now) + "px";
		constructorObject.withElement.style.left	= (origLeft		- ((parseInt(constructorObject.now) * aspectRatio) / 2)) + "px";
		constructorObject.withElement.style.top		= origTop		- (parseInt(constructorObject.now) / 2) + "px";
		ZENChangeOpac(100 - parseInt(constructorObject.now), constructorObject.withElement.id);
		
	}

	function reversedpuff() {
		
		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.width	= origWidth		+ (parseInt(constructorObject.now) * aspectRatio) + "px";
		constructorObject.withElement.style.height	= origHeight	+ parseInt(constructorObject.now) + "px";
		constructorObject.withElement.style.left	= (origLeft		- ((parseInt(constructorObject.now) * aspectRatio) / 2)) + "px";
		constructorObject.withElement.style.top		= origTop		- (parseInt(constructorObject.now) / 2) + "px";
		ZENChangeOpac(100 - parseInt(constructorObject.now), constructorObject.withElement.id);
		
	}


	function width() {

		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.width = parseInt(constructorObject.now) + "px";
		
	}


	function height() {
		
		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.overflow = "hidden";
		constructorObject.withElement.style.height = parseInt(constructorObject.now) + "px";
		
	}


	function zoom() {

		ZENInterpolate(constructorObject);
		constructorObject.withElement.style.width	= origWidth		+ (parseInt(constructorObject.now) * aspectRatio) + "px";
		constructorObject.withElement.style.height	= origHeight	+ parseInt(constructorObject.now) + "px";
		constructorObject.withElement.style.left	= (origLeft		- ((parseInt(constructorObject.now) * aspectRatio) / 2)) + "px";
		constructorObject.withElement.style.top		= origTop		- (parseInt(constructorObject.now) / 2) + "px";

	}

}


/**
 * @id ZENScrollBar
 * @param {Object} constructor
 * @type {Object} attachTo: DOM element
 */
function ZENScrollBar(constructor) {
// constructor
// .attachTo: [div]
// Sample usage:
// 	var foo = new ScrollBar({attachTo: document.getElementById('bar')});

	var uniqueId = (new Date).getTime();
	var scrollBarContainer;
	var scrollHandleContainer;
	var scrollHandleOverlay;
	
	var isCurrentlyDragging;
	var scrollToAction = true;

	var interpolationObject;

	var yPosDiff;

	var slideToDest = null;

	initWithDiv();

	/**
	 * @id initWithDiv
 	 * @classDescription Creates and attaches a scrollbar to a DOM element
  	 * @constructor
	 * @method
	 * @memberOf ZENScrollBar
	 */
	function initWithDiv() {
	
		scrollBarContainer = document.createElement("div");
		scrollBarContainer.id = "id" + uniqueId;
		scrollBarContainer.style.position = "absolute";
		scrollBarContainer.style.top	= constructor.attachTo.offsetTop + "px";
		scrollBarContainer.style.left	= (constructor.attachTo.offsetLeft + constructor.attachTo.offsetWidth + 1) + "px";
		scrollBarContainer.style.width	= "16px";
		scrollBarContainer.style.height	= constructor.attachTo.offsetHeight + "px";
		scrollBarContainer.style.zIndex = "0";

			var scrollBarContainerTop = document.createElement("img");
			scrollBarContainerTop.id = scrollBarContainer.id + "ContainerTop"
			scrollBarContainerTop.style.position = "absolute";
			scrollBarContainerTop.style.top = "0px";
			scrollBarContainerTop.style.left = "0px";
			scrollBarContainerTop.src = "gfx/ScrollContainerTop.png";
			scrollBarContainerTop.style.zIndex = "0";
			scrollBarContainer.appendChild(scrollBarContainerTop);

			var scrollBarContainerMid = document.createElement("img");
			scrollBarContainerMid.id = scrollBarContainer.id + "ContainerMid"
			scrollBarContainerMid.style.position = "absolute";
			scrollBarContainerMid.style.top = "16px";
			scrollBarContainerMid.style.left = "0px";
			scrollBarContainerMid.src = "gfx/ScrollContainerMiddle.png";
			scrollBarContainerMid.height = (constructor.attachTo.offsetHeight - 32);
			scrollBarContainerMid.width = 16;
			scrollBarContainerMid.style.zIndex = "0";
			scrollBarContainer.appendChild(scrollBarContainerMid);

			var scrollBarContainerBot = document.createElement("img");
			scrollBarContainerBot.id = scrollBarContainer.id + "ContainerBot"
			scrollBarContainerBot.style.position = "absolute";
			scrollBarContainerBot.style.top = (constructor.attachTo.offsetHeight - 16) + "px";
			scrollBarContainerBot.style.left = "0px";
			scrollBarContainerBot.src = "gfx/ScrollContainerBottom.png";
			scrollBarContainerBot.style.zIndex = "0";
			scrollBarContainer.appendChild(scrollBarContainerBot);
			
		scrollHandleOverlay = document.createElement("div");
		scrollHandleOverlay.id = scrollBarContainer.id + "scrollHandleOverlay";
		scrollHandleOverlay.style.position	= "absolute";
		scrollHandleOverlay.style.top			= "0px";
		scrollHandleOverlay.style.left		= "0px";
		scrollHandleOverlay.style.width		= "16px";
		scrollHandleOverlay.style.height		= ((constructor.attachTo.offsetHeight / constructor.attachTo.scrollHeight) * constructor.attachTo.offsetHeight) + "px";
		scrollHandleOverlay.style.zIndex = "2";
		scrollHandleOverlay.style.backgroundColor = "black";
		scrollBarContainer.appendChild(scrollHandleOverlay);

		scrollHandleContainer = document.createElement("div");
		scrollHandleContainer.id = scrollBarContainer.id + "scrollHandleContainer";
		scrollHandleContainer.style.position	= "absolute";
		scrollHandleContainer.style.top			= "0px";
		scrollHandleContainer.style.left		= "0px";
		scrollHandleContainer.style.width		= "16px";
		scrollHandleContainer.style.height		= ((constructor.attachTo.offsetHeight / constructor.attachTo.scrollHeight) * constructor.attachTo.offsetHeight) + "px";
		scrollHandleContainer.style.zIndex = "1";

			var scrollHandleTop = document.createElement("img");
			scrollHandleTop.id = scrollBarContainer.id + "ScrollHandleTop";
			scrollHandleTop.style.position = "absolute";
			scrollHandleTop.style.top = "0px";
			scrollHandleTop.style.left = "0px";
			scrollHandleTop.src = "gfx/ScrollHandleTop.png";
			scrollHandleTop.style.zIndex = "0";
			scrollHandleContainer.appendChild(scrollHandleTop);


			var scrollHandleMid = document.createElement("img");
			scrollHandleMid.id = scrollBarContainer.id + "scrollHandleMid";
			scrollHandleMid.style.position = "absolute";
			scrollHandleMid.style.top = "16px";
			scrollHandleMid.style.left = "0px";
			scrollHandleMid.src = "gfx/ScrollHandleMiddle.png";
			scrollHandleMid.height = (((constructor.attachTo.offsetHeight / constructor.attachTo.scrollHeight) * constructor.attachTo.offsetHeight) - 32);
			scrollHandleMid.width = 16;
			scrollHandleMid.style.zIndex = "0";
			scrollHandleContainer.appendChild(scrollHandleMid);


			var scrollHandleBot = document.createElement("img");
			scrollHandleBot.id = scrollBarContainer.id + "scrollHandleBot";
			scrollHandleBot.style.position = "absolute";
			scrollHandleBot.style.top = (((constructor.attachTo.offsetHeight / constructor.attachTo.scrollHeight) * constructor.attachTo.offsetHeight) - 16) + "px";
			scrollHandleBot.style.left = "0px";
			scrollHandleBot.src = "gfx/ScrollHandleBottom.png";
			scrollHandleBot.style.zIndex = "0";
			scrollHandleContainer.appendChild(scrollHandleBot);


		scrollBarContainer.appendChild(scrollHandleContainer);
		scrollBarContainer.onclick = ScrollToHandler;

		if (constructor.attachTo.addEventListener)
			constructor.attachTo.addEventListener('DOMMouseScroll', handleScrollWheel, false);
		
		constructor.attachTo.onmousewheel = handleScrollWheel;
		

		if (scrollHandleOverlay.addEventListener) {
		
			scrollHandleOverlay.addEventListener("mousedown",DragHandler,true);
		
		} else if (scrollHandleOverlay.attachEvent) {
		
			scrollHandleOverlay.attachEvent("onmousedown",DragHandler);
			
		} else {

			scrollHandleOverlay.onmousedown = DragHandler;

		}

		document.body.appendChild(scrollBarContainer);
		
		ZENChangeOpac(0,scrollHandleOverlay.id);

	}
	
	/**
	 * Handles initial stage of a drag event
	 * @id DragHandler
	 * @param {Object} e
	 * @method
	 * @memberOf ZENScrollBar
	 */
	function DragHandler(e) {

		if (!e)
			var e = window.event;

		yPosDiff = e.clientY - scrollBarContainer.offsetTop - scrollHandleContainer.offsetTop;

		if (!isCurrentlyDragging) {
			
			isCurrentlyDragging		= true;
			scrollToAction			= false;
			document.onmousemove	= PerformDrag;
			document.onmouseup		= EndDrag;
	
		}
	
	}

	/**
	 * Handles a drag event while it is occurring
	 * @id PerformDrag
	 * @param {Object} e
	 * @memberOf ZENScrollBar
	 * @method
	 * @return {BOOL}
	 */
	function PerformDrag(e) {

		if (isCurrentlyDragging) {
			
			if (!e)
				var e = window.event;
			
			
			var theYPos = e.clientY - scrollBarContainer.offsetTop;
		
			window.status = theYPos;
		
			theYPos = ((theYPos - yPosDiff) < 0) ? 0 : theYPos - yPosDiff;
			theYPos = ((theYPos + scrollHandleContainer.offsetHeight) > scrollBarContainer.offsetHeight) ? scrollBarContainer.offsetHeight - scrollHandleContainer.offsetHeight : theYPos;

			scrollHandleContainer.style.top = (theYPos) + "px";
			scrollHandleOverlay.style.top = (theYPos) + "px";

			// BEGIN live tracking

			handlePositionInPercent = (theYPos / (scrollBarContainer.offsetHeight - scrollHandleContainer.offsetHeight));			
			constructor.attachTo.scrollTop = handlePositionInPercent * (constructor.attachTo.scrollHeight - constructor.attachTo.offsetHeight);

			// END live tracking
			
			return false;
	
		}

	}

	/**
	 * Finalizes a drag event
	 * @id EndDrag
	 * @param {Object} e
	 * @memberOf ZENScrollBar
	 */
	function EndDrag(e) {

		if (!e)
			var e = window.event;
	
		if (isCurrentlyDragging) {

			yPosDiff = null;
			isCurrentlyDragging=false;
			scrollToAction = false;

		}

	}
	
	/**
	 * Handles initial stage of a scroll to event / click on the scroll bar background
	 * @id ScrollToHandler
	 * @param {Object} e
	 * @memberOf ZENScrollBar
	 */
	function ScrollToHandler(e) {

		if (scrollToAction) {

			if (!e)
				var e = window.event;
			
			yPosDiff = scrollHandleContainer.offsetHeight / 2;

			var theYPos = e.clientY - scrollBarContainer.offsetTop;
	
			handlePositionInPercent = (theYPos / (scrollBarContainer.offsetHeight));			
	
			theYPos = handlePositionInPercent * scrollBarContainer.offsetHeight;
			
			theYPos = ((theYPos - yPosDiff) < 0) ? 0 : theYPos - yPosDiff;
			theYPos = ((theYPos + scrollHandleContainer.offsetHeight) > scrollBarContainer.offsetHeight) ? scrollBarContainer.offsetHeight - scrollHandleContainer.offsetHeight : theYPos;

			interpolationObject = {duration: 250, starttime:((new Date).getTime() - 13), to:theYPos, now:0.0, from:scrollHandleContainer.offsetTop, timer:null};
			interpolationObject.timer = setInterval (function () { slideHandleToDest(interpolationObject); }, 13);
			slideHandleToDest(interpolationObject);			

			yPosDiff = null;
			isCurrentlyDragging=false;

		}

		scrollToAction = true;

	}
	
	/**
	 * Handles the actual scroll to event / click on the scroll bar background
	 * @id slideHandleToDest
	 * @param {Object} interpolationObject
	 * @memberOf ZENScrollBar
	 */
	function slideHandleToDest(interpolationObject) {

		ZENInterpolate(interpolationObject);

		if (interpolationObject.from < interpolationObject.to) {
		
			var absPosnInPercent = interpolationObject.now / (constructor.attachTo.offsetHeight - scrollHandleContainer.offsetHeight);
			var posnInPercent = (interpolationObject.from - interpolationObject.now) / (interpolationObject.from - interpolationObject.to);
		
		} else {
		
			var absPosnInPercent = interpolationObject.now / constructor.attachTo.offsetHeight;
			var posnInPercent = (interpolationObject.to - interpolationObject.now) / (interpolationObject.to - interpolationObject.from);
			
		}

		scrollHandleContainer.style.top = parseInt(interpolationObject.now) + "px";
		scrollHandleOverlay.style.top = parseInt(interpolationObject.now) + "px";
		constructor.attachTo.scrollTop = absPosnInPercent * (constructor.attachTo.scrollHeight - constructor.attachTo.offsetHeight);

	}

	
	/**
	 * Performs the actual scrolling of a scroll wheel event	 * @id performScrollWithWheel
	 * @param {int} delta
	 * @memberOf ZENScrollBar
	 */
	function performScrollWithWheel(delta) {

		constructor.attachTo.scrollTop -= delta * 50;

		var scrollPosn = constructor.attachTo.scrollTop / (constructor.attachTo.scrollHeight - constructor.attachTo.offsetHeight);

		var sliderPosn = scrollPosn * (scrollBarContainer.offsetHeight - scrollHandleContainer.offsetHeight);

		scrollHandleContainer.style.top = parseInt(sliderPosn) + "px";
		scrollHandleOverlay.style.top = parseInt(sliderPosn) + "px";

	}

	/**
	 * Handles the initial stage of a mouse scroll wheel event
	 * @id handleScrollWheel
	 * @param {Object} event
	 * @memberOf ZENScrollBar
	 */
	function handleScrollWheel(event) {

		var delta = 0;

		if (!event) event = window.event;

		if (event.wheelDelta) {

			delta = event.wheelDelta / 120; 
			if (window.opera) delta = -delta;

		} else if (event.detail) {

			delta = -event.detail / 3;

		}

		if (delta)
			performScrollWithWheel(delta);

	}

}


function ZENInterpolate(constructorObject) {

	/*
	General purpose interpolation with time function
	Constructor:
	duration: [int, millisecs] the interpolation takes this many millisecs to perform
	starttime: [int] [init with 0]
	to: [int or float] destination value for the interpolation
	now: [int or float] [init with 0]
	fr0m: source value for the interpolation
	
	Sample constructor object:
	var sample = {duration:500, starttime:0, to:271.0, now:0.0, from:171.0, timer:null};
	
	Sample function usage:
	ZENInterpolate({duration:500, starttime:0, to:271.0, now:0.0, from:171.0, timer:null});
	
	Notes:
	ZENInterpolate() will modify the referenced object passed to it
	(not a copy of the constructor object) which means that one may pass
	constructors with more properties in them than the minimum set as defined above.
	
	This is the case with the ZENEffectController() class which
	passes an extended constructor reference to ZENInterpolate() for modification.
	
	*/

	var T;
	var ease;
	var time = (new Date).getTime();
	T = limit_3(time - constructorObject.starttime, 0, constructorObject.duration);
	
	if (T >= constructorObject.duration) {

		clearInterval (constructorObject.timer);
		constructorObject.timer = null;
		constructorObject.now = constructorObject.to;

	} else {
	
		ease = 0.5 - (0.5 * Math.cos(Math.PI * T / constructorObject.duration));
		constructorObject.now = computeNextFloat (constructorObject.from, constructorObject.to, ease);

	}


}

function limit_3 (a, b, c) {

	return a < b ? b : (a > c ? c : a);

}

function computeNextFloat (from, to, ease) {

	return from + (to - from) * ease;

}



function ZENPlaybackListener(aConstructorObject) {
	/*
	Class to perform a function on and event with an instance of the ZENMediaController class.
	
	aConstructorObject accepts the following propterties
	attachTo: [an instance of ZENMediaController]
	reactOnEvent: [a custom event constant like ZEN_MOVIE_HAS_ENDED (defined in config.js)]
	executesFunctionOnEvent: [a globally available function]
	withInterval: [listen with interval of this many millisecs]
	
	Sample class usage:
	var playbackListener = new ZENPlaybackListener({attachTo: vc, reactOnEvent: ZEN_MOVIE_HAS_ENDED, executesFunctionOnEvent: "foo()", withInterval: 1000});

	*/

	ZENDebug();

	var listenerInterval = setInterval( function() { listen(); }, aConstructorObject.withInterval);

	function listen() {

		try {

			if (aConstructorObject.reactOnEvent == ZEN_MOVIE_HAS_ENDED) {
			
				if (!aConstructorObject.attachTo.IsPlaying() && aConstructorObject.attachTo.PlayBackProgress() > 99) {
					
					clearInterval(listenerInterval);
					eval(aConstructorObject.executesFunctionOnEvent);
							
				}
		
			}
		
		} catch (e) {}
		
	}
	
}


function ZENChangeOpac(opacity, id) {

	/*
	General purpose, cross browser opacity change of elements
	*/

	/* This is *not* a bug. Leave it be. */
	if (opacity > 99)
		opacity = 99;
	
	if (typeof document.getElementById(id) != 'undefined' && document.getElementById(id) != null) {

		var object = document.getElementById(id).style; 
		object.opacity = (opacity / 100); 
		object.MozOpacity = (opacity / 100); 
		object.KhtmlOpacity = (opacity / 100); 
		object.filter = "alpha(opacity=" + opacity + ")"; 

	}

} 


//
// SCORM Related Functions
//
//

var SCO_RIGHT = 1;
var SCO_WRONG = 2;

//
// ZENSCOEval({withCondition: [predefd constant], targetSCO: [string]})
//
function ZENSCOEval(constructor) {

	var SCORE;
	var SUCCESS_STATUS;
	var UNLOAD_PAGE_MESSAGE;

	switch (constructor.withCondition) {
		
		case SCO_RIGHT:
			SCORE = "100";
			SUCCESS_STATUS = "passed";
			UNLOAD_PAGE_MESSAGE = "completed";
			break;

		case SCO_WRONG:
			SCORE = "0";
			SUCCESS_STATUS = "failed";
			UNLOAD_PAGE_MESSAGE = "incomplete";
			break;

	}

	// These methods *must* be applied to the LMS in order for a navigatinal request (adl.nav.request) to take place.
	doSetValue( "cmi.score.raw", SCORE);
	doSetValue( "cmi.success_status", SUCCESS_STATUS);
	ZENSCONavigate({withTargetSCO: constructor.targetSCO, unloadPageMessage: UNLOAD_PAGE_MESSAGE});

}

//
// ZENSCONavigate({withTargetSCO:aTargetSCO, unloadPageMessage: aMessage})
// SCORM 2004 adl.nav.request wrapper for online (inside LMS) and offline (outside LMS) purposes.
//
function ZENSCONavigate(constructor) {

	if (typeof top.ZEN_SCO_RUNS_OFFLINE != 'undefined' && top.ZEN_SCO_RUNS_OFFLINE != null && top.ZEN_SCO_RUNS_OFFLINE) {
	// Offline / outside an LMS
	
		document.location = constructor.withTargetSCO + ".htm";

	} else {
	// Online / inside an LMS
	
		doSetValue("adl.nav.request", "{target=" + ZENSCOIdPrefix + constructor.withTargetSCO + "}choice");
	 	unloadPage((constructor.unloadPageMessage != null) ? constructor.unloadPageMessage: "");

	}

}


//
// ZENResetCase(aCaseId,anURI)
// Note: Needs inclusion of APIWrapper.js
//
function ZENResetCase(aCaseId,anURI) {
		
	var str = doLMSGetValue('cmi.suspend_data').toString();	
	
	var theFirstPart	= str.indexOf(aCaseId + "[");
	var theSecondPart	= str.substr(theFirstPart,str.length).indexOf("]") + 1;
		
	doLMSSetValue('cmi.suspend_data',str.substring(0,theFirstPart) + str.substring(theSecondPart,str.length));

	if (typeof anURI != 'undefined' || anURI != null) {
		
		document.location = anURI;
		
	}

}

//
// ZENResetAllCases()
// Note: Needs inclusion of APIWrapper.js and APIWrapper.js
//
function ZENResetAllCases() {
	
	ZENDebug();
	doLMSSetValue('cmi.suspend_data','')
	
}


