// Miscellaneous

// create crossbrowser element object
function xbObj(el)
{
	if(document.layers)
		return document.layers[el];
	else if(document.all)
		return document.all[el];
	else if(document.getElementById)
		return document.getElementById(el);
	else
		return false;
}

// DX:TEXT CONTROL ----------------------------------------------------------------------------------------------------------------------------------

function dxText() {
	// Inherits dxControl functionality.
	dxControl.call(this);
}


//Support function - not a control object.
function dxTextCounter(field, countfield, maxlimit) {
	var value;

	if(field) {
		if(field.getValue) {
			value = field.getValue();
		}
		else {
			value = field.value;
		}
		
		if(value == null || value == undefined) value = "";
		
		if(value.length > maxlimit) {
			var overage = value.length - maxlimit;
			var unit = (overage == 1) ? "character" : "characters";
			
	   	if(countfield.style.color != "red") 
				countfield.style.color = "red";
	   	if(countfield.innerHTML != "You are " + overage + " " + unit + " over the limit") 
				countfield.innerHTML = "You are " + overage + " " + unit + " over the limit";
		}
	   else {
	   	if(countfield.style.color != "#000") 
	   		countfield.style.color = "#000";
	   	if(countfield.innerHTML != (maxlimit - value.length)) 
	   		countfield.innerHTML = maxlimit - value.length;
	   }
	}
}



// DX:DROP-DOWN CONTROL ----------------------------------------------------------------------------------------------------------------------------------

function dxDropDown() {
	// Inherits dxControl functionality.
	dxControl.call(this);
	this.getCode = dxDropDown_getCode;
	this.getText = dxDropDown_getText;
	this.toXml = dxDropDown_toXml;
	this.getSortValue = dxDropDown_getSortValue;
	if(this.onchange && !this.dxDropDown_base_onchange) {
		this.dxDropDown_base_onchange = this.onchange;
	}
	this.onchange = dxDropDown_onchange;
	this.setValue = dxDropDown_setValue;
	
	// Store the initial value.
	this.previousValue = this.getValue();
}

function dxDropDown_setValue() {
	this.settingValue = true;
	dxControl_setValue.apply(this, arguments);
	this.settingValue = false;
}

function dxDropDown_getCode() {
	var index = this.selectedIndex;
	if(index == -1) {
		return("");
	}
	else {
		var item = this.options[index];
		if(item.code) {
			return(item.code);
		}
		else {
			return("");
		}
	}
}

function dxDropDown_getText() {
	var index = this.selectedIndex;
	if(index == -1) {
		return("");
	}
	else {
		var item = this.options[index];
		if(item.text) {
			return(item.text);
		}
		else {
			return("");
		}
	}
}

function dxDropDown_toXml() {
	if(!this.multiple) {
		// If this is NOT a multi-select list, then do the default behavior that dxControl does.
		return(dxControl_toXml.call(this));
	}
	else {
		// If this IS a multi-select list, then the output is different.
		var aXML = new Array();
		var name = (this.name ? this.name : this.id);
		var tagName = XMLEncodeName((name ? name : this.tagName));
		var bStructured = (this["xml-format"] == "structured");
		if(bStructured) {
			aXML.push("<" + tagName + ">");
		}
		var options = this.options;
		var valueTagName = (bStructured ? "Value" : tagName);
		for(var counter = 0; counter < options.length; counter++) {
			var option = options[counter];
			if(option.selected) {
				aXML.push(XMLEncodeElement(valueTagName, option.value, true));
			}
		}
		if(bStructured) {
			aXML.push("</" + tagName + ">");
		}
		return(aXML.join(""));
	}
}


// Returns the value to be used when sorting a series of these controls.
function dxDropDown_getSortValue() {
	var index = this.selectedIndex;
	if(index == -1 ) {
		return(null);
	}
	else {
		var item = this.options[index];
		if(item.DisplayOrder) {
			return(item.DisplayOrder);
		}
		else {
			return(item.text);
		}
	}
}

function dxDropDown_onchange() {
	if(this.dxDropDown_base_onchange) {
		this.dxDropDown_base_onchange.apply(this, arguments);
	}
	// The dxOnChange event will be called separately, from within the setValue method itself, so there's no reason to call it from here or else it will get called twice.
	if(!this.settingValue) {
		if(this.dxOnChange) {
			this.dxOnChange(this.previousValue);
		}
	}
	this.previousValue = this.getValue();
}

