/* BEGIN: GLOBAL */

// Global/framework.js
//
// Base framework for all Web Applications
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

// Array Support
if (!Array.indexOf) {
	Array.prototype.indexOf = function (obj) {
		var i;
		for (i = 0; i < this.length; i++) {
			if (this[i] == obj) {
				return i;
			}
		}
		return -1;
	};
}

// RGBA Support
function testRGBASupport ()
{
	var element = document.createElement("a");
	try {
		element.style.backgroundColor = 'rgba(0,0,0,0)';
		return true;
	} catch (err) {
		return false;
	}
}

// Chrome Frame Support
var gcfCheck = function ()
{
};

// REAL Studio Namespace
var RS = {
	version: 4,
	mode: 1,
	begin: function () {},
	init: function () {},
	getElementID: function () {},
	postLoadObjects: [],
	wheelTargets: [],
	refreshObjects: [],
	imageCache: [],
	controls: [],
	loaders: [],
	pageWindows: [],
	styleSheetLookups: [],
	changedFields: [],
	holdInterval: null,
	holdOffset: null,
	dragTarget: null,
	dragCallback: null,
	activeLoader: null,
	pageID: null,
	pageFinishedLoading: false,
	appURL: '',
	sessionURL: '',
	sessionID: '',
	refreshLocks: 0,
	serializer: null,
	rgbaSupported: testRGBASupport(),
	opacitySupported: true,
	stopInit: false,
	platform: -1,
	engine: -1,
	browser: -1,
	interactionAllowed: true,
	view: {},
	comm: {},
	menus: {},
	input: {
		begin: function () {},
		move: function () {},
		end: function () {},
		enter: function () {},
		exit: function () {},
		install: function () {},
		isTouchUI: function () {},
		getCoordinates: function () {},
		refireMove: function () {},
		forwardEvent: function () {},
		mouseEventData: function () {},
		doubleClick: function() {},
		keyDown: function () {},
		keyUp: function () {},
		keyPress: function () {},
		keyQueue: [],
		setFocusControl: function () {},
		mIsTouchUI: false,
		target: null,
		holdInterval: 0,
		lastCoordinates: [],
		lastEvent: null,
		setLastEvent: function () {},
		installedElements: [],
		pointerTarget: null,
		focusControl: null,
		touchHandler: function() {}
	},
	console: {
		error: function () {},
		log: function () {},
		present: function () {},
		dismiss: function () {},
		isVisible: function () {},
		submit: function () {},
		mIsVisible: false
	},
	events: {
		addListener: function () {},
		removeListener: function () {},
		preventDefault: function () {},
		stopPropagation: function () {},
		fireEvent: function() {}
	},
	DOM: {
		addClass: function () {},
		removeClass: function () {},
		getAppliedStyle: function () {},
		getArrayOfClassNames: function () {},
		hasClass: function () {},
		get: function() {},
		getElementsByClassName: function() {}
	},
	utils: {
		toCamelCase: function() {},
		toHyphens: function() {},
		tabCapture: function() {}
	},
	ua: { }
};

// Communication functions
RS.comm = {
	begin: function () {
		try {
			if(RS.mode == 1) {
				RS.comm.websockets.didConnect = false;
				var host = 'ws://' + window.location.host + '/' + RS.sessionID + "/comm/push";
				var sock = new WebSocket(host);
				sock.onopen = function (event) {
					clearTimeout(RS.comm.websockets.timeout);
					RS.comm.websockets.didConnect = true;
					RS.comm.sendOpen();
				};
				sock.onerror = function (event) {
					clearTimeout(RS.comm.websockets.timeout);
					RS.comm.ajax.begin();
				};
				sock.onclose = function () {
					if(RS.comm.websockets.didConnect) {
						//if it connected before, try again.
						RS.comm.begin(); 				
					} else {	
						clearTimeout(RS.comm.websockets.timeout);
						RS.comm.ajax.begin();
					}
				};
				sock.onmessage = function (event) {
					clearTimeout(RS.comm.websockets.timeout);
					RS.comm.processResponse(event.data);
				};
				
				RS.comm.websockets.socket = sock;
				//timeout for browsers using new websocket protocol w/ no fallback
				RS.comm.websockets.socket.timeout = setTimeout(RS.comm.websockets.socket.onerror,3000); 
			} else {
				RS.comm.ajax.begin();
			}
		} catch (wsErr) {
			RS.comm.ajax.begin();
		}
	},
	sendOpen: function () {
		if (RS.comm.inited === false) {
			RS.view.setLoaderState(2);
			var currentDate = new Date();
			var offset;
			if (currentDate.getTimeZoneOffset) {
				offset = currentDate.getTimeZoneOffset();
			} else {
				offset = currentDate.getTimezoneOffset();
				offset = offset / 60;
			}
			offset = offset * -1;
			
			var dimensions = RS.view.sizing.dimensions();
			
			var userdata = [];
			userdata.push(dimensions.width);
			userdata.push(dimensions.height);
			userdata.push(offset);
			userdata.push(window.location.hash);
			
			RS.comm.triggerEvent('Event','Open',userdata);
			RS.comm.inited = true;
			RS.view.monitorHashTag(window.location.hash);
		}
	},
	triggerEvent: function (control,event,userdata,ev) {
		var url = RS.sessionURL + '/comm/event/';
		if ((control !== null) && (control !== '')) {
			url = url + control + '.' + event;
		}
		
		if ((!userdata) || (userdata.constructor.toString().indexOf('Array') === -1)) {
			userdata = [];
		}
		
		var queries = prepareFormData(RS.changedFields);
		queries.push('params=' + encodeURIComponent(userdata.join('&')));
		RS.changedFields = [];
		
		if (RS.comm.websockets.connected() === true) {
			queries.push('url=' + url);
			queries.push('WSCookies=' + document.cookie);
			RS.comm.websockets.socket.send(queries.join('&'));
		} else {
			var xhr;
			if (window.XMLHttpRequest) {
				xhr = new XMLHttpRequest();
			} else {
				RS.console.error("This browser does not support AJAX.");
				return;
			}
			
			xhr.open('POST',url,true);
			xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
			xhr.setRequestHeader('Cache-Control','no-cache');
			xhr.onreadystatechange = function () {
				if (this.readyState === 4) {
					if (this.status === 200) {
						RS.comm.processResponse(this.responseText);
					} else if (this.status === 404) {
						RS.console.log("Requested content was not found.");
					} else {
						RS.console.log("HTTP Error: " + this.statusText);
					}
				}
			};
			xhr.send(queries.join('&'));
		}
	},
	processResponse: function (response) {
		var obj;
		try {
			obj = eval("(" + response + ")");
		} catch (jsonErr) {
			RS.console.error("Trouble evaluating response: " + jsonErr.message + "\nSource: " + response);
			return null;
		}
		
		// update the html
		var c = obj.html.length;
		var i = 0;
		var parent, target, o;
		for (i = 0; i < c; i++) {
			o = obj.html[i];
			
			parent = document.getElementById(o.parent);
			target = document.createElement('div');
			target.innerHTML = o.source;
			target = target.children[0];
			
			if (parent) {
				switch (o.mode) {
				case '1': // source should replace parent content
					parent.innerHTML = o.source;
					break;
				case '2': // source should be appended to parent content
					parent.appendChild(target);
					break;
				case '3': // source should be prepended to parent content
					parent.insertBefore(target,parent.firstChild);
					break;
				case '4': // parent should be removed
					if (parent.parentNode) {
						parent.parentNode.removeChild(parent);
					}
					break;
				case '5': // source should replace parent
					if (parent.parentNode) {
						var destination = parent.parentNode;
						destination.removeChild(parent);
						destination.appendChild(target);
					}
					break;
				}
			}
		}
		
		// insert css
		var css = obj.cssSource;
		var cssID = obj.cssID || "";
		createStyleSheet(css,cssID);
		
		// execute the returned javascript
		if (obj.jsSource !== '' ) {
			RS.view.refresh.lock();
			try {
				eval(obj.jsSource);
			} catch (jsErr) {
				RS.console.error("Could not execute returned javascript: " + jsErr.message + "\nSource: " + obj.jsSource);
			}
			RS.view.refresh.unlock();
		}
		
		// done
		didFinishLoading();
		
		// execute post-load
		var object;
		for (i = 0; i < RS.postLoadObjects.length; i++) {
			object = RS.postLoadObjects[i];
			object.postLoad();
		}
		
		return obj;
	},
	ajax: {
		begin: function () {
			RS.comm.sendOpen();
			
			if ((RS.comm.websockets.connected() === true) || (RS.comm.ajax.xhr !== null)) {
				return;
			}
			
			var xhr;
			if (window.XMLHttpRequest) {
				xhr = new XMLHttpRequest();
			} else {
				return;
			}
			
			xhr.open('POST',RS.sessionURL + '/comm/push',true);
			xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
			xhr.setRequestHeader('Cache-Control','no-cache');
			xhr.onreadystatechange = function () {
				if (this.readyState === 4) {
					RS.comm.ajax.xhr = null;
					if (this.status === 200) {
						RS.comm.processResponse(this.responseText);
					} else {
						setTimeout(RS.comm.ajax.ping,3000);
					}
				}
			};
			xhr.send();
			
			RS.comm.ajax.xhr = xhr;
		},
		end: function (gracefully) {
			if (gracefully === null) {
				gracefully = false;
			}
			if (RS.comm.ajax.xhr) {
				RS.comm.ajax.xhr.abort();
				RS.comm.ajax.xhr = null;
				if (gracefully === false) {
					preventPageInteraction();
				}
			}
		},
		ping: function () {
			var xhr;
			if (window.XMLHttpRequest) {
				xhr = new XMLHttpRequest();
			} else {
				return;
			}
			
			xhr.open('POST',RS.sessionURL + '/comm/ping',true);
			xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
			xhr.setRequestHeader('Cache-Control','no-cache');
			xhr.onreadystatechange = function () {
				if (this.readyState === 4) {
					if (this.status === 200) {
						RS.comm.processResponse(this.responseText);
					} else {
						RS.view.preventInteraction();
					}
				}
			};
			xhr.send();
		},
		xhr: null
	},
	websockets: {
		connected: function () {
			if ((RS.comm.websockets.socket !== null) && (RS.comm.websockets.socket.readyState === 1)) {
				return true;
			} else {
				return false;
			}
		},
		socket: null
	},
	terminate: function () {
		if (RS.comm.websockets.connected() === true) {
			RS.comm.websockets.socket.onclose = function () {};
			RS.comm.websockets.socket.close();
		}
		if (RS.comm.ajax.xhr !== null) {
			RS.comm.ajax.xhr.abort();
			RS.comm.ajax.xhr = null;
		}
		RS.view.preventInteraction();
	},
	inited: false
};

// View Control
RS.view = {
	showOverlay: function () {
		if (RS.view.overlayCount == 0) {
			var overlay = document.getElementById('REALOverlay');
			if (overlay) {
				overlay.style.display = 'block';
			}
			
			RS.view.preventScrolling();
		}
		RS.view.overlayCount = RS.view.overlayCount + 1;
	},
	hideOverlay: function () {
		if (RS.view.overlayCount <= 0) {
			return;
		}
		
		RS.view.overlayCount = RS.view.overlayCount - 1;
		
		if (RS.view.overlayCount == 0) {
			var overlay = document.getElementById('REALOverlay');
			if (overlay) {
				overlay.style.display = 'none';
			}
			
			RS.view.allowScrolling();
		}
	},
	overlayCount: 1,
	preventScrolling: function () {
		RS.menus.dismissAllMenus();
		if (RS.view.scrollPreventionCount === 0) {
			var container = document.getElementById('REALContainer');
			if (container) {
				container.style.minWidth = '100%';
				container.style.minHeight = '100%';
			}
		}
		RS.view.scrollPreventionCount = RS.view.scrollPreventionCount + 1;
	},
	allowScrolling: function () {
		RS.menus.dismissAllMenus();
		if (RS.view.scrollPreventionCount <= 0) {
			return;
		}
		
		RS.view.scrollPreventionCount = RS.view.scrollPreventionCount - 1;
		
		if (RS.view.scrollPreventionCount === 0) {
			var container = document.getElementById('REALContainer');
			var page = document.getElementById(RS.view.currentPage);
			if ((container) && (page)) {
				container.style.minWidth = page.style.minWidth;
				container.style.minHeight = page.style.minHeight;
			}
		}
	},
	scrollPreventionCount: 1,
	dismissLoader: function () {
		try { clearTimeout(loaderTimeout); } catch(err) { }
		RS.view.setLoaderState(3);
		document.getElementById('REALLoader').style.top = '100%';
		setTimeout("document.getElementById('REALLoader').style.display = 'none'",100);
		setTimeout(RS.view.hideOverlay,101);
	},
	setLoaderState: function (state) {
		var bar = document.getElementById('REALLoaderBar');
		bar.style.backgroundPosition = '0px -' + (state * 21) + 'px';
	},
	showPage: function (pageID) {
		if (RS.view.currentPage !== '') {
			var el = document.getElementById(RS.view.currentPage);
			if (el) {
				el.style.display = 'none';
			}
			RS.comm.triggerEvent(RS.view.currentPage,'Hidden');
		}
		
		var page = document.getElementById(pageID);
		var container = document.getElementById('REALPages');
		container.style.minWidth = page.style.minWidth;
		container.style.minHeight = page.style.minHeight;
		
		var container = document.getElementById('REALContainer');
		container.style.minWidth = page.style.minWidth;
		container.style.minHeight = page.style.minHeight;
		
		RS.view.currentPage = pageID;
		page.style.left = '0';
		page.style.display = '';
		
		RS.comm.triggerEvent(pageID,'Shown');
	},
	setStatus: function (message) {
		try {
			window.status = message;
		} catch (statErr) {
		}
	},
	setHashTag: function (hash) {
		RS.view.lastHashTag = hash;
		window.location.hash = hash;
	},
	monitorHashTag: function (startingTag) {
		RS.view.lastHashTag = startingTag;
		
		var fn = function () {
			if (window.location.hash != RS.view.lastHashTag) {
				RS.view.lastHashTag = window.location.hash;
				RS.comm.triggerEvent('Event','HashTagChanged',[window.location.hash]);
			}
		};
		if("onhashchange" in window) {
			RS.events.addListener(window,"hashchange",fn,false);
		} else {
			setInterval(fn,250);
		}
	},
	preventInteraction: function () {
		RS.view.showOverlay();
		var blocker = document.getElementById('REALDisconnect');
		if ((blocker) && (blocker.style.display !== 'block')) {
			blocker.style.display = 'block';
			setTimeout("document.getElementById('REALDisconnect').style.top = '0%'",10);
			
			//Stop any controls that continue to cause events to fire
			for(i=0;i<RS.controls.length;i++) {
				var ctl = RS.controls[i];
				try { if(ctl.constructor == timer) { RS.controls[i].setMode(0); }} catch(err) { }
				try { if(ctl.constructor == movieplayer) {
						var id=RS.controls[i].controlID;
						var el = document.getElementById(id);
						el.parentNode.removeChild(el);  }} catch(err) { }
				try { if(ctl.constructor == spinner) { ctl.setEnabled(false); }} catch(err) { }
			}			
		}
	},
	allowInteraction: function () {
		var blocker = document.getElementById('REALDisconnect');
		if ((blocker) && (blocker.style.display === 'block')) {
			blocker.style.top = '100%';
			setTimeout("document.getElementById('REALDisconnect').style.display = 'none'",10);
			setTimeout(RS.view.hideOverlay,11);
		}
	},
	handleConfirmation: function (event) {
		if ((RS.view.confirmationText !== null) && (RS.view.confirmationText !== '')) {
			var r = RS.view.confirmationText;
			event = event || window.event;
			if (event !== null) {
				event.returnValue = r;
			}
			return r;
		}
	},
	confirmationText: null,
	currentPage: '',
	lastHashTag: '',
	sizing: {
		resized: function () {
			RS.menus.dismissAllMenus();
			if (RS.view.sizing.notifyDelay !== 0) {
				clearTimeout(RS.view.sizing.notifyDelay);
			}
			RS.view.sizing.notifyControls(false);
			RS.view.sizing.notifyDelay = setTimeout(RS.view.sizing.notifyServer,250);
		},
		rotated: function () {
			RS.view.sizing.notifyServer();
		},
		notifyControls: function (complete) {
			if (RS.stopInit === true) {
				return;
			}
			
			var object, i;
			RS.view.refresh.lock();
			for (i = 0; i < RS.view.sizing.targets.length; i++) {
				object = RS.view.sizing.targets[i];
				object.resize();
				if (complete === true) {
					object.resizeComplete();
				}
			}
			RS.view.refresh.unlock();
		},
		notifyServer: function () {
			RS.view.sizing.notifyControls(true);
			
			var userdata = [];
			var d = RS.view.sizing.dimensions();
			userdata.push(d.width);
			userdata.push(d.height);
			RS.comm.triggerEvent('Event','Resized',userdata);
		},
		dimensions: function () {
			var view = document.getElementById('REALContainer');
			return { width : view.offsetWidth , height : view.offsetHeight };
		},
		notifyDelay: 0,
		targets: []
	},
	refresh: {
		lock: function () {
			RS.view.refresh.lockCount = Math.max(RS.view.refresh.lockCount,0) + 1;
		},
		unlock: function (caller) {
			if (RS.view.refresh.lockCount <= 0) {
				return;
			}
			RS.view.refresh.lockCount = RS.view.refresh.lockCount - 1;
			
			if (RS.view.refresh.lockCount === 0) {
				var i,obj;
				for (i = 0; i < RS.view.refresh.targets.length; i++) {
					obj = RS.view.refresh.targets[i];
					var el = document.getElementById(obj.controlID);
					if(el) {
						if ((obj.refresh) && (obj != caller)) {
							obj.refresh();
						}
					}
				}
				RS.view.refresh.targets = [];
			}
		},
		locked: function () {
			if (RS.view.refresh.lockCount > 0) {
				return true;
			} else {
				return false;
			}
		},
		lockCount: 0,
		targets: []
	}
};

