// **********************************************************
// **** JavaScript Library   Version 2.60   October 2011 ****
// **********************************************************
//
// function visitorLog(page, ASPTime)
//
// function ajax(pageURL, startTag, endTag, retryFlag)
// function ajaxPost(pageURL, parameters, startTag, endTag, retryFlag)
//
// fumction ajaxAsync(pageURL, callbackFunction, startTag, endTag, timeout)
// function ajaxPostAsync(pageURL, parameters, callbackFunction, startTag, endTag, timeout)
//
// fumction ajaxAsyncUpdateDiv(pageURL, divId, startTag, endTag, timeout)
// function ajaxPostAsyncUpdateDiv(pageURL, parameters, divId, startTag, endTag, timeout)
//
// function strHTML(s)
// function strTrim(s)
// function strTitle(s)
// function strDecode(s)
// function strEncrypt(s)
// function strGetInnerHTML(html, tag)
// function strEncodeHTML(s)
// function strDecodeHTML(s)
// function strReplace(strInput, s1, s2)
//
// function formatDate0(d)
// function formatDate1(d)
// function formatDate2(d)
// function formatDate3(d)
// function formatDate4(d)
// function formatMonth1(d)
// function formatTime1(d)
//
// function setCookie(cookieName, coockieValue, expiresInDays)
// function getCookie(cookieName)
// function deleteCookie(cookieName)
//
// function checkEmailSyntax(emailAddress)
//
// function getScreenSize()
// function centerDiv(divId)
//
// function hourglass(mode)
//
// -----------------------------------------------------------------------------------------------------------------------------------------
//
// Change log:
//
//     V2.60 - Small changes to the strGetInnerHTML(html, tag) function - check the input parameters more closely.
//     V2.59 - Added function formatDate0(d)
//     V2.58 - Added function formatDate4(d)
//     V2.57 - Added function strReplace(x, s1, s2)
//     V2.56 - Added function setCookie(cookieName, coockieValue, expiresInDays)
//     V2.56 - Added function getCookie(cookieName)
//     V2.56 - Added function deleteCookie(cookieName)
//     V2.55 - Bug fix in function ajaxPostAsyncUpdateDiv();
//     V2.54 - Added function strTitle(s)
//     V2.53 - Added optional retryFlag parameter to ajax() and ajaxPost();
//     V2.53 - Fixed some bugs in ajaxAsyncUpdateDiv() and ajaxPostAsyncUpdateDiv();
//     V2.52 - Added function strEncodeHTML(s)
//     V2.52 - Added function strDecodeHTML(s)
//     V2.52 - Added function strGetInnerHTML(html, tag).
//     V2.51 - Added function formatDate3(d).
//     V2.50 - Rewrote function checkEmailSyntax(emailAddress).
//     V2.49 - Rewrote all ajax functions.
//     V2.48 - Added optional parameter timeout to functions ajaxAsync(), ajaxPostAsync(), ajaxAsyncUpdateDiv(), ajaxPostAsyncUpdateDiv()
//     V2.47 - Added function formatMonth1(d)
//     V2.47 - Added function formatMonth2(d)
//     V2.47 - Added function formatDate1(d)
//     V2.47 - Added function formatDate2(d)
//     V2.47 - Added function formatTime1(d)
//     V2.46 - Added fumction ajaxAsync(pageURL, callbackFunction, startTag, endTag)
//     V2.46 - Added function ajaxPostAsync(pageURL, parameters, callbackFunction, startTag, endTag)
//     V2.46 - Added function strEncrypt(s)
//     V2.45 - Added function strDecode(s)
//     V2.44 - Added function ajaxAsyncUpdateDiv(pageURL, divId, startTag, endTag)
//     V2.44 - Added function ajaxPostAsyncUpdateDiv(pageURL, parameters, divId, startTag, endTag)
//     V2.43 - Added function strHTML(s).
//     V2.42 - Added function getScreenSize().
//     V2.42 - Added function centerDiv(divId).
//     V2.42 - Added function hourglass(mode).
//     V2.42 - Rewrote visitorLog(page, ASPTime) to take advantage of the new function getScreenSize() which calculates the available window size much more acurately.
//     V2.41 - Added function checkEmailSyntax(emailAddress).
//     V2.40 - Initial consolidated version of the library.
//
// -----------------------------------------------------------------------------------------------------------------------------------------