// dxFakeDropdown ----------------------------------------------------------------------------------
// <dx:drop-down edit-mode="table" ...>

	function dxFakeDropdown() {
		
		// Popup Management.
		this.getPopup = dxFakeDropdown_getPopup;
		this.createPopup = dxFakeDropdown_createPopup;
		this.getPopupInnerHtml = dxFakeDropdown_getPopupInnerHtml;
		this.getOptionsHtml = dxFakeDropdown_getOptionsHtml;
		this.refreshPopup = dxFakeDropdown_refreshPopup;
		this.displayPopup = dxFakeDropdown_displayPopup;
		this.hidePopup = dxFakeDropdown_hidePopup;
		this.popupVisible = dxFakeDropdown_popupVisible;
		this.getDefaultDisplayHtml = dxFakeDropdown_getDefaultDisplayHtml;
		this.updateText = dxFakeDropdown_updateText;
		this.togglePopup = dxFakeDropdown_togglePopup;
		
		// Mouse and keyboard event handling.
		this.onmousedown = dxFakeDropdown_onmousedown;
		this.ondblclick = dxFakeDropdown_onmousedown;
		this.onkeydown = dxFakeDropdown_onkeydown;
		this.ondragstart = function() {return(false);};		
		this.onmouseover = dxFakeDropdown_onmouseover;
		this.onmouseout = dxFakeDropdown_onmouseout;
		
		// Dropdown list manipulation.
		this.getContent = dxFakeDropdown_getContent;
		this.updateOptionHtml = dxFakeDropdown_updateOptionHtml;
		this.updateOptionsHtml = dxFakeDropdown_updateOptionsHtml;
		this.toggleItemState = dxFakeDropdown_toggleItemState;
		this.selectItem = dxFakeDropdown_selectItem;
		
		// Programmatic interface.
		this.getValue = dxFakeDropdown_getValue;
		this.getComplexValue = dxFakeDropdown_getComplexValue;
		this.setValue = dxFakeDropdown_setValue;
		this.optionSelected = dxFakeDropdown_optionSelected;
		this.optionByValue = dxFakeDropdown_optionByValue;
		this.mergeValues = dxFakeDropdown_mergeValues;
		this.getCode = dxFakeDropdown_getCode;
		this.setCode = dxFakeDropdown_setCode;
		this.getText = dxFakeDropdown_getText;
		this.toXml = dxFakeDropdown_toXml;
		this.setEnabled = dxFakeDropdown_setEnabled;
		this.raiseOnChanged = dxFakeDropdown_raiseOnChanged;
		this.getSortValue = dxFakeDropDown_getSortValue;
		this.getOptions = dxFakeDropDown_getOptions;
		this.needsBlankOption = dxFakeDropdown_needsBlankOption;
		this.addBlankOptionIfMissing = dxFakeDropdown_addBlankOptionIfMissing;
		this.setOptions = dxFakeDropDown_setOptions;
		this.normalizeOptions = dxFakeDropDown_normalizeOptions;
		this.getStateCycleForOption = dxFakeDropdown_getStateCycleForOption;
		this.doBehaviorEvent = dxFakeDropdown_doBehaviorEvent;
		
		// Cosmetic Behavior. (still needs work - flickers.)
		this.getButton = dxFakeDropDown_getButton;
		
		var Anchor = this.firstChild.firstChild;
		Anchor.onclick = dxFakeDropdown_Anchor_onclick;
		Anchor.onfocus = dxFakeDropdown_Anchor_onfocus;
		Anchor.onblur = dxFakeDropdown_Anchor_onblur;
		Anchor.getControlElement = dxFakeDropDown_Anchor_getControlElement;
		Anchor.onmouseenter = dxFakeDropDown_Anchor_onmouseenter;
		Anchor.onmouseout = dxFakeDropDown_Anchor_onmouseout;
		
		// Initialization.
		this.selectionColor = Anchor.style.color;
		if(typeof(this.onchange) == "string" && !this.dxFakeDropDown_base_onchange) {
			this.dxFakeDropDown_base_onchange = new Function(this.onchange);
		}
		this.onchange = dxFakeDropDown_onchange;
		
		var dxOnChange = this.getAttribute("dx-onchange");
		if(typeof(dxOnChange) == "string") {
			this.dxOnChange = new Function(dxOnChange);
		}
		
		this.multiState = (this["multi-state"] == 'true' || this.multiple);
		this.stickyText = null;
		this.displayAttribute = this["display-attribute"] ? this["display-attribute"] : "description";
		
		var popup = this.getPopup();
		
		this.options = this.normalizeOptions(this.options);
		this.addBlankOptionIfMissing();
		
		// Set value and selected index.
		if(!this.multiState) {
			if (this.value == "" && this["no-selection-text"]) {
				this.selectedIndex = -1;
				this.updateText();
			}
			else {
				this.setValue(this.value);
			}
		}
		else {
			this.selectedIndex = -1;
			this.updateText();
		}
		
		this.setEnabled(!this.disabled);
		if (!this.anyNonBinaryStates)
		{
			this.previousValues = this.getValue();
		}
		this.initialized = true;
	}
	
	/***************************************************
	Popup Management
	****************************************************/
	
	// Monitors the popup's visibility, raises certain events and cleans up when it is closed.
	// (This is not a method of the control.  Just a function that occurs in an "interval" when the popup is opened). 
	function dxFakeDropdown_checkPopup() {
		if(window.currentPopup) {
			if(!window.currentPopup.isOpen) {
				clearInterval(window.currentPopupTimer);
				window.currentPopup = null;
				if(window.currentFakeDropdown) {
					window.currentFakeDropdown.raiseOnChanged();
					window.currentFakeDropdown = null;
				}
			}
		}
		else {
			window.currentFakeDropdown = null;
		}
	}
	
	function dxFakeDropdown_getPopup()
	{
		if (!window.popups) window.popups = new Object();
		
		var popup = window.popups[this.popupID];
		if (!popup) popup = window.popups[this.popupID] = this.createPopup();
		
		return popup;
	}
	
	var fakeDropdownStyles;
	
	// Create stub of dropdown's popup.  Populated with actual content and JS functionality in refreshPopup().
	function dxFakeDropdown_createPopup()
	{
		var popup = window.top.createPopup();
		var doc = popup.document;
		
		if(!fakeDropdownStyles) {
			fakeDropdownStyles = new Array();
			
			for (var s = 0; s < document.styleSheets.length; s++) { 
				var sheet = document.styleSheets[s];
				for(var r = 0; r < sheet.rules.length; r++) {
					var rule = sheet.rules[r];
					var selectorText = rule.selectorText;
					if(selectorText.indexOf("GlobalImageList") != -1 || selectorText.indexOf("img_") != -1 || selectorText.indexOf("dxFakeDropdown") != -1) {
						fakeDropdownStyles.push({selectorText: selectorText, cssText: rule.style.cssText});
					}
				}
			}
			fakeDropdownStyles.push({selectorText: ".GlobalImageList", cssText: "background-image: url(" + root + "/images/_GlobalImageList" + (is_ie7up ? ".png" : ".gif") + ")"});
		}
		
		var sheet = doc.createStyleSheet();
		// Copy the relevant styles from the current document into the Popup's document.
		for (var i=0; i < fakeDropdownStyles.length; i++) { 
			var rule = fakeDropdownStyles[i];
			if (!rule.cssText || rule.cssText == "") {
				rule.cssText = " ";
			}
			sheet.addRule(rule.selectorText, rule.cssText);
		}
		
		return popup;
	}
	
	function dxFakeDropdown_getPopupInnerHtml()
	{
		var html =
			[
				'<div class="dxFakeDropdownContent">',
					'<table cellspacing="0">',
						this.multiState ? '<col style="width: 22px;"></col>' : '',
						this.options.anyImages ? '<col style="width: 22px;"></col>' : '',
						'<col style="width: 100%;"></col>',
						
						this.getOptionsHtml(),
					'</table>',
				'</div>'
			];
		return html.join('');
	}
	
	function dxFakeDropdown_getOptionsHtml()
	{
		var html = [], option, value, stateCycle, state = {}, cellStyle;
		if (!this.multiState) value = this.getValue();
		
		for (var i = 0; i < this.options.length; i++)
		{
			// Context
			option = this.options[i];
			if (this.multiState)
			{
				stateCycle = option.stateCycle;
				state = stateCycle.getState(option.stateIndex);
			}
			cellStyle = state.style ? state.style : (this.style ? this.style : "");
			
			if (i == 0 && !this.multiState && option.value == "" && option.description == "")
			{
				// Initial blank option.
				html.push('<tr><td');
				if (cellStyle) html.push(XMLEncodeAttribute("style", cellStyle));
				html.push('>&nbsp;</td></tr>');
			}
			else
			{
				// Normal option row.
				
				// Row header.
				html.push('<tr');
				for (var o in option)
				{
					if (o != 'description') html.push(XMLEncodeAttribute(o, option[o]));
				}
				if (option.separator) html.push(XMLEncodeAttribute("class", "separator"));
				if (this.multiState)
				{
					if (state.style && !option.style) html.push(' style="' + state.style + '"');
				}
				html.push('>');
				
				// Checkbox column.
				if (this.multiState)
				{
					html.push('<td');
					if (cellStyle) html.push(XMLEncodeAttribute("style", cellStyle));
					html.push('>');
					
					if (state.image)
					{
						html.push('<div cb="true" class="GlobalImageList img_' + state.image + '"');
						if (state.value) html.push(' checked="checked" state="' + state.value + '"');
						html.push('></div>');
					}
					
					html.push('</td>');
				}
				
				// Image column.
				if (this.options.anyImages)
				{
					html.push('<td');
					if (cellStyle) html.push(XMLEncodeAttribute("style", cellStyle));
					html.push('>');
					if (option.image)
						html.push('<div class="GlobalImageList img_' + option.image + '"></div>');
					else
						html.push('&nbsp;');
					html.push('</td>');
				}
				
				// Content.
				html.push('<td');
				if (cellStyle) html.push(XMLEncodeAttribute("style", cellStyle));
				html.push('>' + option.description);
				html.push('</td></tr>');
			}
		}
		
		return html.join('');
	}
	
	// Re-render popup HTML.
	function dxFakeDropdown_refreshPopup() {
		var popup = this.getPopup();
		var alreadyVisible = popup.isOpen;
		
		if (!alreadyVisible) popup.show(0, this.offsetHeight, 1, 1, this);
		
		popup.document.body.innerHTML = this.getPopupInnerHtml();  // Build content of popup.
		var content = this.getContent();
		// Apply the js-class to the popup internal table.
		dxFakeDropdownContent.call(content, window);
		
		var table = content.firstChild;
		var rows = table.rows;
		var rowCount = rows.length;
		if(rowCount > 30) rowCount = 30;
		var lastVisibleRow = rows[rowCount - 1];
		var height;
		if(rowCount > 0)
			height = lastVisibleRow.offsetTop + lastVisibleRow.offsetHeight + 2;
		else
			height = 13;
		
		if(!this.optimalWidth) {
			this.optimalWidth = 0;
			for(var r = 0; r < rows.length; r++) {
				var rowWidth = 0;
				var row = rows[r];
				for(var c = 0; c < row.cells.length; c++) {
					var cell = row.cells[c];
					rowWidth += cell.scrollWidth + 8; // assume 4 pixels of padding on either side.
				}
				rowWidth += 20; // Add width of potential scroll bar.
				if(rowWidth > this.optimalWidth)
					this.optimalWidth = rowWidth;
			}
		}
		if(this.offsetWidth > this.optimalWidth) this.optimalWidth = this.offsetWidth;
		popup.show(0, this.offsetHeight, this.optimalWidth, height, this);
		
		if(!this.multiState && this.selectedIndex != -1) {
			content.highlightRow(this.selectedIndex);
			content.ensureVisible(table.rows[this.selectedIndex]);
		}
	}
	
	// Shows the popup window to display the dropdown list.
	function dxFakeDropdown_displayPopup() {
		var popup = window.popups[this.popupID];
		window.currentPopup = popup;
		window.currentFakeDropdown = this;
		this.refreshPopup();
		window.currentPopupTimer = setInterval(dxFakeDropdown_checkPopup, 50);
	}
	
	// Hides the popup window.
	function dxFakeDropdown_hidePopup() {
		window.popups[this.popupID].hide();
		try {
			if(!this.disabled) this.firstChild.focus();
		}
		catch(e) {}
		dxFakeDropdown_checkPopup();
	}
	
	// Returns whether the popup is currently visible.
	function dxFakeDropdown_popupVisible() {
		return(window.popups[this.popupID].isOpen);
	}
	
	function dxFakeDropdown_togglePopup() {
		if(!this.disabled) {
			if(!window.currentPopup) {
				this.displayPopup();
			}
			else {
				this.hidePopup();
			}
		}
	}
	
	function dxFakeDropDown_onchange() {
		if(this.dxFakeDropDown_base_onchange) {
			this.dxFakeDropDown_base_onchange.apply(this, arguments);
		}
		if(this.dxOnChange) {
			this.dxOnChange(this.previousValues);
		}
	}

	/***************************************************
	Mouse and Keyboard Event Handling
	****************************************************/
	
	//Show or hide the popup on a mouse click.
	function dxFakeDropdown_onmousedown() {
		if(event.button == 1) {
			this.togglePopup();
			event.cancelBubble = true;
		}
		return(false);	
	}
	
	// Handle keypresses.
	function dxFakeDropdown_onkeydown() {
		if(!this.disabled) {
			// Alt+Up or Alt+Down toggle the display of the popup.
			if(event.altKey && (event.keyCode == 40 || event.keyCode == 38)) {
				this.togglePopup();
				event.cancelBubble = true;
				return(false);
			}
			else {
				var inEditTable = false;
				if(event.keyCode == 40 || event.keyCode == 38) {
					var table = findParentByTagName(this, "TABLE");
					if(table) {
						var jsClass = table["js-class"];
						if(jsClass == "dxDataTable" || jsClass == "dxTreeTable") {
							inEditTable = true;
						}
					}
				}
				
				switch(event.keyCode) {
					// The up and down arrow keys change the selected item from the list.
					case 40: // Down.
						if(!inEditTable || this.popupVisible()) {
							if (this.selectedIndex < this.options.length - 1) {
								this.selectItem(this.selectedIndex + 1);
							}
							event.cancelBubble = true;
						}
						return(false);
						break;
					case 38: // Up.
						if(!inEditTable || this.popupVisible()) {
							if(this.selectedIndex > 0) {
								this.selectItem(this.selectedIndex - 1);
							}
							event.cancelBubble = true;
						}
						return(false);
						break;
					case 37: // Left.
					case 39: // Right.
					case 32: // Space bar.
						if(this.multiState && !inEditTable && this.popupVisible()) {
							if (this.selectedIndex >= 0) {
								this.toggleItemState(this.selectedIndex, event.keyCode == 37);
								event.cancelBubble = true;
							}
							return(false);
						}
						break;
						
					// The Enter key closes the list and commits the selection.				
					case 13: // Enter;
						if(this.popupVisible()) {
							this.hidePopup();
							this.raiseOnChanged();
							event.cancelBubble = true;
							return(false);
						}
						break;
					
					default:
						// If the key that is pressed is either a letter or a number, find the first (or next) item
						// in the list that starts with that character.
						if(!event.ctrlKey && !event.altKey && !event.shiftKey && String.fromCharCode(event.keyCode).search(/\w/) != -1) {
							if ((!this.multiState) || this.popupVisible())
							{
								var options = this.options;
								var re = new RegExp("^" + String.fromCharCode(event.keyCode), "i");
								var currentOptionText = "";
								if(this.selectedIndex != -1) {
									currentOptionText = options[this.selectedIndex][this.displayAttribute];
								}
								var start;
								// If the current row's text starts with the character that was typed
								if(currentOptionText.search(re) != -1) {
									// then only search rows that are subsequent to this one.
									start = this.selectedIndex + 1;
								}
								else {
									// otherwise, start from the top.
									start = 0;
								}
								
								var numOptions = options.length;
								// Examine the rows in the table.
								for(var i = 0; i < numOptions; i++) {
									var index = i + start;
									if(index >= numOptions) index -= numOptions;
									
									// Get the row's text.
									var text = options[index][this.displayAttribute];
									
									// If it matches the search expression...
									if(text.search(re) != -1) {
										// Select it and get out.
										this.selectItem(index);
										event.cancelBubble = true;
										return(false);
									}
								}
							}
						}
						break;
				}
			}
		}
	}
	
	// onmouseover event handler for the dxFakeDropdown control
	// Note: this is overridden in dx-forms-fe.js
	function dxFakeDropdown_onmouseover() {
	}
	
	// onmouseover event handler for the dxFakeDropdown control
	// Note: this is overridden in dx-forms-fe.js
	function dxFakeDropdown_onmouseout() {
	}
	
	/***************************************************
	Dropdown List Manipulation
	****************************************************/
	// Returns the table element that presents the list.
	function dxFakeDropdown_getContent() {
		return(window.popups[this.popupID].document.body.firstChild);
	}
	
	function dxFakeDropdown_updateOptionHtml(index)
	{
		if (!this.multiState) throw newFrameworkException("notSupported", "Method only supported for multi-state options.");
		
		var option = this.options[index];
		var stateCycle = option.stateCycle;
		var state = stateCycle.getState(option.stateIndex);
		
		var content = this.getContent();
		var row = content.firstChild.rows[index];
		
		row.selected = (state.value != null);
		row.firstChild.firstChild.checked = row.selected;
		row.firstChild.firstChild.className = "GlobalImageList " + (state.image ? "img_" + state.image : "");
		row.style.cssText = (state.style ? state.style : "");
		for (var i = 0; i < row.cells.length; i++)
		{
			row.cells[i].style.cssText = row.style.cssText;
		}
	}
	
	function dxFakeDropdown_updateOptionsHtml()
	{
		for (var i = 0; i < this.options.length; i++)
		{
			this.updateOptionHtml(i);
		}
	}
	
	// Toggles the state of the current option in a multi-state dropdown.
	function dxFakeDropdown_toggleItemState(index, toggleBackwards)
	{
		if (!this.multiState) throw newFrameworkException("notSupported", "Cannot toggle item state in single-state dropdown.");
		
		if (index >= 0 && index < this.options.length)
		{
			// Context.
			var option = this.options[index];
			var stateCycle = option.stateCycle;
			
			// Determine new state.
			var state, oldIndex = option.stateIndex;
			if (toggleBackwards)
				state = stateCycle.getPrevState(option.stateIndex);
			else
				state = stateCycle.getNextState(option.stateIndex);
			option.stateIndex = state.index;
			
			var anyChanges = false;
			if (this.doBehaviorEvent('onToggleItemState', [option, oldIndex, option.stateIndex])) anyChanges = true;
			if (this.doBehaviorEvent('onOptionStateChanged')) anyChanges = true;
			
			if (this.popupVisible())
			{
				if (anyChanges)
					this.updateOptionsHtml();
				else
					this.updateOptionHtml(index);
			}
			
			this.updateText();
			if (this.onToggleItemState) this.onToggleItemState(index);
		}
	}
	
	// Highlights the specified list item, and for single state dropdowns, sets the current value and selectionIndex.
	function dxFakeDropdown_selectItem(index) {
		this.selectedIndex = index;
		
		// For single-state dropdowns, change the current selected item.
		if (!this.multiState)
		{
			if (index == -1)
				this.lastChild.value = this.value = null;
			else
				this.lastChild.value = this.value = this.options[index].value;
		}
		
		this.updateText();
		
		if (this.popupVisible())
		{
			var content = this.getContent();
			var table = content.firstChild;
			content.highlightRow(index);
			if (index != -1) content.ensureVisible(table.rows[index]);
		}
		else if (!this.multiState && this.initialized && this.onchange)
		{
			this.onchange();
		}
	}
	
	// Returns an object that contains:
	//	displayHtml
	//	titleText (tooltip) - may be undefined
	//	displayColor - may be undefined
	function dxFakeDropdown_getDefaultDisplayHtml()
	{
		var options = this.options;
		var numOptions = options.length;
		var option, textValue;
		var htmlBuilder, textBuilder;
		var args = {
			displayHtml: ''
		}
		
		if (this.anyNonBinaryStates) {
			args.displayHtml = "(multiple)";
		}
		// Can still handle full display for simple on/off (checkbox) states.
		else if (this.multiState) {
			var textSeparator = this["multiple-text-separator"];
			if(!textSeparator) textSeparator = ", ";
			
			var numSelected = 0;
			var numPossibleSelections = 0;
			var allOptionSelected = false;
			for(var i = 0; i < numOptions; i++) {
				option = options[i];
				if (!option.behavior || !option.behavior.excludeValue)
				{
					numPossibleSelections++;
					if (this.optionSelected(i, true)) numSelected++;
				}
				if(option.behavior && option.behavior.name == 'All' && this.optionSelected(i, true)){
					allOptionSelected = true;
				}
			}
			
			if (numSelected > 0) {
				if (this["all-selection-text"] && (numSelected == numPossibleSelections || allOptionSelected))
				{
					args.titleText = args.displayHtml = XMLEncode(this["all-selection-text"]);
				}
				else if (this["multiple-selection-text"] && numSelected > 1)
				{
					args.titleText = args.displayHtml = XMLEncode(this["multiple-selection-text"]);
				}
				else
				{
					htmlBuilder = [];
					textBuilder = [];
					
					for (var i = 0; i < numOptions; i++)
					{
						option = options[i];
						if (this.optionSelected(i, true))
						{
							textValue = option[this.displayAttribute];
							
							if (numSelected == 1 && option.image)
							{
								htmlBuilder.push('<div class="GlobalImageList img_' + option.image + '" style="margin-top: -1px"></div>&#160;');
							}
							htmlBuilder.push(XMLEncode(textValue));
							textBuilder.push(textValue);
						}
					}
					args.displayHtml = htmlBuilder.join(textSeparator);
					args.titleText = textBuilder.join(textSeparator);
				}
				if (this["no-selection-color"]) args.displayColor = this.selectionColor;
			}
			else {
				if(this["no-selection-text"]) {
					args.displayHtml = XMLEncode(this["no-selection-text"]);
					if(this["no-selection-color"]) args.displayColor = this["no-selection-color"];
				}
				else {
					args.displayHtml = "";
				}
			}
		}
		else {
			htmlBuilder = [];
			
			var selectedBlankOption = false;
			if (this.selectedIndex >= 0)
			{
				var selectedOption = this.options[this.selectedIndex];
				selectedBlankOption = selectedOption.value == '' || !selectedOption.value;
			}
			
			if(this.selectedIndex != -1 && !(this["no-selection-text"] && selectedBlankOption)) {
				option = this.options[this.selectedIndex];
				if(option.image) htmlBuilder.push('<div class="GlobalImageList img_' + option.image + '" style="margin-top: -1px"></div>&#160;');
				
				textValue = option[this.displayAttribute];
				htmlBuilder.push(XMLEncode(textValue));
				
				args.displayHtml = htmlBuilder.join('');
				args.titleText = textValue;
				if (this["no-selection-color"]) args.displayColor = this.selectionColor;
			}
			else {
				if(this["no-selection-text"]) {
					args.displayHtml = XMLEncode(this["no-selection-text"]);
					if(this["no-selection-color"]) args.displayColor = this["no-selection-color"]
				}
				else {
					args.displayHtml = "";
				}
				args.titleText = "";
			}
		}
		
		return args;
	}
	
	function dxFakeDropdown_updateText() {
		var args;
		
		if (this.onDisplayText)
			args = this.onDisplayText();  // Use external hook to populate display values.
		else if (this.stickyText)
			args = { displayHtml: XMLEncode(this.stickyText) };
		else
			args = this.getDefaultDisplayHtml();
		
		var displayElement = this.firstChild.firstChild;
		
		// Plug final values into the DOM.
		var anyImages = /<img/.test(args.displayHtml) || /GlobalImageList/.test(args.displayHtml);
		displayElement.style.marginTop = (anyImages ? "0px" : "");
		displayElement.innerHTML = args.displayHtml;
		displayElement.style.color = args.displayColor ? args.displayColor : null;
		this.title = args.titleText ? args.titleText : '';
		if (!this.anyNonBinaryStates)
		{
			this.value = this.getValue();
			this.lastChild.value = this.value;
		}
	}
	
	function dxFakeDropDown_getButton () {
		return this.children[1];
	}
	
	
	/***************************************************
	Programmatic Interface
	****************************************************/
	
	// Returns the "value" of the selected item.
	function dxFakeDropdown_getValue(delimiter) {
		if (this.anyNonBinaryStates) {
			throw newFrameworkException("notSupported", "getValue() not supported for multi-state dropdowns with complex states.");
		}
		if(this.multiState) { // Simple binary states for each option. Can be expressed as simple delimited list.
			var values = new Array();
			var options = this.options;
			for(var i = 0; i < options.length; i++) {
				var option = options[i];
				if(this.optionSelected(i) && (!option.behavior || !option.behavior.excludeValue)) {
					values.push(option.value);
				}
			}
			if(!delimiter) delimiter = this["multiple-value-separator"];
			if(!delimiter || delimiter == "") delimiter = ",";
			return(values.join(delimiter));
		}
		else {
			return this.value;
		}
	}
	
	// Returns value(s) as JavaScript data structure.
	//		Multi-state with non-binary states?		==> array of records (each with a "value" and "state" property)
	//		Multi-state with binary states only?	==>	array of scalar values
	//		Single-state?							==> scalar value
	function dxFakeDropdown_getComplexValue()
	{
		if (this.multiState)
		{
			var values = new Array();
			var options = this.options;
			for(var i = 0; i < options.length; i++) {
				var option = options[i];
				if(this.optionSelected(i) && (!option.behavior || !option.behavior.excludeValue)) {
					if (this.anyNonBinaryStates)
						values.push({
							value: option.value,
							state: option.stateCycle.getState(option.stateIndex).value });
					else
						values.push(option.value);
				}
			}
			return values;
		}
		else
		{
			return this.getValue();
		}
	}
	
	// Sets the selected item to the specified value. Pass different type of value depending on mode:
	//		Multi-state with non-binary states?		==> array of records (each with a "value" and "state" property)
	//		Multi-state with binary states only?	==>	array of scalar values
	//		Single-state?							==> scalar value
	function dxFakeDropdown_setValue(value, delimiter, text) {
		var i, visible = this.popupVisible();
		if (text) this.stickyText = text;
		
		if (this.multiState)
		{
			var option, stateCycle, stateValue;
			
			// SPECIAL CASE. If binary states only, could have received values as delimited string. 
			if (!this.anyNonBinaryStates && (typeof(value) == 'string' || typeof(value) == 'number'))
			{
				if (!delimiter) delimiter = ",";
				value = value.toString().split(delimiter);
			}
			
			this.mergeValues(value);

			this.doBehaviorEvent('onOptionStateChanged');
			if (visible) this.updateOptionsHtml(i);
			
			this.updateText();
			if (!this.anyNonBinaryStates)
			{
				this.previousValues = this.getValue();
			}
		}
		else
		{
			var index = this.optionByValue(value);
			this.selectItem(index);
			this.previousIndex = index;
		}
		
		// Assuming text was actually changed above, *now* roll back the stickyText setting. 
		// Included here for backward compatibility. The text parameter in the setValue() method should only change 
		// the text until some other text refresh method is called.
		if (text) this.stickyText = null;
	}
	
	// Given a value, return the index of the option that matches it.
	// Returns -1 if no option found.
	function dxFakeDropdown_optionByValue(value)
	{
		var options = this.options;
		var numOptions = options.length;
		
		for (var i = 0; i < numOptions; i++)
		{
			if (options[i].value == value) return i;
		}
		
		return -1;
	}
	
	// For multi-state dropdowns, set the state of the options 
	// according to the given list of values (and state information).
	// SCOPE: just update the options collection. Depend on the caller 
	// to do everything else. 
	function dxFakeDropdown_mergeValues(values)
	{
		// Build hash table of value-to-state lookups.
		var stateByValue = {};
		for (i = 0; i < values.length; i++)
		{
			if (this.anyNonBinaryStates)
				stateByValue[values[i].value] = values[i].state;
			else
				stateByValue[values[i]] = "1";
		}
		
		// Match values to options.
		for (i = 0; i < this.options.length; i++)
		{
			option = this.options[i];
			if (!option.behavior || !option.behavior.excludeValue)
			{
				stateCycle = option.stateCycle;
				stateValue = stateByValue[option.value];
				option.stateIndex = stateCycle.getStateByValue(stateValue).index;
			}
		}
	}
	
	// Whether a given option is "selected" or not. 
	// In a multi-state dropdown with non-binary states, this gets complicated. There are two ways to determine if an option is selected:
	//	1. The Explicit Way - an option is selected if its current "state" has a non-empty value. This means the option's value ends up in 
	//		the list returned by getComplexValue(). 
	//	2. The Conceptual Way - an option is considered "selected" by the user of the application, even if its value doesn't end up in the 
	//		list returned by getComplexValue(). 
	// Examples:  Consider the merge inherit functionality of the grid control, where each option can be checked explicitly, grayed-out-checked
	//	(indicating inheritance of the value from a parent), or X'ed out explicitly.  In this case:
	//		* Explicitly checked (bold) options are both explicitly and conceptually selected.
	//		* Grayed-out-checked options are NOT explicitly selected (their value doesn't appear in the getComplexValue() list), but they ARE 
	//			conceptually selected. This means, among other things, that the "All" box could still be checked if all options were grayed-out-checked. 
	//		* Explicitly X'ed options ARE explicitly selected (state.value is non-empty (-1), value included with -1 state in getComplexValue()) but 
	//			NOT conceptually selected (state.countsAsSelected = true; user considers them as "un-selected".)
	function dxFakeDropdown_optionSelected(index, bConceptualMode)
	{
		var option = this.options[index];
		if (this.multiState && bConceptualMode)
		{
			var state = option.stateCycle.getState(option.stateIndex);
			return state.countsAsSelected || (state.countsAsSelected == undefined && state.value != null);
		}
		else if (this.multiState)
			return option.stateCycle.getState(option.stateIndex).value != null;
		else
			return this.selectedIndex == index;
	}
	
	// Returns the "code" of the selected item.
	function dxFakeDropdown_getCode() {
		if (this.multiState) throw newFrameworkException("notSupported", "getCode() not supported for multi-state dropdowns.");
		
		if(this.selectedIndex != -1) {
			return(this.options[this.selectedIndex].code);
		}
		else {
			return("");
		}
	}

	// Returns the "text" of the selected item.
	function dxFakeDropdown_getText() {
		if (this.multiState) throw newFrameworkException("notSupported", "getText() not supported for multi-state dropdowns.");
		
		if(this.selectedIndex != -1) {
			return(this.options[this.selectedIndex].description);
		}
		else {
			return("");
		}
	}

	
	// Returns the value to be used when sorting a series of these controls.
	function dxFakeDropDown_getSortValue() {
		if (this.multiState) throw newFrameworkException("notSupported", "getSortValue() not supported for multi-state dropdowns.");
		
		var index = this.selectedIndex;
		if(index == -1 ) {
			return(null);
		}
		else {
			var option = this.options[this.selectedIndex];
			if(option.DisplayOrder) {
				return(option.DisplayOrder);
			}
			else {
				return(option.description);
			}
		}
	}
	
	
	// Sets the selected item to the specified code.
	function dxFakeDropdown_setCode(code) {
		if (this.multiState) throw newFrameworkException("notSupported", "setCode() not supported for multi-state dropdowns.");
		
		for(var i = 0; i < this.options.length; i++) {
			if(this.options[i].code == code) {
				this.selectItem(i);
				return;
			}
		}
		this.selectItem(-1);
	}
	
	// Returns an XML representation of the item.
	function dxFakeDropdown_toXml() {
		if(!this.multiState) {
			return(XMLEncodeElement(this.name, this.value, true));
		}
		else {
			// If this IS a multi-select list, then the output is different.
			var aXML = new Array();
			var name = (this.name ? this.name : this.id);
			var tagName = XMLEncodeName((name ? name : this.tagName));
			var includeStates = this.anyNonBinaryStates;
			var bStructured = (this["xml-format"] == "structured");
			if(bStructured) {
				aXML.push("<" + tagName + ">");
			}
			var valueTagName = (bStructured ? "Value" : tagName);
			var options = this.options;
			for(var i = 0; i < options.length; i++) {
				var option = options[i];
				if(this.optionSelected(i) && (!option.behavior || !option.behavior.excludeValue)) {
					if (includeStates)
					{
						aXML.push("<" + valueTagName + XMLEncodeAttribute("state", option.stateCycle.getState(option.stateIndex).value) + ">");
						aXML.push(XMLEncode(option.value));
						aXML.push("</" + valueTagName + ">");
					}
					else
					{
						aXML.push(XMLEncodeElement(valueTagName, option.value, true));
					}
				}
			}
			if(bStructured) {
				aXML.push("</" + tagName + ">");
			}
			return(aXML.join(""));
		}
	}

	// Enables or disables the control.
	function dxFakeDropdown_setEnabled(enabled) {
		this.disabled = !enabled;
		this.lastChild.disabled = !enabled;
		this.className = "dxFakeDropDown" + (enabled ? "" : " dxFakeDropDownDisabled");
	}

	// Raises the onchange event, if applicable.
	function dxFakeDropdown_raiseOnChanged() {
		var invokeSetDirty = false;
		if (this.multiState && this.anyNonBinaryStates) {
			invokeSetDirty = true;
			if (this.onchange) this.onchange();
		}
		else if(this.multiState) {
			if(this.previousValues != this.getValue()) {
				invokeSetDirty = true;
				if(this.onchange) {
					this.onchange();
				}
			}
		}
		else {
			if(this.selectedIndex != this.previousIndex) {
				invokeSetDirty = true;
				if(this.onchange) {
					if(this.onchange() == false) {
						this.selectItem(this.previousIndex);
						invokeSetDirty = false;
					}
				}
				this.previousIndex = this.selectedIndex;
			}
		}
		if (invokeSetDirty) {
			this.lastChild.isDirty = true;
			setDirty();
		}
		
		if (!this.anyNonBinaryStates) this.previousValues = this.getValue();
	}
	
	function dxFakeDropDown_getOptions() {
		var options = this.options;
		var aOptions = new Array();
		var option, newOption;
		for (var i = 0; i < options.length; i++)
		{
			option = options[i];
			newOption = {
				value: option.value,
				text: option.description,
				abbreviation: option.abbreviation,
				title: option.title,
				selected: (this.selectedIndex == i),
				image: option.image,
				behavior: option.behavior,
				stateCycle: option.stateCycle,
				stateIndex: option.stateIndex
			};
			aOptions.push(newOption);
		}
		return(aOptions);
	}
	
	// Parameter is optional. If not given, will use this.options.
	function dxFakeDropdown_needsBlankOption(options)
	{
		if (!options) options = this.options;
		var foundBlankOption = false;
		for (var i = 0; i < options.length; i++)
		{
			if (options[i].value == "" && options[i].description == "")
			{
				foundBlankOption = true;
				break;
			}
		}
		
		return !this.multiState && !foundBlankOption && this["blank-option-requested"] && !this["blank-option-denied"];
	}
	
	// Returns true if added a blank option.
	// Parameter is optional. If not given, will operate on this.options.
	function dxFakeDropdown_addBlankOptionIfMissing(options)
	{
		if (!options) options = this.options;
		var addedBlankOption = false;
		
		if (this.needsBlankOption(options))
		{
			options.unshift( { value: "", description: "", separator: false } );
			addedBlankOption = true;
		}
		
		return addedBlankOption;
	}
	
	function dxFakeDropDown_setOptions(aOptions, bPreserveSelection) {
		var value; if (bPreserveSelection) value = this.getComplexValue();
		
		// PREPROCESS
		// Build internal options data structure.
		var newOptions = this.normalizeOptions(aOptions);
		
		var newDefaultState;
		
		// If not preserving selection on multi-state dropdown, apply values from the incoming options here.
		if (this.multiState && !bPreserveSelection)
		{
			// For each of the new options...
			for (var i = 0; i < aOptions.length; i++)
			{
				if (this.anyNonBinaryStates)
				{
					if (aOptions[i].selected) {
						newDefaultState = newOptions[i].stateCycle.getDefaultCheckedState();
					}
					else {
						newDefaultState = newOptions[i].stateCycle.getDefaultUncheckedState();
					}
					if (newDefaultState != null) {
						newOptions[i].stateIndex = newDefaultState.index;
					}
				}
				else
					newOptions[i].stateIndex = newOptions[i].stateCycle.getStateByValue(aOptions[i].selected ? "1" : null).index;
			}
		}
		else if (!this.multiState)
		{
			this.addBlankOptionIfMissing(newOptions);
		}
		
		// FINALIZE options. 
		this.options = newOptions;
		
		// AFTERMATH
		// Set dropdown value(s) and if visible, refresh the visible dropdown menu.
		this.optimalWidth = undefined;
		if (this.multiState)
		{
			if (bPreserveSelection) this.mergeValues(value);
			this.doBehaviorEvent('onOptionStateChanged');
			if (this.popupVisible()) this.refreshPopup();
			this.updateText();
		}
		else
		{
			var newIndex = -1;
			if (bPreserveSelection) newIndex = this.optionByValue(value);
			if(bPreserveSelection && newIndex == -1) {  // If preserving selection and the value was removed from the list, change the selectedIndex, but do not change the value.
				this.selectedIndex = -1;
			}
			else {
				this.selectItem(newIndex);
			}
		}
	}
	
	// Returns array of normalized option records. Size of 
	// resulting array will be the same as the size of the original array.
	// No side-effects. Works with isolated input and returns isolated output.
	// NOTE: may add blank option to the top of the return value. 
	//	Caller should compare lengths of aOptions to return value. If length of 
	//	return value options is greater by one, a blank option has been added.
	function dxFakeDropDown_normalizeOptions(aOptions) {
		var options = new Array(aOptions.length)
		
		// PREPROCESS
		// Build internal options data structure.
		for (var i = 0; i < aOptions.length; i++)
		{
			options[i] = {};
			if (typeof(aOptions[i]) == 'string')
			{
				options[i].value = options[i].description = aOptions[i];
			}
			else
			{
				for (var j in aOptions[i])
				{
					switch(j)
					{
						case 'text':
							options[i].description = options[i].text = aOptions[i].text;
							break;
						case 'behavior':
							options[i].behavior = new dxFakeDropdown.Behaviors[aOptions[i].behavior](aOptions[i], this);
							break;
						case 'image':
							options[i].image = aOptions[i].image;
							options.anyImages = true;
							break;
						default:
							options[i][j] = aOptions[i][j];
					}
				}
			}
			if (this.multiState)
			{
				options[i].stateCycle = this.getStateCycleForOption(aOptions[i]);
				options[i].stateIndex = aOptions[i].stateIndex;
			}
		}
		
		return options;
	}
	
	function dxFakeDropdown_getStateCycleForOption(option)
	{
		var stateCycle = null;
		if (option.stateCycle) stateCycle = this.StateCycles[option.stateCycle];
		
		if (stateCycle)
			return stateCycle;
		else
		{
			for (var i in this.StateCycles) return this.StateCycles[i]; // Use first state cycle as default.
		}
		
		return null;
	}
	
	// Return true iff any behavior event handlers returned true, which 
	// means that one of the behaviors changed something. 
	function dxFakeDropdown_doBehaviorEvent(eventName, args)
	{
		if (!args) args = [];
		// Prepend common arguments onto args. 
		args.unshift(this);
		args.unshift(null); // Will be populated with reference to current option.
		
		var option, anyChanges = false;
		for (var i = 0; i < this.options.length; i++)
		{
			option = this.options[i];
			if (option.behavior && option.behavior[eventName])
			{
				args[0] = option;
				if (option.behavior[eventName].apply(option.behavior, args)) anyChanges = true;
			}
		}
		
		return anyChanges;
	}
	
	
	/***************************************************
	Misc Utilities
	****************************************************/
	
	// Array sorting handler for multi-state value records (useful in comparing collections of multi-state values.)
	// Pass this function to array.sort()
	function dxFakeDropdown_compareMultiStateValues(a, b)
	{
		if (a.value == undefined && b.value == undefined)
			return 0;
		if (a.value == undefined)
			return -1;
		else if (b.value == undefined)
			return 1;
		else if (a.value < b.value)
			return -1;
		else if (a.value > b.value)
			return 1;
		else if (a.state == undefined && b.state == undefined)
			return 0;
		else if (a.state == undefined)
			return -1;
		else if (b.state == undefined)
			return 1;
		else if (a.state < b.state)
			return -1;
		else if (a.state > b.state)
			return 1;
		else
			return 0;
	}
	
	// Compares two result sets from getComplexValue() (multi-state).
	// Returns true iff the two sets of values are equivalent.
	// SIDE-EFFECT WARNING: input arrays are sorted in-place.
	function dxFakeDropdown_multiStateValuesEqual(a, b)
	{
		if (a.length != b.length) return false;
		
		a.sort(dxFakeDropdown_compareMultiStateValues);
		b.sort(dxFakeDropdown_compareMultiStateValues);
		
		// Compare sorted arrays element by element.
		for (var i = 0; i < a.length; i++)
		{
			if (a[i].value != b[i].value || a[i].state != b[i].state) return false;
		}
		
		return true;
	}
	
	/***************************************************
	Anchor Behavior
	****************************************************/
	//Cancel any click on the anchor.
	function dxFakeDropdown_Anchor_onclick() {
		return(false);
	}

	//Highlight the control when it receives focus.
	function dxFakeDropdown_Anchor_onfocus() {
		if(!this.getControlElement().noFocusHighlight) {
			with(this.style) {
				backgroundColor = "highlight";
				color = "highlighttext";
			}
		}
	}

	//Unhighlight the control when it loses focus.
	function dxFakeDropdown_Anchor_onblur() {
		var ctl = this.getControlElement();
		if(!ctl.noFocusHighlight) {
			with(this.style) {
				backgroundColor = "window";
				color = "windowtext";
			}
		}
		ctl.updateText();
	}
	
	function dxFakeDropDown_Anchor_getControlElement() {
		return this.parentNode.parentNode;
	}
	
	function dxFakeDropDown_Anchor_onmouseenter() {
		this.getControlElement().getButton().style.backgroundColor = "#E2E9FF";
	}
	
	function dxFakeDropDown_Anchor_onmouseout() {
		this.getControlElement().getButton().style.backgroundColor = "";
	}
	
	/***************************************************
	dxFakeDropdown Behaviors
		
		Common Properties
			* name - typically the value of option/@behavior in the XML
			* excludeValue (bool) - whether to exclude the option's value from the list in getValue or getComplexValue
		
		Common Event Handlers
			* onOptionStateChanged(thisOption, ctl) - whenever the list of options changes or the selected values/states change.
			* onToggleItemState(thisOption, ctl, activeOption, oldStateIndex, newStateIndex) - (multi-state only) whenever a single option is clicked on, changing its state.
	****************************************************/
	
	dxFakeDropdown.Behaviors = {
		All: dxFakeDropdownAllBehavior,
		Exclusive: dxFakeDropdownExclusiveBehavior
	};
	
	// Associated with an "All" option that is checked 
	// iff all options are checked. 
	// For multi-state dropdowns only. 
	function dxFakeDropdownAllBehavior(thisOption, ctl)
	{
		this.name = "All";
		this.excludeValue = thisOption.excludeValue !== undefined ? (thisOption.excludeValue == true) : true;
	}
	
	dxFakeDropdownAllBehavior.prototype.onOptionStateChanged = function(thisOption, ctl)
	{
		// All option is selected iff all other options are selected.
		var option, exclusion, foundAnyNotSelected = false;
		var oldState = (thisOption.stateIndex) ? thisOption.stateCycle.getState(thisOption.stateIndex).value : '0';
		
		for (var i = 0; i < ctl.options.length; i++)
		{
			option = ctl.options[i];
			exclusion = (option.excludeFromBehavior ? option.excludeFromBehavior : '');
			if (option != thisOption && exclusion != this.name)
			{
				if (!ctl.optionSelected(i, true))
				{
					foundAnyNotSelected = true;
					break;
				}
			}
		}
		// Turn "All" option on or off. 
		var newState = (foundAnyNotSelected || ctl.options.length == '1') ? '0' : '1';
		var stateChanged = (newState != oldState);
		thisOption.stateIndex = thisOption.stateCycle.getStateByValue(newState).index;
		
		return stateChanged;
	};
	
	dxFakeDropdownAllBehavior.prototype.onToggleItemState = function(thisOption, ctl, activeOption, oldStateIndex, newStateIndex)
	{
		var anyChanges = false;
		
		if (activeOption == thisOption)
		{
			var option, stateIndex, exclusion, state, foundAppropriateState;
			var selectAll = (thisOption.stateCycle.getState(newStateIndex).value == 1);
			
			// If All option clicked, turn on or off all other options. 
			for (var i = 0; i < ctl.options.length; i++)
			{
				option = ctl.options[i];
				exclusion = (option.excludeFromBehavior ? option.excludeFromBehavior : '');
				if (option != thisOption && exclusion != this.name)
				{
					state = option.stateCycle.getState(option.stateIndex);
					
					do
					{
						stateIndex = state.index;
						foundAppropriateState = (	
							(selectAll && option.stateCycle.stateCountsAsSelected(state))
							|| (!selectAll && !option.stateCycle.stateCountsAsSelected(state))
						);
						state = option.stateCycle.getNextState(state.index);
					}
					while (!foundAppropriateState && state.index != option.stateIndex)
					
					stateIndex = foundAppropriateState ? stateIndex : 0;
					if (stateIndex != option.stateIndex) anyChanges = true;
					option.stateIndex = stateIndex;
				}
			}
		}
		
		return anyChanges;
	};
	
	// Associated with an "Exclusive" option that is checked 
	// Only this option is allowed to be checked. 
	// For multi-state dropdowns only. 
	function dxFakeDropdownExclusiveBehavior(thisOption, ctl)
	{
		this.name = "Exclusive";
		this.excludeValue = false;
	}
	
	dxFakeDropdownExclusiveBehavior.prototype.onOptionStateChanged = function(thisOption, ctl)
	{
		// Exclusive option is de-selected iff any other option is selected.
		var option, exclusion, foundAnySelected = false;
		var oldState = thisOption.stateCycle.getState(thisOption.stateIndex).value;
		
		for (var i = 0; i < ctl.options.length; i++)
		{
			option = ctl.options[i];
			exclusion = (option.excludeFromBehavior ? option.excludeFromBehavior : '');
			if (option != thisOption && exclusion != this.name)
			{
				if (ctl.optionSelected(i, true))
				{
					foundAnySelected = true;
					break;
				}
			}
		}
		// Turn "All" option on or off.
		var stateChanged = false;
		if(foundAnySelected) { 
			var newState = '0';
			stateChanged = (newState != oldState);
			thisOption.stateIndex = thisOption.stateCycle.getStateByValue(newState).index;
		}
		
		return stateChanged;
	};
	
	dxFakeDropdownExclusiveBehavior.prototype.onToggleItemState = function(thisOption, ctl, activeOption, oldStateIndex, newStateIndex)
	{
		var anyChanges = false;
		
		if (activeOption == thisOption)
		{
			var option, stateIndex, exclusion, state, foundAppropriateState;
			var deselectAll = (thisOption.stateCycle.getState(newStateIndex).value == 1);
			
			// If Exclusive option clicked, turn off all other options. 
			for (var i = 0; deselectAll && i < ctl.options.length; i++)
			{
				option = ctl.options[i];
				exclusion = (option.excludeFromBehavior ? option.excludeFromBehavior : '');
				if (option != thisOption && exclusion != this.name)
				{
					state = option.stateCycle.getState(option.stateIndex);
					
					do
					{
						stateIndex = state.index;
						foundAppropriateState = (	
							(!option.stateCycle.stateCountsAsSelected(state))
						);
						state = option.stateCycle.getNextState(state.index);
					}
					while (!foundAppropriateState && state.index != option.stateIndex)
					
					stateIndex = foundAppropriateState ? stateIndex : 0;
					if (stateIndex != option.stateIndex) anyChanges = true;
					option.stateIndex = stateIndex;
				}
			}
		}
		
		return anyChanges;
	};
	
	
	/***************************************************
	dxFakeDropdownStateCycle
	****************************************************/
	
	function dxFakeDropdownStateCycle(name, states)
	{
		this.name = name;
		this.anyNonBinaryStateValues = false;
		
		this._states = states ? states : [];
		this._statesByValue = {};	// References to state, indexed by state value. If two states share a value, only the first state is referenced.
		this._defaultCheckedState = null; // Refers to the first state that has a value (i.e. considered to be "checked")
		this._defaultUncheckedState = null; // Refers to the first state that has no value (i.e. considered to be "unchecked")
		
		var state;
		for (var i = 0; i < this._states.length; i++)
		{
			state = this._states[i];
			if (state.value)
			{
				if (!this._statesByValue[state.value]) this._statesByValue[state.value] = state;
				if (this._defaultCheckedState == null) this._defaultCheckedState = state;
				if (state.value != "1") this.anyNonBinaryStateValues = true;
			}
			else
			{
				if (this._defaultUncheckedState == null) this._defaultUncheckedState = state;
			}
		}
	}
	
	dxFakeDropdownStateCycle.prototype.getState = function(index)
	{
		return this._states[index];
	};
	
	// Given an index of a given state, return the index of the next state in the cycle. 
	dxFakeDropdownStateCycle.prototype.getNextState = function(index)
	{
		if (index < 0 || index >= this._states.length - 1)
			return this._states[0];
		else
			return this._states[index + 1];
	};
	
	// Given an index of a given state, return the index of the previous state in the cycle. 
	dxFakeDropdownStateCycle.prototype.getPrevState = function(index)
	{
		if (index > this._states.length - 1 || index <= 0)
			return this._states[this._states.length - 1];
		else
			return this._states[index - 1];
	};
	
	// Get state by the state value (do not confuse state value with dropdown option's value.)
	dxFakeDropdownStateCycle.prototype.getStateByValue = function(stateValue)
	{
		if (stateValue == null)
		{
			return this.getDefaultUncheckedState();
		}
		else
		{
			var state = this._statesByValue[stateValue];
			if (state)
				return state;
			else
				return this.getDefaultUncheckedState();
		}
	};
	
	dxFakeDropdownStateCycle.prototype.getDefaultCheckedState = function()
	{
		return this._defaultCheckedState;
	};
	
	dxFakeDropdownStateCycle.prototype.getDefaultUncheckedState = function()
	{
		return this._defaultUncheckedState;
	};
	
	dxFakeDropdownStateCycle.prototype.stateCountsAsSelected = function(state)
	{
		return state.countsAsSelected || (state.countsAsSelected == undefined && state.value != undefined);
	};

