/********************************************************************
 * Global variables
 ********************************************************************/
var g_httpPrefix = location.href.split("://")[0] + "://";
var g_thisURL = location.href;

/********************************************************************
 * Pop up behavior manipulation utilities
 ********************************************************************/
function popupRel(link, data) {
	var url;
	var popup;
	if (typeof link == "string") {
		url = link;
	} else {
		url = link.getAttribute("href");
		if (data.length > 0) {
			link.target = data[0];
		}
	}
/********************************************************************
 * If a popup window name is already being used, this will change the second window
 * name invoked to be named EMPTY_STRING.  This allows a popup window to
 * open another popup window and not replace its existing location.
 ********************************************************************/
	data[0] = (window.name === data[0]) ? "" : data[0];
	switch (data.length) {
		case 0:
			popup = window.open(url);
			break;
		case 1:
			/*@cc_on
			if (isDocument(url)) { popup = window.open("", data[0]); popup.close(); }
			@*/
			popup = window.open(url, data[0]);
			break;
		default:
			/*@cc_on
			if (isDocument(url)) { popup = window.open("", data[0], data[1]); popup.close(); }
			@*/
			popup = window.open(url, data[0], data[1]);
			break;
	}
	popup.focus();
	return false;
}

function isDocument(url){
	var string_arr = url.split(".");
	var extension = string_arr[string_arr.length-1].replace("/","").split("?")[0];
	var bool;
	bool = (extension === "pdf" || extension === "doc" || extension === "xls") ? true : false;
	return bool;
}

