var betfair = {
	Config: {
		paths: {
			redirects: {masterAccount: "/account/login/LoginMaster.do"},
			secureCommunicationURL: "https://www."+document.domain+"/blank.jsp",
			nonSecureCommunicationURL: "http://www.betfair.com/blank.jsp",
			services: {
				login: {action: "https://www."+document.domain+"/account/login/LoginRequest.do"},
				limb: {action: "/account/login/GetJSONLoginMessages.do"},
				processLimb: {action: "https://www."+document.domain+"/account/login/ProcessJSONLoginMessages.do"},
				logout: {
					casino: {action: "http://site.casino."+document.domain+"/account/login/LogoutAction.do"},
					games: {action: "http://site.games."+document.domain+"/account/login/GamesLogoutAction.do"},
					site: {action: "/account/login/LogoutRequest.do"}
				},
				getUser: {action: "/account/api/getUser.do"},
				retrieveWallet: {action: "/wallet/LocalAccountSummaryWalletView.do"}
			},
			popupWindows: {
				singlesDomain: "http://uk.site."+document.domain+"/",
				portalDomain: null,
				contentURL: "http://content."+document.domain+"/",
				radioURL: "http://radio."+document.domain+"/",
				videoURL: "http://livevideo."+document.domain+"/",
				timeFormURL: "http://horseracing."+document.domain+"/form",
				domain: document.domain
			}
		},
		products: [
			{id:0, type:"DOMAIN", subdomain: document.domain},
			{id:1, type:"EXCH", subdomain:"uk.site.sports."+document.domain, wallet: { name:"主銀包：", secure:true }},
			{id:2, type:"EXCH", subdomain:"au.site.sports."+document.domain, wallet: { name:"澳洲電子錢包", secure:true }},
			{id:3, type:"MULT", subdomain:"site.multiples."+document.domain},
			{id:4, type:"CASI", subdomain:"site.casino."+document.domain, wallet: { name:"", secure:true }},
			{id:5, type:"GAMEX", subdomain:"site.games."+document.domain, wallet: { name:"", secure:true }},
			{id:7, type:"ORBIS", subdomain:"site.arcade."+document.domain}
		],
		application: {
			"productName": "portal"
		},
		defaults: {
			"standardDomain": document.domain,
			"contentDomain": "content."+document.domain,
			"regionId": "GBR",
			"localeId": "zh_TW",
			"brandId": "betfair",
			"productName": "www"
		}
	},
	Templates: {}
};

betfair.getNodeFromHtmlString = function(s) {
	var parent = document.createElement("div");
	parent.innerHTML = s;
	return parent.firstChild;
};

/* There's a bug in Safari 3.0 (based on webkit)
 * where
 *		Math.abs(0) gives -0
 * and
 *		(-0).toFixed(2) gives "0.-0"
 *
 * So Math.abs(size).toFixed(2) won't work
 */
betfair.formatCurrency = function(symbol, amount) {
	if (typeof (symbol) !== "string") {
		symbol = "";
	}
	if (typeof (amount) !== "number") {
		amount = 0;
	}

	var formattedAmount = amount;

	if(formattedAmount < 0) { formattedAmount = -formattedAmount; }

	formattedAmount = formattedAmount.toFixed(2);

	var parts = formattedAmount.split('.');
	var i, formatted = "";

	for(i = parts[0].length; i >= 0; i -= 3) {
		formatted = parts[0].substring(i-3, i) + formatted;
		if (i > 3) { formatted = ',' + formatted; }
	}
	return ((amount <= -0.01) ? "-" : "") + symbol + formatted + '.' + parts[1];
};

betfair.cssjs = function(action,obj,className1,className2) {
	try {
		var c1_regexp = new RegExp("\\b" + className1 + "\\b", 'g');
		if(typeof(obj) === "string") {
			obj = document.getElementById(obj);
		}

		switch(action){
			case 'swap':
				if(betfair.cssjs('check',obj,className1)) {
					obj.className = obj.className.replace(c1_regexp,className2);
				} else {
					obj.className = obj.className.replace(new RegExp("\\b" + className2 + "\\b"),className1);
				}
				break;
			case 'add':
				if(!obj.className) {
					obj.className = className1;
				} else if(obj.className.search(c1_regexp) == -1) {
					obj.className += " "+className1;
				}
				break;
			case 'remove':
				var newClassName = obj.className.replace(c1_regexp, '');
				if(obj.className != newClassName) {
					obj.className = newClassName;
				}
				break;
			case 'check':
				if((typeof className1 == "function")||(typeof className1 == "object")) {
					return className1.test(obj.className);
				} else {
					return c1_regexp.test(obj.className);
				}
				break;
			default:
				break;
		}
	}	catch(e) {
		console.debug("betfair.cssjs: error setting css class with params: action: " + action + " ,obj: ", obj, " ,className1: " + className1 + " ,className2: " + className2 + ". Exception: ", e);
	}
};

betfair.copyNodeListIntoArray = function(nl) {
	if(!nl || nl.length == null || nl.length === 0) return [];
	var newArray;
	//try to use the slice method to create a new array - most efficient
	try {
		newArray = Array.prototype.slice.call(nl, 0);
		if(newArray[0] == null) throw "";
	} catch(e) {
		newArray = [];
		for(var i = 0, j = nl.length; i < j; i++) {
			newArray.push(nl[i]);
		}
	}
	return newArray;
};

betfair.getElementsByClassName = function(rootElement, tagName, cssClass) {
	if (!rootElement) return [];
	var nodes = [];
	
	// bug in Webkit querySelectorAll may mean selector brings back zero and className brings back zero
	if (rootElement.querySelectorAll) {
		var query = "." + cssClass;
		if (typeof tagName === "string" && tagName !== "*") {
			query = tagName.toLowerCase() + query;
		}
		nodes = betfair.copyNodeListIntoArray(rootElement.querySelectorAll(query));
	} else if (rootElement.getElementsByClassName) {
		nodes = betfair.copyNodeListIntoArray(rootElement.getElementsByClassName(cssClass));
		if (typeof tagName === "string" && tagName !== "*") {
			tagName = tagName.toLowerCase();
			for (var i = nodes.length-1; i>=0; i--) {
				if (nodes[i].tagName.toLowerCase() !== tagName) {
					nodes.splice(i,1);
				}
			}
		}
	}
	
	// cross-browser most reliable method (but slow)
	if (nodes.length === 0) {
		var elements = rootElement.getElementsByTagName( typeof tagName === "string" ? tagName : "*" );
		var test = new RegExp("\\b" + cssClass + "\\b");
		for (var i = 0, length = elements.length; i < length; i += 1) {
			if (test.test(elements[i].className)) {
				nodes.push(elements[i]);
			}
		}
	}
	return nodes;
}

// prevent javascript console in Safari from going mental
if(!window.console || !console.firebug) {
	var names = [
		"log", "debug", "info", "warn",
		"error", "assert", "dir", "dirxml",
		"group", "groupEnd", "time", "timeEnd",
		"count", "trace", "profile", "profileEnd"
	];

	window.console = {};
	for(var i=0; i<names.length; ++i) {
		window.console[names[i]] = function() {};
	}
}

var betfair = betfair || {}; 
betfair.Events = {};
betfair.Events.customEvent = function() {
	var events = [];
	
	var eventHandler = (function() {
		var tempEvents,
			firing = false, eventsAdded = false, eventsRemoved = false;
			
		function startFire() {
			tempEvents = [];
			firing = true;
			eventsAdded = eventsRemoved = false;
			//sort the event handlers by the event indexes
			events.sort(function(a, b) {
				return a[2] === b[2] ? 0 : (a[2] < b[2] ? 1 : -1);
			});
		}
		
		function endFire() {
			if (eventsRemoved) {
				for (var i = events.length-1; i>=0; i--) {
					if (events[i] == null) {
						events.splice(i, 1);
					}
				}
			}
			if (eventsAdded) {
				for (var i = tempEvents.length-1; i>=0; i--) {
					events.push(tempEvents[i]);
				}
			}
			firing = false;
		}
		
		function getEventApplyArgs(args, newArg) {
			args.splice(args.length, 0, newArg); 
			return args;
		}
		
		return {
			firing: firing,
			fire: function() {
				startFire();
				var	returnVal = true, 
					funcReturnVal,
					i = 0, j = events.length,
					applyArguments;
				for (i; i < j; i++) {
					if (events[i] == null) continue;
					//handle calling the handler including the additional param that may be passed
					if (events[i][3]) {
						applyArguments = getEventApplyArgs(copyNodeListIntoArray(arguments, []), events[i][3]);
					} else {
						applyArguments = arguments;
					}
					//store the return value from each handler.  If any are false, set the master event return value to false
					funcReturnVal = events[i][0].apply(events[i][1] || this, applyArguments);
					if (returnVal && funcReturnVal === false) returnVal = false;
				}
				endFire();
				return returnVal;
			},
			addHandler: function(event) {
				eventsAdded = true;
				tempEvents.push(event);
			},
			removeHandler: function(i) {
				eventsRemoved = true;
				events[i] = null;
			},
			removeAllHandlers: function() {
				for (var i = events.length-1; i>=0; i--) {
					this.removeHandler(i);
				}
			}
		}
	})();
	
	this.addHandler = function(fn, context, sortIndex, param) {
		var event = [fn, context, sortIndex || 99, param];
		if (eventHandler.firing) {
			eventHandler.addHandler(event);
		} else {
			events.push(event);
		}
		return fn;
	};
	this.removeHandler = function(fn) {
		//the event handler may have been added multiple times hence loop through complete array
		for (var i = events.length - 1; i >= 0; i--) {
			if (events[i][0] === fn) {
				if (eventHandler.firing) {
					eventHandler.removeHandler(i);
				} else {
					events.splice(i, 1);
				}
			}
		}
	};
	this.removeAllHandlers = function() {
		if (eventHandler.firing) {
			eventHandler.removeAllHandlers();
		} else {
			events = [];
		}
	};
	this.fire = function() {
		return eventHandler.fire.apply(this, arguments);
	};
};

/*
listeners takes the format:
	{
		DOM: [
			{
				id: id of element (overrides element property),
				element: id or ref to elements,
				eventType: "click",
				handler: function ref,
				context: this,
				sortIndex: 99,
				param: a parameter of any type to pass to the handler
			}
		],
		custom: [
			{
				event: betfair.Events.type.name,
				handler: function ref,
				context: this,
				sortIndex: 99,
				param: a parameter of any type to pass to the handler
			}
		]
	}
*/
betfair.Events.delegate = function(listeners, registerOnConstructor) {

	listeners = listeners || {DOM:[], custom:[]};
	if (!listeners.DOM) listeners.DOM = [];
	if (!listeners.custom) listeners.custom = [];

	this.addListeners = function(newListeners, autoRegister) {
		if (newListeners.DOM && newListeners.DOM instanceof Array) {
			listeners.DOM = listeners.DOM.concat(newListeners.DOM);
		}
		if (newListeners.custom && newListeners.custom instanceof Array) {
			listeners.custom = listeners.custom.concat(newListeners.custom);
		}
		if (autoRegister === true) this.registerAllListeners();
	};

	this.registerAllListeners = function() {
		this.registerDOMListeners();
		this.registerCustomEventListeners();
	};
	this.registerDOMListeners = function() {
		var domListeners = listeners.DOM;
		if (domListeners == null) return;
		for (var i = domListeners.length-1; i>=0; i--) {
			if (domListeners[i].registered && domListeners[i].registered === true) continue;
			registerDOMListener(domListeners[i]);
		}
	};
	this.registerCustomEventListeners = function() {
		var customListeners = listeners.custom;
		if (customListeners == null) return;
		for (var i = customListeners.length-1; i>=0; i--) {
			if (customListeners[i].registered === true) continue;
			registerCustomEventListener(customListeners[i]);
		}
	};

	this.unRegisterAllListeners = function() {
		this.unRegisterDOMListeners();
		this.unRegisterCustomEventListeners();
	};
	this.unRegisterDOMListeners = function() {
		var domListeners = listeners.DOM;
		if (domListeners == null) return;
		for (var i = domListeners.length-1; i>=0; i--) {
			if (domListeners[i].registered !== true) continue;
			unRegisterDOMListener(domListeners[i]);
		}
	};
	this.unRegisterCustomEventListeners = function() {
		var customListeners = listeners.custom;
		if (customListeners == null) return;
		for (var i = customListeners.length-1; i>=0; i--) {
			if (customListeners[i].registered !== true) continue;
			unRegisterCustomEventListener(customListeners[i]);
		}
	};

	this.unRegisterSpecificDOMListener = function(listener) {
		var domListeners = listeners.DOM;
		if (domListeners == null) return;
		listener.element = typeof(listener.element) === "object" ? listener.element : document.getElementById(listener.id || listener.element);
		for (var i = domListeners.length-1; i>=0; i--) {
			if (domListeners[i].element != null &&
				domListeners[i].element === listener.element &&
				domListeners[i].eventType === listener.eventType &&
				domListeners[i].eventHandler === listener.eventHandler)
			{
				unRegisterDOMListener(domListeners[i]);
				break;
			}
		}
	};

	this.unRegisterSpecificCustomEventListener = function(listener) {
		var customListeners = listeners.custom;
		if (customListeners == null) return;
		for (var i = customListeners.length-1; i>=0; i--) {
			if (customListeners[i].event === listener.event && customListeners[i].handler === listener.handler) {
				unRegisterCustomEventListener(customListeners[i]);
				break;
			}
		}
	}

	this.unRegisterDOMListenerGroup = function(listeners) {
		for (var i = listeners.length-1; i>=0; i--) {
			this.unRegisterSpecificDOMListener(listeners[i]);
		}
	}

	this.unRegisterCustomEventListenerGroup = function(listeners) {
		for (var i = listeners.length-1; i>=0; i--) {
			this.unRegisterSpecificCustomEventListener(listeners[i]);
		}
	}

	if (registerOnConstructor === true) this.registerAllListeners();

	function registerDOMListener(listener) {
		if (listener.attemptedRegister !== true) {
			if (listener.id || typeof(listener.element) === "string") {
				listener.element = document.getElementById(listener.id || listener.element);
			}
			if (!listener.element || listener.element == null) {
				return;
			}
			listener.attemptedRegister = true;
		}
		if (listener.registered !== true) {
			betfair.Events.DOM.addEvent(listener.element, listener.eventType, listener.handler, listener.context, listener.sortIndex, listener.param);
		}
		listener.registered = true;
	}
	function registerCustomEventListener(listener) {
		listener.attemptedRegister = true;
		if (listener.registered !== true) {
			listener.event.addHandler(listener.handler, listener.context, listener.sortIndex, listener.param);
		}
		listener.registered = true;
	}
	function unRegisterDOMListener(listener) {
		betfair.Events.DOM.removeEvent(listener.element, listener.eventType, listener.handler);
		listener.registered = listener.attemptedRegister = false;
	}
	function unRegisterCustomEventListener(listener) {
		if (listener.attemptedRegister === true && listener.registered === true) {
			listener.event.removeHandler(listener.handler);
			listener.registered = false;
		}
	}
};
betfair.Events.delegate.general = (function() {

	var eventsDelegate = new betfair.Events.delegate();

	return {
		DOM: {
			addListener: function(listener) {
				if (!(listener instanceof Array)) {
					listener = [listener];
				}
				eventsDelegate.addListeners( {DOM: listener}, true );
			},
			removeListener: function(listener) {
				if (!(listener instanceof Array)) {
					listener = [listener];
				}
				for (var i = listener.length-1; i>=0; i--) {
					eventsDelegate.unRegisterDOMListenerGroup(listener);
				}
			},
			purgeHandlers: function(el, purgeChildNodes, type) {
				betfair.Events.DOM.purgeHandlers(el, purgeChildNodes, type);
			}
		},
		custom: {
			addListener: function(listener) {
				if (!(listener instanceof Array)) {
					listener = [listener];
				}
				eventsDelegate.addListeners( {custom: listener}, true );
			}
		}
	}
})();
betfair.Events.DOM = (function() {
	var regExs = {
		key: /key/,
		click: /click/i,
		mouse: /mouse/i,
		menu: /menu/i,
		over: /over/i,
		out: /out/i,
		DOMMouseScroll: /DOMMouseScroll|mousewheel/
	};
	var handler = function() {
		var eventHandler = new betfair.Events.customEvent();
		var oldFire = eventHandler.fire;
		eventHandler.fire = function(e) {
			//normalise the event object for browser compatability
			e = e || event;
			e.sourceNode = (e.target || e.srcElement) || null;
			if (regExs.key.test(e.type))
				e.keyPressed = (e.which || e.keyCode) || null;
			if (regExs.click.test(e.type) || regExs.mouse.test(e.type) || regExs.menu.test(e.type)) {
				e.mouse = {
					x: e.pageX || e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
					y: e.pageY || e.clientY + document.body.scrollTop + document.documentElement.scrollTop
				};
			}
			if (regExs.over.test(e.type))
				if (!e.relatedTarget && e.fromElement) e.relatedTarget = e.fromElement;
			if (regExs.out.test(e.type))
				if (!e.relatedTarget && e.toElement) e.relatedTarget = e.toElement;
			if (regExs.DOMMouseScroll.test(e.type))
				e.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
			e.rightClick = (e.which == 3) || (e.button == 2);
			if (!e.stopPropagation) {
				e.stopPropagation = function() {
					this.cancelBubble = true;
				};
			}
			if (!e.preventDefault) {
				e.preventDefault = function() {
					this.returnValue = false;
				};
			}
			e.stop = function() {
				this.preventDefault();
				this.stopPropagation();
			}
			//call the old fire method
			return oldFire.call(this, e);
		};
		return eventHandler;
	};
	function setupDomContentLoaded() {
		/*@cc_on @*/
		/*@if (@_jscript_version < 5.8)
		document.write("<script id=\"ieScriptLoad\" defer src=\"//:\"><\/script>");
		document.getElementById("ieScriptLoad").onreadystatechange = function() {
			if (this.readyState === "complete") {
				betfair.Events.DOM.fire(window, "DOMContentLoaded");
				setTimeout( function() {document.getElementById("ieScriptLoad").parentNode.removeChild(document.getElementById("ieScriptLoad"));}, 200);
			}
		};
		@else @*/
		if (navigator.userAgent.search(/WebKit/i) !== -1) {
			window.DOMLoadTimer = setInterval(function () {
				if (document.readyState.search(/loaded|complete/i) !== -1) {
					clearInterval(window.DOMLoadTimer);
					betfair.Events.DOM.fire(window, "DOMContentLoaded");
				}
			}, 10);
		} 
		if (document.addEventListener) {
			document.addEventListener("DOMContentLoaded", function(e) {clearInterval(window.DOMLoadTimer);betfair.Events.DOM.fire(window, "DOMContentLoaded");}, false);
		} else {
			betfair.Events.DOM.addEvent( window, "load", function() {betfair.Events.DOM.fire(window, "DOMContentLoaded");}, 1000 );
		}
		/*@end @*/
		setupDomContentLoaded = function() {};
	}
	
	return {
		addEvent: function(el, type, fn, context, sortIndex, param) {
			if (typeof fn !== "function") return;
			if (el === window && type === "DOMContentLoaded") {
				setupDomContentLoaded();
			}
			if (el.callBackWhenThisReadyState && type === "readystatechange") {
				el.fnCallback = fn;
				fn = function() {
					if (el.readyState === el.callBackWhenThisReadyState) {
						setTimeout(el.fnCallback, 200);
					}
				};
			}
			if (!el.events) el.events = {};
			if (!el.events[type]) {
				el.events[type] = new handler();
				el["on" + type] = el.events[type].fire;
			}
			el.events[type].addHandler(fn, context, sortIndex, param);
			return fn;
		},
		removeEvent: function(el, type, fn) {
			var events = el.events;
			if (events && events[type] instanceof betfair.Events.customEvent)
				events[type].removeHandler(fn);
		},
		fire: function(el, type) {
			var events = el.events;
			if (events && events[type]) {
				events[type].fire({});
			}
		},
		purgeHandlers: function(el, purgeChildNodes, type) {
			var events = typeof type === "string" ? el.events && el.events[type] : el.events;
			if (!events) return;
			if (events instanceof betfair.Events.customEvent) {
				events.removeAllHandlers();
			} else {
				for (var t in events) {
					if (events[t] instanceof betfair.Events.customEvent) {
						events[t].removeAllHandlers();
					}
				}
			}
			if (purgeChildNodes === true) {
				var children = el.getElementsByTagName("*");
				for (var i = children.length-1; i>=0; i--) {
					this.purgeHandlers(children[i], false, type);
				}
			}
		}
	};
})();