// dxFakeDropdownContent ----------------------------------------------------------------------------------------
/*
 * This class assigns behavior to the "list" portion of the dxFakeDropdown.
 */	
	
function dxFakeDropdownContent(ownerWindow) {
	document.ownerWindow = ownerWindow;
	var table = this.firstChild;
	var rows = table.rows;
	for(var i = 0; i < rows.length; i++) {
		var row = rows[i];
		row.onmouseover = dxFakeDropdownContentTableRow_onmouseover;
		row.onclick = dxFakeDropdownContentTableRow_onclick;
		row.ondblclick = dxFakeDropdownContentTableRow_onclick;
	}
	this.highlightRow = dxFakeDropdownContent_highlightRow;
	this.onselectstart = dxFakeDropdownContent_onselectstart;
	this.ensureVisible = dxFakeDropdownContent_ensureVisible;
}

// Make sure that the selected item is visible within the scroll area of a long list.
function dxFakeDropdownContent_ensureVisible(row) {
	if(row) {
		if((row.offsetTop + row.offsetHeight - this.scrollTop) >= this.clientHeight)
			this.scrollTop = row.offsetTop + row.offsetHeight - this.clientHeight;
		if(row.offsetTop < this.scrollTop)
			this.scrollTop = row.offsetTop;
	}
}