RS.menus = {
	create: function (menu,depth) {
		if (typeof(depth) === 'undefined') {
			depth = -1;
		}
		
		var action = function (event) {
			event = event || window.event;
			RS.events.preventDefault(event);
			RS.events.stopPropagation(event);
			
			if (RS.menus.mouseDownItem === null) {
				return;
			}
			
			var menuItem;
			if (this.id) {
				menuItem = this;
			} else if ((event.srcElement) || (event.target)) {
				menuItem = event.srcElement || event.target;
			} else {
				RS.menus.mouseDownItem = null;
				return;
			}
			var menuID = menuItem.id.substring(0,10);
			menuItem = document.getElementById(menuID + '_item');
			
			if ((menuItem.className == 'item') && (menuItem === RS.menus.mouseDownItem)) {
				if (RS.menus.items.indexOf(menuID) === -1) {
					if (RS.menus.menuTarget !== null) {
						RS.menus.menuTarget.menuItemSelected(menuID);
					}
					RS.menus.dismissAllMenus();
				}
			}
		};
		
		var mouseDown = function (event) {
			event = event || window.event;
			RS.events.preventDefault(event);
			RS.events.stopPropagation(event);
			
			var menuItem;
			if (this.id) {
				menuItem = this;
			} else if ((event.srcElement) || (event.target)) {
				menuItem = event.srcElement || event.target;
			} else {
				return;
			}
			var menuID = menuItem.id.substring(0,10);
			RS.menus.mouseDownItem = document.getElementById(menuID + '_item');
		};
		
		var item = document.getElementById(menu.menuID + '_item');
		if (!item) {
			item = document.createElement('li');
			item.id = menu.menuID + '_item';
			
			RS.events.addListener(item,'mousedown',mouseDown,false);
			RS.events.addListener(item,'contextmenu',action,false);
		}
		
		if (menu.text === '-') {
			item.className = 'separator';
			return item;
		}
		
		var caption;
		if (item.children.length < 1) {
			caption = document.createElement('span');
			caption.id = menu.menuID + "_caption";
			RS.events.addListener(caption,'mousedown',mouseDown,false);
			RS.events.addListener(caption,'contextmenu',action,false);
			item.appendChild(caption);
		} else {
			caption = item.children[0];
		}
		
		if (menu.children.length > 0) {
			RS.menus.items[menu.menuID] = menu;
			RS.menus.items.push(menu.menuID);
			
			caption.className = 'submenu';
			
			var shell = document.getElementById(menu.menuID);
			if (!shell) {
				shell = document.createElement('div');
				shell.id = menu.menuID;
				shell.style.display = 'none';
				
				var pointer = document.createElement('img');
				pointer.id = menu.menuID + '_pointer';
				pointer.className = 'pointer';
				pointer.src = '/framework/spacer.gif';
				RS.events.addListener(pointer,'contextmenu',RS.input.contextClick,false);
				shell.appendChild(pointer);
				
				document.getElementById('REALMenus').appendChild(shell);
			}
			var ul = document.getElementById(menu.menuID + '_inner');
			if (!ul) {
				ul = document.createElement('ul');
				ul.id = menu.menuID + '_inner';
				ul.className = 'menu';
				ul.style.display = 'inline-block';
				shell.appendChild(ul);
			} else {
				if (ul.hasChildNodes()) {
					while (ul.childNodes.length >= 1) {
						ul.removeChild(ul.firstChild);
					}
				}
			}
			
			var i;
			for (i = 0; i < menu.children.length; i++) {
				ul.appendChild(RS.menus.create(menu.children[i],depth + 1));
			}
			
			var showMenu = function (event) {
				event = event || window.event;
				RS.events.preventDefault(event);
				RS.events.stopPropagation(event);
				
				var menuItem;
				if (this.id) {
					menuItem = this;
				} else if ((event.srcElement) || (event.target)) {
					menuItem = event.srcElement || event.target;
				} else {
					return;
				}
				var menuID = menuItem.id.substring(0,10);
				menuItem = document.getElementById(menuID + '_item');
				
				var pos = getPosition(menuItem);
				var r = new Rect(pos.x,pos.y,menuItem.offsetWidth,menuItem.offsetHeight);
				var x = r.right;
				var edge = 1;
				var width = document.getElementById('REALContainer').offsetWidth - 40;
				if (width - r.right < r.width()) {
					x = r.left;
					edge = 3;
				}
				RS.menus.displayMenuForPoint(menuItem.id.substring(0,10),x,r.verticalCenter(),edge,depth + 1);
			};
			RS.events.addListener(item,'mouseover',showMenu,false);
		} else {
			var hideMenus = function (event) {
				event = event || window.event;
				RS.events.preventDefault(event);
				RS.events.stopPropagation(event);
				
				RS.menus.dismissAllMenus(depth + 1);
			};
			RS.events.addListener(item,'mouseover',hideMenus,false);
		}
		
		if (menu.enabled === true) {
			RS.events.addListener(item,'mouseup',action,false);
			item.className = 'item';
		} else {
			item.className = 'disabled';
		}
		while (caption.firstChild !== null) {
			caption.removeChild(caption.firstChild);
		}
		caption.appendChild(document.createTextNode(menu.text));
		
		return item;
	},
	remove: function (menuID) {
	},
	findSuitableEdgeForRect: function (originRect, menuRect) {
		var dimensions = RS.view.sizing.dimensions();
		var bottomSpace = dimensions.height - originRect.bottom;
		var rightSpace = dimensions.width - originRect.right;
		var leftSpace = originRect.left;
		var topSpace = originRect.top;
		
		if (topSpace >= menuRect.height() + 20) {
			return 0;
		}
		if (bottomSpace >= menuRect.height() + 20) {
			return 2;
		}
		if (rightSpace >= menuRect.width() + 20) {
			return 1;
		}
		if (leftSpace >= menuRect.width() + 20) {
			return 3;
		}
		
		return 4;
	},
	displayMenuForRect: function (menuID, rect, mouseX, mouseY, depth) {
		if (RS.menus.visibleItems.length === 0) {
			var container = document.getElementById('REALMenus');
			container.style.visibility = 'hidden';
			container.style.display = 'block';
		}
		document.getElementById(menuID).style.display = 'inline-block';
		
		var ul = document.getElementById(menuID + '_inner');
		var menuRect = new Rect(0,0,ul.offsetWidth,ul.offsetHeight)
		var edge = RS.menus.findSuitableEdgeForRect(rect,menuRect);
		
		switch (edge) {
			case 0:
				RS.menus.displayMenuForPoint(menuID,rect.horizontalCenter(),rect.top,edge,depth);
				break;
			case 1:
				RS.menus.displayMenuForPoint(menuID,rect.right,rect.verticalCenter(),edge,depth);
				break;
			case 2:
				RS.menus.displayMenuForPoint(menuID,rect.horizontalCenter(),rect.bottom,edge,depth);
				break;
			case 3:
				RS.menus.displayMenuForPoint(menuID,rect.left,rect.verticalCenter(),edge,depth);
				break;
			case 4:
				if ((mouseX === null) || (mouseY === null)) {
					RS.menus.displayMenuForPoint(menuID,rect.horizontalCenter(),rect.verticalCenter(),edge,depth);
				} else {
					RS.menus.displayMenuForPoint(menuID,mouseX,mouseY,-1,depth);
				}
				break;
		}
	},
	displayMenuForPoint: function (menuID, x, y, edge, depth) {
		if (typeof(depth) === 'undefined') {
			depth = 0;
		}
		RS.menus.dismissAllMenus(depth);
		
		var container = document.getElementById('REALMenus');
		var menu = document.getElementById(menuID);
		var pointer = document.getElementById(menuID + '_pointer');
		var menuInner = document.getElementById(menuID + '_inner');
		if ((container) && (menu) && (menuInner) && (pointer)) {
		} else {
			return;
		}
		container.style.visibility = 'hidden';
		container.style.display = 'block';
		menu.style.display = 'inline-block';
		container.style.visibility = 'visible';
		var menuRect = new Rect(0,0,menuInner.offsetWidth,menuInner.offsetHeight);
		
		switch (edge) {
			case -1:
				var originRect = new Rect(x - 1,y - 1,2,2);
				edge = RS.menus.findSuitableEdgeForRect(originRect,menuRect);
				break;
			case 5:
				var rightSpace = container.offsetWidth - x;
				if (rightSpace > menuRect.width()) {
					edge = 1;
				} else {
					edge = 3;
				}
				break;
			case 6:
				var bottomSpace = container.offsetHeight - y;
				if (bottomSpace > menuRect.height()) {
					edge = 2;
				} else {
					edge = 0;
				}
				break;
		}
		
		if (x < 35) {
			edge = 1;
		} else if (x > container.offsetWidth - 35) {
			edge = 3;
		}
		
		var menuOuter,pointerRect,diff;
		
		menu.style.position = 'absolute';
		switch (edge) {
			case 0:
				menuOuter = new Rect(x - Math.floor(menuRect.width() / 2),y - (menuRect.height() + 20),menuRect.width(),menuRect.height() + 20);
				pointerRect = new Rect(Math.floor(menuRect.width() / 2) - 20,menuRect.height(),40,20);
				
				if (menuOuter.left < 10) {
					diff = 10 - menuOuter.left;
					menuOuter.offset(diff,0);
					pointerRect.offset(diff * -1,0);
				} else if (menuOuter.right > container.offsetWidth - 10) {
					diff = menuOuter.right - (container.offsetWidth - 10);
					menuOuter.offset(diff * -1,0);
					pointerRect.offset(diff,0);
				}
				pointerRect.left = Math.min(Math.max(pointerRect.left,5),menuRect.width() - 45);
				pointerRect.right = pointerRect.left + 40;
				
				menu.style.top = menuOuter.top + 'px';
				menu.style.left = menuOuter.left + 'px';
				menu.style.visibility = 'visible';
				menuInner.style.top = '0px';
				menuInner.style.left = '0px'
				pointer.width = '40';
				pointer.height = '20';
				pointer.style.top = pointerRect.top + 'px';
				pointer.style.left = pointerRect.left + 'px';
				pointer.style.backgroundPosition = '0px 20px';
				
				break;
			case 1:
				menuOuter = new Rect(x,y - Math.floor(menuRect.height() / 2),menuRect.width() + 20,menuRect.height());
				pointerRect = new Rect(0,Math.floor(menuRect.height() / 2) - 20,20,40);
				
				if (menuOuter.top < 10) {
					diff = 10 - menuOuter.top;
					menuOuter.offset(0,diff);
					pointerRect.offset(0,diff * -1);
				} else if (menuOuter.bottom > container.offsetHeight - 10) {
					diff = menuOuter.bottom - (container.offsetHeight - 10);
					menuOuter.offset(0,diff * -1);
					pointerRect.offset(0,diff);
				}
				pointerRect.top = Math.min(Math.max(pointerRect.top,5),menuRect.height() - 45);
				pointerRect.bottom = pointerRect.top + 40;
				
				menu.style.top = menuOuter.top + 'px';
				menu.style.left = menuOuter.left + 'px';
				menu.style.visibility = 'visible';
				menuInner.style.top = '0px';
				menuInner.style.left = '20px';
				pointer.width = '20';
				pointer.height = '40';
				pointer.style.top = pointerRect.top + 'px';
				pointer.style.left = pointerRect.left + 'px';
				pointer.style.backgroundPosition = '0px 0px';
				break;
			case 2:
				menuOuter = new Rect(x - Math.floor(menuRect.width() / 2),y,menuRect.width(),menuRect.height() + 20);
				pointerRect = new Rect(Math.floor(menuRect.width() / 2) - 20,0,40,20);
				
				if (menuOuter.left < 10) {
					diff = 10 - menuOuter.left;
					menuOuter.offset(diff,0);
					pointerRect.offset(diff * -1,0);
				} else if (menuOuter.right > container.offsetWidth - 10) {
					diff = menuOuter.right - (container.offsetWidth - 10);
					menuOuter.offset(diff * -1,0);
					pointerRect.offset(diff,0);
				}
				pointerRect.left = Math.min(Math.max(pointerRect.left,5),menuRect.width() - 45);
				pointerRect.right = pointerRect.left + 40;
				
				menu.style.top = menuOuter.top + 'px';
				menu.style.left = menuOuter.left + 'px';
				menu.style.visibility = 'visible';
				menuInner.style.top = '20px';
				menuInner.style.left = '0px';
				pointer.width = '40';
				pointer.height = '20';
				pointer.style.top = pointerRect.top + 'px';
				pointer.style.left = pointerRect.left + 'px';
				pointer.style.backgroundPosition = '0px 0px';
				break;
			case 3:
				menuOuter = new Rect(x - (menuRect.width() + 20),y - Math.floor(menuRect.height() / 2),menuRect.width() + 20,menuRect.height());
				pointerRect = new Rect(menuRect.width(),Math.floor(menuRect.height() / 2) - 20,20,40);
				
				if (menuOuter.top < 10) {
					diff = 10 - menuOuter.top;
					menuOuter.offset(0,diff);
					pointerRect.offset(0,diff * -1);
				} else if (menuOuter.bottom > container.offsetHeight - 10) {
					diff = menuOuter.bottom - (container.offsetHeight - 10);
					menuOuter.offset(0,diff * -1);
					pointerRect.offset(0,diff);
				}
				pointerRect.top = Math.min(Math.max(pointerRect.top,5),menuRect.height() - 45);
				pointerRect.bottom = pointerRect.top + 40;
				
				menu.style.top = menuOuter.top + 'px';
				menu.style.left = menuOuter.left + 'px';
				menu.style.visibility = 'visible';
				menuInner.style.top = '0px';
				menuInner.style.left = '0px';
				pointer.width = '20';
				pointer.height = '40';
				pointer.style.top = pointerRect.top + 'px';
				pointer.style.left = pointerRect.left + 'px';
				pointer.style.backgroundPosition = '20px 0px';
				break;
			case 4:
				menuOuter = new Rect(x - Math.floor(menuRect.width() / 2),y - Math.floor(menuRect.height() / 2),menuRect.width(),menuRect.height());
				
				menu.style.top = menuOuter.top + 'px';
				menu.style.left = menuOuter.left + 'px';
				menu.style.visibility = 'visible';
				menuInner.style.top = '0px';
				menuInner.style.left = '0px';
				pointer.style.display = 'none';
				break;
		}
		RS.menus.visibleItems.push(menuID);
	},
	dismissMenu: function (menuID) {
		var idx = RS.menus.visibleItems.indexOf(menuID);
		if (idx === -1) {
			return;
		}
		
		var menu = document.getElementById(menuID);
		menu.style.display = 'none';
		RS.menus.visibleItems.splice(idx,1);
		
		if (RS.menus.visibleItems.length === 0) {
			var container = document.getElementById('REALMenus');
			container.style.display = 'none';
			container.style.visibility = 'visible';
			RS.menus.menuTarget = null;
		}
	},
	dismissAllMenus: function (depth) {
		if (typeof(depth) === 'undefined') {
			depth = 0;
		}
		while (RS.menus.visibleItems.length > depth) {
			RS.menus.dismissMenu(RS.menus.visibleItems[depth]);
		}
	},
	items: [],
	visibleItems: [],
	mouseDownItem: null,
	menuTarget: null,
	action: 'context'
};

// Library Functions
RS.begin = function (sessionID)
{
	gcfCheck();
	if (RS.stopInit === true) {
		return;
	}
	
	RS.sessionID = sessionID;
	RS.appURL = '';
	RS.sessionURL = RS.appURL + "/" + RS.sessionID;
	
	try {
		var test = document.createElement('div');
		var touchEventName = 'ontouchstart';
		RS.input.mIsTouchUI = (touchEventName in test);
		if (!RS.input.mIsTouchUI) {
			test.setAttribute(touchEventName,'return');
			RS.input.mIsTouchUI = typeof test[touchEventName] == 'function';
		}
		test = null;
	} catch (touchErr) {
		RS.input.mIsTouchUI = false;
	}
	
	document.onmousemove = RS.input.move;
	document.onmouseup = RS.input.end;
	document.onkeydown = RS.input.keyDown;
	document.onkeyup = RS.input.keyUp;
	document.onkeypress = RS.input.keyPress;
	window.onresize = RS.view.sizing.resized;
	
	RS.events.addListener(document,'mousewheel', trackMouseWheel, false);
	RS.events.addListener(window,'mousewheel', trackMouseWheel, false);
	RS.events.addListener(window,'DOMMouseScroll', trackMouseWheel, false);
		
	window.onbeforeunload = RS.view.handleConfirmation;
	
	RS.events.addListener(document.body,'contextmenu',RS.input.contextClick,false);
	RS.events.addListener(window,'blur',function () { RS.menus.dismissAllMenus(0) },false);
	
	cacheImage('/framework/appicon128.png');
	cacheImage('/framework/pagestop.png');
	cacheImage('/framework/dimmer.png');
	cacheImage('/framework/pointer.png');
	cacheImage('/framework/submenu-normal.png');
	cacheImage('/framework/submenu-hover.png');
	cacheImage('/framework/AlerterButtons.png');
	
	setTimeout('RS.view.setLoaderState(1)',0);
	var commDelay = 1;
	if(RS.ua.mobile=="Android") { commDelay = 1000; };
	setTimeout(RS.comm.begin,commDelay);
};

function didFinishLoading (pageID)
{
	var i, controlID, control;
	for (i = 0; i < RS.controls.length; i++) {
		controlID = RS.controls[i];
		control = RS.controls[controlID];
		if (control.hasFinishedLoading === false) {
			control.didFinishLoading();
			control.hasFinishedLoading = true;
		}
	}
}

function getPosition (e)
{ 
	var left = 0; 
	var top  = 0; 
	
	while (e.offsetParent){ 
		left += e.offsetLeft; 
		top += e.offsetTop; 
		e = e.offsetParent;
	} 
	
	left += e.offsetLeft; 
	top += e.offsetTop; 
	
	return {x:left, y:top};
}

function mouseCoords (ev)
{
	ev = ev || window.event;
	if (!ev) {
		return {x:0, y:0};
	}
	if (ev.pageX || ev.pageY) {
		return {x:ev.pageX, y:ev.pageY};
	}
	return {x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, y: ev.clientY + document.body.scrollTop - document.body.clientTop};
}


function getMouseOffset (target, ev)
{
	ev = ev || window.event;
	var docPos = getPosition(target);
	var mousePos = mouseCoords(ev);
	return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}

function prepareFormData (fields)
{
	var queries = [];
	var element;
	var v;
	for (var i = 0; i < fields.length; i++) {
		element = fields[i];
		if (!element) {
			continue;
		}
		v = encodeURIComponent(element.value());
		queries.push(element.name() + '=' + v);
	}
	return queries;
}

function addPostLoadObject (object)
{
	RS.postLoadObjects.push(object);
}

function getPageDimensions ()
{
	var page = document.getElementById(RS.view.currentPage);
	return { width : page.offsetWidth , height : page.offsetHeight };
}

function addWheelTarget (target)
{
	RS.wheelTargets.push(target);
}

function preventEventDefault(ev)
{
	if (ev) {
		if (ev.preventDefault) {
			ev.preventDefault();
		}
		ev.returnValue = false;
	}
}

function trackMouseWheel (ev)
{
	var deltaX = 0;
	var deltaY = 0;
	if (!ev) {
		ev = window.event;
	}
	if ((ev.wheelDeltaX !== undefined) && (ev.wheelDeltaY !== undefined)) {
		deltaX = ev.wheelDeltaX / 120;
		deltaY = ev.wheelDeltaY / 120;
		if (!window.opera) {
			deltaX = deltaX * -1;
			deltaY = deltaY * -1;
		}
	} else if (ev.wheelDelta) {
		deltaY = ev.wheelDelta / 120;
		if (!window.opera) {
			deltaY = deltaY * -1;
		}
	} else if (ev.detail) {
		deltaY = (ev.detail / 3);
	}
	
	if ((deltaX === 0) && (deltaY === 0)) {
		return;
	}
	
	var i, target, pos, mousePos, handled;
	
	mousePos = mouseCoords(ev);
	handled = false;
	for (i = 0; i < RS.wheelTargets.length; i++) {
		target = RS.wheelTargets[i];
		pos = getPosition(target.object());
		
		if ((handled === false) && (mousePos.x >= pos.x) && (mousePos.x <= pos.x + target.object().offsetWidth) && (mousePos.y >= pos.y) && (mousePos.y <= pos.y + target.object().offsetHeight)) {
			if (target.enabled()) {
				handled = target.mouseWheel(deltaX, deltaY);
				if (handled) {
					break;
				}
			}
		}
	}
		
	if ((handled === true) && (ev)) {
		RS.events.preventDefault(ev);
	}
}

function findChildrenByClass (parent, className)
{
	var children = parent.children;
	var results = Array();
	var i;
	
	for (i = 0; i < children.length; i++) {
		if (children.item(i).className == className) {
			results.push(children.item(i));
		}
	}
	
	return results;
}

function isRefreshingLocked ()
{
	return (RS.refreshLocks > 0);
}

function cacheImage (url,useCache)
{
	if(useCache==undefined) useCache = true;
	var img,i,s;
	if(useCache) {
		for (i = 0; i < RS.imageCache.length; i++) {
			s = RS.imageCache[i].src;
			s = s.substring(s.length - url.length);
			if (s === url) {
				img = RS.imageCache[i];
				break;
			}
		}
	}
	
	if (img == null) {
		img = new Image();
		img.src = url;
		img.loaded = false;
		RS.imageCache.push(img);
	} else {
		img.loaded = true;
	}
	
	return img;
}

// Compatibility

function outerHTML (element)
{
	try {
		if (RS.serializer === null) {
			RS.serializer = new XMLSerializer();
		}
		return RS.serializer.serializeToString(element);
	} catch (err) {
		return element.outerHTML;
	}
}

function createRandomString (length)
{
	var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
	var s = "";
	var i,r;
	for (i = 0; i < length; i++) {
		r = Math.floor(Math.random() * chars.length);
		s += chars.substring(r,r + 1);
	}
	return s;
}

// Style Manipulation

function createStyleSheet (source,id)
{
	if (source == "") { return; }
	var sheet;
	var oldsheet = document.getElementById(id);
	if(!oldsheet || id == "") {
		sheet = document.createElement("style");
		sheet.type = "text/css";
		sheet.rel = "stylesheet";
		sheet.media = "all";
		if(id!==undefined && id!=="") sheet.id = id;
	} else {
		sheet = oldsheet;
	}

	try {
		sheet.innerHTML = source;
	} catch (err) {
		try {
			sheet.styleSheet.cssText = source;
		} catch (err) {
			sheet.style.cssText = source;
		}
	}
	if(!oldsheet) {
		document.getElementsByTagName("head")[0].appendChild(sheet);
	}
	return sheet;
}

function markControlChanged (field)
{
	var i;
	for (i = 0; i < RS.changedFields.length; i++) {
		if (RS.changedFields[i] == field) {
			return;
		}
	}
	RS.changedFields.push(field);
}

// Input Support (Mouse, Fingers, etc)

RS.input.isTouchUI = function ()
{
	return RS.input.mIsTouchEnabled;
};

RS.input.install = function (element)
{
	if (RS.input.installedElements.indexOf(element.id) == -1) {
		RS.events.addListener(element,"mousedown",RS.input.begin,false);
		RS.events.addListener(element,"mouseover",RS.input.enter,false);
		RS.events.addListener(element,"mouseout",RS.input.exit,false);
		RS.events.addListener(element,"dblclick",RS.input.doubleClick,false);
		RS.input.installedElements.push(element.id);
	}
};

RS.events.addListener(document,"load", function() {
	document.addEventListener("touchstart", RS.input.touchHandler, true);
	document.addEventListener("touchmove", RS.input.touchHandler, true);
	document.addEventListener("touchend", RS.input.touchHandler, true);
	document.addEventListener("touchcancel", RS.input.touchHandler, true);
});

RS.input.begin = function (event)
{
	var id = '';
	if (this.id) {
		id = this.id.substring(0,8);
	} else if ((event.srcElement) || (event.target)) {
		var element = event.srcElement || event.target;
		while (((element.id === '') || (RS.controls.indexOf(element.id) == -1)) && (element.offsetParent !== null)) {
			element = element.offsetParent;
		}
		id = element.id.substring(0,8);
	}
	if ((id === '') || (!event)) {
		return;
	}
	
	var control = RS.controls[id];
	if (!control) {
		return;
	}
	
	RS.input.forwardEvent(event, control);
};

RS.input.move = function (event)
{
	event = event || window.event;
	if (RS.input.target !== null) {
		RS.input.setLastEvent(RS.input.target.object(),event);
		if (RS.input.lastCoordinates.length > 0) {
			preventEventDefault(event);
		}
		return;
	} else if (RS.input.pointerTarget !== null) {
		var control = RS.input.pointerTarget;
		RS.input.setLastEvent(control.object(),event);
		if (RS.input.lastCoordinates.length > 0) {
			if (control.implementedEvents.indexOf('MouseMove') > -1) {
				RS.comm.triggerEvent(control.controlID,'MouseMove',RS.input.mouseEventData(event,RS.input.lastCoordinates),event);
			}
			var handled = control.mouseMove(event, RS.input.lastCoordinates);
			if (handled === true) {
				preventEventDefault(event);
			}
		}
		return;
	}
};

RS.input.end = function (event)
{
	if (!event) {
		event = RS.input.lastEvent;
	}
	if (RS.input.target === null) {
		return;
	}
	if (RS.input.holdInterval > 0) {
		clearInterval(RS.input.holdInterval);
		RS.input.holdInterval = 0;
	}
	
	if (RS.input.lastCoordinates.length > 0) {
		if (RS.input.target.implementedEvents.indexOf('MouseUp') > -1) {
			RS.comm.triggerEvent(RS.input.target.controlID,'MouseUp',RS.input.mouseEventData(event,RS.input.lastCoordinates),event);
		}
		var handled = RS.input.target.touchEnd(event, RS.input.lastCoordinates);
		if (handled === true) {
			try {
			preventEventDefault(event);
			} catch(e) { }
		}
	}
	RS.input.target = null;
	RS.input.lastCoordinates = [];
};



RS.input.enter = function (event)
{
	if (RS.input.pointerTarget !== null) {
		return;
	}
	var id = '';
	if (this.id) {
		id = this.id.substring(0,8);
	} else if ((event.srcElement) || (event.target)) {
		var element = event.srcElement || event.target;
		while (((element.id === '') || (RS.controls.indexOf(element.id) == -1)) && (element.offsetParent !== null)) {
			element = element.offsetParent;
		}
		id = element.id.substring(0,8);
	}
	if ((id === '') || (!event)) {
		return;
	}
	
	var control = RS.controls[id];
	if (!control) {
		return;
	}
	
	RS.input.pointerTarget = control;
	RS.input.setLastEvent(control.object(),event);
	if (RS.input.lastCoordinates.length > 0) {
		var el = control.object();
		var pos = getPosition(el);
		var mc = mouseCoords(event);
		if(!control.mouseWithin && mc.x >= pos.x && mc.x <= (pos.x + el.offsetWidth) && mc.y >= pos.y && mc.y <= (pos.y + el.offsetHeight)) {
			control.mouseWithin = true;
			if (control.implementedEvents.indexOf('MouseEnter') > -1) {
				RS.comm.triggerEvent(control.controlID,'MouseEnter',null,event);
			}
		}
		var handled = control.mouseEnter(event);
		if (handled === true) {
			preventEventDefault(event);
		}
	}
};

RS.input.exit = function (event)
{
	if (RS.input.pointerTarget === null) {
		return;
	}
	
	var control = RS.input.pointerTarget;
	
	RS.input.setLastEvent(control.object(),event);
	if (RS.input.lastCoordinates.length > 0) {
		var el = control.object();
		var pos = getPosition(el);
		var mc = mouseCoords(event);
		if(control.mouseWithin && (mc.x < pos.x || mc.x > (pos.x + el.offsetWidth) || mc.y < pos.y || mc.y > (pos.y + el.offsetHeight))) {
			control.mouseWithin = false;
			if (control.implementedEvents.indexOf('MouseExit') > -1 && RS.view.currentPage != control.controlID) {
				RS.comm.triggerEvent(control.controlID,'MouseExit',null,event);
			}
		}
		var handled = control.mouseExit(event);
		if (handled === true) {
			preventEventDefault(event);
		}
	}
	
	RS.input.pointerTarget = null;
};

RS.input.doubleClick = function (event)
{
	var id = '';
	if (this.id) {
		id = this.id.substring(0,8);
	} else if ((event.srcElement) || (event.target)) {
		var element = event.srcElement || event.target;
		while (((element.id === '') || (RS.controls.indexOf(element.id) == -1)) && (element.offsetParent !== null)) {
			element = element.offsetParent;
		}
		id = element.id.substring(0,8);
	}
	if ((id === '') || (!event)) {
		return;
	}
	
	var control = RS.controls[id];
	if (!control) {
		return;
	}
	
	RS.input.setLastEvent(control.object(),event);
	if (RS.input.lastCoordinates.length > 0) {
		if (control.implementedEvents.indexOf('DoubleClick') > -1) {
			RS.comm.triggerEvent(control.controlID,'DoubleClick',RS.input.mouseEventData(event,RS.input.lastCoordinates),event);
		}
		var handled = control.doubleClick(event);
		if (handled === true) {
			preventEventDefault(event);
		}
	}
};

RS.input.getCoordinates = function (target, event)
{
	var results = [];
	var result;
	var offset = {x: 0, y: 0};
	if (target) {
		offset = getPosition(target);
	}
	if (RS.input.isTouchUI() === true) {
		for (var i = 0; i < event.touches.length; i++) {
			result = {pageX: event.touches[i].pageX, pageY: event.touches[i].pageY};
			result.x = result.pageX - offset.x;
			result.y = result.pageY - offset.y;
			results.push(result);
		}
	} else {
		if (event.pageX) {
			result = {pageX: event.pageX, pageY: event.pageY};
		} else {
			result = {
				pageX: event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft),
				pageY: event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)
			};
		}
		result.x = result.pageX - offset.x;
		result.y = result.pageY - offset.y;
		results.push(result);
	}
	return results;
};

RS.input.refireMove = function ()
{
	if (RS.input.target === null) {
		return;
	}
	if (RS.input.lastCoordinates.length > 0) {
		if (RS.input.target.implementedEvents.indexOf('MouseDrag') > -1) {
			RS.comm.triggerEvent(RS.input.target.controlID,'MouseDrag',RS.input.mouseEventData(event,RS.input.lastCoordinates),event);
		}
		RS.input.target.touchMove(null, RS.input.lastCoordinates);
	}
};

RS.input.forwardEvent = function (event, control)
{
	RS.input.target = control;
	RS.input.setLastEvent(control.object(),event);
	var r = false;
	if (RS.input.lastCoordinates.length > 0) {
		if (control.implementedEvents.indexOf('MouseDown') > -1) {
			RS.comm.triggerEvent(control.controlID,'MouseDown',RS.input.mouseEventData(event,RS.input.lastCoordinates),event);
		}
		var handled = control.touchBegin(event, RS.input.lastCoordinates);
		if (handled === true) {
			r = true;
			preventEventDefault(event);
		}
		if(control.mEnabled) {
			handled = control.touchMove(event, RS.input.lastCoordinates);
		}
		if (handled === true) {
			RS.input.holdInterval = setInterval(RS.input.refireMove,10);
		}
	}
	return r;
};

RS.input.mouseEventData = function (event, coordinates)
{
	var userdata = [];
	
	userdata.push(coordinates.length);
	for (var i = 0; i < coordinates.length; i++) {
		userdata.push(coordinates[i].pageX);
		userdata.push(coordinates[i].pageY);
	}
	userdata.push(event.button);
	
	return userdata;
};