betfair.Events.custom = {
	LIMB: {
		startLoading: new betfair.Events.customEvent(),
		unloaded: new betfair.Events.customEvent()
	},
	User: {
		loginState: {
			loggedIn: new betfair.Events.customEvent(),
			limbo: new betfair.Events.customEvent(),
			loggingOut: new betfair.Events.customEvent(),
			loggedOut: new betfair.Events.customEvent()
		}
	}
};
betfair.Cache = function(config) {
	var cache = {};

	this.id = (config && config.cacheId) ? config.cacheId : "global";

	this.getCache = function() {
		return cache;
	};

	this.contains = function(id) {
		return cache[id] ? true : false;
	};

	this.get = function(id, returnObj) {
		var obj = {}, val = cache[id];
		obj[id] = val;
		if(val) return returnObj?obj:val;
	};

	this.getMulti = function(l) {
		var a = [];
		for (var k in l) {
			a.push(this.get(l[k]));
		}
		return a;
	};

	this.getType = function(t){
		var a = [];
		for (var o in cache) {
			if(typeof(cache[o])==t) {
				a.push(this.get(o));
			}
		}
		return a;
	};

	this.getMultiType = function(l) {
		var a = [];
		for (var t in l) {
			for (var o in cache) {
				if(typeof(cache[o])==l[t]) {
					a.push(this.get(o));
				}
			}
		}
		return a;
	};

	this.setMulti = function(elementIds) {
		var element;
		for(i=0,len=elementIds.length; i<len; i+=1) {
			element = document.getElementById(elementIds[i]);
			if(!element) { continue; }
			this.set(element.id, element);
		}
	}

	this.set = function(n,v) {
		if(cache[n]) { delete(cache[n]); }
		cache[n]=v;
		if (arguments[2]) {
			var ttl = arguments[2].ttl || null;
			if(ttl) {
				var self = this,
					to = setTimeout(function() {
							self.remove(n);
						}, ttl);
			}
			return (cache[n])?1:0;
		}
	};

	this.add = function(n,v) {
		if(!cache[n]) {
			cache[n]=v;
			if (arguments[2]) {
				var ttl = arguments[2].ttl || null;
				if(ttl) {
					var self = this,
						to = setTimeout(function() {
								self.remove(n);
							}, ttl);
				}
			}
			return (cache[n])?1:0;
		}
	};

	this.replace = function(n,v) {
		if(cache[n]){
			delete(cache[n]);
			cache[n]=v;
			if (arguments[2]){
				var ttl = arguments[2].ttl || null;
				if(ttl) {
					var self = this,
						to = setTimeout(function() {
							self.remove(n);
						}, ttl);
				}
			}
			return (cache[n])?1:0;
		}
	};

	this.remove = function(n) {
		delete(cache[n]);
		return (!cache[n])?1:0;
	};

	this.invalidate = function() {
		for(k in cache) {
			delete(cache[k]);
		}
		return 1;
	};
};

betfair.JSON = (function(){
	var leafNode = (function() {
		//	method: get
		//	Purpose: Attempts to return a value from a primative object [json]
		//	Arguments:
		//		rootNode: the root node
		//		leafNodeKey: the path to the value using .notation
		function get(rootNode, leafNodeKey) {
			var tmpNode = rootNode;
			var leafNodeKeyTokens = leafNodeKey.split(".");
			var i, len = leafNodeKeyTokens.length;

			var nodeExists = true;
			var rtn = null;

			for(i=0; i<len; i++) {
				tmpNode = tmpNode[leafNodeKeyTokens[i]];
				if(tmpNode == null) {
					nodeExists = false;
				}
			}
			if(nodeExists) {
				rtn = tmpNode;
			}
			return rtn;
		}

		//	method: set
		//	Purpose: Sets a value into a primative [json] object at a particular keypoint
		//	Arguments:
		//		rootNode: the root node
		//		leafNodeKey: the path to the value's key using .notation
		//		leafNodeValue: the value to set into the leafNodeKey [this can be object]
		function set(rootNode, leafNodeKey, leafNodeValue) {
			var tmpNode = rootNode;
			var leafNodeKeyTokens = leafNodeKey.split(".");
			var i, len = leafNodeKeyTokens.length;
			for(i=0; i<len; i++) {
				if(i < len-1) {
					if(typeof tmpNode[leafNodeKeyTokens[i]] === "undefined") {
						tmpNode[leafNodeKeyTokens[i]] = {};
					}
					tmpNode = tmpNode[leafNodeKeyTokens[i]];
				} else {
					tmpNode[leafNodeKeyTokens[i]] = leafNodeValue;
				}
			}
		}

		return {
			get: get,
			set: set
		};
	})();
	
	function stripScripts(htmlStr) {
		var scriptFragment = '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)';
		return htmlStr.replace(new RegExp(scriptFragment, 'img'), '');
	}

	function evalJSON(json) {
		var obj = {};
		if(!json) { return obj; }
		json = json.toString().replace(/^\s\s*/, '').replace(/\s\s*$/, '');
		json = stripScripts(json);
		if(json.length > 0) { 
			try {
				obj = eval("("+json+")");				
			} catch (e) { 		
				// squash any exceptions caused by bad URLs [404 response html]
			}
		}
		return obj;
	}

	return {
		leafNode: leafNode,
		eval: evalJSON
	};
})();
betfair.AJAX = function(options) {
	var timeoutLength = 12000;
	var requestObj = null;
	var requestDetails = { method: "get" };
	var timeout = null;
	var failed = false;
	var me = this;

	/* allow the passing in of an object literal */
	if (typeof options == "object") {
		requestDetails.URL = options.URL || null;
		requestDetails.method = options.method || requestDetails["method"];
		requestDetails.onSuccess = (typeof options.onSuccess == "function") ? options.onSuccess : null;
		requestDetails.onFail = (typeof options.onFail == "function") ? options.onFail : null;
		requestDetails.scope = (typeof options.scope == "object") ? options.scope : null;
		requestDetails.timeoutLength = options.timeoutLength || timeoutLength;
		if ( options.headers instanceof Array ) {
			for (var i = options.headers.length-1; i>=0; i--)
				addRequestHeader( options.headers[i][0] || options.headers[i]["key"] || null, options.headers[i][1] || options.headers[i]["value"] || null );
		}
	}

	function addRequestHeader(key, value) {
		if (key != null && value != null) {
			requestDetails.requestHeaders = requestDetails.requestHeaders || {};
			requestDetails.requestHeaders[key] = value;
		}
	}
	this.send = function(data) {
		//reset the failed notifier
		failed = false;
		//check that a URL has been specified
		if (requestDetails.URL == null || requestDetails.URL == "")
			return false;
		//check for data and if not provided, set to the empty string
		if (arguments.length < 1 || data == null)
			data = "";
		//get an XMLHttpRequest object
		requestObj = requestObj || this.getRequestObject();
		//open the request
		requestObj.open(requestDetails.method, requestDetails.URL, true);
		//set the correct encoding type for post requests
		if (requestDetails.method.toLowerCase() == "post")
			requestObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		//add the supplied headers to the request
		for (var key in requestDetails.requestHeaders)
			requestObj.setRequestHeader(key, requestDetails.requestHeaders[key]);
		//set the onreadystatechange handler
		requestObj.onreadystatechange = this.handleReadyStateChange;
		//initiate the timeout for handling request timeouts
		timeout = setTimeout(this.handleTimeout, requestDetails.timeoutLength);
		//send the request
		requestObj.send(data);

		return true;
	};
	this.close = function() {
		requestObj.abort();
	};
	this.handleTimeout = function() {
		me.clearTimeout();
		if (typeof requestDetails.onFail == "function") {
			failed = true;
			me.close();
			fail(betfair.AJAX.FailureCodes.timeout);
		}
	};
	this.clearTimeout = function() {
		clearTimeout(timeout);
	};
	//fail the request with the given fail code or with a general error if none is supplied
	function fail(failCode) {
		failed = true;
		requestDetails.onFail.call( requestDetails.scope || requestDetails.onFail, me, failCode || betfair.AJAX.FailureCodes.general );
	}
	this.handleReadyStateChange = function() {
		//if the request has already failed, dont bother going any further
		if (failed == true) return;
		//if the response has arrived
		if (requestObj.readyState == 4) {
			//clear the timeout to avoid firing a timeout error
			me.clearTimeout();
			//if the request has returned OK
			if (requestObj.status == 200) {
				//if a success handler has been provided, call it now and pass back in the AJAX object
				if (typeof requestDetails.onSuccess == "function")
					requestDetails.onSuccess.call( requestDetails.scope || requestDetails.onSuccess, me );
			} else {
				//set the failed notifier
				failed = true;
				//if a fail handler has been provided, call it
				if (typeof requestDetails.onFail == "function") {
					var status = requestObj.status;
					var failureCode = betfair.AJAX.FailureCodes.general;
					//calculate if a fail code matches the status of the request
					for (var failType in betfair.AJAX.FailureCodes) {
						if (betfair.AJAX.FailureCodes[failType] == status) {
							failureCode = betfair.AJAX.FailureCodes[failType];
							break;
						}
					}
					fail(failureCode);
				}
			}
		}
	};
	this.getResponseHeader = function(headerName) {
		return requestObj.getResponseHeader(headerName);
	};
	this.getAllResponseHeaders = function() {
		return requestObj.getAllResponseHeaders();
	};
	this.getResponseText = function() {
		return requestObj.responseText;
	};
	this.getResponseXML = function() {
		return requestObj.responseXML;
	};
	this.getUrl = function() {
		return requestDetails.URL;
	};
};

betfair.AJAX.prototype.getRequestObject = function() {
	betfair.AJAX.supported = true;
	if (typeof XMLHttpRequest != "undefined" && typeof XMLHttpRequest != null) {
		return function() {
			return new XMLHttpRequest();
		};
	} else if (window.ActiveXObject) {
		return function() {
			return new ActiveXObject("Microsoft.XMLHTTP");
		};
	} else {
		betfair.AJAX.supported = false;
		return function() {
			return null;
		};
	}
} ();

betfair.AJAX.FailureCodes = {
	general: "xx1",
	unauthorised: 401,
	notFound: 404,
	timeout: 408,
	server: 500
};