// Prevent drag-and-drop text selection.
function dxFakeDropdownContent_onselectstart() {
	return(false);
}

// Highlight a row as the mouse hovers over it.
function dxFakeDropdownContentTableRow_onmouseover() {
	var div = this.parentNode.parentNode.parentNode;
	var dropdown = document.ownerWindow.currentFakeDropdown;
	if (dropdown.multiState)
		dropdown.selectItem(this.sectionRowIndex);
	else
		div.highlightRow(this.sectionRowIndex);
}

// Handle the click event.
function dxFakeDropdownContentTableRow_onclick() {
	var event = this.document.parentWindow.event;
	var srcElement = event.srcElement;
	var dropdown = document.ownerWindow.currentFakeDropdown;
	if(dropdown.multiState) {
		dropdown.toggleItemState(this.sectionRowIndex);
	}
	else {
		if(dropdown) {
			dropdown.selectItem(this.sectionRowIndex);
			dropdown.hidePopup();
		}
	}
}

// Highlight the specified row, and remove highlighting from any other row.
function dxFakeDropdownContent_highlightRow(index) {
	var dropdown = document.ownerWindow.currentFakeDropdown;
	var rows = this.firstChild.rows;
	for(var i = 0; i < rows.length; i++) {
		var row = rows[i];
		
		if(row.sectionRowIndex == index) {
			row.style.backgroundColor = "highlight";
			row.style.color = "highlighttext";
			if(!row.title) row.title = row.innerText;
		}
		else {
			if (dropdown.multiState) {
				dropdown.updateOptionHtml(row.sectionRowIndex);
			}
			else {
				row.style.backgroundColor = "";
				row.style.color = "";
			}
		}
		
		for (var c = 0; c < row.cells.length; c++) {
			row.cells[c].style.backgroundColor = row.style.backgroundColor;
			row.cells[c].style.color = row.style.color;
		}
	}
}




