/* Release 5.1 - update CenterTile fix */

/** 
 * Highest level, global, generic functions which can be used anywhere.
 * This means that functionality here should be applicable to any application,
 * even by an outside company or website. 
 * 
 * @module ua
 * 
 */

window.ua = {}; // Namespace for all UA-specific functionality
window.ua.runtime = {}; // Use to store information generated upon startup & execution
window.ua.startTime = (new Date).getTime(); // Tracking execution time of this script 

ua.config = {
	siteURL: 'http://www.united.com/',
	assetPath: '//www.united.com/ual/asset/',
	copyrightYear: '2011',
	voTiles: {
		unitedFooter: {
			leftQty: 1,
			rightQty: 2
		},
		mpFooter: {
			topQty: 1,
			bottomQty: 1
		}
	}
};

/*
 * 
 * Prototype Extensions
 * 
 * 
 */

/**
 * Remove all whitespace from a string.
 * http://jsperf.com/remove-whitespace/2
 * 
 * @property removeSpaces
 * @type String 
 */
String.prototype.removeSpaces = function() {
	return this.replace(/\s/g, "");
};

/**
 * Prototype extension. Remove whitespace from the front and back of a string. 
 * Will only extend the prototype if native trim() doesn't exist.
 * http://jsperf.com/trim-multiple-regex
 * 
 * @property trim
 * @type String
 */
if (!String.prototype.trim) {
	String.prototype.trim = function() {
		return this === null ? "" : this.toString().replace(/^\s+/, "").replace(/\s+$/, "");
	};
}

/**
 * Prototype extension. Insert commas into a string 
 * Reference: http://blog.stevenlevithan.com/archives/commafy-numbers
 * 
 * @property commafy
 * @type String
 */
String.prototype.commafy = function () {
	return this.replace(/(^|[^\w.])(\d{4,})/g, function($0, $1, $2) {
		return $1 + $2.replace(/\d(?=(?:\d\d\d)+(?!\d))/g, "$&,");
	});
};

/**
 * Prototype extension. Insert commas into a number 
 * Reference: http://blog.stevenlevithan.com/archives/commafy-numbers
 * 
 * @property commafy
 * @type Number
 */
Number.prototype.commafy = function() { 
	return String(this).commafy(); 
};


/** 
 * Prototype extension. Ordinals: Format numbers to include "st" "nd" "rd" & "th"
 * http://davidchambersdesign.com/converting-integers-to-ordinals/
 * 
 * @property ordinal
 * @type Number
 */
Number.prototype.ordinal = function() {
	var n = Math.abs(this);
	if (10 < n && n < 14) {
		return this + 'th';
	}
	switch (n % 10) {
		case 1: return this + 'st';
		case 2: return this + 'nd';
		case 3: return this + 'rd';
		default: return this + 'th';
	}
};

/** 
 * Prototype extension.
 * 
 * @property indexOf
 * @type Number
 */
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(elt /*, from*/){
        var len = this.length;
        var from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
        if (from < 0) {
			from += len;
		}
        for (; from < len; from++) {
            if (this.hasOwnProperty(from) && this[from] === elt) {
				return from;
			}
        }
        return -1;
    };
}

Array.prototype.contains = function(value) {
	return this.indexOf(value) > -1;
};

Array.max = function( array ){
    return Math.max.apply( Math, array );
};

Array.min = function( array ){
    return Math.min.apply( Math, array );
};

/*
 * Date.prototype.dateAdd
 *
 * Allows addition or subtraction of a date object.
 *
 * Usage: 
 *     var myDate = new Date();
 *     myDate.dateAdd('d',1);
 *     myDate.dateAdd('d',-5);
 *     
 * Available intervals: 
 *     yyyy - year			y - day of year			q - quarter
 *     m - month			w - weekday				ww - week of year
 *     d - day				h - hour				n - minute
 *     s - second			ms - millesecond
 */
