///////////////////////////////////////////////////////////////////////
//
//	global.js - the Mentor Webpage Object Model (M-WOM)
//
var _version_global_js = "0.2.1";
//
//	Copyright 2000, Mentor Systems Ltd.  All rights reserved.
//
//	Author: Austin David France - Ramesys (CS) Ltd
//
//	Amendments:
//
//	001 Sun 14th May 2000 - Austin David France - The Software Sorcerer
//		Version: 0.1.3
//		- Added exception handler when defining a style sheet to handle
//		the fact that style sheets can't be loaded until at least one
//		style sheet exists.
//		- Extended the WebPage object to include a loadScript()
//		method for loading script source code.
//
//	003 Mon 15th May 2000 - Austin David France - Ramesys (CS) Ltd
//		Version: 0.1.4
//		- Reworked WebPage object into a single static object.
//		- Added browser language detection method.
//		- Extended String object to include pad() and format() methods.
//
//	004 Tue 6th June 2000 - Austin David France - Ramesys (CS) Ltd
//		Version: 0.1.5
//		- Added support for document.ongloballoaded() event handler
//		fired at the end of this script.
//
//	005 Tue 29th June 2000 - Austin David France - Ramesys (CS) Ltd
//		Version: 0.1.6
//		- Use document.createStyleSheet() to load a style sheet, not
//		StyleSheets(0).addImport().
//		- Fix problem with toString() method always returning thePage
//		rather than a reference into the object pool.
//		- It appears that you can't call createStyleSheet() once the
//		header has completed loading (or the body has).  This can
//		happen for example when the script calling loadStyleSheet()
//		has the defer attribute (is not run until the page is loaded).
//		Changed loadStyleSheet() to use the import method if the 
//		document has already loaded.
//
//	006 Wed 21st February 2001 - Austin David France - Ramesys (CS) Ltd
//		Version 0.1.7
//		Add WebPage.kickIEImages(el) method which can be called to kick
//		IE into displaying images it forgot about.  This has been
//		confirmed as a bug in IE.  See KB Q269802
//
//	008 Wed 26th February 2001 - Austin David France - Ramesys (CS) Ltd
//		Version 0.1.8
//		Add copyToClipboard() method that will copy the passed string
//		to the clipboard.
//
//	009 Wed 09 May 2001 - Craig Dobson - Ramesys (CS) Ltd
//		Version 0.1.9
//		Add gotScript() method to return the status of a script being
//		loaded on the current document.  Amended the loadScript method()
//		to work (Quote missing).
//
//	010 Mon 30 July 2001 - Craig Dobson - Ramesys (CS) Ltd
//		Version 0.2.0
//		Extended the Number object with a new trimString method.
//
//	011 Tue 31 July 2001 - Craig Dobson - Ramesys (CS) Ltd
//		Version 0.2.1
//		Extended thePage object with a isCollection method.
//		This method just return true or false to say whether
//		an element is a collection of elements or not.
//

///////////////////////////////////////////////////////////////////////
//////////////////////////// Number Object ////////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Number::trimString ([iDecimals])
//
// Parameters:
//	iDecimals	Optional Integer, Number of decimals for the number
//				to be trimmed or extended to.  Default: 0 - No decimal
//				places
//
// Description:
//	Trims or extendes the the current number to a value with the 
//	required amount of decimal places.
//
// Return Value:
//	String		Trimmed.Extended number represented as a string.
//
Number.prototype.trimString = function (iDecimals) {
	var sValue = new String(this.valueOf());
	
	// Ensure that we have a valid decimals value.
	if (iDecimals < 0) {
		alert ("Number::toTrimString - Invalid decimals value, value cannot not be negative.");
		return sValue;
	}
	
	// If the value is to have no decimal places.
	if (!iDecimals || iDecimals == 0) {
		// If the value has a decimal place.
		if ((iPos = sValue.indexOf(".")) != -1) {
			return sValue.substr(0, iPos - 1);
		} else {
			return sValue;
		}
	} else {
		// If the value has a decimal place.
		if ((iPos = sValue.indexOf(".")) == -1) {
			sValue += ".";
			iPos = sValue.indexOf(".");
		}
		
		// Append the req	uired amount of values.
		while(sValue.length < (iPos + iDecimals + 1)) sValue += "0";
		
		return sValue.substr(0, (iPos + iDecimals + 1));
	}
}

///////////////////////////////////////////////////////////////////////
//////////////////////////// Array Object /////////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Array::indexOf (varValue)
//
// Parameters:
//	varValue	Variant, Value to be located within the array.
//
// Description:
//	Returns the index position of the first occurence of a value within
//	the array. -1 is returned if no match is found.
//
// Return Value:
//	Integer		Index position, -1 if no occurence is located.
Array.prototype.indexOf = function (varValue) {
	for (var i = 0; i < this.length; i++) if (this[i] == varValue) return (i);
	return (-1);
}

///////////////////////////////////////////////////////////////////////
///////////////////////////// Date Object /////////////////////////////
///////////////////////////////////////////////////////////////////////