// DX:NUMBER CONTROL ----------------------------------------------------------------------------------------------------------------------------------
// Depends on code in DebtX.Formatting.js

function dxNumber() {
	// Inherits dxControl functionality.
	dxControl.call(this);
	
	this.dxNumber_base_getValue = this.getValue;
	this.getValue = dxNumber_getValue;
	this.formatValue = dxNumber_formatValue;
	this.unFormatValue = dxNumber_unFormatValue;
	
}

function dxNumber_getValue() {
	var val = this.dxNumber_base_getValue();
	var nVal = parseFloat(val);
	if(!isNaN(nVal))
		return(parseFloat(val));
	else
		return(val);
}

function dxNumber_formatValue(value) {
	var multiplier = this.multiplier;
	if(!multiplier || isNaN(multiplier)) multiplier = 1;

	if(!isNaN(value) && value != "") {
		value = parseFloat(value) / multiplier;
	}

	return(dxFormatNumber(value, this.getAttribute("decimal-places")));
}

function dxNumber_unFormatValue(value) {
	var multiplier = this.multiplier;
	if(!multiplier) multiplier = 1;
	
	var result = dxUnFormat(value);

	if(!isNaN(result) && result != "") {
		result = parseFloat(result) * multiplier;
	}
	return(result);
}



// DX:CURRENCY CONTROL --------------------------------------------------------------------------------------------------------------------------------
// Depends on code in DebtX.Formatting.js

function dxCurrency() {
	// Inherits dxControl functionality.
	dxControl.call(this);

	this.hiddenCurrencyInput = dxCurrency_hiddenCurrencyInput;
	this.hiddenRawValueInput = dxCurrency_hiddenRawValueInput;
	
	if(!this.getAttribute("currency")) this.setAttribute("currency", "USD");

	this.dxCurrency_base_getValue = this.getValue;
	this.getValue = dxCurrency_getValue;

	this.setCurrency = dxCurrency_setCurrency;
	this.formatValue = dxCurrency_formatValue;
	this.unFormatValue = dxCurrency_unFormatValue;
	this.oncurrencychanged = dxCurrency_oncurrencychanged;
	this.multiplier = this.getAttribute("multiplier");
}

function dxCurrency_hiddenCurrencyInput() {
	if(this.tagName.toUpperCase() == "INPUT" && this.getAttribute("mode") != "simple") {
		return(this.nextSibling);
	}
	else {
		return(null);
	}
}

function dxCurrency_hiddenRawValueInput() {
	if(this.tagName.toUpperCase() == "INPUT" && this.getAttribute("mode") != "simple") {
		return(this.nextSibling.nextSibling.nextSibling.nextSibling);
	}
	else {
		return(null);
	}
}



function dxCurrency_getValue() {
	var val = this.dxCurrency_base_getValue();
	var nVal = parseFloat(val);
	if(!isNaN(nVal))
		return(parseFloat(val));
	else
		return(val);
}

function dxCurrency_setCurrency(currency) {
		var tmp = this.getValue();
		//Update the hidden input control containing the additional currency info.
		this.setAttribute("currency", currency);
		if(this.hiddenCurrencyInput()) {
			this.hiddenCurrencyInput().value = currency;
		}
		this.setValue(tmp);
}

function dxCurrency_formatValue(value) {
	var multiplier = this.multiplier;
	if(!multiplier) multiplier = 1;

	if(!isNaN(value) && value != "") {
		value = parseFloat(value) / multiplier;
	}

	return(dxFormatCurrency(this.getAttribute("currency"), value, this.getAttribute("decimal-places"), false));
}

function dxCurrency_unFormatValue(value) {
	var multiplier = this.multiplier;
	if(!multiplier || isNaN(multiplier) || multiplier == "") multiplier = 1;
	
	var result = dxUnFormatCurrency(this.getAttribute("currency"), value);

	if(!isNaN(result) && result != "") {
		result = parseFloat(result) * multiplier;
	}
	return(result);
}

function dxCurrency_oncurrencychanged(CurrencyCode, SourceFieldName) {
	if(!this.CurrencyIDSibling || this.CurrencyIDSibling == SourceFieldName) {
		if(CurrencyCode == "NAV" || CurrencyCode == "VAR") {
			this.setCurrency("");
		}
		else {
			this.setCurrency(CurrencyCode);
		}
	}
}

// Setup RaiseCurrencyChangedEvent method on the document object.  If a currency selector changes its value, 
// it should call this method in its onchange event, and all dependent dxCurrency controls will be updated.
document.RaiseCurrencyChangedEvent = function(CurrencyCode, SourceFieldName) {
	var controlArrays = [
		this.getElementsByTagName("INPUT"),
		this.getElementsByTagName("DIV"),
		this.getElementsByTagName("SPAN"),
		this.getElementsByTagName("IFRAME")
	];
	
	for(var i = 0; i < controlArrays.length; i++) {
		var controls = controlArrays[i];
		for(var c = 0; c < controls.length; c++) {
			var control = controls[c];
			
			if(control.oncurrencychanged) {
				try {
					if(typeof(control.oncurrencychanged) == "string") {
						control.oncurrencychanged = new Function(control.oncurrencychanged);
					}
					control.oncurrencychanged(CurrencyCode, SourceFieldName);
				}
				catch(e){}
			}
		}
	}
}
	


// DX:PERCENT CONTROL --------------------------------------------------------------------------------------------------------------------------------

function dxPercent() {
	// Inherits dxControl functionality.
	dxControl.call(this);

	this.dxPercent_base_getValue = this.getValue;
	this.getValue = dxPercent_getValue;
	this.formatValue = dxPercent_formatValue;
	this.unFormatValue = dxPercent_unFormatValue;
}

function dxPercent_getValue() {
	var val = this.dxPercent_base_getValue();
	var nVal = parseFloat(val);
	if(!isNaN(nVal))
		return(parseFloat(val));
	else
		return(val);
}

function dxPercent_formatValue(value) {
	var strNum = value.toString().replace(/\s|%|,/g, "");
	var convert = this.getAttribute("convert");
	var decimalPlaces = this.getAttribute("decimal-places");

	if(isNaN(parseFloat(strNum)) || value.toString().length == 0) {
		return(value);
	}
	if(isNaN(parseInt(decimalPlaces))) {
		decimalPlaces=2;
	}
	
	var num = value.toString().replace(/%|\,/g,'');
	
	if(!(convert && convert == "no")) {
		num = num * 100.00;
	}
	return(dxFormatNumber(num, decimalPlaces, ",", ".") + (this.getAttribute("show-symbol") == "no" ? "" : "%"));
}

function dxPercent_unFormatValue(value) {
	var strNum = dxUnFormat(value, ".");
	var convert = this.getAttribute("convert");

	if(isNaN(parseFloat(strNum)) || strNum == "") {
		return(this.getControlValue());
	}
	
	if(convert && convert == "no") {
		return(parseFloat(strNum));
	}
	else {
		return(parseFloat(strNum) / 100);		
	}
}


// DX:DATE CONTROL --------------------------------------------------------------------------------------------------------------------------------

function dxDate() {
	// Inherits dxControl functionality.
	dxControl.call(this);
	
	//Setup the control accessors.
	if(this.tagName.toUpperCase() == "INPUT") {
		this.getCalendarButton = dxDate_getCalendarButton;
		var calendarButton = this.getCalendarButton();
		calendarButton.getInput = dxDate_calendarButton_getInput;
		calendarButton.pickDate = dxDate_calendarButton_pickDate;
		calendarButton.onclick = dxDate_calendarButton_onclick;
	}

	this.formatValue = dxDate_formatValue;
	this.unFormatValue = dxDate_unFormatValue;
	this.setVisible = dxDate_setVisible;
	this.toXml = dxDate_toXml;
	
	this.useRealPopup = (this.getAttribute("use-real-popup") == "true");
}

function dxDate_getCalendarButton() {
	return(this.parentNode.parentNode.getElementsByTagName("A")[0]);
}

function dxDate_formatValue(value) {
	if((new Date(value)).toString() != 'NaN') {
		if(value.indexOf(":") != -1) {
			return(dxFormatDateTime(value));
		}
		else {
			return(dxFormatDate(value));
		}
	}
	else {
		return(value);
	}
}

function dxDate_unFormatValue(value) {
	return(value);
}

function dxDate_setVisible(boolFlag) {
	var table = findParentByTagName(this, 'table');
	table.style.visibility = (boolFlag ? 'visible' : 'hidden');
}

function dxDate_calendarButton_getInput() {
	return(this.parentNode.parentNode.getElementsByTagName("INPUT")[0]);
}

function dxDate_calendarButton_pickDate(date) {
	this.getInput().setValue(date);
}

function dxDate_calendarButton_onclick() {
	var textbox = this.getInput();
	if (!textbox.disabled && !textbox.readOnly) {
		date = textbox.value;
		var cal = new dxCalendar(date);
		var field = textbox;
		cal.useRealPopup = field.useRealPopup;
		var dateOnly = true;
		cal.onDateSelected = function (value) {
			var originalDate;
			var originalTime = "";
			if(dateOnly) {
				if(!isNaN(date)) {
					originalTime = dxFormatDateTime(date, "%i:%N %p");
				}
			}
			field.setValue(dxFormatDateTime(value, "%Y-%M-%D" + (!dateOnly ? "\xA0\xA0" + originalTime : "")));
		}
		cal.selectDate(textbox, -2, textbox.offsetHeight);
	}
	return(false);
}

function dxDate_pad(value, num) {
	var padding = ""
	for(var c = 1; c <= num; c++) 
		padding += "0";
		
	padding += value;
	return(padding.substr(padding.length -num));
}

function dxDate_toXml() {
	if(this.isStatic()) return("");
	var value = this.getValue()
	var d = new Date(Date.parse(value));
	if(!isNaN(d.valueOf())) {
		value = dxDate_pad(d.getFullYear(), 4)
				+ "-" 
				+ dxDate_pad((d.getMonth()+1), 2)
				+ "-"
				+ dxDate_pad(d.getDate(), 2)
				+ (d.getHours() + d.getMinutes() + d.getSeconds() != 0 ? 
					"T"
					+ dxDate_pad(d.getHours(), 2)
					+ ":"
					+ dxDate_pad(d.getMinutes(), 2)
					+ ":"
					+ dxDate_pad(d.getSeconds(), 2)
					: 
					""
				);
	}
	return(XMLEncodeElement(this.name, value, true));
}

// DX:TIME CONTROL --------------------------------------------------------------------------------------------------------------------------------
function dxTime() {
	// Inherits dxControl functionality.
	dxControl.call(this);

	this.formatValue = dxTime_formatValue;
	this.unFormatValue = dxTime_unFormatValue;
}

function dxTime_formatValue(value) {
	if (value.indexOf(':') <1)
	{
		value = getNumbersOnly(value);
	}
	return(dxFormatTime(value));
}


function getNumbersOnly(strString)
	 //  check for valid numeric strings	
	 {
	 var strValidChars = "0123456789";
	 var strChar;
	 var retString
	 var stop = false;
	 var i = 0;
	 var hour = '';

	 if (strString.length == 0) return '';

	var pm = strString.indexOf('p');
	if (pm < 1)
	{
		pm = strString.indexOf('P');
	}
	var am = strString.indexOf('a');
	if (am < 1)
	{
		am = strString.indexOf('A');
	}
	 var iCount = 0;
	 for (i = 0; i < strString.length+1 && stop == false && i < 5; i++)
			{
			strChar = strString.charAt(i);
			if (strValidChars.indexOf(strChar) == -1)
				 {
				 stop = true;
				 }
			iCount = i;
			}
	 retString = strString.substr(0,iCount);
	 
				 if (retString.length < 3)
				 {
						hour = retString;
						hr = parseInt(hour);
						if (hr > 12)
						{
							hr = hr - 12;
							hour=hr.toString();
							pm = 1;
						}
						retString = hour+':00';
					}
					else
					{
						hour = retString.substr(0,retString.length-2);
						hr = parseInt(hour);
						if (hr > 12)
						{
							hr = hr - 12;
							hour=hr.toString();
							pm = 1;
						}
						retString = hour+':'+retString.substr(retString.length-2,2);
					}
					if (pm > 0)
						retString = retString + ' PM';
					else if (am > 0)
						retString = retString + ' AM';
					else
					{
						if ((hr > 6) && (hr < 12))
						{
							retString = retString + ' AM';
						}
						else
						{
							retString = retString + ' PM';
						} 
					}
					return(retString);
	 }