betfair.messages = {
	error: {
		"Global.NoCookies": "您流覽器中的存儲記憶程式（Cookies）似乎沒有啟動。我們的網站在Cookies啟用狀態下功效最好。請啟動Cookies。"
	},
	login: {
		failure: {
			"Frontpage.Login.Error.No.User.Name.Password": "請確定輸入以下資料:\n您的用戶名稱\n您的密碼.",
			"Login.Error.Message": "用戶名稱或密碼不符 - 請再試.\n 請記住, 用戶名稱或密碼要區分大小寫!\n查看鍵盤上的'大小寫'按鍵",
			"Login.Account.Locked": "為確保安全的理由, 閣下的戶口已被凍結. 這是因為閣下連續輸入六次錯誤的密碼.\n 為安全起見,請致電我們的客戶服務部熱線來重新開啟您的戶口.",
			"Login.Account.Already.Locked": "為確保安全的理由, 閣下的戶口已被凍結. 這是因為閣下連續輸入六次錯誤的密碼.\n 為安全起見,請致電我們的客戶服務部熱線來重新開啟您的戶口.",
			"Login.Error.Account.Excluded": "出於本公司博彩負責條例規定﹐您的戶口暫時\n不能使用。\n如有任何問題﹐請聯絡客戶服務部。",
			"Login.Restricted.Location.Message": "You may not access this account from this location.",
			"Login.Security.Restricted.Message": "無法登入。請聯絡必發客戶服務部: asian@betfair.com",
			"Login.Account.Betting.Restricted.Location": "我們的軟體測試出您可能正在從一個必發不接受下注的國家進入必發網站。如果您認為此測試結果是錯誤的請聯繫客戶服務部以獲取更多幫助。",
			"Forgotten.Password.Account.Canceled.Message": "拒絕登入此帳戶 – 帳戶已關閉。如有任何問題，請聯絡客戶服務部。"
		},
		suspended: {
			"Login.Suspended.Message": "您的戶口已被暫停.\n\n您只可以修改戶口簡檔. 戶口的其它功能已被刪除.\n\n如獲詳情請聯絡必發客戶服務部\n(電郵地址: asian@betfair.com or 電話: <br>英國境內免費電話熱線 0800 358 8833<br>馬來西亞免費電話熱線 1800 808 188<br>中國大陸免費電話熱線 10800 120 1293<br>由其他地區請打 +44 20 8834 8065)"
		}
	},
	logout: {
		"Current.Bets.View.Unmatched.Bets.Confirmation": "您是否決定登出﹖",
		"Current.Bets.View.Unmatched.Bets.Instructions": "點擊‘確定’登出或‘取消’參閱您的未成交訂單。",
		"Current.Bets.View.Unmatched.Bets.UK": "在英國交易裡您還有未成交訂單。",
		"Current.Bets.View.Unmatched.Bets.AUS": "在澳洲交易裡您還有未成交訂單。",
		"Current.Bets.View.Unmatched.Bets.Intl": "您有未成交的押注。"
	},
	account: {
		"Async.Field.Loading": "裝載中"
	}
};

// Navigation must be before Account
betfair.Navigation = (function(){
	var cache = new betfair.Cache({cacheId:("betfair.Navigation")});

	var UIStateHandlers = {
		loggedIn: function() {
			betfair.cssjs("add", cache.get("navigation"), "authenticated");
		},
		limbo: function() {
		},
		loggingOut: function() {
		},
		loggedOut: function() {
			betfair.cssjs("remove", cache.get("navigation"), "authenticated");
		}
	};

	var	events = {
			DOM: [
				{ element: window, eventType: "DOMContentLoaded", handler: initialiseCache },
				{ element: window, eventType: "load", handler: initialiseManagedWindowLinks }
			],
			custom: [
				{ event: betfair.Events.custom.User.loginState.loggedIn, handler: UIStateHandlers.loggedIn }
				,{ event: betfair.Events.custom.User.loginState.limbo, handler: UIStateHandlers.limbo }
				,{ event: betfair.Events.custom.User.loginState.loggingOut, handler: UIStateHandlers.loggingOut }
				,{ event: betfair.Events.custom.User.loginState.loggedOut, handler: UIStateHandlers.loggedOut }
			]
		};
	var eventHandler = new betfair.Events.delegate(events, true);

	function initialiseManagedWindowLinks() {
		// Links that are to be opened in a new window should be assigned the 'managedWindow' class.
		var els = betfair.getElementsByClassName(document.getElementById("site_frame"), "A", "managedWindow", false, true);
		var i, len;
		var events = {
			DOM: [{ element: "help", eventType: "click", handler: handleHelp}]
		};
		// cssProperties are of the form: name(value)
		var cssPropertyRegex = /(\w+)\(([\w\d]*)\)/gi;
		for(i=0, len=els.length; i<len; i+=1) {
			var currentClass = els[i].className;
			if(cssPropertyRegex.test(currentClass)) {
				var cssPropertyContainer = els[i].cssProperties = {
					"cssProperties": true
				};

				// as test has succeeded, we can rely on the match succeeding
				var matched = currentClass.match(cssPropertyRegex);

				var cssPropertyId, cssProperty, nameValuePair;
				for(cssPropertyId=matched.length-1; cssPropertyId>=0, cssProperty=matched[cssPropertyId]; cssPropertyId-=1) {
					cssPropertyRegex.lastIndex = 0;
					nameValuePair = cssPropertyRegex.exec(cssProperty);
					cssPropertyContainer["" + nameValuePair[1]] = nameValuePair[2];
				}
			}
			events.DOM.push( { element: els[i], eventType: "click", handler: handleManagedWindowLinkClick, context: els[i] } );
		}
		eventHandler.addListeners( events, true );
	}
	function initialiseCache() {
		var elementIds = [
			"navigation"
		];

		cache.setMulti(elementIds);
	}

	function handleManagedWindowLinkClick(e) {
		e.stop();
		betfair.WindowManager.openProgressive(this.target, this.href, this.cssProperties);
	}

	function handleHelp() {
		betfair.WindowManager.open('help', 'GHL');
	}

	return {};
})();
betfair.Navigation.localisationSelection = (function() {
	var events = {
			DOM: [{ element: window, eventType: "DOMContentLoaded", handler: initialise}]
		},
		eventHandler = new betfair.Events.delegate(events, true),
		localisationSelect = null;

	var urlChars = {
		hash: '#',
		amp:  '&',
		mark: '?',
		slash: '/',
		prefix: 'pi.' // typically
	};

	var useNewLocaleUrls = true;

	function initialise() {
		localisationSelect = document.getElementById("languageSelector");
		if (!localisationSelect) { return; }
		//  based on page rendering (new URL construct via CMS) - deprecated
		//setSelectedLanguageOption();

		//register other handlers
		eventHandler.addListeners( {
			DOM: [{ element: localisationSelect, eventType: "change", handler: handleLocalisationSelection }]
		}, true );
	}

	function setSelectedLanguageOption() {
		if (!localisationSelect) { return; }
		var localisationSelection = betfair.Config.defaults.localeId + "," + betfair.Config.defaults.regionId;
		var localisationSelectOptions = localisationSelect.options;
		var idx, len = localisationSelectOptions.length, currentOption;
		for (idx = 0; idx < len; idx += 1) {
			currentOption=localisationSelectOptions[idx];
			if(currentOption.value === localisationSelection) {
				currentOption.selected = true;
				break;
			}
		}
	}

	function handleLocalisationSelection(e) {
		var target = e.sourceNode;
		var value = target.options[target.selectedIndex].value;
		if (!value || value === "" || !value.match(/,/)) { return; }

		var splits = value.split(",");
		if (splits.length != 2) { return; }

		setAllCookies(splits[0], splits[1]);
		loadPage(splits[0], splits[1]);
	}

	function setAllCookies(localeId, regionId) {
		setLocRegCookieValues('&', localeId, regionId, "TrackingTags", "pi.localeId", "pi.regionId", "target=portal", 1, false);
	}

	function setLocRegCookieValues(token, localeId, regionId, cookieName, localeVariableName, regionVariableName, extra, persistence, encode) {
		// data validation: must not set cookie
		if (typeof (token) !== "string" || token === "") { return; }
		if (typeof (cookieName) !== "string" || cookieName === "") { return; }
		if (typeof (localeId) !== "string" || localeId === "") { return; }
		if (typeof (regionId) !== "string" || regionId === "") { return; }
		if (typeof (localeVariableName) !== "string" || localeVariableName === "") { return; }
		if (typeof (regionVariableName) !== "string" || regionVariableName === "") { return; }
		// data validation: allowed to set cookie
		if (typeof (extra) !== "string") { extra = ""; }
		if (typeof (persistence) !== "number") { persistence = null; } // sets to 1 year in CookieManager
		if (typeof (encode) !== "boolean") { encode = true; }

		var cookie = betfair.CookieManager.get(cookieName);
		if (cookie === null || cookie === "null" || cookie == "" || typeof (cookie) === "undefined") {
			cookie = "";
		}
		var cookieSplits = cookie.split(token),
			i, length = cookieSplits.length,
			values = [], regex = new RegExp(localeVariableName + "|"+ regionVariableName);


		for (i = 0; i < length; i += 1) {
			if (!regex.test(cookieSplits[i]) && cookieSplits[i] !== "") {
				values.push(cookieSplits[i]);
			}
		}

		values.push(localeVariableName+"="+localeId, regionVariableName+"="+regionId);
		if (extra !== "") { values.push(extra); }
		betfair.CookieManager.set(cookieName, values.join(token), persistence, null, encode, true);
	}

	function loadPage(localeId, regionId) {
		if (localeId === "" || regionId === "") { return; }

		function loadPageLegacyURLparameters(qStringArr, url, localeId, regionId, hashPart) {
			if (!url || !localeId || !regionId || !qStringArr) { return; }
			if (localeId) { qStringArr.push(urlChars.prefix + "localeId=" + localeId); }
			if (regionId) { qStringArr.push(urlChars.prefix + "regionId=" + regionId); }

			// re-add localeId and regionId to existing qstring params
			var newUrl = [url];
			if (qStringArr.length > 0) { newUrl.push(urlChars.mark, qStringArr.join(urlChars.amp));	}
			if (hashPart) {	newUrl.push(hashPart); }
			top.location = newUrl.join("");
		}

		function loadPageNewURLslashes(qStringArr, url, localeId, regionId, hashPart) {
			if (!url || !localeId || !regionId || !qStringArr) { return; }

			// Work-around for SPR-1210
			if (betfair.User && betfair.User.getLoginState() === "loggedIn") {
				if (localeId) { qStringArr.push(urlChars.prefix + "localeId=" + localeId); }
				if (regionId) { qStringArr.push(urlChars.prefix + "regionId=" + regionId); }
				qStringArr.push("rnd=" + new Date().getTime());
			}

			var slashParts = [];
			if (regionId === "GBR") {
				slashParts.push(localeId === "en_GB" ? "en" : localeId);
			} else {
				slashParts.push(regionId);
				if (localeId !== "en") {
					slashParts.push(localeId);
				}
			}

			// strip down current URL
			url = url.replace(/\/$/,"").replace("\/"+betfair.Config.defaults.regionId,"").replace("\/"+betfair.Config.defaults.localeId,"");
			var newUrl = [url];

			// add locale and region to slash part of URL, and keep any qstring params
			if (slashParts.length > 0) { newUrl.push(urlChars.slash, slashParts.join('/')); }
			newUrl.push(urlChars.slash); // ending slash
			if (qStringArr.length > 0) { newUrl.push(urlChars.mark, qStringArr.join(urlChars.amp)); }
			if (hashPart) {	newUrl.push(hashPart); }
			top.location = newUrl.join("");
		}

		var redirectionFunction = (useNewLocaleUrls) ? loadPageNewURLslashes : loadPageLegacyURLparameters;

		var hashPart = "";
		var hashSplits = top.location.href.split(urlChars.hash);
		if (hashSplits.length == 0) { return; }
		if (hashSplits.length == 2) { hashPart = urlChars.hash + hashSplits[1]; }

		var URLSplits = hashSplits[0].split(urlChars.mark);
		if (URLSplits.length == 0) { return; }
		if (URLSplits.length > 2) {
			var newURLSplits = [], i, length = URLSplits.length;
			for (i = 1; i < length; i += 1) { // start i at 1
				newURLSplits.push(URLSplits[i]);
			}
			URLSplits = [URLSplits[0], newURLSplits.join(urlChars.amp)];
		}
		if (URLSplits.length === 2) {
			var i, matches, newQStringArr = [], qStringSplits = URLSplits[1].split(urlChars.amp);
			for (i in qStringSplits) {
				matches = qStringSplits[i].match(/(\w+\.?)?(localeId|regionId)/);
				if (matches && matches.length === 3 && (matches[2] && matches[2].match(/localeId|regionId/))) {
					urlChars.prefix = matches[1] ? matches[1] : urlChars.prefix;
					continue; //remove only localeId or regionId params
				}
				if (qStringSplits[i].match(/^rnd=/)) {
					continue;
				}
				newQStringArr.push(qStringSplits[i]);
			}
			redirectionFunction(newQStringArr, URLSplits[0], localeId, regionId, hashPart);
		} else {
			redirectionFunction([], URLSplits[0], localeId, regionId, hashPart);
		}
	}
})();
betfair.Navigation.startPageSelection = (function() {
	var	events = {
			DOM: [
				{ element: window, eventType: "DOMContentLoaded", handler: initialise}
			],
			custom: [
				{ event: betfair.Events.custom.LIMB.startLoading, handler: handleLIMBLoad },
				{ event: betfair.Events.custom.LIMB.unloaded, handler: handleLIMBUnLoad }
			]
		};
	var eventHandler = new betfair.Events.delegate(events, true);
	var	startPageSelect = null;

	function getDOMElement() {
		if (startPageSelect === null) {
			startPageSelect = document.getElementById("startPage");
		}
	}

	function initialise() {

		getDOMElement();

		setCurrentPage();

		//register other handlers
		eventHandler.addListeners( {
			DOM: [{ element: startPageSelect, eventType: "change", handler: handleStartPageSelection }]
		}, true );

	}

	function setCurrentPage() {
		var userHistoryCookie = betfair.CookieManager.get("userhistory");
		var valueTokens = userHistoryCookie.split("|");
		if(valueTokens.length >= 6) {
			var startPageElOptions = startPageSelect.options;
			var idx, len = startPageElOptions.length, currentOption, startPageSelection = valueTokens[5];
			if (startPageSelection === "home") { startPageSelection = "-1"; } // force first option selected
			for(idx = 0; idx < len; idx += 1) {
				currentOption=startPageElOptions[idx];
				if(currentOption.value === startPageSelection) {
					currentOption.selected = true;
					break;
				}
			}
		}
	}

	function handleStartPageSelection(e) {
		var target = e.sourceNode;
		var value = target.options[target.selectedIndex].value;
		if (value === "-1") { return; }

		var cookie = betfair.CookieManager.get("userhistory");
		var valueTokens = cookie.split("|");
		// compatibility if other apps URLEncode the userhistory cookie
		if (valueTokens.length === 1) {
			valueTokens = cookie.split("%7C");
		}
		var valueTokensLength = valueTokens.length;
		if(valueTokensLength >= 6) {
			valueTokens[5] = value;
			betfair.CookieManager.set("userhistory", valueTokens.join("|"));
		}
		loadPage(value);
	}

	function handleLIMBLoad() {
		getDOMElement();
		startPageSelect.disabled = true;
	}
	function handleLIMBUnLoad() {
		getDOMElement();
		startPageSelect.disabled = false;
	}

	function loadPage(subdomain) {
		// handle no reload if subdomain set to same as current page or none
		if (subdomain === "home" || subdomain === "portal" || subdomain === "-1" || subdomain === "") { subdomain = "www"; } // catch all edge cases
		if (subdomain === "www" && top.location.href.match("http://"+document.domain)) { return; }
		if (top.location.href.match("http://"+subdomain+"."+document.domain)) { return; }
		top.location = "http://"+subdomain+"."+document.domain;
	}
})();

