/*

FILENAME:		utilities.js

DESCRIPTION:	External JavaScript file to supports JavaScript functions, including pop-up windows, form validation routines, AJAX calls, etc.

AUTHOR:			Alex Jonas

LAST MODIFIED:	12/16/2011

*/

	var newWin = true;

	function popWin(url, winName) {

		newWin = window.open(url, winName, 'width=600,height=500,resizable,scrollbars,screenX=50,screenY=50,left=50,top=50');

	}


	function createXMLHttpRequest() {

		var objXMLHttpRequest = false;

		if (window.XMLHttpRequest) {

			try {

				objXMLHttpRequest = new XMLHttpRequest();

			} catch(e) {

				objXMLHttpRequest = false;

			}

		} else if (window.ActiveXObject) {

			var arrVersions = [

				'MSXML2.XMLHttp.6.0',
				'MSXML2.XMLHttp.3.0'

			];

			try {

				for (var i = 0; i < arrVersions.length; i++) {

					try {

						objXMLHttpRequest = new ActiveXObject(arrVersions[i]);
						return objXMLHttpRequest;

					} catch(e) {

						var objXMLHttpRequest = false;

					}

				}

			} catch(e) {

				objXMLHttpRequest = false;

			}

		}

		return objXMLHttpRequest;

	}


	function isGoodFormat(str, format) {

		// Pass in string value and correct format also as a string value, 
		// with the pound sign (#) used as a marker for numbers.
		// For example, '123-45-6789' and '###-##-####' for U.S. SSNs,
		// '01/01/2005' and '##/##/####' for date strings in mm/dd/yyyy format.

		if (str.length != format.length) {

			return false;

		}

		for (var i = 0; i < format.length; i++) {

			if (format.charAt(i) == '#') {

				if (!isNumeric(str.charAt(i))) {

					return false;

				}

			} else {

				if (format.charAt(i) != str.charAt(i)) {

					return false;

				}

			}

		}

		return true;

	}


	function isNumeric(a) {

		// Evaluates to true or false, depending on whether the passed string is numeric.

		return (a == parseInt(a));

	}


	function isGoodTimePeriod(startDate, endDate) {

		// Evaluates to true or false, depending on whether the endDate is greater than or equal to the startDate.

		var dtStartDate = new Date(startDate);
		var dtEndDate = new Date(endDate);

		return ((dtEndDate - dtStartDate) >= 0);

	}


	function showStatePostalAbbreviations() {

		var postalAbbreviations = document.open('http://www.icons.umd.edu/staff/shared.postabbv','postal_abbreviations','width=475,height=325,scrollbars,screenX=25,screenY=25,left=25,top=25');

	}
	
	
	function go_to_resource(external_resource_id) {

		if ( external_resource_id != parseInt(external_resource_id, 10) ) return;  //external_resource_id must be an integer
	
		var strResourceURL;
		var strURL;
		var strBaseURL;
		var strParams;
		var strParameter;
		var name;
		var value;

		var arrURLParts;
		var arrParams;
		var arrParameter;

		strResourceURL = ('http://www.icons.umd.edu/programs/website.log_access?p_id=' + external_resource_id + '&p_sid=');
	
		strURL = window.location.href;
	
		arrURLParts = strURL.split('?');
	
		if (arrURLParts.length > 1) {
	
			strBaseURL = arrURLParts[0];
			strParams = arrURLParts[1];
	
		}
	
		arrParams = strParams.split('&');

		if (arrParams) {
	
			for (var i = 0; i < arrParams.length; i++) {
		
				if (arrParams[i] != null) {
			
					strParameter = arrParams[i];
			
					arrParameter = strParameter.split('=');
				
					name = arrParameter[0];
					value = arrParameter[1];
				
					if (name.toLowerCase() == 'p_sid') {
				
						if ( value == parseInt(value, 10) ) {  //p_sid must be an integer
					
							strResourceURL += value;
						
							window.location.href = strResourceURL;
					
						} else {
					
							return;
						
						}
				
					}					
			
				}
		
			}
	
		}
	
		return;

	}

	
	function autocorrectEmailDomain(element) {
  
		//Corrects common e-mail address domain typos.
  
		if (element.value.length == 0 || element.value.indexOf('@') == -1) return;

		var typoDomain = new Array();
		typoDomain[0] = ['gmial.co','gmail.co'];
		typoDomain[1] = ['gail.co','gmail.co'];
		typoDomain[2] = ['gmil.co','gmail.co'];
		typoDomain[3] = ['gmal.co','gmail.co'];
		typoDomain[4] = ['gmai.co','gmail.co'];
		typoDomain[5] = ['mgail.co','gmail.co'];
		typoDomain[6] = ['gmial.co','gmail.co'];
		typoDomain[7] = ['gmali.co','gmail.co'];
		typoDomain[8] = ['ggmail.co','gmail.co'];
		typoDomain[9] = ['gmmail.co','gmail.co'];
		typoDomain[10] = ['gmaail.co','gmail.co'];
		typoDomain[11] = ['gmaiil.co','gmail.co'];
		typoDomain[12] = ['gmaill.co','gmail.co'];
		typoDomain[13] = ['yaho.co','yahoo.co'];
		typoDomain[14] = ['ahoo.co','yahoo.co'];
		typoDomain[15] = ['yhoo.co','yahoo.co'];
		typoDomain[16] = ['yaoo.co','yahoo.co'];
		typoDomain[17] = ['yaho.co','yahoo.co'];
		typoDomain[18] = ['yaho.co','yahoo.co'];
		typoDomain[19] = ['ayhoo.co','yahoo.co'];
		typoDomain[20] = ['yhaoo.co','yahoo.co'];
		typoDomain[21] = ['yaoho.co','yahoo.co'];
		typoDomain[22] = ['yahoo.co','yahoo.co'];
		typoDomain[23] = ['yyahoo.co','yahoo.co'];
		typoDomain[24] = ['yaahoo.co','yahoo.co'];
		typoDomain[25] = ['yahhoo.co','yahoo.co'];
		typoDomain[26] = ['yahooo.co','yahoo.co'];
		typoDomain[27] = ['yahooo.co','yahoo.co'];
		typoDomain[28] = ['hotmial.co','hotmail.co'];
		typoDomain[29] = ['otmail.co','hotmail.co'];
		typoDomain[30] = ['htmail.co','hotmail.co'];
		typoDomain[31] = ['homail.co','hotmail.co'];
		typoDomain[32] = ['hotail.co','hotmail.co'];
		typoDomain[33] = ['hotmil.co','hotmail.co'];
		typoDomain[34] = ['hotmal.co','hotmail.co'];
		typoDomain[35] = ['hotmai.co','hotmail.co'];
		typoDomain[36] = ['ohtmail.co','hotmail.co'];
		typoDomain[37] = ['htomail.co','hotmail.co'];
		typoDomain[38] = ['homtail.co','hotmail.co'];
		typoDomain[39] = ['hotamil.co','hotmail.co'];
		typoDomain[40] = ['hotmial.co','hotmail.co'];
		typoDomain[41] = ['hotmali.co','hotmail.co'];
		typoDomain[42] = ['hhotmail.co','hotmail.co'];
		typoDomain[43] = ['hootmail.co','hotmail.co'];
		typoDomain[44] = ['hottmail.co','hotmail.co'];
		typoDomain[45] = ['hotmmail.co','hotmail.co'];
		typoDomain[46] = ['hotmaail.co','hotmail.co'];
		typoDomain[47] = ['hotmaiil.co','hotmail.co'];
		typoDomain[48] = ['hotmaill.co','hotmail.co'];
		typoDomain[49] = ['hotamil.co','hotmail.co'];

		var userId;
		var domain;
		var regex;

		//[userId, domain] = element.value.toLowerCase().split('@');
		
		var emailPart = new Array();
		
		emailPart = element.value.toLowerCase().split('@');
			
		userId = emailPart[0];
		domain = emailPart[1];
		
		for (var i = 0; i < typoDomain.length; i++) {

			regex = new RegExp("^" + typoDomain[i][0]);

			if ( regex.test(domain) ) {  //If there's a match with a domain typo...

				domain = domain.replace(regex, typoDomain[i][1]);
				element.value = userId.toLowerCase() + '@' + domain; // ...Change the input value to reflect the corrected domain.
				break;

			} else {

				element.value = element.value.toLowerCase();  // ...Else change the existing input value to lowercase.

			}
				
		}


	}

	