function dxTime_unFormatValue(value) {
	return(value);
}



// DX:PHONE CONTROL -------------------------------------------------------------------------------------------------------------------------
// Depends on code in DebtX.Formatting.js

function dxPhone() {
	// Inherits dxControl functionality.
	dxControl.call(this);

	this.formatValue = dxPhone_formatValue;
}

function dxPhone_formatValue(value) {
	return(dxFormatPhoneNumber('USCA', value));
}


// DX:SSN CONTROL -------------------------------------------------------------------------------------------------------------------------
// Depends on code in DebtX.Formatting.js

function dxSSN() {
	// Inherits dxControl functionality.
	dxControl.call(this);

	this.formatValue = dxSSN_formatValue;
}

function dxSSN_formatValue(value) {
	return(dxFormatSSN(value));
}


// DX:TEXT-AREA CONTROL ----------------------------------------------------------------------------------------------------------------------------------

function dxTextArea() {
	dxControl.call(this);
	switch(this.tagName) {
		case "TEXTAREA":
			break;
			
		case "DIV":
			this.generateFormInput = dxTextArea_generateFormInput;
			
			if(this.value && this.childNodes.length == 0) {
				this.setValue(this.value);
			}
			break;			
	}
	this.isStatic = dxControl_isStatic;
	this.toXml = dxTextArea_toXml;
	
	if(this.getAttribute("maxlength") != null) {
		this.updateCounter = dxTextArea_updateCounter;
		var thisElement = this;
		setInterval(
			function() {
				thisElement.updateCounter();
			},
			100
		);
	}
}

function dxTextArea_updateCounter() {
	dxTextCounter(this, findParentByTagName(this, "TR").nextSibling.nextSibling.getElementsByTagName("span")[0], this.getAttribute("maxlength"));
}

function dxTextArea_generateFormInput(dest, prefix) {
	var inp = document.createElement("input");
	inp.setAttribute("type", "hidden");
	inp.setAttribute("name", (prefix ? prefix : "") + (this.name ? this.name : this.id));
	inp.value = this.getValue();
	dest.insertAdjacentElement("BeforeEnd", inp);
}

function dxTextArea_toXml() {
	if(this.isStatic()) return("");
	return(XMLEncodeElement(this.name, this.getValue(), true));
}


// DX:RADIO CONTROL ----------------------------------------------------------------------------------------------------------------------------------
function dxRadio () {
	dxControl.call(this);
	this.toXml = dxRadio_toXml;
}

function dxRadio_toXml () {
	if(this.checked) {
		return(XMLEncodeElement(this.name, this.value, true));
	}
	else {
		return("");
	}
}

// DX:RADIO-GROUP CONTROL ----------------------------------------------------------------------------------------------------------------------------------
function dxRadioGroup () {
	this.getValue = dxRadioGroup_getValue;
	this.setValue = dxRadioGroup_setValue;
	this.setEnabled = dxRadioGroup_setEnabled;
	this.isStatic = dxControl_isStatic;
	this.toXml = dxRadioGroup_toXml;

	var options = this.parentNode.getElementsByTagName("input");
	for(var i = 0; i < options.length; i++) {
		var opt = options[i];
		if(opt.type == "radio") {
			if(opt.onclick) opt.dxRadioGroup_Item_OriginalOnClick = opt.onclick;
			opt.onclick = dxRadioGroup_Item_onclick;
		}
	}
}

function dxRadioGroup_Item_onclick() {
	var input = findParentByTagName(this, 'DIV').getElementsByTagName('INPUT')[0];
	input.value = this.value;
	if(input.onchange) input.onchange();
	if(this.dxRadioGroup_Item_OriginalOnClick) this.dxRadioGroup_Item_OriginalOnClick();
}

function dxRadioGroup_getValue() {
	var options = this.parentNode.getElementsByTagName("input");
	for(var i = 0; i < options.length; i++) {
		var opt = options[i];
		if(opt.type == "radio") {
			if(opt.checked) {
				return(opt.value);
			}
		}
	}
	return(null);
}

function dxRadioGroup_setValue(value) {
	var options = this.parentNode.getElementsByTagName("input");
	for(var i = 0; i < options.length; i++) {
		var opt = options[i];
		if(opt.type == "radio" && opt.value.toString() == value.toString()) {
			if(!opt.checked) {
				opt.click();
				return;
			}
		}
	}
}

function dxRadioGroup_setEnabled(enabled) {
	var options = this.parentNode.getElementsByTagName("input");
	for(var i = 0; i < options.length; i++) {
		var opt = options[i];
		if(opt.type == "radio") {
			opt.disabled = !enabled;
		}
	}
}

function dxRadioGroup_toXml() {
	if(this.isStatic()) return("");
	return(XMLEncodeElement(this.name, this.getValue(), true));
}


// DX:CHECKBOX CONTROL ----------------------------------------------------------------------------------------------------------------------------------

function dxCheckbox() {
	dxControl.call(this);
	this.toXml = dxCheckbox_toXml;
	if(this.onclick && !this.dxCheckbox_base_onclick) {
		this.dxCheckbox_base_onclick = this.onclick;
	}
	this.onclick = dxCheckbox_onclick;
}

function dxCheckbox_onclick() {
	if(this.dxCheckbox_base_onclick) {
		this.dxCheckbox_base_onclick.apply(this, arguments);
	}
	if(this.dxOnChange) {
		this.dxOnChange(!this.checked);
	}
}

function dxCheckbox_toXml() {
	if(this.isStatic()) return("");
	if(this.checked) {
		return(XMLEncodeElement(this.name, this.getValue(), true));
	}
	else {
		return("<" + this.name + "/>");
	}
}

// DX:FRAME CONTROL ----------------------------------------------------------------------------------------------------------------------------------
function dxFrame() {
	this.loadContent = dxFrame_loadContent;
	this.toXml = dxFrame_toXml;
	if(this.load == "always") {
		this.contentLoaded = true;
	}
}

function dxFrame_loadContent() {
	this.src = this.contentUrl;
	this.contentLoaded = true;
}

function dxFrame_toXml() {
	if(!this.noxml) {
		var aXML = new Array();
		// Create the Frame element's opening tag, supplying the name attribute.
		aXML.push("<Frame " + XMLEncodeAttribute("name", this.name) + ">");
		
		// Recursively search for elements within the content document that can be converted to XML.
		aXML.push(dxForm_recurseToXML(this.contentWindow.document.body));
		
		// Create the form element's closing tag.
		aXML.push("</Frame>");
		
		// Merge the array into a single string.
		return(aXML.join(""));
	}
	else {
		return("");
	}
}

// DX:FILE CONTROL -----------------------------------------------------------------------------------------------------------------------------------

var dxFileUploadIDCounter = 0;

function dxFile() {
	this.extractFileName = dxFile_extractFileName;
	this.getDisplayValue = dxFile_getDisplayValue;
	this.getUploadID = dxFile_getUploadID;
	this.getValue = dxFile_getValue;
	this.setDisplayValue = dxFile_setDisplayValue;
	this.setBrowseMode = dxFile_setBrowseMode;
	this.toXml = dxFile_toXml;
	
	if(is_ie && !is_ie8up) {
		this.onkeypress = dxFile_onkeypress;
	}
}

function dxFile_getUploadID() {
	if(!this.uploadID) {
		dxFileUploadIDCounter ++;
		this.uploadID = "u" + dxFileUploadIDCounter + (new Date().valueOf().toString(36));
	}
	return this.uploadID;
}

function dxFile_toXml() {
	if(this.value.trim().length != 0) {
		xml = [];
		xml.push("<" + XMLEncodeName(this.name));
	
		xml.push(XMLEncodeAttribute("UploadID", this.getUploadID()));
		xml.push(XMLEncodeAttribute("ClientPath", this.value));
		xml.push(">" + XMLEncode(this.extractFileName(this.value)) + "</" + XMLEncodeName(this.name) + ">");

		return xml.join("");
	}
}

function dxFile_extractFileName(path) {
	if(path) {
		var tmpPath = path.replace(/[\\\/\:]/g, "/");
		var index = tmpPath.lastIndexOf("/");
		if(index != -1) {
			return tmpPath.substring(index + 1);
		}
		else {
			return path;
		}
	}
}

function dxFile_getValue() {
	return this.value;
}

function dxFile_getDisplayValue() {
	return this.extractFileName(this.getValue());
}

function dxFile_setDisplayValue(value) {
	// Can't actually set the value of the file input for security reasons.  But this will set the display value.
	var span = this.parentNode.parentNode;
	var span2 = span.nextSibling;
	var table = span2.getElementsByTagName("table")[0];
	var cell = table.tBodies[0].rows[0].cells[0];
	cell.innerText = value;
	cell.setAttribute("title", value);
	this.setBrowseMode(false);
}

function dxFile_setBrowseMode(browseMode) {
	var span = this.parentNode.parentNode;
	var span2 = span.nextSibling;
	
	if(browseMode) {
		span2.style.display = "none";
		span.style.display = "inline";
	}
	else {
		span.style.display = "none";
		span2.style.display = "inline";
	}
}

function dxFile_ReplaceButton_onclick() {
	var span2 = findParentByTagName(this, "span");
	var span = span2.previousSibling;
	span2.style.display = "none";
	span.style.display = "inline";
}

// Only used in IE7 or lower.  In IE8 and up, this behavior is built-in.  Also built-in to other browsers.
function dxFile_onkeypress() {
	return false;
}


//dx:simple-data-table -------------------------------------------------------------------------------------------------------------------------

function dxSimpleDataTable() {
	this.toXml = dxSimpleDataTable_toXml;
	this.addRow = dxSimpleDataTable_addRow;
	this.deleteRow = dxSimpleDataTable_deleteRow;
	this.getCurrentRow = dxSimpleDataTable_getCurrentRow;
	this.getCurrentRowFields = dxSimpleDataTable_getCurrentRowFields;
	this.getRowFields = dxSimpleDataTable_getRowFields;
	this.setRowEnabled = dxSimpleDataTable_setRowEnabled;
}

function dxSimpleDataTable_getCurrentRow(element) {
	var tr = findParentByTagName(element, "tr");
	return tr;
}

// Gets all the fields in the same row as the specified element.
function dxSimpleDataTable_getCurrentRowFields(element) {
	return this.getRowFields(this.getCurrentRow(element));
}

// Gets all the inputs, selects, and textareas in the specified row.
// Returns an array that is also indexed by field name.
function dxSimpleDataTable_getRowFields(tr) {
	var fields = [];
	var tags = ["input", "select", "textarea"];
	
	for(var t = 0; t < tags.length; t++) {
		var elements = tr.getElementsByTagName(tags[t]);
		for(var i = 0; i < elements.length; i++) {
			var element = elements[i];
			fields[element.name] = element;
			fields.push(element);
		}
	}
	return fields;
}

// Enables or disables a row and all the inputs within.
function dxSimpleDataTable_setRowEnabled(tr, enabled) {
	tr.disabed = !enabled;
	var fields = this.getRowFields(tr);
	for(var i = 0; i < fields.length; i++) {
		var fld = fields[i];
		if(fld.setEnabled) 
			fld.setEnabled(enabled);
		else if(fld.setDisabled)
			fld.setDisabled(!enabled);
		else
			fld.disabled = !enabled;
	}
}


function dxSimpleDataTable_toXml(useAttributes) {
	if(this.getAttribute("no-xml") == "true") {
		return "";
	}
	
	if(useAttributes == undefined) {
		useAttributes = (this.getAttribute("save-fields-as") == "attributes");
	}
	
	var xml = new Array();	
	var elementName = XMLEncodeName(this.id);
	var rowElementName = this.getAttribute("data-element-name");
	if(!rowElementName) rowElementName = "Row";
	rowElementName = XMLEncodeName(rowElementName);
	xml.push("<" + elementName + ">");
	
	var row = this.tBodies[0].rows[0];
	while(row) {
		if(row.nodeType == 1) {
			xml.push("<" + rowElementName + ">");
			
			xml.push(dxForm_recurseToXML(row));
					
			xml.push("</" + rowElementName + ">");
		}
		row = row.nextSibling;
	}
	xml.push("</" + elementName + ">");
	
	return xml.join("");
}

function dxSimpleDataTable_addRow() {
	var newRow = this.tBodies[1].rows[0].cloneNode(true);
	this.tBodies[0].appendChild(newRow);
	setupJSClasses(newRow, true);
	if(this.onNewRowAdded) this.onNewRowAdded(newRow);
}

function dxSimpleDataTable_deleteRow(row) {
	row.parentNode.removeChild(row);
	if(this.onRowDeleted) this.onRowDeleted(row);
}