function visitorLog(page, ASPTime)
{
	// The parameter ASPTime (number, single precision) is optional, it is the number of seconds it took to prepare the ASP page - i.e. ASP execution time.
	// When calling this function, do not forget to use escape() for the page parameter.

	if(ASPTime)
		ajax("AppVisitorLog.asp?Page=" + page + "&ScreenW=" + getScreenSize().width + "&ScreenH=" + getScreenSize().height + "&AvailableW=" + getScreenSize().availableWidth + "&AvailableH=" + getScreenSize().availableHeight + "&ASPTime=" + ASPTime);
	else
		ajax("AppVisitorLog.asp?Page=" + page + "&ScreenW=" + getScreenSize().width + "&ScreenH=" + getScreenSize().height + "&AvailableW=" + getScreenSize().availableWidth + "&AvailableH=" + getScreenSize().availableHeight);
}

function ajax(pageURL, startTag, endTag, retryFlag)
{
	// Requests a web page with arguments in the URL (get method).
	// The call is synchronous, the code will wait for a response.
	// If startTag and endTag are supplied, returns only the section inside those tags.
	// Set the optional parameter retryFlag to true if the code needs to retry in case of whatever error (for up to 1 minute, then an error is thrown).
	// If you need to specify retryFlag but not startTag and endTag, then simply put undefined for those two arguments.
	// When calling ASP pages using this function, for debugging define the variable debugAjax as follow: var debugAjax = true;

	return ajaxPost(pageURL, null, startTag, endTag, retryFlag);
}

function ajaxPost(pageURL, parameters, startTag, endTag, retryFlag)
{
	// Requests a web page with arguments in the URL (if any is supplied in pageURL) and also in the HTTP header (post method).
	// This way more data can be sent that using ajax().
	// Put the parameters for the header in 'parameters' - example: "param1=" + escape("blahblah") + "&param2=" + escape("blahblah"). Notice the use of escape().
	// The call is synchronous, the code will wait for a response.
	// If startTag and endTag are supplied, returns only the section inside those tags.
	// Set the optional parameter retryFlag to true if the code needs to retry in case of whatever error (for up to 1 minute, then an error is thrown).
	// If you need to specify retryFlag but not startTag and endTag, then simply put undefined for those two arguments.
	// When calling ASP pages using this function, for debugging define the variable debugAjax as follow: var debugAjax = true;

	var now = new Date;
	var randomNumber;
	var cacheOverride;
	var xmlHttp;
	var startTime = new Date();
	var currentTime;

	randomNumber = escape(now.toUTCString() + " " + now.getUTCMilliseconds() + " " + Math.floor(Math.random()*100000));

	if(pageURL.indexOf("?") == -1)
		cacheOverride = "?CacheOverride=" + randomNumber;
	else
		cacheOverride = "&CacheOverride=" + randomNumber;

	try {
		xmlHttp = new XMLHttpRequest();
	} catch(e) {
		try {
			xmlHttp = new ActiveXObject("Msxml2.xmlHttp");
		} catch(e) {
			try {
				xmlHttp = new ActiveXObject("Microsoft.xmlHttp");
			} catch(e) {
				return null;
			}
		}
	}
	
	while(true) {
	
		try {

			if(parameters == null) {
				xmlHttp.open("get", pageURL + cacheOverride, false);
				xmlHttp.send(null);
				
			} else {
				xmlHttp.open("post", pageURL + cacheOverride, false);
				xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
				xmlHttp.setRequestHeader("Content-length", parameters.length);
				xmlHttp.setRequestHeader("Connection", "close");
				xmlHttp.send(parameters);
			}

			if(xmlHttp.readyState == 4)
				if(xmlHttp.status == 200)
					return ajaxProcessHtml(xmlHttp.responseText, startTag, endTag);
				
			ajaxError("error", pageURL + cacheOverride, xmlHttp);
		
			if(retryFlag == undefined)
				return null;
			
		} catch(e) {
			if(retryFlag == undefined)
				return null;
		}
		
		currentTime = new Date();
		
		if(currentTime - startTime > 60000) {
			alert('Error communicating with remote server using Ajax!');
			throw('Ajax error');
		}
	}
}