//ARRAY EXTRAS
//Array methods introduced in JavaScript versions 1.6 and higher, as codified in ECMAScript.
//The following scripts add support for these array methods to those browsers, most notably Internet Explorer,
//that do not already support them.

//Returns the first index at which a given element can be found in the array, or -1 if it is not present.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = 0;
    if (arguments.length > 0)
    {
      n = Number(arguments[1]);
      if (n !== n)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    if (n >= len)
      return -1;

    var k = n >= 0
          ? n
          : Math.max(len - Math.abs(n), 0);

    for (; k < len; k++)
    {
      if (k in t && t[k] === searchElement)
        return k;
    }
    return -1;
  };
}



//Returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards, starting at fromIndex.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
if (!Array.prototype.lastIndexOf)
{
  Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = len;
    if (arguments.length > 0)
    {
      n = Number(arguments[1]);
      if (n !== n)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    var k = n >= 0
          ? Math.min(n, len - 1)
          : len - Math.abs(n);

    while (k >= 0)
    {
      if (k in t && t[k] === searchElement)
        return k;
    }
    return -1;
  };
}


//Tests whether all elements in the array pass the test implemented by the provided function.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t && !fun.call(thisp, t[i], i, t))
        return false;
    }

    return true;
  };
}


//Creates a new array with all elements that pass the test implemented by the provided function.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
      {
        var val = t[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, t))
          res.push(val);
      }
    }

    return res;
  };
}