/*********************************************************************************************************************************
dxCalendar
**********************************************************************************************************************************
Popup calendar. IE Only for now, but could easily be made multi-browser by using an iframe instead of createPopup in other 
browsers.
**********************************************************************************************************************************/
function dxCalendar(currentDate) {
	if(!currentDate) 
		this.currentDate = new Date();
	else {
		var dateValue = Date.parse(currentDate);
		if(isNaN(dateValue)) 
			this.currentDate = new Date();
		else
			this.currentDate = new Date(dateValue);
	}
		
	this.monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

	this.toString = function (year, month) {
		var a = [];
		
		if(!year) year = this.currentDate.getFullYear();
		if(!month) month = this.currentDate.getMonth() + 1;
		var numWeeks = this.getNumWeeksInMonth(year, month);
		var firstDay = this.getFirstDayOfMonth(year, month);
		var today = new Date();
		return '<html><head>' + this.renderHeaderContent() + '</head><body style="margin: 0px; border: 1px solid black;" scroll="no" onselectstart="return false;" ondragstart="return false;">' + this.renderBodyContent(year, month) + '	</body>	</html>';}
	
	this.renderHeaderContent = function (year, month) {
		return '<style type="text/css"> select { font: 8pt tahoma; font-weight: bold; width: 100%;} tr.week { height: 17px; }' +
					'tr.week a { width: 100%; height: 100%; padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px; color: blue;} ' +
				'	tr.week a:hover { background-color: #D5DCFF; color: black;} '+
				'	td { font: 8pt tahoma; text-align: right; padding: none;} '+
				'	td.today a { border: 1px solid darkred; }  '+
				'	td.selected a { background-color: darkblue; color: white; }  '+
				'	tr.Month td { font-weight: bold; text-align: center; padding: 2px; }'  +
				'	tr.Header td { border-bottom: 1px solid black; text-align: center; padding-top: 5px;}  '+
				'	td.Weekend { background-color: #dddddd; }  '+
				'	td.nextMonth a, td.lastMonth a { color: #909090; }  '+
				'	input { font: 8pt tahoma; border: 1px raised; height: 25px; } </style> ';
	}
	
	this.renderBodyContent = function(year, month) {
		var a = [];
		
		if(!year) year = this.currentDate.getFullYear();
		if(!month) month = this.currentDate.getMonth() + 1;
		var numWeeks = this.getNumWeeksInMonth(year, month);
		var firstDay = this.getFirstDayOfMonth(year, month);
		var today = new Date();
		a.push('<form name="frmCalendar"> <table cellspacing="0" cellpadding="0" width="100%" height="100%"> <tr class="Month">	<td colspan="4" align="center"> <select name="Month" onchange="document.owner.refreshPopup(parseInt(frmCalendar.Year.value), parseInt(frmCalendar.Month.value) + 1);">');
						for(var i = 0; i < 12; i++) {
							a.push('<option value="' + i + '"' + (i == month-1 ? ' selected': '') + '>' + this.monthNames[i] + '</option>'); 
						}				
						a.push('</select> </td> <td colspan="3" align="center"> <select name="Year" onchange="document.owner.refreshPopup(parseInt(frmCalendar.Year.value), parseInt(frmCalendar.Month.value) + 1);">');
						for(var i = year - 20; i <= year + 40; i++) {
							a.push('<option value="' + i + '"' + (i == year ? ' selected' : '') + '>' + i + '</option>');
						}	
						a.push('</select></td></tr><tr class="header"><td>S</td><td>M</td><td>T</td><td>W</td><td>T</td><td>F</td><td>S</td></tr>');
		var day = -firstDay + 1;

		for(var week = 0; week < numWeeks; week++) {
			a.push('<tr class="Week">');
			for(var i = 0; i < 7; i++) { 
				var date = new Date(year, month - 1, day);
				var className = "";
				if(i == 0 || i == 6) className += "weekend";
				if(date.getMonth() < month - 1)	className += " lastMonth";
				if(date.getMonth() > month - 1)	className += " nextMonth";
				if(date.getMonth() > month - 1)	className += " nextMonth";
				if(new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), this.currentDate.getDate()).toString() == date.toString()) className += " selected";

				if(new Date(today.getFullYear(), today.getMonth(), today.getDate()).toString() == date.toString()) className += " today";
				
				a.push('<td' + (className != '' ? ' class="' + className + '"' : '') + '><a href="#" onclick="document.owner.popupWindow.hide(); if(document.owner.onDateSelected) document.owner.onDateSelected(new Date(' + date.getFullYear() + ',' + date.getMonth() + ',' + date.getDate() + ')); return false;">' + date.getDate() + '</a></td>');
				day ++;
			}
			a.push('</tr>');
		}
		a.push('<tr height="100%"><td colspan="7" align="middle" valign="bottom"><input type="button" value="Today" style="width: 100%;" onclick="document.owner.popupWindow.hide(); if(document.owner.onDateSelected) document.owner.onDateSelected(new Date(' + today.getFullYear() + ',' + today.getMonth() + ',' + today.getDate() + '));"></input></td></tr></table> </form>');
		return a.join("");
	}
	
	this.getNumDaysInMonth = function(year, month) {
		return new Date(year, month, 0).getDate();
	}
	
	this.getFirstDayOfMonth = function (year, month) {
		return new Date(year, month-1, 1).getDay();
	}
	
	this.getNumWeeksInMonth = function(year, month) {
		var numDaysInMonth = this.getNumDaysInMonth(year, month);
		var firstDayOfMonth = this.getFirstDayOfMonth(year, month);
		return Math.ceil((numDaysInMonth + firstDayOfMonth) / 7);
	}
	
	this.selectDate = function (owner, left, top) {
		if(is_ie7up || (is_ie6 && this.useRealPopup)) {
			this.popupWindow = window.createPopup();
			this.popupWindow.document.write(this.toString());
		}
		else {
			this.popupWindow = fake_createPopup();
			this.popupWindow.document.open();
			this.popupWindow.document.write(this.toString());
			this.popupWindow.document.close();
			this.popupWindow.show = fake_popup_show;
			this.popupWindow.hide = fake_popup_hide;
		}
		this.popupWindow.document.owner = this;
		if(is_ie6 && !this.useRealPopup) {
			top += 8;
		}
		this.popupWindow.show(left, top, 175, 175, owner);
		var cal = this;
		// Must clean up the object references once the calendar has closed.
		this.popupTimer = setInterval(
			function () { 
				if(!cal.popupWindow || !cal.popupWindow.isOpen) {
					clearInterval(cal.popupTimer);
					cal.popupWindow.document.owner = null;
					cal.popupWindow = null;
					if(this.onCalendarClosed) this.onCalendarClosed();
					this.onDateSelected = null;
				}
			},
			1
		);
	}
	
	this.refreshPopup = function (Year, Month) {
		this.popupWindow.document.body.innerHTML = this.renderBodyContent(Year, Month);
	}
	
	this.onDateSelected = function() {};
}

function fake_createPopup() {
	var iframe = document.createElement("iframe");
	iframe.style.position = "absolute";
	iframe.style.display = "none";
	iframe.style.left = 0;
	iframe.style.top = 0;
	iframe.style.backgroundColor = "white";
	iframe.style.border = "none";
	iframe.style.zIndex = 100;
	iframe.frameBorder = 0;
	iframe.scrolling = "no";
	iframe.src = "javascript:''";
	document.body.appendChild(iframe);
	var contentWindow = iframe.contentWindow;
	return contentWindow;	
}

function fake_popup_show(left, top, width, height, owner) {
	var style = this.frameElement.style;
	style.left = (getX(owner) + left) + "px";
	style.top = (getY(owner) + top) + "px";
	style.display = "block";
	style.width = width + "px";
	style.height = height + "px";
	this.isOpen = true;
	var pDoc = this.parent.document;
	pDoc.currentPopup = this;
	if(pDoc.onmousedown != doc_onmousedown) {
		this.old_doc_onmousedown = pDoc.onmousedown;
		pDoc.onmousedown = doc_onmousedown;
	}
}

function fake_popup_hide() {
	this.frameElement.style.display = "none";
	this.isOpen = false;
	if(this.parent.document.currentPopup) {
		this.parent.document.currentPopup = null;
		this.parent.document.onmousedown = this.old_doc_onmousedown;
	}
}

function doc_onmousedown() {
	if(this.currentPopup) {
		this.currentPopup.hide();
		this.currentPopup = null;
	}
}

// MISCELLANEOUS CONTROLS --------------------------------------------------------------------------------------------------------------------------------

var errorDisplayStyle;		//This variable determines which style of error display (popup boxes, or div's) to use
var popupTimer = null;
var errorSubstitutions = new Object();
var popups = new Object();

function getPopup(fieldName) {
	var popup;
	
	if(typeof(popups[fieldName]) == 'undefined') {
		popup = DxCreatePopup("msg" + fieldName, "HelpBox");

		//Set the onMouseOut and onMouseOver events.
		popup.onmouseout = function() { popupTimer = setTimeout("hideBoxes();", 4000); };
		popup.onmouseover = function() { clearTimeout(popupTimer);};
		popup.onclick = function () { this.style.visibility = xbHide; };
		popups[fieldName] = popup;
	}
	else
		popup = popups[fieldName];

	return(popup);
}

function DxCreatePopup(fieldName, className) {
	if(browserName == "IE") {
		var sHTML = '<div name="' + fieldName + '" id="' + fieldName + '" class="' + className + '" style="position: absolute; visibility: hidden"></div>';
		document.body.insertAdjacentHTML("BeforeEnd", sHTML);
		return(xbObj(fieldName));
	}
	else {
		var popup = new Layer(150);
		popup.id = "msg" + fieldName;
		popup.name = "msg" + fieldName;
		return(popup);
	}
}

function setPopupText(popup, text) {
	if(document.layers) {
		popup.document.open("text/html", "replace");
		popup.document.write("<html><body bgcolor='#ffffe1' marginleft='2' margintop='2' marginbottom='2' marginright='2'><a href='javascript://' style='text-decoration: none; color: black;' onclick='hideBoxes();'><font size='2'>" + text + "</font></a></body></html>");
		popup.document.close();
	}
	else {
		if(popup.innerHTML != text) popup.innerHTML = text;
	}
}



function showBox(fieldName, text, e, mode) {
	// Clear any pre-existing timer.
	clearTimeout(popupTimer);
	
	// Get the initialized popup.
	var popup = getPopup(fieldName);
	
	// If not displaying custom text, get the mouse coordinates.  This is where the popup will be displayed.
	if(mode == "help") {
		if(browserName == "IE") {
			popup.style.left = event.x; 
			popup.style.top = event.y + document.body.scrollTop;
		}
		else {
			popup.left = e.pageX;
			popup.top = e.pageY;
		}
	}
	else { // Else, text will be displayed next to field.
		
		if(browserName == "IE") {
			var pos = GetElementPosition("pos" + fieldName);
			if(pos) {
				popup.style.left = pos.x + 22;
				popup.style.top = pos.y - document.body.scrollTop - 2;
			}
			else {
				popup.style.left = 0;
				popup.style.top = 100;
			}
		}
		else {
			var pos = GetElementPosition("aErr" + fieldName);
			if(pos) {
				popup.left = pos.x + 22;
				popup.top = pos.y;
			}
			else {
				popup.left = 0;
				popup.top = 100;
			}
		}
	}

	// Set text to be displayed in popup.
	setPopupText(popup, text);
	
	// Display the popup.
	if(browserName == "IE") {
		popup.style.visibility = xbShow;
	}
	else {
		popup.visibility = xbShow;
	}
}

function showHelpBox(fieldName, text, e) {
	// Hide all other popup boxes.
	hideBoxes();

	showBox(fieldName, text, e, "help");

	// Activate the timer.
	popupTimer = setTimeout("hideBoxes()", 4000);	}

function showErrorBox(fieldName, errText) {
	if(typeof(errorSubstitutions[fieldName]) != "undefined") {
		fieldName = errorSubstitutions[fieldName];
	}
	showBox(fieldName, errText, null, "error");
	if(document.layers) {
		var a = document.anchors["aErr" + fieldName]
		if(a) a.onclick = function() { hideBoxes(); showErrorBox(fieldName, errText); }
		var img = document.images["imgErr" + fieldName];
		if(img) img.src = imgRoot + "x.gif";
	}
	else {
		var row = xbObj("row" + fieldName);
		var img = xbObj("imgErr" + fieldName);
		if(img) {
			img.onclick = function() { hideBoxes(); showErrorBox(fieldName, errText); };
			img.src = imgRoot + "x.gif";
		}
		if(row) paintErrorArea(fieldName);
	}
}

function paintErrorArea(fieldName) {
	var row = xbObj("row" + fieldName);
	if (row) row.className = "errField";
}

function hideErrorBox(fieldName) {
	if(typeof(errorSubstitutions[fieldName]) != "undefined") {
		fieldName = errorSubstitutions[fieldName];
	}
	if(popups[fieldName]) {
		var msg = popups[fieldName];

		msg.style.visibility = xbHide;
	
		var img;
		if(document.layers) {
			document.anchors["aErr" + fieldName].onclick = function() { }
			var img = document.images["imgErr" + fieldName];
			if(img) img.src = imgRoot + "spacer.gif";
		}
		else {
			var img = xbObj("imgErr" + fieldName);
			if(img) {
				img.src = imgRoot + "spacer.gif";
				img.onclick = function() { };
			}
			var row = xbObj("row" + fieldName);
			if(row) row.className = "Field";
		}		
	}
}


function hideBoxes(bHideErrors) {
	for(var fieldName in popups) {
		if (bHideErrors) {
			hideErrorBox(fieldName);
		}
		else {
			var popup = popups[fieldName];
			if(browserName == "IE") {
				if(popup.style.visibility != xbHide) popup.style.visibility = xbHide;
			}
			else {
				if(popup.visibility != xbHide) popup.visibility = xbHide;
			}
		}
	}
}



var useIEPopup = false;//(is_ie5_5up && is_win);

//dx:menu-bar ------------------------------------------------------------------------------------------

var menuBars = new Object();

// If using IE popups, make sure they're closed before unloading the page.
if (useIEPopup) {
	bodyOnUnload.push(
		function() {
			for (var i in menuBars) {
				hideMenu(menuBars[i]);
			}
		}
	);
}

function setupMenuBar(menuBarID, settings) {
	var menuBar = new Object();
	menuBar.menuBarID = menuBarID;
	
	if (useIEPopup) menuBar.popup = false;
	
	for (var i in settings) {
		menuBar[i] = settings[i];
	}
	
	menuBars[menuBarID] = menuBar;
	
	// Either the main document object, or the IE popup document object (IE 5.5+).
	menuBar.menuDoc = document;
	
	// Horizontal and vertical offsets (determining the position of the drop menu, when it 
	// appears).
	menuBar.hOffset = settings.hOffset;
	menuBar.vOffset = settings.vOffset;
	
	// Give menu DIVs their own references to the menuBars data structure. This is necessary 
	// because in IE, when popup appears, the menu div will live in there and will need 
	// a reference to the opening page's data structure.
	for (var i in menuBar.menus) {
		var menu = getObjectById('menu_' + menuBar.menus[i]);
		menu.menuBars = menuBars;
		menu.menuBar = menuBar;
		menu.overMenuHeader = false;
		menu.overMenu = false;
	}
	
	menuBar.menuItemClick = dxMenuBar_menuItemClick;
	menuBar.menuItemKeyDown = dxMenuBar_menuItemKeyDown;
	menuBar.menuItemFocus = dxMenuBar_menuItemFocus;
	menuBar.menuItemBlur = dxMenuBar_menuItemBlur;
	menuBar.menuItemMouseOver = dxMenuBar_menuItemMouseOver;
	menuBar.menuItemMouseOut = dxMenuBar_menuItemMouseOut;
	menuBar.initClose = dxMenuBar_initClose;
	menuBar.stopClose = dxMenuBar_stopClose;
	
	if (useIEPopup) {
		// Create IE popup object and initialize.
		
		menuBar.popup = window.createPopup();
		var popDoc = menuBar.popup.document;
		popDoc.write(stubHTML_preInclude);
		
		// Add stylesheets from the current document.
		for (var i in document.styleSheets) {
			if (document.styleSheets[i].href) {
				popDoc.write(
					'<link rel="stylesheet" type="text/css" href="'
					+ escape(document.styleSheets[i].href) + '">');
			} else {
				popDoc.write(
					'<style type="text/css">\n' + document.styleSheets[i].cssText
					+ '\n</style>');
			}
		}
		
		popDoc.write(stubHTML_preContent);
		popDoc.write('<div id="MenuContainer" style="margin: 0px; padding: 0px; border: 0px;"></div>');
		popDoc.write(stubHTML_postContent);
		popDoc.close();
		
		// Link references.
		menuBar.menuDoc = popDoc;
	}
}