Date.prototype.dateAdd = function(b,a){new String;b=b.toLowerCase();if(isNaN(a))throw"The second parameter must be a number. \n You passed: "+a;a=new Number(a);switch(b.toLowerCase()){case "yyyy":this.setFullYear(this.getFullYear()+a);break;case "q":this.setMonth(this.getMonth()+a*3);break;case "m":this.setMonth(this.getMonth()+a);break;case "y":case "d":case "w":this.setDate(this.getDate()+a);break;case "ww":this.setDate(this.getDate()+a*7);break;case "h":this.setHours(this.getHours()+a);break;case "n":this.setMinutes(this.getMinutes()+ a);break;case "s":this.setSeconds(this.getSeconds()+a);break;case "ms":this.setMilliseconds(this.getMilliseconds()+a);break;default:throw"The first parameter must be a string from this list: \nyyyy, q, m, y, d, w, ww, h, n, s, or ms. You passed: "+b;}return this};

/*
 * Date Format 1.2.3
 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
 * MIT license
 * Documentation: http://blog.stevenlevithan.com/archives/date-time-format
 * 
 * Includes enhancements by Scott Trenda <scott.trenda.net>
 * and Kris Kowal <cixar.com/~kris.kowal/>
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 */
_dateFormat = function(){var q=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,r=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,s=/[^-+\dA-Z]/g,d=function(a,c){a=String(a);for(c=c||2;a.length<c;)a="0"+a;return a};return function(a,c,h){var f=_dateFormat;if(arguments.length==1&&Object.prototype.toString.call(a)=="[object String]"&&!/\d/.test(a)){c=a;a=undefined}a=a?new Date(a):new Date;if(isNaN(a))throw SyntaxError("invalid date"); c=String(f.masks[c]||c||f.masks["default"]);if(c.slice(0,4)=="UTC:"){c=c.slice(4);h=true}var b=h?"getUTC":"get",g=a[b+"Date"](),l=a[b+"Day"](),i=a[b+"Month"](),m=a[b+"FullYear"](),e=a[b+"Hours"](),n=a[b+"Minutes"](),o=a[b+"Seconds"]();b=a[b+"Milliseconds"]();var k=h?0:a.getTimezoneOffset(),p={d:g,dd:d(g),ddd:f.i18n.dayNames[l],dddd:f.i18n.dayNames[l+7],m:i+1,mm:d(i+1),mmm:f.i18n.monthNames[i],mmmm:f.i18n.monthNames[i+12],yy:String(m).slice(2),yyyy:m,h:e%12||12,hh:d(e%12||12),H:e,HH:d(e),M:n,MM:d(n), s:o,ss:d(o),l:d(b,3),L:d(b>99?Math.round(b/10):b),t:e<12?"a":"p",tt:e<12?"am":"pm",T:e<12?"A":"P",TT:e<12?"AM":"PM",Z:h?"UTC":(String(a).match(r)||[""]).pop().replace(s,""),o:(k>0?"-":"+")+d(Math.floor(Math.abs(k)/60)*100+Math.abs(k)%60,4),S:["th","st","nd","rd"][g%10>3?0:(g%100-g%10!=10)*g%10]};return c.replace(q,function(j){return j in p?p[j]:j.slice(1,j.length-1)})}}();
_dateFormat.masks={"default":"ddd mmm dd yyyy HH:MM:ss",shortDate:"m/d/yy",mediumDate:"mmm d, yyyy",longDate:"mmmm d, yyyy",fullDate:"dddd, mmmm d, yyyy",shortTime:"h:MM TT",mediumTime:"h:MM:ss TT",longTime:"h:MM:ss TT Z",isoDate:"yyyy-mm-dd",isoTime:"HH:MM:ss",isoDateTime:"yyyy-mm-dd'T'HH:MM:ss",isoUtcDateTime:"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"};
_dateFormat.i18n={dayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","January","February","March","April","May","June","July","August","September","October","November","December"]};
Date.prototype.dateFormat = function(mask, utc){return _dateFormat(this, mask, utc);};

/* 
 * Ever wanted to create a function that has optional params with default values? Here you go. 
 * http://parentnode.org/javascript/default-arguments-in-javascript-functions/
 * 
 * Example:
 * var foo = function(a, b) {
 *		...functionality here...
 * }.defaults(42, 'default_b');
 *
 */
/*
Function.prototype.defaults = function() {
	var _f = this;
	var _a = Array(_f.length - arguments.length).concat(Array.prototype.slice.apply(arguments));
	return function(){
		return _f.apply(_f, Array.prototype.slice.apply(arguments).concat(_a.slice(arguments.length, _a.length)));
	};
};
*/

ua.utils = new function() {
	/*
	 * @PUBLIC - Load individual JS or CSS files into the current document upon request. 
	 */
	this.loadModule = function(fileName,basePath,callback){
		var fileType = '',
			tagName = '',
			mimeType = '',
			head = '',
			source = '',
			element = '';
			
		if (!ua.utils.isArray(ua.runtime.loadedModules)) { 
			ua.runtime.loadedModules = []; 
		}

		if (typeof basePath !== 'string') {
			basePath = ua.config.assetPath;
		}
		
		if (ua.runtime.loadedModules.contains(basePath + fileName)) { 
			return; /* Let's not load a file twice */
		}
		
		fileType = fileName.substr(fileName.lastIndexOf('.') + 1);
		switch(fileType){
			case 'js':
				tagName = 'script';
				mimeType = 'text/javascript';
				source = 'src';
				break;
			case 'css':
				tagName = 'link';
				mimeType = 'text/css';
				source = 'href';
				break;
		}
		/* http://paulirish.com/2011/surefire-dom-element-insertion/ */
		var ref = document.getElementsByTagName('script')[0];
		element = document.createElement(tagName);
		element.type = mimeType;
		element.async = true;
		element[source] = basePath + fileName;
		ref.parentNode.insertBefore(element, ref);
		ua.runtime.loadedModules.push(element[source]);
		
		if (typeof callback === 'function') callback();
	};

	/*
	 * @PUBLIC 
	 * Load individual files into the current document after $.ready() has occurred.
	 * Can be used with any file type jQuery's $.ajax() method allows 
	 */
	ua.runtime.scriptQueue = [];
	this.deferLoad = function(url,type,callback,xmlcache) {
		ua.runtime.scriptQueue.push([url,type,callback]);
	};
	
	this.loadDeferredFiles = function() {
		var scriptQueue = ua.runtime.scriptQueue,
			isAsync = true;
		
		/* Set a recursive call to process the queue of files */
		if (scriptQueue.length > 0) {
			setTimeout(ua.utils.loadDeferredFiles,10);
		} else {
			/* If there are no files to load, we slow down the recursion, but
			 * always keep it going just in case more files are added later.
			 */
			setTimeout(ua.utils.loadDeferredFiles,250);
			return;
		}
		
		/* Init the next file */
		var nextScript = scriptQueue.shift(),
			file = {},
			callback = '';
		
		file.src = nextScript[0];
		file.type = nextScript[1];
		callback = nextScript[2];
		file.xmlcache = nextScript[3];
		var fetchMethod = "GET";
		cacheCheck = false;
		/* If the request has a callback associated with it, we want to
		 * force the request to complete before invoking the callback 
		 */
		if (typeof callback === 'function') {
			isAsync = false;
		}
		if(file.xmlcache == 'xml'){
		
		var milliseconds = new Date().getTime();
			file.src = file.src+'?t='+milliseconds;
			fetchMethod = "POST";
			cacheCheck = true;
		}
		/* Load it */
		$.ajax({
			type: fetchMethod,
			url: file.src,
			dataType: file.type,
			cache: cacheCheck,
			async: isAsync,
			success: function(content){
				if (typeof callback === 'function') callback(content);
			}
		});
	};
	
	/* Kick off the deferred file loader (now done at the end of this file)
	$(document).ready(function(){
		ua.utils.loadDeferredFiles();
	});
	*/

	
	/* @PUBLIC */
	this.setCookie = function(name, value, expiredays, path, domain, secure) {
		var cookie_string = name + "=" + escape(value);
		if (path) {
			cookie_string += "; path=" + escape(path);
		}
		if (expiredays)  {
			var expires = new Date();
			expires.setDate(expires.getDate() + expiredays);
			cookie_string += "; expires=" + expires.toGMTString();
		}
		if (domain) {
			cookie_string += "; domain=" + escape(domain);
		}
		if (secure) {
			cookie_string += "; secure";
		}
		document.cookie = cookie_string;
	};
	
	/* @PUBLIC */
	this.getCookie = function(cookieName) {
		var cookie = document.cookie,
			c_start = 0,
			c_end = 0;

	    if (typeof cookie !== 'undefined') {  
	        c_start = cookie.indexOf(cookieName + '=');
	        if (c_start !== -1) {
	            c_start = c_start + cookieName.length + 1;
	            c_end = cookie.indexOf(';', c_start);
	            if (c_end === -1) { c_end = cookie.length; }
	            return unescape(cookie.substring(c_start, c_end));
	        }
	    }
        return '';
	};
		
	/* @PUBLIC */
	this.deleteCookie = function(name,path,domain) {
		setCookie(name,null,-1,path,domain);
	};
	
	/* @PUBLIC - Compare two multi-value, delimited lists and return true or false based on the matchType.
	 * The function tests whether any/all of the 2nd list exist in the 1st list.
	 * 
	 * Example: 
     *  var1 = '1,2,3,6';
     *  var2 = '3,4,5';
     *  if (listContains(var1,var2,'any')) { alert('Yup! The number 3 exists in var1'); }
     *  if (listContains(var1,var2,'all')) { alert('Nope! None of var2 exist in var1'); }
     */
	this.listContains = function(str1, str2, matchType, delimiter) {
		if (typeof delimiter === 'undefined') { delimiter = ','; }
		var arr1 = str1.split(delimiter),
			arr2 = str2.split(delimiter),
			arr1Len = arr1.length,
			arr2Len = arr2.length,
			matchArr = [],
			i = 0,
			j = 0;

		for (i = 0; i < arr2Len; i++) {
			for (j=0; j < arr1Len; j++) {
				/* Ignore JSlint error here. I want "==" rather than "===" for loose duck typing */
				if (arr1[j].trim() == arr2[i].trim()) {
					matchArr.push(arr1[j]);
				}
			}
		}

		switch (matchType) {
			case "all":
				if (matchArr.length === arr2.length) { return true; }
				break;
	
			case "any":
				if (matchArr.length > 0) { return true; }
				break;
	
			/* This really isn't necessary, as you can do "!listContains(any/all)", but for ease of use, we include it */
			case "none": 
				if (matchArr.length === 0) { return true; }
				break;
		}
		return false;
	};

	/* 
	 * @PUBLIC
	 * Reference: http://documentcloud.github.com/underscore/underscore.js 
	 * Returns: Boolean
	 */
	this.isArray = function(obj) {
		return !!(obj && obj.concat && obj.unshift && !obj.callee);
	};
	
	/* 
	 * @PUBLIC
	 * Reference: http://documentcloud.github.com/underscore/underscore.js 
	 * Returns: Boolean
	 */
	this.isDate = function(obj) {
		return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear && obj !== 'Invalid Date');
		};

	/* 
	 * @PUBLIC
	 * Reference: http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844
	 * Returns: Boolean
	 */
	this.isNumeric = function(n) {
		return !isNaN(parseFloat(n)) && isFinite(n);
	};
	
	/* 
	 * @PUBLIC
	 * Reference: http://mattsnider.com/javascript/type-detection/
	 * Returns: Boolean
	 */
	this.isBoolean = function(o) {
		return 'boolean' === typeof o;
	};
		
	/* 
	 * @PUBLIC
	 * Test for variations of hex code formats. 
	 *    Strict: #ffffff
	 *    Loose: fff, ffffff, #fff, #ffffff
	 * Returns: Boolean
	 */
	this.isHexCode = function(str, strict){
		var regExpEasy = /^(#)?([0-9a-fA-F]{3})([0-9a-fA-F]{3})?$/; /* This one takes 3 or 6 chars and an optional hash */
		var regExpStrict = /^(#)([0-9a-fA-F]{6})$/; /* This one must be 6 chars and include a hash */
		if (!ua.utils.isBoolean(strict)) {
			strict = true; /* Default to strict */
		}
		
		if (strict) {
			return regExpStrict.test(str);
		}
		else {
			return regExpEasy.test(str);
		}
	};
	
	/*
	 * @PUBLIC - Test email formatted string
	 * Returns: Boolean
	 */
	this.isEmail = function(str) {
		return /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]{0,4}[a-zA-Z]$/.test(str);
	};

	/*
	 * @PUBLIC - Determine whether or not an object has content
	 * Returns: Boolean
	 */
	this.isEmpty = function(o) {
		for(var p in o) {
			if (o[p] !== o.constructor.prototype[p])
				return false;
			}
		return true;
	}; // END isEmpty

	/*
	 * @PUBLIC - Test credit card formatted string
	 * Returns: Boolean
	 */
	this.isCC = function(cardNo) {
		/*
		Visa	4-4-4-4, prefix 4 (4111 1111 1111 1111)
		American Express	4-6-5, prefix 37-34  (3400 000000 00009)
		Carte Blanche	3000 0000 0000 04
		Discover	4-4-4-4, prefix 6011 (6011 0000 0000 0004)
		Diner's Club	3000 0000 0000 04
		enRoute	2014 0000 0000 009
		JCB	2131 0000 0000 0008
		MasterCard	51-55, 5500 0000 0000 0004
		Solo	6334 0000 0000 0004
		Switch	4903 0100 0000 0009
		UATP 101657900007043
		*/
		var nCheck = 0,	nDigit = 0,	bEven = false;
		var cardNo = cardNo.replace(/\D/g, ""); 
		var cardRe = /^\d{13,16}$/;
		if (!cardRe.test(cardNo)) { return false; } 
		return true;
	};

	
	/*
	 * @PUBLIC - Add a listener to a JS variable. When the variable has
	 * been defined (anything but "null" -- even an empty string), execute
	 * the "success" callback function. If variable is not defined after 
	 * the DOM is ready, the "failure" calback function will be executed.
	 * 
	 * Returns: Object, options + variable's value 
	 * 
	 * Example: 
	 *		ua.utils.whenDefined({
	 *			object: 'webAnalyticsPageTitle',
	 *			success: function(result){
	 *				alert('Defined: ' + result.variable + '\n\nValue: ' + result.value);
	 *			},
	 *			failure: function(result){
	 *				alert(result.variable + 'was not defined by the time the document was completely loaded.');
	 *			},
	 *			interval: 2500,
	 *			stopOnReady: false
	 *		});
	 * 
	 */
	this.whenDefined = function(options) {
		/* Options:
		 *     object: string (name of object)
		 *     success: function
		 *     failure: function
		 *     interval: int, ms
		 *     stopOnReady: boolean
		 */
		if (typeof options.interval !== 'number') {
			options.interval = 250;
		}
		if (typeof options.stopOnReady !== 'boolean') {
			options.stopOnReady = true;
		}
		
		try {
			/* See if we can evaluate the string to a legit object */ 
			var obj = eval(options.object);
		} catch(e) { 
			/* Guess that didn't work, but that's ok. We leave this empty and 
			 * test 'obj' separately on purpose to ensure it correctly handles
			 * nested vars within an object. 
			 */
		}
		
		/* Check the object. Has it been defined yet? */
		if (typeof obj === 'undefined') {
			/* 
			 * To prevent an infinite loop, we have the option of breaking 
			 * the loop when the onLoad event has executed.
			 * http://jsperf.com/order-of-if-statement
			 */
			if (options.stopOnReady && jQuery.isReady) { 
				if (typeof options.failure === 'function') {
					options.failure(options);
				}
				return null; 
			}

			
			/* Otherwise, let's set a recursive call to continue polling */
			setTimeout(function(){
				ua.utils.whenDefined(options);
			}, options.interval);
			
			return null;
		}
		
		/* 
		 * The object has been defined! Let's execute the callback if it exists
		 * and pass our object's value back to it for further use. 
		 */	
		if (typeof options.success === 'function') {
			options.object = obj; /* Converts "options.object" from a string to a real object for use in the callback */ 
			options.success(options);
		}
	};
	
	/*
	 * @PUBLIC - Apply context and parameters to a function. Adapted from
	 * http://bit.ly/aJljaB
	 */
	this.applyFunction = function(functionName, context, params) {
	    return function() { 
	    	functionName.apply(context, params); 
	    };
	};
	
	/*
	 * @PRIVATE - Parse URL query string for easy access to all parameters via "ua.url.parameterName"
	 */
	var parseURL = function() {
		ua.url = {};
		ua.url._location = document.location;
		ua.url._query = document.location.search.substr(1); //start after the first char (the "?")
		if (document.location.search.indexOf('?') == -1) return; // If no query string to parse, let's bail
		if (typeof ua.url._query == 'string') {
			var arrParams = ua.url._query.split("&");
			var len = arrParams.length
			for (var i=0; i<len; i++) {
				var param = arrParams[i].split("=");
				if (param[0]) {
					ua.url[param[0]] = unescape(param[1]);
				}
			}
		}
	}(); // END parseURL (self-executing at runtime)
	
	/*
	 * @PRIVATE - Parse existing cookies
	 */
	var parseCookies = function(){
		ua.cookies = []; /* Always defined, even if empty */
		var c = document.cookie;
		if (c.length) {
			var cookieArray = c.split(';');
			var i = 0;
			var l = cookieArray.length;
			var oneCookie, cookieName;
			
			for (i=0; i < l; i++) {
				oneCookie = cookieArray[i].split('=');
				cookieName = oneCookie[0].replace(/^\s+|\s+$/, '');
				ua.cookies[cookieName] = oneCookie[1];
			}
		}
		window.myCookies = ua.cookies; //TODO: UA-specific variable, should move to ua.united
	}(); // Self-executing at runtime
	
	/*
	 * @PRIVATE - Add special classes to the <HTML> tag in order to 
	 * deliver browser- and version-specific CSS.
	 */

	var addBrowserClasses = (function($){
		var targetElement = jQuery('html'),
			browser = jQuery.uaMatch(navigator.userAgent).browser,
			version = parseFloat($.uaMatch(navigator.userAgent).version),
			versionStr = version.toString().replace('.','-'), /* CSS classes cannot contain dots */
	    	mode = document.compatMode,
			modeClassName = '';
		
		/* 
		 * Sniff the rendering mode of the browser in order to add the ability to target 
		 * appropriate CSS. This is very helpful when handling different environments. 
		 * http://www.webmasterworld.com/forum21/6361.htm
		 */
	    if (mode) {
	        if (mode == 'BackCompat') modeClassName = 'quirksMode'; 
	        else if (mode == 'CSS1Compat') modeClassName = 'standardsMode';
	        else modeClassName = 'standardsMode'; // "Almost Standards Mode"
	        targetElement.addClass(modeClassName); 
	    }
				
		switch(browser) {
			case 'msie': /* IE */
				/* Always add these classes. 
				 * Useful for default values, future-proofing, and minor versions (3.5 vs. 3)
				 * jQuery will not add duplicate classes, so we don't worry about duplicates.
				 */
				targetElement.addClass('ie ie'+versionStr); 
				
				/* Now, we add version-specific class names */
				if (version <= 6) targetElement.addClass('ie6 lte9 lte8 lte7 lte6');
				else if (version == 7) targetElement.addClass('ie7 lte9 lte8 lte7');
				else if (version == 8) targetElement.addClass('ie8 lte9 lte8');
				else if (version == 9) targetElement.addClass('ie9 lte9');
				break;
				
			case 'mozilla': /* FireFox */
				targetElement.addClass('moz moz'+versionStr);
				break;
				
			case 'webkit': /* Chrome & Safari */
				targetElement.addClass('webkit webkit'+versionStr);
				break;
		}

 	})(jQuery); // Self-executing at runtime
 	
	/*
	 * @PUBLIC - Get the selected value of a radio button set.
	 */
	this.getRadioValue = function(radioObj) {
		if (!radioObj) return '';
		var radioLength = radioObj.length;
		if (radioLength == undefined) 
			if (radioObj.checked) {
				return radioObj.value;
			}
			else {
				return "";
			}
		for(var i = 0; i < radioLength; i++) {
			if(radioObj[i].checked) {
				return radioObj[i].value;
			}
		}
		return '';
	};
	
	/*
	 * @PUBLIC - Queue up event handlers. Using 3 flavors of unload
	 * functionality (Event Listeners, window.onunload, &
	 * window.onbeforeunload), which covers the widest variety of browser
	 * capabilities.
	 * 
	 * http://vidasp.net/jQuery-unload.html
	 * 
	 * Function parameters are passed as an array. Example: If the function is
	 * this: function showAlert(msg1,msg2) { alert(msg1 + '-' + msg2); }
	 * 
	 * It's added as an unload task like this: var anyVar = 'OMG!';
	 * ua.utils.attachEvent(window,'unload',showAlert,[anyVar,"I can't believe it's not butter!"]);
	 * 
	 * You can attach an event to anything, where the 1st param is the acting object. 
	 * A link, for example: ua.utils.attachEvent(document.links[3],'click',getLinkInfo,[]);
	 * 
	 * Also, a previous version of this exists in
	 * //www.united.com/ual/asset/toolbox.js
	 */
	window.ua.runtime.events = [];
	this.attachEvent = function(context,event,func,paramArray) {
		/* 
		 * If someone tries to pass an outdated event format (one with 'on' prefix), we'll
		 * convert it to the standard format by stripping the prefix.
		 */
		var legacyFormat = new RegExp(/^[on]{2}/i);
		if (legacyFormat.test(event)) {
			event = event.substring(2,event.length);
		}

		var eventQueue = event + 'arr';
		var functionObj = '';
		var standardEventName = event; /* blur, click, unload, etc. */
		var legacyEventName = 'on' + event; /* onblur, onclick, onunload, etc. */ 
		
		ua.runtime.events.push([event,func,paramArray]);
		
		if(ua.utils.isArray(paramArray)) { 
			functionObj = ua.utils.applyFunction(func,this,paramArray); 
		} else { 
			functionObj = func; 
		}
		
		if (typeof context.addEventListener != "undefined") {   /* W3C */
			context.addEventListener(standardEventName,functionObj,false); 
			}
		else if (typeof context.attachEvent != "undefined") {   /* IE */ 
			context.attachEvent(legacyEventName,functionObj); 
			}
		else { /* Legacy, window properties */
			/* Create our storage array */
			if (!ua.utils.isArray(context[eventQueue])) {
				context[eventQueue] = [];
				
				/* If an event already exists. Let's save it to the array, so we don't overwrite it */
				if (context[legacyEventName]) {				
					context[eventQueue].push(context[legacyEventName]);
				}
			}
			
			/* Now we save the current function to the array */
			context[eventQueue].push(functionObj);
			
			/* Finally, set the event to call our array to execute all stored functions.
			 * Using while() and .shift() within a self-executing function like this 
			 * allows 3 things to happen:
			 * 
			 * 1) The first element in the array is executed
			 * 2) The same element is deleted from the array to make way for the next element
			 * 3) while() cycles through all array elements until complete
			 * 
			 * Reference: http://bit.ly/aJljaB
			 * 
			 */ 
			context[legacyEventName] = function(){
				while(context[eventQueue].length > 0) {
					try {
						(context[eventQueue].shift())();
					} catch(e1) {
						/* Just in case someone throws us a bad function. We don't want to interrupt all others */
						//alert('Error: ' + e1);
					}
				}
			};
		}
	};
}; // END ua.utils

/* 
 * Backwards compatibility assurance. 
 * These declarations will allow any old code, which references old function names,
 * to continue working until we can refactor the code appropriately.
 */
window.copyright_year = ua.config.copyrightYear;
window.validateEml = window.isEmail = ua.utils.isEmail;
window.validateCC = ua.utils.isCC;
window.TrimString = window.bTrimString = function(str){ return str.trim(); };
window.removeSpaces = window.removeWhitespace = function(str){ return str.removeSpaces(); };
window.isDigit = window.isNumeric = ua.utils.isNumeric;
window.setCookie = ua.utils.setCookie;
window.getCookie = ua.utils.getCookie;
window.deleteCookie = ua.utils.deleteCookie;
window.addCommas = function(str){ return str.commafy(); };
window.isHexCode = ua.utils.isHexCode;
window.listContains = ua.utils.listContains;
window.addEvent = function(event,func){
	ua.utils.attachEvent(window,event,func,[]);
}

/* Kick off the deferred file loader */
ua.utils.attachEvent(window,'load',function () {
	ua.utils.loadDeferredFiles();
});

/* Let's keep track of how long it takes to initialize the whole script */
ua.endTime = (new Date).getTime();
ua.runtime.execTime = ua.endTime - ua.startTime;

/* Clean up the ua namespace */
delete ua.startTime;
delete ua.endTime;