var MapLinks = {
	runMapLinks: true,
	popup: function(rel, targetObj, e) {
		e = e || window.event;
		var self = MapLinks;
		var functionData = self.relFunctionsMap[rel];
		if ( isPresent(functionData) ) {
			var functionRef = functionData[0];
			var functionValues = functionData[1];
			if (!functionRef(targetObj, functionValues) ) {
				if (e) {
					e.preventDefault();
					return false;
				}
			}
		}
	},
	handler: function(e) {
		var self = MapLinks;
		if (!self.runMapLinks) {
			self.runMapLinks = true;
			return;
		}
		if (!e) {
			e = window.event;
		}
		var targetObj = getTargetObj(e, "a") || getTargetObj(e, "area");
		if (!targetObj) {
			return;
		}
		return self.relHandler(targetObj, e);
	},
	relHandler: function(objLink, e) {
		var self = MapLinks;
		var rel = objLink.getAttribute("rel");
		var functionData = self.relFunctionsMap[rel];
		if (isPresent(functionData) && !isModifiedClick(e) ) {
			var functionRef = functionData[0];
			var functionValues = functionData[1];
			if (!functionRef(objLink, functionValues) ) {
				e.preventDefault();
				return false;
			}
		}
	},
/**************************************************************
 * relFunctionsMap maps rel attributes to functions.
 * syntax is:  relName:[function, functionArgsAsArray]
 **************************************************************/
	relFunctionsMap: {
		  external:[popupRel, ["external","width=800, height=600, menubar=yes, scrollbars=yes, resizable=yes, location=yes, toolbar=yes"]],
		     popup:[popupRel, ["popup","width=800, height=600, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
	 popupToolbars:[popupRel, ["popupToolbars","width=800, height=600, menubar=yes, scrollbars=yes, resizable=yes, location=yes, toolbar=yes"]],
		      mini:[popupRel, ["mini","width=400, height=250, status=no, resizable=yes, scrollbars=yes, toolbar=no, menubar=no, location=no"]],
		  glossary:[popupRel, ["glossary","width=540, height=560, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		       pdf:[popupRel, ["pdf","width=800, height=600, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		definition:[popupRel, ["definition","width=600, height=350, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		calculator:[popupRel, ["","width=740, height=770, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		       aam:[popupRel, ["aam","width=580, height=600, menubar=no, scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		fundquotes:[popupRel, ["fundquotes","width=350, height=275, menubar=no, scrollbars=no, resizable=yes, location=no, toolbar=no"]],
		 contactus:[popupRel, ["contactus","width=650,height=650,menubar=no,scrollbars=yes, resizable=yes, location=no, toolbar=no"]],
		  sitetour:[popupRel, ["sitetour","width=633,height=475,menubar=no,scrollbars=yes, resizable=no, location=no, toolbar=no"]],
	trainingModule:[popupRel, ["trainingModule","width=997,height=690,menubar=no,scrollbars=yes, resizable=no, location=no, toolbar=no"]],
	  sendToOpener:[sendToOpener,[this.href]],
// unfortunately the popup parameters can't be placed here for this special object.  the popup parameters are found on the
// getImgProperties function below.  Ideally we can put this the function map.
	      imgPopup:[getImgProperties, [this]],
		 fiduciary:[saveScroll,[this.href]],
		 "video": [popupRel, ["video","toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,copyhistory=no,width=520,height=480"]]
	}
};


/********************************************************************
 * Plugin Utilities
 ********************************************************************/
var g_isMozPlugin = (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length);
var g_isIePlugin = (!g_isMozPlugin && window.ActiveXObject);

// adobe is creating functions in the global namespace that don't test params
// being past before using them that cause javascript errors when they pass null.
// So we fix it by overwriting their code to test that param is of the right type
// before they attempt to use the params methods/properties.
var AdobeFix = function() {
	var self = {
		init: function() {
			self.__flash__addCallback();
			self.__flash__removeCallback();
			self.__flash__arrayToXML();
			self.__flash__argumentsToXML();
			self.__flash__objectToXML();
			self.__flash__escapeXML();
		},
		__flash__addCallback: function() {
			window.__flash__addCallback = function(instance, name) {

				if (instance && typeof instance === "object") {
					instance[name] = function () {
						return eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
					};
				}

			};
		},
		__flash__removeCallback: function() {
			window.__flash__removeCallback = function(instance, name) {

				if (instance && typeof instance === "object") {
					instance[name] = null;

				}
			};
		},
		__flash__arrayToXML: function() {
			window.__flash__arrayToXML = function(obj) {
				var s = "<array>";
				if (obj && typeof obj === "object") {	
					for (var i=0; i<obj.length; i++) {
						s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
					}

				}
				return s+"</array>";
			};
		},	
		__flash__argumentsToXML: function() {
			window.__flash__argumentsToXML = function(obj,index) {
				var s = "<arguments>";
				if (obj && typeof obj === "object") {
					for (var i=index; i<obj.length; i++) {
						s += __flash__toXML(obj[i]);

					}
				}
				return s+"</arguments>";
			};
		
		},
		__flash__objectToXML: function() {
			window.__flash__objectToXML = function(obj) {
				var s = "<object>";
				if (obj && typeof obj === "object") {
					for (var prop in obj) {
						s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";

					}
				}

				return s+"</object>";

			};
		},
		__flash__escapeXML: function() {
			window.__flash__escapeXML = function(s) {
				if (s && s.replace) {
					return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");

				}
			};
		}	 
	};
	return self;
}();

function pdfPluginInstalled() {
	var isPdfPluginInstalled = false;
	if (g_isMozPlugin) {
		duff(navigator.plugins, function(objPlugin) {
			// "Adobe PDF" is the description for Acrobat 8 (ver 3 doesn't have "Adobe" in the desc)
			if (objPlugin.description.indexOf("Adobe Acrobat") != -1 || objPlugin.description.indexOf("Adobe PDF") != -1) {
				isPdfPluginInstalled = true;
			}
		});
	}
	else if (g_isIePlugin) {
		var versions = [
			"AcroPDF.PDF.1",
			"PDF.PdfCtrl.6",
			"PDF.PdfCtrl.5",
			"PDF.PdfCtrl.1"
		];
		for (i = 0; i < versions.length; i++) {
			try {
				objAcro = eval("new ActiveXObject(versions[i]);");
				if (objAcro) {
					isPdfPluginInstalled = true;
					break;
				}
			}
			catch(e) { }
		}
	}
	return (isPdfPluginInstalled) ? true : false;
}

var SwfDetection = function() {
	var self = {
		ver: null,
		getSwfVer: function() {
			var strVersion;
			var objFlash;
			var arrVer;

			if (g_isMozPlugin) {
				var swfVer = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
				objFlash = navigator.plugins["Shockwave Flash" + swfVer];
				if (!objFlash) { return null; }
				arrVer = objFlash.description.match(/(\d+)\.(\d+)\s+\w(\d+)$/);
				return [(arrVer[1]|0), (arrVer[2]|0), (arrVer[3]|0)];
			}
			else if (g_isIePlugin) {
				eval('try { objFlash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); objFlash.AllowScriptAccess = "always"; strVersion = objFlash.GetVariable("$version"); } catch(e) {}');

				if (!strVersion) {
					eval('try { objFlash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); strVersion = " 6,0,21"; } catch(e) {}');
				}

				if (!strVersion) {
					eval('try { objFlash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); strVersion = objFlash.GetVariable("$version"); } catch(e) {}');
				}
			}

			if (!strVersion) { return null; }
			arrVer = strVersion.split(" ")[1].split(",");
			return [(arrVer[0]|0), (arrVer[1]|0), (arrVer[2]|0)];
		},

		getVersionString: function() {
			if (!self.ver) { self.ver = self.getSwfVer(); }
			return self.ver ? self.ver.join(".") : "n/a";
		},

		reqVersionMet: function(reqMajorVer, reqMinorVer, reqRevision) {
			if (!self.ver) { self.ver = self.getSwfVer(); }
			if (!self.ver) { return false; }
			var versionArray = self.ver;
			var versionMajor = versionArray[0];
			var versionMinor = versionArray[1];
			var versionRevision = versionArray[2];
			if (versionMajor > reqMajorVer) { return true; }
			if (versionMajor == reqMajorVer) {
				if (versionMinor > reqMinorVer) { return true; }
				if (versionMinor == reqMinorVer && versionRevision >= reqRevision) { return true; }
			}
			return false;
		}
	};
	return self;
}();

var MakePlugin = function() {
	var self = {
		objEmbedContainer: {},
		objEmbededMedia: {},
		create: function(id, type, url, width, height, params, isFixedWidth) {
			var insertObj = document.getElementById(id);
			var parentObj = insertObj.parentNode;
			var strDivWidth, objObject;
			if (!insertObj) { return; }
			
			var strObject = '<object';
			switch(type) {
				case "flash" :
					strObject += g_isIePlugin ? ' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' +
						' codebase="' + g_httpPrefix + 'fpdownload.macromedia.com/get/flashplayer/current/swflash.cab"' :
						' type="application/x-shockwave-flash" data="' + url + '"';
					strObject += ' id="' + id.toLowerCase().replace(/[-,\*,\.]/gi, "_") + '_fix" width="' + width + '" height="' + height + '" style="position: absolute; z-index: 0;">';
					strObject += '<param name="movie" value="' + url + '" />';
					strObject += '<param name="wmode" value="window" />';
					break;
				case "quicktime" :
					strObject += g_isIePlugin ? ' classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"' +
						' codebase="' + g_httpPrefix + 'www.apple.com/qtactivex/qtplugin.cab"' :
						' type="video/quicktime" data="' + url + '"';
					strObject += ' width="' + width + '" height="' + height + '">';
					strObject += g_isIePlugin ? '<param name="src" value="' + url + '" />' : "";
					break;
				case "windowsMedia" :
					strObject += g_isIePlugin ? ' classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"' :
						' type="video/x-ms-wmv" data="' + url + '"';
					strObject += ' width="' + width + '" height="' + height + '">';
					strObject += '<param name="' + (g_isIePlugin ? "url" : "src") + '" value="' + url + '"/>';
					break;
			}
			
			strObject += self.addParams(id, params);
			strObject += "</object>";
			strDivWidth = !isFixedWidth ? "" : "width: "+ width + "px;";
			
			/* this is used because IE makes all quicktimes movies added 
			   via the dom to have their position changed to relative 
			   to the view port instead of relative to their 
			   containing element */
			if (type == "quicktime" && g_isIePlugin) {
				insertObj.style.height = height + "px";
				insertObj.style.width = strDivWidth;
				insertObj.style.position = "relative";
				insertObj.innerHTML = strObject;
				return;
			}
			strObject = '<div id="' + insertObj.id + '-flash" class="flash-content" style="position: relative; height:' + height + 'px;' + strDivWidth + '">' + strObject + "</div>";
			
			// This is because IE breaks extneralInerfaceCalls if not added to the DOM this way.
			if (type == "flash" && g_isIePlugin) {
				addClass(insertObj,"non-flash-content");
				parentObj.innerHTML = strObject + parentObj.innerHTML;
				self.getMediaObject(id);
				return;
			}
			
			objObject = strObject.toDom();
			addClass(insertObj,"non-flash-content");
			parentObj.insertBefore(objObject,insertObj);
			self.getMediaObject(id);

			parentObj = null;
			insertObj = null;
			objObject = null;
		},
		addParams: function(id, params) {
			function sObjectToJSON() {
				var s_account = window.s_account;
				var s = window.s;
				if (!s_account || !s) { return ""; }
				var strJSON = '{"account": "' + s_account + '"', type, strTmp;
				var afProps = s.__addedProps;
				for (var i in afProps) {    
					type = String(typeof afProps[i]).toLowerCase();
					switch(type) {
						case "function": 
							break;
						case "object": 
							//one or more of the objects is causing a recursion error, 
							//so right now, we just skip them
							continue;
							break;
						default: 
							strTmp = afProps[i]+"";
							if (strTmp.match(/%\d/g) ) { strTmp = unescape(strTmp); }
							strJSON += ', "' + i + '": "' + escape(strTmp) + '"';
							break;
					}
				}
				
				strJSON += "}";
				return escape(strJSON);
			}
			
			if (!params) {
				params = { "FlashVars": "containerId="+id };
			} else if (!params.FlashVars) { 
				params.FlashVars = "containerId="+id; 
			} else if (params.FlashVars.indexOf("containerId") === -1) {
				params.FlashVars += "&amp;containerId="+id;
			}
			
			params.FlashVars += "&amp;sObject=" + sObjectToJSON();
			
			var strParams = "";
			for (var key in params) {
				strParams += '<param name="' + key + '" value="' + params[key] + '" />';
			}
			
			return strParams;
		},
		getMediaObject: function(id) {
			if (!self.objEmbededMedia[id]) {
				self.objEmbedContainer[id] = document.getElementById(id + "-flash");
				self.objEmbededMedia[id] = self.objEmbedContainer[id].getElementsByTagName("object")[0];
			}
		},
		changeHeight: function(containerId,height) {
			self.objEmbedContainer[containerId].style.height = height + "px";
			self.objEmbededMedia[containerId].setAttribute("height", height);
		},
		changeWidth: function(containerId,width) {
			if (self.objEmbedContainer[containerId].style.width !== "") {
				self.objEmbedContainer[containerId].style.width = width + "px";
			}
			self.objEmbededMedia[containerId].setAttribute("width", width);
		},
		changeObjectId: function(containerId,instanceId) {
			//removing changing id on object tag as it messes up externalInterface calls.
			//need to keep changeObjectId method until we convert the 
			//Differentiating Our Funds flash presenations, to AS3.
			//self.objEmbededMedia[containerId].setAttribute("id", instanceId);
		},
		updateMediaStats: function(mediaStats) {
			var mediaStatsCookie = new Cookie("s_br");
			mediaStatsCookie.set(mediaStats);
		}
	};
	return self;
}();

function reqFlashVerPluginInstalled() {
	return SwfDetection.reqVersionMet(9,0,115);
}





function getImgProperties(obj) {
	var hrefStr = obj.href;
	var dimensions = hrefStr.split("?")[1];

	//if (isPresent(dimensions)) {
		var width = dimensions.split("&")[0];
		var height= dimensions.split("&")[1];
		var popupProperties = width+","+height+",menubar=no,scrollbars=no,resizable=yes,location=no,toolbar=no";
		return popupRel(obj.href,["",popupProperties]);
	/*} else {
		return popupRel(obj.href,[""]);
	}*/
}


function showNav() {
	this.getElementsByTagName('ul').item(0).style.visibility='visible';
}


function hideNav() {
	this.getElementsByTagName('ul').item(0).style.visibility='hidden';
}


function validateSearch(fieldObj, submitObj) {
	var sLength = fieldObj.value.replace(/\W/g, "").length;
	var Limit   = 255;
	var errmsg  = "";

	if (sLength == 0 || sLength > Limit){
		if (sLength == 0) {
			errmsg = "Please enter text to search before clicking \"" + submitObj.value + "\".";
			fieldObj.value = "";
		}
		if (sLength > Limit){
			errmsg = "There is a " + Limit + " character limit in the search query.";
			var s = fieldObj.value.substr(0,Limit);
			fieldObj.value = s;
		}
		alert(errmsg);
		fieldObj.focus();
		return false;
	}
	return true;
}


function popup(href, name, specs) {
	// if the specs are not passed, assign the default parameters
	if (typeof specs != "string") specs = "";  // empty implies 'yes' to all
	var windowObj = window.open(href, name.replace(/-/g, ""), specs);
	windowObj.focus();

	if(window.event){
		event.returnValue = false;
	}
	return false;
}


function sendToOpener(href) {
	if (window.opener.closed) return true;
	window.opener.location = href;
	window.opener.focus();
	//self.close();

	if(window.event){
		event.returnValue = false;
	}
	return false;
}


function backButton() {
	var historyObj = window.history;
	if (historyObj.length > 1) document.write('<form id="formBackButton"><fieldset><input type="button" onclick="history.back()" value="Back" class="button" /></fieldset></form>');
}

/*****************************************************************
 * Used to save the scroll location when refreshing the fiduciary article
 ****************************************************************/
function saveScroll(url){
	return alsoSaveScroll(url);
}

function alsoSaveScroll(_targeturl) {
	var x,y;
	if (self.pageYOffset) {
		x = self.pageXOffset;
		y = self.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollTop) {
		x = document.documentElement.scrollLeft;
		y = document.documentElement.scrollTop;
	} else if (document.body) {
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	window.location = _targeturl + '&scrollX=' + x + '&scrollY=' + y;
	if(window.event){
		event.returnValue = false;
	}
}

/********************************************************************
 * Dom manipulation utilities
 ********************************************************************/
function appendChild(parentObj, addObj) {
	if (addObj.id != "tmp-div") {
		parentObj.appendChild(addObj);
	}
	else {
		duff(addObj.childNodes, function(node) {
			parentObj.appendChild(node.cloneNode(true));
		});
	}
}

function replaceChild(parentObj, newObj, replaceObj) {
	if (newObj.id != "tmp-div") {
		parentObj.replaceChild(newObj, replaceObj);
	}
	else {
		insertBefore(parentObj, newObj, replaceObj);
		parentObj.removeChild(replaceObj);
	}
}

function insertBefore(parentObj, newObj, beforeObj) {
	if (newObj.id != "tmp-div") {
		parentObj.insertBefore(newObj, beforeObj);
	}
	else {
		duff(newObj.childNodes, function(node) {
			parentObj.insertBefore(node.cloneNode(true), beforeObj);
		});
	}
}

/********************************************************************
 * Event handler utilities
 ********************************************************************/
// the following event handling code created by Dean Edwards and Tino Zijdel
// with modifications to ensure handler execution order

// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
	if (isPresent(element.type) && element.type.indexOf("select-") == 0 ) {
		element["on" + type] = handler;
		return;
	}
	if (!handler.$$guid) handler.$$guid = addEvent.guid++;
	if ( !isPresent(element.events) ) element.events = new Object();
	var handlers = element.events[type];
	if (!handlers) {
		handlers = element.events[type] = new Object();
		handlers.order = new Array();
		if (element["on" + type] && (element != document || type != "readystatechange") ) {
			handlers[0] = element["on" + type];
			handlers.order[0] = 0;
		}
	}
	handlers[handler.$$guid] = handler;
	handlers.order[handlers.order.length] = handler.$$guid;
	if (element != document || type != "readystatechange") {
		element["on" + type] = handleEvent;
	}
}
addEvent.guid = 1;

function removeEvent(element, type, handler) {
	if (element.events && element.events[type]) {
		var handlers = element.events[type];
		var id = handler.$$guid;
		if (delete handlers[handler.$$guid]) {
			for (var i = 0; i < handlers.order.length; i++) {
				if (handlers.order[i] == handler.$$guid) {
					var newOrder = handlers.order.slice(0, i);
					if (i + 1 != handlers.order.length) {
						newOrder = newOrder.concat( handlers.order.slice(i + 1) );
					}
					handlers.order = newOrder;
				}
			}
		}
	}
}

function handleEvent(event) {
	var returnValue = true;
	event = isPresent(event) ? event : isPresent(document.getElementById) ? fixEvent(window.event) : window.event;
	var handlers = this.events[event.type];
	var order = handlers.order;
	for (var i = 0; i < order.length; i++) {
		this.$$handleEvent = handlers[ order[i] ];
		if (this.$$handleEvent(event) === false) {
			returnValue = false;
		}
	}
	return returnValue;
}

function endOfPageDivExists() {
	var endDiv = document.getElementById("end-of-page-check");
	return (typeof endDiv != "undefined");
}

window.intervalId = 0;

function handleReadyStateChange() {
	if (window.intervalId != 0) {
		if ( endOfPageDivExists() ) {
			clearInterval(window.intervalId);
			window.intervalId = 0;
		}
		else {
			return;
		}
	}
	var event = new Object();
	event.readyState = "complete";
	event.srcElement = document;
	event.target = document;
	event.currentTarget = document;
	event.type = "readystatechange";
	if ( !isPresent(document.events) ) {
		document.Events = new Object();
		var dummyEvents = new Object();
		dummyEvents.readystatechange = dummyHandlers;
		document.events = dummyEvents;
	}
	if ( !isPresent(document.events.readystatechange) ) {
		var dummyHandlers = new Object();
		dummyHandlers.order = new Array();
		document.events.readystatechange = dummyHandlers;
	}
	document.$$handleEvent = handleEvent;
	document.$$handleEvent(event);
}

function fixEvent(event) {
	event = event || window.event;
	if (document.getElementById) {
		if (event.srcElement) {
			event.target = event.srcElement;
		}
		if (event.target && (event.target.nodeType != 1) ) {
			event.target = event.target.parentNode;
		}
		if (!event.preventDefault) {
			event.preventDefault = fixEvent.preventDefault;
		}
		if (!event.stopPropagation) {
			event.stopPropagation = fixEvent.stopPropagation;
		}
	}
	return event;
}

fixEvent.preventDefault = function() {
	this.returnValue = false;
}

fixEvent.stopPropagation = function() {
	this.cancelBubble = true;
}

function isModifiedClick(e) {
	var intButton = (e.which) ? e.which - 1 : e.button;
	return ( intButton != 0 || e.ctrlKey || e.shiftKey);
}

function getTargetObj(e, targetTag, withAttr) {
	if (!e) { e = window.event; }
	var isBody = (targetTag == "body");
	var targetObj =  isBody ? document.body : e.target ? e.target : e.srcElement ? e.srcElement : null;
	if (!targetObj) { return null; }
	if (!isBody && targetObj.nodeType == 3) { targetObj = targetObj.parentNode; } //defeat khtml bug
	if (getTagName(targetObj.tagName) != targetTag || !hasAttribute(targetObj,withAttr)) {
		targetObj = getAncestor(targetObj, targetTag, withAttr);
	}
	return targetObj;
}

/********************************************************************
 * Class utilities
 ********************************************************************/
function hasClass(obj, className) {
	var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)");
	return regexp.test(obj.className);
}

function addClass(obj, className) {
	if (!hasClass(obj, className)) {
		if (obj.className) {
			obj.className += " " + className;
		}
		else {
			obj.className = className;
		}
	}
}

function removeClass(obj, className) {
	var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)");
	obj.className = obj.className.replace(regexp, "$2");
}

function toggleClass(obj, className) {
	if (hasClass(obj, className)) {
		removeClass(obj, className);
	}
	else {
		addClass(obj, className);
	}
}

/********************************************************************
 * General utilities
 ********************************************************************/
function isPresent(param) {
	return typeof param != "undefined" && param != null;
}

// "duff" functions to unroll loops for faster performance
// default version loops forward
function duff(objectArray, method) {
	var arrayLength = objectArray.length;
	var loopLength = arrayLength % 8;
	var index = 0;
	while (loopLength--) {
		method(objectArray[index++]);
	}
	loopLength = parseInt(arrayLength / 8);
	while (loopLength--) {
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
		method(objectArray[index++]);
	}
}

// reverse variation loops backward
function duffReverse(objectArray, method) {
	var arrayLength = objectArray.length;
	var loopLength = arrayLength % 8;
	var index = arrayLength - 1;
	while (loopLength--) {
		method(objectArray[index--]);
	}
	loopLength = parseInt(arrayLength / 8);
	while (loopLength--) {
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
		method(objectArray[index--]);
	}
}

// function used to get a specified Ancester. requires an obj and tagName of the targetTag you wish to stop at.
// example getAncestor(document.getElementById('foo'),"div")
function getAncestor(objT, targetTag, withAttr) {
	var isBody = (targetTag == "body");
	if (isBody) {
		objT = document.body;
	}
	else {
		objT = objT.parentNode;
		while (objT && getTagName(objT.tagName) != targetTag) {
			if (isValueInArray(getTagName(objT.tagName), ["body", "html"]) ) {
				return null;
			}
			objT = objT.parentNode;
		}
	}

	if (objT && !hasAttribute(objT, withAttr)) {
		if (isValueInArray(getTagName(objT.tagName), ["body", "html"]) ) {
			return null;
		}
		objT = getAncestor(objT, targetTag, withAttr);
	}

	return objT;
}

function getTagName(str) {
	if (!isAValue(str) ) { return ""; }
	var tmpArr = str.split(":");
	return trim((tmpArr.length > 1 ? tmpArr[1] : str).toLowerCase() );
}

function hasAttribute(objT,withAttr) {
	if (!isPresent(withAttr) ) { return true; }
	var attrConverter = {"class":"className", "className":"className", "for":"htmlFor", "htmlFor":"htmlFor"};
	var blnTmp = true;

	for (var attr in withAttr) {
		var realValue = attrConverter[attr] ? objT[attrConverter[attr] ] : objT.getAttribute(attr);
		if (!isPresent(realValue) || realValue == "") {
			return false;
		}

		var testValues = withAttr[attr];
		if (!isPresent(testValues) || !testValues.length) {
			continue;
		}

		realValue = trim(realValue.replace(",", " ") ).split(" ");
		duff(testValues, function(testValue) {
			if (!blnTmp) { return; }
			blnTmp = isValueInArray(testValue, realValue);
		});
	}

	return  blnTmp;
}

// function used to get specified parent. requires obj and tagname of parent you wish to stop at
// example getParent(document.getElementById("foo"),"div")
// should be replaced with getAncestor()
function getParent(objT, stopAt) {
	return getAncestor(objT, stopAt);
}

function isNumeric(e, legalChar) {
	if (!e) { e = window.event; }
	if (isControlCharacter(e)) {
		return true;
	}
	var keyCode = isAValue(e) ? (isAValue(e.which) ? e.which : e.keyCode) : window.event.keyCode;
	var pattern;
	if (legalChar) {
		pattern = new RegExp("[\\d\\r\\b\\t\\x00\\x2e\\x25\\x26\\x27\\x28\\x60\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x69" + legalChar + "]");
	}
	else {
		pattern = /[\d\r\b\t\x00\-\x00\x2e\x25\x26\x27\x28\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69]/;
	}
	return pattern.test(String.fromCharCode(keyCode));
}

function isAValue(param) {
	return typeof param != "undefined" && param != null;
}

function isControlCharacter(e) {
	if (isAValue(e) && isAValue(e.modifiers)) {
		return e.modifiers ^ 2 == 2;
	}
	else {
		return isAValue(e) ? e.ctrlKey : window.event.ctrlKey;
	}
}

function isValueInArray(value, array) {
	var i = array.length;
	while (i--) {
		if (value == array[i]) {
			return true;
		}
	}
	return false;
}

/********************************************************************
 * String utilities
 ********************************************************************/
// trim whitespace from left and right of string
function trim(str) {
	return str.replace(/^\s*|\s*$/g,"");
}

// trim whitespace from left of string
function ltrim(str) {
	return str.replace(/^\s*/g,"");
}

// trim whitespace from right of string
function rtrim(str) {
	return str.replace(/\s*$/g,"");
}

function applyCommas() {
	this.value = this.value.replace(/,/g, "");
	this.value = addComma(this.value);
}

function addComma(nStr){
	nStr += '';
	var dpos = nStr.indexOf('.');
	var nStrEnd = '';
	var rgx = /(\d+)(\d{3})/;
	if (dpos != -1) { nStrEnd = '.' + nStr.substring(dpos + 1, nStr.length); nStr = nStr.substring(0, dpos); }
	while (rgx.test(nStr)) nStr = nStr.replace(rgx, '$1' + ',' + '$2');
	return nStr + nStrEnd;
}

//pass url w/query and query param you want the value from
function getQueryParamValue(strLocation, strParam) {
	strLocation = strLocation.split("#")[0];
	var arrQuery = strLocation.split("?");
	if (arrQuery.length < 2) {
		return false;
	}
	var arrQuery = arrQuery[1].split("&");
	var i = arrQuery.length;
	while (i--) {
		var arrParam = arrQuery[i].split("=");
		if (arrParam[0] == strParam) {
			return trim(arrParam[1]);
		}
	}
	return false;
}

function setQueryParamValue(strLocation, objParams, escapeAmps) {
	var arrTmp = strLocation.split("#");
	var strHash = arrTmp.length > 1 ? "#" + arrTmp[1] : "";
	var strNewParamValue, strCurrValue, strCurrParamValue, arrQuery, strUrl;
	strLocation = arrTmp[0];

	for (var strParam in objParams) {
		strValue = escape(objParams[strParam]);
		strNewParamValue  = strParam + "=" + strValue;
		strCurrValue = getQueryParamValue(strLocation, strParam);
		arrQuery = strLocation.split("?");

		if (arrQuery.length > 1 && trim(arrQuery[1]).length !== 0) {
			arrQuery[1] = trim(arrQuery[1]);
			if (strCurrValue.length > 0 || strLocation.indexOf(strParam + "=") != -1) {
				strUrl = arrQuery[0] + "?" + arrQuery[1].replace(strParam + "=" + strCurrValue, strNewParamValue) + strHash;
			} else {
				strUrl = arrQuery[0] + "?" + arrQuery[1] + "&" + strNewParamValue + strHash;
			}
		} else {
			strUrl = arrQuery[0] + "?" + strNewParamValue + strHash;
		}
		strLocation = strUrl;
	}
	return  escapeAmps ? strUrl.replace("&", "&amp;") : strUrl;
}

String.prototype.toDom = function() {
	var xslProc, regex = /(function|object)/;
	var xslDoc, xmlDoc, htmlObj, tmpObj, objChildren;
	var xslStr = '<?xml version="1.0" encoding="utf-8"?>' +
	'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">' +
	'<xsl:output method="html" encoding="utf-8"/>' +
	'<xsl:template match="root">' +
	'<xsl:copy-of select="node()"/>' +
	'</xsl:template>' +
	'</xsl:stylesheet>';
	xmlStr = "<?xml version=\"1.0\"?><root>" + this + "</root>";
	if (regex.test(typeof XSLTProcessor) && regex.test(typeof (new XSLTProcessor()).importStylesheet)) {
		xslProc = new XSLTProcessor();
		xmlDoc = (new DOMParser).parseFromString(xmlStr, "text/xml");
		xslDoc = (new DOMParser).parseFromString(xslStr, "text/xml");
		xslProc.importStylesheet(xslDoc);
		htmlObj = xslProc.transformToFragment(xmlDoc, document);
	}
	else {
		htmlObj = document.createDocumentFragment();
		tmpObj = document.createElement("div");
		tmpObj.innerHTML = this;
		objChildren = tmpObj.childNodes;
		duffReverse(objChildren, function(child) {
			var firstChild = htmlObj.firstChild;
			if (firstChild) {
				htmlObj.insertBefore(child, firstChild);
			} else {
				htmlObj.appendChild(child);
			}
			firstChild = null;
			child = null;
		});
	}

	xslDoc = null;
	xmlDoc = null;
	xslProc = null;
	tmpObj = null;

	return htmlObj;
};

String.prototype.stripHtml = function() {
	return this.replace(/<\/?[^>]+\/?>/gi," ").replace(/\s+/gi," ").replace(/([\w\)]\/)\s((&#8203;)?\s)?/gi,"$1$3");
};

/********************************************************************
 * Cookie utilities -- Get, set, delete, and parse cookies
 ********************************************************************/

 // Create client-side Cookie manipulation object, cookieName: the name of the cookie to get, set or delete
function Cookie(cookieName) {
	this.name = escape(cookieName);
}

// returns the value of the cookie represented by this object, or null if the cookie is not valid
Cookie.prototype.get = function() {
	if (!isPresent(document.cookie) ) {
		return null;
	}
	var valueRegExp = new RegExp(this.name + "=([^;]*)");
	var value = valueRegExp.exec(document.cookie);
	if (value && value[1]) {
		value = unescape(value[1]);
		return value == "__invalid__" ? null : value;
	}
	return null;
};

 // sets the cookie represented by this object. If seconds not provided, makes a session cookie.
Cookie.prototype.set = function(value, seconds) {
	var cookieText = this.name + "=" + escape(value) + "; path=/";
	if (isPresent(seconds) ) {
		var expiry = new Date();
		expiry.setTime(expiry.getTime() + (seconds * 1000) );
		expiry = expiry.toUTCString().split(" ");
		expiry[1] = ("00" + expiry[1]).substring(expiry[1].length);
		expiry = "; expires=" + expiry.join(" ").replace(/([a-zA-Z]{3}, \d{2}) ([a-zA-Z]{3}) /, "$1-$2-").replace(/UTC/, "GMT");
		cookieText += expiry;
	}
	document.cookie = cookieText;
};

// sets a session cookie for the cookie represented by this object
Cookie.prototype.setInSession = function(value) {
	this.set(value);
};

 // removes the cookie represented by this object, returning the last value present for the cookie
Cookie.prototype.remove = function() {
	var value = this.get();
	this.set("__invalid__", -(365 * 24 * 60 * 60) );
	return value;
};

function cookieExists(cname) {
	return (new Cookie(cname) ).get() != null;
}

function getCookie(name) {
	return (new Cookie(name) ).get();
}

Mapping = {
	idMap: {},

	mapCookie: new Cookie("nav"),

	init: function(idMap) {
		Mapping.idMap = idMap;
		addEvent(document, "click", Mapping.delegator);
	},

	delegator: function(event) {
		var root = Mapping;
		var element = root.privateFunctions.getTargetLink(event);
		if (element == null) {
			return;
		}
		relType = element.getAttribute('rel');
		switch(relType){
			case 'login':
			case 'external':
			case 'pdf':
				return;
				break;
			default:
				break;
		}
		var locationText = root.privateFunctions.getLocationText(element);
		if (locationText) {
			root.storeNavLocation(locationText);
		}
		else {
			root.mapCookie.remove();
		}
	},

	storeNavLocation: function(locationText) {
		Mapping.mapCookie.setInSession(locationText);
	},

	getNavLocation: function() {
		return Mapping.mapCookie.remove();
	},

	storeNavLocationById: function(id) {
		var text = Mapping.idMap[id];
		if (text && typeof text != "function") {
			Mapping.storeNavLocation(text);
			return true;
		}
		return false;
	},

	addMappings: function(newMappings) {
		var map = Mapping.idMap;
		for (var id in newMappings) {
			map[id] = newMappings[id];
		}
	},

	privateFunctions: {
		getTargetLink: function(event) {
			var element = event.target;
			var body = document.getElementsByTagName("body")[0];
			while (element != body && element != document.documentElement) {
				var tagName = element.tagName.toLowerCase();
				if (tagName == "a" || tagName == "area") {
					return element;
				}
				element = element.parentNode;
			}
			return null;
		},

		getLocationText: function(element) {
			var body = document.getElementsByTagName("body")[0];
			var text = null;
			var getTextFromId = Mapping.privateFunctions.getTextFromId;
			while (element != body && element != document.documentElement) {
				text = getTextFromId(element);
				if (text) {
					break;
				}
				element = element.parentNode;
			}
			return text || getTextFromId(element) || getTextFromId(null);
		},

		getTextFromId: function(element) {
			var id = element ? element.id : "__undefined__";
			var text = Mapping.idMap[id];
			return typeof text == "function" ? text(element) : text;
		}
	}
};


//SiteCatalyst navigation tracking
Mapping.init(
	{
		//<div> id: title
		"logo": "American funds logo",
		"global": "Top global links",
		"nav-main": "Top navigation",
		"nav-section": "Left navigation",
		"overview-section": "Section overview",
		"overview-section-custom": "Section overview",
		"overview-topic": "Topic overview page",
		"overview-topic-list": "Topic overview page",
		"overview-subtopic": "Sub-topic overview",
		"site-hedge": "Hedge",
		"nav-bottom": "Footer",
		"footer": "Footer"
	}
);

function mapSearchToGlobalLinks() {
	Mapping.storeNavLocationById("global");
}

addEvent(document, "readystatechange", function() {
	var globalLinks = document.getElementById("global");
	if (globalLinks) {
		var form = globalLinks.getElementsByTagName("form");
		if (form.length > 0) {
			addEvent(form[0], "submit", mapSearchToGlobalLinks);
		}
	}
});


addEvent(document, "click", MapLinks.handler);

/********************************************************************
 * AAM functions
 ********************************************************************/
function setClass(objId,newClass) { // a generic CSS class switcher. helps IE<7 mimic div:hover,td:hover, etc. (used on AAM)
	var obj = document.getElementById(objId);
	obj.className = newClass;
}

function setAAModel(currModel) {
	if (currModel == "model-curr-") { currModel = "model-curr-a"; }
	document.getElementById('model-curr-a').style.display = "none";
	document.getElementById('model-curr-a').style.position = "relative";
	document.getElementById('model-curr-b').style.display = "none";
	document.getElementById('model-curr-b').style.position = "relative";
	document.getElementById('model-curr-c').style.display = "none";
	document.getElementById('model-curr-c').style.position = "relative";
	document.getElementById('model-curr-d').style.display = "none";
	document.getElementById('model-curr-d').style.position = "relative";
	document.getElementById(currModel).style.display = "block";
	document.getElementById(currModel).style.position = "absolute";
	document.getElementById(currModel).style.top = "0";
}

/**********************************************************************
 * BROWSER BASELINE PAGE DETECTION Functions
 *********************************************************************/
var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
BrowserDetect.init();


 /* Set Browser Check Cookie */
function setbrowserCheckCookie() {
	var browserCheckCookie = new Cookie("browserCheck");
	browserCheckCookie.set("checked");
}

/* Browser Baseline Pardon Page Check */
if (!onDetectionPage) {
	if (onDetectionPage != true) {
		var onDetectionPage = false;
	}
}

function browserCheck() {
/* Set browser and version variables based on new browser detection script*/
var agent             = BrowserDetect.browser;
var version           = parseFloat(BrowserDetect.version);
var pardonLocation	  = '/content/pardons/browser-requirements-page.html';

/* Set list of our supported browsers and baseline versions (IE6, IE7, IE8, FF3.0, Safari 3+) */
/* Firefox users under 3.0 will not be pardoned */
var isFF			  = (agent.indexOf('Firefox')!=-1)
var isIE              = (agent.indexOf('Explorer') != -1)
var isSafari          = (agent.indexOf('Safari') != -1);

var ieBaseline        = (isIE && (version >= 6 && version <= 8));
var ffBaseline	      = (isFF && (version >= 1.5 && version < 4));
var safariBaseline    = (isSafari && (version >= 420));


	/* Redirect functions based on below browser check */
	function warning(){location.replace('/content/pardons/browser-requirements.html?referrer='+g_thisURL);};
	function proceed(){location.replace(g_thisURL);};


	/* Browers Checks, first check for detection cookie, then detects user's browser */
	if (!onDetectionPage) {
		if (!(cookieExists("browserCheck"))) {
			if      (isIE)      { (!ieBaseline)      ? warning() : setbrowserCheckCookie();}
			else if (isFF)	    { (!ffBaseline) 	 ? warning() : setbrowserCheckCookie();}
			else if (isSafari)  { (!safariBaseline)  ? warning() : setbrowserCheckCookie();}
			else                { warning() }
		}
	}
}
addEvent(document, "readystatechange", browserCheck);

/**
 * Utility methods
 */
var DataUtilities = (function() {
	
	//Privileged variables and methods
	var self = {
		"preventXSS": function(string) {
			return string.toString().replace(/\<|\>/g,"");
		},
		"processXML": function(xml) {
			if (typeof ActiveXObject === "function") {
				try {
					var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
					xmlDoc.loadXML(xml);
					xml = xmlDoc;
				}
				catch (err) {
					if (typeof console !== "undefined") {
						console.log("No data returned from the server. Error: " + err);	
					}
				}
			}
			else {
				try {
					xml = new DOMParser().parseFromString(xml, "text/xml");
				}
				catch(err) {
					if (typeof console !== "undefined") {
						console.log("No data returned from the server. Error: " + err);	
					}
				}
			}
			return xml;
		}
	};
	return self;
})();