function dxMenuBar_menuItemClick(itemID) {
	var item = this.items[itemID];
	
	if (useIEPopup) displayMenu(this.menuBarID);	// hide IE popup
	
	if (item.onclick()) {
		window.location.href = item.href;
	}
}

function dxMenuBar_switchSubMenuFocus(itemClicked, baseClass)
{
	var newSubMenu = itemClicked.parentNode
	if (newSubMenu) 
	{
		var subMenus = newSubMenu.parentNode.getElementsByTagName('span');
		for (var j = 0; j < subMenus.length; j++)
		{
			// remove the (Selected) title blurb from the actively selected sub-tab
			dxMenuBar_titleTextReplace(subMenus[j], ' (Selected)', '');
			
			if (subMenus[j].className != baseClass + '_Divider')
				subMenus[j].className = baseClass + '_SubMenuItem';
		}
		
		// Set the (Selected) title blurb for the newly selected sub-tab
		dxMenuBar_titleTextReplace(newSubMenu, ' - ', ' (Selected) - ');
		
		newSubMenu.className = baseClass + '_SubMenuItemCurrent';
	}
	return;
}

// Replaces text in the title attribute for a dxMenuBar subMenu item
function dxMenuBar_titleTextReplace(menuItem, searchText, replaceText)
{
	var anchors = menuItem.getElementsByTagName('a');
	if (anchors.length > 0)
	{
		var title = anchors[0].attributes['title'];
		if (title.value.indexOf(searchText) > -1)
		{
			title.value = title.value.replace(searchText, replaceText);
		}
	}
}

function dxMenuBar_menuItemKeyDown(e, menuBarID, subMenuID, itemID) {
	if (!e) e = window.event;

	var iCode;
	if ((e.charCode) && (e.keyCode==0)) {
		iCode = e.charCode
	}
	else {
		iCode = e.keyCode;
	}
	
	var ret = dxMenuBar_menuItemProcessKeyDown(e.shiftKey, iCode, menuBarID, subMenuID, itemID);
	return(ret);
}
function dxMenuBar_menuItemProcessKeyDown(shiftKey, iCode, menuBarID, subMenuID, itemID) {
	var topMenu, topMenuItems;
	var subMenu, subMenuItems;
	var i, currentTopMenuIndex, currentSubMenuIndex, subMenuIDWithNoPrefix;

	subMenuIDWithNoPrefix = subMenuID.substr(5);
	currentTopMenuIndex = -1;
	currentSubMenuIndex = -1;

	topMenu = document.getElementById(menuBarID + "_table");
	if (topMenu) {
		topMenuItems = topMenu.getElementsByTagName('A');
		if (topMenuItems) {
			for (i = 0; i < topMenuItems.length; i++) {
				if (topMenuItems[i].id == "link_" + subMenuIDWithNoPrefix) {
					currentTopMenuIndex = i;
				}
			}
		}
	}

	subMenu = document.getElementById(subMenuID);
	if (subMenu) {
		subMenuItems = subMenu.getElementsByTagName('A');
		if (subMenuItems) {
			for (i = 0; i < subMenuItems.length; i++) {
				if (subMenuItems[i].id == "menuItemLink_" + itemID) {
					currentSubMenuIndex = i;
				}
			}
		}
	}

	switch(iCode) {
		case 9: // Tab
			if (shiftKey && currentSubMenuIndex == 0) {
				dxMenuBar_menuItemProcessKeyDown(false, 38, menuBarID, subMenuID, itemID);
			}
			else if (!shiftKey && currentSubMenuIndex == (subMenuItems.length - 1)) {
				if (currentTopMenuIndex != (topMenuItems.length - 1)) {
					topMenuItems[currentTopMenuIndex+1].focus();
					// The next line was the old approach, at least temporarily scrapped because Deque was having problems with it.
					//dxMenuBar_menuItemProcessKeyDown(false, 39, menuBarID, subMenuID, itemID);
				}
				else {
					topMenuItems[currentTopMenuIndex].focus();
					return(true);
				}
			}
			else {
				return(true);
			}
			break;

		case 38: // Up
			if (subMenuItems) {
				if (currentSubMenuIndex > 0) {
					subMenuItems[currentSubMenuIndex-1].focus();
				}
				else {
					topMenuItems[currentTopMenuIndex].focus();
				}
			}
			break;

		case 40: // Down
			if (subMenuItems && currentSubMenuIndex != -1 && currentSubMenuIndex < (subMenuItems.length - 1)) {
				subMenuItems[currentSubMenuIndex+1].focus();
			}
			break;

		case 37: // Left
		case 39: // Right
			menuProcessKeyDown(shiftKey, iCode, menuBarID, topMenuItems[currentTopMenuIndex].id.substr(5));
			break;

		default:
			return(true);
			break;
	}

	return(false);
}

function dxMenuBar_menuItemMouseOver(itemID) {
	dxMenuBar_menuItemMouseOverOrFocus(this, itemID);
}
function dxMenuBar_menuItemFocus(itemID) {
	dxMenuBar_menuItemMouseOverOrFocus(this, itemID);
}
function dxMenuBar_menuItemMouseOverOrFocus(objThis, itemID) {
	objThis.stopClose();
	var menuItem = objThis.menuDoc.getElementById("menuItem_" + itemID);
	menuItem.className = objThis.menuItemSelectedClass;
}

function dxMenuBar_menuItemMouseOut(itemID) {
	dxMenuBar_menuItemMouseOutOrBlur(this, itemID);
}
function dxMenuBar_menuItemBlur(itemID) {
	dxMenuBar_menuItemMouseOutOrBlur(this, itemID);
}
function dxMenuBar_menuItemMouseOutOrBlur(objThis, itemID) {
	objThis.initClose();
	var menuItem = objThis.menuDoc.getElementById("menuItem_" + itemID);
	menuItem.className = objThis.menuItemClass;
}

function dxMenuBar_initClose() {
	this.timer = setTimeout("displayMenu('" + this.menuBarID + "', null);unhideAllDropDownsIfIE6();", 500);
}

function dxMenuBar_stopClose() {
	clearTimeout(this.timer);
}

function menuKeyDown(e, menuBarID, menuID) {
	if (!e) e = window.event;

	var iCode;
	if ((e.charCode) && (e.keyCode==0)) {
		iCode = e.charCode
	}
	else {
		iCode = e.keyCode;
	}
	
	var ret = menuProcessKeyDown(e.shiftKey, iCode, menuBarID, menuID);
	return(ret);
}
function menuProcessKeyDown(shiftKey, iCode, menuBarID, menuID, extra) {
	var topMenu, topMenuItems;
	var subMenu, subMenuItems;
	var i, currentTopMenuIndex;

	currentTopMenuIndex = -1;

	topMenu = document.getElementById(menuBarID + "_table");
	if (topMenu) {
		topMenuItems = topMenu.getElementsByTagName('A');
		if (topMenuItems) {
			for (i = 0; i < topMenuItems.length; i++) {
				if (topMenuItems[i].id == "link_" + menuID) {
					currentTopMenuIndex = i;
				}
			}
		}
	}

	subMenu = document.getElementById("menu_" + menuID);
	if (subMenu) {
		subMenuItems = subMenu.getElementsByTagName('A');
	}

	switch(iCode) {
		case 9: // Tab (and Shift-Tab)
			if (shiftKey) {
				if (currentTopMenuIndex < 1) {
					return(true);
				}
				else {
					var previousSubMenu = document.getElementById("menu_" + topMenuItems[currentTopMenuIndex-1].id.substr(5));
					if (previousSubMenu) {
						var previousSubMenuItems = previousSubMenu.getElementsByTagName('A');
						if (previousSubMenuItems.length > 0) {
							// We have to make the previous submenu visible first,
							// or IE chokes due to timing and visibility issues.
							menuFocus(menuBarID, previousSubMenu.id.substr(5));
							setTimeout("document.getElementById('" + previousSubMenuItems[previousSubMenuItems.length-1].id + "').focus();", 10);
						}
					}
				}
			}
			else {
				if (subMenuItems) {
					if (subMenuItems.length == 0) {
						return(true);
					}
					else {
						subMenuItems[0].focus();
					}
				}
			}
			break;
			
		case 40: // Down
			if (subMenuItems) {
				if (subMenuItems.length > 0) {
					subMenuItems[0].focus();
				}
			}
			break;
			
		case 37: // Left
			if (topMenuItems && currentTopMenuIndex != -1 && currentTopMenuIndex > 0) {
				topMenuItems[currentTopMenuIndex-1].focus();
			}
			break;

		case 39: // Right
			if (topMenuItems && currentTopMenuIndex != -1 && currentTopMenuIndex < (topMenuItems.length - 1)) {
				topMenuItems[currentTopMenuIndex+1].focus();
			}
			break;

		default:
			return(true);
			break;
	}

	return(false);
}

function menuMouseOver(menuBarID, menuID) {
	menuMouseOverOrFocus(menuBarID, menuID);
}
function menuFocus(menuBarID, menuID) {
	menuMouseOverOrFocus(menuBarID, menuID);
}
function menuMouseOverOrFocus(menuBarID, menuID) {
	if (menuBars[menuBarID]) {
		if (menuBars[menuBarID].timer) menuBars[menuBarID].stopClose();
		setTimeout("displayMenu('" + menuBarID + "','" + menuID + "');", 10);
	}
}

function menuMouseOut(menuBarID, menuID) {
	menuMouseOutOrBlur(menuBarID, menuID);
}
function menuBlur(menuBarID, menuID) {
	menuMouseOutOrBlur(menuBarID, menuID);
}
function menuMouseOutOrBlur(menuBarID, menuID) {
	if (menuBars[menuBarID]) {
		menuBars[menuBarID].initClose();
	}
}

function displayMenu(menuBarID, menuID) {
	var menuBar = menuBars[menuBarID];
	
	hideAllDropDownsIfIE6();

	if (useIEPopup) {
		if (menuID) {
			showMenu(menuBar, menuID);
		} else {
			hideMenu(menuBar);
		}
	} else {
		var counter;
		// Show the new menu item BEFORE hiding any that were open.
		for(counter = 0; counter < menuBar.menus.length; counter++) {
			if(menuBar.menus[counter] == menuID) {
				showMenu(menuBar, menuID);
			}
		}
		for(counter = 0; counter < menuBar.menus.length; counter++) {
			if(menuBar.menus[counter] != menuID) {
				hideMenu(menuBar, menuBar.menus[counter]);
			}
		}
	}
}

function hideAllDropDownsIfIE6() {
	if (hideAllDropDownsOnMenuOpen) {
		var dropDownLists = document.getElementsByTagName('SELECT');
		if (dropDownLists) {
			for (var i = 0; i < dropDownLists.length; i++) {
				if (dropDownLists[i].style.display != "none") {
					dropDownLists[i].style.unhideOnMenuClose = "1";
					dropDownLists[i].style.display = "none";
				}
			}
		}
	}
}

function unhideAllDropDownsIfIE6() {
	if (hideAllDropDownsOnMenuOpen) {
		var dropDownLists = document.getElementsByTagName('SELECT');
		if (dropDownLists) {
			for (var i = 0; i < dropDownLists.length; i++) {
				if (dropDownLists[i].style.unhideOnMenuClose == "1") {
					dropDownLists[i].style.display = "";
				}
				dropDownLists[i].style.unhideOnMenuClose = "";
			}
		}
	}
}

function showMenu(menuBar, menuID, setFocus) {
	var menu = getObjectById("menu_" + menuID);
	var header = getObjectById("header_" + menuID);
	var rect = getRect(header);
	var headerWidth = rect.right - rect.left;
	var menuRect;
	
	if (useIEPopup) {
		if (menuID) {
			var popDoc;
			
			popDoc = menuBar.popup.document;
			popDoc.all.MenuContainer.innerHTML = menu.outerHTML;
			
			var remoteMenu = popDoc.all[menu.id];
			
			// Link popup event handlers to parent page event handlers.
			remoteMenu.menuBars = menuBars;
			
			showObject(null, remoteMenu);
			remoteMenu.style.width = headerWidth;
			
			// Call .show() twice to initialize the dimensional properties of the inner 
			// menu div. 
			menuBar.popup.show(0, 0, 0, 0, document.body);
			menuRect = getRect(remoteMenu);
			menuBar.popup.show(menuBar.hOffset, (rect.bottom - rect.top) + menuBar.vOffset, 
				menuRect.right - menuRect.left, menuRect.bottom - menuRect.top,
				header);
		}
	} else {
		menu.style.left = rect.left + menuBar.hOffset;
		menu.style.top = rect.bottom + menuBar.vOffset;
		showObject(null, menu);
		
		menuRect = getRect(menu);
		var menuWidth = menuRect.right - menuRect.left;
		
		if (menuWidth < headerWidth) {
			menu.style.width = headerWidth;
		}
	}
}

function hideMenu(menuBar, menuID) {
	if (useIEPopup) {
		if (menuBar.popup) {
			menuBar.popup.hide();
		}
	} else {
		hideObject("menu_" + menuID);
	}
}