//
//	Extend the date object with some useful methods.
//

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::now ()
//
// Description:
//	Returns an integer value representing the number of milliseconds 
//	between midnight, January 1, 1970.
//
// Return Value:
//	Integer		Number of milliseconds between midnight, January 1, 
//				1970.
//	
Date.now = function() {
	return new Date().getTime();
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::getDayString ()
//
// Description:
//	Returns the day of the week as a string.
//
// Return Value:
//	String		Day of the week.
//
Date.prototype.getDayString = function() {
	var arrDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
	return (arrDays[this.getDay()]);
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::dateAdd (sInterval, iNumber)
//
// Parameters:
//	sInterval	String, Expression that is the interval you want to 
//				add. Posible sInterval strings:-
//					sInterval	Description 
//					=========	===========
//					yyyy 		Year 
//					q 			Quarter 
//					m 			Month 
//					y 			Day of year 
//					d 			Day 
//					w 			Weekday 
//					ww 			Week of year 
//					h 			Hour 
//					n 			Minute 
//					s 			Second 
//
//	iNumber		Integer, Numeric expression that is the number of 
//				interval you want to add. The numeric expression can 
//				either be positive or negative.
//
// Description:
//	This method returns a date to which a specified time interval 
//	has been applied.
//
// Return Value:
//	Date		Date object with the applied date interval.
//
Date.prototype.dateAdd = function (sInterval, iNumber) {
	// Break up the date & time into something more workable.
	iDate 		= this.getDate();
	iMonth		= this.getMonth();
	iYear		= this.getYear();
	iHours 		= this.getHours();
	iMinutes	= this.getMinutes();
	iSeconds	= this.getSeconds();	

	// Carry out the required processing on the required date/time element.
	switch (sInterval.toLowerCase()) {
		case "ww" :
			iDate += (iNumber * 7);
			break;

		case "y" :
		case "d" :
			// If we are deducting days from the date then don't include today.
			if (iNumber < 0) iNumber -=1;
			
			iDate += iNumber;
			break;
			
		case "m" :
			iMonth += iNumber;
			break;			

		case "yyyy" :
			iYear += iNumber;
			break;	
		
		case "q" :
			iMonth += iNumber * 3;
			break;

		case "w" :
			var sDay = 0;
			
			// Loop round and increment the day excluding weekends until we have added
			// the number of required weekdays to the passed date.
			for (var i = 0; i< iNumber; i++) {
				iDate ++;
				sDay = new Date(iYear, iMonth, iDate).getDay();
				
				// We are only interested in Weekday so don't include Saturday or Sunday
				if (sDay == 6) { iDate ++; sDay = 0; }
				if (sDay == 0) { iDate ++; }
			}
			
			break;
		
		case "q" :
			iMonth += iNumber * 3;
			break;

		case "h" :	
			iHours += iNumber;
			break;

		case "m" :	
			iMinutes += iNumber;
			break;

		case "s" :	
			iSeconds += iNumber;
			break;			
										
		default :
			break;
	}
	
	// Convert the processed broken down date/time elements back into a date.
	return (new Date (iYear, iMonth, iDate, iHours, iMinutes, iSeconds));	
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::getDayOfYear()
//
// Description:
//	This method will return the number of days since the beginning of
//	the year.
//
// Return Value:
//	Integer		Day of the year.
//
Date.prototype.getDayOfYear = function () {
	// Break up the date & time into something more workable.
	iDate 		= this.getDate();
	iMonth		= this.getMonth();
	iYear		= this.getYear();

	// Loop round and deduct days of the current date until we reach the 
	// beginning of the year.
	for (var i = 0; i < 352; i++) {
		
		// Get our new date minus the day counter
		var dTemp = new Date (iYear, iMonth, iDate - i);
				
		// If we are at the beginning of the year
		if (dTemp.getMonth() == 0 && dTemp.getDate() == 1) {
			// Return the day of the year
			return (i + 1);
		}
	}
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::getWeekOfYear()
//
// Description:
//	This method will return week number of the date within the year.
//
// Return Value:
//	Integer		Week of the year.
//
Date.prototype.getWeekOfYear = function () {
	// Return the week of the year
	return (Math.ceil (this.getDayOfYear() / 7));
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Date::formatString(sFormat)
//
// Parameters:
//	sFormat		String, Format of date to be returned. ie. mm/dd/yyyy
//						mm:		Month
//						dd:		Date
//						yyyy:	Year
//						yy:		Year
//						h:		Hour
//						m:		Minutes
//						s:		Seconds
//
// Description:
//	This method will return a string containing a Date formated into the
//	passed string format.
//
// Return Value:
//	String		Formatted date string.
//
Date.prototype.formatString = function (sFormat)
{
	// If no format has been passed then just return the date.
	if (!sFormat) return this;
	
	// Ensure that we have a string object for the format string.
	if (typeof (sFormat) != "string") sFormat = new String (sFormat);

	if (sFormat.indexOf ("h") != -1) {
		var intHours = this.getHours();
		sFormat = sFormat.replace ("h", intHours < 10 ? String ("0" + intHours) : String (intHours));
	}

	if (sFormat.indexOf ("mm") != -1)   sFormat = sFormat.replace ("mm", this.getMonth() + 1);

	if (sFormat.indexOf ("m") != -1) {
		var intMinutes = this.getMinutes();
		sFormat = sFormat.replace ("m", intMinutes < 10 ? String ("0" + intMinutes) : String (intMinutes));
	}

	if (sFormat.indexOf ("s") != -1) {
		var intSeconds = this.getSeconds();
		sFormat = sFormat.replace ("s", intSeconds < 10 ? String ("0" + intSeconds) : String (intSeconds));
	}	
	
	if (sFormat.indexOf ("dd") != -1)   sFormat = sFormat.replace ("dd", this.getDate());
	if (sFormat.indexOf ("yyyy") != -1) sFormat = sFormat.replace ("yyyy", this.getYear());
	if (sFormat.indexOf ("MMMM") != -1) sFormat = sFormat.replace ("MMMM", this.getMonthString());
	if (sFormat.indexOf ("DDDD") != -1) sFormat = sFormat.replace ("DDDD", this.getDayString());

	if (sFormat.indexOf ("yy") != -1) {
		var strYear = new String (this.getYear());
		sFormat = sFormat.replace ("yy", strYear.length == 2 ? strYear : strYear.substr(2));	
	}

	return (sFormat);
}
			
///////////////////////////////////////////////////////////////////////
//////////////////////////// String Object ////////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	String::pad(width)
//
// Parameters:
//	width		Integer, Number of spaces to be applied.
//
// Description:
//	This method will return a space padded version of the string.  If
//	width is negative, the string is left padded (spaces inserted at
//	the front) otherwise the string is right padded (spaces added at
//	the end).
//
// Return Value:
//	The padded string.  The string the method was called on remains
//	un-altered.
//	
String.prototype.pad = function(width)
{
	// Right Pad
	if (width < 0)
	{
		var s = "";
		for (var i = 0; i > width; i --) {
			s += " ";
		}
		return s + this;
	}

	// Left Pad
	if (width > 0)
	{
		var s = this;
		for (var i = 0; i < width; i ++) {
			s += " ";
		}
		return s;
	}

	// Nothing to do, return the unaltered string
	return this;			
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	String::format()
//
// Description:
//	This method works similar to printf with a few exceptions.  The
//	string object is used as the format string and the argument list
//	are the values to be plugged.
//
//	The supported plugs are:
//
//	%s		Plug as string.
//	%10s	Plug as string, pad right to 10 characters.
//	%-10s	Plug as string, pad left to 10 characters.
//
//	%d		Plug as number.
//	%10d	Plug as number, pad left to 10 characters.
//	%-10d	Plug as number, pad right to 10 characters.
//
//	%i		Same as %d
//
// Return Value:
//	The padded string.  The string the method was called on remains
//	un-altered.
//	
String.prototype.format = function()
{
	var str = "";				// Result
	var arg = 0;				// Current plug index

	// Scan each character of the pattern (this string object).
	for (var i = 0; i < this.length; i++)
	{
		var thisWasChar = null;
		var size = 0;				// Padding size

		// Get the current character from the format string
		var thisChar = this.charAt(i);

		// If we have a possible plug and we are not at the end of the string
		if (thisChar == '%' && i < this.length-1)
		{
			// Skip the plug lead in
			thisChar = this.charAt(++i);

			// If we have just a %% sequence, then simply collapse this
			// to a single % in the result.
			if (thisChar == '%')
			{
				str += '%';
			}
			else
			{
				// Check if there is a size specification with this plug
				if (thisChar >= '0' && thisChar <= '9')
				{
					// Extract the size
					size = parseInt(thisChar);

					// Skip other digits
					for (i++; (thisChar = this.charAt(i)) >= '0' && thisChar <= '9'; i++)
					{
						if (i == this.length) {
							// Oops, hit end of string, incomplete pattern
							// just break the loop and stop processing
							break;
						}
					}

					// If the current character is NOT a format char, and size is < 10 then
					// we had a %1 %2 type plug.
					if ((thisChar == '' || "dis".indexOf(thisChar) == -1) && size < 10) {
						thisWasChar = thisChar;
						thisChar = String(size);
						size = 0;
					}
				}

				// How we format this plug depends upon the plug type
				switch (thisChar)
				{
				case 'd': case 'i':

					// Numeric value, pad it to the required size.  If the
					// plug value is a number, convert to a string first.
					if (typeof(arguments[arg]) == 'number') {
						str += new String(arguments[arg]).pad(-size);
					} else {
						str += arguments[arg++].pad(-size);
					}
					break;

				case '1': case '2': case '3': case '4':
				case '5': case '6': case '7': case '8': case '9':
					if (parseInt(thisChar) <= arguments.length) {
						str += arguments[parseInt(thisChar)-1] + (thisWasChar ? thisWasChar : '');
					}
					break;

				case 's':

					// String value, simply add it padded appropriatly.
					str += arguments[arg++].pad(size);
					break;
				}
			}
		}
		else
		{
			// A normal character or a trailing %, just add it as-is to the
			// result.
			str += this.charAt(i);
		}
	}

	// Return the formatted string
	return str;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	String::reverse()
//
// Parameters:
//
// Description:
//	Returns the reverse of the string. IE last character becomes 
//	first etc.
//
// Return Value:
//	String		Results from the execution.
//
String.prototype.reverse = function() {
	var sOut = "";
	for (var i = this.length - 1; i >= 0; i--) sOut += this.charAt(i);
	return sOut;
}
 
///////////////////////////////////////////////////////////////////////
/////////////////////////// Rectangle Object //////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Object Rect (top, left, width, height)
//
// Parameters:
//	top			Integer, Top most coordinate (Y axis) of the rectangle.
//
//	left		Integer, Left most coordinate (X axis) of the rectangle.
//
//	width		Integer, Width of the rectangle.
//
//	height		Integer, Height of the rectangle.
//
// Description:
//	Rect object contructor, Creates and sets up the properties required
//	for a rectangle object.
//
// Return Value:
//	Rect		Rectangle object.
//
// Example:
//	var oRect = new Rect(10, 10, 10, 10);
//
function Rect(top, left, width, height) {
	this.top = top ? top : 0;
	this.left = left ? left : 0;
	this.width = width ? width : 0;
	this.height = height ? height : 0;
	this.bottom = this.top + this.height - 1;
	this.right = this.left + this.width - 1;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Rect::setWidth(w)
//
// Parameters:
//	w			Integer, New width to be applied to the rectangle.
//
// Description:
//	Alters the width of the rectangle object, the right property is
//	also adjusted for the new width.
//
Rect.prototype.setWidth = function(w) { 
	this.width = parseInt(w);
	this.right = this.left + this.width - 1;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Rect::setHeight(h)
//
// Parameters:
//	h			Integer, New height to be applied to the rectangle.
//
// Description:
//	Alters the height of the rectangle object, the bottom property is
//	also adjusted for the new height.
//
Rect.prototype.setHeight = function(h) { 
	this.height = parseInt(h);
	this.bottom = this.top + this.height - 1;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Rect::isEmpty()
//
// Description:
//	Determines whether this rectangle is empty. A rectangle is empty if 
//	its width or its height is less than or equal to zero.
//
// Return Value:
//	Boolean		true if rectangle is empty, false otherwise.
//
Rect.prototype.isEmpty = function() {
	return this.width == 0 || this.height == 0;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Rect::isInside(x, y)
//
// Parameters:
//	x			Integer, X coordinate to be checked agains't the
//				area of the rectangle.
//
//	y			Integer, Y coordinate to be checked agains't the
//				area of the rectangle.
//
// Description:
//	Determines whether the passed coordinates fall within the area of
//	of the rectangle.
//
// Return Value:
//	Boolean		true if coordinates fall within area occupied by the
//				rectangle, false otherwise.
//
Rect.prototype.isInside = function(x,y) {
	return x >= this.left && x <= this.right && y >= this.top && y <= this.bottom;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Rect::toString()
//
// Description:
//	Returns a string representation of the Rect object.
//
// Return Value:
//	String		String representation of the Rect object.
//
Rect.prototype.toString = function() {
	return 'Rect(' + this.left + ',' + this.top + ',' + this.width + ',' + this.height + ')';
}

///////////////////////////////////////////////////////////////////////
//////////////////////////// Element Object ///////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Object Element(obj)
//
// Parameters:
//	obj			HTML Element/Object reference to be wrapped up.
//
// Description:
//	This object is designed to wrap up an object from the DOM of the
//	browser in order to provide additional and compatable functionality
//	not available using the native DOM.
//
//	Where practical, the DOM interface has been replicated.
//
// Example:
//	var oElement = new Element(document.all("mainTable"));
//
function Element(obj) {

	// The DOM object reference
	this.el = obj;

	// Mirror some of the DOM collections
	if (this.el)
	{
		if (thePage.is.ie)
		{
			this.style		= obj.style;
			this.filters	= obj.filters;
			this.all		= obj.all;
		}
		else if (thePage.is.ns)
		{
			this.style		= obj;
			this.all		= null;		// TODO - How do we do this?
		}
	}

	// For inline method calling, return the new object
	return this;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::toString()
//
// Description:
//	Returns a string representation of the Element object.
//
// Return Value:
//	String		String representation of the Element object.
//
Element.prototype.toString = function() {
	return "Element(" + (this.el ? this.el.nodeName : 'undefined') + ")";
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::all(vKey)
//
// Parameters:
//	vKey		Variant, Integer or string that specifies the element 
//				or collection to retrieve. If this parameter is an 
//				integer, the method returns the element in the collection 
//				at the given position, where the first element has value 
//				0, the second has 1, and so on. If this parameter is a 
//				string and there is more than one element with the name 
//				or id property equal to the string, the method returns a
//				collection of matching elements.
//
// Description:
//	Returns a reference to a child element or a collection of child
//	elements.
//
// Return Value:
//	Variant		Element reference or collection of elements.
//
Element.prototype.all = function(vKey)
{
	if (this.el) {
		return this.el.all(vKey);
	}
	return null;
}

function _Element_Evaluate(str)
{
	return eval(str);
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::eval(str)
//
// Parameters:
//	String		Expression to be evaluated.
//
// Description:
//	Evaluates the required string expression and returns the result of
//	evaluation to the caller.
//
// Return Value:
//	Variant		Results returned from evaluating the str expression.
//
Element.prototype.eval = function(str) {
	if (typeof(this.el.eval) != 'function') {
		this.el.eval = _Element_Evaluate;
	}
	return this.el.eval(str);
} 

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::getWindowRect()
//
// Description:
//	Return a rectangle object relative to the origin of the client area
//	of the body of the current document.  The window area is the area
//	used by the element including it's border.
//
// Notes:
//	The Window Area also includes the elements scroll bars, margins
//	and padding.
//
// Return Value:
//	Rect		Rect object.
//
Element.prototype.getWindowRect = function()
{
	var rc = new Rect();
	if (this.el)
	{
		rc.top  = this.el.offsetTop;
		rc.left = this.el.offsetLeft;

		// See Measuring Element Dimension and Location from MSDN
		for (var o = this.el.offsetParent; o; o = o.offsetParent) {
			rc.top  += o.clientTop + o.offsetTop;
			rc.left += o.clientLeft + o.offsetLeft;
		}

		// The origin of elements positioned on a page is the top
		// left corner of the client area of the document body (or
		// so it seems).
		rc.left -= document.body.clientLeft;
		rc.top -= document.body.clientTop;

		// Set the width and height of the element to the offsetWidth
		// and offsetHeight which includes padding, margins and 
		// borders according the the documentation.
		rc.setWidth(this.el.offsetWidth);
		rc.setHeight(this.el.offsetHeight);
	}
	return rc;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::getClientRect()
//
// Description:
//	Return a rectangle object relative to the current document that
//	defines the client area of the Element object.  The client area
//	is the area used by the element excluding it's border.
//
// Return Value:
//	Rect		Rect object.
//
Element.prototype.getClientRect = function()
{
	var rc = this.getWindowRect();
	if (this.el) {
		rc.top += this.el.clientTop;
		rc.left += this.el.clientLeft;
		rc.setWidth(this.el.clientWidth);
		rc.setHeight(this.el.clientHeight);
	}
	return rc;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::moveIntoView(container)
//
// Description:
//	This method can be called to cause the left and top position of
//	the Element object to be adjusted so that the right and bottom
//	edges of the element are visible witin the specified container.
//	If the element is simply too large, the top and left positions are
//	simply clipped at the top & left most visble co-ordinate and the
//	right or bottom edges will remain not visible.
//
// Return Value:
//	Rect		Rect object. A rectangle object containing the updated 
//				window rect of the element.
//	
Element.prototype.moveIntoView = function(container)
{
	if (!container) container = document.body;
	var rc = this.getWindowRect();
	var right = container.scrollLeft + container.clientWidth;
	if (rc.right > right) {
		this.el.style.left = right - rc.width;
		if (this.el.style.left < container.scrollLeft) { 
			this.el.style.left = container.scrollLeft;
		}
		rc = this.getWindowRect();
	}
	var bottom = container.scrollTop + container.clientHeight;
	if (rc.bottom > bottom) {
		this.el.style.top = bottom - rc.height;
		if (this.el.style.top < container.scrollTop) { 
			this.el.style.top = container.scrollTop;
		}
		rc = this.getWindowRect();
	}
	return rc;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::centerInView([container])
//
// Parameters:
//	container		Optional Element, DOM Element/Object reference.
//					Default: document.body
//
// Description:
//	Positions the Element into the center of the container object.
//  
Element.prototype.centerInView = function(container)
{
	if (!container) container = document.body;
	if (this.el) {
		this.el.style.left = (container.clientWidth - this.el.offsetWidth) / 2;
		this.el.style.top  = (container.clientHeight - this.el.offsetHeight) / 2;
	}
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::findAttribute(name, [accum])
//
// Parameters:
//	name		String, Name of the attribute to be checked on parent 
//				elements of the current Element.
//
//	accum		Optional Boolean, True: Return all parent element 
//				attribute values of the required name. False: Only
//				return the value of the first attribute located
//				within onr of the parent elements.
//				Default: False
//
// Description:
//	Retreives the value(s) of the required attribute from parent
//	elements.
//
// Return Value:
//	Variant		Attribute value(s).
//  
Element.prototype.findAttribute = function(name, accum) {

	var attr = null;
	for (var o = this.el; o; o = o.parentElement) {
		var v = o.getAttribute(name);
		if (v) {
			if (!accum) { attr = v; break; }
			attr = attr ? v + attr : v;
		}
	}
	return attr;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::findElement(nodeName)
//
// Parameters:
//	String		Name of the parent node to be located.
//
// Description:
//	Searches up the parent tree to locate an Element with a nodeName
//	that matches the name of the node required.
//
// Return Value:
//	Element		Reference to a parent element with a matching nodeName,
//				null if no match is found.
//
Element.prototype.findElement = function(nodeName) {
	return this.getParentElement(nodeName);
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::getParentElement(nodeName)
//
// Parameters:
//	String		Name of the parent node to be located.
//
// Description:
//	Searches up the parent tree to locate an Element with a nodeName
//	that matches the name of the node required.
//
// Return Value:
//	Element		Reference to a parent element with a matching nodeName,
//				null if no match is found.
//
Element.prototype.getParentElement = function(nodeName) {
	nodeName = nodeName.toUpperCase();
	for (var o = this.el; o; o = o.parentElement) {
		if (o.nodeName == nodeName) {
			return o;
		}
	}
	return null;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Element::getChildElement(nodeName)
//
// Parameters:
//	String		Name of the child node to be located.
//
// Description:
//	Searches down the child tree to locate an Element with a nodeName
//	that matches the name of the node required.
//
// Return Value:
//	Element		Reference to a child element with a matching nodeName,
//				null if no match is found.
//
Element.prototype.getChildElement = function(nodeName) {

	nodeName = nodeName.toUpperCase();

	for (var i = 0, o = this.el; i < o.children.length; i++) {
		if (o.children(i).nodeName == nodeName) {
			return (o.children(i));
		}
	}
	return null;
}

///////////////////////////////////////////////////////////////////////
////////////////////// Mentor Web Page interface ////////////////////// 
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Object WebPage()
//
// Description:
//	The WebPage object is a single global static object that is
//	used to manage resources on a web page and provide functionality
//	via methods attached to the object.
//

var WebPage = new Object;

MentorWebPage = WebPage;			// backward compatability

///////////////////////////////////////////////////////////////////////
// WebPage: Methods
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::toString()
//
// Description:
//	Returns the name of the WebPage object.
//
// Return Value:
//	String		Name of the WebPage
//
WebPage.toString = function ()
{
	return WebPage.m_strName;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::setDebugLevel(l)
//
// Parameters:
//	l			Integer, Level of debugging to be set.
//
// Description:
//	Set the debug level to be applied within the WebPage object.
//
WebPage.setDebugLevel = function (l)
{
	thePage.debugLevel = l;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::debug(v)
//
// Parameters:
//	v			Variant(s), Arguments to be output to the debug area.
//
// Description:
//	Locates or creates an element with a name or ID of $$debug.  The 
//	innerText property of the debug element is then set to display
//	the debugs within the arguments collection.
//
WebPage.debug = function ()
{
	// Ignore, debugs not active
	if (!thePage.debugLevel) return;

	// Find the place to show debugs
	var el = document.all("$$debug");
	if (!el) {
		document.body.insertAdjacentHTML(
			"BeforeEnd",
			'<DIV id="$$debug" style="border:1;z-index:65535;position:absolute;top:0;left:0;'
								+ 'background-color:white;color:black"></DIV>');
		el = document.all("$$debug");
		if (!el) return;
	}

	// Display the debug message
	var str = "";
	var i; for (i = 0; i < arguments.length; i++) {
		if (i > 0) str += " ";
		str += arguments[i];
	}
	el.innerText = str;
}

///////////////////////////////////////////////////////////////////////
//	Browser Identification 

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::BrowserIs()
//
// Description:
//	Detects the browser make and version as well as the client operating 
//	system.  The object contains the following properties when created:
//
//	.major		The browser reported major version number.
//	.minor		The browser reported minor version number.
//
//	.nt			True if running under Windows NT
//	.nt4		True if running under Windows NT 4
//	.nt5		True if running under Windows NT 5
//
//	.ns			True if running under Netscape Navigator / Communicator
//	.ns2		True if running under Netscape 2
//	.ns3		True if running under Netscape 3
//	.ns4		True if running under Netscape 4
//	.ns5		True if running under Netscape 5
//
//	.ie			True if running under Internet Explorer
//	.ie3		True if running under Internet Explorer 3
//	.ie4		True if running under Internet Explorer 4
//	.ie5		True if running under Internet Explorer 5
//
//	.dhtml		True if this browser supports DHTML
//	
// Example:
//	var is = new WebPage.BrowserIs();

WebPage.BrowserIs = function ()
{
	////////////////////////////////////////////////////////
	// Get the browser major and minor versions
	////////////////////////////////////////////////////////

	this.major  = parseInt(navigator.appVersion);
	this.minor  = parseFloat(navigator.appVersion);

	////////////////////////////////////////////////////////
	// Detect the O/S
	////////////////////////////////////////////////////////

	var i;
	var v = navigator.appVersion;
	this.nt  = (i = v.indexOf("Windows NT")) != -1;
	if (this.nt) {
		this.nt4 = v.charAt(i+10) == ";";
		this.nt5 = !this.nt4 && v.charAt(i+11) == "5";
	}

	////////////////////////////////////////////////////////
	// Internet Explorer Detection
	////////////////////////////////////////////////////////

	var agent = navigator.userAgent.toLowerCase();
	if (this.ie = agent.indexOf("msie"))
	{
		this.ie = true;
		this.ie3 = this.major < 4;
		this.ie4 = this.major == 4 && agent.indexOf("msie 5.0") == -1;
		this.ie5 = this.major == 4 && agent.indexOf("msie 5.0") != -1;
	}

	////////////////////////////////////////////////////////
	// Netscape Detection
	////////////////////////////////////////////////////////

	if (agent.indexOf('mozilla') != -1
				&& agent.indexOf('spoofer') == -1
				&& agent.indexOf('compatible') == -1
				&& agent.indexOf('opera') == -1
				&& agent.indexOf('webtv') == -1)
	{
		 this.ns = true;
		 this.ns2 = this.major == 2;
		 this.ns3 = this.major == 3;
		 this.ns4 = this.major == 4;
		 this.ns5 = this.major >= 5;
	}

	// Check for DHTML support
	this.dhtml = this.major >= 4;
}

///////////////////////////////////////////////////////////////////////
//	Browser Compatability 
/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::_InitCompatability()
//
// Description:
//	Allows for some IE and Netscape differences to become less trivial.
//	The layers collection is created if running under IE and the .all
//	collection is created if running under NetScape.
//
WebPage._InitCompatability = function()
{
	// Detect browser version
	WebPage.is = new WebPage.BrowserIs();

	// Define the "layers" collection (for IE)
	if (!document.layers && document.all) {
		document.layers = document.all;
	}

	// Define the "all" collection (for netscape)
	if (!document.all) document.all = document;
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::layers(name)
//
// Parameters:
//	name		Variant, Key index, or ID/Name of the layer required
//				from the layers collection.
//
// Description:
//	Accesses the layers collection and retrieves the required layer.
//
// Return Value:
//	Layer		Returns a reference to the required Layer 
//				object/element.
//
WebPage.layers = function(name)
{
	return document.layers(name);
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::all(name)
//
// Parameters:
//	name		Variant, Key index, or ID/Name of the element required
//				from the document element (.all) collection.
//
// Description:
//	Accesses the .all collection and retrieves the required element.
//
// Return Value:
//	Element		Returns a reference to the required DOM 
//				object/element.
//
WebPage.all = function(name)
{
	return document.all(name);
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::OnImageLoad(img)
//
// Parameters:
//	img			IMG Object/Element, Element to have its onload event
//				cancelled
//
// Description:
//	Animated GIF's fire the onload handler each time they loop so
//	cancel the onload event as it fires.
//
WebPage.OnImageLoad = function(img)
{
	// Cancel the onload handler.
	// Animated GIF's fire the onload handler each time they loop!!
	if (img) {
		img.onload = null;
	}
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::loadImage(src)
//
// Parameters:
//	src			String, URL of the image to be loaded. 
//
// Description:
//	Forces an image to be loaded (pre-cached).  The image is instantly
//	available to the browser when it is required, e.g. dynamic HTML
//	may have the background image of a button changed as and when an
//	event fires (onmouseover), having the image pre-loaded means that 
//	the browser doesn't have to download the new background image 
//	before it can be displayed.
//
WebPage.loadImage = function(src)
{
	var imgId = 0;
	WebPage.m_imgPool[imgId = WebPage.m_imgPool.length] = new Image();
	WebPage.m_imgLoading ++;
	WebPage.m_imgPool[imgId].onload = new Function(
							"return WebPage.OnImageLoad("
								+ "WebPage.m_imgPool[" + imgId + "]"
							+ ");");
	WebPage.m_imgPool[imgId].src = src;
	return WebPage.m_imgPool[imgId];
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::addToObjectPool(obj)
//
// Parameters:
//	obj			Object Reference, Reference to the object that is to
//				be added to the object pool.
//
// Description:
//	Allows us to get back to an object instance during an event handler.
//
// Example:
//	function MyTableObject(objTable) {
//		thePage.addToObjectPool(this);
//
//		// Store a reference to the passed table Element/Object.
//		this.table = objTable;
//
//		// Register the event handlers for the required table.
//		this.table.onmouseover = new Function ( "return " + this.toString() + ".onmouseover();" );
//		this.table.onmouseout  = new Function ( "return " + this.toString() + ".onmouseout();" );
//	}
//
//	MyTableObject.prototype.onmouseover = function () {
//		// Some table code.......
//	}
//
//	MyTableObject.prototype.onmouseout = function () {
//		// Some table code.......
//	}
//
WebPage.addToObjectPool = function(obj)
{
	var objId = 0;
	WebPage.m_objPool[objId = this.m_objPool.length] = obj;
	obj.m_nObjectId = objId;
	obj.m_strName = "WebPage.m_objPool[" + obj.m_nObjectId + "]";
	obj.toString = new Function ("return this.m_strName;")
	return objId;
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::loadStyleSheet(url, i)
//
// Parameters:
//	url			String, Specifies how to add the style sheet to the 
//				document. If a file name is specified for the URL, the 
//				style information will be added as a link object. If 
//				the URL contains style information, this information 
//				will be added to the style object.
//
//	i			Integer, Specifies the index that indicates where the 
//				new style sheet is inserted in the styleSheets 
//				collection. The default is to insert the new style 
//				sheet at the end of the collection.
//
// Description:
//	Loads a stylesheet into the calling document.
//
WebPage.loadStyleSheet = function(url, i)
{
	// the document.createStyleSheet() method only works if the header has
	// not finished loading (for example, from a defer'd script).
	// So if the body element is defined, the use alternative ways of
	// loading the style sheet.
	if (!document.body && document.createStyleSheet)
	{
		// Still loading header, can create a style sheet.
		document.createStyleSheet(url, i);
	}
	else
	{
		// If we have a style sheet collection, then we can import the
		// style sheet into one of the existing ones.
		if (document.styleSheets.length > 0)
		{
			document.styleSheets(0).addImport(url, i);
		}
		else
		{
			// TODO: We got here either because document.createStyleSheet()
			// is not supported or the document has already loaded and there 
			// are no stylesheets in the stylesheet collection.
			if (document.body)
			{
				// Bit knackered, dunno what to do.  Issue an error message and
				// drop through and emit a link element just incase it works
				alert("can't load only stylesheet once document's loaded");
			}

			// Still in the header, and emit a link element
			document.write('<link rel="StyleSheet" type="text/css" href="' + url + '">');
		}
	}
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::loadScript(url, [language])
//
// Parameters:
//	url			String, URL to an external file that contains the 
//				source code or data. 
//
//	language	Optional String, Language in which the current script is 
//				written. Default 'JavaScript'.
//
// Description:
//	Loads a script into the calling document.
//
WebPage.loadScript = function(url, language)
{
	document.write('<script language="'
					+ (language ? language : 'JavaScript') + '" src="' + url + '"></s' + 'cript>');
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::scriptLoaded(scr)
//
// Parameters:
//	scr			String, Name of a script file to registered as loaded.
//
// Description:
//	Registers the required script file as being loaded.  This allows
//	other scripts with dependancies to check the loaded state of
//	scripts that it may have a dependency on.
//
WebPage.scriptLoaded = function(scr)
{
	scr = "{" + scr + "}";
	if (typeof(WebPage.m_strScriptsLoaded) == 'undefined')
	{
		WebPage.m_strScriptsLoaded = scr;
	}
	else
	{
		if (WebPage.m_strScriptsLoaded.indexOf(scr) == -1) {
			WebPage.m_strScriptsLoaded += scr;
		}
	}
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::gotScript(scr)
//
// Parameters:
//	scr			String, Name of a script file to be checked.
//
// Description:
//	Checks and returns the results of a script having being loaded
//	into the current document.  See the scriptLoaded method for
//	further documentation.
//
// Return Value:
//	Boolean		Status of script being loaded, True: Loaded, False: 
//				Not loaded.
//
WebPage.gotScript = function(scr)
{
	scr = "{" + scr + "}";
	return (typeof(WebPage.m_strScriptsLoaded) != 'undefined' && WebPage.m_strScriptsLoaded.indexOf(scr) != -1)
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::disableContextMenu()
//
// Description:
//	Disables the right click context menu on the calling document.
//
WebPage.disableContextMenu = function() {
	document.oncontextmenu = function() {
		return false;
	}
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::enableContextMenu()
//
// Description:
//	Enables the right click context menu on the calling document after
//	it has been cancelled.
//
WebPage.enableContextMenu = function() {
	document.oncontextmenu = null;
}

/////////////////////////////////////////////////////////////////////// 
// Prototype:
//	WebPage::cookieEnabled()
//
// Description:
//	Retreives the status of cookies being enabled.
//
// Return Value:
//	Boolean		Cookie enabled status, True: Enabled, False: Disabled.
//
WebPage.cookieEnabled = function ()
{
	return navigator.cookieEnabled;
}

///////////////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::readCookie(name, [def])
//
// Parameters:
//	name		String, Name of a value to be read from the cookie.
//
//	def			Optional Variant, Default value to be returned if the value
//				from the cookie can't be retreived.
//
// Description:
//	Retrieve the value of the cookie specified by "name". Please see the 
//	setCookie method for more documentation.
//
// Return Value:
//	Variant		Required value from a cookie.  
//
WebPage.readCookie = function(name, def)
{
	var theBigCookie;

	// If no cookies on this page, then fail now.
	if ((theBigCookie = document.cookie).length > 0)
	{
		// there is a cookie, see if the cookie we want exists
		var firstChar = theBigCookie.indexOf(name + '=');

		// if the cookie was found
		if (firstChar != -1)
		{
			// skip 'name' and '='
			firstChar += name.length + 1;

			// Find the end of the value string (i.e. the next ';').
			var lastChar = theBigCookie.indexOf(';', firstChar);
			if (lastChar == -1) {
				lastChar = theBigCookie.length;
			}

			// return the cookie value
			return unescape(theBigCookie.substring(firstChar, lastChar));
		}
	}

	// There was no cookie of that name, return the default if defined or null.
	return def ? def : null; 
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::setCookie(name, value, [hours], [path], [domain], [secure])
//
// Parameters:
//	name		String, Name to be associated with the value, same 
//				name to be used to retreive the value.
//				(Please see the readCookie method).
//
//	value		String, Value to be stored within the cookie.
//
//	hours		Optional Variant, If "hours" is specified then this is 
//				used to set an expiry time for the cookie.  If "hours" 
//				is a number, then it is the number of hours before the 
//				cookie should expire.  If "hours" is a string, then it 
//				is interpreted as a date string specifying the time 
//				the cookie should expore.
//
//	path		Optional String, Setting a path for the cookie allows 
//				the current document to share cookie information with 
//				other pages within the same domain—that is, if the path 
//				is set to thispathname, all pages in thispathname and 
//				all pages in subfolders of thispathname can access the 
//				same cookie information.
//
//	domain		Optional String, Setting the domain of the cookie allows 
//				pages on a domain made up of more than one server to 
//				share cookie information. 
//
//	secure		Setting a cookie as secure; means the stored cookie 
//				information can be accessed only from a secure 
//				environment.
//
// Description:
//	Sets the "value" of the cookie specified by "name" for the optionally
//	specified path and domain.
//
// Return Value:
//	Variant		If the cookie exists, the value of the cookie is returned, otherwise
//				null is returned.
//
WebPage.setCookie = function (name, value, hours, path, domain, secure)
{
	// Don't waste your time if the browser doesn't accept cookies.
	if (WebPage.cookieEnabled())
	{
		// Netscape Navigator 2 cannot handle Dates, so skip this part
		if (hours && !this.ns2)
		{
			var numHours = null;

			// already a Date string
			if ( (typeof(hours) == 'string') && Date.parse(hours) )
			{
				numHours = hours;
			}
			else
			{
				// calculate Date from number of hours
				if (typeof(hours) == 'number')
				{
					numHours = Date.now() + (hours * 3600000);
					numHours = (new Date(numHours)).toGMTString();
				}
			}
		}
		
		// Set the cookie, adding any parameters that were specified.
		document.cookie = name	+ '=' + escape(value)
								+ (numHours ? (';expires=' + numHours) : '')
								+ (path ? ';path=' + path : '')
								+ (domain ? ';domain=' + domain : '')
								+ ((secure && (secure == true)) ? '; secure' : '');
	}
}

///////////////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::killCookie(name, [path], [domain])
//
//	name		String, Name of the cookie to be killed.
//
//	path		Optional String, Path containing the cookie to be killed.
//
//	domain		Optional String, domain containing the cookie to be killed.
//
// Description:
//	Delete (kill) the cookie who's name is "name".  If domain and or path are
//	specified, the cookie within that path/domain is killed.
//
//	The cookie is killed by making it expired.
//
WebPage.killCookie = function(name, path, domain)
{
	// We need the value to kill the cookie
	var theCookie = thePage.readCookie(name);
  
	// get the time of the recent past
	var exp = new Date(Date.now() - 1);
  
	// set an already-expired cookie of the same name and value
	document.cookie = name + "=" + "; expires=" + exp.toGMTString()
									+ (path ? ';path=' + path : '')
									+ (domain ? ';domain=' + domain : '');
} 

// ??? - crad - Is This Still Needed
///////////////////////////////////////////////////////////////////////
// Prototype:
//	thePage::getLang()
//
// Description:
//	Call this method obtain the two character browser language code.
//
// Return:
//	String		Two character country code of the browser.
//
WebPage.getLang = function()
{
	return navigator.browserLanguage.substr(0,2);
}

// ??? - crad - Is This Still Needed
///////////////////////////////////////////////////////////////////////
// Prototype:
//	thePage::getLanguage()
//
// Description:
//	Call this method obtain the full browser language.
//
// Return Value:
//	String		Browser language.
WebPage.getLanguage = function()
{
	return navigator.browserLanguage;
}

// ??? - crad - Is This Still Needed
///////////////////////////////////////////////////////////////////////
// Prototype:
//	thePage::loadResourceScript(baseUrl, [suffix], [fEvenEnglish])
//
//	baseUrl		String, URL of the script to be loaded.
//
//	suffix		Optional String, Allows the suffix of the script to be 
//				specified, Default: '.js'.
//
//	fEvenEnglish	Optional String, Tells this method to only try and 
//					load the resource script if the language is not an 
//					english variant.  Default: false.
//
// Description:
//	Call this method to load a resource script (a javascript file 
//  containing language specific strings etc) from the specified base
//	location.
//
WebPage.loadResourceScript = function(baseUrl, suffix, fEvenEnglish)
{
	var lang = WebPage.getLang();
	if (lang != 'en' || fEvenEnglish) {
		document.write('<script language="JavaScript" src="'
						+ baseUrl
						+ lang
						+ (suffix ? suffix : '.js')
						+ '"></script>');
	}
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::queryString (arg, [def], [url])
//
// Parameters:
//	arg			String, name of the variable in the HTTP query string 
//				to retrieve.
//
//	def			Optional Variant, Value to be returned to the caller
//				if the required querystring argument doesn't exist.
//
//	url			Optional String, URL for the value to be taken from.
//				Default: document.URL.
//
// Description:
//	Retrieves the required querystring argument from the current 
//	document's URL.
//
// Return Value:
//	Varaint		Query string argument value or the def value.
//
WebPage.queryString = function (arg, def, url) {
	// Default the return value to be an empty string.
	if (typeof(def) == "undefined") def = "";
	
	// If we haven't been passed a URL to extract the value from then
	// use the current documents URL.
	if (typeof(url) == "undefined" || !url) url = document.URL;
	
	// Check for arguments.
	var nArgs = url.indexOf ("?");
	
	// If we have arguments.
	if (nArgs != -1) {
		// Ensure we have a string object
		arg = new String (arg);

		// Retreive the current documents URL with the querystring.
		var strUrl = unescape(url.substr (nArgs));

		// Locate the position of the passed argument within the URL querystring.
		var nArgIndex = strUrl.indexOf ("?" + arg + "=");
		if (nArgIndex == -1) nArgIndex = strUrl.indexOf ("&" + arg + "=");			
		
		// If the argument was located within the querystring
		if (nArgIndex != -1) {
			var strValue = strUrl.substr (strUrl.indexOf ("=", nArgIndex) + 1);
			
			// If the value of the passed arguments has trailing argument then detach them
			// from our value.
			if (strValue.indexOf ("&") != -1) {
				strValue = strValue.substr (0, strValue.indexOf ("&"));
			}
		
			return strValue;
		}
	
	}
	return def;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::launchHref (sHref, [sTarget])
//
// Parameters:
//	sHref		String, Href to be launched form an anchor point.
//
//	sTarget		Optional String, Window or frame at which to target the 
//				contents.
//
// Description:
//	Launches the required href as if it was an anchor that had been
//	clicked.
//
WebPage.launchHref = function (sHref, sTarget) {
	// Create a new (A)nchor element.
	var objA = document.createElement("A");
	
	// Set the required link properties.
	objA.href = sHref;
	if (typeof(sTarget) != "undefined" && sTarget) objA.target = sTarget;
	
	// Append the link to the current document.
	document.body.appendChild (objA);
	
	// Fire of the link and then remove it from the document.
	objA.click();
	objA = objA.removeNode (true);
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::hideSupportInfo ()
//
// Description:
//	Hides the support info element.
//
WebPage.hideSupportInfo = function() {
	if (WebPage.m_objSupportInfo) {
		WebPage.m_objSupportInfo.style.display = 'none';
	}
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::showSupportInfo ()
//
// Description:
//	Shows the support info element.
//
WebPage.showSupportInfo = function()
{
	var strHTML;

	// Make sure the Support Info layer is available.
	WebPage.m_objSupportInfo = new Element(thePage.layers("$$SupportInfo"));
	if (!WebPage.m_objSupportInfo.el)
	{
		strHTML = '<table id="$$SupportInfo"'
						+ ' style="position:absolute;z-index:65535;'
								+ 'background-color: white; font-family: Arial;'
								+ 'border-top: 4px #D0D0D0 solid;'
								+ 'border-left: 4px #D0D0D0 solid;'
								+ 'border-right: 4px black solid;'
								+ 'border-bottom: 4px black solid;'
								+ 'margin:10px; padding:10px;">'
						+ '<tr><td valign="top" id="$$SupportInfoDetails">'
						+ '</td></tr></table>';
		document.body.insertAdjacentHTML("BeforeEnd", strHTML);
		WebPage.m_objSupportInfo = new Element(thePage.layers("$$SupportInfo"));
	}

	var sPath = getRootPath(document.location.pathname);
	
	// Generate the support info popup window.
	strHTML = '<table width="100%">'
				+ '<tr><td colspan="3" bgcolor="blue">'
					+ '<table width="100%"><tr style="color:white; font-weight: bold;">'
						+ '<td>'
						+	'<img border="0" src="' + sPath + 'images/framework/icons/info-32x32.gif" align="absmiddle">'
						+	'&nbsp;<FONT SIZE="+1">Support Info:</FONT></td>'
						+ '<td align="right">'
						+	'<img style="cursor:hand" onclick="thePage.hideSupportInfo()"'
						+		' border="0" align="right" src="' + sPath + 'images/framework/icons/cross.gif">'
						+	'</td>'
					+ '</tr></table>'
				+ '</td></tr>'
				+ '<tr><td width="10">&nbsp;</td><td>'
				+ '<br><div style="height:300;width:500;overflow:scroll;">'
				+ '<table width="100%">'

				// Support Info Content
				+ '<tr><td colspan="2" bgcolor="#808080"'
					+ ' style="color:white;font-size:10pt;font-weight:bold;">Browser Details:</td></tr>'

				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>appName:</td>'
				+ '<td style="font-size:10pt;">' + navigator.appName + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>appVersion:</td>'
				+ '<td style="font-size:10pt;">' + navigator.appVersion + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>browserLanguage:</td>'
				+ '<td style="font-size:10pt;">' + navigator.browserLanguage + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>cookieEnabled:</td>'
				+ '<td style="font-size:10pt;">' + thePage.cookieEnabled() + '</td></tr>'

				+ '<tr><td colspan="2">&nbsp;</td></tr>'
				+ '<tr><td colspan="2" bgcolor="#808080"'
					+ ' style="color:white;font-size:10pt;font-weight:bold;">Page Details:</td></tr>'

				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>thePage Object:</td>'
				+ '<td style="font-size:10pt;">'
					+ WebPage.m_strName + ' (Version ' + WebPage.m_strVersion + ')'
					+ '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>URL:</td>'
				+ '<td style="font-size:10pt;">' + document.URL + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>Referrer:</td>'
				+ '<td style="font-size:10pt;">' + document.referrer + '</td></tr>'
				+ ( WebPage.m_strPageVersion
					? '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>Page Version:</td>'
						+ '<td style="font-size:10pt;">'
						+ WebPage.m_strPageVersion
						+ '</td></tr>'
					: 'not specified')
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>Ready State:</td>'
				+ '<td style="font-size:10pt;">' + document.readyState + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>Last Modified:</td>'
				+ '<td style="font-size:10pt;">' + document.lastModified + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>File Created:</td>'
				+ '<td style="font-size:10pt;">' + document.fileCreatedDate + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>File Modified:</td>'
				+ '<td style="font-size:10pt;">' + document.fileModifiedDate + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>File Size:</td>'
				+ '<td style="font-size:10pt;">' + document.fileSize + '</td></tr>'
				+ '<tr><td style="font-size:10pt;font-weight:bold;" nowrap>Design Mode:</td>'
				+ '<td style="font-size:10pt;">' + document.designMode + '</td></tr>'

				+ '<tr><td colspan="2">&nbsp;</td></tr>'

				+ '</table>'
				+ '</div><p align="right" style="padding:0;margin:0;font-family:Arial;font-size:7pt">'
				+ 'Copyright 2000, Mentor Systems Ltd.  All rights reserved.</p>'
				+ '</td>'
				+ '<td width="10">&nbsp;</td>'
				+ '</tr></table>';

	// Show the info dialog.
	WebPage.m_objSupportInfo.el.all("$$SupportInfoDetails").innerHTML = strHTML;
	WebPage.m_objSupportInfo.style.display = 'block';
	WebPage.m_objSupportInfo.centerInView();
}

///////////////////////////////////////////////////////////////////////

WebPage.setPageVersion = function(ver) {
	WebPage.m_strPageVersion = ver;
}

//// 006 //////////////////////////////////////////////////////////////

WebPage.kickIEImagesHandler = function() {
	// No Work
}

WebPage.kickIEImages = function(el)
{
	// Create our kicked images array
	if (typeof(document.kickedImages) == "undefined") {
		document.kickedImages = new Array();
	}
	
	// Q269802: When you browse to a Web site 
	// that dynamically adds images to a page, 
	// some of those images may intermittently 
	// fail to appear.
  	var imgs = el.all.tags("IMG");
	for (var i = 0; imgs && i < imgs.length; i++) {
		var img = document.kickedImages[document.kickedImages.length] = new Image;
		img.src = imgs[i].src;
		imgs[i].kicker = img;
		imgs[i].onreadystatechange = WebPage.kickIEImagesHandler;
	}
}

//// 006 //////////////////////////////////////////////////////////////

WebPage.remoteExec = function(url) {
	if (typeof(WebPage.m_objHiddenFrame) == "undefined") {
		document.body.insertAdjacentHTML(
				"afterEnd", '<IFRAME name="m_objHiddenFrame" src="" width="0" height="0"></IFRAME>'
			);
		WebPage.m_objHiddenFrame = document.frames("m_objHiddenFrame");
	}
	WebPage.m_objHiddenFrame.window.location.href = url;
}

//// 007 //////////////////////////////////////////////////////////////
//
// Prototype:
//	WebPage::copyToClipboard(str)
//
// Description:
//	Copy the passed string to the clipboard.
//
// Warnings:
//	The current selection is undefined after calling this method.
//	
WebPage.copyToClipboard = function (str)
{
	var el = document.all("WebPage_copyToClipboard");
	if (!el) {
		document.body.insertAdjacentHTML("beforeEnd",
				'<TEXTAREA style="z-index:-1;position:absolute;top:0;width:0;height:0;overflow:clip;" id="WebPage_copyToClipboard"></TEXTAREA>'
			);
		el = document.all("WebPage_copyToClipboard");
	}
	el.innerText = str;
	var sel = document.body.createTextRange();
	sel.moveToElementText(el);
	sel.select();
	document.execCommand("Copy");
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::isCollection(oElement)
//
// Parameters:
//	oElement		Variant, Element to be checked if its a collection.
//
// Description:
//	Checks the passed element to see whether or not it is a collection.
//
// Return Value:
//	Boolean			Status of the passed oElement being a collection.
//
WebPage.isCollection = function(oElement) {
	return	typeof(oElement) != "undefined"
			&& oElement
			&& typeof(oElement.item) != "undefined"
			&& (typeof(oElement.length) != "undefined" || typeof(oElement.count) != "undefined");
		 	
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	WebPage::getParentWindow(sName, oWindow)
//
// Parameters:
//	sName		String, Name of the window to be located within the 
//				parent hierarchy of window elements.
//
//	oWindow		Optional Window, Reference to the starting window
//				window element to be used as the starting point
//				for the parent hierarchy.
//				Default: Current window.
//
// Description:
//	Retreives a reference to a parent window.
//
// Return Value:
//	Variant		Window reference if a window is found with the requried 
//				name or null if no matching window is found.
//
WebPage.getParentWindow = function(sName, oWindow) {
	// If we haven't been passed starting window object 
	// then use the window of the current document.
	if (!oWindow) oWindow = window;
	
	// Loop up the parent windows until we find the required window.
	for (;oWindow && oWindow.name != sName; oWindow = oWindow.parent);
	
	// Return a reference to our findings.
	return oWindow;
}

///////////////////////////////////////////////////////////////////////
// WebPage: Properties
///////////////////////////////////////////////////////////////////////

// Define the web page object name (global reference) and the global.js
// version
WebPage.m_strName = "thePage";
WebPage.m_strVersion = _version_global_js;

// Add our selves to our own object pool.
WebPage.m_objPool = new Array();
WebPage.addToObjectPool(this);

// The web page image pool (for pre-caching web page images)
WebPage.m_imgPool = new Array();
WebPage.m_imgLoading = 0;

// Initialise browser compatability methods
WebPage._InitCompatability();

///////////////////////////////////////////////////////////////////////
/////////////////////////// thePage Object ////////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Object thePage();
//
// Description:
//	The "thePage" object is a reference to the static WebPage
//	object.  This object is used to hold web page resources such as
//	the image and object pools, and has many methods to aid in web
//	page development.
//
// Example:
//	<script language="JavaScript" src="lib/objects/global.js"></script>
//	

var thePage = WebPage;

///////////////////////////////////////////////////////////////////////

// Signal that global.js has now loaded
thePage.scriptLoaded("global.js");

///////////////////////////////////////////////////////////////////////////////
//
//	Fire the "ongloballoaded" event if a handler is defined
if (typeof(document.ongloballoaded) == "function") {
	document.ongloballoaded();
}

///////////////////////////////////////////////////////////////////////
////////////////////////// collection Object //////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Object Collection()
//
// Description:
//	Handles and controls an array as if it was a collection.
//
// Example:
//	var cNames = new Collection();
//	cNames.add ("Mr Turkey Face", "turkey");
//
//	alert (cNames.item("turkey));	// Output 'Mr Turkey Face'
//
// Notes:
//	The string/integer value of an existing item can only be changed by 
//	accessing the collection property (Array Object) directly.
//		e.g. cName.collection["turkey"] = "Mr Turkey Nose";
//	This does not apply to any other items i.e. Objects.
//
function Collection () {
	// Create an array to store our collection items.
	this.newenum = this.collection = new Array();
	this.count = this.length = 0;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::item(vKey)
//
// Parameters:
//	vKey		Variant, String Key or index position of the item
//				required from the collection.
//
// Description:
//	Access the collection and returns the required element.
//
// Return Value:
//	Variant		Required value from within the collection.
//
Collection.prototype.item = function(vKey) {
	return this.collection[vKey];
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::add(vItem, [sKey], [vPosition])
//
// Parameters:
//	vItem		Variant, Item to be added into the collection.
//
//	sKey		Optional String, Key value to be used against the 
//				new entry within the collection.  This value can
//				be used with the .item method.
//
//	vPosition	Optional Variant, Key or index position of an exising
//				item of which we are to insert the new item before.
//				Default: Item is appended to the collection.
//
// Description:
//	Adds/Inserts a new item into the collection.
//
// Return Value:
//	Variant		New item.
//
Collection.prototype.add = function(vItem, sKey, vPosition) {
	switch (true) {
		case typeof(sKey) == "undefined" || !sKey:
			// If the item isn't a string then we can't use it as a key.
			if (typeof(vItem) != "string") {
				// Update the count/length properties.
				this.count = this.length = this.collection.length + 1;
				
				if (typeof(vPosition) == "undefined") {
					// No key string, this item can only be accessed through its index position.
					var newItem = this.collection[this.collection.length] = vItem;
				} else {
					var newItem = this.collection[vPosition];
				}

				return newItem;
			} else {
				// Use the actual value of the item as the key.
				sKey = vItem
			}

		case typeof(sKey) == "string":
			// Update the count/length properties.
			this.count = this.length = this.collection.length + 1;

			if (typeof(vPosition) == "undefined") {
				// We have been given a key string to be associated with the collection item.
				var newItem = this.collection[sKey] = this.collection[this.collection.length] = vItem;
			} else {
				this.collection[sKey] = vItem;
				this.collection.splice(vPosition, 0, vItem);
				var newItem = this.collection[vPosition];
			}
			break;
	}

	return newItem;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::clear()
//
// Description:
//	Clears down the existing collection.
//
Collection.prototype.clear = function() {
	delete this.collection;
	delete this.newenum;
	this.newenum = this.collection = new Array();
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::itemexists(vKey)
//
// Parameters:
//	vKey		Variant, Key or index position of item to be checked.
//
// Description:
//	Checks whether an item exists within the collection.
//
// Return Value:
//	Boolean		Status of item existing.
//
Collection.prototype.itemExists = function(vKey) {
	try {
		// Try to access the required item.
		return (typeof(this.item(vKey)) != "undefined");
	} catch (e) {
		// If we have reached here, then its because an error occured
		// trying to access the required element (element doesn't exist).
		return false;
	}
	
	// No errors occured so the item must exist.
	return true;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::remove(vKey)
//
// Parameters:
//	vKey		Variant, Key or index position of the item to be
//				removed from the collection.
//
// Description:
//	Removes a particular item from the Collection.
//
Collection.prototype.remove = function(vKey) {
	// We can only remove valid items.
	if (typeof(vKey) == "undefined") return;
	
	// Ensure that the memory allocated to the array element to be removed
	// is properly cleared down.
	delete this.collection[vKey];

	// Remove the required item from the collection using its key/index.
	this.collection.splice(vKey, 1);

	// Update the count/length properties.
	this.count = this.length = this.collection.length;
}

///////////////////////////////////////////////////////////////////////
// Prototype:
//	Collection::execute(vKey)
//
// Parameters:
//	vKey		Variant, Key or index position of the item to be
//				executed.
//
// Description:
//	It is possible to build up a list of eval strings or function
//	references.  This method allows for the execution of a particular
//	item.
//
// Return Value:
//	Variant		Results from the execution.
//
Collection.prototype.execute = function(vKey) {
	// Determine the type of execution we need to carry out.
	switch (typeof(this.collection[vKey])) {
		case "string": 		return (eval(this.collection[vKey]));
		case "function":	return this.collection[vKey]();
		default: 			alert ("collection Error: Invalid collection key/index."); break;
	}
	
	return null;
}

function getRootPath(sPath)
{
	return "/ramportal/";
	//var iPos = sPath.indexOf("/", 1);
	//return sPath.substr(0, iPos + 1);
}