function ajaxAsync(pageURL, callbackFunction, startTag, endTag, timeout)
{
	// Requests a web page with arguments in the URL (get method).
	// The call is asynchronous, the code will not wait for a response.
	// But when a response is received, it will invoke the callback function and pass to it the retrieved HTML.
	// If startTag and endTag are supplied, returns only the section inside those tags.
	// The optional timeout parameter is in seconds (not miliseconds). In case of a timeout, callbackFunction will be called with null as it's parameter.
	// If you need to specify timeout but not startTag and endTag, then simply put undefined for those two arguments.
	// When calling ASP pages using this function, for debugging define the variable debugAjax as follow: var debugAjax = true;
	// Example:
	//     ajaxAsync("test.asp", function(html) { alert(html); } );
 
	ajaxPostAsync(pageURL, null, callbackFunction, startTag, endTag, timeout);
}

function ajaxPostAsync(pageURL, parameters, callbackFunction, startTag, endTag, timeout)
{
	// Requests a web page with arguments in the URL (if any is supplied in pageURL) and also in the HTTP header (post method).
	// This way more data can be sent that using ajax().
	// Put the parameters for the header in 'parameters' - example: "param1=" + escape("blahblah") + "&param2=" + escape("blahblah"). Notice the use of escape().
	// The call is asynchronous, the code will not wait for a response.
	// But when a response is received, it will invoke the callback function and pass to it the retrieved HTML.
	// If startTag and endTag are supplied, returns only the section inside those tags.
	// The optional timeout parameter is in seconds (not miliseconds). In case of a timeout, callbackFunction will be called with null as it's parameter.
	// If you need to specify timeout but not startTag and endTag, then simply put undefined for those two arguments.
	// When calling ASP pages using this function, for debugging define the variable debugAjax as follow: var debugAjax = true;
	// Example:
	//     ajaxPostAsync("test.asp", "a=123", function(html) { alert(html); } );
	
	var now = new Date;
	var randomNumber;
	var cacheOverride;
	var timer;
	var xmlHttp;
	var callCounter = 0;

	randomNumber = escape(now.toUTCString() + " " + now.getUTCMilliseconds() + " " + Math.floor(Math.random()*100000));

	if(pageURL.indexOf("?") == -1)
		cacheOverride = "?CacheOverride=" + randomNumber;
	else
		cacheOverride = "&CacheOverride=" + randomNumber;

	try {
		xmlHttp = new XMLHttpRequest();
	} catch(e) {
		try {
			xmlHttp = new ActiveXObject("Msxml2.xmlHttp");
		} catch(e) {
			try {
				xmlHttp = new ActiveXObject("Microsoft.xmlHttp");
			} catch(e) {
				callbackFunction(null);
				return null;
			}
		}
	}

	xmlHttp.onreadystatechange = function() {
		if(xmlHttp.readyState == 4) {
			clearTimeout(timer);
			if(xmlHttp.status == 200) {
				if(++callCounter == 1)
					callbackFunction(ajaxProcessHtml(xmlHttp.responseText, startTag, endTag));
			} else {
				ajaxError("error", pageURL + cacheOverride, xmlHttp);
				if(++callCounter == 1)
					callbackFunction(null);
			}
		}
	};

	if(timeout) {
		timer = setTimeout(function () {
			ajaxError("timeout", pageURL + cacheOverride, xmlHttp);
			try {
				xmlHttp.abort();
			} catch(e) {
			}
			if(++callCounter == 1)
				callbackFunction(null);
		}, timeout * 1000);
	}
	
	try {

		if(parameters == null) {
			xmlHttp.open("get", pageURL + cacheOverride, true);
			xmlHttp.send(null);
		} else {
			xmlHttp.open("post", pageURL + cacheOverride, true);
			xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			xmlHttp.setRequestHeader("Content-length", parameters.length);
			xmlHttp.setRequestHeader("Connection", "close");
			xmlHttp.send(parameters);
		}
		
	} catch(e) {
		clearTimeout(timer);
		if(++callCounter == 1)
			callbackFunction(null);
	}
}