betfair.Navigation.tabs = (function() {
	var eventHandler = new betfair.Events.delegate( {
		custom: [
			{ event: betfair.Events.custom.LIMB.startLoading, handler: handleLIMBLoad },
			{ event: betfair.Events.custom.LIMB.unloaded, handler: handleLIMBUnLoad }
		]
	}, true );
	
	function handleLIMBLoad() {
		eventHandler.addListeners( {
			DOM:[
				{element: document.getElementById("productNavigation"), eventType: "click", handler: function(e) { e.stop(); } }
			]
		}, true );
	}
	function handleLIMBUnLoad() {
		eventHandler.unRegisterDOMListeners();
	}
})();
betfair.Account = (function(){
	var cache = new betfair.Cache({cacheId:("betfair.Account")});

	var exchangeCount = 0;
	var login = {
		timeout: null,
		timeoutTime: 60000
	};

	var pcodeRegex = document.location.search.match(/promotionCode=([\w\.-]+)/);
	var openAccountPromotionCode = (pcodeRegex) ? pcodeRegex[1] : null;

	var eventHandler = new betfair.Events.delegate( {DOM: [{ element: window, handler: function() { initialise(true); }, eventType: "DOMContentLoaded" }]}, true );

	var eventHandlers = {
// login
		handleLogin: function(e) {
			e.stop();

			var loginForm = cache.get("loginForm");
			if(cache.get("username").value === "" || cache.get("password").value === "") {
				alert(betfair.messages.login.failure["Frontpage.Login.Error.No.User.Name.Password"]);
				return;
			}

			setOverlayDimensions();
			cache.get("overlay").style.display = "block";

			loginForm.setAttribute("action", betfair.Config.paths.services["login"].action);
/*
			SPR-1507 - Removed workaround to an existing bug...
			eventHandler.unRegisterSpecificDOMListener(loginEventDefinition);
			eventHandler.registerDOMListeners();
*/
			loginForm.submit();

			login.timeout = setTimeout( function() { cancelLoginAttempt(); }, login.timeoutTime );
		},
// account
		handleFundsDisplay: function(e) {
			if(betfair.User.dataInterfaceDisabled) { return; }

			var showAvailableFundsEl = e.sourceNode,
				showFundsDetails = showAvailableFundsEl.checked,
				fundsVisibility = "hidden";

			if(showFundsDetails) {
				betfair.Wallet.retrieveFunds();
				fundsVisibility = "visible";
			}

			// we enable the transfers button if we're not the portal page and more than one exchange exists
			if(betfair.Config.application.productName !== "portal" && exchangeCount > 1) {
				cache.get("transferFunds").disabled = false;
			}
			betfair.cssjs((showFundsDetails ? "remove" : "add"), cache.get("totalFunds"), "hidden");
			betfair.cssjs((showFundsDetails ? "remove" : "add"), cache.get("refreshBalance"), "hidden");
			betfair.CookieManager.set("UserPreferencesShowAvailableFunds", showFundsDetails, null, betfair.User.getData("accountId"), true);
		},
		handleFundsDeposit: function(e) {
			betfair.WindowManager.open("myAccount", "http://www."+document.domain+"/myaccount/account/MyAccount.do?tabID=3");
		},
		handleFundsTransfer: function(e) {
			betfair.WindowManager.open('transfer','PDB');
		},
		handleWalletFundsRefresh: function(e) {
			betfair.Wallet.retrieveFunds();
		},
		handleWalletHelpRequest: function(e) {
			if(betfair.User.getData("locale") === "en") {
				betfair.WindowManager.open("newHelp", "http://help."+document.domain+"/contents/itemId/i65767685/index.en.html");
			} else {
				betfair.WindowManager.open("help","Help.Managing.Account","Wallets");
			}
		},
		handleLivePricesRequest: function(e) {
			var livePricesHelp = cache.get("livePricesHelp");
			var livePricesVisible = livePricesHelp.style.display == "block";
			livePricesHelp.style.display = livePricesVisible ? "none" : "block";
		},
		handleLogout: function(e) {
			var marketFrame = ((top.Content && top.Content.main)? top.Content.main : false);
			if(marketFrame) {
				var uiController = marketFrame.betexUIController ? marketFrame.betexUIController: false;
				if(uiController) {
					marketFrame.interface_savePreferences(true);
				}
			}
			betfair.Account.Logout.logout();
		},
		handleLIMBLoad: function() {
			var elements = [
					document.getElementById("depositFunds"),
					cache.get("transferFunds"),
					cache.get("toggleFundsDisplay")
				], i = elements.length-1;
			for (i; i>=0; i--) {
				if (elements[i]) {
					elements[i].disabled = true;
				}
			}
			eventHandler.unRegisterSpecificDOMListener({element: "walletHelp", eventType: "click", handler: this.handleWalletHelpRequest });
		},
		handleLIMBUnLoad: function() {
			var elements = [
					document.getElementById("depositFunds"),
					cache.get("toggleFundsDisplay")
				], i = elements.length-1;
			for (i; i>=0; i--) {
				if (elements[i]) {
					elements[i].disabled = false;
				}
			}
			eventHandler.registerDOMListeners();
			cache.get("registeredUserName").innerHTML = betfair.User.getData("accountUserName");
			if(betfair.Config.application.productName !== "portal" && exchangeCount > 1) {
				cache.get("transferFunds").disabled = false;
			}
			if (cache.get("toggleFundsDisplay").checked) {
				betfair.Wallet.retrieveFunds();
				betfair.cssjs("remove", cache.get("totalFunds"), "hidden");
				betfair.cssjs("remove", cache.get("refreshBalance"), "hidden");
			}
			betfair.User.retrieveData(betfair.Config.paths.services["getUser"].action);
		},
		UIStateHandlers: {
			loggedIn: function() {
				cache.get("username").value = "";
				cache.get("password").value = "";
				betfair.cssjs("add", cache.get("account"), "authenticated");
				betfair.cssjs("remove", cache.get("account"), "loginStatePending");
				cache.get("overlay").style.display = "none";
			},
			limbo: function() {
				betfair.cssjs("add", cache.get("account"), "authenticated");
				betfair.cssjs("remove", cache.get("account"), "loginStatePending");
				cache.get("overlay").style.display = "none";
			},
			loggingOut: function() {
				cache.get("overlay").style.display = "block";
			},
			loggedOut: function() {
				cache.get("username").value = "";
				cache.get("password").value = "";
				betfair.cssjs("remove", cache.get("account"), "authenticated");
				betfair.cssjs("remove", cache.get("account"), "loginStatePending");
				setTotalFunds(betfair.messages.account["Async.Field.Loading"]);
				cache.get("registeredUserName").innerHTML = "";
				cache.get("overlay").style.display = "none";
			}
		},
		registerEvents: function() {
			eventHandler.addListeners( {
				DOM: [
					// unauthenticated
					{element: "loginForm", eventType: "submit", handler: this.handleLogin }
					// possible in both
					,{element: "livePricesHelpLaunch", eventType: "click", handler: this.handleLivePricesRequest }
					,{element: "livePricesHelpClose", eventType: "click", handler: this.handleLivePricesRequest }
					// authenticated
					,{element: "toggleFundsDisplay", eventType: "click", handler: this.handleFundsDisplay }
					,{element: "refreshBalance", eventType: "click", handler: this.handleWalletFundsRefresh }
					,{element: "depositFunds", eventType: "click", handler: this.handleFundsDeposit }
					,{element: "transferFunds", eventType: "click", handler: this.handleFundsTransfer }
					,{element: "walletHelp", eventType: "click", handler: this.handleWalletHelpRequest }
					,{element: "logout", eventType: "click", handler: this.handleLogout }
				],
				custom: [
					{ event: betfair.Events.custom.LIMB.startLoading, handler: this.handleLIMBLoad }
					,{ event: betfair.Events.custom.LIMB.unloaded, handler: this.handleLIMBUnLoad }
					,{ event: betfair.Events.custom.User.loginState.loggedIn, handler: this.UIStateHandlers.loggedIn }
					,{ event: betfair.Events.custom.User.loginState.limbo, handler: this.UIStateHandlers.limbo }
					,{ event: betfair.Events.custom.User.loginState.loggingOut, handler: this.UIStateHandlers.loggingOut }
					,{ event: betfair.Events.custom.User.loginState.loggedOut, handler: this.UIStateHandlers.loggedOut }
				]
			}, true );
		}
	};

	function setOverlayDimensions() {
		var overlay = cache.get("overlay");
		var account = cache.get("account");
		overlay.style.width = account.clientWidth + "px";
		overlay.style.height = account.scrollHeight + "px";
	}

	function cookiesEnabled() {
		// we can't rely on navigator.cookieEnabled as it is not consistent across all browsers
		// nor is it reliable within any particular browser (cookies can be disabled globally, but allowed for a particular domain and vice versa)
		var cookiesEnabled = false;
		var cookieTest = {
			name: "cookiesAvailable",
			value: "true",
			ttl: 0
		};
		betfair.CookieManager.set(cookieTest.name, cookieTest.value, cookieTest.ttl);
		if(betfair.CookieManager.get(cookieTest.name) === cookieTest.value) {
			cookiesEnabled = true;
			betfair.CookieManager.clear(cookieTest.name);
		}

		return cookiesEnabled;
	}

	function initialise(initialiseOnLoad) {
		if(initialiseOnLoad===true) {
			var elementIds = [
				"loginForm","loginChannel","username","password","overlay",
				"account","transferFunds","totalFunds","toggleFundsDisplay","refreshBalance","registeredUserName",
				"livePricesHelp"
			];
			cache.setMulti(elementIds);

			var loginChannelIframe = cache.get("loginChannel");
			loginChannelIframe.callBackWhenThisReadyState = "complete";
			
			var loginEventDefinition = {
				element: loginChannelIframe,
				eventType: loginChannelIframe.readyState ? "readystatechange" : "load",
				handler: configureUserState
			};
			eventHandler.addListeners({DOM: [loginEventDefinition]}, false);

			if(!cookiesEnabled()) {
				alert(betfair.messages.error["Global.NoCookies"]);
				return;
			}

			setOverlayDimensions();

			eventHandlers.registerEvents();
			var i;
			for(i in betfair.Config.products) {
				if(betfair.Config.products[i].type === "EXCH") {
					exchangeCount++;
				}
			}
		}

		configureUserState(null, initialiseOnLoad);
	}

	function configureUserState(e, initialiseOnLoad) {
		betfair.User.determineLoginState();
		var userLoginState = betfair.User.getLoginState()
		if((initialiseOnLoad && userLoginState === "loggedIn") || (!initialiseOnLoad && (userLoginState !== "loggedOut")) || betfair.LIMB.isActive()) {
			betfair.User.retrieveData(betfair.Config.paths.services["getUser"].action);
		}
	}

	function setTotalFunds(amount) {
		cache.get("totalFunds").innerHTML = amount;
	}

	function cancelLoginAttempt() {
		clearTimeout(login.timeout);
		login.timeout = 0;
		cache.get("overlay").style.display = "none";
	}

	return {
		setTotalFunds: setTotalFunds,
		initialise: initialise
	};
})();

betfair.Account.Logout = (function(){
	var messages = betfair.messages.logout;

	var productEnum = {
		exchange: "EXCH",
		casino: "CASI"
	};

	var logoutContinuationFlags = {
		exchange: false,
		casino: false
	};

	var logoutConfig = {
		requests: {},
		exchange: {
			bets: 0,
			requestCallback: {
				response: function(unmatchedBetsCount, productId) {
					// if server returns a null response, consider it down and allow logout to continue
					var unmatchedBets = unmatchedBetsCount ? unmatchedBetsCount : 0;
					logoutConfig.exchange.bets += unmatchedBets;
					logoutConfig.requests[productEnum.exchange + productId].betCount = unmatchedBets;
					logoutConfig.requests[productEnum.exchange + productId].complete = true;
					if(pendingProductRequestsComplete()) {
						logout.account.questionAccountAccess();
					}
				},
				timeout: function(cookieName) {
					logoutConfig.requests[cookieName].complete = true;
					if(pendingProductRequestsComplete()) {
						logout.account.questionAccountAccess();
					}
				}
			}
		},
		casino: {
			balance: 0,
			requestCallback: {
				response: function(wallet, productId) {
					logoutConfig.requests[productEnum.casino].complete = true;
					if(wallet && wallet.availableToWithdraw){
						logoutConfig.casino.balance = wallet.availableToWithdraw;
					}
					if(pendingProductRequestsComplete()) {
						logout.account.questionAccountAccess();
					}
				},
				timeout: function(cookieName) {
					logoutConfig.requests[cookieName].complete = true;
					if(pendingProductRequestsComplete()) {
						logout.account.questionAccountAccess();
					}
				}
			}
		}
	};

	function pendingProductRequestsComplete() {
		var pendingProductRequestsComplete = true;
		for(product in logoutConfig.requests) {
			if(logoutConfig.requests[product].complete !== true) {
				pendingProductRequestsComplete = false;
				break;
			}
		}
		return pendingProductRequestsComplete;
	}

	var logout = {
		initialise: function() {
			var oElement = window.frames['main'];
			if(oElement) {
				var uiController = false;
				try {
					uiController = oElement.interface_getUIController();
				} catch(x) {
					uiController = false;
				}
				if(uiController) {
					oElement.interface_savePreferences(true);
				}
			}

			logoutContinuationFlags.exchange = false;
			logoutContinuationFlags.casino = false;

			logoutRequests = logoutConfig.requests;
			betfair.User.setLoginState("loggingOut");
			var product, betfairProducts = betfair.Config.products;
			for(product in betfairProducts) {
				if(betfairProducts[product].type === productEnum.exchange) {
					// reset in case of multiple logout iterations
					logoutConfig.exchange.bets = 0;
					logoutRequests[productEnum.exchange+betfairProducts[product].id] = {
						type: productEnum.exchange,
						productId: betfairProducts[product].id,
						URL: ("http://" + betfairProducts[product].subdomain + "/account/login/ExitSpawns.do?productId=" + betfairProducts[product].id)
					};
				} else if(betfairProducts[product].type === productEnum.casino) {
					// reset in case of multiple logout iterations
					logoutConfig.casino.balance = 0;
					logoutRequests[productEnum.casino] = {
						type: productEnum.casino,
						productId: betfairProducts[product].id,
						URL: ("http://" + betfairProducts[product].subdomain + "/wallet/LocalAccountSummaryWalletView.do?productId=" + betfairProducts[product].id)
					};
				}
			}

			var JSONRequestCookieConfig = {};
			var currentAsyncLogoutRequest;
			for(product in logoutConfig.requests) {
				if(logoutConfig.requests[product].type === productEnum.exchange) {
					JSONRequestCookieConfig = {
						'cookieName': product,
						'productId': logoutConfig.requests[product].productId
					};
					currentAsyncLogoutRequest = new betfair.JSONRequest(logoutConfig.exchange.requestCallback.response, logoutConfig.exchange.requestCallback.timeout, false, JSONRequestCookieConfig);
					currentAsyncLogoutRequest.get(logoutConfig.requests[product].URL);
				} else if(logoutConfig.requests[product].type === productEnum.casino) {
					JSONRequestCookieConfig = {
						'cookieName': product
					};
					currentAsyncLogoutRequest = new betfair.JSONRequest(logoutConfig.casino.requestCallback.response, logoutConfig.casino.requestCallback.timeout, false, JSONRequestCookieConfig);
					currentAsyncLogoutRequest.get(logoutConfig.requests[product].URL);
				}
			}
		},
		account: {
			questionAccountAccess: function() {
				if(!logoutContinuationFlags.exchange && logoutConfig.exchange.bets > 0) {
					if(logout.account.confirmation.requestExchangeConfirmation())
					{
						betfair.User.setLoginState("loggedIn");
						return;
					}
					logoutContinuationFlags.exchange = true;
				} else {
					logoutContinuationFlags.exchange = true;
				}

				//if the user has casino funds, always pop up the casino funds transfer window,
				//and that window will call continueLogout again if the user selects logout from it.
				if(!logoutContinuationFlags.casino && logoutConfig.casino.balance > 0) {
					logout.account.confirmation.requestCasinoConfirmation();
					betfair.User.setLoginState("loggedIn");
					return;
				} else {
					logoutContinuationFlags.casino = true;
				}
				logout.finalise();
			},
			confirmation: {
				requestExchangeConfirmation: function() {
					var rtn = false, i;
					var message = betfair.messages.logout["Current.Bets.View.Unmatched.Bets.Confirmation"] + "\n\n";

					var unmatchedBetsLicence = null;
					var userData = {
						defaultExchange: betfair.User.getData("defaultExchange"),
						isInternationalCustomer: betfair.User.getData("isInternationalCustomer")
					};
					var defaultExchangeId = userData.defaultExchange ? userData.defaultExchange : 1;

					var unmatchedBets = logoutConfig.requests[productEnum.exchange+defaultExchangeId].betCount;
					if(unmatchedBets > 0) {
						unmatchedBetsLicence = defaultExchangeId;
					}

					if(!unmatchedBetsLicence) {
						for(i in logoutConfig.requests) {
							if(logoutConfig.requests[i].type === productEnum.exchange && logoutConfig.requests[i].betCount > 0) {
								unmatchedBetsLicence = logoutConfig.requests[i].id;
								break;
							}
						}
					}

					for(i in logoutConfig.requests) {
						if(logoutConfig.requests[i].type === productEnum.exchange && logoutConfig.requests[i].betCount > 0) {
							if(i === (productEnum.exchange+1)) {
								var unmatchedExchange1BetsText = betfair.messages.logout["Current.Bets.View.Unmatched.Bets." + (userData.isInternationalCustomer ? "Intl" : "UK")];
								message += unmatchedExchange1BetsText;
							} else {
								message += betfair.messages.logout["Current.Bets.View.Unmatched.Bets.AUS"];
							}
							message += "\n";
						}
					}

					message += "\n" + betfair.messages.logout["Current.Bets.View.Unmatched.Bets.Instructions"];

					// ok to logout, cancel to view unmatched bets
					if(!confirm(message)) {
						betfair.WindowManager.open("myAccount", "http://www."+document.domain+"/myaccount/account/MyAccount.do?tabID=6&ex="+unmatchedBetsLicence+"&logout=true");
						rtn = true;
					}

					return rtn;
				},
				requestCasinoConfirmation: function() {
					betfair.WindowManager.open("myCasinoAccTransfer");
				}
			}

		},
		finalise: function() {
			var logoutCommunicationChannels = {};

			logoutCommunicationChannels.casino = new betfair.JSONRequest(function(){ }, function(){ }, false, {cookieName: "CASINO"}, false).get(betfair.Config.paths.services.logout.casino.action, true);
			logoutCommunicationChannels.games = new betfair.JSONRequest(function(){ }, function(){ }, false, {cookieName: "GAMES"}, false).get(betfair.Config.paths.services.logout.games.action, true);

			betfair.WindowManager.close("joinNow");
			betfair.WindowManager.close("myAccountHeader");
			betfair.WindowManager.close("myAccountFromRegistration");

			logoutCommunicationChannels.site = new betfair.AJAX(
				 {
					URL: betfair.Config.paths.services.logout.site.action,
					method: "GET",
					onSuccess: function(){ },
					onFail: function(){ },
					context: this,
					timeoutLength: 2000
				}
			);
			logoutCommunicationChannels.site.send();

			betfair.User.setLoginState("loggedOut");
		}
	};

	return {
		logout: logout.initialise,
		finalise: logout.finalise
	};
})();