RS.input.keyDown = function (event)
{
	event = event || window.event;
	var handled = false;
	var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : 0);
	var keyName = (event.keyIdentifier) ? event.keyIdentifier : String.fromCharCode(charCode);
	var props = [event.keyCode,charCode,keyName,event.shiftKey,event.ctrlKey,event.altKey];
	if(event.metaKey) props[props.length] = event.metaKey;
	if (RS.input.focusControl !== null) {
		handled = RS.input.focusControl.keyDown(event);
		if(event.keyCode == 46 || event.keyCode == 8) {
			//Make sure Backspace and Delete keys fire KeyPressed event (WebKit)
			RS.input.handleKey(event,"KeyPressed");
		}
	}
};

RS.input.keyPress = function (event) {
	event = event || window.event;
	var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : 0);
	if(!(event.keyCode == 8 || event.keyCode == 46)) { //Don't let keyPress fire for Delete or Backspace
		if(RS.input.handleKey(event,"KeyPressed")) {
			return true;
		}
	}
}

RS.input.keyUp = function (event)
{
	event = event || window.event;
	try {
		if (event.keyCode == 13) {
			//Don't fire a keyUp event for Return/Enter
			RS.events.stopPropagation(event);
			RS.events.preventDefault(event);
			return;
		}
	} catch(err) {}
	var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : 0);
	var keyName = (event.keyIdentifier) ? event.keyIdentifier : String.fromCharCode(charCode);
	if(keyName.length !== 1 && keyName.indexOf("U+")==-1) {
		return RS.input.handleKey(event,"KeyPressed");
	}
};

RS.input.handleKey = function(event, eventName) {
	var handled = false;
	var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : 0);
	var keyName = (RS.input.lastKey !== "" && RS.input.lastKey !== undefined) ? RS.input.lastKey : ((event.keyIdentifier) ? event.keyIdentifier : String.fromCharCode(charCode));
	var keyCode = (event.keyCode > 0) ? event.keyCode : charCode;
	if (event.modifiers) {
		event.shiftKey = (event.shiftKey || (event.modifiers && 4));
		event.altKey = (event.altKey || (event.modifiers && 1));
		event.ctrlKey = (event.ctrlKey || (event.modifiers && 2));
	}
	var props = [keyCode,charCode,keyName,event.shiftKey,event.ctrlKey,event.altKey];
	if(event.metaKey) props[props.length] = event.metaKey;
	if (RS.input.focusControl !== null) {
		handled = RS.input.focusControl.keyUp(event);
		if ((handled !== true) && (RS.input.focusControl.implementedEvents.indexOf('KeyPressed') > -1)) {
			setTimeout(function() { RS.comm.triggerEvent(RS.input.focusControl.controlID,'KeyPressed',props,event); },0);
			handled = true;
		}
	}
	if ((handled !== true) && (RS.controls[RS.view.currentPage].implementedEvents.indexOf('KeyPressed') > -1)) {
		setTimeout(function() { RS.comm.triggerEvent(RS.view.currentPage,'KeyPressed',props,event); },0);
		handled = true;
	}
	return handled;
}

RS.input.setFocusControl = function (control)
{
	if(RS.input.focusControl !== null) {
		if(RS.input.focusControl.implementedEvents.indexOf('LostFocus') > -1) {
			RS.comm.triggerEvent(RS.input.focusControl.controlID,'LostFocus',"",null);
		}
		if(typeof RS.input.focusControl.lostFocus === "function") {
			RS.input.focusControl.lostFocus();
		}
	}
	RS.input.focusControl = control;
	if(RS.input.focusControl !== null) {
		if(RS.input.focusControl.implementedEvents.indexOf('GotFocus') > -1) {
			RS.comm.triggerEvent(RS.input.focusControl.controlID,'GotFocus',"",null);
		}
		if(typeof RS.input.focusControl.gotFocus === "function") {
			RS.input.focusControl.gotFocus();
		}
	}
};

RS.input.setLastEvent = function (relObject,event) {
	if(event) {
		RS.input.lastCoordinates = RS.input.getCoordinates(relObject,event);
		RS.input.lastEvent = event;
	}
};

RS.input.touchHandler = function (event) {
    var touches = event.changedTouches,
        first = touches[0],
        type = "";
         switch(event.type)
    {
        case "touchstart": type = "mousedown"; break;
        case "touchmove":  type="mousemove"; break;        
        case "touchend":   type="mouseup"; break;
        default: return;
    }

             //initMouseEvent(type, canBubble, cancelable, view, clickCount, 
    //           screenX, screenY, clientX, clientY, ctrlKey, 
    //           altKey, shiftKey, metaKey, button, relatedTarget);
    
    var simulatedEvent = document.createEvent("MouseEvent");
    simulatedEvent.initMouseEvent(type, true, true, window, 1, 
                              first.screenX, first.screenY, 
                              first.clientX, first.clientY, false, 
                              false, false, false, 0/*left*/, null);
    if(first.target.id==document.body.id) {
		first.target.dispatchEvent(simulatedEvent);
		event.preventDefault();
    }
};

RS.input.contextClick = function (event) {
	event = event || window.event;
	if (!event) {
		return;
	}
	
	var id = '';
	if (this.id) {
		id = this.id.substring(0,8);
	} else if ((event.srcElement) || (event.target)) {
		var element = event.srcElement || event.target;
		while (((element.id === '') || (RS.controls.indexOf(element.id) == -1)) && (element.offsetParent !== null)) {
			element = element.offsetParent;
		}
		id = element.id.substring(0,8);
	}
	if ((id === '') || (!event)) {
		return;
	}
	
	var control = RS.controls[id];
	if (!control) {
		return;
	}
	
	var coordinates = RS.input.getCoordinates(null,event);
	var menuID = control.menuID;
	if (menuID === '') {
		menuID = RS.controls[RS.view.currentPage].menuID;
	}
	if (menuID !== '') {
		RS.menus.dismissAllMenus();
		RS.menus.displayMenuForPoint(menuID,coordinates[0].pageX,coordinates[0].pageY,-1);
		RS.menus.menuTarget = control;
		RS.menus.action = 'context';
	}
	RS.events.preventDefault(event);
	RS.events.stopPropagation(event);
	return false;
};

// Debug Console

RS.console.error = function (msg) {
	var form = document.getElementById('REALAlerterDialog').children[0];
	if (form) {
		form.errorbody.value = msg;
		RS.console.present();
		form.userdetails.focus();
	}
};

RS.console.log = function (msg) {
	if ((typeof console) != 'undefined') {
		console.log(msg);
	}
};

RS.console.isVisible = function () {
	return RS.console.mIsVisible;
};

RS.console.present = function () {
	var cn = document.getElementById('REALAlerter');
	if (cn) {
		if (RS.console.mIsVisible === false) {
			RS.console.mIsVisible = true;
			RS.view.showOverlay();
			
			cn.style.display = 'block';
			setTimeout("document.getElementById('REALAlerter').style.opacity = '1'",1);
		}
	}
};

RS.console.dismiss = function () {
	var cn = document.getElementById('REALAlerter');
	if (cn) {
		if (RS.console.mIsVisible === true) {
			RS.console.mIsVisible = false;
			
			cn.style.opacity = '0';
			setTimeout("document.getElementById('REALAlerter').style.display = 'none'",260);
			setTimeout(RS.view.hideOverlay,260);
		}
	}
};

RS.console.submit = function () {
	var form = document.getElementById('REALAlerterDialog').children[0];
	if (form) {
		form.submit();
	}
};

// Events
RS.events.listeners = [];
RS.events.listenersDisabled = [];

//Define the listenerClass
RS.events.listener = function(el, eventName, callback, capture) {
	this.el = el;
	this.event = eventName;
	this.callback = callback;
	this.capture = capture;
};

RS.events.addListener = function (el, eventName, fn, capture) {
	if(window.addEventListener) {
		el.addEventListener(eventName, fn, capture);
	} else {
		if(el.attachEvent) {
			el.attachEvent("on"+eventName, fn);
		} else {
			el["on"+eventName] = fn;
		}
	}
	var lstn = new RS.events.listener(el,eventName,fn,capture);
	RS.events.listeners.push(lstn);
};

RS.events.removeListener = function (el, eventName, fn, capture) {
	if(window.removeEventListener) {
		el.removeEventListener(eventName, fn, capture);
	} else {
		if(el.detachEvent) {
			el.detachEvent("on"+eventName, fn);
		} else {
			el["on"+eventName] = null;
		}
	}
	for(i=0;i<RS.events.listeners.length;i++) {
		var lstn = RS.events.listeners[i];
		if((lstn.el.nodeName == el.nodeName || lstn.el.id == el.id) && lstn.event == eventName && lstn.callback == fn && lstn.capture == capture) {
			RS.events.listeners.splice(i,1);
		}
	}
};

RS.events.preventDefault = function (event) {
	event.returnValue = false;
	if (event.preventDefault) {
		event.preventDefault();
	}
};

RS.events.stopPropagation = function (event) {
	event.cancelBubble = true;
	if (event.stopPropagation) {
		event.stopPropagation();
	}
};

RS.events.fireEvent = function(el, eventname, props) {
	props = props || null;
	if(document.createEvent) {
		var evt = document.createEvent("Event");
		evt.initEvent(eventname,true,true);
		for(var prop in props) {
		    if(props.hasOwnProperty(prop))
		    	evt[prop] = props[prop];
		}
		return el.dispatchEvent(evt);
	} else { //Do it the IE way
		var ieEvt = document.createEventObject();
		ieEvt.cancelBubble = false;
		ieEvt.returnValue = true;
		for(var prop in props) {
		    if(props.hasOwnProperty(prop))
		    	ieEvt[prop] = props[prop];
		}
		var ieEventName = "on"+eventname;
		try {
			el.fireEvent(ieEventName,ieEvt);
		} catch(err) {
			//If IE<9 and it is a custom event, call it directly
			for(i=0;i<RS.events.listeners.length;i++) {
				var lstn = RS.events.listeners[i];
				if((lstn.el.nodeName == el.nodeName || lstn.el.id == el.id) && lstn.event == eventname) {
					lstn.callback(ieEvt);
				}
			}
		}
	}
};

//DOM
RS.DOM.addClass = function(el,className) {
	var classNames = RS.DOM.getArrayOfClassNames(el);
	if(classNames.indexOf(className)===-1) {
		classNames.push(className);
		el.className = classNames.join(' ');
	}
};

RS.DOM.removeClass = function(el,className) {
	var classNames = RS.DOM.getArrayOfClassNames(el);
	var newNames = [];
	for(var i = 0; i < classNames.length; i++) {
		if(className != classNames[i]) {
			newNames.push(classNames[i]);
		}
	}
	el.className = newNames.join(' ');
};

RS.DOM.hasClass = function(el,className) {
	var classNames = RS.DOM.getArrayOfClassNames(el);
	for(var i = 0;i<classNames.length;i++) {
		if(className == classNames[i]) {
			return true;
		}
	}
	return false;
};

RS.DOM.getAppliedStyle = function(el,styleName) {
	var style = "";
	if(window.getComputedStyle) {
		style = el.ownerDocument.defaultView.getComputedStyle(el,null).getPropertyValue(RS.utils.toHyphens(styleName));
	} else if(el.currentStyle) {
		style = el.currentStyle(RS.utils.toCamelCase(styleName));
	}
	return style;
};

RS.DOM.getArrayOfClassNames = function(el) {
	var classNames = [];
	if(el.className) {
		classNames = el.className.split(' ');
	}
	return classNames;
};

RS.DOM.get = function(el) {
	if(typeof el === "string") {
		el = document.getElementById(el);
	}
	return el;
};

RS.DOM.getElementsByClassName = function(className, tag, root) {
	tag = tag || "*";
	root = (root) ? RS.DOM.get(root) : null || document;
	if(!root) {
		return [];
	}
	var nodes = [];
	var elements = root.getElementsByTagName(tag);
	var hasClass = RS.DOM.hasClass;
	for(var i = 0, len = elements.length; i < len; ++i) {
		if(hasClass(elements[i], className)) {
			nodes[nodes.length] = elements[i];
		}
	}
	return nodes;
};

// Utils
RS.utils.toCamelCase = function(hyphenatedValue) {
	var result = hyphenatedValue.replace(/-\D/g, function(character) { return character.charAt(1).toUpperCase(); });
	return result;
};

RS.utils.toHyphens = function(camelCaseValue) {
	var result = camelCaseValue.replace(/[A-Z]/g, function(character) { return ('-' + character.charAt(0).toLowerCase());});
	return result;
};

RS.utils.tabCapture = function() {
	if(event.keyCode==9) {
		RS.events.preventDefault(event);
		return false;
	}
	return true;
};

// Framework Base Class

function frameworkSubclass (subClass, baseClass)
{	
	function inheritance() {}
	inheritance.prototype = baseClass.prototype;
	
	subClass.prototype = new inheritance();
	subClass.prototype.constructor = subClass;
	subClass.baseConstructor = baseClass;
	subClass.superClass = baseClass.prototype;
}

function frameworkObject (target, events)
{
	if (!events) {
		events = [];
	}
	
	this.controlID = target;
	this.implementedEvents = events;
	
	var installEvents = ['MouseDown','MouseUp','MouseDrag','MouseEnter','MouseExit','MouseMove','DoubleClick'];
	for (var i = 0; i < events.length; i++) {
		if (installEvents.indexOf(events[i]) > -1) {
			RS.input.install(this.object());
			break;
		}
	}
	
	RS.controls.push(this.controlID);
	RS.controls[this.controlID] = this;
}

frameworkObject.prototype = {
	controlID: "",
	mObject: null,
	mMouseOffsetX: 0,
	mMouseOffsetY: 0,
	mMouseDown: false,
	mEnabled: false,
	mBaseStyle: "",
	mOpacity: 1.0,
	shouldBecomeVisible: true,
	hasFinishedLoading: false,
	implementedEvents: [],
	menuID: "",
	name: function () {
		return this.controlID;
	},
	object: function () {
		var locate = false;
		try {
			if (this.mObject === null) {
				locate = true;
			} else if (this.mObject.offsetParent === null) {
				locate = true;
			}
		} catch (err) {
			locate = true;
		}
		if (locate === true) {
			this.mObject = document.getElementById(this.controlID);
		}
		return this.mObject;
	},
	parent: function () {
		return this.object().offsetParent;
	},
	value: function () {
		return null;
	},
	mouseDown: function () {
	},
	mouseDrag: function () {
	},
	mouseUp: function () {
	},
	mouseWheel: function () {
	},
	resize: function () {
		this.refresh();
	},
	resizeComplete: function () {
	},
	destroy: function () {
        var parent = this.object().offsetParent;
        if (parent) {
            parent.removeChild(this.object());
        }
		RS.controls.splice(RS.controls.indexOf(this.controlID),1);
	},
	enabled: function () {
		return this.mEnabled;
	},
	setEnabled: function (value) {
		this.setDisabledAppearance(! value);
		this.mEnabled = value;
	},
	setDisabledAppearance: function (value) {
		if(value == this.mEnabled) {
			var el = this.object();
			if (! value) {
				RS.DOM.removeClass(el,"disabled");
			} else {
				RS.DOM.addClass(el,"disabled");
			}
			if(typeof this.setAppearance == 'function') {
				this.setAppearance(!value);
			}
		}
	},
	visible: function ()
	{
		if (this.object().style.visibility == 'hidden') {
			return false;
		} else {
			return true;
		}
	},
	setVisible: function (value)
	{
		if (value) {
			this.object().style.display = 'block';
		} else {
			this.object().style.display = 'none';
		}
	},
	setStyle: function (value)
	{
		var className;
		if (value === null) {
			className = "";
		} else {
			className = value;
		}
		if (this.mBaseStyle !== "") {
			if (className !== "") {
				className = this.mBaseStyle + " " + className;
			} else {
				className = this.mBaseStyle;
			}
		}
		this.object().className = className;
	},
	refresh: function ()
	{
		if (RS.view.refresh.locked() === true) {
			if (RS.view.refresh.targets.indexOf(this) == -1) {
				RS.view.refresh.targets.push(this);
			}
		} else {
			this.willRefresh();
		}
	},
	willRefresh: function ()
	{
		// subclasses should override
	},
	focus: function ()
	{
		// subclasses should override
	},
	didFinishLoading: function ()
	{
		var obj = this.object();
		if (!obj) {
			return;
		}
		var style = obj.style;
		if (!style) {
			return;
		}
		if (this.shouldBecomeVisible === false) {
			style.display = 'none';
		}
		style.visibility = 'visible';
		this.finishedLoading();
	},
	finishedLoading: function ()
	{
		// subclasses should override
	},
	opacity: function ()
	{
		if (this.object().style.opacity) {
			return parseFloat(this.object().style.opacity);
		} else {
			return this.mOpacity;
		}
	},
	setOpacity: function (value)
	{
		this.mOpacity = value;
		
		var obj = this.object();
		obj.style.opacity = value.toString();
		try {
			obj.filters.alpha.opacity = value*100;
		} catch(err) {
			obj.style.filter = "alpha(opacity=" + (value*100) + ")";
		}
	},
	touchBegin: function (event, coordinates)
	{
	},
	touchMove: function (event, coordinates)
	{
	},
	touchEnd: function (event, coordinates)
	{
	},
	mouseEnter: function (event)
	{
	},
	mouseMove: function (event, coordinates)
	{
	},
	mouseExit: function (event)
	{
	},
	doubleClick: function (event, coordinates)
	{
	},
	keyDown: function (event)
	{
	},
	keyUp: function (event)
	{
	},
	presentContextualMenu: function (event) {
		if (this.menuID !== "") {
			var rect = this.bounds();
			
			RS.menus.dismissAllMenus();
			if (event) {
				var coordinates = RS.input.getCoordinates(null,event);
				RS.menus.displayMenuForPoint(this.menuID,coordinates[0].pageX,coordinates[0].pageY,-1);
			} else {
				RS.menus.displayMenuForRect(this.menuID,rect,null,null);
			}
			RS.menus.menuTarget = this;
			RS.menus.action = 'context';
		}
	},
	bounds: function () {
		var pos = getPosition(this.object());
		return new Rect(pos.x,pos.y,this.object().offsetWidth,this.object().offsetHeight);
	},
	menuItemSelected: function (menuID) {
		RS.comm.triggerEvent(this.controlID,'MenuSelected',[menuID]);
	}
};

// Rect

function Rect (left, top, width, height) {
	this.left = left;
	this.top = top;
	this.right = left + width;
	this.bottom = top + height;
}

Rect.prototype = {
	left: 0,
	top: 0,
	right: 0,
	bottom: 0,
	width: function () {
		return this.right - this.left;
	},
	height: function () {
		return this.bottom - this.top;
	},
	area: function () {
		return this.width() * this.height();
	},
	union: function (source) {
		var result = new Rect(0,0,0,0);
		result.left = Math.min(this.left,source.left);
		result.top = Math.min(this.top,source.top);
		result.right = Math.max(this.right,source.right);
		result.bottom = Math.max(this.bottom,source.bottom);
		return result;
	},
	containsPoint: function (x,y) {
		if ((x >= this.left) && (x <= this.right) && (y >= this.top) && (y <= this.bottom)) {
			return true;
		} else {
			return false;
		}
	},
	offset: function (left, top) {
		this.left = this.left + left;
		this.top = this.top + top;
	},
	verticalCenter: function () {
		return this.top + Math.floor(this.height() / 2);
	},
	horizontalCenter: function () {
		return this.left + Math.floor(this.width() / 2);
	}
};

function loadScript(id,url,callback,location,source) {
	if(location==undefined || location=="") location = "head";
	var targetEl = location;
	if(typeof location == "string") {
		targetEl = document.getElementsByTagName(location)[0];
		if(!targetEl) {
			targetEl = document.getElementById(location);
		}
	}
	if(targetEl) {
		var el = document.getElementById(id);
		if(!el) {
			var script = document.createElement("script")
			script.id = id;
			script.type = "text/javascript";
			if(url!=undefined && url!="") {
				if(script.readyState) {
					script.onreadystatechange = function(){
						if(script.readyState == "loaded" || script.readyState == "complete") {
							script.onreadystatechange = null;
							if(callback!=null) {
								callback();
							}
						}
					};
				} else {
					script.onload = function(ev) {
						if(callback!=null) {
							callback();
						}
					};
				}
				script.src = url;
			} else {
				if(source != undefined) script.innerHTML = source;
				if(callback!=null) {
					callback();
				}
			}
			targetEl.appendChild(script);
		} else {
			callback();
		}
	}
}

/*
Copyright © 2011 Yahoo! Inc. All rights reserved.
Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of Yahoo! Inc. nor the names of YUI's contributors may be used to endorse or promote products derived from this software without specific prior written permission of Yahoo! Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// User agent sniffer
RS.ua = function() {
	var numberfy = function(s) {
		var c = 0;
		return parseFloat(s.replace(/\./g, function() {
			return (c++ == 1) ? '' : '.';
		}));
	},
	nav = navigator,
	o = {
		ie: 0,
		opera: 0,
		gecko: 0,
		webkit: 0,
		mobile: null,
		air: 0,
		caja: nav.cajaVersion,
		secure: false,
		os: null
	},	    
	ua = navigator && navigator.userAgent, 
	loc = window && window.location,
	href = loc && loc.href,
	m;
	o.secure = href && (href.toLowerCase().indexOf("https") === 0);
    if (ua) {
        if ((/windows|win32/i).test(ua)) {
            o.os = 'windows';
        } else if ((/macintosh/i).test(ua)) {
            o.os = 'macintosh';
        } else if ((/linux/i).test(ua)) {
        	o.os = 'linux';
        }
    
        // Modern KHTML browsers should qualify as Safari X-Grade
        if ((/KHTML/).test(ua)) {
            o.webkit=1;
        }

        // Modern WebKit browsers are at least X-Grade
        m=ua.match(/AppleWebKit\/([^\s]*)/);
        if (m&&m[1]) {
            o.webkit=numberfy(m[1]);

            // Mobile browser check
            if (/ Mobile\//.test(ua)) {
                o.mobile = "iOS"; // iPhone or iPod Touch
            } else if(/Android/.test(ua)) {
            	o.mobile = "Android";
            } else {
                m=ua.match(/NokiaN[^\/]*/);
                if (m) {
                    o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
                }
            }

            m=ua.match(/AdobeAIR\/([^\s]*)/);
            if (m) {
                o.air = m[0]; // Adobe AIR 1.0 or better
            }

        }

        if (!o.webkit) { // not webkit
            // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
            m=ua.match(/Opera[\s\/]([^\s]*)/);
            if (m&&m[1]) {
                o.opera=numberfy(m[1]);
                m=ua.match(/Opera Mini[^;]*/);
                if (m) {
                    o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
                }
            } else { // not opera or webkit
                m=ua.match(/MSIE\s([^;]*)/);
                if (m&&m[1]) {
                    o.ie=numberfy(m[1]);
                } else { // not opera, webkit, or ie
                    m=ua.match(/Gecko\/([^\s]*)/);
                    if (m) {
                        o.gecko=1; // Gecko detected, look for revision
                        m=ua.match(/rv:([^\s\)]*)/);
                        if (m&&m[1]) {
                            o.gecko=numberfy(m[1]);
                        }
                    }
                }
            }
        }
    }

    return o;
}();

/* END: GLOBAL */

/* BEGIN: BUTTON */

// Button/framework.js
//
// Provides sync abilities to WebButton class
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function button (target, events)
{
	button.baseConstructor.call(this,target,events);
	
	var cid = this.controlID;
	if (events.indexOf('Action') > -1) {
		RS.events.addListener(this.field(),"click",function () { RS.controls[cid].action() },false);
	}
	RS.events.addListener(this.field(),"focus",function () { RS.input.setFocusControl(RS.controls[cid]) },false);
	RS.events.addListener(this.field(),"blur",function () { RS.input.setFocusControl(null) },false);
}
frameworkSubclass(button, frameworkObject);

button.prototype.action = function ()
{
	RS.comm.triggerEvent(this.controlID,'Action');
}

button.prototype.field = function ()
{
	return this.object().children[0];
};

button.prototype.value = function ()
{
	return this.field().value;
};

button.prototype.setValue = function (input)
{
	this.field().value = input;
};

button.prototype.setEnabled = function (value)
{
	if (value === true) {
		this.field().disabled = false;
	} else {
		this.field().disabled = true;
	}
	this.mEnabled = value;
};

button.prototype.setStyle = function (value)
{
	var className;
	if (value === null) {
		className = "";
	} else {
		className = value;
	}
	if (this.mBaseStyle !== "") {
		if (className !== "") {
			className = this.mBaseStyle + " " + className;
		} else {
			className = this.mBaseStyle;
		}
	}
	this.field().className = className;
};

button.prototype.keyDown = function (event)
{
	return true;
};

button.prototype.keyUp = function (event)
{
	return true;
};

/* END: BUTTON */

/* BEGIN: TEXTLABEL */