function ajaxAsyncUpdateDiv(pageURL, divId, startTag, endTag, timeout)
{
	// Same as ajaxAsync, but when a response is received it will updated a div (or whatever other element) whose id has been provided).
	
	ajaxAsync(pageURL, function(html) {
		if(document.getElementById(divId))
			document.getElementById(divId).innerHTML = (html != null ? html : "");
	}, startTag, endTag, timeout);
}

function ajaxPostAsyncUpdateDiv(pageURL, parameters, divId, startTag, endTag, timeout)
{
	// Same as ajaxPostAsync, but when a response is received it will updated a div (or whatever other element) whose id has been provided).

	ajaxPostAsync(pageURL, parameters, function(html) {
		if(document.getElementById(divId))
			document.getElementById(divId).innerHTML = (html != null ? html : "");
	}, startTag, endTag, timeout);
}

function ajaxProcessHtml(html, startTag, endTag)
{
	var p;
	
	if(html == null)
		return null;
	
	if(html == '')
		return null;

	if(startTag)
		if((p = html.toUpperCase().indexOf(startTag.toUpperCase())) > -1)
			html = html.slice(p + startTag.length);

	if(endTag)
		if((p = html.toUpperCase().indexOf(endTag.toUpperCase())) > -1)
			html = html.slice(0, p);

	if(html == '')
		return null;

	return html;
}

function ajaxError(errorType, pageURL, xmlHttp)
{
	if(typeof debugAjax == "undefined")
		return;
		
	if(!debugAjax)
		return;
		
	var msg = "Ajax " + errorType + "!\nURL = " + pageURL;
	
	try {
		msg += "\nreadyState = " + xmlHttp.readyState + "\nstatus = " + xmlHttp.status + "\nresponseText = " + xmlHttp.responseText;
	} catch(e) {
	}
		
	if(typeof(console) == 'undefined')
		alert(msg);
	else
		console.error(msg);
}