var interfaces_logout = betfair.Account.Logout.logout;

// handles changes relating to the site content area
betfair.ContentArea = (function () {
	
	var eventHandler = new betfair.Events.delegate( {DOM: [
		{handler: init, eventType: "DOMContentLoaded"},
		{handler: resizeContentContainer, element: window, eventType: "resize"}
	]}, true );

	var headingContainer, contentContainer;

	function init() {
		headingContainer = document.getElementById("heading");
		contentContainer = document.getElementById("Content");
		resizeContentContainer();
	}
	
	function getInnerHeight() {
		var height = 0;
		if (typeof window.innerHeight === "number") {
			height = window.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) {
			//IE strict
			height = document.documentElement.clientHeight;
		} else if (document.body && document.body.clientHeight) {
			//IE4 quirks
			height = document.body.clientHeight;
		}
		return height;
	}
	
	// Content area needs to be sized correctly
	function resizeContentContainer() {
		//if (!headingContainer || !contentContainer) { return; }
		//contentContainer.style.height = (getInnerHeight() - headingContainer.offsetHeight)+"px";
	}

	var functionsToRunOn = {
		"loggedIn": [
			setInternationalFooter
		]
	};

	// International Users see slightly different footer data
	function setInternationalFooter() {
		var site_frame = document.getElementById("site_frame");
		if (!site_frame || !betfair.User) { return; }

		switch (betfair.User.getData("isInternationalCustomer")) {
			case "true":
			case true:
				betfair.cssjs("add",site_frame,"international_customer");
				break;
			default:
				betfair.cssjs("remove",site_frame,"international_customer");
				break;
		}
	};

	function runOn(event) {
		if (!event || !functionsToRunOn[event]) { return; }
		var f = 0, length = functionsToRunOn[event].length;
		for (f; f < length; f += 1){
			functionsToRunOn[event][f]();
		}
	};

	return {
		runOn: runOn
	};
})();
betfair.CookieManager = (function() {
	var cookies = {
		session: {
			"betexRegionSessionCookie": "bRSC",
			"betexLocaleSessionCookie": "bLSC",
			"betexCMSLocaleSessionCookie": "bCMSLSC",
			"betexTimeZoneSessionCookie": "bTZSC",
			"betexCurrencySessionCookie": "bCSC",
			"betexBrand": "bB",
			"betexSkin": "bSSC"
		},
		betexPtk : {
			"betexRegion": "bR",
			"betexLocale": "bL",
			"betexCMSLocale": "bCMSL",
			"betexTimeZone": "bTZ",
			"betexCurrency": "bC"
		},
		preferences: {
			displayLayPrices: {name: "bspLP", shortName: "", share: true },
			displayMarketDepth: {name: "bspMD", shortName: "", share: true },
			displayStartingPrices: {name: "bspSP", shortName: "", share: false },
			showDemoHelp: {name: "ShowDemoHelp", shortName: "", share: true },
			uiView: {name: "UIView", shortName: "", share: true },
			layColour: {name: "LayColour", shortName: "", share: true },
			showHelp: {name: "ShowHelp", shortName: "", share: true },
			autoRefresh: {name: "AutoRefresh", shortName: "", share: true },
			openSubmenu: {name: "OpenSubMenu", shortName: "", share: true },
			userHistory: {name: "userhistory", shortName: "", share: true },
			showAvailableFunds: {name: "UserPreferencesShowAvailableFunds", shortName: "upSAF", defaultValue: true, share: true }
		},
		login: {
			status: "loginStatus",
			message: "loginMessage",
			sso: "ssoid"
		}
	};

	function generateExpiryToken(days) {
		var expires, date = new Date();
		if(!isNaN(parseInt(days,10))) {
			if(days === 0) {
				// session expiry
				expires = "";
			} else {
				// set explicit expiry date based up on days
				date.setTime(date.getTime()+(days*24*60*60*1000));
				expires = "; expires="+date.toGMTString();
			}
		} else {
			// arg[days] not passed, set generic expiry date [365 days]
			date.setTime(date.getTime() + 365*24*60*60*1000);
			expires = "; expires="+date.toGMTString();
		}
		return expires;
	}

	function buildUserPreferenceCookie(cookieName, cookieValue, userAccId) {
		var preferencesArray,
			existingCookieValues,
			accountSpecificCookieName = "Betex_"+userAccId;

		if(document.cookie !== "") {
			var existingCookies = document.cookie.split(";");
			for(i = 0; i < existingCookies.length; i++) {
				var currentCookieTokens = existingCookies[i].split("=");
				if(currentCookieTokens.length && (currentCookieTokens[0] === accountSpecificCookieName)) {
					existingCookieValues = currentCookieTokens[1];
					break;
				}
			}
		}

		if(existingCookieValues && existingCookieValues.length) {
			existingCookieValues = unescape(existingCookieValues).split("||");
			var nameValueArray = {};
			for(i = 0; i < existingCookieValues.length; i++)	{
				var tokens = existingCookieValues[i].split("::");
				nameValueArray[tokens[0]] = tokens[1];
			}
			preferencesArray = nameValueArray;
		}

		if(!preferencesArray) {
			preferencesArray = {};
			for(cookieDefinition in cookies.preferences) {
				var currentCookie = cookies.preferences[cookieDefinition];
				if(currentCookie.name === cookieName && currentCookie.shortName) {
					preferencesArray[currentCookie.shortName] = currentCookie.defaultValue;
					break;
				}
			}
		}

		var userPreferences = [], i = 0;
		for(preference in preferencesArray) {
			userPreferences.push(preference,"::");
			if(cookies.preferences.showAvailableFunds.shortName === preference) {
				//the name/value pair exists in the cookie array and is to be updated
				userPreferences.push(cookieValue);
			} else {
				//the current name/value pair exists but isn't being updated
				userPreferences.push(preferencesArray[preference]);
			}

			if(++i < preferencesArray.length) {
				userPreferences.push("||");
			}
		}
		var rtn = accountSpecificCookieName+"="+escape(userPreferences.join(""));

		return rtn;
	}

	function get(cookieName,userAccId) {
		var cookieIs = {
			userPreferenceCookie: (cookies.preferences.showAvailableFunds.name === cookieName && cookies.preferences.showAvailableFunds.shortName !== ""),
			sessionCookie: (cookies.session[cookieName] && cookies.session[cookieName] !== ""),
			betexPtkCookie: (cookies.betexPtk[cookieName] && cookies.betexPtk[cookieName] !== "")
		};
		var rtn = "", existingCookies, tokens, nameEQ = cookieName+"=";

		switch(true) {
			case cookieIs.sessionCookie:
			case cookieIs.betexPtkCookie:
				nameEQ = (cookieIs.sessionCookie) ? "betexPtkSess=" : "betexPtk=";
				begin = document.cookie.indexOf(nameEQ);
				if(begin !== -1) {
					begin += nameEQ.length;
					end = document.cookie.indexOf(";", begin);
					if(end === -1) {
						end = document.cookie.length;
					}

					var sessionDetailsArray = (unescape(document.cookie.substring(begin, end))).split("~");
					for(var i = 0; i < sessionDetailsArray.length; i++) {
						tokens = sessionDetailsArray[i].split("=");
						if(tokens[0] === cookieName) {
							rtn = tokens[1];
							break;
						}
					}
				}
				break;
			case cookieIs.userPreferenceCookie:
				nameEQ = "Betex_"+userAccId;
				var preferenceArray;
				var existingCookieValues;
				existingCookies = document.cookie.split(";");

				for(i=0; i<existingCookies.length; i++) {
					var currentCookie = existingCookies[i];
					while(currentCookie.charAt(0) === " ") {
						currentCookie = currentCookie.substring(1,currentCookie.length);
					}
					var currentCookieTokens = currentCookie.split("=");
					if(currentCookieTokens[0] === nameEQ) {
						if(currentCookieTokens[1] && currentCookieTokens[1].length) {
							existingCookieValues = unescape(currentCookieTokens[1]).split("||");
							var nameValueArray = {};
							for(i=0; i<existingCookieValues.length; i++)	{
								tokens = existingCookieValues[i].split("::");
								nameValueArray[tokens[0]] = tokens[1];
							}
							preferenceArray = nameValueArray;
						}
						break;
					}
				}

				if(!preferenceArray) {
					preferenceArray = {};
					for(var cookieId in cookies.preferences) {
						var currentPrefCookie = cookies.preferences[cookieId];
						if(currentPrefCookie.shortName && currentPrefCookie.defaultValue) {
							preferenceArray[currentPrefCookie.shortName] = ""+currentPrefCookie.defaultValue; // force string type
						}
					}
				}
				rtn = preferenceArray;
				break;
			default:
				nameEQ = cookieName+(userAccId?"_"+userAccId:"")+"=";
				var offset = -1;
				var cookieLocated = false;
				existingCookies = document.cookie;
				if(existingCookies.length > 0) {
					// to ensure that this is the cookie's name and not one that contains the cookie's name as a substring
					// i.e. (userhistory vs. xguserhistory) or (userhistory vs. userhistoryxg)
					while(!cookieLocated) {
						offset = existingCookies.indexOf(nameEQ);
						if(offset > 1) {
							if(existingCookies.substring(offset-2, offset) === "; ") {
								cookieLocated = true;
							} else {
								existingCookies = existingCookies.substring((offset+nameEQ.length), existingCookies.length);
							}
						} else if (offset <= 0) {
							cookieLocated = true;
						}
					}

					if(offset >= 0) {
						offset += nameEQ.length;
						var cookieValueLength = existingCookies.indexOf(";", offset);
						if(cookieValueLength == -1) {
							cookieValueLength = existingCookies.length;
						}
						rtn = unescape(existingCookies.substring(offset, cookieValueLength));
					}
				}
				break;
		}
		return rtn; // default string, otherwise as per case
	}

	function set(cookieName, cookieValue, days, userAccId, escapeValue, scas) {
		var newCookie = [];
		//check to see if this name is a user preference cookie value
		var isUserPreference = (cookies.preferences.showAvailableFunds.name === cookieName && cookies.preferences.showAvailableFunds.shortName !== "");
		if(isUserPreference) {
			newCookie.push(buildUserPreferenceCookie(cookieName, cookieValue, userAccId));
		} else {
			newCookie.push(cookieName,(userAccId?("_"+userAccId):""),"=");
		}
		// legacy? Can we remove the user prefs cookie differences to make processing easier?
		// it appears that the user prefs cookie only contains one user pref: showAvailableFunds
		// which stores whether or not to show the funds in the account widget.
		if(!isUserPreference) {
			newCookie.push((escapeValue ? escape(cookieValue) : cookieValue));
		}
		newCookie.push(generateExpiryToken(days),"; path=/");

		// do we need to permit access to the cookie from subdomains?
		if (typeof(scas) === "undefined") { scas = false; }
		var cookieId, currentCookie, shareCookieAcrossSubDomains = scas;
		for(cookieId in cookies.preferences) {
			currentCookie = cookies.preferences[cookieId];
			if(currentCookie.name === cookieName && currentCookie.share) {
				shareCookieAcrossSubDomains = true;
				break;
			}
		}

		// append . in front of domain to grant access from subdomains
		if(shareCookieAcrossSubDomains) {
			newCookie.push("; domain=."+document.domain);
		}

		newCookie = newCookie.join("");

		document.cookie = newCookie;

		var defendedCookies = {
			"JSESSIONID": get("JSESSIONID"),
			"bsessionid": get("bsessionid")
		};
		for(cookieId in defendedCookies) {
			defend(cookieId, defendedCookies[cookieId]);
		}
	}

	function defend(cookieName, value) {
		// IE drops cookies when 20 cookies exceeded.
		// If the 'JSESSIONID' [or, apparently, 'bsessionid'] cookie is dropped, the user is no longer authenticated.
		// 	returns [true|false] to indicate success.
		if(value != get(cookieName)) {
			set(cookieName,escape(value));
			return (value === get(cookieName));
		}
	}

	function clear(cookieName) {
		set(cookieName,"",-1);
	}

	return {
		cookies: cookies,
		get: get,
		set: set,
		clear: clear
	};
})();