// TextLabel/framework.js
//
// Utility class for working with TextLabels
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function textlabel (target,events)
{
	textlabel.baseConstructor.call(this,target,events);
	var insides = this.object().innerHTML;
	this.object().innerHTML = '<div style="position: absolute; left: 0px; right: 0px; top: 50%; overflow: hidden;">M</div>';
	this.mLineHeight = this.innerCell().offsetHeight;
	this.innerCell().innerHTML = insides;
	this.refresh();
}
frameworkSubclass(textlabel, frameworkObject);
textlabel.prototype.mMultiline = false;
textlabel.prototype.mLineHeight = 0;

textlabel.prototype.value = function ()
{
	return this.innerCell().innerHTML;
};

textlabel.prototype.setAppearance = function(enabled) {
	try {
		var el = this.innerCell().children[0];
		if(enabled) {
			if(this.storedhref) el.setAttribute('href',this.storedhref);
			el.style.textDecoration = "";
		} else {
			this.storedhref = el.getAttribute('href');
			el.removeAttribute('href');
			if(this.storedhref != undefined && this.storedhref != "") {
				el.style.textDecoration = "underline";
			}
		}
	} catch(err) {	}
}

textlabel.prototype.setValue = function (input)
{
	this.innerCell().innerHTML = input;
	this.refresh();
};

textlabel.prototype.innerCell = function ()
{
	var obj = this.object().children[0];
	return obj;
};

textlabel.prototype.setMultiline = function (value)
{
	if (value != this.mMultiline) {
		this.mMultiline = value;
		this.refresh();
	}
};

textlabel.prototype.willRefresh = function ()
{
	var cell = this.innerCell();
	if (this.mMultiline) {
		cell.style.top = '0px';
		cell.style.bottom = '0px';
		cell.style.marginTop = '';
		cell.style.height = '';
		cell.style.maxHeight = '';
	} else {
		cell.style.top = '50%';
		cell.style.bottom = '';
		cell.style.marginTop = '-' + Math.floor(this.mLineHeight / 2) + 'px';
		cell.style.height = this.mLineHeight + 'px';
		cell.style.maxHeight = cell.style.height;
	}
};

/* END: TEXTLABEL */

/* BEGIN: TEXTCONTROL */

// TextControl/framework.js
//
// Utility class for working with input-based TextControls
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function textcontrol (target,events)
{
	textcontrol.baseConstructor.call(this,target,events);
	this.mBaseStyle = "textcontrol";
	var cid = this.controlID;
	RS.events.addListener(this.field(),"focus",function () { RS.input.setFocusControl(RS.controls[cid]) },false);
	RS.events.addListener(this.field(),"blur",function () { RS.input.setFocusControl(null) },false);
	this.catchMouseEvents();
}
frameworkSubclass(textcontrol, frameworkObject);
textcontrol.prototype.mDelayTimer = 0;

textcontrol.prototype.action = function ()
{
	if (this.implementedEvents.indexOf('TextChanged') > -1) {
		RS.comm.triggerEvent(this.controlID,'TextChanged');
	}
};

textcontrol.prototype.field = function ()
{
	return this.object().children[0];
};

textcontrol.prototype.value = function ()
{
	return this.field().value;
};

textcontrol.prototype.setValue = function (input)
{
	this.field().value = input;
};

textcontrol.prototype.setAppearance = function (enabled)
{
	if (enabled === true) {
		this.field().disabled = false;
	} else {
		this.field().disabled = true;
	}
};

textcontrol.prototype.focus = function ()
{
	this.field().focus();
};

textcontrol.prototype.setStyle = function (value)
{
	var className;
	if (value === null) {
		className = "";
	} else {
		className = value;
	}
	if (this.mBaseStyle !== "") {
		if (className !== "") {
			className = this.mBaseStyle + " " + className;
		} else {
			className = this.mBaseStyle;
		}
	}
	this.field().className = className;
};

textcontrol.prototype.insertText = function (position, value)
{
	var text = this.field().value;
	var pretext = text.substring(0,position - 1);
	var posttext = text.substring(position - 1);
	this.field().value = pretext + value + posttext;
};

textcontrol.prototype.keyDown = function (event)
{
	this.fireAction();
	return false;
};

textcontrol.prototype.keyUp = function (event)
{
	this.fireAction();
	return false;
};

textcontrol.prototype.fireAction = function() {
	markControlChanged(this);
	if (this.mDelayTimer !== 0) {
		clearTimeout(this.mDelayTimer);
		this.mDelayTimer = 0;
	}
	if (RS.comm.websockets.connected() === true) {
		this.mDelayTimer = setTimeout("RS.controls['" + this.controlID + "'].action()",100);
	} else {
		this.mDelayTimer = setTimeout("RS.controls['" + this.controlID + "'].action()",1000);
	}
};

textcontrol.prototype.setType = function(fieldType) {
	try {
		this.field().type = fieldType;
		this.catchMouseEvents();
	} catch(ex) {
		
	}
};

textcontrol.prototype.catchMouseEvents = function() {
	if (this.implementedEvents.indexOf('MouseUp') == -1) {
		var fieldType = this.field().type.toLowerCase();
		var that = this;
		switch(fieldType) {
		case "number":
			RS.events.addListener(this.field(),"mouseup",function(event) { textcontrol.prototype.touchEnd.call(that,event); },false);
			break;
		default:
			RS.events.removeListener(this.field(),"mouseup",function(event) { textcontrol.prototype.touchEnd.call(that,event); },false);
			break;
		}
	}
}

textcontrol.prototype.touchEnd = function(event)
{
	var fieldType = this.field().type.toLowerCase();
	if(fieldType == "number") {
		if (this.implementedEvents.indexOf('TextChanged') > -1) {
			markControlChanged(this);
			RS.comm.triggerEvent(this.controlID,'TextChanged');
		}
	}
};

/* END: TEXTCONTROL */

/* BEGIN: CHECKBOX */

// CheckBox/framework.js
//
// Utility class for working with checkboxes
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function checkbox (target, events)
{
	checkbox.baseConstructor.call(this,target,events);
	var box = document.getElementById(this.controlID + '_box');
	if (box) {
		if (box.checked) {
			this.mValue = true;
		} else {
			this.mValue = false;
		}
	}
	var cid = this.controlID;
	RS.events.addListener(box,"focus",function () { RS.input.setFocusControl(RS.controls[cid]) },false);
	RS.events.addListener(box,"blur",function () { RS.input.setFocusControl(null) },false);
}
frameworkSubclass(checkbox, frameworkObject);
checkbox.prototype.mValue = false;

checkbox.prototype.toggle = function ()
{
	var box = document.getElementById(this.controlID + '_box');
	if (!box) {
		return;
	}

	if (box.disabled === true) {
		return;
	}
	
	this.setValue(!this.value(),false);
};

checkbox.prototype.value = function ()
{
	return this.mValue;
};

checkbox.prototype.setValue = function (input,silent)
{
	if (typeof(silent) == 'undefined') {
		silent = false;
	}
	var box = document.getElementById(this.controlID + '_box');
	if (input === true) {
		box.checked = true;
		box.value = '1';
		this.mValue = true;
	} else {
		box.checked = false;
		box.value = '0';
		this.mValue = false;
	}
	if (silent === false) {
		markControlChanged(this);
		if (this.implementedEvents.indexOf('ValueChanged') > -1) {
			RS.comm.triggerEvent(this.controlID,'ValueChanged');
		}
	}
};

checkbox.prototype.caption = function ()
{
	var caption = document.getElementById(this.controlID + '_caption');
	return caption.innerHTML;
};

checkbox.prototype.setCaption = function (input)
{
	var caption = document.getElementById(this.controlID + '_caption');
	caption.innerHTML = input;
};

checkbox.prototype.enabled = function ()
{
	var box = document.getElementById(this.controlID + '_box');
	if (box.disabled === true) {
		return false;
	} else {
		return true;
	}
};

checkbox.prototype.setEnabled = function (input)
{
	var box = document.getElementById(this.controlID + '_box');
	
	if (input === true) {
		box.disabled = false;
	} else {
		box.disabled = true;
	}
	
	this.setDisabledAppearance(!input);
	this.mEnabled = input;
};

/* END: CHECKBOX */

/* BEGIN: ANIMATOR */

// Animator/framework.js
//
// Client-side Animator doesn't get much better than this
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function animatedObject (target, prefix)
{
	this.object = target;
	
	var style = target.object().style;
	this.TransitionProperty = style[prefix + 'TransitionProperty'];
	this.TransitionDuration = style[prefix + 'TransitionDuration'];
	this.TransitionTimingFunction = style[prefix + 'TransitionTimingFunction'];
	
	var parts = style[prefix + 'Transform'].split(' ');
	var i, chunk, part;
	var transforms = [];
	part = '';
	for (i = 0; i < parts.length; i++) {
		chunk = parts[i];
		if (chunk.substring(chunk.length - 1) == ')') {
			transforms.push(part + chunk);
			part = '';
		} else {
			part += chunk;
		}
	}
	
	this.Transforms = transforms;
}

animatedObject.prototype = {
	object: null,
	TransitionProperty: '',
	TransitionDuration: '',
	TransitionTimingFunction: '',
	Transforms: [],
	OnComplete: '',
	addValues: function (properties, duration, timingFunction, transform)
	{
		if (this.TransitionProperty == 'none') {
			this.TransitionProperty = '';
		}
		if (this.TransitionProperty.indexOf(properties) == -1) {
			if (this.TransitionProperty !== '') {
				this.TransitionProperty += ', ';
			}
			this.TransitionProperty += properties;
		}
		this.TransitionDuration = duration;
		this.TransitionTimingFunction = timingFunction;
		
		if (transform) {
			var transformName = transform.substring(0,transform.indexOf("("));
			var i, functionName, found;
			
			found = false;
			for (i = 0; i < this.Transforms.length; i++) {
				functionName = this.Transforms[i];
				if (functionName.substring(0,transformName.length) == transformName) {
					found = true;
					this.Transforms[i] = transform;
				}
			}
			
			if (!found) {
				this.Transforms.push(transform);
			}
		}
	}
};

function animator (target, events)
{
	animator.baseConstructor.call(this,target,events);
	addPostLoadObject(this);
	
	var element = document.createElement('a');
	var prefixes = ['','Webkit','Moz','O','ms'];
	var i;
	for (i = 0; i < prefixes.length; i++) {
		var type = typeof element.style[prefixes[i] + 'Transform'];
		if (type !== 'undefined') {
			this.jsPrefix = prefixes[i];
			break;
		}
	}
	
	if ((RS.platform == 2) && (RS.browser == 1)) {
		// Nasty bug in Windows Safari. I hate this, but there's no other way.
		this.jsPrefix = '';
		this.cssPrefix = '';
		this.css3D = false;
		this.css2D = false;
		this.cssTransitions = false;
	} else {
		if ((typeof element.style[this.jsPrefix + 'Perspective']) !== 'undefined') {
			this.css3D = true;
		}
		if ((typeof element.style[this.jsPrefix + 'Transition']) !== 'undefined') {
			this.cssTransitions = true;
		}
		if ((typeof element.style[this.jsPrefix + 'Transform']) !== 'undefined') {
			this.css2D = true;
		}
		if (this.jsPrefix !== '') {
			this.cssPrefix = '-' + this.jsPrefix.toLowerCase() + '-';
		}
	}
	
	markControlChanged(this);
}
frameworkSubclass(animator,frameworkObject);
animator.prototype.objects = [];
animator.prototype.timeouts = [];
animator.prototype.moveActions = [];
animator.prototype.resizeActions = [];
animator.prototype.opacityActions = [];
animator.prototype.colorActions = [];
animator.prototype.cssPrefix = '';
animator.prototype.jsPrefix = '';
animator.prototype.css2D = false;
animator.prototype.css3D = false;
animator.prototype.cssTransitions = false;

animator.prototype.value = function ()
{
	var s = '';
	if ((this.css2D) && (this.cssTransitions)) {
		s = "true";
	} else {
		s = "false";
	}
	if ((this.css3D) && (this.cssTransitions)) {
		s += " true";
	} else {
		s += " false";
	}
	if (RS.opacitySupported === true) {
		s += " true";
	} else {
		s += " false";
	}
	return s;
};

animator.prototype.findIndexForObject = function (target)
{
	var i, obj;
	for (i = 0; i < this.objects.length; i++) {
		obj = this.objects[i];
		if (obj.object == target) {
			return i;
		}
	}
	
	obj = new animatedObject(target,this.jsPrefix);
	this.objects.push(obj);
	return this.objects.length - 1;
};

animator.prototype.postLoad = function ()
{
	var i, obj, style;
	for (i = 0; i < this.timeouts.length; i++) {
		clearTimeout(this.timeouts[i]);
	}
	this.timeouts = [];
	
	for (i = 0; i < this.objects.length; i++) {
		obj = this.objects[i];
		if (obj.object.object() === null) {
			continue;
		}
		style = obj.object.object().style;
		
		style[this.jsPrefix + 'TransitionProperty'] = obj.TransitionProperty;
		style[this.jsPrefix + 'TransitionDuration'] = obj.TransitionDuration + 's';
		style[this.jsPrefix + 'TransitionTimingFunction'] = obj.TransitionTimingFunction;
		style[this.jsPrefix + 'Transform'] = obj.Transforms.join(' ');
		
		if ((typeof(obj.left) !== 'undefined') && (obj.left !== null)) {
			style.left = obj.left;
		}
		if ((typeof(obj.top) !== 'undefined') && (obj.top !== null)) {
			style.top = obj.top;
		}
		if ((typeof(obj.width) !== 'undefined') && (obj.width !== null)) {
			style.width = obj.width;
		}
		if ((typeof(obj.height) !== 'undefined') && (obj.height !== null)) {
			style.height = obj.height;
		}
		if ((typeof(obj.opacity) !== 'undefined') && (obj.opacity !== null)) {
			obj.object.setOpacity(obj.opacity);
		}
		if ((typeof(obj.color) !== 'undefined') && (obj.color !== null)) {
			style.backgroundColor = obj.color;
		}
        if ((typeof(obj.marginLeft) !== 'undefined') && (obj.marginLeft !== null)) {
            style.marginLeft = obj.marginLeft;
        }
        if ((typeof(obj.marginTop) !== 'undefined') && (obj.marginTop !== null)) {
            style.marginTop = obj.marginTop;
        }
		
		if (obj.OnComplete !== '') {
			this.timeouts.push(setTimeout(obj.OnComplete,obj.TransitionDuration * 1000));
		}
		this.timeouts.push(setTimeout("RS.controls['" + this.controlID + "'].complete(RS.controls['" + obj.object.controlID + "'])",obj.TransitionDuration * 1000));
	}
	
	this.objects = [];
};

animator.prototype.complete = function (target)
{
	var obj = target.object();
	if (obj) {
		var style = obj.style;
		style[this.jsPrefix + 'TransitionProperty'] = 'none';
	}
	if (target.animationComplete) {
		target.animationComplete();
	}
};

animator.prototype.move = function (target, left, top, durationInSeconds, easing)
{
	if (this.cssTransitions) {
		var idx = this.findIndexForObject(target);
		var p;
		if ((left !== null) && (top !== null)) {
			p = 'left, top';
		} else if (left !== null) {
			p = 'left';
		} else if (top !== null) {
			p = 'top';
		} else {
			return;
		}
		this.objects[idx].addValues(p,durationInSeconds,easing);
		if (left !== null) {
			this.objects[idx].left = left;
		} else {
			this.objects[idx].left = null;
		}
		if (top !== null) {
			this.objects[idx].top = top;
		} else {
			this.objects[idx].top = null;
		}
	} else {
		var i;
		for (i = 0; i < this.moveActions.length; i++) {
			clearTimeout(this.moveActions[i]);
		}
		this.moveActions = [];
		
		var obj = target.object();
        var leftSuffix, leftDiff, leftStart;
        var topSuffix, topDiff, topStart;
		if (left !== null) {
            leftStart = obj.style.left;
            if (left.substring(left.length - 1) == '%') {
                leftSuffix = '%';
                if (leftStart === '') {
                    leftStart = (obj.offsetLeft + (obj.offsetWidth / 2)) / obj.offsetParent.offsetWidth;
                    leftStart = Math.floor(leftStart * 100);
                } else {
                    leftStart = parseInt(leftStart.substring(0,leftStart.length - 1),10);
                }
                left = parseInt(left.substring(0,left.length - 1),10);
            } else {
                leftSuffix = 'px';
                if (leftStart === '') {
                    leftStart = obj.offsetLeft;
                } else {
                    leftStart = parseInt(leftStart.substring(0,leftStart.length - 2),10);
                }
                left = parseInt(left.substring(0,left.length - 2),10);
            }
            leftDiff = left - leftStart;
		}
		if (top !== null) {
			topStart = obj.style.top;
            if (topStart.substring(topStart.length - 1) == '%') {
                topSuffix = '%';
                if (topStart === '') {
                    topStart = (obj.offsetTop + (obj.offsetHeight / 2)) / obj.offsetParent.offsetHeight;
                    topStart = Math.floor(topStart * 100);
                } else {
                    topStart = parseInt(topStart.substring(0,topStart.length - 1),10);
                }
                top = parseInt(top.substring(0,top.length - 1),10);
            } else {
                topSuffix = 'px';
                if (topStart === '') {
                    topStart = obj.offsetTop;
                } else {
                    topStart = parseInt(topStart.substring(0,topStart.length - 2),10);
                }
                top = parseInt(top.substring(0,top.length - 2),10);
            }
            topDiff = top - topStart;
		}
		
		var delay = 1/24;
		var tickDelay = delay * 1000;
		var frames = Math.ceil(durationInSeconds * (1 / delay));
		var frame, period, cmd, leftPos, topPos;
		
		for (frame = 0; frame <= frames; frame++) {
			period = Math.floor(frame * tickDelay);
			if (frame == frames) {
				period = durationInSeconds * 1000;
			}
			if (left !== null) {
				leftPos = "'" + (Math.floor(this.getEaseValue(easing,period / 1000,leftStart,leftDiff,durationInSeconds) * 100) / 100) + leftSuffix + "'";
			} else {
				leftPos = "null";
			}
			if (top !== null) {
				topPos = "'" + (Math.floor(this.getEaseValue(easing,period / 1000,topStart,topDiff,durationInSeconds) * 100) / 100) + topSuffix + "'";
			} else {
				topPos = "null";
			}
			cmd = "RS.controls['" + this.controlID + "'].moveStep(RS.controls['" + target.controlID + "']," + leftPos + "," + topPos + ")";
			this.moveActions.push(setTimeout(cmd,period));
		}
		if (target.animationComplete) {
			this.moveActions.push(setTimeout("RS.controls['" + target.controlID + "'].animationComplete()",durationInSeconds * 1000));
		}
	}
};

animator.prototype.moveStep = function (target, left, top)
{
	var obj = target.object();
	var style = obj.style;
	if (left !== null) {
		if (style.left != left) {
			style.left = left;
		}
	}
	if (top !== null) {
		if (style.top != top) {
			style.top = top;
		}
	}
};

animator.prototype.resize = function (target, width, height, durationInSeconds, easing, widthCenter, heightCenter)
{
	if (widthCenter === null) {
        widthCenter = false;
    }
    if (heightCenter === null) {
        heightCenter = false;
    }
    var obj = target.object();
    if (this.cssTransitions) {
		var idx = this.findIndexForObject(target);
        var values = 'width, height';
        if (widthCenter === true) {
            values = values + ', marginLeft';
        }
        if (heightCenter === true) {
            values = values + ', marginTop';
        }
		this.objects[idx].addValues(values,durationInSeconds,easing);
		this.objects[idx].width = width + 'px';
		this.objects[idx].height = height + 'px';
        if (widthCenter === true) {
            this.objects[idx].marginLeft = '-' + Math.floor(width / 2) + 'px';
        }
        if (heightCenter === true) {
            this.objects[idx].marginTop = '-' + Math.floor(height / 2) + 'px';
        }
	} else {
		var i;
		for (i = 0; i < this.resizeActions.length; i++) {
			clearTimeout(this.resizeActions[i]);
		}
		this.resizeActions = [];
		
		var startWidth = obj.clientWidth;
		var startHeight = obj.clientHeight;
		var widthDiff = width - startWidth;
		var heightDiff = height - startHeight;
		
		var delay = 1/24;
		var tickDelay = delay * 1000;
		var frames = Math.ceil(durationInSeconds * (1 / delay));
		var frame, period, cmd, widthValue, heightValue;
		
		for (frame = 0; frame <= frames; frame++) {
			period = Math.floor(frame * tickDelay);
			if (frame == frames) {
				period = durationInSeconds * 1000;
			}
			widthValue = this.getEaseValue(easing,period / 1000,startWidth,widthDiff,durationInSeconds);
			heightValue = this.getEaseValue(easing,period / 1000,startHeight,heightDiff,durationInSeconds);
			cmd = "RS.controls['" + this.controlID + "'].resizeStep(RS.controls['" + target.controlID + "']," + widthValue + "," + heightValue + "," + widthCenter + "," + heightCenter + ")";
			this.resizeActions.push(setTimeout(cmd,period));
		}
		if (target.animationComplete) {
			this.resizeActions.push(setTimeout("RS.controls['" + target.controlID + "'].animationComplete()",durationInSeconds * 1000));
		}
	}
};

animator.prototype.resizeStep = function (target, width, height, widthCenter, heightCenter)
{
	var obj = target.object();
	var style = obj.style;
	if (style.width != width + 'px') {
		style.width = width + 'px';
        if (widthCenter === true) {
            style.marginLeft = '-' + Math.floor(width / 2) + 'px';
        }
	}
	if (style.height != height + 'px') {
		style.height = height + 'px';
        if (heightCenter === true) {
            style.marginTop = '-' + Math.floor(height / 2) + 'px';
        }
	}
};

animator.prototype.setopacity = function (target, opacity, durationInSeconds, easing)
{
	if (this.cssTransitions) {		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues('opacity',durationInSeconds,easing);
		this.objects[idx].opacity = opacity;
	} else {
		var i;
		for (i = 0; i < this.opacityActions.length; i++) {
			clearTimeout(this.opacityActions[i]);
		}
		this.opacityActions = [];
		
		if (durationInSeconds > 0) {
			var startOpacity = target.opacity();
			var opacityDiff = opacity - startOpacity;
			
			var delay = 1/24;
			var tickDelay = delay * 1000;
			var frames = Math.ceil(durationInSeconds * (1 / delay));
			var frame, period, cmd, opacityValue;
			
			for (frame = 0; frame <= frames; frame++) {
				period = Math.floor(frame * tickDelay);
				if (frame == frames) {
					period = durationInSeconds * 1000;
				}
				opacityValue = this.getEaseValue(easing,period / 1000,startOpacity,opacityDiff,durationInSeconds);
				cmd = "RS.controls['" + this.controlID + "'].opacityStep(RS.controls['" + target.controlID + "']," + opacityValue + ")";
				this.opacityActions.push(setTimeout(cmd,period));
			}
		} else {
			RS.controls[this.controlID].opacityStep(RS.controls[target.controlID],opacity);
		}
		if (target.animationComplete) {
			this.opacityActions.push(setTimeout("RS.controls['" + target.controlID + "'].animationComplete()",durationInSeconds * 1000));
		}
	}
};

animator.prototype.opacityStep = function (target, opacity)
{
	target.setOpacity(opacity);
};

animator.prototype.setcolor = function (target, red, green, blue, opacity, durationInSeconds, easing)
{
	if (this.cssTransitions) {
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues('background-color',durationInSeconds,easing);
		this.objects[idx].color = 'rgba(' + red + ',' + green + ',' + blue + ',' + opacity + ')';
	} else {
		var i;
		for (i = 0; i < this.colorActions.length; i++) {
			clearTimeout(this.colorActions[i]);
		}
		this.colorActions = [];
		
		var obj = target.object();
		var style = obj.style;
		
		var colorValue = style.backgroundColor;
		if (colorValue == 'transparent') {
			colorValue = 'rgba(0,0,0,0)';
		}
		colorValue = colorValue.substring(colorValue.indexOf('(') + 1);
		colorValue = colorValue.substring(0,colorValue.indexOf(')'));
		var parts = colorValue.split(',');
		var startRed = parseInt(parts[0],10);
		var startGreen = parseInt(parts[1],10);
		var startBlue = parseInt(parts[2],10);
		var startOpacity = parseFloat(parts[3]);
		var redDiff = red - startRed;
		var greenDiff = green - startGreen;
		var blueDiff = blue - startBlue;
		var opacityDiff = opacity - startOpacity;
		
		var delay = 1/24;
		var tickDelay = delay * 1000;
		var frames = Math.ceil(durationInSeconds * (1 / delay));
		var frame, period, cmd, redValue, blueValue, greenValue, opacityValue;
		
		for (frame = 0; frame <= frames; frame++) {
			period = Math.floor(frame * tickDelay);
			if (frame == frames) {
				period = durationInSeconds * 1000;
			}
			redValue = this.getEaseValue(easing,period / 1000,startRed,redDiff,durationInSeconds);
			greenValue = this.getEaseValue(easing,period / 1000,startGreen,greenDiff,durationInSeconds);
			blueValue = this.getEaseValue(easing,period / 1000,startBlue,blueDiff,durationInSeconds);
			opacityValue = this.getEaseValue(easing,period / 1000,startOpacity,opacityDiff,durationInSeconds);
			cmd = "RS.controls['" + this.controlID + "'].colorStep(RS.controls['" + target.controlID + "']," + redValue + "," + greenValue + "," + blueValue + "," + opacityValue + ")";
			this.colorActions.push(setTimeout(cmd,period));
		}
		if (target.animationComplete) {
			this.colorActions.push(setTimeout("RS.controls['" + target.controlID + "'].animationComplete()",durationInSeconds * 1000));
		}
	}
};