function strHTML(s)
{
	// Formats a string for use in HTML - encodes & < >.
	// This is useful when, for instance, setting the innerHTML property of a DOM object.
	// It does NOT encode the quote character (as it should).
	// This function has been replaced by strEncodeHTML(s) and strDecodeHTML(s).
		
	return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

function strTrim(s)
{
	while(s.substr(0, 1) == " " || s.substr(0, 1) == "\n" || s.substr(0, 1) == "\r" || s.substr(0, 1) == "\t")
		s = s.slice(1, s.length)

	while(s.substr(s.length - 1) == " " || s.substr(s.length - 1) == "\n" || s.substr(s.length - 1) == "\r" || s.substr(s.length - 1) == "\t")
		s = s.slice(0, s.length - 1)

	return s
}

function strTitle(s)
{
	// Capitalizes each world in a string (if the first letter was lowercase).
	
	var x = ' ';
	var r = '';

	for(i = 0; i < s.length; i++) {
	
		c = s.substr(i, 1);
		
		if(x == ' ')
			r += c.toUpperCase();
		else
			r += c;
			
		x = c;
	}
	
	return r;
}


function strDecode(s)
{
	// This is a pair of functions:
	// - VB StrEncode(s) is used to encode a string.
	// - JavaScript strDecode(s) is used to decode the string.
	// This is practical when calling JavaScript from HTML (like onclick or whatever), a string parameter can be encode and then no worries about special characters.
	
	var a;
	var x = "";
	
	if(!s)
		return("");

	a = s.split(",");
		
	for(i = 0; i < a.length; i++)
		x = x + String.fromCharCode(a[i]);
		
	return(x);		
}

function strEncrypt(s)
{
	// This is used for simple encryption.
	// It uses XOR so there is no need for a separate decryption routine - simply call strEncrypt() to encrypt and to decrypt.
	// There is an equavalent VB function.

	var i, k, x;
	
	k = "reuadnaL vatsuG - .yltnereffid gnivaheb yb ,spihsnoitaler rehto gnitcartnoc yb ti yortsed ew ;roivaheb namuh fo edom a ,sgnieb namuh neewteb pihsnoitaler niatrec a ,noitidnoc a si etatS ehT";

	while(s.length > k.length)
		k = k + k

	x = "";

	for(i = 0; i < s.length; i++)
		x = x + String.fromCharCode(s.charCodeAt(i) ^ k.charCodeAt(i));

	return(x);
}

function strGetInnerHTML(html, tag)
{
	// Serches an html string and returns the part that is inclosed by the specified tag.
	// The serch for the tag is not case sensitive.
	// The tag argument can be something like '<test>' or just 'test'.
	// If the spefified tag is, say, '<test>', the function will expand it to also include '<test xxx yyy zzz>'.
	// If the tag is not found, the function returns null.
	// If html is an empty string or null, the function returns null.
	// If tag is an empty string or null, the function returns null.
	//
	// Example: strGetInnerHTML('<test>1965</test>', 'test') will return 1965.
	// Example: strGetInnerHTML('<test>1965</test>', '<test>') will also return 1965.
	// Example: strGetInnerHTML('<test xxx yyy zzz>1998</test>', 'test') will return 1998.
	// Example: strGetInnerHTML('<test></test>', 'test') will return an empty string.
	// Example: strGetInnerHTML('<test></test>', 'body') will return null.
	
	var h;
	var t;
	var p1, p2, p3;
	
	// Check the input parameters.
	
	if(html == null || tag == null)
		return null;
		
	if(html.length == 0 || tag.length == 0)
		return null;

	// For the purpose of searching the strings, convert them to lowercase.

	h = html.toLowerCase();
	t = tag.toLowerCase();
	
	// If the tag argument has < and >, then remove those.
		
	if(t.charAt(0) == '<')
		t = t.substr(1);
		
	if(t.length == 0)
		return null;

	if(t.charAt(t.length - 1) == '>')
		t = t.substr(0, t.length - 1);

	if(t.length == 0)
		return null;
	
	// Find the starting tag.
	
	if((p1 = h.indexOf('<' + t)) == -1)
		return null;
	
	if((p2 = h.indexOf('>', p1 + t.length)) == -1)
		return null;
		
	// Find the ending tag.

	if((p3 = h.indexOf('</' + t + '>', p2 + 1)) == -1)
		return null;
		
	// Extract what's inside the tags.
		
	return html.substr(p2 + 1, p3 - p2 - 1);
}

function strEncodeHTML(s)
{
	// The function decodes html special characters (< > " &).

	while(s.indexOf('&') != -1)
		s = s.replace('&', '[AMPSPECIALCHARACTER]');
	
	while(s.indexOf('<') != -1)
		s = s.replace('<', '&lt;');

	while(s.indexOf('>') != -1)
		s = s.replace('>', '&gt;');

	while(s.indexOf('"') != -1)
		s = s.replace('"', '&quot;');
		
	while(s.indexOf('[AMPSPECIALCHARACTER]') != -1)
		s = s.replace('[AMPSPECIALCHARACTER]', '&amp;');

	return s;
}

function strDecodeHTML(s)
{
	// The function decodes html special characters (&lt; &gt; &quot; &amp;).

	while(s.indexOf('&lt;') != -1)
		s = s.replace('&lt;', '<');

	while(s.indexOf('&gt;') != -1)
		s = s.replace('&gt;', '>');

	while(s.indexOf('&quot;') != -1)
		s = s.replace('&quot;', '"');

	while(s.indexOf('&amp;') != -1)
		s = s.replace('&amp;', '&');
		
	return s;
}

function strReplace(x, s1, s2)
{
	// This function takes x and replaces all instances of s1 with s2.
	
	var p1 = 0;
	var p2;
	var y = '';
	
	while((p2 = x.indexOf(s1, p1)) >= 0) {
		y += x.substring(p1, p2) + s2;
		p1 = p2 + s1.length;
	}
	
	return y + x.substring(p1);
}
	
function formatDate0(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "yyyy-mm-dd".

	if(!d)
		d = new Date();

	return d.getFullYear() + "-" + (d.getMonth() + 1 < 10 ? '0' : '') + (d.getMonth() + 1) + "-" + (d.getDate() < 10 ? '0' : '') + d.getDate();
}

function formatDate1(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "yyyy-m-d".

	if(!d)
		d = new Date();
	
	return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate();
}

function formatDate2(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "Dddd Mmmm d, yyyy".
	
	var weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
	var month   = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	
	if(!d)
		d = new Date();
		
	return weekday[d.getDay()] + " " + month[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
}

function formatDate3(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "Mmmm d, yyyy".
	
	var month   = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	
	if(!d)
		d = new Date();
		
	return month[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
}

function formatDate4(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "Ddd m/d".
	
	var weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
	
	if(!d)
		d = new Date();
		
	return weekday[d.getDay()] + " " + (d.getMonth() + 1) + "/" + d.getDate();
}

function formatMonth1(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "Mmmm".

	var month   = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

	if(!d)
		d = new Date();
	
	return month[d.getMonth()];
}

function formatMonth2(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "Mmm".

	var month   = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

	if(!d)
		d = new Date();
	
	return month[d.getMonth()].substr(0, 3);
}

function formatTime1(d)
{
	// Takes as input a date (optional - if not supplied, uses the current date and time). Returns a string "hh:mm am/pm".
	
	var h1, h2, m1, m2, ampm;
	
	if(!d)
		d = new Date();
	
	h1 = d.getHours();
	m1 = d.getMinutes();
	
	if(h1 == 0) {
		h2 = "12";
		ampm = "am";
	} else if(h1 >= 1 && h1 <= 9) {
		h2 = "0" + h1;
		ampm = "am";
	} else if(h1 >= 10 && h1 <= 11) {
		h2 = h1.toString();
		ampm = "am";
	} else if(h1 == 12) {
		h2 = "12";
		ampm = "pm";
	} else {
		h2 = (h1 - 12).toString();
		ampm = "pm";
	}
	
	if(m1 < 10)
		m2 = "0" + m1
	else
		m2 = m1
		
	return h2 + ":" + m2 + " " + ampm
}

function setCookie(cookieName, coockieValue, expiresInDays)
{
	// expiresInDays is optional. If not supplied, the cookie will expire when the browser is closed.

	if(expiresInDays) {
		
		var expireDate = new Date();

		expireDate.setDate(expireDate.getDate() + expiresInDays);

		document.cookie = cookieName + "=" + escape(coockieValue) + ";expireDate=" + expireDate.toGMTString();
	
	} else {
		
		document.cookie = cookieName + "=" + escape(coockieValue);
	}
}

function getCookie(cookieName)
{
	var search = cookieName + "="

	if (document.cookie.length > 0) {
		offset = document.cookie.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = document.cookie.indexOf(";", offset);
			if (end == -1)
				end = document.cookie.length;
			return unescape(document.cookie.substring(offset, end));
		}
	}
	
	return null;
}

function deleteCookie(cookieName)
{
	document.cookie = cookieName + "=; expireDate=Fri, 31 Dec 1999 23:59:59 GMT;";
}

function checkEmailSyntax(emailAddress)
{
	// Checks the email syntax, returns true or false.
	//
	// Note: The local part of an email address is case sensitive.
	//
	// This function is self-contained, it does not call anything else in JavaScript.js.
	// It is equivalent to the VBS function CheckEmailSyntax() in Utilities.vbs.
	//
	// For reference on valid email syntax: http://en.wikipedia.org/wiki/Email_address
	// For reference on valid TLDs: http://en.wikipedia.org/wiki/List_of_Internet_top-level_domainParts

	var localPart, domainPart;
	var i, p;

	var localPartValidChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-/=?^_`{|}~.";
	var domainPartValidChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.";

	var tld   = [".com", ".gov", ".mil", ".net", ".org", ".edu", ".int",
                 ".aero", ".asia", ".biz", ".cat", ".coop", ".info", ".jobs", ".mobi", ".museum", ".name", ".pro", ".tel", ".travel",
                 ".arpa",
                 ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".ax", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gb", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".me", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".rs", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".su", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".za", ".zm", ".zw"];

	// Check to see if we got anyting at all.

	if(emailAddress == null)
		return false;

	if(emailAddress == "")
		return false;

	// The email address cannot be longer than 254 characters.
	
	if(emailAddress.length > 254)
		return false;

	// Separate local part and domain part.
	
	p = emailAddress.indexOf("@");
	
	if(p == -1)
		return false;

	localPart = emailAddress.substr(0, p);
	domainPart = emailAddress.substring(p + 1);
	
	// Local part must be at least 1 character long but no longer than 64 characters.

	if(localPart.length < 1 || localPart.length > 64)
		return false;

	// Domain part must be at least 4 characters long and contain a dot.

	if(domainPart.length < 4 || domainPart.indexOf(".") == -1)
		return false;

	// Local part cannot start or end with a dot, no consecutive dots.

	if(localPart.charAt(0) == "." || localPart.charAt(localPart.length - 1) == "." || localPart.indexOf("..") != -1)
		return false;

	// Domaint part cannot start or end with a dot, no consecutive dots.

	if(domainPart.charAt(0) == "." || domainPart.charAt(domainPart.length - 1) == "." || domainPart.indexOf("..") != -1)
		return false;

	// Verify valid characters in local part.

	for(i = 0; i < localPart.length; i++)
		if(localPartValidChars.indexOf(localPart.charAt(i)) == -1)
			return false;

	// Verify valid characters in domain part.

	for(i = 0; i < domainPart.length; i++)
		if(domainPartValidChars.indexOf(domainPart.charAt(i)) == -1)
			return false;

	// Check the TLD (not case sensitive) and exit.
	
	for(i = 0; i < tld.length; i++)
    	if(domainPart.substring(domainPart.lastIndexOf(".")).toLowerCase() == tld[i])
    		return true;         
	
	return false;
}

function getScreenSize()
{
	// This function returns the screen resolution and the available (visible) size of the browser window (also called the viewport).
	//
	// Returns:
	//
	//     getScreenSize().width           = The screen resolution, width.
	//     getScreenSize().height          = The screen resolution, height.
	//     getScreenSize().availableWidth  = The available (visible) width of the browser window.
	//     getScreenSize().availableHeight = The available (visible) height of the browser window.
	//
	// Example: alert(getScreenSize().width + " x " + getScreenSize().height + "\n" + getScreenSize().availableWidth + " x " + getScreenSize().availableHeight);
	//
	// For reference see: http://www.demtron.com/blog/post/2009/01/14/Centering-a-DIV-Window-with-Cross-Browser-JavaScript.aspx
	//                    http://www.w3schools.com/jsref/dom_obj_all.asp
	//                    http://james.padolsey.com/javascript/get-document-height-cross-browser/
	//
	// This function was verified in IE8, FF 3.6.8, and Safari 5.0.1.
	// This function was verified with: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
	
	var v, h;
	var aw, ah;

	w = screen.width;
	h = screen.height;

	if(!window.innerWidth) {

		//IE.

		if(!(document.documentElement.clientWidth == 0)) {
			// Strict mode.
			aw = document.documentElement.clientWidth;
			ah = document.documentElement.clientHeight;
		} else {
			// Quirks mode.
			aw = document.body.clientWidth;
			ah = document.body.clientHeight;
		}
		
	} else {

		//W3C.

		aw = window.innerWidth;
		ah = window.innerHeight;
		
		// If the scrollbar(s) are present, substract 17.
		
		if(document.documentElement.scrollWidth > aw)
			ah -= 17;
		
		if(document.documentElement.scrollHeight > ah)
			aw -= 17;
	}

	return {width: w, height: h, availableWidth: aw, availableHeight: ah};
}

function centerDiv(divId)
{
	// Centers a window on the visible part of the browser window (viewport).
	//
	// The parameter divID is the name of the div to center (not a pointer to it).
	
	var d = document.getElementById(divId).style;
	var w = parseInt(d.width);
	var h = parseInt(d.height);
	var offsetX;
	var offsetY;
		
	if(!window.pageYOffset) {
	
		//IE.

		if(!(document.documentElement.scrollTop == 0)) {
			// Strict mode.
			offsetX = document.documentElement.scrollLeft;
			offsetY = document.documentElement.scrollTop;
		} else {
			// Quirks mode.
			offsetX = document.body.scrollLeft;
			offsetY = document.body.scrollTop;
		}

	} else {

		//W3C.

		offsetX = window.pageXOffset;
		offsetY = window.pageYOffset;
	}

	d.left = parseInt(((getScreenSize().availableWidth  - w) / 2) + offsetX) + "px";
	d.top  = parseInt(((getScreenSize().availableHeight - h) / 2) + offsetY) + "px";
}

function hourglass(mode)
{
	// This function will display a rotating hourglass on the screen.
	//
	// Call as follow:
	//
	//     hourglass('on')      Displays the rotating hourglass.
	//     hourglass('off')     Hides the rotating hourglass.
	//     hourglass('resize')  Call this every time the window resizes.
	//
	// The following images are prerequisites:
	//
	//     Images/OpaqueScreen.png
	//     Images/RotatingHourglass.gif
	
	var d;
	
	if(!document.getElementById("waitScreen")) {
		d = document.createElement("div");
		d.id                    = "waitScreen";
		d.style.position        = "absolute";
		d.style.left            = "0px";
		d.style.top             = "0px";
		d.style.width           = "100px";
		d.style.height          = "100px";
		d.style.display         = "none";
		d.style.zIndex          = "9998";
		d.style.backgroundImage = "url('Images/OpaqueScreen.png')";
		document.body.appendChild(d);
	}
	
	if(!document.getElementById("waitHourglass")) {
		d = document.createElement("div");
		d.id                    = "waitHourglass";
		d.style.position        = "absolute";
		d.style.left            = "0px";
		d.style.top             = "0px";
		d.style.width           = "236px";
		d.style.height          = "236px";
		d.style.display         = "none";
		d.style.zIndex          = "9999";
		d.innerHTML             = "<img src=\"Images/RotatingHourglass.gif\" border=\"0\" style=\"width: 236px; height: 236px\">";
		document.body.appendChild(d);
	}
	
	var ws = document.getElementById("waitScreen").style;
	var wh = document.getElementById("waitHourglass").style;

	with(document.getElementById("waitHourglass").style) {
	
		switch(mode) {

			case "on":
			
				ws.width  = getScreenSize().availableWidth + "px";
				ws.height = getScreenSize().availableHeight + "px";
			
				centerDiv("waitScreen");
				centerDiv("waitHourglass");

				ws.display = "block";
				wh.display = "block";

				break;

			case "off":

				ws.display = "none";
				wh.display = "none";

				break;

			case "resize":
			
				if(ws.display == "block") {
					ws.width  = getScreenSize().availableWidth + "px";
					ws.height = getScreenSize().availableHeight + "px";
					centerDiv("waitScreen");
				}

				if(wh.display == "block")
					centerDiv("waitHourglass");
		}
	}
}