betfair.IFrameAjaxRequest = function() {
	//AJAX status descriptors:
	//	{
	//		0: uninitialized,
	//		1: setup not sent,
	//		2: request in progress,
	//		3: response in progress (not used in this implementation),
	//		4: request complete
	//	}
	var self = this;
	var status = 0;
	var eventHandler = new betfair.Events.delegate();
	var iframe = {
		element: null,
		id: "IFrameAjaxRequest."+ new Date().getTime(),
		create: function(url, context) {
			if(this.element == null) {
				this.element = document.createElement('iframe');
				this.element.src = (context.isSecure ? betfair.Config.paths.secureCommunicationURL : "");
				this.element.id = this.id;
				this.element.callBackWhenThisReadyState = "complete";
				this.element.style.display = "none";
				document.body.appendChild(this.element);
				eventHandler.addListeners(
					{
						DOM: [
							{
								element: this.element,
								eventType: this.element.readyState ? "readystatechange" : "load", // generally only IE
								handler: window[this.id].handleResponse,
								context: context
							}
						]
					},
					true
				);
				document.close();
			}  else if (!context.persistIFrame) {
				//if the iframe is not persisted on a previous use, the element exists but is not in the document, so add it
				document.body.appendChild(this.element);
			}
		},
		getDocument: function() {
			try {
				var doc = null;
				if(this.element.contentDocument) { // NS6
					doc = this.element.contentDocument;
				} else if(this.element.contentWindow) { // IE5.5 and IE6
					doc = this.element.contentWindow.document;
				} else if(iframe.document) { // IE5
					doc = this.element.document;
				} else { // an unobtained reference
					console.debug("betfair.IFrameAjaxRequest: [pmf] getIframeDocument: error, couldn't obtain reference to the IFRAME's document");
				}
				return doc;
			} catch(x) {
				return null;
			}
		},
		getHTML: function() {
			try {
				var iframeDoc = this.getDocument();
				if (!iframeDoc) { return null; }
				var textarea = iframeDoc.getElementById("jsonResponse");
				if (!textarea) { return iframeDoc.body.innerHTML; } // backwards compatibility
				return textarea.value;
			} catch(x) { return null; } // e.g. domain protection error
		}
	};
	var ajaxTimeoutId = null;
	var timeoutDuration = 10000;

	var registration = {
		register: function() {
			// global callback
			window[iframe.id] = self;
		},
		unregister: function(persistIFrame) {
			if(!persistIFrame) {
				// prevents ff from erroneously presenting the loading ticker on the window
				var iframeElementId = iframe.element.id;
				var fn = function() {
					if (!iframeElementId) { return; }
					var ifr = document.getElementById(iframeElementId);
					if (ifr && ifr.parentNode) { ifr.parentNode.removeChild(ifr); }
				};
				setTimeout(fn, 1000);
			}
			// unregister global callback
			window[iframe.id] = null;
		}
	};

	var serialiseData = function(data) {
		var a = [], type, name;
		for(name in data) {
			type = typeof data[name];
			if(type !== "undefined" && type !== "function") {
				a.push(escape(name)+"="+escape(data[name]));
			}
		}
		return a.join("&");
	};

	this.get = function(url, fireAndForget) {
		if(this.isSecure) {
			url += (url.match(/\?/) ? "&" : "?") + "transportCookieName=" + this.cookieName;
		}

		//only service request if not in progress
		if(status === 0) {
			status = 1;
			registration.register();
			iframe.create(url, self);
			if(url.indexOf("?origin=initiate") === -1) {
				ajaxTimeoutId = window.setTimeout(
					function() {
						self.handleTimeout(self.cookieName);
						ajaxTimeoutId = null;
						registration.unregister(self.persistIFrame);
						status = 0;
					},
					timeoutDuration);
				iframe.element.src = url;
				if(fireAndForget) {
					eventHandler.unRegisterSpecificDOMListener(
						{
							element: iframe.element,
							eventType: "load",
							handler: window[iframe.id].handleResponse
						}
					);

					registration.unregister();
				}
				status = 2;
			}
		}
	};

	this.decode64 = function(input) {
		// This function must not run on an empty string
		// because String.fromCharCode(0) !== "", so you
		// end up joining null terminators or something which
		// don't equal the empty string.
		if (!input) { return ""; }
		var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var output = [];
		var i = 0;
		var counter = 0;
		var data = { chr: [], enc: [] };
		var base64test = /[^A-Za-z0-9\+\/\=]/g;

		input = input.replace(base64test, "");
		do {
			for(counter=0; counter<4; counter++) {
				data.enc[counter] = keyStr.indexOf(input.charAt(i++));
			}
			data.chr[0] = (data.enc[0] << 2) | (data.enc[1] >> 4);
			data.chr[1] = ((data.enc[1] & 15) << 4) | (data.enc[2] >> 2);
			data.chr[2] = ((data.enc[2] & 3) << 6) | data.enc[3];
			output.push(String.fromCharCode(data.chr[0]));
			if(data.enc[2] != 64) {
				output.push(String.fromCharCode(data.chr[1]));
			}
			if(data.enc[3] != 64) {
				output.push(String.fromCharCode(data.chr[2]));
			}
		} while (i < input.length);

		return output.join("");
	};

	this.post = function(requestURL,requestData) {
		if(!this.timeoutId) {
			if(typeof requestData == "object") {
				requestData = serialiseData(requestData);
			}
			this.get(requestURL + "?" + requestData);
		}
	};

	this.handleResponse = function() {
		if(ajaxTimeoutId !== null) {
	 		status = 4;
	 		window.clearTimeout(ajaxTimeoutId);
			ajaxTimeoutId = null;

			try {
				self.handleResponseHTML(self, iframe.getHTML());
			} catch(e) {
				console.debug(e);
				//invoke the error handler
				try {
					self.handleError();
				} catch(e1) {
					console.debug(e1);
				}
			}
			registration.unregister(self.persistIFrame);
			status = 0;
		}
		return true;
	};
};

betfair.IFrameAjaxRequest.prototype.handleResponseHTML = function(request, html) {
	// over-ride in implementation
};

betfair.IFrameAjaxRequest.prototype.handleTimeout = function(cookieName) {
	// over-ride in implementation
};

betfair.IFrameAjaxRequest.prototype.handleError = function() {
	this.handleTimeout(this.cookieName);
};

betfair.JSONRequest = function(callbackHandler, timeoutHandler, isSecure, cookieParams, persistIFrame) {
	betfair.IFrameAjaxRequest.call(this);
	this.callbackHandler = callbackHandler;
	this.timeoutHandler = timeoutHandler || null;
	this.isSecure = isSecure || false;
	this.cookieName = cookieParams.cookieName;
	this.productId = cookieParams.productId || null;
	this.persistIFrame = persistIFrame || false;

	this.handleResponseHTML = function(request, html) {
		var obj = null;

		// cross protocol call http-https the content of the iframe is not accessible
		// attempt to retrieve encoded information from the cookie set from the iframe
		if(html === null) {
			var transportCookieBase64 = betfair.CookieManager.get(request.cookieName);
			html = this.decode64(transportCookieBase64);

			var expires = new Date();
				expires.setSeconds(expires.getSeconds()-1);
			//remove the data transport cookie
			document.cookie = request.cookieName+"=;expires="+expires.toGMTString()+";path=/;domain="+document.domain;
		}

		if(html !== null && html !== "") {
			obj = betfair.JSON.eval(html);
		}
		if(request.productId) {
			request.callbackHandler(obj, request.productId);
		} else {
			request.callbackHandler(obj);
		}
	};

	this.handleTimeout = function(cookieName) {
		if(this.timeoutHandler) {
			this.timeoutHandler(cookieName);
		}
	};
};

betfair.JSONRequest.prototype = new betfair.IFrameAjaxRequest();

betfair.LIMB = (function() {
	var LIMBLoaded = false,
		messagesLoaded = false,
		stopOnSuspend = false,  // revert to old LIMB functionality = true
		getMessages,
		messages,
		LIMB,
		LIMBCookie = (function() {
			cookieName = "inLIMB";
			return {
				isActive: function() {
					return betfair.CookieManager.get(cookieName) === "true";
				},
				set: function() {
					betfair.CookieManager.set(cookieName, "true", 0);
				},
				clear: function() {
					betfair.CookieManager.clear(cookieName);
				}
			}
		})();

	//register to the loginstatechange limbo event
	new betfair.Events.delegate( {
		custom: [
			{ event: betfair.Events.custom.User.loginState.limbo, handler: function() {
				//arm the LIMB
				getMessages = new betfair.JSONRequest( handleGetMessages, handleGetMessagesFailure, false, {cookieName:"LIMB"}, false);
				getMessages.get(betfair.Config.paths.services.limb.action);
				loadResources(document.getElementsByTagName("head")[0]);
			} },
			{ event: betfair.Events.custom.User.loginState.loggedIn, handler: removeLIMB },
			{ event: betfair.Events.custom.User.loginState.loggedOut, handler: removeLIMB }
				]
	}, true);

	//load the resources
	function loadResources(head) {
		//load the javascript
		var st = document.createElement("script"),
			css = document.createElement("link");
		st.type = "text/javascript";
		st.id = "LIMBResources";
		st.src = "/cms/bundles/LIMB.js?pi.regionId=GBR&pi.localeId=zh_TW";
		css.type = "text/css";
		css.rel = "stylesheet";
		css.href = "http://cache.betfair.com/www/betfair/GBR/zh_TW/prospect/css/LIMB.css";
		//append in this order to ensure there is no chance of JS blocking download of css
		head.appendChild(css);
		head.appendChild(st);
		loadResources = function(){};
	}

	function handleGetMessages(response) {
		if (response === null) { return; }
		messages = response;
		messagesLoaded = true;
		startLIMB();
	}

	function handleGetMessagesFailure() {
		betfair.User.setLoginState("loggedOut");
	}

	function startLIMB() {
		if (!LIMBLoaded || !messagesLoaded || typeof messages !== "object") {
			return;
		}
		LIMBCookie.set();
		betfair.Events.custom.LIMB.startLoading.fire();
		contentHandler.hideContent();
		//refactor the messages into the correct format
		messages = betfair.LIMB.messageConverter.convert(messages);
		//fire the LIMB
		LIMB = new betfair.LIMB.controller(messages.numberOfDaysUntilEnforceDate, messages.suspended, stopOnSuspend);
		betfair.LIMB.setButtonStates = LIMB.setButtonStates;
		//add the messages to it in order - defined by the messageMap
		var messageMap = betfair.LIMB.messageMap,
			messageInfo,
			i = 0, j = messageMap.length, k, l;

		for (i; i<j; i++) {
			if (messages.suspended === true && messageMap[i].useInSuspendedMode !== true) continue;
			//set messageInfo to the item from the messages list returned from the middle tier that corresponds with the current item being dealt with in the message map
			messageInfo = messages[messageMap[i].dataName];

			//does this message type exist in the messages sent from the middle tier
			//is the message enabled
			if (messageInfo == null || messageInfo.enabled === false) continue;

			//check if messageInfo is an Array of multiple messages of the one message type and if so loop through each one
			if (messageInfo instanceof Array) {
				for (k = 0, l = messageInfo.length; k<l; k++) {
					LIMB.loadMessage( messageMap[i], messageInfo[k], k+1 );
				}
			} else {
				LIMB.loadMessage( messageMap[i], messageInfo );
			}
		}
		LIMB.render();
	}

	var contentHandler = (function() {
		var contentNodes = [];
		function cacheContentNodes() {
			contentNodes = [
				document.getElementById("footer"),
				document.getElementById("content"),
				document.getElementById("subNavigation")
			];
			cacheContentNodes = function(){};
		}
		return {
			hideContent: function() {
				cacheContentNodes();
				var i = contentNodes.length-1;
				for (i; i>=0; i--) {
					if (contentNodes[i]) {
						contentNodes[i].style.display = "none";
					}
				}
			},
			showContent: function() {
				cacheContentNodes();
				var i = contentNodes.length-1;
				for (i; i>=0; i--) {
					if (contentNodes[i]) {
						contentNodes[i].style.display = "block";
					}
				}
			}
		};
	})();
	
	function removeLIMB() {
		if (LIMB != null) {
			LIMB.shutdown();
		}
		contentHandler.showContent();
		messages = null;
		LIMB = null;
		LIMBCookie.clear();
	}

	return {
		setLIMBLoaded: function() {
			LIMBLoaded = true;
			startLIMB();
		},
		getSuspendedStatus: function() {
			return messages.suspended || false;
		},
		getStopOnSuspendedStatus: function() {
			return stopOnSuspend || false;
		},
		isActive: LIMBCookie.isActive
	};
})();

// handles alternate domains to allow homepage to work on dev/qa/staging etc
betfair.MediaplexHandler = (function () {
	var timestamp = new Date().getTime();
	var urlPrefix = "http://altfarm.mediaplex.com/ad/fm/";
	var idPrefix = "Mediaplex_";
	var mptParam = "?mpt=" + timestamp;

	var eventHandler = new betfair.Events.delegate( {DOM: [
		{ element: window, handler: function() { initialise();}, eventType: "DOMContentLoaded"}
	]}, true );

	function action() {
		var mediaplexIframes = betfair.getElementsByClassName(document, "iframe", "mediaplex");
		var iframe, source, i, length = mediaplexIframes.length;
		for (i = 0; i < length; i += 1 ) {
			iframe = mediaplexIframes[i];
			if (!iframe.id) { continue; }
			iframe.src = urlPrefix + iframe.id.replace(idPrefix, '') + mptParam;
		}
	}

	function initialise() {
		setTimeout("betfair.MediaplexHandler.action()",1);
	}

	return {
		action: action
	};
})();
betfair.User = (function() {
	var cache = new betfair.Cache({cacheId:("betfair.User")});
	var communicationChannel;
	var data = {};

	var loginState = {
		"loggedIn": false,
		"loggingOut": false,
		"loggedOut": false,
		"limbo": false
	};

	var loginResponse = {
		success: "success",
		failure: "failure",
		nowLocked: "nowLocked",
		alreadyLocked: "alreadyLocked",
		accountExcluded: "accountExcluded",
		requireTermsAndConditionsAcceptance: "requireTermsAndConditionsAcceptance",
		messages: "messages",
		restrictedLocation: "restrictedLocation",
		bettingRestrictedLocation: "bettingRestrictedLocation",
		accountClosed: "accountClosed",
		nonAV: "nonAV",
		ageVerSuspended: "ageVerSuspended",
		authPending: "authPending",
		kycSuspended: "kycSuspended",
		suspended: "Login.Suspended.Message"
	};

	function initialiseCache() {
		var elementIds = [
			"account","totalFunds","refreshBalance","registeredUserName","toggleFundsDisplay"
		];
		cache.setMulti(elementIds);
	}

	function retrieveData(serviceURL) {
		function callbackFunction(ajax) {
			if(arguments.length < 2) {
				var responseText = null;
				if (typeof (ajax.getResponseText()) === "string") {
					responseText = ajax.getResponseText().replace(/^\s\s*/, '').replace(/\s\s*$/, '');
				}
				if(responseText !== null && responseText !== "") {
					setData(betfair.JSON.eval(responseText));
				}
			} else {
				setData({});
			}

			initialiseCache();

			var userLoginState = getLoginState();

			if(userLoginState === "loggedIn") {
				cache.get("registeredUserName").innerHTML = getData("accountUserName");
				var userAccId = getData("accountId");
				var userPrefs = betfair.CookieManager.get("UserPreferencesShowAvailableFunds", (userAccId ? userAccId : null));
				var showFunds = (userPrefs[betfair.CookieManager.cookies.preferences.showAvailableFunds.shortName] === "true");
				if(showFunds) {
					cache.get("toggleFundsDisplay").checked = true;
					betfair.Wallet.retrieveFunds();
				}
				betfair.cssjs((showFunds? "remove" : "add"), cache.get("totalFunds"), "hidden");
				betfair.cssjs((showFunds? "remove" : "add"), cache.get("refreshBalance"), "hidden");
				betfair.ContentArea.runOn(userLoginState);
			} else if(userLoginState === "limbo") {
				betfair.cssjs("add", cache.get("refreshBalance"), "hidden");
				betfair.cssjs("add", cache.get("totalFunds"), "hidden");
			}
		}

		if(typeof(communicationChannel) === "undefined") {
			communicationChannel = new betfair.AJAX(
				 {
					URL: serviceURL,
					method: "GET",
					onSuccess: callbackFunction,
					onFail: callbackFunction,
					context: this
				}
			);
		}
		communicationChannel.send();
	}

	function setData(newData) {
		data = newData;
	}

	function getData(leafNodePath) {
		var leafNodeValue = betfair.JSON.leafNode.get(data, leafNodePath);
		return leafNodeValue;
	}

	function setLoginState(statusId) {
		var status;
		for(status in loginState) {
			loginState[status] = false;
		}
		loginState[statusId] = true;
		betfair.Events.custom.User.loginState[statusId].fire();
	}

	function getLoginState() {
		var status, rtnStatus;
		for(status in loginState) {
			if(loginState[status] === true) {
				rtnStatus = status;
				break;
			}
		}
		return rtnStatus;
	}

	// ssoid: logged in
	// !ssoid and cookieLoginState !== "success": not logged in, but check for error messages/LIMB [set to limbo]
	function determineLoginState() {
		var ssoToken = betfair.CookieManager.get(betfair.CookieManager.cookies.login.sso);
		var cookieLoginState = betfair.LIMB.isActive() ? loginResponse.messages : betfair.CookieManager.get(betfair.CookieManager.cookies.login.status);
		var showTermsAndConditions = false;
		if(ssoToken !== "") {
			setLoginState("loggedIn");
			//check if the user is suspended
			if (cookieLoginState === loginResponse.suspended) {
				alert(betfair.messages.login.suspended[cookieLoginState]);
			}
		} else if(cookieLoginState !== "") {
			var loginFailureKeyExists = false, loginFailureKey;
			switch(cookieLoginState) {
				case loginResponse.failure:
					loginFailureKeyExists = true;
					break;
				case loginResponse.nowLocked:
					loginFailureKeyExists = true;
					break;
				case loginResponse.alreadyLocked:
					loginFailureKeyExists = true;
					break;
				case loginResponse.accountExcluded:
					loginFailureKeyExists = true;
					break;
				case loginResponse.requireTermsAndConditionsAcceptance:
					// empty condition - need to accept T's and C's
					break;
				case loginResponse.messages:
					setLoginState("limbo");
					break;
				case loginResponse.restrictedLocation:
					loginFailureKeyExists = true;
					break;
				case loginResponse.bettingRestrictedLocation:
					loginFailureKeyExists = true;
					break;
				case loginResponse.accountClosed:
					loginFailureKeyExists = true;
					break;
				case loginResponse.nonAV:
					loginFailureKeyExists = true;
					break;
				case loginResponse.ageVerSuspended:
					loginFailureKeyExists = true;
					break;
				case loginResponse.authPending:
					loginFailureKeyExists = true;
					break;
				case loginResponse.kycSuspended:
					loginFailureKeyExists = true;
					break;
				default:
					// empty default state
					break;
			}

			if(loginFailureKeyExists) {
				setLoginState("loggedOut");
				loginFailureKey = betfair.CookieManager.get(betfair.CookieManager.cookies.login.message);
				// potentially more than 1 key returned [pipe delimited]
				var loginFailureMessages = betfair.messages.login.failure[loginFailureKey].split("|"),
					resultantFailureMessageArray = [],
					i,
					len;
				for(i=0, len=loginFailureMessages.length; i<len; i+=1) {
					resultantFailureMessageArray.push(loginFailureMessages[i]);
				}
				alert(resultantFailureMessageArray.join("\n"));
			} else {
				// non messaged state: ["requireTermsAndConditionsAcceptance"]
			}
		} else {
			setLoginState("loggedOut");
		}
		// clean stored cookie data to make way for subsequent calls
		betfair.CookieManager.clear(betfair.CookieManager.cookies.login.status);
		betfair.CookieManager.clear(betfair.CookieManager.cookies.login.message);
	}

	return {
		retrieveData: retrieveData,
		getData: getData,
		setLoginState: setLoginState,
		getLoginState: getLoginState,
		determineLoginState: determineLoginState,
		loginResponse: loginResponse
	};
})();