animator.prototype.colorStep = function (target, red, green, blue, opacity)
{
	var obj = target.object();
	var style = obj.style;
	var s = "rgba(" + red + "," + green + "," + blue + "," + opacity + ")";
	if (style.backgroundColor != s) {
		style.backgroundColor = s;
	}
};

animator.prototype.scale = function (target, widthfactor, heightfactor, durationInSeconds, easing)
{
	if ((this.css2D) && (this.cssTransitions)) {
		var js = 'scale(' + widthfactor + ',' + heightfactor + ')';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.rotatex = function (target, degrees,  durationInSeconds, easing)
{
	if ((this.css3D) && (this.cssTransitions)) {
		var js = 'rotatex(' + degrees + 'deg)';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.rotatey = function (target, degrees,  durationInSeconds, easing)
{
	if ((this.css3D) && (this.cssTransitions)) {
		var js = 'rotatey(' + degrees + 'deg)';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.rotatez = function (target, degrees,  durationInSeconds, easing)
{
	if ((this.css2D) && (this.cssTransitions)) {
		var js = 'rotatez(' + degrees + 'deg)';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.skewx = function (target, degrees,  durationInSeconds, easing)
{
	if ((this.css2D) && (this.cssTransitions)) {
		var js = 'skewx(' + degrees + 'deg)';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.skewy = function (target, degrees,  durationInSeconds, easing)
{
	if ((this.css2D) && (this.cssTransitions)) {
		var js = 'skewy(' + degrees + 'deg)';
		
		var idx = this.findIndexForObject(target);
		this.objects[idx].addValues(this.cssPrefix + 'transform',durationInSeconds,easing,js);
	}
};

animator.prototype.getEaseValue = function (timingFunction, elapsed, startValue, changeInValue, duration)
{
	switch (timingFunction) {
		case 'linear':
			return ((changeInValue * elapsed) / duration) + startValue;
		case 'ease-in':
			elapsed = (elapsed / duration);
			return (((changeInValue * ((elapsed))) * elapsed) * elapsed) + startValue;
		case 'ease-out':
			elapsed = (elapsed / duration) - 1;
			return (changeInValue * (((((elapsed)) * elapsed) * elapsed) + 1)) + startValue;
		case 'ease-in-out':
			elapsed = elapsed / (duration / 2);
			if (elapsed < 1) {
				return ((((changeInValue / 2) * elapsed) * elapsed) * elapsed) + startValue;
			}
			elapsed = elapsed - 2;
			return ((changeInValue / 2) * (((elapsed * elapsed) * elapsed) + 2)) + startValue;
		default:
			return 0;
	}
};

/* END: ANIMATOR */

/* BEGIN: DIALOG */

// Dialog/framework.js
//
// Utility class for working with dialogs
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function dialog (target,events)
{
	dialog.baseConstructor.call(this,target,events);
	
	if (this.type() == 'hud') {
		this.mImagePrefix = 'hud';
	} else {
		this.mImagePrefix = 'palette';
	}

	cacheImage('/framework/' + this.mImagePrefix + '_resize.png');

	var resizeHandle = document.createElement('img');
	resizeHandle.id = this.controlID + '_resize';
	resizeHandle.className = 'resize';
	resizeHandle.src = '/framework/' + this.mImagePrefix + '_resize.png';
	resizeHandle.width = 15;
	resizeHandle.height = 15;
	resizeHandle.alt = '';
	document.getElementById(this.controlID + '_body').appendChild(resizeHandle);
	RS.input.install(resizeHandle);
	
	var anim = document.createElement('div');
	anim.id = this.controlID + '_anim';
	anim.setAttribute('style','display: none;');
	anim.innerHTML = '&nbsp;';
	this.object().appendChild(anim);
	this.animator = new animator(this.controlID + '_anim',[]);
	
	switch (this.object().className) {
		case 'palette':
		case 'hud':
			cacheImage('/framework/' + this.mImagePrefix + '_close_normal.png');
			cacheImage('/framework/' + this.mImagePrefix + '_close_hover.png');
			cacheImage('/framework/' + this.mImagePrefix + '_close_pressed.png');
			
			RS.input.install(document.getElementById(this.controlID + '_titlebar'));
			
			break;
	}
	this.mBaseStyle = this.object().className;
	this.body = new frameworkObject(this.controlID + '_body');
}

frameworkSubclass(dialog, frameworkObject);
dialog.prototype.mInsideRect = 0;
dialog.prototype.mImagePrefix = 'palette';
dialog.prototype.animator = null;
dialog.prototype.body = null;
dialog.prototype.mOpen = false;

dialog.prototype.didFinishLoading = function ()
{
	this.object().style.display = 'none';
	this.object().style.visibility = 'visible';
};

dialog.prototype.present = function ()
{
	this.mOpen = true;
	switch (this.object().className) {
	case 'sheet':
		this.object().style.visibility = 'hidden';
		this.object().style.display = 'block';
		RS.view.preventScrolling();
		
		var body = document.getElementById(this.controlID + '_body');
		var bodyHeight = body.offsetHeight;
		
		body.style.top = '-' + bodyHeight + 'px';
		if (RS.opacitySupported === true) {
			this.setOpacity(0);
		}
		this.object().style.visibility = 'visible';
		
		this.animator.move(this.body,null,'0px',0.2,'ease-out');
		if (RS.opacitySupported === true) {
			this.animator.setopacity(this,1,0.2,'ease-out');
		}
		break;
	case 'modal':
	case 'palette':
	case 'hud':
		this.object().style.display = 'block';
		
		if (RS.opacitySupported === true) {
			this.setOpacity(0);
			this.animator.setopacity(this,1,0.2,'ease-out');
		} else {
			this.object().style.display = 'block';
		}
        var style;
        if (this.object().className == 'modal') {
			RS.view.preventScrolling();
            style = document.getElementById(this.controlID + '_body').style;
        } else {
            style = this.object().style;
        }
        if ((typeof style[this.animator.jsPrefix + 'AnimationName']) !== 'undefined') {
            style[this.animator.jsPrefix + 'AnimationName'] = 'pop';
            style[this.animator.jsPrefix + 'AnimationDuration'] = '0.2s';
            style[this.animator.jsPrefix + 'AnimationDirection'] = 'normal';
            style[this.animator.jsPrefix + 'AnimationIterationCount'] = '1';
        }
		break;
	}
	
	// fire the Shown event
	RS.comm.triggerEvent(this.controlID,'DialogShown');
	
	//Set focus on the first field
	var els = RS.DOM.getElementsByClassName("tabWrapFirstField","input",this.controlID);
	if(els.length > 0) {
		els[els.length-1].focus();
	}
};

dialog.prototype.dismiss = function ()
{
	// fire the Dismissed event
	RS.comm.triggerEvent(this.controlID,'DialogDismissed');
	
	this.mOpen = false;
	switch (this.object().className) {
	case 'sheet':
		var body = document.getElementById(this.controlID + '_body');
		var bodyHeight = body.offsetHeight;
		
		this.animator.move(this.body,null,(bodyHeight * -1) + 'px',0.2,'ease-out');
		this.animator.setopacity(this,0,0.2,'ease-out');
		break;
	case 'modal':
	case 'palette':
	case 'hud':
		if (RS.opacitySupported === true) {
			this.animator.setopacity(this,0,0.2,'ease-out');
		} else {
			this.object().style.display = 'none';
		}
		break;
	}
	setTimeout("RS.controls['" + this.controlID + "'].object().style.display = 'none';",300);
	RS.view.allowScrolling();
};

dialog.prototype.animationComplete = function ()
{
	if (this.object() === null) {
		return;
	}
	
	if (this.mOpen === true) {
		return;
	}
	
	switch (this.object().className) {
	case 'sheet':
		this.object().style.visibility = 'hidden';
		this.object().style.display = 'none';
		break;
	case 'modal':
	case 'palette':
	case 'hud':
		this.object().style.display = 'none';
		break;
	}
};

dialog.prototype.touchBegin = function (event, coordinates)
{
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	
	var widget = document.getElementById(this.controlID + '_close');
	var widgetTop = 0, widgetHeight = 0, widgetLeft = 0, widgetWidth = 0;
	if (widget) {
		widgetTop = widget.parentNode.offsetTop;
		widgetHeight = widget.parentNode.offsetHeight;
		widgetLeft = widget.parentNode.offsetLeft;
		widgetWidth = widget.parentNode.offsetWidth;
	}
	
	var resize = document.getElementById(this.controlID + '_resize');
	var resizeTop = resize.offsetTop;
	var resizeHeight = resize.offsetHeight;
	var resizeLeft = resize.offsetLeft;
	var resizeWidth = resize.offsetWidth;
	
	var titlebar = document.getElementById(this.controlID + '_titlebar');
	if (titlebar) {
		resizeTop = resizeTop + titlebar.offsetHeight;
	}
	
	switch (this.object().className) {
	case 'sheet':
	case 'modal':
		var target = document.getElementById(this.controlID + '_body');
		resizeTop = resizeTop + target.offsetTop;
		resizeLeft = resizeLeft + target.offsetLeft;
		break;
	}
	
	if ((widget) && (x >= widgetLeft) && (x <= widgetLeft + widgetWidth) && (y >= widgetTop) && (y <= widgetTop + widgetHeight)) {
		this.mInsideRect = 1;
		widget.src = '/framework/' + this.type() + '_close_pressed.png';
	} else if ((x >= resizeLeft) && (x <= resizeLeft + resizeWidth) && (y >= resizeTop) && (y <= resizeTop + resizeHeight)) {
		this.mInsideRect = 2;
	} else {
		this.mInsideRect = 0;
	}
	
	this.mMouseOffsetX = x;
	this.mMouseOffsetY = y;
	this.mMouseDown = true;
	
	return true;
};

dialog.prototype.touchMove = function (event, coordinates)
{
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	var thisClassName = this.object().className;
	
	var target;
	switch (thisClassName) {
	case 'sheet':
	case 'modal':
		target = document.getElementById(this.controlID + '_body');
		break;
	default:
		target = this.object();
	}
	
	switch (this.mInsideRect) {
	case 1:
		break;
	case 2:
		var diffWidth = x - this.mMouseOffsetX;
		var diffHeight = y - this.mMouseOffsetY;
		switch (thisClassName) {
		case 'palette':
			diffWidth = diffWidth - 2;
			diffHeight = diffHeight - 2;
		}
		var targetWidth = target.offsetWidth + diffWidth;
		var targetHeight = target.offsetHeight + diffHeight;
		
		switch (thisClassName) {
		case 'modal':
			targetHeight = targetHeight + diffHeight;
			target.style.marginTop = '-' + Math.floor(targetHeight / 2) + 'px';
			// don't break here
		case 'sheet':
			targetWidth = targetWidth + diffWidth;
			target.style.marginLeft = '-' + Math.floor(targetWidth / 2) + 'px';
			break;
		}
		
		target.style.width = targetWidth + 'px';
		target.style.height = targetHeight + 'px';
		
		this.mMouseOffsetX = x;
		this.mMouseOffsetY = y;
		break;
	default:
		switch (thisClassName) {
		case 'palette':
			var styleY = (coordinates[0].pageY - this.mMouseOffsetY) + 'px';
			if (target.style.top != styleY) {
				target.style.top = styleY;
			}
			var styleX = (coordinates[0].pageX - this.mMouseOffsetX) + 'px';
			if (target.style.left != styleX) {
				target.style.left = styleX;
			}
			break;
			
		default:
			break;
		}
		break;
	}
	
	return true;
};

dialog.prototype.touchEnd = function (event, coordinates)
{
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	
	switch (this.mInsideRect) {
	case 1:
		var widget = document.getElementById(this.controlID + '_close');
		if (widget) {
			var widgetTop = widget.parentNode.offsetTop;
			var widgetHeight = widget.parentNode.offsetHeight;
			var widgetLeft = widget.parentNode.offsetLeft;
			var widgetWidth = widget.parentNode.offsetWidth;
			
			if ((x >= widgetLeft) && (x <= widgetLeft + widgetWidth) && (y >= widgetTop) && (y <= widgetTop + widgetHeight)) {
				widget.src = '/framework/' + this.type() + '_close_hover.png';
				RS.comm.triggerEvent(this.controlID,'Closed');
			} else {
				widget.src = '/framework/' + this.type() + '_close_normal.png';
			}
		}
		break;
	case 2:
		RS.comm.triggerEvent(this.controlID,'DialogResized',[this.object().offsetWidth,this.object().offsetHeight]);
		break;
	default:
		if (this.implementedEvents.indexOf('Moved') > -1) {
			RS.comm.triggerEvent(this.controlID,'Moved',[this.object().offsetLeft,this.object().offsetTop]);
		}
		break;
	}
	
	this.mMouseDown = false;
	return true;
};

dialog.prototype.closeMouseEnter = function ()
{
	var widget = document.getElementById(this.controlID + '_close');
	if ((widget) && (this.mMouseDown)) {
		widget.src = '/framework/' + this.type() + '_close_pressed.png';
	} else {
		widget.src = '/framework/' + this.type() + '_close_hover.png';
	}
};

dialog.prototype.closeMouseExit = function ()
{
	var widget = document.getElementById(this.controlID + '_close');
	if (widget) {
		widget.src = '/framework/' + this.type() + '_close_normal.png';
	}
};

dialog.prototype.setTitle = function (value)
{
	var title = document.getElementById(this.controlID + '_titlecell');
	if (!title) {
		return;
	}
	title.innerHTML = value;
};

dialog.prototype.setResizable = function (showResize)
{
	var resize = document.getElementById(this.controlID + '_resize');
	if (!resize) {
		return;
	}
	if (showResize) {
		resize.style.display = 'block';
	} else {
		resize.style.display = 'none';
	}
};

dialog.prototype.type = function ()
{
	return this.object().className;
};

dialog.prototype.setEnabled = function (value)
{
	this.mEnabled = value;
};

dialog.prototype.destroy = function () {
	var parent = document.getElementById('REALDialogs');
	if (parent) {
		parent.removeChild(this.object());
	}
	RS.controls.splice(RS.controls.indexOf(this.controlID),3);
};

/* END: DIALOG */

/* BEGIN: SCROLLBAR */

// ScrollBar/framework.js
//
// Utility class for working with scrollbars
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function scrollbar (target, events)
{
	scrollbar.baseConstructor.call(this,target,events);
	
    var obj = this.object();
	obj.innerHTML = '<div class="decrease"></div><div class="increase"></div><div class="track"><div class="thumb"></div></div>';
	
	switch (this.object().className) {
	case 'scrollbar vertical':
		this.mVertical = true;
		this.baseStyle = this.object().className;
		break;
	case 'scrollbar horizontal':
		this.mVertical = false;
		this.baseStyle = this.object().className;
		break;
	default:
		this.mVertical = this.object().offsetHeight > this.object().offsetWidth;
		if (this.mVertical) {
			this.baseStyle = 'scrollbar vertical';
		} else {
			this.baseStyle = 'scrollbar horizontal';
		}
		break;
	}
    
	RS.input.install(this.object());
	RS.view.sizing.targets.push(this);
	addWheelTarget(this);
}

frameworkSubclass(scrollbar, frameworkObject);
scrollbar.prototype.mMinimum = 0;
scrollbar.prototype.mMaximum = 0;
scrollbar.prototype.mValue = 0;
scrollbar.prototype.mPageStep = 20;
scrollbar.prototype.mLineStep = 1;
scrollbar.prototype.mMouseDownX = 0;
scrollbar.prototype.mMouseDownY = 0;
scrollbar.prototype.mVertical = true;
scrollbar.prototype.mInsideThumb = false;
scrollbar.prototype.mInsideTrack = false;
scrollbar.prototype.mHoldWidget = null;
scrollbar.prototype.mAnimator = 0;
scrollbar.prototype.valueChanged = '';
scrollbar.prototype.animator = 0;
scrollbar.prototype.animationElapsed = 0;
scrollbar.prototype.animationPeriod = Math.floor(1000 / 60);
scrollbar.prototype.animationStartValue = 0;
scrollbar.prototype.animationEndValue = 0;
scrollbar.prototype.animationDuration = 500;

scrollbar.prototype.touchBegin = function (event, coordinates)
{
	if(this.mEnabled) {
		if (this.mMaximum <= this.mMinimum) {
			return true;
		}
		var x = coordinates[0].x;
		var y = coordinates[0].y;
		
		var track = findChildrenByClass(this.object(),'track');
		track = track[0];
		var thumb = findChildrenByClass(track,'thumb');
		thumb = thumb[0];
		
		if (this.mAnimator !== 0) {
			clearInterval(this.mAnimator);
			this.mAnimator = 0;
		}
		
		if (this.mVertical) {
			this.mInsideTrack = ((y >= track.offsetTop) && (y <= track.offsetTop + track.offsetHeight));
			if (this.mInsideTrack) {
				y = y - track.offsetTop;
				this.mInsideThumb = ((y >= thumb.offsetTop) && (y <= thumb.offsetTop + thumb.offsetHeight));
				if (this.mInsideThumb) {
					y = y - thumb.offsetTop;
				}
			} else {
				this.mInsideThumb = false;
			}
		} else {
			this.mInsideTrack = ((x >= track.offsetLeft) && (x <= track.offsetLeft + track.offsetWidth));
			if (this.mInsideTrack) {
				x = x - track.offsetLeft;
				this.mInsideThumb = ((x >= thumb.offsetLeft) && (x <= thumb.offsetLeft + thumb.offsetWidth));
				if (this.mInsideThumb) {
					x = x - thumb.offsetLeft;
				}
			} else {
				this.mInsideThumb = false;
			}
		}
		
		this.mMouseDownX = x;
		this.mMouseDownY = y;
		if ((this.mInsideTrack) && (!this.mInsideThumb)) {
			this.jumpTo(x,y);
		} else {
			return this.touchMove(event, coordinates);
		}
		
		return true;
	}
};

scrollbar.prototype.touchMove = function (event, coordinates)
{
	if(this.mEnabled) {
		if (this.mMaximum <= this.mMinimum) {
			return true;
		}
		var x = coordinates[0].x;
		var y = coordinates[0].y;
		
		var track = findChildrenByClass(this.object(),'track');
		track = track[0];
		var thumb = findChildrenByClass(track,'thumb');
		thumb = thumb[0];
		
		var pixelRange;
		if (this.mVertical) {
			pixelRange = track.offsetHeight - thumb.offsetHeight;
		} else {
			pixelRange = track.offsetWidth - thumb.offsetWidth;
		}
		
		var valueRange = this.maximum() - this.minimum();
		var pct;
		
		if (this.mInsideThumb === true) {
			var deltaX = x - this.mMouseDownX;
			var deltaY = y - this.mMouseDownY;
			
			if ((deltaX === 0) && (deltaY === 0)) {
				return true;
			}
					
			if (this.mVertical) {
				deltaY = deltaY - track.offsetTop;
			} else {
				deltaX = deltaX - track.offsetLeft;
			}
			
			if (this.mVertical) {
				pct = deltaY / pixelRange;
			} else {
				pct = deltaX / pixelRange;
			}
			this.setValue(pct * valueRange);
		} else if (this.mInsideTrack === true) {
			return true;
		} else {
			var decrease = findChildrenByClass(this.object(),'decrease');
	        if (decrease.length === 0) {
	            decrease = findChildrenByClass(this.object(),'decrease pressed');
	        }
	        var increase = findChildrenByClass(this.object(),'increase');
	        if (increase.length === 0) {
	            increase = findChildrenByClass(this.object(),'increase pressed');
	        }
	        decrease = decrease[0];
	        increase = increase[0];
	        
	        if ((x >= decrease.offsetLeft) && (x <= decrease.offsetLeft + decrease.offsetWidth) && (y >= decrease.offsetTop) && (y <= decrease.offsetTop + decrease.offsetHeight)) {
	            this.setValue(this.value() - this.lineStep());
	            this.mHoldWidget = decrease;
	            if (decrease.className == 'decrease') {
	                decrease.className = 'decrease pressed';
	            }
	        } else if ((x >= increase.offsetLeft) && (x <= increase.offsetLeft + increase.offsetWidth) && (y >= increase.offsetTop) && (y <= increase.offsetTop + increase.offsetHeight)) {
	            this.setValue(this.value() + this.lineStep());
	            this.mHoldWidget = increase;
	            if (increase.className == 'increase') {
	                increase.className = 'increase pressed';
	            }
	        } else {
	            return true;
	        }
		}
		
		return true;
	}
};

scrollbar.prototype.touchEnd = function (event, coordinates)
{
	if(this.mEnabled) {
		if (this.mMaximum <= this.mMinimum) {
			return true;
		}
		
		if (this.mHoldWidget) {
			if (this.mHoldWidget.className == 'decrease pressed') {
				this.mHoldWidget.className = 'decrease';
			} else if (this.mHoldWidget.className == 'increase pressed') {
				this.mHoldWidget.className = 'increase';
			}
			this.mHoldWidget = null;
		}
		
		return true;
	}
};

scrollbar.prototype.mouseWheel = function (deltaX, deltaY)
{
	if(this.mEnabled) {
		if (this.mVertical) {
	        this.setValue(this.value() + (deltaY * this.lineStep()));
	    } else {
	        this.setValue(this.value() + (deltaX * this.lineStep()));
	    }
		return true;
	}
};

scrollbar.prototype.jumpTo = function (x,y)
{
	var track = findChildrenByClass(this.object(),'track');
	track = track[0];
	var thumb = findChildrenByClass(track,'thumb');
	thumb = thumb[0];
	
	var thumbSize, trackSize, pixelMin, pixelMax;
	if (this.mVertical) {
		thumbSize = thumb.offsetHeight;
		trackSize = track.offsetHeight;
	} else {
		thumbSize = thumb.offsetWidth;
		trackSize = track.offsetWidth;
	}
	pixelMin = thumbSize / 2;
	pixelMax = trackSize - (thumbSize / 2);
	
	var amt;
	if (this.mVertical) {
		amt = (y - pixelMin) / (pixelMax - pixelMin);
	} else {
		amt = (x - pixelMin) / (pixelMax - pixelMin);
	}
	amt = Math.min(Math.max(amt,0),1);
	
	var valueRange = this.maximum() - this.minimum();
	
	this.setValueAnimated(amt * valueRange);
};

scrollbar.prototype.setValue = function (newValue)
{
	newValue = parseInt(newValue,10);
    var v = Math.max(Math.min(newValue,this.maximum()),this.minimum());
	if (this.mValue == v) {
		return;
	}
	this.mValue = v;
	this.refresh();
	markControlChanged(this);
	if (this.valueChanged !== '') {
		eval(this.valueChanged);
	} else if (this.implementedEvents.indexOf('ValueChanged') > -1) {
		RS.comm.triggerEvent(this.controlID,'ValueChanged');
	}
};

scrollbar.prototype.setValueAnimated = function (newValue)
{
	newValue = parseInt(newValue,10);
    if (this.animator > 0) {
        clearInterval(this.animator);
    }
    this.animationElapsed = 0;
    this.animationStartValue = this.value();
    this.animationEndValue = newValue;
    this.animator = setInterval("RS.controls['" + this.controlID + "'].animationStep();",this.animationPeriod);
};

scrollbar.prototype.animationStep = function ()
{
    this.animationElapsed = Math.min(this.animationElapsed + this.animationPeriod,this.animationDuration);
    var duration = (this.animationDuration / 1000);
    var elapsed = ((this.animationElapsed / 1000) / duration) - 1;
    var diff = this.animationEndValue - this.animationStartValue;
    var value = (diff * (((((elapsed)) * elapsed) * elapsed) + 1)) + this.animationStartValue;
    
    this.setValue(value);
    
    if (this.animationElapsed >= this.animationDuration) {
        clearInterval(this.animator);
        this.animator = 0;
        if (this.value() != this.animationEndValue) {
            this.setValue(this.animationEndValue);
        }
    }
};

scrollbar.prototype.value = function ()
{
	return parseInt(this.mValue,10);
};

scrollbar.prototype.setMinimum = function (newValue)
{
	this.mMinimum = parseInt(newValue,10);
	if (this.mValue < this.mMinimum) {
		this.setValue(this.mMinimum);
	} else {
		this.refresh();
	}
};

scrollbar.prototype.minimum = function ()
{
	return parseInt(this.mMinimum,10);
};

scrollbar.prototype.setMaximum = function (newValue)
{
	this.mMaximum = parseInt(newValue,10);
	if (this.mValue > this.mMaximum) {
		this.setValue(this.mMaximum);
	} else {
		this.refresh();
	}
};

scrollbar.prototype.maximum = function ()
{
	return parseInt(this.mMaximum,10);
};

scrollbar.prototype.setPageStep = function (newValue)
{
	this.mPageStep = parseInt(newValue,10);
	this.refresh();
};

scrollbar.prototype.pageStep = function ()
{
	return parseInt(this.mPageStep,10);
};

scrollbar.prototype.setLineStep = function (newValue)
{
	this.mLineStep = parseInt(newValue,10);
	this.refresh();
};

scrollbar.prototype.lineStep = function ()
{
	return parseInt(this.mLineStep,10);
};

scrollbar.prototype.willRefresh = function ()
{
	var track = findChildrenByClass(this.object(),'track');
	track = track[0];
	var thumb = findChildrenByClass(track,'thumb');
	thumb = thumb[0];
	
	if (this.mMaximum <= this.mMinimum) {
		// neutral
		thumb.style.display = 'none';
		if (this.mVertical) {
			track.style.top = '-15px';
			track.style.bottom = '-15px';
		} else {
			track.style.left = '-15px';
			track.style.right = '-15px';
		}
		return;
	} else if (thumb.style.display == 'none') {
		thumb.style.display = 'block';
		if (this.mVertical) {
			track.style.top = '15px';
			track.style.bottom = '15px';
		} else {
			track.style.left = '15px';
			track.style.right = '15px';
		}
	}
	
	var valueRange = this.maximum() - this.minimum();
	var valuePercent = (this.value() - this.minimum()) / (this.maximum() - this.minimum());
	var pixelRange;
	if (this.mVertical) {
		pixelRange = track.offsetHeight;
	} else {
		pixelRange = track.offsetWidth;
	}
	var thumbSize = Math.max(pixelRange * this.pageStep() / (valueRange + this.pageStep()),16);
	if(isNaN(thumbSize)) { thumbSize = 16; }
	pixelRange = pixelRange - thumbSize;
	
	var low, high;
	if (this.mVertical) {
		low = Math.floor(Math.max(valuePercent * pixelRange,0));
		high = Math.floor(Math.max(track.offsetHeight - (low + thumbSize),0));
		thumb.style.top = low + 'px';
		thumb.style.bottom = high + 'px';
		thumb.style.height = '';
	} else {
		low = Math.floor(Math.max(valuePercent * pixelRange,0));
		high = Math.floor(Math.max(track.offsetWidth - (low + thumbSize),0));
		thumb.style.left = low + 'px';
		thumb.style.right = high + 'px';
		thumb.style.width = '';
	}
};

scrollbar.prototype.resize = function ()
{
	this.refresh();
};

/* END: SCROLLBAR */

/* BEGIN: LISTBOX */

// ListBox/framework.js
//
// Utility class for working with listboxes
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function listbox (target, events)
{
	listbox.baseConstructor.call(this,target,events);
	
	var myName = this.controlID;
	this.mSelectedRows = [];
	this.mColumnWidths = [];
	this.mColumnStyles = [];
	this.mBaseStyle = 'listbox';
	
	var headers = document.getElementById(myName + "_headers");
	var content = document.getElementById(myName + "_content");
	content.style.top = headers.offsetHeight + 'px';
	
	var element;
	element = document.createElement('div');
	element.id = myName + '_vScroll';
	element.className = "scrollbar vertical";
	this.object().appendChild(element);
	element = document.createElement('div');
	element.id = myName + '_hScroll';
	element.className = "scrollbar horizontal";
	this.object().appendChild(element);
	element = document.createElement('div');
	element.id = myName + '_scrollCorner';
	element.className = "corner";
	element.innerHTML = '&nbsp;';
	this.object().appendChild(element);
	
	this.verticalScroller = new scrollbar(myName + "_vScroll",[]);
	this.verticalScroller.setEnabled(true);
	this.verticalScroller.valueChanged = "RS.controls['" + myName + "'].scrollVertical()";
	this.horizontalScroller = new scrollbar(myName + "_hScroll",[]);
	this.horizontalScroller.setEnabled(true);
	this.horizontalScroller.valueChanged = "RS.controls['" + myName + "'].scrollHorizontal()";
	RS.input.install(this.object());
	RS.view.sizing.targets.push(this);
	addWheelTarget(this);
	this.refresh();
	
	//Add some listeners to make the touch experience a little better
	try {
		content.addEventListener('touchstart',this, false);
		content.addEventListener('touchmove',this,false);
		content.addEventListener('touchend',this,false);
		content.addEventListener('touchcancel',this,false);
	} catch(err) {
		//If it can't handle addEventListener, it's probably not iOS or Android
	}
}

frameworkSubclass(listbox, frameworkObject);
listbox.prototype.verticalScroller = null;
listbox.prototype.horizontalScroller = null;
listbox.prototype.mSelectedRows = null;
listbox.prototype.mColumnWidths = null;
listbox.prototype.mColumnStyles = null;
listbox.prototype.mMinimumRowHeight = -1;
listbox.prototype.mPrimaryRowColor = '#FFFFFF';
listbox.prototype.mAlternateRowColor = '#EDF3FE';
listbox.SCROLLBARWIDTH = 15;
listbox.SCROLLBARHEIGHT = 15;

listbox.prototype.scrollVertical = function ()
{
	var rows = document.getElementById(this.controlID + "_rows");
	if (rows) {
		rows.style.top = Math.floor(this.verticalScroller.value() * -1) + 'px';
	}
};

listbox.prototype.scrollHorizontal = function ()
{
	var rows = document.getElementById(this.controlID + "_rows");
	var headers = document.getElementById(this.controlID + "_headers");
	if ((rows) && (headers)) {
		rows.style.left = Math.floor(this.horizontalScroller.value() * -1) + 'px';
		headers.style.left = rows.style.left;
	}
};

listbox.prototype.willRefresh = function ()
{
	var headers = document.getElementById(this.controlID + "_headers");
	var content = document.getElementById(this.controlID + "_content");
	var rows = document.getElementById(this.controlID + "_userrows");
	
	var i, headerChildren, min;
	headerChildren = headers.children;
	headerChildren = headerChildren.item(0).rows;
	headerChildren = headerChildren.item(0).cells;
	
	for (i = this.mColumnWidths.length; i < headerChildren.length -1; i++) {
		this.mColumnWidths[i] = '*';
	}
	min = Math.min(this.mColumnWidths.length,headerChildren.length - 1);
	
	var thisObject = this.object();
	var headersHeight = 22;
	var viewportWidth = thisObject.offsetWidth;
	var viewportHeight = thisObject.offsetHeight - headersHeight;
	var columnWidths;
	var contentWidth = 0;
	var contentHeight = 0;
	var needsHorizontalScroll = false;
	var needsVerticalScroll = false;
	var last = {'viewportWidth':0,'viewportHeight':0};
	var padderWidth, w, style;
	var finish = false;
	var cssWidths, padder;
	var row, r, cell, c;

	//See if we'll be needing scrollbars today, and adjust the viewportWidth and height
	headersHeight = headers.offsetHeight;
	contentHeight = rows.offsetHeight;
	if ((contentHeight > viewportHeight) && (needsVerticalScroll === false)) {
		needsVerticalScroll = true;
		viewportWidth = viewportWidth - listbox.SCROLLBARWIDTH;
	}
	if ((contentWidth > viewportWidth) && (needsHorizontalScroll === false)) {
		needsHorizontalScroll = true;
		viewportHeight = viewportHeight - listbox.SCROLLBARHEIGHT;
	}
	
	while (finish !== true) {
		//If the viewport width has changed, we need to do it again
		if ((viewportWidth != last.viewportWidth) || (viewportHeight != last.viewportHeight)) {	
			//Calculate the individual column widths
			columnWidths = this.actualColumnWidths(viewportWidth);
			//Figure out how wide all of the columns are together
			contentWidth = 0;
			for (i = 0; i < columnWidths.length; i++) {
				contentWidth = contentWidth + columnWidths[i];
			}
			//Update the stored viewport size (so we'll know if they changed again)
			last.viewportWidth = viewportWidth;
			last.viewportHeight = viewportHeight;
			
			//padderWidth is the width of the column that needs to be created to make up any space to the right of the defined columns
			padderWidth = thisObject.offsetWidth;
			
			//Calculate how wide each section should be in CSS units, removing 1 pixel per column to account for the borders
			cssWidths = [];
			for (i = 0; i < columnWidths.length; i++) {
				w = columnWidths[i]-1;
				w = Math.max(w - 6,0); // Allow for padding
				padderWidth = padderWidth - columnWidths[i]; //subtract each column width
				cssWidths[i] = w;
			}
			
			//For each of the headers, set the min, max and current widths
			for (i = 0; i < Math.min(headerChildren.length,cssWidths.length); i++) {
				style = headerChildren[i].style;
				if ((style) && (style.width != cssWidths[i])) {
					style.display = '';
					style.width = cssWidths[i]+'px';
					style.minWidth = cssWidths[i]+'px';
					style.maxWidth = cssWidths[i]+'px';
				}
				
				if(RS.ua.ie==0 || RS.ua.ie > 8) {
					//Do the same for all of the following rows
					for(r=0;r<rows.rows.length;r++) {
						var widthOffset = 0;
						if(i>0) {
							widthOffset = 0;
						}
						style = rows.rows[r].cells[i].style;
						style.display = '';
						
						style.width = (cssWidths[i]-widthOffset)+'px';
						style.minWidth = (cssWidths[i]-widthOffset)+'px';
						style.maxWidth = (cssWidths[i]-widthOffset)+'px';
					}
				}
			}
			
			//After the columns are inserted, calculate the width of the padder
			if (!padder) {
				padder = this.padder();
				padder.style.borderRight = 'none';
			}
			
			padderWidth = Math.max(padderWidth,0); //Make sure padderWidth is at least 0
			if (padderWidth > 0) {
				padderWidth = Math.max(listbox.SCROLLBARWIDTH,padderWidth); //If it's greater than zero, make it at least the width of the scrollbar
			}
			
			if((RS.ua.ie > 6 && RS.ua.ie < 9)) {
				for (r = 0; r < rows.rows.length; r++) {
					row = rows.rows[r];
					for (c = 0; c < row.cells.length; c++) {
						cell = row.cells[c];
						style = cell.style;
						if (style) {
							if (c < cssWidths.length) {
								w = cssWidths[c] + 'px';
							} else {
								if(RS.ua.ie == 8) {
									w = viewportWidth + 'px';
								} else {
									w = padderWidth + 'px';
								}
							}
							style.width = w;
							style.minWidth = w;
							style.maxWidth = w;
						}
					}
				}
			} else {				
				if (padder.style.width != padderWidth + 'px') {
					padder.style.minWidth = padderWidth + 'px';
					padder.style.maxWidth = padderWidth + 'px';
					padder.style.width = padderWidth + 'px';
				}
			}
			headersHeight = headers.offsetHeight;
			contentHeight = rows.offsetHeight;
			content.style.top = headersHeight + 'px';
			viewportHeight = content.offsetHeight;
			if (needsHorizontalScroll === true) {
				viewportHeight = viewportHeight - listbox.SCROLLBARHEIGHT;
			}
		}
		if ((contentHeight > viewportHeight) && (needsVerticalScroll === false)) {
			needsVerticalScroll = true;
			viewportWidth = viewportWidth - listbox.SCROLLBARWIDTH;
			continue;
		}
		if ((contentWidth > viewportWidth) && (needsHorizontalScroll === false)) {
			needsHorizontalScroll = true;
			viewportHeight = viewportHeight - listbox.SCROLLBARHEIGHT;
			continue;
		}
		finish = true;
	}
	
	if (needsVerticalScroll === true) {
		this.verticalScroller.setLineStep(this.minimumRowHeight());
		this.verticalScroller.setPageStep(viewportHeight);
		this.verticalScroller.setMaximum(contentHeight - viewportHeight);
		this.verticalScroller.object().style.display = 'block';
		if (needsHorizontalScroll === true) {
			this.verticalScroller.object().style.bottom = '14px';
		} else {
			this.verticalScroller.object().style.bottom = '-1px';
		}
		this.verticalScroller.object().style.top = headersHeight + 'px';
	} else {
		this.verticalScroller.object().style.display = 'none';
		if (this.verticalScroller.value() !== 0) {
			this.verticalScroller.setValue(0);
		}
		if (this.verticalScroller.maximum() !== 0) {
			this.verticalScroller.setMaximum(0);
		}
	}
	
	if (needsHorizontalScroll === true) {
		this.horizontalScroller.setLineStep(10);
		this.horizontalScroller.setPageStep(viewportWidth);
		this.horizontalScroller.setMaximum(contentWidth - viewportWidth);
		this.horizontalScroller.object().style.display = 'block';
		if (needsVerticalScroll === true) {
			this.horizontalScroller.object().style.right = '14px';
		} else {
			this.horizontalScroller.object().style.right = '-1px';
		}
	} else {
		this.horizontalScroller.object().style.display = 'none';
		if (this.horizontalScroller.value() !== 0) {
			this.horizontalScroller.setValue(0);
		}
		if (this.horizontalScroller.maximum() !== 0) {
			this.horizontalScroller.setMaximum(0);
		}
	}
	
	w = Math.max(contentWidth,this.object().offsetWidth) + 'px';
	var rowsTable = document.getElementById(this.controlID + "_rows");
	rowsTable.style.width = w;
	rowsTable.style.minWidth = w;
	rowsTable.style.maxWidth = w;
	headers.style.width = w;
	headers.style.minWidth = w;
	headers.style.maxWidth = w;
	
	var corner = document.getElementById(this.controlID + "_scrollCorner");
	var cornerDisplay = 'none';
	if ((needsHorizontalScroll === true) && (needsVerticalScroll === true)) {
		cornerDisplay = 'block';
	}
	if (corner.style.display != cornerDisplay) {
		corner.style.display = cornerDisplay;
	}
	
	if (viewportHeight > contentHeight) {
		var autoContent = document.getElementById(this.controlID + "_autocontent");
		var excess = viewportHeight - contentHeight;
		var requiredRows = Math.ceil(excess / this.mMinimumRowHeight);
		
		var autoRows = autoContent.rows;
		for (i = autoRows.length + rows.rows.length; i < requiredRows + rows.rows.length; i++) {
			row = autoContent.insertRow(-1);
			cell = row.insertCell(-1);
			cell.setAttribute("colSpan","99");
			cell.innerHTML = "&nbsp;";
			cell.style.minHeight = this.mMinimumRowHeight + 'px';
			cell.style.height = cell.style.minHeight;
			cell.style.width = w;
			cell.style.minWidth = cell.style.width;
			cell.style.maxWidth = cell.style.width;
			row.style.backgroundColor = (i % 2 === 0) ? this.mPrimaryRowColor : this.mAlternateRowColor;
			c++;
		}
	}
	
	this.verticalScroller.refresh();
	this.horizontalScroller.refresh();
};

listbox.prototype.finishedLoading = function ()
{
	this.recolorRows();
};

listbox.prototype.actualColumnWidths = function (width)
{
	var widths = [];
	var remaining = width;
	var i, numFractions, exp, last, body, w, fillPercent;
	var n = this.columnCount();
	
	numFractions = 0;
	fillPercent = 0;
	for (i = 0; i < n; i++) {
		exp = this.mColumnWidths[i];
		last = exp.substring(exp.length - 1);
		body = exp.substring(0,exp.length - 1);
		
		if (last == '%') {
			w = Math.floor(width * (parseFloat(body) / 100));
			fillPercent = fillPercent + parseFloat(body);
		} else if (last == '*') {
			if (body === '') {
				body = '1';
			}
			numFractions = numFractions + parseFloat(body);
			widths[i] = body + '*';
			continue;
		} else {
			w = parseFloat(exp);
			//fillPercent = fillPercent + Math.round((w/width) * 100);
		}
		
		remaining = remaining - w;
		widths[i] = w;
	}
	for (i = 0; i < n; i++) {
		exp = widths[i].toString();
		last = exp.substring(exp.length - 1);
		body = exp.substring(0,exp.length - 1);
		
		if (last == '*') {
			w = Math.floor(remaining * (parseFloat(body) / numFractions));
			fillPercent = fillPercent + Math.round((w / width) * 100);
		} else {
			continue;
		}
		
		numFractions = numFractions - 1;
		remaining = remaining - w;
		widths[i] = w;
	}
	return widths;
};

listbox.prototype.totalColumnWidths = function (width) {
	var cols = this.actualColumnWidths(width);
	var total = 0;
	var i = 0;
	for(i=0;i<cols.length;i++) {
		total += cols[i];
	}
	return total;
};

listbox.prototype.padder = function ()
{
	return document.getElementById(this.controlID + "_padder");
};

listbox.prototype.touchBegin = function (event, coordinates)
{
	if(this.mEnabled) {
		var x = coordinates[0].x;
		var y = coordinates[0].y;
		
		var vScrollWidth = this.verticalScroller.object().offsetWidth;
		var vScrollHeight = this.verticalScroller.object().offsetHeight;
		var vScrollLeft = this.verticalScroller.object().offsetLeft;
		var vScrollTop = this.verticalScroller.object().offsetTop;
		
		var hScrollWidth = this.horizontalScroller.object().offsetWidth;
		var hScrollHeight = this.horizontalScroller.object().offsetHeight;
		var hScrollLeft = this.horizontalScroller.object().offsetLeft;
		var hScrollTop = this.horizontalScroller.object().offsetTop;
		
		if ((x >= vScrollLeft) && (y >= vScrollTop) && (x <= vScrollLeft + vScrollWidth) && (y <= vScrollTop + vScrollHeight) && (this.verticalScroller.object().style.display != 'none')) {
			return RS.input.forwardEvent(event,this.verticalScroller);
		} else if ((x >= hScrollLeft) && (y >= hScrollTop) && (x <= hScrollLeft + hScrollWidth) && (y <= hScrollTop + hScrollHeight) && (this.horizontalScroller.object().style.display != 'none')) {
			return RS.input.forwardEvent(event,this.horizontalScroller);
		}
		
		return true;
	}
};

listbox.prototype.touchEnd = function (event, coordinates)
{
	if(this.mEnabled) {
		var x = coordinates[0].x;
		var y = coordinates[0].y;
		
		var headers = document.getElementById(this.controlID + "_headers");
		var headersHeight = headers.offsetHeight;
		
		if (y <= headersHeight) {
			return;
		} else {
			y = y - headersHeight;
		}
		
		var rows = document.getElementById(this.controlID + "_rows");
		var userRows = document.getElementById(this.controlID + "_userrows");
		y = y - rows.offsetTop;
		
		if (y > userRows.offsetHeight) {
			this.setSelectedRows(null);
			return;
		}
		var selectType;
		if (event.shiftKey === true) {
			selectType = 2;
		} else {
			if (RS.platform == 1) {
				if (event.metaKey === true) {
					selectType = 3;
				} else {
					selectType = 1;
				}
			} else {
				if (event.ctrlKey === true) {
					selectType = 3;
				} else {
					selectType = 1;
				}
			}
		}
		
		var children = userRows.children;
		var i, s, row;
		for (i = 0; i < children.length; i++) {
			if ((y >= children[i].offsetTop) && (y <= children[i].offsetTop + children[i].offsetHeight)) {
				row = i;
				break;
			}
		}
		
		if (this.implementedEvents.indexOf('CellClick') > -1) {
			var column = -1, cx = 0;
			if (headersHeight > 0) {
				children = headers.rows[0].cells;
			} else {
				children = children[row].cells;
			}
			for (i = 0; i < (children.length - 1); i++) {
				if ((x >= cx) && (x <= cx + children[i].offsetWidth)) {
					column = i;
					break;
				} else {
					cx = cx + children[i].offsetWidth;
				}
			}
			if (column > -1) {
				RS.comm.triggerEvent(this.name(),'CellClick',[row,column],event);
			}
		}
		
		s = row.toString();
		var selRows;
		if (selectType == 1) {
			this.setSelectedRows([s],true);
		} else if (selectType == 2) {
			selRows = this.mSelectedRows;
			var low = row, high = row;
			for (i = 0; i < selRows.length; i++) {
				low = Math.min(selRows[i],low);
				high = Math.max(selRows[i],high);
			}
			selRows = [];
			for (i = low; i <= high; i++) {
				selRows.push(String(i));
			}
			this.setSelectedRows(selRows,false);
		} else if (selectType == 3) {
			selRows = this.mSelectedRows;
			if (selRows.indexOf(s) == -1) {
				selRows.push(s);
			} else {
				selRows.splice(selRows.indexOf(s),1);
			}
			this.setSelectedRows(selRows,false);
		}
		return true;
	}
};

listbox.prototype.mouseWheel = function (deltaX, deltaY)
{
	if(this.mEnabled) {
		this.verticalScroller.setValue(this.verticalScroller.value() + (deltaY * this.verticalScroller.lineStep()));
		this.horizontalScroller.setValue(this.horizontalScroller.value() + (deltaX * this.horizontalScroller.lineStep()));
		return true;
	}
};

listbox.prototype.columnCount = function ()
{
	var headers = document.getElementById(this.controlID + "_headers");
	var tbody = headers.children.item(0);
	var columns = tbody.children.item(0).children;
	return columns.length - 1;
};

listbox.prototype.appendRow = function (columnData)
{
	this.insertRow(-1,columnData);
};

listbox.prototype.insertRow = function (rowIndex, columnData)
{
	var userContents = document.getElementById(this.controlID + "_userrows");
	var i;
	var selRows = this.mSelectedRows;
	if ((selRows) && (rowIndex >= 0)) {
		for (i = 0; i < selRows.length; i++) {
			if (selRows[i] >= rowIndex) {
				selRows[i] = parseInt(selRows[i],10) + 1;
				selRows[i] = selRows[i].toString();
			}
		}
		this.mSelectedRows = selRows;
	}
    
    var rows = userContents.rows;
    var row, cell;
    if ((rowIndex < 0) || (rowIndex >= rows.length)) {
        rowIndex = -1;
    }
    row = userContents.insertRow(rowIndex);
	var c = this.columnCount();
	var s = '';
    for (i = 0; i < c; i++) {
        cell = row.insertCell(-1);
		cell.style.minHeight = this.mMinimumRowHeight + 'px';
		cell.style.height = cell.style.minHeight;
		s = this.columnStyle(i);
		if (s !== '') {
			s = s + ' ';
		}
        cell.className = s + "column" + (i + 1);
        if (i < columnData.length) {
            cell.innerHTML = columnData[i];
        } else {
            cell.innerHTML = "&nbsp;";
        }
    }
    cell = row.insertCell(-1);
    cell.className = "padder";
    cell.innerHTML = "&nbsp;";
    
	this.recolorRows();
	this.refresh();
};

listbox.prototype.removeRow = function (rowIndex)
{
	var userContents = document.getElementById(this.controlID + "_userrows");
    userContents.deleteRow(rowIndex);
	
	var selRows = this.mSelectedRows;
	var idx = selRows.indexOf(String(rowIndex));
	if (idx != -1) {
		selRows.splice(idx,1);
		this.setSelectedRows(selRows,false,false);
	}
	
	this.recolorRows();
	this.refresh();
};

listbox.prototype.deleteAllRows = function ()
{
	var userContents = document.getElementById(this.controlID + "_userrows");
	var c = userContents.rows.length;
    var i;
    for (i = 0; i < c; i++) {
        userContents.deleteRow(0);
    }
    
	this.mSelectedRows = [];
	this.setSelectedRows(this.mSelectedRows,false,false);
	this.recolorRows();
	this.refresh();
};

listbox.prototype.recolorRows = function ()
{
	var rowColor = this.mPrimaryRowColor;
	var rows = document.getElementById(this.controlID + "_rows").rows;
	var r,style;
	
	for (r = 0; r < rows.length; r++) {
		style = rows[r].style;
		if (style) {
			style.backgroundColor = rowColor;
		}
		if (this.isRowSelected(r) === true) {
			if (rows[r].className != 'selected') {
				rows[r].className = 'selected';
			}
		} else {
			if (rows[r].className !== null) {
				rows[r].className = null;
			}
		}
		rowColor = (rowColor == this.mPrimaryRowColor) ? this.mAlternateRowColor : this.mPrimaryRowColor;
	}
};

listbox.prototype.setSelectedRows = function (rows, scroll, triggerEvent)
{
	if (rows === null) {
        rows = [];
    }
	if ((this.mSelectedRows.length === 0) && (rows.length === 0)) {
		return;
	}
	if(triggerEvent === undefined) { triggerEvent = true; }
	this.mSelectedRows = rows;
	this.recolorRows();
    
    if ((scroll === null) || (scroll === true)) {
        if (rows.length > 0) {
            this.scrollToRow(rows[0]);
        }
    }
    
	markControlChanged(this);
	if (triggerEvent) {
		if (this.implementedEvents.indexOf('SelectionChanged') > -1) {
			RS.comm.triggerEvent(this.name(),'SelectionChanged');
		}
	}
};

listbox.prototype.scrollToRow = function (rowIndex)
{
    var body = document.getElementById(this.controlID + "_rows");
    var rows = body.rows;
    if ((rowIndex < 0) || (rowIndex >= rows.length)) {
        return;
    }
    var row = rows[rowIndex];
    var viewportHeight = document.getElementById(this.controlID + "_content").offsetHeight;
    var position = body.offsetTop;
    var top = row.offsetTop + position;
    var bottom = top + row.offsetHeight;
    
    if (top < 0) {
        this.verticalScroller.setValueAnimated(top - position);
    } else if (bottom > viewportHeight) {
        var diff = bottom - viewportHeight;
        this.verticalScroller.setValueAnimated(this.verticalScroller.value() + diff);
    }
};

listbox.prototype.isRowSelected = function (rowIndex)
{
	
	if (this.mSelectedRows.indexOf(String(rowIndex)) == -1) {
		return false;
	} else {
		return true;
	}
};

listbox.prototype.value = function ()
{
	return this.mSelectedRows.join(",");
};

listbox.prototype.setValue = function (input)
{
	var rows = input.split(",");
	this.setSelectedRows(rows);
};

listbox.prototype.setColumnWidths = function (widthString)
{
	var widths = widthString.split(",");
	this.mColumnWidths = widths;
	this.refresh();
};

listbox.prototype.setColumnHeading = function (column, heading)
{
	if ((column < 0) || (column >= this.columnCount())) {
		return;
	}
	var headers = document.getElementById(this.controlID + "_headers");
	var tbody = headers.children.item(0);
	var columns = tbody.children.item(0).children;
	
	columns[column].innerHTML = heading;
	this.refresh();
};

listbox.prototype.setColumnCount = function (count)
{
	var currentCount = this.columnCount();
	
	if (currentCount == count) {
		return;
	}
	
	var headers = document.getElementById(this.controlID + "_headers");
	var headers_body = headers.children.item(0);
	var user_rows = document.getElementById(this.controlID + "_userrows");
	var auto_rows = document.getElementById(this.controlID + "_autocontent");
	
	this.alterColumns(headers_body, count);
	this.alterColumns(user_rows, count);
	this.alterColumns(auto_rows, count);
	this.recolorRows();
	this.refresh();
};

listbox.prototype.alterColumns = function (tbody, columnCount)
{
	var rows = tbody.rows;
	var cells,currentCount;
	if (rows.length > 0) {
		cells = rows.item(0).cells;
		currentCount = cells.length - 1;
	} else {
		currentCount = this.columnCount();
	}
    if (currentCount == columnCount) {
        return;
    }
    
	var r,c,cell;
	for (r = 0; r < rows.length; r++) {
		cells = rows.item(r).children;
        if (columnCount > currentCount) {
            // add cells
            for (c = currentCount; c < columnCount; c++) {
                cell = rows.item(r).insertCell(c);
                cell.className = "column" + (c + 1);
                cell.innerHTML = "&nbsp;";
            }
		} else {
            // remove cells
            for (c = columnCount; c < currentCount; c++) {
                rows.item(r).deleteCell(columnCount);
            }
        }
	}
};

listbox.prototype.setMinimumRowHeight = function (value)
{
	value = Math.max(1,parseInt(value,10));
	if (value != this.mMinimumRowHeight) {
		var rows = document.getElementById(this.controlID + "_rows").rows;
		var row,r,c,style;
		for (r = 0; r < rows.length; r++) {
			row = rows[r];
			for (c = 0; c < row.cells.length; c++) {
				style = row.cells[c].style;
				if ((style) && (style.minHeight != value + 'px')) {
					style.minHeight = value + 'px';
					style.height = style.minHeight;
				}
			}
		}
		this.mMinimumRowHeight = value;
		this.refresh();
	}
};

listbox.prototype.minimumRowHeight = function ()
{
	return this.mMinimumRowHeight;
};

listbox.prototype.setPrimaryRowColor = function (value)
{
	if (value != this.mPrimaryRowColor) {
		this.mPrimaryRowColor = value;
		this.recolorRows();
	}
};

listbox.prototype.setAlternateRowColor = function (value)
{
	if (value != this.mAlternateRowColor) {
		this.mAlternateRowColor = value;
		this.recolorRows();
	}
};

listbox.prototype.setCellContents = function (row, column, contents)
{
	var tbody = document.getElementById(this.controlID + "_userrows");
	var cell = tbody.children.item(row).children.item(column);
	if (cell) {
		cell.innerHTML = contents;
	}
};

listbox.prototype.setEnabled = function (value)
{
	this.setDisabledAppearance(!value);
	this.mEnabled = value;
	this.refresh();
};

listbox.prototype.setHeadingVisible = function (value)
{
	var headers = document.getElementById(this.controlID + "_headers");
	if (value === true) {
		headers.style.display = "block";
	} else {
		headers.style.display = "none";
	}
	this.refresh();
};

listbox.prototype.columnStyle = function (column) {
	if ((column < 0) || (column >= this.columnCount()) || (column >= this.mColumnStyles.length)) {
		return '';
	} else {
		return this.mColumnStyles[column];
	}
};

listbox.prototype.setColumnStyle = function (column, className)
{
	var c = this.columnCount();
	if ((column < 0) || (column >= c)) {
		return;
	}
	
	while (this.mColumnStyles.length < c) {
		this.mColumnStyles.push('');
	}
	
	var oldStyle = this.mColumnStyles[column];
	if (className) {
		this.mColumnStyles[column] = className;
	} else {
		this.mColumnStyles[column] = '';
	}
	var newStyle = this.mColumnStyles[column];
	
	var rows = document.getElementById(this.controlID + '_userrows').rows;
	var i, className;
	for (i = 0; i < rows.length; i++) {
		className = rows[i].cells[column].className;
		if (oldStyle !== '') {
			if (className.indexOf(oldStyle) > -1) {
				className = className.replace(oldStyle,newStyle);
			} else {
				className = newStyle;
			}
		} else {
			className = newStyle;
		}
		rows[i].cells[column].className = newStyle;
	}
};

listbox.prototype.setCellStyle = function (row, column, className)
{
	var rows = document.getElementById(this.controlID + "_userrows").rows;
	if ((row >= 0) && (row < rows.length) && (column >= 0) && (column <= this.columnCount())) {
		var cell = rows[row].cells[column];
		var cn = this.columnStyle(column);
		if (cn !== '') {
			cn = cn + ' ';
		}
		cn = cn + 'column' + (column + 1) + '';
		if (className) {
			cn = cn + ' ' + className;
		}
		cell.className = cn;
	}
};

//methods for iOS and Android
listbox.prototype.handleEvent = function(event) {
	if(typeof(this[event.type]) === "function") {
		return this[event.type](event);
	}
}

listbox.prototype.touchstart = function(event) {
	if(this.mEnabled) {
		event.stopPropagation();
		//Record the start point
		var rows = document.getElementById(this.controlID + "_rows");
		var fingerOne = event.targetTouches[0];
		this.touchStartX = fingerOne.pageX;
		this.touchStartY = fingerOne.pageY;
		this.startPosX = rows.style.left || "0px";
		this.startPosY = rows.style.top || "0px";
	
		var rr = /px/g;
		this.startPosX = parseInt(this.startPosX.replace(rr,""));
		this.startPosY = parseInt(this.startPosY.replace(rr,""));
		this.touchMoved = false;
	}
};

listbox.prototype.touchmove = function(event) {
	if(this.mEnabled) {
		event.stopPropagation();
		event.preventDefault();
		//Move the list
		var fingerOne = event.targetTouches[0];
		var curX = fingerOne.pageX;
		var curY = fingerOne.pageY;
		this.dx = curX-this.touchStartX;
		this.dy = curY-this.touchStartY;
		this.touchScrollList(this.startPosX+this.dx,this.startPosY+this.dy);
		this.verticalScroller.setValue(-1*(this.startPosY+this.dy));
		this.horizontalScroller.setValue(-1*(this.startPosX+this.dx));
		this.touchMoved = true;
	}
};

listbox.prototype.touchend = function(event) {
	if(this.mEnabled) {
		event.stopPropagation();
		if(!this.touchMoved) {
			RS.input.touchHandler(event);
		} else {
			//set a css transform for the momentum		
		}
	}
};

listbox.prototype.touchcancel = function(event) {
	//Return to the original state
	rows.style.left = this.startPosX;
	rows.style.top = this.startPosY;
};

listbox.prototype.touchScrollList = function(xpos,ypos) {

	var rows = document.getElementById(this.controlID + "_rows");
	var userrows = document.getElementById(this.controlID + "_userrows");
	var headers = document.getElementById(this.controlID + "_headers");
	var content = document.getElementById(this.controlID + "_content");
	var vscroll = document.getElementById(this.controlID + "_vScroll");
	var hscroll = document.getElementById(this.controlID + "_hScroll");
	
	var maxNegX = -1 * (Math.max(parseInt(userrows.offsetWidth) - parseInt(content.offsetWidth)),0);
	var maxNegY = -1 * ((parseInt(userrows.offsetHeight) - parseInt(content.offsetHeight)));
	if (vscroll.style.display == "none") {
		maxNegX += vscroll.offsetWidth;
		maxNegY = 0;
	}
	if (hscroll.style.display == "none") {
		maxNegY += hscroll.offsetHeight;
		maxNegX = 0;
	}
	
	var x = Math.max(maxNegX,Math.min(0,Math.floor(xpos)));
	var y = Math.max(maxNegY,Math.min(0,Math.floor(ypos)));
	
	rows.style.left = x + 'px';
	rows.style.top = y + 'px';
	
	if(headers) {
		headers.style.left = rows.style.left;
	}
}

/* END: LISTBOX */

/* BEGIN: SEGMENTED */

// Segmented/framework.js
//
// Utility class for working with SegmentedControls
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function segmented (target, events)
{
	segmented.baseConstructor.call(this,target,events);
	
	RS.input.install(this.object());
	this.object().className = "segmented";
	RS.view.sizing.targets.push(this);
	this.refresh();
}

frameworkSubclass(segmented,frameworkObject);
segmented.prototype.mSelectionType = 0;
segmented.prototype.mMouseDownCell = -1;

segmented.prototype.willRefresh = function ()
{
	var cells = this.object().children;
	var w = this.object().offsetWidth;
	var num = cells.length;
	var baseWidth = Math.floor(w / num);
	var remainder = w - (num * baseWidth);
	var cellLeft = 0;
	var cellWidth,cellRight,i;
	
	for (i = 0; i < cells.length; i++) {
		cellWidth = baseWidth;
		if (i < remainder) {
			cellWidth = cellWidth + 1;
		}
		cellRight = w - (cellLeft + cellWidth);
		if (cells[i].style.left != cellLeft + 'px') {
			cells[i].style.left = cellLeft + 'px';
		}
		if (cells[i].style.right != cellRight + 'px') {
			cells[i].style.right = cellRight + 'px';
		}
		cellLeft = cellLeft + cellWidth;
		
		var caption = cells[i].children[0];
		if (caption) {
			var captionWidth = caption.offsetWidth;
			var captionHeight = caption.offsetHeight;
			var captionLeft = '-' + Math.floor(captionWidth / 2) + 'px';
			var captionTop = '-' + Math.ceil(captionHeight / 2) + 'px';
			if (caption.style.marginTop != captionTop) {
				caption.style.marginTop = captionTop;
			}
			if (caption.style.marginLeft != captionLeft) {
				caption.style.marginLeft = captionLeft;
			}
		}
	}
};

segmented.prototype.selectionType = function ()
{
	return this.mSelectionType;
};

segmented.prototype.setSelectionType = function (value)
{
	if (value == this.mSelectionType) {
		return;
	}
	
	this.mSelectionType = value;
	
	var i = 0;
	var c = this.object().children.length;
	
	switch (this.mSelectionType) {
		case 0:
			var selIndex = -1;
			for (i = 0; i < c; i++) {
				if ((this.isCellSelected(i)) && (selIndex == -1)) {
					this.setIsCellSelected(i,true);
					selIndex = i;
				} else {
					this.setIsCellSelected(i,false);
				}
			}
			if (selIndex == -1) {
				this.setIsCellSelected(0,true);
			}
			break;
		case 2:
			for (i = 0; i < c; i++) {
				this.setIsCellSelected(i,false);
			}
			break;
	}
};

segmented.prototype.setSelectedCell = function (index)
{
	var i = 0;
	var c = this.object().children.length;
	
	switch (this.mSelectionType) {
		case 0:
			for (i = 0; i < c; i++) {
				this.setIsCellSelected(i,i == index);
			}
			break;
		case 1:
			this.setIsCellSelected(index,!this.isCellSelected(index));
			break;
		case 2:
			break;
	}
	
	markControlChanged(this);
    var userdata = [];
    userdata.push(index);
	if (this.implementedEvents.indexOf('Action') > -1) {
		RS.comm.triggerEvent(this.name(),'Action',userdata);
	}
};

segmented.prototype.isCellSelected = function (index)
{
	var cell = this.object().children[index];
	if (!cell) {
		return false;
	}
	
	var className = cell.className;
	return (className.indexOf("selected") != -1);
};

segmented.prototype.setIsCellSelected = function (index,value)
{
	var sel = this.isCellSelected(index);
	if (((value) && (sel)) || ((!value) && (!sel))) {
		return;
	}
	
	var cell = this.object().children[index];
	if (!cell) {
		return;
	}
	
	var className = cell.className;
	
	if (value) {
		className = className + " selected";
	} else {
		className = className.replace(" selected","");
	}
	
	cell.className = className;
};

segmented.prototype.touchBegin = function (event, coordinates)
{
	if(this.mEnabled) {
		var x = coordinates[0].x;
		var cells = this.object().children;
		var i;
		this.mMouseDownCell = -1;
		for (i = 0; i < cells.length; i++) {
			if ((x >= cells[i].offsetLeft) && (x <= cells[i].offsetLeft + cells[i].offsetWidth)) {
				this.mMouseDownCell = i;
				break;
			}
		}
		return true;
	}
};

segmented.prototype.touchMove = function (event, coordinates)
{
	return false;
}

segmented.prototype.touchEnd = function (event, coordinates)
{
	if(this.mEnabled) {
		if (this.mMouseDownCell == -1) {
			return;
		}
		var x = coordinates[0].x;
		var y = coordinates[0].y;
		
		var cellIndex = this.mMouseDownCell;
		this.mMouseDownCell = -1;
		var cell = this.object().children[cellIndex];
		if (!cell) {
			return;
		}
		
		if ((x < cell.offsetLeft) || (x > cell.offsetLeft + cell.offsetWidth) || (y < 0) || (y > cell.offsetHeight)) {
			return;
		}
		
		this.setSelectedCell(cellIndex);
	}
};

segmented.prototype.value = function ()
{
	var values = [];
	var i = 0;
	var cells = this.object().children;
	
	for (i = 0; i < cells.length; i++) {
		if (this.isCellSelected(i)) {
			values.push("1");
		} else {
			values.push("0");
		}
	}
	
	return values.join(" ");
};

segmented.prototype.setValue = function (value)
{
	var values = value.split(" ");
	var i = 0;
	var cells = this.object().children;
	
	for (i = 0; i < cells.length; i++) {
		this.setIsCellSelected(i,values[i] == "1");
	}
};

segmented.prototype.setCellContents = function (index,contents)
{
	var cell = this.object().children[index];
	if (!cell) {
		return;
	}
	
	cell.innerHTML = contents;
	this.refresh();
};

/* END: SEGMENTED */

/* BEGIN: SEARCHFIELD */

// searchfield/framework.js
//
// Utility class for working with input-based searchfields
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function searchfield (target,events)
{
	searchfield.baseConstructor.call(this,target,events);
	this.mIsNative = (this.field().type == 'search');
	
	var cid = this.controlID;
	RS.events.addListener(this.field(),"search",function () { RS.controls[cid].action() },false);
	RS.events.addListener(this.field(),"focus",function () { RS.input.setFocusControl(RS.controls[cid]) },false);
	RS.events.addListener(this.field(),"blur",function () { RS.input.setFocusControl(null) },false);
	RS.events.addListener(this.field(),"input",function () { RS.controls[cid].input() },false);
	
	if (this.mIsNative === false) {
		this.field().className = this.field().className + " searchField";
	}
}
frameworkSubclass(searchfield, frameworkObject);
searchfield.prototype.mIsNative = false;
searchfield.prototype.mPlaceholder = 'Search';
searchfield.prototype.mDelayTimer = 0;

searchfield.prototype.action = function ()
{
	if (this.implementedEvents.indexOf('TextChanged') > -1) {
		RS.comm.triggerEvent(this.controlID,'TextChanged');
	}
};

searchfield.prototype.field = function ()
{
	return this.object().children[0];
};

searchfield.prototype.value = function ()
{
	return this.field().value;
};

searchfield.prototype.setValue = function (input)
{
	this.field().value = input;
};

searchfield.prototype.setEnabled = function (value)
{
	if (value === true) {
		this.field().disabled = false;
	} else {
		this.field().disabled = true;
	}
	this.setDisabledAppearance(!value);
	this.mEnabled = value;
};

searchfield.prototype.focus = function ()
{
	this.field().focus();
};

searchfield.prototype.gotFocus = function ()
{
	if (this.mIsNative === false) {
		var obj = this.field();
		if (obj.style.color == 'rgb(127,127,127)' || obj.style.color == 'rgb(127, 127, 127)') {
			obj.style.color = 'rgb(0, 0, 0)';
			obj.value = '';
		}
	}
};

searchfield.prototype.lostFocus = function ()
{
	if (this.mIsNative === false) {
		var obj = this.field();
		if (obj.value === '') {
			obj.style.color = 'rgb(127,127,127)';
			obj.value = this.mPlaceholder;
		}
	}
};

searchfield.prototype.setPlaceholder = function (value)
{
	var obj = this.field();
	if ((this.mIsNative === false) && (obj.value == this.mPlaceholder)) {
		obj.value = this.mPlaceholder;
	} else if (this.mIsNative) {
		obj.setAttribute('placeholder',value);
	}
	this.mPlaceholder = value;
};

searchfield.prototype.keyDown = function (event)
{
	this.fireAction();
	return false;
};

searchfield.prototype.keyUp = function (event)
{
	this.fireAction();
	return false;
};

searchfield.prototype.input = function (event) {
	this.fireAction();
	return false;
};

searchfield.prototype.fireAction = function() {
	markControlChanged(this);
	if (this.mDelayTimer !== 0) {
		clearTimeout(this.mDelayTimer);
		this.mDelayTimer = 0;
	}
	if (RS.comm.websockets.connected() === true) {
		this.mDelayTimer = setTimeout("RS.controls['" + this.controlID + "'].action()",100);
	} else {
		this.mDelayTimer = setTimeout("RS.controls['" + this.controlID + "'].action()",1000);
	}
};

/* END: SEARCHFIELD */

/* BEGIN: IMAGEVIEW */

// imageview/framework.js
//
// Provides sync abilities to WebImage class
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function imageview (target, events)
{
	imageview.baseConstructor.call(this,target,events);
	
	this.setSource(this.image().src);
	RS.view.sizing.targets.push(this);
}
frameworkSubclass(imageview, frameworkObject);
imageview.prototype.mSource = null;
imageview.prototype.mVerticalAlignment = 0;
imageview.prototype.mHorizontalAlignment = 0;

imageview.prototype.setSource = function (url)
{
	var img = cacheImage(url,false);
	img.loaded = false;
	if (img) {
		img.targetObject = this;
		img.onload = function () {
			img.targetObject.mSource = img;
			img.targetObject.refresh();
			img.onload = null;
		};
	}
};

imageview.prototype.image = function ()
{
	return this.object().children.item(0);
};

imageview.prototype.willRefresh = function ()
{
	if (!this.mSource) {
		return;
	}
	
	var image = this.image();
	image.src = this.mSource.src;
	image.width = this.mSource.width;
	image.height = this.mSource.height;
	image.style.width = this.mSource.width + 'px';
	image.style.height = this.mSource.height + 'px';
	
	switch (this.mVerticalAlignment) {
		case 0:
		case 2:
			// middle
			image.style.top = '50%';
			image.style.bottom = '';
			image.style.marginTop = '-' + (this.mSource.height / 2) + 'px';
			break;
		case 1:
			// top
			image.style.top = '0px';
			image.style.bottom = '';
			image.style.marginTop = '0px';
			break;
		case 3:
			// bottom
			image.style.top = '';
			image.style.bottom = '0px';
			image.style.marginTop = '0px';
			break;
	}
	
	switch (this.mHorizontalAlignment) {
		case 0:
		case 2:
			// center
			image.style.left = '50%';
			image.style.right = '';
			image.style.marginLeft = '-' + (this.mSource.width / 2) + 'px';
			break;
		case 1:
			// left
			image.style.left = '0px';
			image.style.right = '';
			image.style.marginLeft = '0px';
			break;
		case 3:
			// right
			image.style.left = '';
			image.style.right = '0px';
			image.style.marginLeft = '0px';
			break;
	}
};

imageview.prototype.setVerticalAlignment = function (value)
{
	this.mVerticalAlignment = value;
	this.refresh();
};

imageview.prototype.setHorizontalAlignment = function (value)
{
	this.mHorizontalAlignment = value;
	this.refresh();
};

imageview.prototype.touchBegin = function (event, coordinates)
{
	return true;
};

imageview.prototype.touchMove = function (event, coordinates)
{
	return true;
};

imageview.prototype.touchEnd = function (event, coordinates)
{
	return true;
};

/* END: IMAGEVIEW */

/* BEGIN: TIMER */

// Timer/framework.js
//
// Provides sync abilities to WebTimer class
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function timer (target, events)
{
	timer.baseConstructor.call(this,target,events);
	this.setup(this.mMode,this.mPeriod);
}
frameworkSubclass(timer, frameworkObject);
timer.prototype.mMode = 2;
timer.prototype.mPeriod = 1000;
timer.prototype.mTimer = 0;
timer.prototype.mEnabled = true;

timer.prototype.setPeriod = function (value)
{
	if (this.mPeriod != value) {
		this.setup(this.mMode,value);
	}
};

timer.prototype.setMode = function (value)
{
	if (this.mMode != value) {
		this.setup(value,this.mPeriod);
	}
};

timer.prototype.setEnabled = function (value) {
	this.mEnabled = value;
};

timer.prototype.setup = function (mode, period)
{
	if (this.mTimer > 0) {
		if (this.mMode == 1) {
			clearTimeout(this.mTimer);
		} else if (this.mMode == 2) {
			clearInterval(this.mTimer);
		}
		this.mTimer = 0;
	}
	
	this.mMode = mode;
	this.mPeriod = period;
	
	var action = "RS.controls['" + this.controlID + "'].action()";
	if (this.mMode === 0) {
		return; // do nothing
	} else if (this.mMode == 1) {
		this.mTimer = setTimeout(action,this.mPeriod);
	} else if (this.mMode == 2) {
		this.mTimer = setInterval(action,this.mPeriod);
	}
};

timer.prototype.action = function ()
{
	if ((RS.stopInit === false) && (RS.interactionAllowed === true)) {
		if (this.mEnabled && this.implementedEvents.indexOf('Action') > -1) {
			RS.comm.triggerEvent(this.name(),'Action');
		}
	} else {
		this.setMode(0);
	}
};

/* END: TIMER */

/* BEGIN: SPINNER */

// Spinner/framework.js
//
// Utility class for working with ProgressWheels
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function spinner (target, events)
{
	spinner.baseConstructor.call(this,target,events);
}

frameworkSubclass(spinner, frameworkObject);
spinner.prototype.timer = 0;
spinner.prototype.mType = 0;
spinner.prototype.mFrameNum = 0;

spinner.prototype.setEnabled = function (value)
{
	if (this.mEnabled == value) {
		return;
	}
	if (value) {
		this.timer = setInterval("RS.controls['" + this.controlID + "'].step()",41);
	} else if (this.timer !== 0) {
		clearInterval(this.timer);
	}
	
	this.setDisabledAppearance(!value);
	this.mEnabled = value;
};

spinner.prototype.step = function ()
{
	var frames = 11;
	this.mFrameNum = this.mFrameNum + 1;
	if (this.mFrameNum > frames) {
		this.mFrameNum = 0;
	}
	
	var frameSize = this.object().offsetWidth;
	var framePosition = frameSize * this.mFrameNum;
	
	this.object().style.backgroundPosition = '-' + framePosition + 'px 0px';
};

spinner.prototype.type = function ()
{
	return this.mType;
};

spinner.prototype.setType = function (value)
{
	this.mType = value;
	var size;
	var o = this.object();
	switch (this.mType) {
		case 0:
			o.className = "spinner black large";
			size = 32;
			break;
		case 1:
			o.className = "spinner black small";
			size = 16;
			break;
		case 2:
			o.className = "spinner white large";
			size = 32;
			break;
		case 3:
			o.className = "spinner white small";
			size = 16;
			break;
	}
	this.mBaseStyle = o.ClassName;
	
	var w = o.offsetWidth;
	var h = o.offsetHeight;
	
	if (w != size) {
		o.style.width = size + 'px';
		o.style.maxWidth = size + 'px';
		o.style.minWidth = size + 'px';
	}
	
	if (h != size) {
		o.style.height = size + 'px';
		o.style.maxHeight = size + 'px';
		o.style.minHeight = size + 'px';
	}
};

/* END: SPINNER */

/* BEGIN: POPUPMENU */

// PopupMenu/framework.js
//
// Utility class for working with popupmenus
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function popupmenu (target, events)
{
	popupmenu.baseConstructor.call(this,target,events);
	addPostLoadObject(this);
	
	var cid = this.controlID;
	RS.events.addListener(this.field(),"change",function () { RS.controls[cid].action() },false);
	RS.events.addListener(this.field(),"focus",function () { RS.input.setFocusControl(RS.controls[cid]) },false);
	RS.events.addListener(this.field(),"blur",function () { RS.input.setFocusControl(null) },false);
}
frameworkSubclass(popupmenu, frameworkObject);
popupmenu.prototype.selectedIndex = -1;

popupmenu.prototype.action = function ()
{
	this.selectedIndex = this.field().selectedIndex;
	markControlChanged(this);
	if (this.implementedEvents.indexOf('SelectionChanged') > -1) {
		RS.comm.triggerEvent(this.controlID,'SelectionChanged');
	}
};

popupmenu.prototype.field = function ()
{
	return this.object().children[0];
};

popupmenu.prototype.willRefresh = function ()
{
	this.field().selectedIndex = this.selectedIndex;
};

popupmenu.prototype.appendRow = function (row)
{
	var field = this.field();
	field.length = field.length + 1;
	field.options[field.length - 1] = new Option(row,field.length - 1);
};

popupmenu.prototype.insertRow = function (index,row)
{
	var field = this.field();
	field.length = field.length + 1;
	
	var i;
	for (i = field.length - 1; i > index; i--) {
		field.options[i].text = field.options[i - 1].text;
		field.options[i].value = i;
	}
	
	field.options[index] = new Option(row,index);
	
	if (field.selectedIndex >= index) {
		this.selectedIndex = this.selectedIndex + 1;
		field.selectedIndex = this.selectedIndex;
	}
};

popupmenu.prototype.removeRow = function (index)
{
	var field = this.field();
	if ((index < 0) || (index >= field.length)) {
		return;
	}
	
	if (field.length == 1) {
		field.length = 0;
		return;
	}
	
	if (index == field.length - 1) {
		field.length = Math.max(field.length - 1,0);
		return;
	}
	
	var i;
	for (i = index; i < field.length - 1; i++) {
		field.options[i].text = field.options[i + 1].text;
		field.options[i].value = i;
	}
	
	if (field.selectedIndex > index) {
		this.selectedIndex = this.selectedIndex - 1;
		field.selectedIndex = this.selectedIndex;
	} else if (field.selectedIndex = index) {
		this.selectedIndex = -1;
		field.selectedIndex = -1;
	}
	
	field.length = Math.max(field.length - 1,0);
};

popupmenu.prototype.changeRow = function (index,row)
{
	this.field().options[index].text = row;
};

popupmenu.prototype.deleteAllRows = function ()
{
	this.field().length = 0;
	this.selectedIndex = -1;
};

popupmenu.prototype.value = function ()
{
	return this.selectedIndex;
};

popupmenu.prototype.setValue = function (input)
{
	var i;
    var field = this.field();
    var options = field.options;
	
	input = parseInt(input,10);
	this.selectedIndex = input;
    
    for (i = 0; i < options.length; i++) {
        options[i].defaultSelected = (i == input);
    }
    field.selectedIndex = input;
};

popupmenu.prototype.setEnabled = function (input)
{
	if (input === true) {
		this.field().disabled = false;
	} else {
		this.field().disabled = true;
	}
	this.mEnabled = input;
};

popupmenu.prototype.length = function ()
{
	return this.field().length;
};

popupmenu.prototype.setLength = function (input)
{
	this.field().length = input;
};

popupmenu.prototype.setStyle = function (value)
{
	var className;
	if (value === null) {
		className = "";
	} else {
		className = value;
	}
	if (this.mBaseStyle !== "") {
		if (className !== "") {
			className = this.mBaseStyle + " " + className;
		} else {
			className = this.mBaseStyle;
		}
	}
	this.field().className = className;
};

popupmenu.prototype.postLoad = function ()
{
	this.refresh();
};

popupmenu.prototype.keyDown = function (event)
{
	return true;
};

popupmenu.prototype.keyUp = function (event)
{
	return true;
};

/* END: POPUPMENU */

/* BEGIN: CONTAINER */

// Container/framework.js
//
// Utility class for working with ContainerControls
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function container (target, events)
{
	container.baseConstructor.call(this,target,events);
	
	//Add some listeners to make the touch experience a little better
	try {
		var content = this.object();
		content.addEventListener('touchstart',this, false);
		content.addEventListener('touchmove',this,false);
		content.addEventListener('touchend',this,false);
		content.addEventListener('touchcancel',this,false);
	} catch(err) {
		//If it can't handle addEventListener, it's probably not iOS or Android
	}
}

frameworkSubclass(container, frameworkObject);

container.prototype.setVisible = function (value)
{
	if (value) {
		this.object().style.display = 'block';
	} else {
		this.object().style.display = 'none';
	}
};

container.prototype.visible = function ()
{
	if (this.object().style.display == 'none') {
		return false;
	} else {
		return true;
	}
};

//methods for iOS and Android
container.prototype.handleEvent = function(event) {
	if(typeof(this[event.type]) === "function") {
		return this[event.type](event);
	}
}

container.prototype.touchstart = function(event) {
	//Record the start point
	var fingerOne = event.targetTouches[0];
	this.touchObj = { touchStartX: fingerOne.pageX,	touchStartY:fingerOne.pageY, startX: this.object().scrollLeft, startY: this.object().scrollTop, touchMoved: false }
};

container.prototype.touchmove = function(event) {
	event.preventDefault();
	console.log()
	//Move the list
	var fingerOne = event.targetTouches[0];
	var curX = fingerOne.pageX;
	var curY = fingerOne.pageY;
	this.touchObj.dx = curX - this.touchObj.touchStartX;
	this.touchObj.dy = curY - this.touchObj.touchStartY;
	this.object().scrollLeft = (this.touchObj.startX - this.touchObj.dx);
	this.object().scrollTop = (this.touchObj.startY - this.touchObj.dy);
	this.touchObj.touchMoved = true;
	this.touchObj.moveStart = (new Date()).getTime();
};

container.prototype.touchend = function(event) {
	if(!this.touchObj.touchMoved) {
		RS.input.touchHandler(event);
	}
	//Clean up the variables we created
	delete this.touchObj;
};

/* END: CONTAINER */

/* BEGIN: UPLOADER */

// WebFileUploader/framework.js
//
// Utility class for working with the file uploader control
//
// © 2010 REAL Software Inc. -- All Rights Reserved
// This code contains patent-pending technology.

function uploader (target, events)
{
	uploader.baseConstructor.call(this,target,events);
	this.allChoosers = [];
	this.mSelectedRows = [];
	
	var obj = this.object();
	obj.innerHTML = '<div id="' + this.controlID + '_content" style="position: relative;"><table cellpadding="0" cellspacing="0" border="0" class="rows"></table></div><div id="' + this.controlID + '_autorows"><table cellpadding="0" cellspacing="0" border="0" class="rows"></table></div><div id="' + this.controlID + '_buttons" class="buttons"><table cellpadding="0" cellspacing="0" border="0"><tr><td class="button active"><img src="/framework/UploaderAdd.png" width="30" height="24" alt="" id="' + this.controlID + '_add"></td><td class="button inactive"><img src="/framework/UploaderRemove.png" width="30" height="24" alt="" id="' + this.controlID + '_remove"></td><td>&nbsp;</td></tr></table></div>';
	
	var scrollerSource = document.createElement("div");
	scrollerSource.setAttribute("id",this.controlID + "_scroller");
	scrollerSource.setAttribute("style","top: 0px; bottom: 25px; right: 0px; width: 15px;");
	scrollerSource.setAttribute("class","scrollbar vertical");
	obj.appendChild(scrollerSource);
	this.scroller = new scrollbar(this.controlID + "_scroller");
	this.scroller.setEnabled(true);
	this.scroller.valueChanged = "RS.controls['" + this.controlID + "'].scroll()";
	
	var spinnerSource = document.createElement("div");
	spinnerSource.setAttribute("class","spinner black large");
	spinnerSource.setAttribute("id",this.controlID + "_spinner");
	spinnerSource.setAttribute("style","position: absolute; top: 50%; margin-top: -16px; left: 50%; margin-left: -16px;");
	spinnerSource.innerHTML = "&nbsp;";
	
	var overlay = document.createElement("div");
	overlay.setAttribute("class","overlay");
	overlay.setAttribute("style","display: none;");
	overlay.setAttribute("id",this.controlID + "_overlay");
	overlay.appendChild(spinnerSource);
	RS.events.addListener(overlay,"mousedown",function () { return false },false);
	obj.appendChild(overlay);
	this.spinner = new spinner(this.controlID + "_spinner");
	
	this.addChooser();
	RS.input.install(this.object());
	RS.view.sizing.targets.push(this);
	addWheelTarget(this);
	this.refresh();
}

frameworkSubclass(uploader, frameworkObject);
uploader.prototype.nextChooser = null;
uploader.prototype.allChoosers = null;
uploader.prototype.mSelectedRows = null;
uploader.prototype.activeButton = null;
uploader.prototype.spinner = null;
uploader.prototype.scroller = null;
uploader.prototype.mWorking = false;
uploader.prototype.mFileLimit = -1;
uploader.prototype.mFileCount = 0;
uploader.prototype.mMinimumRowHeight = 22;

uploader.prototype.willRefresh = function ()
{
	var autorows = document.getElementById(this.controlID + "_autorows");
	var content = document.getElementById(this.controlID + "_content");
	var bar = document.getElementById(this.controlID + "_buttons");
	var autorows_table = autorows.children[0];
	var content_table = content.children[0];
	
	var viewportHeight = this.object().offsetHeight;
	viewportHeight = viewportHeight - bar.offsetHeight;
	
	this.scroller.setMaximum(Math.max(content_table.offsetHeight - viewportHeight,0));
	if (this.scroller.maximum() > 0) {
		this.scroller.setLineStep(this.mMinimumRowHeight);
		this.scroller.setPageStep(viewportHeight);
		this.scroller.object().style.display = 'block';
	} else {
		this.scroller.object().style.display = 'none';
		if (this.scroller.value() !== 0) {
			this.scroller.setValue(0);
		}
	}
	this.scroller.refresh();
	
	var requiredRows = Math.ceil(viewportHeight / this.mMinimumRowHeight);
	requiredRows = Math.max(requiredRows - content_table.rows.length,0);
	requiredRows = Math.max(requiredRows - autorows_table.rows.length,0);
	
	var row,cell,i;
	if (requiredRows > 0) {
		for (i = 0; i < requiredRows; i++) {
			row = autorows_table.insertRow(-1);
			cell = row.insertCell(-1);
			cell.innerHTML = '&nbsp;';
		}
	}
	
	var className = 'odd';
	for (i = 0; i < content_table.rows.length; i++) {
		if (this.mSelectedRows.indexOf(String(i)) > -1) {
			content_table.rows[i].className = 'selected';
		} else {
			content_table.rows[i].className = className;
		}
		className = (className == 'odd') ? 'even' : 'odd';
	}
	for (i = 0; i < autorows_table.rows.length; i++) {
		autorows_table.rows[i].className = className;
		className = (className == 'odd') ? 'even' : 'odd';
	}
	
	var removeButton = document.getElementById(this.controlID + "_remove");
	if (this.selectedRows().length > 0) {
		removeButton.offsetParent.className = "button active";
	} else {
		removeButton.offsetParent.className = "button inactive";
	}
	
	var addButton = document.getElementById(this.controlID + "_add");
	if ((this.mFileLimit > -1) && (this.mFileCount >= this.mFileLimit)) {
		addButton.offsetParent.className = "button inactive";
	} else {
		addButton.offsetParent.className = "button active";
	}
};

uploader.prototype.addChooser = function ()
{
	var chooser;
	if (this.nextChooser) {
		chooser = document.getElementById(this.nextChooser);
		chooser.style.display = 'none';
		chooser.style.left = '-30px';
		chooser = null;
	}
	
	if ((this.mFileLimit > -1) && (this.mFileCount >= this.mFileLimit)) {
		return;
	}
	
	var div = document.createElement("div");
	div.className = 'chooser';
	
	chooser = document.createElement("input");
	chooser.setAttribute("type","file");
	chooser.setAttribute("name",createRandomString(10));
	
	var cid = this.controlID;
	RS.events.addListener(chooser,"change",function () { RS.controls[cid].fileChosen(chooser) },false);
	
	div.setAttribute("id",chooser.name);
	div.appendChild(chooser);
	this.object().appendChild(div);
	this.allChoosers.push(div.id);
	this.nextChooser = div.id;
};

uploader.prototype.touchBegin = function (event, coordinates)
{
	if (this.mWorking === true) {
		return true;
	}
	
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	
	var bar = document.getElementById(this.controlID + "_buttons");
	
	if ((this.mFileLimit == -1) || (this.mFileCount < this.mFileLimit)) {
		var addButton = document.getElementById(this.controlID + "_add");
		var addRect = {
			left: bar.offsetLeft + addButton.offsetParent.offsetLeft + addButton.offsetLeft,
			top: bar.offsetTop + addButton.offsetParent.offsetTop + addButton.offsetTop
		};
		addRect.right = addRect.left + addButton.offsetWidth;
		addRect.bottom = addRect.top + addButton.offsetHeight;
		
		if ((x >= addRect.left) && (x <= addRect.right) && (y >= addRect.top) && (y <= addRect.bottom)) {
			addButton.offsetParent.className = "button active pressed";
			this.activeButton = addButton;
			return false;
		}
	}
	
	var selRows = this.selectedRows();
	if (selRows.length > 0) {
		var removeButton = document.getElementById(this.controlID + "_remove");
		var removeRect = {
			left: bar.offsetLeft + removeButton.offsetParent.offsetLeft + removeButton.offsetLeft,
			top: bar.offsetTop + removeButton.offsetParent.offsetTop + removeButton.offsetTop
		};
		removeRect.right = removeRect.left + removeButton.offsetWidth;
		removeRect.bottom = removeRect.top + removeButton.offsetHeight;
		if ((x >= removeRect.left) && (x <= removeRect.right) && (y >= removeRect.top) && (y <= removeRect.bottom)) {
			removeButton.offsetParent.className = "button active pressed";
			this.activeButton = removeButton;
			return true;
		}
	}
	
	var scrollRect = {
		left: this.scroller.object().offsetLeft,
		top: this.scroller.object().offsetTop
	};
	scrollRect.right = scrollRect.left + this.scroller.object().offsetWidth;
	scrollRect.bottom = scrollRect.top + this.scroller.object().offsetHeight;
	if ((x >= scrollRect.left) && (x <= scrollRect.right) && (y >= scrollRect.top) && (y <= scrollRect.bottom) && (this.scroller.object().display != 'none')) {
		return RS.input.forwardEvent(event,this.scroller);
	}
	
	return true;
};

uploader.prototype.touchEnd = function (event, coordinates)
{
	if (this.mWorking === true) {
		return true;
	}
	
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	
	if (this.activeButton) {
		RS.view.refresh.lock();
		var bar = document.getElementById(this.controlID + "_buttons");
		var rect = {
			left: bar.offsetLeft + this.activeButton.offsetParent.offsetLeft + this.activeButton.offsetLeft,
			top: bar.offsetTop + this.activeButton.offsetParent.offsetTop + this.activeButton.offsetTop
		};
		rect.right = rect.left + this.activeButton.offsetWidth;
		rect.bottom = rect.top + this.activeButton.offsetHeight;
		
		if ((x >= rect.left) && (x <= rect.right) && (y >= rect.top) && (y <= rect.bottom)) {
			var removeButton = document.getElementById(this.controlID + "_remove");
			if (this.activeButton == removeButton) {
				this.removeSelectedFiles();
			}
		}
		
		this.activeButton.offsetParent.className = "button active";
		this.activeButton = null;
		RS.view.refresh.unlock();
		return true;
	}
	
	var content = document.getElementById(this.controlID + "_content");
	var content_table = content.children[0];
	var contentHeight = content_table.offsetHeight;
	
	y = y - content.offsetTop;
	if (y > contentHeight) {
		this.setSelectedRows(null);
		return true;
	}
	
	var selectType;
	if (event.shiftKey === true) {
		selectType = 2;
	} else {
		if (RS.platform == 1) {
			if (event.metaKey === true) {
				selectType = 3;
			} else {
				selectType = 1;
			}
		} else {
			if (event.ctrlKey === true) {
				selectType = 3;
			} else {
				selectType = 1;
			}
		}
	}
	
	var rows = content_table.rows;
	var i,rowIndex;
	for (i = 0; i < rows.length; i++) {
		if ((y >= rows[i].offsetTop) && (y <= rows[i].offsetTop + rows[i].offsetHeight)) {
			rowIndex = i;
		}
	}
	
	var s = rowIndex.toString();
	var selRows;
	if (selectType == 1) {
		this.setSelectedRows([s],true);
	} else if (selectType == 2) {
		selRows = this.selectedRows();
		var low = rowIndex, high = rowIndex;
		for (i = 0; i < selRows.length; i++) {
			low = Math.min(selRows[i],low);
			high = Math.max(selRows[i],high);
		}
		selRows = [];
		for (i = low; i <= high; i++) {
			selRows.push(String(i));
		}
		this.setSelectedRows(selRows,false);
	} else if (selectType == 3) {
		selRows = this.selectedRows();
		if (selRows.indexOf(s) == -1) {
			selRows.push(s);
		} else {
			selRows.splice(selRows.indexOf(s),1);
		}
		this.setSelectedRows(selRows,false);
	}
	
	return true;
};

uploader.prototype.touchMove = function (event, coordinates)
{
	if (this.mWorking === true) {
		return true;
	}
	
	var x = coordinates[0].x;
	var y = coordinates[0].y;
	
	if (this.activeButton) {
		var bar = document.getElementById(this.controlID + "_buttons");
		var rect = {
			left: bar.offsetLeft + this.activeButton.offsetParent.offsetLeft + this.activeButton.offsetLeft,
			top: bar.offsetTop + this.activeButton.offsetParent.offsetTop + this.activeButton.offsetTop
		};
		rect.right = rect.left + this.activeButton.offsetWidth;
		rect.bottom = rect.top + this.activeButton.offsetHeight;
		
		var p = this.activeButton.offsetParent;
		var cn = "button active";
		if ((x >= rect.left) && (x <= rect.right) && (y >= rect.top) && (y <= rect.bottom)) {
			cn = cn + " pressed";
		}
		if (p.className != cn) {
			p.className = cn;
		}
	}
	
	return true;
};

uploader.prototype.mouseWheel = function (deltaX, deltaY)
{
	this.scroller.setValue(this.scroller.value() + deltaY);
};

uploader.prototype.selectedRows = function ()
{
	return this.mSelectedRows;
};

uploader.prototype.setSelectedRows = function (rows, scrollTo)
{
	if (rows === null) {
		rows = [];
	}
	this.mSelectedRows = rows;
	this.refresh();
	
	if ((scrollTo === null) || (scrollTo === true)) {
		if (rows.length > 0) {
			this.scrollToRow(rows[0]);
		}
	}
};

uploader.prototype.fileChosen = function (chooser)
{
	this.mFileCount++;
	this.addChooser();
	
	var content = document.getElementById(this.controlID + "_content");
	var content_table = content.children[0];
	var row = content_table.insertRow(-1);
	var cell = row.insertCell(-1);
	
	var n = chooser.value;
	var parts = n.split('\\');
	n = parts[parts.length - 1];
	cell.innerHTML = n;
	
	var userdata = [n];
	RS.comm.triggerEvent(this.controlID,'FileAdded',userdata);
	
	this.refresh();
};

uploader.prototype.beginUpload = function ()
{
	if (this.mFileCount < 1) {
		return false;
	}
	
	document.getElementById(this.controlID + "_form").submit();
	
	this.spinner.setEnabled(true);
	this.mWorking = true;
	document.getElementById(this.controlID + "_overlay").style.display = 'block';
	
	var userdata = [];
	userdata.push(this.mFileCount);
	if (this.implementedEvents.indexOf('UploadBegin') > -1) {
		RS.comm.triggerEvent(this.controlID,'UploadBegin',userdata);
	}
};

uploader.prototype.reset = function ()
{
	if (this.mWorking !== true) {
		return;
	}
	
	document.getElementById(this.controlID + "_overlay").style.display = 'none';
	this.spinner.setEnabled(false);
	this.mWorking = false;
	this.mFileCount = 0;
	this.nextChooser = null;
	
	var i,chooser;
	for (i = 0; i < this.allChoosers.length; i++) {
		chooser = document.getElementById(this.allChoosers[i]);
		this.object().removeChild(chooser);
	}
	
	var table = document.getElementById(this.controlID + "_content").children[0];
	for (i = table.rows.length - 1; i >= 0; i--) {
		table.deleteRow(i);
	}
	
	this.allChoosers = [];
	this.addChooser();
	this.refresh();
	
	if (this.implementedEvents.indexOf('UploadComplete') > -1) {
		RS.comm.triggerEvent(this.controlID,'UploadComplete');
	}
};

uploader.prototype.filenames = function ()
{
	var i,chooser,child;
	var results = [];
	for (i = 0; i < this.allChoosers.length - 1; i++) {
		chooser = document.getElementById(this.allChoosers[i]);
		child = chooser.children[0];
		if (child) {
			results.push(child.value);
		}
	}
	return results;
};

uploader.prototype.removeFile = function (rowIndex)
{
	var overLimit = ((this.mFileLimit > -1) && (this.mFileCount >= this.mFileLimit));
	var chooser = document.getElementById(this.allChoosers[rowIndex]);
	this.object().removeChild(chooser);
	this.allChoosers.splice(rowIndex,1);
	
	var rows = document.getElementById(this.controlID + "_content").children[0];
	rows.deleteRow(rowIndex);
	
	var selRows = this.selectedRows();
	if (selRows.indexOf(String(rowIndex)) > -1) {
		selRows.splice(selRows.indexOf(String(rowIndex)),1);
	}
	
	this.mFileCount--;
	if ((overLimit === true) && (this.mFileCount < this.mFileLimit)) {
		var addButton = document.getElementById(this.controlID + "_add");
		addButton.offsetParent.className = "button active";
		this.addChooser();
	}
	this.refresh();
};

uploader.prototype.removeSelectedFiles = function ()
{
	var selRows = this.selectedRows();
	var i;
	var userdata = [];
	for (i = selRows.length - 1; i >= 0; i--) {
		userdata.push(selRows[i]);
		this.removeFile(selRows[i]);
	}
	RS.comm.triggerEvent(this.controlID,'FileRemoved',userdata);
};

uploader.prototype.fileLimit = function ()
{
	return this.mFileLimit;
};

uploader.prototype.setFileLimit = function (value)
{
	this.mFileLimit = parseInt(value,10);
};

uploader.prototype.fileCount = function ()
{
	return this.mFileCount;
};

uploader.prototype.scroll = function ()
{
	var content = document.getElementById(this.controlID + "_content");
	if (content) {
		content.style.top = Math.floor(this.scroller.value() * -1) + 'px';
	}
};

uploader.prototype.scrollToRow = function (rowIndex)
{
	var content = document.getElementById(this.controlID + "_content");
	var content_table = content.children[0];
	var rows = content_table.rows;
	if ((rowIndex < 0) || (rowIndex >= rows.length)) {
		return;
	}
	
	var row = rows[rowIndex];
	var viewportHeight = this.scroller.object().offsetHeight;
	var position = content.offsetTop;
	var top = row.offsetTop + position;
	var bottom = top + row.offsetHeight;
	
	if (top < 0) {
		this.scroller.setValueAnimated(top - position);
	} else if (bottom > viewportHeight) {
		var diff = bottom - viewportHeight;
		this.scroller.setValueAnimated(this.scroller.value() + diff);
	}
};

uploader.prototype.setAppearance = function(enabled) {
	var chooser = document.getElementById(this.nextChooser).children[0];
	if(enabled) {
		chooser.disabled = false;
	} else {
		chooser.disabled = true;
	}
};

/* END: UPLOADER */