//Executes a provided function once per array element.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        fun.call(thisp, t[i], i, t);
    }
  };
}



//Creates a new array with the results of calling a provided function on every element in this array.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map
if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        res[i] = fun.call(thisp, t[i], i, t);
    }

    return res;
  };
}



//Tests whether some element in the array passes the test implemented by the provided function.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t && fun.call(thisp, t[i], i, t))
        return true;
    }

    return false;
  };
}


//Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Reduce
if (!Array.prototype.reduce)
{
  Array.prototype.reduce = function(fun /*, initialValue */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    // no value to return if no initial value and an empty array
    if (len == 0 && arguments.length == 1)
      throw new TypeError();

    var k = 0;
    var accumulator;
    if (arguments.length >= 2)
    {
      accumulator = arguments[1];
    }
    else
    {
      do
      {
        if (k in t)
        {
          accumulator = t[k++];
          break;
        }

        // if array contains no values, no initial value to return
        if (++k >= len)
          throw new TypeError();
      }
      while (true);
    }

    while (k < len)
    {
      if (k in t)
        accumulator = fun.call(undefined, accumulator, t[k], k, t);
      k++;
    }

    return accumulator;
  };
}


//Apply a function simultaneously against two values of the array (from right-to-left) as to reduce it to a single value.
//Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/ReduceRight
if (!Array.prototype.reduceRight)
{
  Array.prototype.reduceRight = function(callbackfn /*, initialValue */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof callbackfn !== "function")
      throw new TypeError();

    // no value to return if no initial value, empty array
    if (len === 0 && arguments.length === 1)
      throw new TypeError();

    var k = len - 1;
    var accumulator;
    if (arguments.length >= 2)
    {
      accumulator = arguments[1];
    }
    else
    {
      do
      {
        if (k in this)
        {
          accumulator = this[k--];
          break;
        }

        // if array contains no values, no initial value to return
        if (--k < 0)
          throw new TypeError();
      }
      while (true);
    }

    while (k >= 0)
    {
      if (k in t)
        accumulator = callbackfn.call(undefined, accumulator, t[k], k, t);
      k--;
    }

    return accumulator;
  };
}	


	var utilities = {

		//A method to create and open a pop-up window;
		//for the size parameter, accepts either pre-defined string values ("small," "medium," "large," and "super") or an object with numeric properties "width" and "height".
		popWin: function (url, size) {
	
			var winWidth = 0;
			var winHeight = 0;
			var winSettings = null;
		
			if (size) {
		
				if (typeof(size) == 'string') {
		
					switch (size) {
		
						case 'small':
							winWidth = 200;
							winHeight = 300;
							break;
				
						case 'medium':
							winWidth = 300;
							winHeight = 350;
							break;
				
						case 'large':
							winWidth = 550;
							winHeight = 400;
							break;
				
						case 'super':
							winWidth = 640;
							winHeight = 480;
							break;
				
						default:
							winWidth = 300;
							winHeight = 350;
							break;
					
					}
		
				} else if (typeof(size) == 'object') {
		
					winWidth = (size.width && typeof(size.width) == 'number') ? size.width : 0;
				
					winHeight = (size.height && typeof(size.height) == 'number') ? size.height : 0;
				
				}
			
			}

			if (!winWidth || !winHeight) {
			
				winWidth = 300;
				winHeight = 350;

			}
		
			winSettings = 'width=' + winWidth.toString() + ',height=' + winHeight.toString() + ',scrollbars,resizable,top=35,left=35,screenX=35,screenY=35';

			var newWin = window.open(url, '', winSettings);

		},

		//Tests to see if a form element value is a valid date string in mm/dd/yyyy format.
		//Used with text, password, hidden, and textarea elements.
		//Expects a form element for the parameter.
		isDate: function (elem) {

			var re = /^[0-1]?\d{1}\/[0-3]?\d{1}\/\d{4}$/;

			if ( !re.test(elem.value) ) return false;

			var strMonth, strDate, strYear

			//[strMonth, strDate, strYear] = elem.value.split('/');
			
			arrDate = elem.value.split('/');
			
			strMonth = arrDate[0];
			strDate	 = arrDate[1];
			strYear	 = arrDate[2];

			if (parseInt(strMonth, 10) < 0 || parseInt(strMonth, 10) > 12) {
				return false;
			}

			if (parseInt(strMonth, 10) == 2) {
				if (isLeapYear(parseInt(strYear, 10))) {
					if (parseInt(strDate, 10) < 0 || parseInt(strDate, 10) > 29) {
						return false;
					}
				} else {
					if (parseInt(strDate, 10) < 0 || parseInt(strDate, 10) > 28) {
						return false;
					}
				}
			} else if (parseInt(strMonth, 10) == 4 || parseInt(strMonth, 10) == 6 || parseInt(strMonth, 10) == 9 || parseInt(strMonth, 10) == 11) {
				if (parseInt(strDate, 10) < 0 || parseInt(strDate, 10) > 30) {
					return false;
				}
			} else {
				if (parseInt(strDate, 10) < 0 || parseInt(strDate, 10) > 31) {
					return false;
				}
			}

			try {
				var objDate = new Date(elem.value);
				return true;
			} catch(err) {
				return false;

			}

		},

		//A method to create and return an XMLHttpRequest Object.
		createXMLHttpRequest: function() {

			var objXMLHttpRequest = false;

			if (window.XMLHttpRequest) {

				try {

					objXMLHttpRequest = new XMLHttpRequest();

				} catch(e) {

					objXMLHttpRequest = false;

				}

			} else if (window.ActiveXObject) {

				var arrVersions = [

					'MSXML2.XMLHttp.6.0',
					'MSXML2.XMLHttp.3.0'

				];

				try {

					for (var i = 0; i < arrVersions.length; i++) {

						try {

							objXMLHttpRequest = new ActiveXObject(arrVersions[i]);
							return objXMLHttpRequest;

						} catch(e) {

							var objXMLHttpRequest = false;

						}

					}

				} catch(e) {

					objXMLHttpRequest = false;

				}

			}

			return objXMLHttpRequest;

		},

		sizeOverlay: function() {
		
			//Sets the width and height of the overlay div used for the Lightbox functions.
		
			if (!document.getElementById) return;
			
			var elem = document.getElementById('overlay');
			
			if (window.innerWidth) {  //Every major browser but IE
				
				if ( document.body.scrollWidth < window.innerWidth ) {
				
					elem.style.width = window.innerWidth + 'px';
					
				} else {
				
					elem.style.width = document.body.scrollWidth + 'px';
					
				}
					
			} else {  //IE
			
				if ( document.compatMode && document.compatMode.indexOf('CSS1') >= 0 ) {  //IE in 'CSS1Compat' mode (i.e., standards compliant mode)
				
					if (document.documentElement.clientWidth > document.body.clientWidth) {
					
						elem.style.width = document.documentElement.clientWidth + 'px';

						} else {
					
						elem.style.width = document.body.clientWidth + 'px';
						
					}

				
				} else {  //IE in 'backCompat' mode(i.e., quirksmode)
				
					elem.style.width = document.body.clientWidth + 'px';
				
				}
			
			}
						
			if (window.innerHeight) {  //Every major browser but IE
				
				if ( document.body.scrollHeight < window.innerHeight ) {
				
					elem.style.height = window.innerHeight + 'px';
					
				} else {
				
					elem.style.height = document.body.scrollHeight + 'px';
					
				}
					
			} else {  //IE
			
				if ( document.compatMode && document.compatMode.indexOf('CSS1') >= 0 ) {  //IE in 'CSS1Compat' mode (i.e., standards compliant mode)
				
					if (document.documentElement.clientHeight > document.body.clientHeight) {
					
						elem.style.height = document.documentElement.clientHeight + 'px';

						} else {
					
						elem.style.height = document.body.clientHeight + 'px';
						
					}

				} else {  //IE in 'backCompat' mode(i.e., quirksmode)
				
					elem.style.height = document.body.clientHeight + 'px';
				
				}
			
			}
						
		},
		
		showOverlay: function() {
		
			//(1) Adds overlay event listener;
			//(2) Calls method to size overlay;
			//(3) Shows overlay.

			if (!document.getElementById) return;
			
			if (document.getElementById('overlay') && pageState) {

				if (document.addEventListener) {  //W3C DOM

					document.addEventListener('keyup', function(evt) { if (utilities.escapePressed(evt)) { utilities.hideOverlay(); } }, false);

				/*
				} else if (document.attachEvent) {  //IE

					document.body.attachEvent('onkeyup', function() { if (utilities.escapePressed()) { utilities.hideOverlay(); } } );

				*/
				} else {  //All other browsers
				
					document.body.onkeyup = function() { if (utilities.escapePressed()) { utilities.hideOverlay(); } };

				}

				this.sizeOverlay();
				
				document.getElementById('overlay').className = 'overlayOn';

			} else {
			
				return;
				
			}
			
		},
	
		hideOverlay: function() {
		
			//(1) Removes overlay event listener;
			//(2) Hides overlay.

			if (!document.getElementById) return;
			
			if (document.getElementById('overlay') && pageState) {

				if (document.removeEventListener) {  //W3C DOM

					document.removeEventListener('keyup',  function(evt) { if (utilities.escapePressed(evt)) { utilities.hideOverlay(); } }, false);

				/*
				} else if (document.detachEvent) {  //IE

					document.body.detachEvent('onkeyup',  function() { if (utilities.escapePressed()) { utilities.hideOverlay(); } });

				*/
				} else {  //All other browsers

					document.body.onkeyup = null;

				}

				document.getElementById('overlay').className = 'overlayOff';
				
			} else {

				return;

			}
			
		},
		
		getLightboxDimensions: function(dimension) {
		
			//Returns an object with properties holding width and height values of the object to be positioned;
			//optional parameters :
			//  (1) id -- the id of the element being displayed in the lightbox;
			//  (2) dimension -- an integer value between 1 and 100 representing the _percentage_ of the viewport to be covered by the content displayed in the lightbox; used for both width and height.
			
			dimension = dimension || 65;  //Default to 65% if no dimension provided.
		
			var myWidth, myHeight;
			myWidth = myHeight = 0;
			
			if (window.innerWidth) {  //Every major browser but IE
			
				if ( dimension && this.isNumeric(dimension) && dimension >= 1 && dimension <= 100 ) {
				
					myWidth = Math.round( window.innerWidth * (dimension / 100) );
					myHeight = Math.round( window.innerHeight * (dimension / 100) );
									
				}
				
			} else {  //IE
			
				if (document.compatMode && document.compatMode.indexOf('CSS1') >= 0) {  //IE in 'CSS1Compat' mode (i.e., standards compliant mode)
				
					myWidth = Math.round( document.documentElement.clientWidth * (dimension / 100) );
					myHeight = Math.round( document.documentElement.clientHeight * (dimension / 100) );
			
				} else {  //IE in 'backCompat' mode(i.e., quirksmode)
			
					myWidth = Math.round( document.body.clientWidth * (dimension / 100) );
					myHeight = Math.round( document.body.clientHeight * (dimension / 100) );
			
				}
			
			}

			return { width: myWidth, height: myHeight };
		
		},
		
		getLightBoxCoords: function(id) {
		
			//Returns an object with properties holding left and top values for the object to be positioned.
		
			if (!document.getElementById) return;

			var elem = document.getElementById(id);
			
			var myLeft, myTop;
			myLeft = myTop = 0;
			
			if (window.innerWidth) {  //Every major browser but IE
			
				myLeft = ( Math.round( (window.innerWidth / 2 ) - ( parseInt(elem.style.width, 10) / 2) ) + window.scrollX );
				myTop = ( Math.round( (window.innerHeight / 2 ) - ( parseInt(elem.style.height, 10) / 2) ) +  window.scrollY );
				
				//myLeft = ( Math.round( (window.innerWidth / 2 ) - ( parseInt(elem.style.width, 10) / 2) ) + window.pageXOffset );
				//myTop = ( Math.round( (window.innerHeight / 2 ) - ( parseInt(elem.style.height, 10) / 2) ) +  window.pageYOffset );
				
			} else {  //IE
			
				if (document.compatMode && document.compatMode.indexOf('CSS1') >= 0) {  //IE in 'CSS1Compat' mode (i.e., standards compliant mode)
				
					myLeft = ( Math.round( (document.documentElement.clientWidth / 2 ) - ( parseInt(elem.style.width, 10) / 2) ) + document.documentElement.scrollLeft );
					myTop = ( Math.round( (document.documentElement.clientHeight / 2 ) - ( parseInt(elem.style.height, 10) / 2) ) + document.documentElement.scrollTop );
					
				} else {  //IE in 'backCompat' mode(i.e., quirksmode)
			
					myLeft = ( Math.round( (document.body.clientWidth / 2 ) - ( parseInt(elem.style.width, 10) / 2) ) + document.body.scrollLeft );
					myTop = ( Math.round( (document.body.clientHeight / 2 ) - ( parseInt(elem.style.height, 10) / 2) ) + document.body.scrollTop );
					
				}
				
			
			}
			return { left: myLeft, top: myTop };
		
		},
		
		centerOnClient: function(id, dimension) {
		
			//Calls Lightbox methods to size and center the lightbox content in the client viewport.
		
			if (!document.getElementById) return;
			
			var elem = document.getElementById(id);
			
			var dimension = this.getLightboxDimensions(dimension);
			elem.style.width = (dimension.width + 'px');
			elem.style.height = (dimension.height + 'px');
				
			var coord = this.getLightBoxCoords(id);
			elem.style.left = (coord.left + 'px');
			elem.style.top = (coord.top + 'px');
				
		},

		showLightboxElem: function(id, dimension) {
		
			//(1) Calls method to show overlay;
			//(2) Calls method to size and center the lightbox content in the client viewport;
			//(3) Shows lightbox content;
			//(4) Creates event listeners to control lightbox behavior;
			//(5) Sets pageState.lightbox property to true.
			
			if (!document.getElementById) return;
			
			var elem = document.getElementById(id);
		
			this.showOverlay();  //The overlay adds its own event listener to hide when the escape key is pressed.
			
			this.centerOnClient(id, dimension);
			
			elem.style.display = 'block';
			
			if (window.addEventListener) {  //W3C DOM
			
				window.addEventListener('keyup', function(evt) { if (utilities.escapePressed(evt)) { utilities.hideLightboxElem(id) }; }, false);
				window.addEventListener('resize', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); }, false);
				window.addEventListener('scroll', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); }, false);
				
			/*
			} else if (window.attachEvent) {  //IE
			
				document.attachEvent('onkeyup', function() { if (utilities.escapePressed()) { utilities.hideLightboxElem(id) }; });
				window.attachEvent('onresize', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); });
				window.attachEvent('onscroll', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); });
			
			*/
			} else {  //All other browsers
			
				document.onkeyup = function(evt) { if (utilities.escapePressed(evt)) { utilities.hideLightboxElem(id) }; };
				window.onresize = function() { utilities.centerOnClient(id); utilities.sizeOverlay(); };
				window.onscroll = function() { utilities.centerOnClient(id); utilities.sizeOverlay(); };
			
			}
		
			pageState.lightbox = true;
				
		},
		
		hideLightboxElem: function(id) {		
		
			//(1) Hides lightbox content;
			//(2) Removes event listeners that control lightbox behavior;
			//(3) Sets pageState.lightbox property to false.
			
			if (!document.getElementById) return;
			
			var elem = document.getElementById(id);
		
			elem.style.display = 'none';
			
			if (document.getElementById('overlay') && pageState && pageState.lightbox) {
			
				utilities.hideOverlay();
			
			}
			
			if (window.removeEventListener) {  //W3C DOM
			
				window.removeEventListener('keyup', function(evt) { if (utilities.escapePressed(evt)) { utilities.hideLightbox(id) }; }, false);
				window.removeEventListener('resize', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); }, false);
				window.removeEventListener('scroll', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); }, false);
				
			/*
			} else if (window.detachEvent) {  //IE
			
				document.detachEvent('onkeyup', function() { if (utilities.escapePressed()) { utilities.hideLightboxElem(id) }; });
				window.detachEvent('onresize', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); });
				window.detachEvent('onscroll', function() { utilities.centerOnClient(id); utilities.sizeOverlay(); });
			
			*/
			} else { //All other browsers
			
				document.onkeyup = null;
				window.onresize = null;
				window.onscroll = null;
			
			}
		
			pageState.lightbox = false;

		},
				
		isNumeric: function(a) {
		
			//Returns JavaScript true if the parameter value is numeric.
		
			return (a == parseInt(a, 10));
		
		},
		
          getPageEventCoordinates: function(evt) {
		
			//Returns an object with properties 'left' and 'top' holding the event coordinates;
			//Based almost verbatim on recipe 9.4 of Goodman, Danny, "JavaScript & DHTML Cookbook, 2nd Ed.," 0'Reilly, pp. 244 - 247.
		
			evt = (evt) ? evt : ((window.event) ? window.event : null);
			
			var coords = { left: 0, top: 0 };
			
			if (evt.pageX) {  //Every major browser but IE
			
				coords.left = evt.pageX;
				coords.top  = evt.pageY;
				
			} else if (evt.clientX) {  //IE
			
				coords.left = evt.clientX + document.body.scrollLeft - document.body.clientLeft;
				coords.top  = evt.clientY + document.body.scrollTop - document.body.clientTop;
				
				if (document.body.parentElement && document.body.parentElement.clientLeft) {  //Added for IE in standards-compliant mode; body has a parent element -- the HTML element
				
					var bodyParent = document.body.parentElement;
					coords.left += bodyParent.scrollLeft - bodyParent.clientLeft;
					coords.top  += bodyParent.scrollTop  - bodyParent.clientTop;
					
				}
			
			}
			
			return coords;
		
		},
		
		escapePressed: function(evt) {
		
			//Returns JavaScript true if user pressed the Esc key.
		
			evt = (evt) ? evt : ((window.event) ? window.event : null);
			
			if (evt) {
			
				return (evt.keyCode == (27 || evt.DOM_VK_ESCAPE));
				
			} else {
			
				return false;
				
			}
		
		},
		
		alertEventProperties: function (evt) {
	
			var strProp = '';

			if (evt && typeof(evt) == 'object') {

				for (var prop in evt) {

					strProp += ('evt[' + prop + '] = ' + evt[prop] + '\n');

				}

				alert(strProp);

			}
		
			return;

		},
		
	//A method that returns a properly-formatted and encoded URL, with optional query string.
	formatURL: function(URL, objArgs) {
	
		if (!URL || typeof(URL) != 'string') return;

		var formattedURL = URL;
		
		//If arguments, process query string.
		if (objArgs && typeof(objArgs) == 'object') {

			var strArgs,
			    queryString;
			
			strArgs = utilities.formatParameters(objArgs);
			
			queryString = ((strArgs) ? ('?' + strArgs) : '');
			
			formattedURL += queryString;

		}
		
		return formattedURL;

	},
	
	//A method that returns a properly encoded parameter string
	//for use with GET and POST requests.
	formatParameters: function(objArgs) {

		//If arguments, process.
		if (objArgs && typeof(objArgs) == 'object') {

			var arrArgs = new Array();

			for (name in objArgs) {

				arrArgs.push( encodeURIComponent(name) + '=' + encodeURIComponent(objArgs[name]) );

			}

			return arrArgs.join('&');

		} else {

			return '';
			
		}

	},
	
	//Return the current date in milliseconds;
	//often used as the value for a dummy parameter in AJAX requests
	//to force IE to poll the server rather than use a cached version of the request.
	getMilliseconds : function() {
		
		var now = new Date();
			
		return now.getTime();
		
	},
	
	//A function to test whether a DOM element is opaque (i.e., at maximum opacity).
	//For elem, accepts a reference to either an element or an element ID.
	isOpaque : function(elem) {
	
		//Get the element.
			
		if (typeof elem === 'string') { 
			
			if (!document.getElementById) { return; }
			
			elem = document.getElementById(elem);
				
		}
			
		if (!elem) { return; }	//Nothing to work with here!
			

		//Test opacity.
		
		var useOpacity = (typeof document.createElement('div').style.opacity !== 'undefined');
	
		var useFilter = (typeof document.createElement('div').style.filter !== 'undefined');
		
		if (useOpacity) {
		
			return (parseFloat(elem.style.opacity) === 1.0) ? true : false;
		
		}
	
		if (useFilter) {
		
			var filter = elem.style.filter;
		
			return (parseInt(filter.substr(filter.indexOf('=') + 1), 10) === 100) ? true : false;
		
		}
		
		return false;
	
	},
	
	//A function to test whether a DOM element is transparent (i.e., at minimum opacity).
	//For elem, accepts a reference to either an element or an element ID.
	isTransparent : function(elem) {
	
		//Get the element.
			
		if (typeof elem === 'string') { 
			
			if (!document.getElementById) { return; }
			
			elem = document.getElementById(elem);
				
		}
			
		if (!elem) { return; }	//Nothing to work with here!
			

		//Test opacity.
		
		var useOpacity = (typeof document.createElement('div').style.opacity !== 'undefined');
	
		var useFilter = (typeof document.createElement('div').style.filter !== 'undefined');
		
		if (useOpacity) {
		
			return (parseFloat(elem.style.opacity) === 0) ? true : false;
		
		}
	
		if (useFilter) {
		
			var filter = elem.style.filter;
		
			return (parseInt(filter.substr(filter.indexOf('=') + 1), 10) === 0) ? true : false;
		
		}
		
		return false;
	
	},
	
	//A function to set a DOM element's opacity.
	//For elem, accepts a reference to either an element or an element ID.
	//For opacity, accepts a value of type number or string.
	setOpacity : function(elem, opacity) {
	
		if (typeof elem === 'string') elem = document.getElementById(elem);	//Ensure we're working with a DOM element
		
		if (!elem) { 
		
			alert('The element does not exist.');
			return;
			
		}
		
		opacity = (opacity) ? opacity : 1;					//Ensure we've got a value.
		
		if (typeof opacity !== 'number') {					//If possible, ensure we've got a number...
			
			if (isNaN(parseFloat(opacity))) {
			
				alert ('Opacity must be a number.');
				return;
					
			} else {
				
				opacity = parseFloat(opacity);
				
			}
		
		}

		if (opacity < 0 || opacity > 1) {					//...with a value between 1 and 1.
			
				alert ('Opacity must be a number between 0 and 1.');
				return;
				
		}
		
		//The following object detection tests were found at the IE9 Blog, "IE9, Opacity, and Alpha," [http://blogs.msdn.com/b/ie/archive/2010/08/17/ie9-opacity-and-alpha.aspx]. Last accessed: 11/13/2010.
			
		var useOpacity = (typeof document.createElement("div").style.opacity !== 'undefined');
		
		var useFilter = (typeof document.createElement("div").style.filter !== 'undefined');
		
		if (useOpacity) {
		
			elem.style.opacity = opacity;
		
		} else if (useFilter) {
		
			elem.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
		
		}
		
		return;

	},
	
	//A function to fade out an element.
	//For elem, accepts a reference to either a DOM element or a string ID.
	fadeOut : function(elem, objArgs, callback) {

		//Get the element.
			
		if (typeof elem === 'string') { 
			
			if (!document.getElementById) { return; }
			
			elem = document.getElementById(elem);
				
		}
			
		if (!elem) { return; }	//Nothing to work with here!
			
			
		//Get & set arguments
			
		var decrement,
		    timeout;

		if (typeof objArgs === 'object') {
			
			decrement = (objArgs.fadeDecrement) ? objArgs.fadeDecrement : 0.05;
				
			timeout = (objArgs.fadeTimeout) ? objArgs.fadeTimeout : 50;
				
		} else {
		
			decrement = 0.05;
				
			timeout = 50;
		
		}


		//Check support for either the W3C CSS opacity feature or the IE alpha filter feature.
			
		var useOpacity = (typeof document.createElement('div').style.opacity !== 'undefined');
				
		var useFilter = (typeof document.createElement('div').style.filter !== 'undefined');
		
		if (!useOpacity && !useFilter) { alert('Object opacity cannot be evaluated.'); return; }	//Nothing to do here!
			
			
		//Get the element's current opacity.
			
		var opacity;
				
		if (useOpacity) { opacity = parseFloat(elem.style.opacity); }
				
		if (useFilter && !useOpacity) { var filter = elem.style.filter; }
				
		if (useFilter && !useOpacity) { opacity = parseInt(filter.substr(filter.indexOf('=') + 1), 10); }
		
			
		//Set the element's new opacity.

		if (opacity > 0) {
			
			//Decrement the element's opacity.
		
			opacity = (useOpacity) ? (((opacity - decrement) >= 0) ? (opacity -= decrement) : 0) : (useFilter ? (((opacity - (decrement * 100)) >= 0) ? (opacity -= (decrement * 100)) : 0) : 0);
						
			if (useFilter && !useOpacity) { elem.style.filter = ('alpha(opacity=' + opacity + ')'); }
				
				
			if (useOpacity) { elem.style.opacity = opacity; }
						
			//Set the function to check opacity again.
				
			setTimeout(function() { utilities.fadeOut(elem, objArgs, callback); }, timeout);
				
		} else {

			//You're done!  Trigger the callback function, if any.
		
			if (callback && typeof(callback) === 'function') {

				callback(elem);

			}

		}
			
		return;
				
	},
	
	//A function to fade in an element.
	//For elem, accepts a reference to either a DOM element or a string ID.
	fadeIn : function(elem, objArgs, callback) {
		
		//Get the element.
			
		if (typeof elem === 'string') { 
			
			if (!document.getElementById) { return; }
			
			elem = document.getElementById(elem);
				
		}
			
		if (!elem) { return; }	//Nothing to work with here!
		

		//Get & set arguments
			
		var increment,
		    timeout;

		if (typeof objArgs === 'object') {
			
			increment = (objArgs.fadeIncrement) ? objArgs.fadeIncrement : 0.05;
				
			timeout = (objArgs.fadeTimeout) ? objArgs.fadeTimeout : 50;
				
		} else {
		
			increment = 0.05;
				
			timeout = 50;
		
		}

		//Check support for either the W3C CSS opacity feature or the IE alpha filter feature.
			
		var useOpacity = (typeof document.createElement('div').style.opacity !== 'undefined');
				
		var useFilter = (typeof document.createElement('div').style.filter !== 'undefined');
			
		if (!useOpacity && !useFilter) { alert('Object opacity cannot be evaluated.'); return; }	//Nothing to do here!
			

		//Get the element's current opacity.
			
		var opacity;
				
		if (useOpacity) { opacity = parseFloat(elem.style.opacity); }
				
		if (useFilter && !useOpacity) { var filter = elem.style.filter; }
				
		if (useFilter && !useOpacity) { opacity = parseInt(filter.substr(filter.indexOf('=') + 1), 10); }
			

		//Set the element's new opacity.
			
		if ( (useOpacity && opacity >= 1) || (useFilter && opacity >= 100) ) {
		
			//You're done!  Trigger the callback function, if any.
		
			if (callback && typeof(callback) === 'function') {

				callback(elem);

			}

		} else {
		
			//Increment the element's opacity.
		
			opacity = (useOpacity) ? (((opacity + increment) < 1) ? (opacity += increment) : 1) : (useFilter ? (((opacity + (increment * 100)) < 100) ? (opacity += (increment * 100)) : 100) : 100);
						
			if (useOpacity) { elem.style.opacity = opacity; }
						
			if (useFilter && !useOpacity) { elem.style.filter = ('alpha(opacity=' + opacity + ')'); }


			//Set the function to check opacity again.
				
			setTimeout(function() { utilities.fadeIn(elem, objArgs, callback); }, timeout);
						
		}
		
		return;
				
	}
	
}