betfair.Wallet = (function(){
	var cookiePrefix = "WPID";
	var defaultWalletText = betfair.messages.account["Async.Field.Loading"];

	// nested objects keyed by productId
	var wallets = {
		requestCache: {},
		funds: {},
		prefix: {},
		domWalletContainers: {},
		totalFunds: 0
	};

	var callbacks = {
		retrieveFunds: {
			onSuccess: function(remoteWallet, productId) {
				setRetrievedFunds(remoteWallet, productId);
				setWalletDisplay(productId);
				legacyMarketViewStuff(productId);
				accrueRetrievedFunds();
			},
			onTimeout: function() {
				fundsRetrievalTimeout();
			}
		}
	};

	function retrieveFunds() {
		var i, len, products = betfair.Config.products, currentProduct, currentProductIdStr;
		var j=0, domWalletContainers = betfair.getElementsByClassName(document, "div", "wallet", false, false);
		for(i=0, len=products.length; i<len; i+=1) {
			currentProduct = products[i];
			if(!currentProduct.wallet) { continue; }

			currentProductIdStr = "" + currentProduct.id;
			if(!wallets.requestCache[currentProductIdStr]) {
				var requestData = {
					'cookieName': cookiePrefix + currentProductIdStr,
					'productId': currentProductIdStr
				};
				wallets.requestCache[currentProductIdStr] = {
					'JSONRequest': new betfair.JSONRequest(callbacks.retrieveFunds.onSuccess, callbacks.retrieveFunds.onTimeout, currentProduct.wallet.secure, requestData),
					'url': ("http" + (currentProduct.wallet.secure?"s":"") + "://" + currentProduct.subdomain + betfair.Config.paths.services.retrieveWallet.action),
					'isSecure': currentProduct.wallet.secure,
					'doGetRequest': function () {
						this.JSONRequest.get(this.url);
					}
				};
			}

			// should all come before the JSON request
			wallets.funds[currentProductIdStr] = null;
			wallets.prefix[currentProductIdStr] = currentProduct.wallet.name+" ";
			if(domWalletContainers[j]) {
				wallets.domWalletContainers[currentProductIdStr] = domWalletContainers[j++];
			}
			setWalletDisplay(currentProductIdStr, true);

			wallets.requestCache[currentProductIdStr].doGetRequest();
		}
	}

	function setRetrievedFunds(remoteWallet, productId) {
		if(typeof (productId) === "undefined") { return; }

		// Set the funds into the wallet including if wallet is null, set as 0.
		wallets.funds[productId] = (typeof (remoteWallet) === "undefined" || !remoteWallet || remoteWallet.suspended) ? 0 : remoteWallet.availableToBet;
	}

	function setWalletDisplay(productId, loading) {
		if(typeof (productId) === "undefined") { return; }
		if(betfair.Config.application.productName === "portal") { return; }
		if(typeof (loading) === "undefined") { loading = false; }

		var str = defaultWalletText;
		if(!loading) {
			str = betfair.formatCurrency(betfair.User.getData("shortCurrencySymbol") || betfair.User.getData("longCurrencySymbol"), wallets.funds[productId]);
		}
		wallets.domWalletContainers[productId].innerHTML = wallets.prefix[productId] + str;
	}

	function legacyMarketViewStuff(productId) {
		var currentMarketFundsUnavailable = false;
		var inMarketView = false;
		var mainFrame = window.frames['main'];
		if(mainFrame) {
			if(mainFrame.interface_getUIController) {
				var uiController = mainFrame.interface_getUIController();
				if(uiController.market !== null) {
					inMarketView = true;
				}
			} else if(mainFrame.exchangeId !== null) {
				inMarketView = true;
			}
		}

		if(inMarketView) {
			var walletId = null;
			if(mainFrame) {
				if(mainFrame.interface_getUIController) {
					walletId = mainFrame.interface_getUIController().market.exchangeID;
				} else {
					walletId = mainFrame.exchangeId;
				}
			}
			if(walletId !== productId) {
				//if in market view, gray out other products...
				currentMarketFundsUnavailable = true;
			}
		}

		if(currentMarketFundsUnavailable) {
			wallets.domWalletContainers[productId].className = "fundsUnavailable";
		}
	}

	function accrueRetrievedFunds() {
		wallets.totalFunds = 0;
		for(var id in wallets.funds) {
			wallets.totalFunds += isNaN(wallets.funds[id]) ? 0 : wallets.funds[id];
		}
		betfair.Account.setTotalFunds(betfair.formatCurrency(betfair.User.getData("shortCurrencySymbol") || betfair.User.getData("longCurrencySymbol"), wallets.totalFunds));
	}

	function fundsRetrievalTimeout() {
		console.debug("betfair.Wallet.[pmf] fundsRetrievalTimeout");
	}

	return {
		retrieveFunds: retrieveFunds
	};

})();

betfair.WindowManager = (function() {
	var windowConfig = {
		"domains": {
			'account': {
				"topDomain": 'account.'+document.domain,
				"contentDomain": 'account.'+document.domain,
				"paths": {
					'openaccount': '/account-web/registerAccount.html'
				}
			},
			'americanfootball': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=6423',
				"paths": {}
			},
			'baseball': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=7511',
				"paths": {}
			},
			'basketball': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=7522',
				"paths": {}
			},
			'casino': {
				"topDomain": 'casino.'+document.domain,
				"contentDomain": 'site.casino.'+document.domain,
				"paths": {
					'wallettx': '/MyAccount.do?panel=transferin&sizeX=600&sizeY=800',
					'mycasinoaccount': '/TransferHistory.do?page=1&menu=transferhistory&sizeX=800&sizeY=600',
					'doLogout': '/account/login/LogoutAction.do',
					'popLogoutTx': '/account/logout/CheckBalanceAction.do?transferFundsQuestion=true&sizeX=800&sizeY=600'
				}
			},
			'content': {
				"topDomain": 'content.'+document.domain,
				"contentDomain": 'content.'+document.domain,
				"paths": {}
			},
			'cricket': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=4',
				"paths": {}
			},
			'darts': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=3503',
				"paths": {}
			},
			'extras': {
				"topDomain": 'extras.'+document.domain,
				"contentDomain": 'site.extras.'+document.domain,
				"paths": {}
			},
			'forum': {
				"topDomain": 'forum.'+document.domain,
				"contentDomain": 'site.forum.'+document.domain+'/jive3',
				"paths": {}
			},
			'games': {
				"topDomain": 'games.'+document.domain,
				"contentDomain": 'site.games.'+document.domain,
				"paths": {
					'wallettx': '/gamex/DepositFundsPopup.do?sizeX=350&sizeY=285',
					'mygamesaccount': '/account/MyAccount.do?tabID=1&sizeX=788&sizeY=500',
					'doLogout': '/account/login/GamesLogoutAction.do'
				}
			},
			'greyhounds': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=4339',
				"paths": {}
			},
			'horses': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=7',
				"paths": {}
			},
			'icehockey': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=7524',
				"paths": {}
			},
			'multiples': {
				"topDomain": 'multiples.'+document.domain,
				"contentDomain": 'site.multiples.'+document.domain,
				"paths": {}
			},
			'myaccount': {
				"topDomain": 'www.'+document.domain,
				"contentDomain": 'www.'+document.domain+'/myaccount',
				"paths": {
					'cardCountries': '/payment/CardCountries.do',
					'cvv2': '/payment/Cv2.do',
					'cardPolicy': '/payment/CardPolicy.do'
				}
			},
			'othersports': {
				"topDomain": 'othersports.'+document.domain,
				"contentDomain": 'othersports.'+document.domain,
				"paths": {}
			},
			'payment': {
				"topDomain": 'payment.'+document.domain,
				"contentDomain": 'site.payment.'+document.domain,
				"paths": {}
			},
			'poker': {
				"topDomain": 'poker.'+document.domain,
				"contentDomain": 'site.poker.'+document.domain,
				"paths": {}
			},
			'politics': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=2378961',
				"paths": {}
			},
			'portal': {
				"topDomain": 'www.'+document.domain,
				"contentDomain": 'www.'+document.domain,
				"paths": {
					'wallettx': '/myaccount/wallet/TransferView.do?sizeX=520&sizeY=520',
					'lostpasswd': '/account/forgotpassword/ForgottenPassword.do?method=initialise',
					'forum': '/account/ForumRedirect.do',
					'openaccount': '/myaccount/account/registration/BeginRegistration.do',
					'myaccount': '/myaccount/account/MyAccount.do',
					'home': '/PortalHomePage.do'
				}
			},
			'rugbyunion': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=5',
				"paths": {}
			},
			'snooker': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=6422',
				"paths": {}
			},
			'soccer': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=1',
				"paths": {}
			},
			'sports': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain,
				"paths": {}
			},
			'tennis': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=2',
				"paths": {}
			},
			'tote': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?toteID=UK',
				"paths": {}
			},
			'toteaus': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?toteID=AUS',
				"paths": {}
			},
			'toteirl': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?toteID=IRL',
				"paths": {}
			},
			'toteuk': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?toteID=UK',
				"paths": {}
			},
			'widgets': {
				"topDomain": 'site.sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain,
				"paths": {}
			},
			'volleyball': {
				"topDomain": 'sports.'+document.domain,
				"contentDomain": 'site.sports.'+document.domain+'?ti=998917',
				"paths": {}
			}
		},
		"linkConfig": {
			"aboutUs": {
				"url": "[[contentURL]]aboutus/?product=exchange[[cookieInfo]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"aboutUsTermsAndConditions": {
				"url": "[[contentURL]]aboutus/?product=exchange&sWhichKey=Terms and Conditions[[cookieInfo]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"affiliateScheme": {
				"url": "http://www.betfairpromo.com/demo2/[[locale]]/index.html",
				"autoscroll": true,
				"dimensions": {"X": 788, "Y": 500}
			},
			"ageRestriction": {
				"url": "/account/registration/AgeRestriction.do",
				"autoscroll": false,
				"dimensions": {"X": 300, "Y": 250}
			},
			"betfairOverview": {
				"url": "http://www.betfairpromo.com/demo/index.asp?locale=[[1]]",
				"autoscroll": true,
				"dimensions": {"X": 730, "Y": 480}
			},
			"bettingGuide": {
				"url": "[[contentURL]]downloads/[[locale]]/Betfair_Guide_to_Betting.pdf",
				"autoscroll": false,
				"dimensions": {"X": 800, "Y": 600}
			},
			"cardCountries": {
				"url": "/payment/CardCountries.do",
				"autoscroll": false,
				"dimensions": {"X": 270, "Y": 420}
			},
			"cmsContactUs": {
				"url": "[[contentURL]]aboutus/?product=exchange[[cookieInfo]]&sWhichKey=Contact Us",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"commission": {
				"url": "[[contentURL]]help/?product=exchange[[cookieInfo]]&sWhichKey=Help.Managing.Account&sWhichAnchor=CommissionPoints",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"cvv2": {
				"url": "/payment/Cv2.do",
				"autoscroll": false,
				"dimensions": {"X": 470, "Y": 380}
			},
			"deepMarketLink": {
				"url": "http://[[singlesDomain]][[1]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"deposit": {
				"url": "/myaccount/payment/CardDeposit.do?formaction=form",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"exchangePokerGameHistory": {
				"url": "/exchangepoker/LoadExchangePokerHistoryAction.do[[1]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"exchangeWebHomePage": {
				"url": "[[singlesDomain]]",
				"autoscroll": false,
				"dimensions": {"X": 800, "Y": 600},
				"statusBar": true,
				"menuBar": true,
				"toolbar": true
			},
			"faqs": {
				"url": "[[contentURL]]faqs/?product=exchange[[cookieInfo]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"forum": {
				"constructUrl": {
					"appName": "forum"
				},
				"autoscroll": true,
				"dimensions": {"X": 788, "Y": 500}
			},
			"forgottenPassword": {
				"constructUrlWithPath": {
					"appName": "portal",
					"pathName": "lostpasswd"
				},
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"marketUnavailable": {
				"url": "/MarketUnavailable.do",
				"autoscroll": false,
				"dimensions": {"X": 600, "Y": 400}
			},
			"myAccountHeader": {
				"constructUrlWithPath": {
					"appName": "portal",
					"pathName": "myaccount"
				},
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 575},
				"statusBar": false
			},
			"myAccount": {
				"url": "[[1]][[2]][[3]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 575},
				"statusBar": false
			},
			"myAccountAgeVerification": {
				"constructUrlWithPath": {
					"appName": "portal",
					"pathName": "myaccount",
					"isSecure": true
				},
				"extraParams": "?tabID=15",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 575},
				"statusBar": false
			},
			"myAccountFromRegistration": {
				"url": "[[1]][[2]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 575},
				"statusBar": false
			},
			"myCasinoAcc": {
				"constructUrlWithPath": {
					"appName": "casino",
					"pathName": "mycasinoaccount"
				},
				"autoscroll": true,
				"dimensions": {"X": 700, "Y": 535}
			},
			"myCasinoAccTransfer": {
				"constructUrlWithPath": {
					"appName": "casino",
					"pathName": "popLogoutTx"
				},
				"autoscroll": true,
				"dimensions": {"X": 800, "Y": 600}
			},
			"myGamesAcc": {
				"constructUrlWithPath": {
					"appName": "games",
					"pathName": "mygamesaccount"
				},
				"autoscroll": false,
				"dimensions": {"X": 700, "Y": 535}
			},
			"netellerWithdrawalHelp": {
				"url": "/payment/netellerWithdrawalHelp.do",
				"autoscroll": false,
				"dimensions": {"X": 470, "Y": 280}
			},
			"newHelp": {
				"url": "[[1]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500}
			},
			"oddsEquivalent": {
				"url": "[[1]]",
				"autoscroll": false,
				"dimensions": {"X": 700, "Y": 500}
			},
			"openAcc": {
				"constructUrlWithPath": {
					"appName": "account",
					"pathName": "openaccount",
					"isSecure": true
				},
				"extraParams": "?origin=[[1]][[2]]",
				"autoscroll": true,
				"dimensions": {"X": 738, "Y": 700}
			},
			"queens": {
				"url": "[[contentURL]]aboutus/?product=exchange[[cookieInfo]]",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 600}
			},
			"radio": {
				"url": "[[radioURL]]",
				"autoscroll": false,
				"dimensions": {"X": 405, "Y": 480}
			},
			"timeform": {
				"url": "[[timeFormURL]]",
				"autoscroll": true,
				"dimensions": {"X": 800, "Y": 600}
			},
			"trustDeed": {
				"url": "[[contentURL]]aboutus/?product=exchange[[cookieInfo]]&sWhichKey=Trust Deed",
				"autoscroll": false,
				"dimensions": {"X": 788, "Y": 500 }
			},
			"video": {
				"url": "[[videoURL]]",
				"extraParams": "?Default.do?eID=[[2]]",
				"autoscroll": true,
				"dimensions": {"X": 920, "Y": 650 }
			},
			"walletTransfer": {
				"url": "[[1]]?transfer=1",
				"autoscroll": true,
				"dimensions": {"X": 520, "Y": 420 }
			}
		}
	};

	var windowRegister = {};

	function getValueMap() {
		var userAccId = betfair.User.getData("accountId");

		var dynValueMap = {
			"cookieInfo": getCookieInfo(false),
			"region": betfair.CookieManager.get("betexRegionSessionCookie", userAccId),
			"locale": betfair.CookieManager.get("betexLocaleSessionCookie", userAccId),
			"brand": betfair.CookieManager.get("betexBrand", userAccId),
			"timeZoneId": betfair.CookieManager.get("betexTimeZoneSessionCookie", userAccId),
			"currency": betfair.CookieManager.get("betexCurrencySessionCookie", userAccId)
		};

		var item;
		for(item in betfair.Config.paths.popupWindows) {
			dynValueMap[item] = betfair.Config.paths.popupWindows[item];
		}

		return dynValueMap;
	}

	function open(windowId) {
		var valueMap = getValueMap();

		for(var i=0; i<arguments.length; i++) {
			valueMap["" + i] = arguments[i];
		}

		var winConfig = windowConfig.linkConfig[windowId];
		var url, queryStringInfo;
		if(winConfig) {
			//popup is defined properly in windowConfig.linkConfig object.
			var details;

			url = [];

			if(winConfig.url) {
				//replace url template variables with values
				url.push(replaceUrlTemplateValues(winConfig.url, valueMap));
			} else if(winConfig.constructUrl) {
				details = winConfig.constructUrl;
				url.push(constructUrl(details.appName, details.isSecure));
			} else if(winConfig.constructUrlWithPath) {
				details = winConfig.constructUrlWithPath;
				url.push(constructUrlWithPath(details.appName, details.pathName, details.isSecure));
			} else { return; }

			if(winConfig.extraParams) {
				url.push(replaceUrlTemplateValues(winConfig.extraParams, valueMap));
			}

			getWindow(windowId, url.join(""), winConfig);

		} else {
			//we have to use a function to generate the url.
			switch(windowId) {
				case "betBreakdown":
					queryStringInfo = ["?betId=",arguments[1]];
					if(arguments[2] !== null) {
						queryStringInfo.push("&subAccountID=",arguments[2]);
					}
					getWindow(windowId, ("/reporting/bethistory/LoadBetBreakdownAction.do" + queryStringInfo.join("")), {"autoscroll": false, "dimensions": {"X":300, "Y":620}});
					break;
				case "help":
					if((arguments[1] === "Help.Contact.Us") && !arguments[2]) {
						open("cmsContactUs");
					} else {
						queryStringInfo = ["help/?product=exchange",getCookieInfo(false)];
						if(valueMap.locale === "cz" && arguments[1] === "Help.Betfair.Internet.Betting") {
							valueMap.contentURL = "http://help.betfairinfo.cz/?p=61";
							queryStringInfo = [];
						} else if(arguments[1] !== "GHL") {
							queryStringInfo.push("&sWhichKey=",arguments[1],"&sWhichAnchor=",arguments[2]);
						} else if(valueMap.locale === "cz") {
							valueMap.contentURL = "http://help.betfairinfo.cz";
							queryStringInfo = [];
						} else {
							queryStringInfo.push("&origin=",arguments[1]);
						}
						url = valueMap.contentURL + queryStringInfo.join("");
						getWindow(windowId, url, {"autoscroll": false, "dimensions": {"X":788, "Y":500}});
					}
					break;
				case "joinNow":
					url = [];
					if(arguments[1] && arguments[1] !== "") {
						url.push("?",arguments[1],"=",arguments[2]);
					}
					getWindow(windowId, url, {"autoscroll": true, "dimensions": {"X":700, "Y":738}, "statusBar": true});
					break;
				case "moreInfoChart":
					queryStringInfo = "&timeZone=" + betfair.CookieManager.get("betexTimeZoneSessionCookie", "") + getCookieInfo(false) + "&currency=" + betfair.CookieManager.get("betexCurrencySessionCookie", "");

					var baseURL = ((arguments[2]) ? arguments[2] : "");
					getWindow(windowId, (baseURL + "/betting/LoadRunnerInfoAction.do" + arguments[1] + queryStringInfo), {"autoscroll": false, "dimensions": {"X":500, "Y":700}});
					break;
				case "payments":
					url = ["http://payments.betfair.com"];
					if(arguments[1] && arguments[2] && arguments[1] !== "" && arguments[2] !== "") {
						url.push("?",arguments[1],"=",arguments[2]);
					}
					if(arguments.length > 3 && typeof(arguments[3]) != "undefined") {
						getWindow(windowId, arguments[3], {"autoscroll": true, "dimensions": {"X":600, "Y":800}});
					} else {
						var region = betfair.CookieManager.get("betexRegionSessionCookie", "");
						getWindow(windowId, url.join(""), {"autoscroll": true, "dimensions": {"X":600, "Y":800}});
					}
					break;
		 		case "placingABet":
		 			var local = {
		 				"config": {"autoscroll": true, "dimensions": {"X":460,"Y":727}},
		 				"url": "http://promo.betfair.com/demo/index.asp?locale=" + arguments[1]
		 			};
					switch(arguments[1]) {
						case "bg":
						case "cz":
						case "da":
						case "de":
						case "el":
						case "es":
						case "fi":
						case "it":
						case "no":
						case "pl":
						case "pt":
						case "ru":
						case "tr":
						case "zh":
							break;
						case "en":
							local.url = "http://www.betfairpromo.com/learnbetfair";
							local.config = {"autoscroll": true, "dimensions": {"X":581,"Y":650}};
							break;
						case "sv":
							local.url = "http://promo.betfair.com/demo/index.asp?locale=se";
							break;
						case "zh_TW":
							local.url = "http://promo.betfair.com/demo/index.asp?locale=cn";
							break;
						default:
							local.url = "http://www.betfairpromo.com/learnbetfair";
							local.config = {"autoscroll": true, "dimensions": {"X":581,"Y":650}};
							break;
					}
		 			getWindow(windowId, local.url, local.config);
		 			break;
				case "priceComparison":
					url = ["/PriceComparison.do"];
					if(arguments[1] && arguments[2] && arguments[1] !== "" && arguments[2] !== "") {
						url.push("?",arguments[1],"=",arguments[2]);
					}
					getWindow(windowId, url.join(""), {"autoscroll": false, "dimensions": {"X":600, "Y":850}});
					break;
				case "privacyPolicy":
					url = ['aboutus/?product=exchange',getCookieInfo(false)];
					if(arguments[1] && arguments[1] !== "") {
						url.push("&jumpTo=",arguments[1]);
					}
					if(arguments[2] && arguments[3] && arguments[2] !== "" && arguments[3] !== "") {
						url.push("&",arguments[2],"=",arguments[3]);
					}
					url.push("&sWhichKey=Privacy Policy");
					getWindow(windowId, (valueMap.contentURL + url.join("")), {"autoscroll": false, "dimensions": {"X":500, "Y":788}});
					break;
		 		case "transfer":
					//set default to "portal" for transfers
					url = "http://www."+document.domain+"/myaccount/wallet/TransferView.do?sizeX=520&sizeY=520";
					var currentApplication = windowConfig.domains[top.productName];
					if(currentApplication && currentApplication.paths["wallettx"]) {
						url = constructUrlWithPath(top.productName, 'wallettx', true);
					}
					getWindow(windowId, url, {"autoscroll": false, "dimensions": getDimensions(url)});
			 		break;
		 		case "onCasinoLogin":
		 			getWindow(windowId, "http://site.casino."+document.domain+"/MyAccount.do?panel=transferin", {"autoscroll": false, "dimensions": {"X":600, "Y":800}});
		 			break;
		 		case "onCasinoLogout":
		 			getWindow(windowId, "http://site.casino."+document.domain+"/account/logout/CheckBalanceAction.do?transferFundsQuestion=true", {"autoscroll": false, "dimensions":  {"X":800, "Y":600}});
			 		break;
			 	default:
			 		break;
			}
		}
	}

	function openProgressive(windowId, url, windowConfig) {
		var valueMap = getValueMap();

		// properties defined as class attributes within the anchor tag.
		windowConfig.position = {
			"X": ((windowConfig.left && (parseInt(windowConfig.left,10) >= 0)) ? windowConfig.left : -1),
			"Y": ((windowConfig.top && (parseInt(windowConfig.top,10) >= 0)) ? windowConfig.top : -1)
		};

		windowConfig.dimensions = {
			"X": (windowConfig.width ? windowConfig.width : 640),
			"Y": (windowConfig.height ? windowConfig.height : 480)
		};

		var tokenReplacementRegEx = new RegExp("\[\[(.+?)\]\]", "ig");
		if(tokenReplacementRegEx.test(url)) {
			replaceUrlTemplateValues(url, valueMap);
		}

		getWindow(windowId, url, windowConfig);
	}

	function close(windowId) {
		if(windowRegister[windowId]) {
			windowRegister[windowId].close();
		}
	}

	function getCookieInfo(isFirstQuerystringParameter) {
		var url = [isFirstQuerystringParameter ? "?" : "&"];
		var userAccId = betfair.User.getData("accountId");

		var betexRegionSessionCookie = betfair.CookieManager.get("betexRegionSessionCookie", userAccId);
		var betexLocaleSessionCookie = betfair.CookieManager.get("betexLocaleSessionCookie", userAccId);
		var betexBrand = betfair.CookieManager.get("betexBrand", userAccId);

		url.push((url.length > 1 ? "&" : ""), (betexRegionSessionCookie ? ("region=" + betexRegionSessionCookie) : ""));
		url.push((url.length > 1 ? "&" : ""), (betexLocaleSessionCookie ? ("locale=" + betexLocaleSessionCookie) : ""));
		url.push((url.length > 1 ? "&" : ""), (betexBrand ? ("brand=" + betexBrand) : ""));

		return url.join("");
	}

	function replaceUrlTemplateValues(url, valueMap) {
		var output = url, stBrace = "\\[\\[", fnBrace = "\\]\\]", template;
		for(var i in valueMap) {
			template = new RegExp(stBrace + i + fnBrace,"g");
			output = output.replace(template, valueMap[i]);
		}
		// remove any remaining, unmatched placeholder tokens
		return output.replace(/\[\[.*\]\]/, "");
	}

	function getDimensions(url) {
		var dimensions = {"X": 712, "Y": 460};
		var regexTokens = ["size","=([\\d]+)"];
		var i, regex, result;
		for(i in dimensions) {
			regex = new RegExp(regexTokens[0] + i + regexTokens[1]);
			result = regex.exec(url);
			if(result && result.length === 2) {
				dimensions[i] = result[1];
			}
		}
		return dimensions;
	}

	function getWindow(windowId, url, windowConfig) {
		if(windowRegister[windowId] && !windowRegister[windowId].closed) {
			windowRegister[windowId].location = url;
			windowRegister[windowId].focus();
			return windowRegister[windowId];
		} else {
			try {
				if(typeof(windowConfig.position) === "undefined" || (windowConfig.position.X === -1 || windowConfig.position.Y === -1)) {
					windowConfig.position = {
						"X": ((screen.availWidth - windowConfig.dimensions.X) / 2),
						"Y": ((screen.availHeight - windowConfig.dimensions.Y) / 2)
					};
				}

				var params = [
					"width=",windowConfig.dimensions.X,
					",height=",windowConfig.dimensions.Y,
					",left=",windowConfig.position.X,
					",top=",windowConfig.position.Y,
					",screenX=",windowConfig.position.X,
					",screenY=",windowConfig.position.Y,
					",scrollbars=",(windowConfig.autoscroll ? "yes" : "no"),
					",status=",(windowConfig.statusBar ? "yes" : "no"),
					",resizable=yes",
					",menubar=",(windowConfig.menuBar ? "yes" : "no"),
					",toolbar=",(windowConfig.toolBar ? "yes" : "no"),
					",location=",(windowConfig.locationBar ? "yes" : "no"),
					",titlebar=yes')"
				].join("");

				windowRegister[windowId] = top.window.open(url, windowId, params);
				return windowRegister[windowId];
			} catch(x) {
				alert("We could not open the window you requested. Please attempt re-configuring your firewall or ad-blocker and try again.");
				return null;
			}
		}
	}

	function getTopDomain(appName) {
		if(windowConfig.domains[appName]) {
			return windowConfig.domains[appName].topDomain;
		}
	}

	function prependProtocol(url, isSecure) {
		return "http" + (isSecure ? "s" : "") + "://" + url;
	}

	function constructUrl(appName, isSecure) {
		if(windowConfig.domains[appName]) {
			return prependProtocol(windowConfig.domains[appName].contentDomain, isSecure);
		}
	}

	function constructUrlWithPath(appName, pathName, isSecure) {
		if(windowConfig.domains[appName]) {
			var url = [windowConfig.domains[appName].contentDomain];
			if(windowConfig.domains[appName].paths[pathName]) {
				url.push(windowConfig.domains[appName].paths[pathName]);
			} else {
				url.push("/",pathName);
			}
			return prependProtocol(url.join(""), isSecure);
		}
	}

	return {
		"open": open,
		"openProgressive": openProgressive,
		"close": close
	};
})();
betfair.RestrictedCountry = (function() {
	var eventHandler = new betfair.Events.delegate( {
		DOM: [ { element: window, eventType: "load", handler: checkRestrictedCountry } ]
	}, true ),
		messageContainer, mask;
	
	function checkRestrictedCountry() {
		//check the cookie
		var cookieValue = betfair.CookieManager.get("restrictedCountry");
		if (cookieValue === "true") {
			createMessage();
			createMask();
			showMessage();
		}
	}
	
	function createMessage() {
		messageContainer = document.createElement("div");
		messageContainer.id = "restrictedCountry";
		messageContainer.innerHTML =	"<iframe src=\"http://cache.betfair.com/www/betfair/GBR/zh_TW/prospect/restrictedCountry.html\"" + 
										"scrolling=\"no\" marginwidth=\"0\" marginheight=\"0\" frameborder=\"0\"></iframe>" + 
										"<div><input type=\"button\" value=\"OK\" id=\"restrictedCountryOK\" /></div>";
	}
	
	function createMask() {
		var winHeight = (function() {
			if (window.innerWidth) {
				return window.innerHeight;
			} else if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientHeight !== 0) {
				return document.documentElement.clientHeight;
			}
			return 0;
		})();
		mask = document.createElement("div");
		mask.id = "restrictedCountryMask";
		mask.style.height = Math.max(document.body.offsetHeight, winHeight) + "px";
	}
	
	function showMessage() {
		document.body.appendChild(mask);
		document.body.appendChild(messageContainer);
		eventHandler.addListeners( {
			DOM: [ {element: document.getElementById("restrictedCountryOK"), eventType: "click", handler: handleOK} ]
		}, true );
	}
	
	function handleOK() {
		eventHandler.unRegisterAllListeners();
		messageContainer.parentNode.removeChild(messageContainer);
		mask.parentNode.removeChild(mask);
	}
})();