/************************************************************************************************************
//	Usage:
//	In your document head, include this script:
//		<script language="javascript" src="http://www.ncbi.nlm.nih.gov/Structure/SharedFiles/bal.js></script>
//	and excecute initBal() when the page is loaded and finiBal() when the page is about to unload:
//		<body onLoad="initBal();" onUnload="finiBal();">
//	Define your own initialization function as 'init()' so that initBal() will automatically call it:
//		init()
//		{
//			// my init code here
//		}
//	Define your own exit function as 'fini()' so that finiBal() will automatically call it:
//		fini()
//		{
//			// my exit code here
//		}
//	After initialization, the following properties and methods are available, along with
//	all global constants:
//		document.bal.sysInfo.browser_id;
//		document.bal.sysInfo.browser_name;
//		document.bal.sysInfo.browser_major;
//		document.bal.sysInfo.browser_minor;
//		document.bal.sysInfo.browser_release;
//		document.bal.sysInfo.os_type;
//		document.bal.body	//document body
//		document.bal.getElementById(strId);
//		document.bal.createNamedAnchor(strName);
//		document.bal.createNamedElement(strTagName, strName);
//		document.bal.setObjOpacity(oObj, iOpacity);	//iOpacity is from 0 to 100
//		document.bal.getObjPosX();
//		document.bal.getObjPosY();
//		document.bal.getWindowWidth();
//		document.bal.getWindowHeight();
//		document.bal.getScrollLeft();
//		document.bal.getScrollTop();
//		document.bal.importXML(strUrl);
//		document.bal.setCookie(strName, strValue, iLifeSpan, strDomain, strPath, bSecure);
//		document.bal.getCookie(strName);
//		document.bal.deleteCookie(strName);
//		document.bal.installHandler(oObj, iEvent, fnHandler, bCapture);
//		document.bal.removeHandler(oObj, iEvent, fnHandler, bCapture);
************************************************************************************************************/
// -- Class augmentation. for flat inheritance.
function OA_initBaseObjects(curClass)
{
	if (curClass && curClass.baseClasses)
	{
		for (var i = 0; i < curClass.baseClasses.length; ++i)
		{
			curClass.baseClasses[i].apply(this);
		}
	}
}
Object.prototype.initBaseObjects = OA_initBaseObjects;


Object.prototype.dummy = function(){};
Function.prototype.dummy = function(){};

function FA_inherit()
{
	this.baseClasses = new Array();
	for (var i = 0; i < arguments.length; ++i)
	{
		this.baseClasses.push(arguments[i]);
		for (var prop in arguments[i].prototype)
		{
			this.prototype[prop] = arguments[i].prototype[prop];
		}
	}
}
Function.prototype.inherit = FA_inherit;

function FA_apply(__this, argArray)
{
	if (__this)
	{
		
		var tmpProp = "tp" + (Math.random() * 100000).toFixed();
		__this.constructor.prototype[tmpProp] = this;	//this is function
		
		var evalStr = "__this." + tmpProp + "(";
		
		if (argArray && typeof(argArray.length) == 'number' && argArray.length > 0)
		{
			evalStr += "argArray[0]";
			for (var i = 1; i < argArray.length; ++i)
			{
				evalStr += ", argArray[" + i + "]";
			}
		}
		
		evalStr += ")";

		eval(evalStr);
		__this.constructor.prototype[tmpProp] = null;
		delete __this.constructor.prototype[tmpProp];
	}
}
Function.prototype.myApply = FA_apply;

if (!Function.apply) Function.prototype.apply = FA_apply;

function FA_staticCall()
{
	
	var buf = new Array();
	
	// -- as separate parameters
	for (var i = 2; i < arguments.length; ++i)
		buf.push(arguments[i]);
	this.prototype[arguments[0]].apply(arguments[1], buf);
}
Function.prototype.staticCall = FA_staticCall;

function FA_staticCall2()
{
	this.prototype[arguments[0]].apply(arguments[1], arguments[2]);
}
Function.prototype.staticCall2 = FA_staticCall2;


function FA_addMethod(name, func)
{
	this.prototype[name] = func;
	return this;
}
Function.prototype.addMethod = FA_addMethod;

function NUM_round()
{
	var numStr = this.toString();
	var dotPos = numStr.indexOf('.');
	if (dotPos < 0 || dotPos == numStr.length - 1)
		return this;
	else
	{
		var newNum = parseInt(numStr.substring(0, dotPos));
		if (numStr[dotPos + 1] >= '5') newNum++;
		return newNum;
		
	}
}
Number.prototype.myRound = NUM_round;
if (!Number.prototype.round) Number.prototype.round = NUM_round;

function NUM_toFixed(precision)
{
	var prec = 0;
	if ('number' == typeof(precision))
		prec = precision.round();
	
	var numStr = this.toString();
	if (prec < 0) return numStr;
	var dotPos = numStr.indexOf('.');
	
	if (-1 == dotPos)
	{
		if (prec > 0)
		{
			numStr += ".";
			for (var i = 0; i < prec; ++i)
				numStr += "0";
		}
		return numStr;
	}
	else
	{
		var diff = numStr.length - dotPos - 1 - prec;
	
		if (diff > 0)
		{
			var cutPointChar = numStr.charAt(dotPos + 1 + prec);
			if (cutPointChar >= '5')
			{
			
				numStr = (this + parseInt("1e-" + prec)).toString();
			}
			numStr = numStr.substr(0, dotPos + 1 + prec);
		}
		else
		{
			for (var i = 0; i < -diff; ++i)
			{
				numStr += '0';
			}
		}
		return numStr;
	
	}
}

Number.prototype.myToFixed = NUM_toFixed;

if (!Number.prototype.toFixed) Number.prototype.toFixed = NUM_toFixed;

// -- global consts -- stupid IE does not recognize 'const' keyword

var LOAD_TIME = new Date();	//time when the page loaded
// -- time in milliseconds
var HALF_SECOND = 500;
var ONE_SECOND = 1000;
var ONE_MINUTE = 60000;	//one minute
var ONE_HOUR = 3600000;
var ONE_DAY = 86400000;
var ONE_WEEK = 604800000;
var ONE_MONTH = 2592000000;
var ONE_YEAR = 31536000000;

var POPUPLAYER = 200000;
var ACTIVEOBJLAYER = 100000;
var DRAGGABLEOBJLAYER = 10000;
var SCROLLABLEOBJLAYER = 1000;
var STATICFLOATINGLAYER = 100;
var NONTOPOBJLAYER = 0;

// -- browser id
var BROWSER_IEXPLORER = 0;
var BROWSER_NETSCAPE =1;
var BROWSER_MOZILLA = 2;
var BROWSER_FIREFOX = 3;
var BROWSER_OPERA = 4;
var BROWSER_SAFARI = 5;
var BROWSER_WEBTV = 6;
var BROWSER_KONQUEROR = 7;
var BROWSER_AOL = 8;
var BROWSER_AOLTV = 9;
var BROWSER_OMNIWEB = 10;
var BROWSER_ICAB = 11;
var BROWSER_HOTJAVA = 12;
var BROWSER_FIREBIRD = 13;
var BROWSER_UNKNOWN = 14;

// -- os type
var OS_WINDOWS = 0;
var OS_LINUX = 1;
var OS_MAC = 2;
var OS_SUN = 3;
var OS_IRIX = 4;
var OS_AIX = 5;
var OS_HPUX = 6;
var OS_SCO = 7;
var OS_UNIXWARE = 8;
var OS_MPRAS = 9;
var OS_RELIANT = 10;
var OS_DEC = 11;
var OS_SINIX = 12;
var OS_FREEBSD = 13;
var OS_BSD = 14;
var OS_UNIX = 15;
var OS_VMS = 16;
var OS_OS2 = 17;
var OS_UNKNOWN = 18;	

// -- XML node types
var NODE_ELEMENT = 1;
var NODE_ATTRIBUTE = 2;
var NODE_TEXT = 3;
var NODE_CDATA_SECTION = 4;
var NODE_ENTITY_REFERENCE = 5;
var NODE_ENTITY = 6;
var NODE_PROCESSING_INSTRUCTION = 7;
var NODE_COMMENT = 8;
var NODE_DOCUMENT = 9;
var NODE_DOCUMENT_TYPE = 10;
var NODE_DOCUMENT_FRAGMENT = 11;
var NODE_NOTATION = 12;

// -- event id
var evt_onabort = 0;
var evt_onblur = 1;
var evt_onchange = 2;
var evt_onclick = 3;
var evt_ondblclick = 4;
var evt_onerror = 5;
var evt_onfocus = 6;
var evt_onkeydown = 7;
var evt_onkeypress = 8;
var evt_onkeyup = 9;
var evt_onload = 10;
var evt_onmousedown = 11;
var evt_onmousemove = 12;
var evt_onmouseout = 13;
var evt_onmouseover = 14;
var evt_onmouseup = 15;
var evt_onreset = 16;
var evt_onresize = 17;
var evt_onscroll = 18;
var evt_onselect = 19;
var evt_onsubmit = 20;
var evt_onunload = 21;
var evt_total = 22;


/************************************************************
//	Implementation part
*************************************************************/
// -- for developers -- init registering

var dimInitCalls = new Array();
function registerInit(iniFunc)
{
	if (iniFunc && typeof(iniFunc) == 'function')
	{
		dimInitCalls.push(iniFunc);
	}
}


// -- client detect
function _this_system()
{
	var __self = this;	//private, accessible to private functions
	var dimBrowserName = new Array("Internet Explorer", "Netscape", "Mozilla", "Firefox", "Opera", "Safari", "WebTV", "Konqueror", "AOL browser", "AOLTV", "OmniWeb", "iCab", "HotJava", "Firebird", "Unknown Browser");
	var dimOSName = new Array("MS Windows", "Linux", "Mac OS", "SUN OS", "IRIX", "AIX", "HP-UX", "SCO", "UNIXWARE", "MPRAS", "reliant unix", "DEC", "SINIX", "FREEBSD", "BSD", "UNIX", "VMS", "OS/2", "Unknown OS");
	
    var agt = navigator.userAgent.toLowerCase();
    var appVer = navigator.appVersion.toLowerCase();
    
    var vendor;
    if (navigator.vendor) vendor = navigator.vendor.toLowerCase();
    var vendorSub;
    if (navigator.vendorSub) vendorSub = navigator.vendorSub.toLowerCase();
    
    var pos = -1;
    
    function searchAgent(strPattern)
    {
    	pos = agt.indexOf(strPattern);
    	return (pos != -1);
    }
    
	function parseVersion(strText, iPos)
	{
		var iCursor = iPos;
		while (strText.charAt(iCursor) < '0' || strText.charAt(iCursor) > '9' && iCursor < strText.length) iCursor++;
		if (iCursor >= strText.length) return;
		var strLit = "";
		while (strText.charAt(iCursor) >= '0' && strText.charAt(iCursor) <= '9')
		{
			strLit += strText.charAt(iCursor);
			iCursor++;
		}
		__self.browser_major = parseInt(strLit);
		
		if (strText.charAt(iCursor) == '.')	//has minor
		{
			strLit = "";
			iCursor++;	//skip .
			while (strText.charAt(iCursor) >= '0' && strText.charAt(iCursor) <= '9')
			{
				strLit += strText.charAt(iCursor);
				iCursor++;
			}
			__self.browser_minor = parseInt(strLit);
		}
		
		if (strText.charAt(iCursor) == '.')	//has minor
		{
		
			strLit = "";
			iCursor++;	//skip .
			while (strText.charAt(iCursor) >= '0' && strText.charAt(iCursor) <= '9')
			{
				strLit += strText.charAt(iCursor);
				iCursor++;
			}
			__self.browser_release = parseInt(strLit);
		}
	}
    
    // detect os type first
    if ((agt.indexOf("win") != -1))
    {
    	this.os_type = OS_WINDOWS;
    }
    else if ((agt.indexOf("linux") != -1))
    {
    	this.os_type = OS_LINUX;
    }
    else if ((agt.indexOf("mac") != -1))
    {
    	this.os_type = OS_MAC;
    }
    else if ((agt.indexOf("sunos") != -1))
    {
    	this.os_type = OS_SUN;
    }
    else if ((agt.indexOf("irix") != -1))
    {
    	this.os_type = OS_IRIX;
    }
    else if ((agt.indexOf("hp-ux") != -1))
    {
    	this.os_type = OS_HPUX;
    }
    else if ((agt.indexOf("aix") != -1))
    {
    	this.os_type = OS_AIX;
    }
    else if ((agt.indexOf("sco") != -1) || agt.indexOf("unix_sv") != -1)
    {
    	this.os_type = OS_SCO;
    }
    else if ((agt.indexOf("unix_system_v") != -1))
    {
    	this.os_type = OS_UNIXWARE;
    }
    else if ((agt.indexOf("ncr") != -1))
    {
    	this.os_type = OS_MPRAS;
    }
    else if ((agt.indexOf("reliantunix") != -1))
    {
    	this.os_type = OS_RELIANT;
    }
    else if ((agt.indexOf("dec") != -1) || (agt.indexOf("osf1") != -1) || (agt.indexOf("dec_alpha") != -1) || (agt.indexOf("alphaserver") != -1) || (agt.indexOf("ultrix") != -1) || (agt.indexOf("alphastation") != -1))
    {
    	this.os_type = OS_DEC;
    }
    else if ((agt.indexOf("sinix") != -1))
    {
    	this.os_type = OS_SINIX;
    }
    else if ((agt.indexOf("freebsd") != -1))
    {
    	this.os_type = OS_FREEBSD;
    }
    else if ((agt.indexOf("bsd") != -1))
    {
    	this.os_type = OS_BSD;
    }
    else if ((agt.indexOf("x11") != -1))
    {
    	this.os_type = OS_UNIX;
    }
    else if ((agt.indexOf("vax") != -1) || (agt.indexOf("openvmx") != -1))
    {
    	this.os_type = OS_VMS;
    }
	else
	{
		this.os_type = OS_UNKNOWN;
	}
    
    this.os_name = dimOSName[this.os_type];
	parseVersion(appVer, 0);

	// now detect browser
	if (searchAgent("konqueror"))
	{
		this.browser_id = BROWSER_KONQUEROR;
		if (this.os_type == OS_UNKNOWN) this.os_type = OS_LINUX;
		parseVersion(agt, pos);
	}
	else if (searchAgent("safari"))
	{
		this.browser_id = BROWSER_SAFARI;
		parseVersion(agt, pos);
	}
	else if (searchAgent("omniweb"))
	{
		this.browser_id = BROWSER_OMNIWEB;
		parseVersion(agt, pos);
	}
	else if (searchAgent("opera"))
	{
		this.browser_id = BROWSER_OPERA;
		parseVersion(agt, pos);
	}
	else if (searchAgent("aol"))
	{
		this.browser_id = BROWSER_AOL;
		parseVersion(agt, pos);
	}
	else if (searchAgent("navio"))
	{
		pos = agt.indexOf("navio");
		this.browser_id = BROWSER_AOLTV;
		parseVersion(agt, pos);
	}
	else if (searchAgent("webtv"))
	{
		this.browser_id = BROWSER_WEBTV;
		parseVersion(agt, pos);
	}
	else if (searchAgent("hotjava"))
	{
		this.browser_id = BROWSER_HOTJAVA;
		parseVersion(agt, pos);
	}
	else if (searchAgent("icab"))
	{
		this.browser_id = BROWSER_ICAB;
		parseVersion(agt, pos);
	}
	else if (searchAgent("msie"))
	{
		this.browser_id = BROWSER_IEXPLORER;
		if (this.os_type == OS_MAC)
		{
			parseVersion(agt, pos);
		}
		else
		{
			pos = appVer.indexOf("msie");
			parseVersion(appVer, pos);
		}
	}
	else if (agt.indexOf("compatible") == -1)	// mozilla family
	{
		if (searchAgent("firefox") || (agt.indexOf("gecko") != -1 && undefined != vendor && vendor.indexOf("firefox") != -1))
		{
			this.browser_id = BROWSER_FIREFOX;
			parseVersion(agt, pos);
		}
		else if (searchAgent("firebird") || (agt.indexOf("gecko") != -1 && undefined != vendor && vendor.indexOf("firebird") != -1))
		{
			this.browser_id = BROWSER_FIREBIRD;
			parseVersion(agt, pos);
		}
		else if (agt.indexOf("gecko") && (undefined == vendor || vendor == "" || vendor.indexOf("mozilla") != -1 || vendor.indexOf("debian") != -1))
		{
			this.browser_id = BROWSER_MOZILLA;
			pos = agt.indexOf("rv:");
			parseVersion(agt, pos + 3);
		}
		else if (agt.indexOf("gecko") != -1 && vendor && (vendor.indexOf("netscape") != -1))
		{
			this.browser_id = BROWSER_NETSCAPE;
			parseVersion(vendorSub, 0);
		}
		else
		{
			this.browser_id = BROWSER_UNKNOWN;
		}
	}
	else
	{
		this.browser_id = BROWSER_UNKNOWN;
	}
	this.browser_name = dimBrowserName[this.browser_id];
}




function _bal()
{
	this.sysInfo = new _this_system();
	if (document.body)
	{
		this.body = document.body;
	}
	else
	{
		this.body = this.getElementByTagName("body")[0];
	}
	
	// -- adjust for OPERA
	if (this.sysInfo.browser_id == BROWSER_OPERA)
	{
		Function.prototype.apply = FA_apply;
	}
	// -- adjust for Mac browsers
	if (this.sysInfo.os_type == OS_MAC && this.sysInfo.browser_id != BROWSER_FIREFOX)
	{
		Number.prototype.toFixed = Number.prototype.myToFixed;
	}
	
	/************************************************************
	//	Private Part
	*************************************************************/
	var __self = this;
	// this.getElementById
	if (document.getElementById)
	{
		this.getElementById = function (strObjId)
		{
			return document.getElementById(strObjId);
		}
	}
	else if (document.all)
	{
		this.getElementById = function (strObjId)
		{
			return document.all[strObjId];
		}
	}
	else
	{
		this.getElementById = function(strId) {Unavailable("getElementById");}
	}
	

	// -- createNamedAnchor
	
	function _createNamedAnchor_w3c(strName)
	{
		var newAnchor = document.createElement("a");
		newAnchor.name = strName;
		return newAnchor;
	}
	
	function _createNamedElement_w3c(strTagName, strName)
	{
		var newElement = document.createElement(strTagName);
		newElement.name = strName;
		return newElement;
	}
	
	try
	{
		var testObj = document.createElement("<a name='testname'>");
		if (testObj.name)
		{
			this.createNamedAnchor = function (strName)
			{
				return document.createElement("<a name='" + strName + "'>");
			}
			this.createNamedElement = function (strTagName, strName)
			{
				return document.createElement("<" + strTagName + " name='" + strName + "'>");
			}
		}
		else
		{
			this.createNamedAnchor = _createNamedAnchor_w3c;
			this.createNamedElement = _createNamedElement_w3c;
		}
	}
	catch (e)
	{
		this.createNamedAnchor = _createNamedAnchor_w3c;
		this.createNamedElement = _createNamedElement_w3c;
	}
	
	
	if (document.frames)
	{
		this.getFrameByName = function (strName)
		{
			return document.frames[strName];
		}
	}
	else if (window.frames)
	{
		this.getFrameByName = function (strName)
		{
			return window.frames[strName];
		}
	}
	

	// -- setObjOpacity
	this.setObjOpacity = function (oObj, op)
	{
		oObj.style.filter = 'alpha(opacity=' + op + ')';
		oObj.style.opacity = op / 100;
	}
	
	
	
	// -- getWindowWidth, getWindowHeight
	if (typeof(window.innerWidth) == 'number')
	{
		this.getWindowWidth = function()
		{
			return window.innerWidth;
		}
		this.getWindowHeight = function()
		{
			return window.innerHeight;
		}
	}
	else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight))
	{
		this.getWindowWidth = function()
		{
			return document.documentElement.clientWidth;
		}
		this.getWindowHeight = function()
		{
			return document.documentElement.clientHeight;
		}
	}
	else if (document.body && (document.body.clientWidth || document.body.clientHeight))
	{
		this.getWindowWidth = function()
		{
			return document.body.clientWidth;
		}
		this.getWindowHeight = function()
		{
			return document.body.clientHeight;
		}
	}
	else
	{
		this.getWindowWidth = function() {Unavailable("getWindowWidth");}
		this.getWindowHeight = function() {Unavailable("getWindowHeight");}
	}
	
	// -- getScrollLeft, -- getScrollTop
	if (typeof(window.pageXOffset) == 'number')
	{
		this.getScrollLeft = function ()
		{
			return window.pageXOffset;
		}
		this.getScrollTop = function ()
		{
			return window.pageYOffset;
		}
	}
	else if (typeof(document.body.scrollLeft) == 'number')
	{
		this.getScrollLeft = function ()
		{
			return document.body.scrollLeft;
		}
		this.getScrollTop = function ()
		{
			return document.body.scrollTop;
		}
	}
	else if (typeof(document.documentElement.scrollLeft) == 'number')
	{
		
		this.getScrollLeft = function ()
		{
			return document.documentElement.scrollLeft;
		}
		this.getScrollTop = function ()
		{
			return document.documentElement.scrollTop;
		}
	}
	else
	{
		this.getScrollLeft = function() {Unavailable("getScrollLeft");}
		this.getScrollTop = function() {Unavailable("getScrollTop");}
	}
	
	// -- getObjWidth
	if (__self.sysInfo.browser_id == BROWSER_SAFARI)
	{
		this.getObjWidth = function (oObj)
		{
			if (oObj.tagName.toLowerCase() == "tr")
			{
				var cells = oObj.cells;
				return cells[cells.length - 1].offsetLeft + cells[cells.length - 1].offsetWidth - cells[0].offsetLeft;
			}
		}
	}
	else
	{
		this.getObjWidth = function (oObj)
		{
			return oObj.offsetWidth;
		}
	}
	
	
	// -- getObjHeight
	if (__self.sysInfo.browser_id == BROWSER_SAFARI)
	{
		this.getObjHeight = function (oObj)
		{
			if (oObj.tagName.toLowerCase() == "tr")
			{
				var h = 0;
				for (var i = 0; i < oObj.cells.length; ++i)
				{
					if (oObj.cells[i].offsetHeight > h) h = oObj.cells[i].offsetHeight;
				}
				return h;
			}
			else
				return oObj.offsetHeight;
		}
	}
	else
	{
		this.getObjHeight = function (oObj)
		{
			return oObj.offsetHeight;
		}
	}
	
	// -- getObjPosX, getObjPosY
	if (typeof(__self.body.x) == 'number')
	{
		this.getObjPosX = function (oObj)
		{
			return oObj.x;
		}
		this.getObjPosY = function (oObj)
		{
			return oObj.y;
		}
	}
	else 
	{
		if (__self.sysInfo.browser_id == BROWSER_OPERA && __self.sysInfo.os_type == OS_WINDOWS)
		{
			this.getObjPosX = function (oObj)
			{
				var iResult = 0;
				while (oObj.offsetParent)
				{
					iResult += oObj.offsetLeft;
					if (oObj.tagName.toLowerCase() == "tr") iResult -= __self.getScrollLeft();
					
					oObj = oObj.offsetParent;
				}
				return iResult;
			}
		}
		else
		{
			this.getObjPosX = function (oObj)
			{
				var iResult = 0;
				while (oObj.offsetParent)
				{
					iResult += oObj.offsetLeft;
					
					oObj = oObj.offsetParent;
				}
				return iResult;
			}
		}
		
		if (__self.sysInfo.browser_id == BROWSER_SAFARI && __self.sysInfo.os_type == OS_MAC)
		{
			this.getObjPosY = function (oObj)
			{
				var iResult = 0;
				while (oObj.offsetParent)
				{
					iResult += oObj.offsetTop;
					if (oObj.tagName.toLowerCase() == "tr")
					{
						iResult += oObj.cells[0].offsetTop;
					}
					oObj = oObj.offsetParent;
				}
				return iResult;
			}
		}
		else
		{
			this.getObjPosY = function (oObj)
			{
				var iResult = 0;
				while (oObj.offsetParent)
				{
					iResult += oObj.offsetTop;
					oObj = oObj.offsetParent;
				}
				return iResult;
			}
		}
		
	}
	

	this.setObjFont = function (obj, strFont)
	{
		var dimStyles = strFont.split(" ");
		for (var i = dimStyles.length; i < 6; ++i)
		{
			dimStyles.push("");
		}
		
		obj.style.color = dimStyles[0];
		obj.style.fontFamily = dimStyles[1];
		obj.style.fontSize = dimStyles[2];
		obj.style.fontStyle = dimStyles[3];
		obj.style.fontVariant = dimStyles[4];
		obj.style.fontWeight = dimStyles[5]
	}
	
	this.clearOptions = function (sel)
	{
		if (sel.tagName.toLowerCase() == "select")
		{
			while (sel.options.length > 0)
			{
				sel.options[sel.options.length - 1] = null;
			}
		}
	}
	
	
	
	this.insertOption = function (sel, disp, val, idx)
	{
		if (sel.tagName.toLowerCase() == "select")
		{
			var newop = new Option(disp, val);
			var ops = sel.options;
			if (!idx || idx < 0 || idx >= ops.length)
				ops.add(newop);
			else
			{
				ops.add(newop, idx);
			}
		}
	}
	
	this.getSelectValue = function (sel)
	{
		if (sel.tagName.toLowerCase() == "select")
		{
			var ops = sel.options;
			for (var i = 0; i < ops.length; ++i)
			{
				if (ops[i].selected) return ops[i].value;
			}
			return null;
		}
		return null;
	}
	
	this.setSelectValue = function (sel, val)
	{
		
		if (sel.tagName.toLowerCase() == "select")
		{
			var ops = sel.options;
			var multi = sel.multiple;
			for (var i = 0; i < ops.length; ++i)
			{
				if (ops[i].value == val) ops[i].selected = true;
				else if (!multi)
				{
					ops[i].selected = false;
				}
			}
		}
	}
	
	// -- importXML
	if (window.XMLHttpRequest)	//most recently implemented in IE7
	{
		this.importXML = function (strFileName, fnOnLoad)
		{
			var oXmlDoc = new XMLHttpRequest();
			oXmlDoc.onreadystatechange = function ()
			{
				if (oXmlDoc.readyState == 4) fnOnLoad(oXmlDoc.responseXML);
			};
			oXmlDoc.open("GET", strFileName, true);
			oXmlDoc.send(null);
			return oXmlDoc;
		}
		
	}
	else if (document.implementation && document.implementation.createDocument)
	{
		this.importXML = function (strFileName, fnOnLoad)
		{
			var oXmlDoc = document.implementation.createDocument("", "", null);
			oXmlDoc.async = true;
			oXmlDoc.onload = function ()
			{
				fnOnLoad(oXmlDoc);
			};
			oXmlDoc.load(strFileName);
			return oXmlDoc;
		}
	}
	else if (window.ActiveXObject)	//MS
	{
		dimMSXmlVers = new Array("Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP");	//version
		for (var i = 0; i < dimMSXmlVers.length; ++i)
		{
			try
			{
				var testDoc = new ActiveXObject(dimMSXmlVers[i]);
				if (testDoc)
				{
					this.iMSXmlVerIdx = i;
					testDoc = null;
					this.importXML = function (strUrl, fnOnLoad)
					{
						var oXmlDoc = new ActiveXObject(dimMSXmlVers[__self.iMSXmlVerIdx]);
						oXmlDoc.onreadystatechange = function ()
						{
							if (oXmlDoc.readyState == 4) fnOnLoad(oXmlDoc.responseXML);
						};
						oXmlDoc.open("GET", strUrl, true);
						oXmlDoc.send();
						return oXmlDoc;
					}
					break;
				}
			}
			catch(__excpt)
			{
				;
			}
		}
		
		if (typeof(__self.iMSXmlVerIdx) != 'number')
		{
			this.importXML = function(xmlfile_url, fnWhenReady) {Unavailable("importXML");}	//(xmlfile_url, fnWhenReady)
			alert("Your browser can not handle xml. Please upgrade.");
		}
	}
	else
	{
		this.importXML = function(xmlfile_url, fnWhenReady) {Unavailable("importXML");}	//(xmlfile_url, fnWhenReady)
		alert("Your browser can not handle xml. Please upgrade.");
	}
	
	document.cookie = "cookie=true";
	if (document.cookie)
	{
		this.setCookie = function(strName, strValue, iLifeSpan, strDomain, strPath, bSecure)
		{
			if (!strName || "" == strName) return;
			var strSaveVal = strValue ? strValue : "?";
			var strCookie = strName + "=" + escape(strSaveVal);
			
			if (iLifeSpan && iLifeSpan >= 0)
			{
				var oCurrentDate = new Date();
				var oExpDate = new Date(oCurrentDate.valueOf() + iLifeSpan);
				strCookie += ";expires=" + oExpDate.toUTCString();
			}
			
			if (strDomain)
			{
				strCookie += ";domain=" + strDomain;
			}
			
			if (strPath)
			{
				strCookie += ";path=" + strPath;
			}
			
			if (bSecure)
			{
				strCookie += ";secure";
			}
			document.cookie = strCookie;
		}
		
		this.getCookie = function(strName)
		{
			var dimCookies = document.cookie.split("; ");	//must be ; plus a white space
			for (var i = 0; i < dimCookies.length; ++i)
			{
				
				var pairCrumb = dimCookies[i].split("=");
				if (strName == pairCrumb[0])
				{
					var strVal = unescape(pairCrumb[1]);
					if ("?" == strVal)
					{
						return "";
					}
					return strVal;
				}
			}
			return null;
		}
		
		this.deleteCookie = function(strName)
		{
			document.cookie = strName + "=;expires=" + LOAD_TIME.toUTCString() + ";";
		}
		
		this.deleteCookie("cookie");	//delete the test cookie
		
	}
	else
	{
		this.setCookie = function(strName, strValue, iLifeSpan, strDomain, strPath, bSecure) {Unavailable("setCookie");}
		this.getCookie = function(strName) {Unavailable("getCookie");}
		this.deleteCookie = function(strName) {Unavailable("deleteCookie");}
	}
	
	
	
	
	// -- padding style
	var testdiv = document.createElement("div");
	testdiv.style.visibility = "hidden";
	testdiv.style.width = "200px";
	testdiv.style.height = "150px";
	this.body.appendChild(testdiv);
	
	testdiv.style.position = "absolute";
	testdiv.style.left = "0px";
	testdiv.style.top = "0px";
	
	
	var readdiv = document.createElement("div");
	testdiv.appendChild(readdiv);
	
	readdiv.style.width = "50px";
	readdiv.style.height = "30px";
	
	var iStartPos = this.getObjPosX(readdiv);
	
	testdiv.style.padding = "2px";
	if (testdiv.offsetWidth > 200)	//outward padding
	{
		this.bW3CPadding = true;
	}
	else
	{
		this.bW3CPadding = false;
	}
	
	
	testdiv.style.padding = "50pt";
	this.pt2px = (this.getObjPosX(readdiv) - iStartPos) / 50;
	
	testdiv.style.padding = "10mm";
	this.mm2px = (this.getObjPosX(readdiv) - iStartPos) / 10;
	
	testdiv.style.padding = "5pc";
	this.pc2px = (this.getObjPosX(readdiv) - iStartPos) / 5;
	
	testdiv.style.padding = "5em";
	this.em2px = (this.getObjPosX(readdiv) - iStartPos) / 5;
	
	testdiv.style.padding = "10ex";
	this.ex2px = (this.getObjPosX(readdiv) - iStartPos) / 10;
	
	this.cm2px = this.mm2px * 10;
	this.in2px = this.mm2px * 25.4;
	
	
	this.getLengthInPx = function (strLength)
	{
		if (typeof(strLength) == 'number')
		{
			return strLength;
		}
		else if (strLength && strLength[strLength.length - 1] == "%")
		{
			return -1;
		}
		else if (strLength && strLength.length != 0)
		{
			var strUnit = strLength.substr(strLength.length - 2);
			
			var strValue = strLength.substring(0, strLength.length - 2);
			
			switch(strUnit)
			{
			case "px":
				return parseInt(strValue).round();
			case "pt":
				return (this.pt2px * parseFloat(strValue)).round();
			case "pc":
				return (this.pc2px * parseFloat(strValue)).round();
			case "mm":
				return (this.mm2px * parseFloat(strValue)).round();
			case "cm":
				return (this.cm2px * parseFloat(strValue)).round();
			case "in":
				return (this.in2px * parseFloat(strValue)).round();
			case "em":
				return (this.em2px * parseFloat(strValue)).round();
			case "ex":
				return (this.ex2px * parseFloat(strValue)).round();
			default:
				return 0;	
			}
		}
		return 0;
	}
	
	this.body.removeChild(testdiv);	
	readdiv = null;
	testdiv = null;
	
	this.clearChildNodes = function (obj)
	{
		if (obj.tagName)	//is an element
		{
			while (obj.childNodes.length)
			{
				obj.removeChild(obj.childNodes[obj.childNodes.length - 1]);
			}
		}
	}
	
	this.isInTree = function (obj)
	{
		var walk = obj;
		do
		{
			if (!walk) return false;
			else if (walk == document.bal.body)
				return true;
				
			walk = walk.parentNode;
		} while (true);
	}
	
	this.isInCollection = function(col, obj)	// see if obj is a child of container
	{
		if (col && col.length)
		{
			if (obj)
			{
				for (var i = 0; i < col.length; ++i)
				{
					if (col[i] == obj) return true;
				}
				return false;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
		
	}
	
	
	
	
	
	
	
	// -- universal event handling
	var dimEventType = new Array("onabort", "onblur", "onchange", "onclick", "ondblclick", "onerror", "onfocus", "onkeydown", "onkeypress", "onkeyup", "onload", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onreset", "onresize", "onscroll", "onselect", "onsubmit", "onunload");
	var dimBubbleHandlers = new Array();
	var dimCaptureHandlers = new Array();
	dimCaptureHandlers.length = evt_total;
	dimBubbleHandlers.length = evt_total;
			
	for (var i = 0; i < evt_total; ++i)
	{
		dimCaptureHandlers[i] = new Array();	//every event has an event array
		dimBubbleHandlers[i] = new Array();	//every event has an event array
	}
	
	function AddHandler(oRecord, fnHandler)
	{
		for (var i = 0; i < oRecord.dimHandlers.length; ++i)
		{
			if (fnHandler == oRecord.dimHandlers[i]) return; //handler already exist
		}
		oRecord.dimHandlers.push(fnHandler);
	}
	
	function RemoveHandler(oRecord, fnHandler)
	{
		for (var i = 0; i < oRecord.dimHandlers.length; ++i)
		{
			if (fnHandler == oRecord.dimHandlers[i])
			{
				oRecord.dimHandlers.splice(i, 1); //handler already exist
			}
		}
	}
	
	function EventRecord(oObj)
	{
		this.dimHandlers = new Array();
		
		if (typeof oObj == "string")	//id
		{
			this.oObj = __self.getElementById(oObj);
		}
		else if (typeof oObj == "object")	//obj itself
		{
			this.oObj = oObj;
		}
	}
	
	function MockEvent(ori_event)
	{
		this.type = ori_event.type;	//standard
		if (typeof(ori_event.button) == 'number')
		{
			this.oriButton = ori_event.button;
		}
	
		if (ori_event.target)
		{
			this.target = ori_event.target;
			this.currentTarget = ori_event.target;
			if (ori_event.type == dimEventType[evt_onkeypress].substr(2))
			{
				this.keyCode = ori_event.charCode;
				if (ori_event.ctrlKey) this.keyCode -= 96;	
			}
			else if (ori_event.type == dimEventType[evt_onkeydown].substr(2) || ori_event.type == dimEventType[evt_onkeyup].substr(2))
			{
				this.keyCode = ori_event.keyCode;
			}
			if (typeof(ori_event.button) == 'number')
			{
				this.button = ori_event.button;
				this.button = 0;
				if (document.bal.sysInfo.browser_id == BROWSER_OPERA && document.bal.sysInfo.browser_major < 8)	//opera specific 
				{
					if (ori_event.button == 3)	//old opera use 3 as middle
					{
						this.button = 4;
					}
					else
					{
						this.button = ori_event.button;
					}
				}
				else if (ori_event.button > 7)
				{
					this.button = 0;
				}
				else	//W3C
				{
					this.button |= (ori_event.button & 2);	//right
					if (ori_event.button & 1) this.button |= 4;	//middle
					if (ori_event.button == 0) this.button |= 1;	//left -- assume when no other button pressed. you never know. W3C sucked on this issue
				}	
				if (ori_event.button & 2) this.button |= 2;
			}
		}
		else if (ori_event.srcElement)	//chances are it's MS model
		{
			this.target = ori_event.srcElement;
			this.currentTarget = ori_event.srcElement;
			if (typeof ori_event.keyCode != undefined) this.keyCode = ori_event.keyCode;
			if (typeof ori_event.button != undefined) this.button = ori_event.button;
		}
		else if (ori_event.srcElement == null)	//strange IE bug? body.onscroll event
		{
			this.target = __self.body;
			this.currentTarget = __self.body;
			if (typeof ori_event.keyCode != undefined) this.keyCode = ori_event.keyCode;
			if (typeof ori_event.button != undefined) this.button = ori_event.button;
		}
		if (ori_event.returnValue)
		{
			this.returnValue = ori_event.returnValue;
			this.cancelBubble = ori_event.cancelBubble;
		}
		else
		{
			this.returnValue = true;
			this.cancelBubble = false;
		}
		
		if (ori_event.relatedTarget)
		{
			this.relatedTarget = ori_event.relatedTarget;
		}
		else if (ori_event.fromElement)
		{
			this.relatedTarget = ori_event.fromElement;
		}
		else if (ori_event.toElement)
		{
			this.relatedTarget = ori_event.toElement;
		}
		if (typeof ori_event.dataTransfer != undefined) this.dataTransfer = ori_event.dataTransfer;
		if (typeof ori_event.altKey != undefined) this.altKey = ori_event.altKey;
		if (typeof ori_event.ctrlKey != undefined) this.ctrlKey = ori_event.ctrlKey;
		if (typeof ori_event.shiftKey != undefined) this.shiftKey = ori_event.shiftKey;
		if (typeof ori_event.metaKey != undefined) this.metaKey = ori_event.metaKey;
		if (typeof ori_event.clientX != undefined) this.clientX = ori_event.clientX;
		if (typeof ori_event.clientY != undefined) this.clientY = ori_event.clientY;
		if (typeof ori_event.screenX != undefined) this.screenX = ori_event.screenX;
		if (typeof ori_event.screenY != undefined) this.screenY = ori_event.screenY;
		if (typeof ori_event.pageX != undefined || typeof ori_event.pageY != undefined)
		{
			this.pageX = ori_event.pageX;
			this.pageY = ori_event.pageY;
		}
		else if (typeof ori_event.clientX != undefined || typeof ori_event.clientY != undefined)
		{
			this.pageX = ori_event.clientX + __self.scrollLeft();
			this.pageX = ori_event.clientY + __self.scrollTop();
		}
		
		var __this = this;
		
		this.preventDefault = function()
		{
			__this.returnValue = false;
		}
			
		this.stopPropagation = function()
		{
			__this.cancelBubble = true;
		}
	}

	function UniversalListener(evt)
	{
		var oOriEvent;
		var oMockEvt;
		var bHandlerReturn = null;
		if (evt)	//got evt, 
		{
			oOriEvent = evt;
			oMockEvt = new MockEvent(evt);
		}
		else
		{
			oOriEvent = event;
			oMockEvt = new MockEvent(event);
		}
				// -- find index
		for (var i = 0; i < evt_total; ++i)
		{
			
			if (oMockEvt.type == dimEventType[i].substr(2))	//found
			{
				var dimRecords = dimCaptureHandlers[i];
				var dimParentPath = new Array();
				dimParentPath.push(oMockEvt.currentTarget);
				while (oMockEvt.currentTarget.parentNode)
				{
					oMockEvt.currentTarget = oMockEvt.currentTarget.parentNode;
					dimParentPath.push(oMockEvt.currentTarget);
				}
				
				for (var j = dimParentPath.length - 1; j >= 0; --j)
				{
					
					for (var k = 0; k < dimRecords.length; ++k)
					{
						if (dimRecords[k].oObj == dimParentPath[j])
						{
							var dimAllListeners = dimRecords[k].dimHandlers;
							oMockEvt.currentTarget = dimParentPath[j];
							for (var ii = 0; ii < dimAllListeners.length; ++ii)
							{
								if (typeof(dimAllListeners[ii]) == 'function')
									bHandlerReturn = dimAllListeners[ii](oMockEvt);
								else if (typeof(dimAllListeners[ii]) == 'string')
									bHandlerReturn = eval(dimAllListeners[ii]);
							}
							break;
						}
					}
					if (oMockEvt.cancelBubble)	//return here
					{
						if (oOriEvent.stopPropagation)	//W3C
						{
							oOriEvent.stopPropagation();	//original always stop propagation
							if (!oMockEvt.returnValue) oOriEvent.preventDefault();
						}
						else	//ie
						{
							oOriEvent.cancelBubble = true;
							oOriEvent.returnValue = oMockEvt.returnValue;
						}
						return bHandlerReturn;
						
					}
					
				}
				// -- Bubbling phase
				dimRecords = dimBubbleHandlers[i];
				for (var j = 0; j < dimParentPath.length; ++j)	//j starts from 1, skip the init obj
				{
					for (var k = 0; k < dimRecords.length; ++k)
					{
						if (dimRecords[k].oObj == dimParentPath[j])
						{
							var dimAllListeners = dimRecords[k].dimHandlers;
							oMockEvt.currentTarget = dimParentPath[j];
							for (var ii = 0; ii < dimAllListeners.length; ++ii)
							{
								if (typeof(dimAllListeners[ii]) == 'function')
									bHandlerReturn = dimAllListeners[ii](oMockEvt);
								else if (typeof(dimAllListeners[ii]) == 'string')
									bHandlerReturn = eval(dimAllListeners[ii]);
							}
							break;
						}
					}
					if (oMockEvt.cancelBubble)
					{
						if (oOriEvent.stopPropagation)	//W3C
						{
							oOriEvent.stopPropagation();	//original always stop propagation
							if (!oMockEvt.returnValue) oOriEvent.preventDefault();
						}
						else	//ie
						{
							oOriEvent.cancelBubble = true;
							oOriEvent.returnValue = oMockEvt.returnValue;
						}
						return bHandlerReturn;
					}
				}
				break;
			}
		}
		if (oOriEvent.stopPropagation)	//W3C
		{
			oOriEvent.stopPropagation();	//original always stop propagation
			if (!oMockEvt.returnValue) oOriEvent.preventDefault();
		}
		else	//ie
		{
			oOriEvent.cancelBubble = true;
			oOriEvent.returnValue = oMockEvt.returnValue;
		}
		
		return bHandlerReturn;
	}
	
	this.removeHandler = function(oObj, iEvent, fnHandler, bCapture)
	{
		if (undefined == oObj || null == oObj || undefined == fnHandler || null == fnHandler || iEvent < 0 || iEvent >= evt_total) return false;
		var dimWhich = bCapture ? dimCaptureHandlers : dimBubbleHandlers;
		for (var i = 0; i < dimWhich[iEvent].length; ++i)
		{
			if (dimWhich[iEvent][i].oObj == oObj)	//found
			{
				RemoveHandler(dimWhich[iEvent][i], fnHandler);
				return true;
			}
		}
	}
	
	this.installHandler = function(oObj, iEvent, fnHandler, bCapture)
	{
		if (undefined == oObj || null == oObj || undefined == fnHandler || null == fnHandler || iEvent < 0 || iEvent >= evt_total) return false;
		
		var dimWhich = bCapture ? dimCaptureHandlers : dimBubbleHandlers;
		
		for (var i = 0; i < dimWhich[iEvent].length; ++i)
		{
			if (dimWhich[iEvent][i].oObj == oObj)	//found
			{
				AddHandler(dimWhich[iEvent][i], fnHandler);
				return true;
			}
		}
		dimWhich[iEvent].push(new EventRecord(oObj));
		AddHandler(dimWhich[iEvent][dimWhich[iEvent].length - 1], fnHandler);
		eval("oObj." + dimEventType[iEvent] + " = UniversalListener;"); 
		
		return true;
	}
	
	
	function Unavailable(strName)
	{
		alert("Function " + strName + " is not supported by this system!");
	}
}


/***************************************************************
//	Mouse Tracking. track mouse position related to document
//	and client screen in document.bal.mouse. it also drags
//	objects.
****************************************************************/
var DRAGPROMOTION = 10000;
function _mouse_tracking()	//constructor
{
	this.x = 0;
	this.y = 0;
	this.clientX = 0;
	this.clientY = 0;
	
	// -- mouse status
	this.keyModel = -1;	//undetermined
	
	this.mouseDown = 0;
	
	
	
	
	// -- private part
	
	var __self = this;
	// -- object dragging
	var draggingObj = null;
	var dragOffsetX = 0;
	var dragOffsetY = 0;
	
	// -- mouse info display
	var dispDiv = document.createElement("div");
	dispDiv.style.zIndex = 1000;
	dispDiv.style.position = "absolute";
	dispDiv.style.color = "black";
	dispDiv.style.fontFamily = "Verdana,Arial,Helvetica";
	dispDiv.style.fontSize = "9pt";
	dispDiv.style.fontWeight = "bold";
	dispDiv.style.padding = "10px";
	dispDiv.style.width = "100px";
	dispDiv.style.height = "50px";
	dispDiv.style.visibility = "hidden";
	
	var mouseDownNotifyQueue = new Array();
	var mouseUpNotifyQueue = new Array();
	var mouseClickNotifyQueue = new Array();
	
	// -- listener
	function hTrackMouseMove(evt)
	{
		var iScrollLeft = document.bal.getScrollLeft();
		var iScrollTop = document.bal.getScrollTop();
		
		if (typeof(evt.pageX) == 'number')
		{
			__self.x = evt.pageX;
			__self.y = evt.pageY;
			__self.clientX = __self.x - iScrollLeft;
			__self.clientY = __self.y - iScrollTop;
		}
		else
		{
			__self.x = evt.clientX + iScrollLeft;
			__self.y = evt.clientY + iScrollTop;
			__self.clientX = evt.clientX;
			__self.clientY = evt.clientY;
		}
		
		// -- mouse pos display
		dispDiv.style.left = __self.x + 5;
		dispDiv.style.top = __self.y + 5;
		dispDiv.innerHTML = "(" + __self.x + ", " + __self.y + ")";
		
		if (draggingObj && draggingObj.setPosition)
		{
			draggingObj.setPosition(__self.x - dragOffsetX, __self.y - dragOffsetY);
			evt.preventDefault();
			evt.stopPropagation();
			return false;
		}
		return true;
	}
	document.bal.installHandler(document.bal.body, evt_onmousemove, hTrackMouseMove, true);	//capture
	
	function hTrackMouseDown(evt)
	{
		if (evt.oriButton > 7 || evt.oriButton == 0)
		{
			if (__self.keyModel != -1) __self.keyModel = BROWSER_MOZILLA;
		}
		else if (evt.oriButton == 3 || evt.oriButton == 5 || evt.oriButton == 7)	//combination
		{
			if (__self.keyModel != -1) __self.keyModel = BROWSER_IEXPLORER;
		}
		
		var idx = 0;
		while (idx < mouseDownNotifyQueue.length)
		{
			if (!mouseDownNotifyQueue[idx].gMouseDown(__self.x, __self.y))
			{
				mouseDownNotifyQueue.splice(idx, 1);
				continue;
			}
			else
			{
				idx++;
			}
		}
	}
	document.bal.installHandler(document.bal.body, evt_onmousedown, hTrackMouseDown, true);	//capture
	
	function hTrackMouseUp(evt)
	{
		if (draggingObj)
		{
			if ('function' == typeof(draggingObj.dragStop)) draggingObj.dragStop();
			draggingObj = null;
		}
		dragOffsetX = 0;
		dragOffsetY = 0;
		
		var idx = 0;
		while (idx < mouseUpNotifyQueue.length)
		{
			if (!mouseUpNotifyQueue[idx].gMouseUp(__self.x, __self.y))
			{
				
				mouseUpNotifyQueue.splice(idx, 1);
				continue;
			}
			else
			{
				idx++;
			}
		}
	}
	document.bal.installHandler(document.bal.body, evt_onmouseup, hTrackMouseUp, true);	//capture
	
	function hTrackMouseClick(evt)
	{
		var idx = 0;
		while (idx < mouseClickNotifyQueue.length)
		{
			if (!mouseUpNotifyQueue[idx].gClick(__self.x, __self.y))
			{
				mouseUpNotifyQueue.splice(idx, 1);
				continue;
			}
			else
			{
				idx++;
			}
		}
	}
	document.bal.installHandler(document.bal.body, evt_onclick, hTrackMouseClick, true);	//capture
	
	
	this.dragObject = function (obj)
	{
		if (typeof(obj) == 'object' && obj.isFloating())
		{
			if ('function' == typeof(obj.dragStart)) obj.dragStart();
			dragOffsetX = __self.x - obj.getPosX();
			dragOffsetY = __self.y - obj.getPosY();
			//obj.changeZIndex(DRAGPROMOTION);
			draggingObj = obj;
		}
	}
	this.registerMouseDown = function(obj)
	{
		for (var i = 0; i < mouseDownNotifyQueue.length; ++i)
		{
			if (mouseDownNotifyQueue[i] == obj) return;
		}
		mouseDownNotifyQueue.push(obj);
	}
	
	this.unRegisterMouseDown = function(obj)
	{
		for (var i = 0; i < mouseDownNotifyQueue.length; ++i)
		{
			if (mouseDownNotifyQueue[i] == obj)
			{
				mouseDownNotifyQueue.splice(i, 1);
				return;
			}
		}
	}
	
	
	this.registerMouseUp = function(obj)
	{
		for (var i = 0; i < mouseUpNotifyQueue.length; ++i)
		{
			if (mouseUpNotifyQueue[i] == obj) return;
		}
		mouseUpNotifyQueue.push(obj);
	}
	
	this.unRegisterMouseUp = function(obj)
	{
		for (var i = 0; i < mouseUpNotifyQueue.length; ++i)
		{
			if (mouseUpNotifyQueue[i] == obj)
			{
				mouseUpNotifyQueue.splice(i, 1);
				return;
			}
		}
	}
	
	this.registerClick = function(obj)
	{
		for (var i = 0; i < mouseClickNotifyQueue.length; ++i)
		{
			if (mouseClickNotifyQueue[i] == obj) return;
		}
		mouseClickNotifyQueue.push(obj);
	}
	
	this.unRegisterClick = function(obj)
	{
		for (var i = 0; i < mouseClickNotifyQueue.length; ++i)
		{
			if (mouseClickNotifyQueue[i] == obj)
			{
				mouseClickNotifyQueue.split(i, 1);
				return;
			}
		}
	}
	
	this.displayMousePosition = function (b)
	{
		if (b)
		{
			if (dispDiv.style.visibility == "visible") return;
			document.bal.body.appendChild(dispDiv);
			dispDiv.style.visibility = "visible"
		}
		else
		{
			if (dispDiv.style.visibility == "hidden") return;
			document.bal.body.removeChild(dispDiv);
			dispDiv.style.visibility = "hidden";
		}
	}
	
	this.stopTracking = function()
	{
		document.bal.removeHandler(document.bal.body, evt_onmousemove, hTrackMouse, true);	//capture
	}
}


function _scroll_tracking()	//to support sticky elements
{
	this.scrollLeft = document.bal.getScrollLeft();
	this.scrollTop = document.bal.getScrollTop();
	
	
	var __self = this;
	var lastScrollLeft = this.scrollLeft;
	var lastScrollTop = this.scrollTop;
	
	var stickyObjs = new Array();
	
	
	function hTrackingScroll(evt)
	{
		//alert("scrolling!");
		__self.scrollLeft = document.bal.getScrollLeft();
		__self.scrollTop = document.bal.getScrollTop();
		
		if (stickyObjs.length > 0)
		{
			for (var i = 0; i < stickyObjs.length; ++i)
			{
				stickyObjs[i].setPosition(stickyObjs[i].getPosX() + __self.scrollLeft - lastScrollLeft,  stickyObjs[i].getPosY() + __self.scrollTop - lastScrollTop);
			}
		}
		lastScrollLeft = __self.scrollLeft;
		lastScrollTop = __self.scrollTop;
	}
	if (window.ActiveXObject)	//chance are IE style
	{
		document.bal.installHandler(document.bal.body, evt_onscroll, hTrackingScroll, true);
	}
	else	//Mozilla
	{
		document.bal.installHandler(document, evt_onscroll, hTrackingScroll, true);
	}
	
	this.registerSticky = function (obj)
	{
		if (typeof(obj) == 'object')
		{
			for (var i = 0; i < stickyObjs.length; ++i)
			{
				if (obj == stickyObjs[i]) return;
			}
			stickyObjs.push(obj);
			
			obj.sticky = true;	//set sticky flag
			obj.incZIndex(SCROLLABLEOBJLAYER);
			obj.oriZIndex = parseInt(obj.divHolder.style.zIndex);
		}
	}
	
	this.unregisterSticky = function (obj)
	{
		if (typeof(obj) == 'object')
		{
			for (var i = 0; i < stickyObjs.length; ++i)
			{
				if (stickyObjs[i] == obj)
				{
					stickyObjs.splice(i, 1);
					break;
				}
			}
		}
	}
}


function initBal()
{
	document.bal = new _bal();
	
	document.bal.mouse = new _mouse_tracking();
	document.bal.scroll = new _scroll_tracking();
	if (dimInitCalls.length > 0)
	{
		for (var i = 0; i < dimInitCalls.length; ++i)
		{
			dimInitCalls[i]();
		}
	}
	window.init();
	//if (window.init)
	//{
	//	alert("Calling init()");
	//	window.init();
	//}
}

function finiBal()
{
	if (window.fini) window.fini();
	dimInitCalls.length = 0;
	document.bal = null;
}


/***********************************************************************************
//	report system, use a new window to display results
***********************************************************************************/

function jsDebugReport(winName, posX, posY, w, h)
{	
	this.open(winName, posX, posY, w, h);
}


jsDebugReport.addMethod("open",
	function (winName, posX, posY, w, h)
	{
		if (this.msgWindow && !this.msgWindow.closed) this.msgWindow.close();
		this.initPosX = typeof(posX) == 'number'?posX:400;
		this.initPosY = typeof(posY) == 'number'?posY:0;
		this.initW = typeof(w) == 'number'?w:400;
		this.initH = typeof(h) == 'number'?h:600;
		
		this.winName = winName ? winName : "";
		
		var featStr = "left=" + this.initPosX + ",top=" + this.initPosY + ",width=" + this.initW + ",height=" + this.initH + ",resizable=yes,scrollbars=yes";
	
		this.msgWindow = window.open("", this.winName, featStr);
		
		this.msgWindow.document.body.innerHTML = "Debug -- " + (this.winName ? this.winName : "(no name)");
		
	}
);



jsDebugReport.addMethod("close",
	function ()
	{
		if (this.msgWindow && !this.msgWindow.closed)
			this.msgWindow.close();
		this.msgWindow = null;
	}
);

jsDebugReport.addMethod("report",
	function (msg)
	{
		if (!this.msgWindow || this.msgWindow.closed) this.open();
		this.msgWindow.document.body.innerHTML = msg + "<br>" + this.msgWindow.document.body.innerHTML;
	}
);

jsDebugReport.addMethod("clear",
	function ()
	{
		if (!this.msgWindow || this.msgWindow.closed) this.open();
		this.msgWindow.document.body.innerHTML = "";
	}
);

jsDebugReport.addMethod("insertTimeTag",
	function ()
	{
		if (!this.msgWindow || this.msgWindow.closed) this.open();
		var now = new Date();
		this.msgWindow.document.body.innerHTML = now.getMinutes().toString() + ":" + now.getSeconds().toString() + ":" + now.getMilliseconds().toString() + "<br>" + this.msgWindow.document.body.innerHTML;
	}
);

/***********************************************************************************
//	a universal container, provide cross-platform margin/border/padding calculation
//	using the microsoft way (inward). it also provide flexible visual setup (multi-
//	layer background, shadow settings, delayed show and hide, callback registering 
//	before show and hide, final position adjustment, etc)
***********************************************************************************/
var CONTAINER_BGEXT_MARGIN = 0;
var CONTAINER_BGEXT_BORDER = 1;
var CONTAINER_BGEXT_PADDING = 2;
var CONTAINER_BGEXT_EFFECTIVE = 3;

// -- for floating 
// -- zindex layer

var currentActive = null;
function setCurrentActive(obj)
{
	if (currentActive == obj) return;
	if (currentActive && currentActive.setZIndex)
	{
		currentActive.setZIndex(currentActive.oriZIndex);
		if (obj.zChange) obj.zChange(currentActive.oriZIndex);
		currentActive = null;
	}
	if (obj && obj.setZIndex)
	{
		if (obj.oriZIndex >= ACTIVEOBJLAYER) return;
		obj.setZIndex(ACTIVEOBJLAYER);
		if (obj.zChange) obj.zChange(ACTIVEOBJLAYER);
		currentActive = obj;
		
	}
}

function findTreeTop(container)
{
	if (!container) return null;
	var treeTop = container;
	while (treeTop.treeParent) treeTop = treeTop.treeParent;
	return treeTop;
}


function jsContainerStyle()
{
	// -- top, right, bottom, left
	this.margin = "0px 0px 0px 0px";
	this.borderTop = "0px solid white";
	this.borderRight = "0px solid white";
	this.borderBottom = "0px solid white";
	this.borderLeft = "0px solid white";
	this.borderOpacity = 100;
	this.padding = "0px 0px 0px 0px";
	this.bgColor = "";
	this.bgImage = "";	//"url repeat attachment position "
	this.bgExtend = "0 0 0 0";	//0 == margin, 1 == border, 2 == padding, 3 == effective
	this.bgOpacity = 100;
	this.bodyBgColor = "";
	this.bodyBgImage = "";
	this.bodyOpacity = 100;
	this.borderBgColor = "";
	this.borderBgImage = "";
	
	this.dropShadow = "";	// if anything, will enable. format like that: "color offX offY"
	this.autoSize = 3;	//0 == none, 1 = width, 2 = height, 3 = both
}


function jsContainer()
{
	var __self = this;	//internal reference
	this.thisClass = "jsContainer";
	this.installedEvents = new Array();
	this.oHostNode = null;
	this.treeParent = null;
	this.oriZIndex = 0;
	
	this.iOuterWidth = 50;
	this.iOuterHeight = 50;
	// -- order is: top, right, bottom, left
	this.dimPadding = new Array(0, 0, 0, 0);
	this.dimBorderWidth = new Array(0, 0, 0, 0);
	this.dimMargin = new Array(0, 0, 0, 0);
	this.dimBgExtend = new Array(CONTAINER_BGEXT_MARGIN, CONTAINER_BGEXT_MARGIN, CONTAINER_BGEXT_MARGIN, CONTAINER_BGEXT_MARGIN);
	
	// -- display elements
	this.divHolder = document.createElement("div");
	this.divHolder.style.cursor = "default";
	this.divHolder.wrapObj = this;
	this.divHolder.style.visibility = "hidden";
	this.divHolder.style.left = "0px";
	this.divHolder.style.top = "0px";
	this.divHolder.style.fontSize = "0px";
	
	this.divEffectShadow = document.createElement("div");
	this.divEffectShadow.style.position = "absolute";
	this.divEffectShadow.style.visibility = "hidden";
	this.divEffectShadow.style.left = "0px";
	this.divEffectShadow.style.top = "0px";
	this.divEffectShadow.style.fontSize = "0px";
	this.divHolder.appendChild(this.divEffectShadow);
	
	this.divBorderShadow = document.createElement("div");
	this.divBorderShadow.style.position = "absolute";
	this.divBorderShadow.style.visibility = "hidden";
	this.divBorderShadow.style.left = "0px";
	this.divBorderShadow.style.top = "0px";
	this.divBorderShadow.style.fontSize = "0px";
	this.divHolder.appendChild(this.divBorderShadow);
	
	this.divBgShadow = document.createElement("div");
	this.divBgShadow.style.position = "absolute";
	this.divBgShadow.style.visibility = "hidden";
	this.divBgShadow.style.left = "0px";
	this.divBgShadow.style.top = "0px";
	this.divBgShadow.style.fontSize = "0px";
	this.divHolder.appendChild(this.divBgShadow);
	
	
	this.divBackground = document.createElement("div");
	this.divBackground.style.position = "absolute";
	this.divBackground.style.left = "0px";
	this.divBackground.style.top = "0px";
	this.divBackground.style.fontSize = "0px";
	this.divHolder.appendChild(this.divBackground);	//first to append, guarranteed at the bottom
	
	this.divBorder = document.createElement("div");
	this.divBorder.style.position = "absolute";
	this.divBorder.style.fontSize = "0px";
	this.divHolder.appendChild(this.divBorder);
	
	this.divEffective = document.createElement("div");
	this.divEffective.wrapObj = this;
	this.divEffective.style.position = "absolute";
	this.divEffective.style.padding = "0px";
	this.divEffective.style.fontSize = "0px";
	this.divHolder.appendChild(this.divEffective);
	
	this.divSolidCover = document.createElement("div");
	
	this.divSolidCover = document.createElement("div");
	this.divSolidCover.style.position = "absolute";
	this.divHolder.appendChild(this.divSolidCover);
	this.divSolidCover.style.cursor = "default";
	this.divSolidCover.wrapObj = this;
	this.divSolidCover.style.visibility = "hidden";
	this.divSolidCover.style.fontSize = "0px";
	if (window.ActiveXObject)	//stupid IE
	{
		this.divSolidCover.style.backgroundColor = "white";
		document.bal.setObjOpacity(this.divSolidCover, 0);
	}
	
	// -- delayed show
	this.iTidShow = null;
	//this.showCallBack = null;
	
	// -- delayed hide
	this.iTidHide = null;
	//this.hideCallBack = null;
	
	//this.fnMaxDispAdjust = null;
	this.dimHiddenSelects = new Array();
	
	this.effDivX = 0;
	this.effDivY = 0;
	
	
	// -- debug
	//this.divHolder.style.backgroundColor = "#CCCCFF";
	//this.divHolder.style.backgroundCOlor = "#CCCCFF";
	
	// -- private part
	
	
	this.fnDelayedShow = function ()
	{
		__self.iTidShow = null;
		__self._show();
	}
	
	
	this.fnDelayedHide = function ()
	{
		__self.iTidHide = null;
		__self._hide();
	}
	
	// -- strictly call this virtual function
	//if (myStyle) this.applyStyle(myStyle);	//supposed to be style
	this.setDefaultStyle();
	this.setZIndex(NONTOPOBJLAYER);
	this.oriZIndex = NONTOPOBJLAYER;
	document.bal.installHandler(this.divHolder, evt_onmousedown, this.hHolderMouseDown, false);

}

jsContainer.prototype.protoStyle = new jsContainerStyle();	//protostyle 

function hDummyCallBack()
{}

jsContainer.addMethod("gMouseDown", hDummyCallBack);
jsContainer.addMethod("gMouseUp", hDummyCallBack);
jsContainer.addMethod("gClick", hDummyCallBack);

jsContainer.addMethod("hHolderMouseDown",
	function (evt)
	{
		var holder = evt.currentTarget;
		var obj = holder.wrapObj;
		while (obj.treeParent) obj = obj.treeParent;
		if (holder.parentNode != document.bal.body) return;
		if (obj.draggable)
		{
			setCurrentActive(obj);
		}
	}
);

jsContainer.addMethod("hMouseDownDrag",
	function (evt)
	{
		document.bal.mouse.dragObject(evt.currentTarget.dragTarget);
	}
);


jsContainer.addMethod("registerDrag",
	function (senseObj, bCapture)	//object that receives mouse down 
	{
		if (senseObj && senseObj.tagName)
		{
			senseObj.dragTarget = this;
			this.dragSensor = senseObj;
			this.dragSensor.bCap = bCapture;
			this.incZIndex(DRAGGABLEOBJLAYER);
			this.oriZIndex = parseInt(this.divHolder.style.zIndex);
			this.draggable = true;
			document.bal.installHandler(senseObj, evt_onmousedown, this.hMouseDownDrag, bCapture);
		}
	}
);

jsContainer.addMethod("unRegisterDrag",
	function ()	//object that receives mouse down 
	{
		if (this.draggable)
		{
			this.setZIndex(this.oriZIndex);
			this.draggable = false;
			document.bal.removeHandler(this.dragSensor, evt_onmousedown, this.hMouseDownDrag, this.dragSensor.bCap);
			this.dragSensor = null;
		}
	}
);



jsContainer.addMethod("isActive",	
	function ()
	{
		return this.divHolder.style.visibility == "visible";
	}
);

jsContainer.addMethod("setSolid",
	function (bSolid)
	{
		if (bSolid)
		{
			if (this.divSolidCover.style.visibility == "visible") return;
			else
			{
				this.divSolidCover.style.visibility = "visible";
				for (var i = 0; i < this.installedEvents.length; ++i)
				{
					document.bal.removeHandler(this.divHolder, this.installedEvents[i].evt, this.installedEvents[i].fnHandler, this.installedEvents[i].bCapture);
					document.bal.InstallHandler(this.divSolidCover, this.installedEvents[i].evt, this.installedEvents[i].fnHandler, this.installedEvents[i].bCapture);
				}
			}
		}
		else
		{
			if (this.divSolidCover.style.visibility == "hidden") return;
			else
			{
				this.divSolidCover.style.visibility = "hidden";
				for (var i = 0; i < this.installedEvents.length; ++i)
				{
					document.bal.removeHandler(this.divSolidCover, this.installedEvents[i].evt, this.installedEvents[i].fnHandler, this.installedEvents[i].bCapture);
					document.bal.InstallHandler(this.divHolder, this.installedEvents[i].evt, this.installedEvents[i].fnHandler, this.installedEvents[i].bCapture);
				}
			}
		}
	}
);

jsContainer.addMethod("handleEvent",
	function (evt, fnHandler, bCapture)
	{
		
		
		for (var i = 0; i < this.installedEvents.length; ++i)
		{
			if (this.installedEvents[i].evt == evt && this.installedEvents[i].fnHandler == fnHandler && this.installedEvents[i].bCapture == (bCapture?true:false))
				return;
		}
		var newEvt = new Object();
		newEvt.evt = evt;
		newEvt.fnHandler = fnHandler;
		newEvt.bCapture = bCapture?true:false;
		this.installedEvents.push(newEvt);
		
		
		if (this.divSolidCover.style.visibility == "visible")document.bal.installHandler(this.divSolidCover, evt, fnHandler, bCapture);
		else document.bal.installHandler(this.divHolder, evt, fnHandler, bCapture);
	}
);

jsContainer.addMethod("releaseEvent",
	function (evt, fnHandler, bCapture)
	{
		for (var i = 0; i < this.installedEvents.length; ++i)
		{
			if (this.installedEvents[i].evt == evt && this.installedEvents[i].fnHandler == fnHandler && this.installedEvents[i].bCapture == (bCapture?true:false))
				this.installedEvents.splice(i, 1);
				
			document.bal.removeHandler(this.divSolidCover, evt, fnHandler, bCapture);
			document.bal.removeHandler(this.divHolder, evt, fnHandler, bCapture);
		}
		
	}
);


jsContainer.addMethod("switchBorder",
	function ()
	{
		this.flatenBorder();	//refundent -- just for stupid Opera
		this.divBorder.style.borderTop = this.myStyle.borderBottom;
		this.divBorder.style.borderBottom = this.myStyle.borderTop;
		this.divBorder.style.borderLeft = this.myStyle.borderRight;
		this.divBorder.style.borderRight = this.myStyle.borderLeft;
	}
);

jsContainer.addMethod("restoreBorder",
	function ()
	{
		this.flatenBorder();	//refundent -- just for stupid Opera
		this.divBorder.style.borderTop = this.myStyle.borderTop;
		this.divBorder.style.borderBottom = this.myStyle.borderBottom;
		this.divBorder.style.borderLeft = this.myStyle.borderLeft;
		this.divBorder.style.borderRight = this.myStyle.borderRight;
	}
);

jsContainer.addMethod("flatenBorder",
	function ()
	{
		this.divBorder.style.borderTop = "0px solid white";
		this.divBorder.style.borderBottom = "0px solid white";
		this.divBorder.style.borderLeft = "0px solid white";
		this.divBorder.style.borderRight = "0px solid white";
	}
);

jsContainer.addMethod("adjustDisplay",
	function ()
	{
		var inTree = document.bal.isInTree(this.divHolder);
		var isVisible = this.isActive();
		var curHost = this.divHolder.parentNode;
		if (!inTree)
		{
			if (curHost) curHost.removeChild(this.divHolder);
			this.divHolder.style.visibility = "hidden";
			document.bal.body.appendChild(this.divHolder);	//put in tree
		}  
		if (this.myStyle.autoSize & 3)
		{
		
			var neededWidth = 0;
			var neededHeight = 0;
			for (var i = 0; i < this.divEffective.childNodes.length; ++i)
			{
				
				var widthExt = this.divEffective.childNodes[i].offsetLeft + this.divEffective.childNodes[i].offsetWidth;
				var heightExt = this.divEffective.childNodes[i].offsetTop + this.divEffective.childNodes[i].offsetHeight;
				if (neededWidth < widthExt) neededWidth = widthExt;
				if (neededHeight < heightExt) neededHeight = heightExt;
			}
			
			if (this.myStyle.autoSize & 1) this.iOuterWidth = neededWidth + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3] + this.dimPadding[1] + this.dimPadding[3];
			if (this.myStyle.autoSize & 2) this.iOuterHeight = neededHeight + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2] + this.dimPadding[0] + this.dimPadding[2];
		}
		
		
		this.divBorder.style.left = this.dimMargin[3] + "px";
		this.divBorder.style.top = this.dimMargin[0] + "px";
		if (document.bal.bW3CPadding)	//outer padding
		{
			this.divBorder.style.width = (this.iOuterWidth - this.dimMargin[3] - this.dimMargin[1] - this.dimBorderWidth[3] - this.dimBorderWidth[1]) + "px";
			this.divBorder.style.height = (this.iOuterHeight - this.dimMargin[2] - this.dimMargin[0] - this.dimBorderWidth[2] - this.dimBorderWidth[0]) + "px";
		}
		else
		{
			this.divBorder.style.width = (this.iOuterWidth - this.dimMargin[3] - this.dimMargin[1]) + "px";
			this.divBorder.style.height = (this.iOuterHeight - this.dimMargin[2] - this.dimMargin[0]) + "px";
		}
		
		// -- record newly adjusted effective
		this.effDivX = this.dimMargin[3] + this.dimBorderWidth[3] + this.dimPadding[3];
		this.effDivY = this.dimMargin[0] + this.dimBorderWidth[0] + this.dimPadding[0];
		this.divEffective.style.left = this.effDivX + "px";
		this.divEffective.style.top = this.effDivY + "px";
		this.divEffective.style.width = (this.iOuterWidth - this.dimMargin[3] - this.dimBorderWidth[3] - this.dimPadding[3] - this.dimMargin[1] - this.dimBorderWidth[1] - this.dimPadding[1]) + "px";

		this.divEffective.style.height = (this.iOuterHeight - this.dimMargin[0] - this.dimBorderWidth[0] - this.dimPadding[0] - this.dimMargin[2] - this.dimBorderWidth[2] - this.dimPadding[2]) + "px";
		
		
		this.divHolder.style.width = this.iOuterWidth + "px";
		this.divHolder.style.height = this.iOuterHeight + "px";
		
		this.divSolidCover.style.left = 0;
		this.divSolidCover.style.top = 0;
		this.divSolidCover.style.width = this.divHolder.style.width;
		this.divSolidCover.style.height = this.divHolder.style.height;
			
		var iStart = 0;
		switch (this.dimBgExtend[0])	//top
		{
		case CONTAINER_BGEXT_BORDER:
			iStart = this.dimMargin[0];
			break;
		case CONTAINER_BGEXT_PADDING:
			iStart = this.dimMargin[0] + this.dimBorderWidth[0];
			break;
		case CONTAINER_BGEXT_EFFECTIVE:
			iStart = this.dimMargin[0] + this.dimBorderWidth[0] + this.dimPadding[0];
			break;
		default:
			this.divBackground.style.top = "0px";
			iStart = 0;
		}
		this.divBackground.style.top = iStart + "px";
		
		
		switch (this.dimBgExtend[2])	//bottom
		{
		case CONTAINER_BGEXT_BORDER:
			this.divBackground.style.height = (this.iOuterHeight - this.dimMargin[2] - iStart) + "px";
			break;
		case CONTAINER_BGEXT_PADDING:
			this.divBackground.style.height = (this.iOuterHeight - this.dimMargin[2] - this.dimBorderWidth[2] - iStart) + "px";
			break;
		case CONTAINER_BGEXT_EFFECTIVE:
			this.divBackground.style.height = (this.iOuterHeight - this.dimMargin[2] - this.dimBorderWidth[2] - this.dimPadding[2] - iStart) + "px";
			break;
		default:
			this.divBackground.style.height = (this.iOuterHeight - iStart) + "px";
		}
		
		switch (this.dimBgExtend[3])	//left
		{
		case CONTAINER_BGEXT_BORDER:
			iStart = this.dimMargin[3];
			break;
		case CONTAINER_BGEXT_PADDING:
			iStart = this.dimMargin[3] + this.dimBorderWidth[3];
			break;
		case CONTAINER_BGEXT_EFFECTIVE:
			iStart = this.dimMargin[3] + this.dimBorderWidth[3] + this.dimPadding[3];
			break;
		default:
			iStart = 0;
		}
		this.divBackground.style.left = iStart + "px";
		
		switch (this.dimBgExtend[1])	//bottom
		{
		case CONTAINER_BGEXT_BORDER:
			this.divBackground.style.width = (this.iOuterWidth - this.dimMargin[1] - iStart) + "px";
			break;
		case CONTAINER_BGEXT_PADDING:
			this.divBackground.style.width = (this.iOuterWidth - this.dimMargin[1] - this.dimBorderWidth[1] - iStart) + "px";
			break;
		case CONTAINER_BGEXT_EFFECTIVE:
			this.divBackground.style.width = (this.iOuterWidth - this.dimMargin[1] - this.dimBorderWidth[1] - this.dimPadding[1] - iStart) + "px";
			break;
		default:
			this.divBackground.style.width = (this.iOuterWidth - iStart) + "px";
		}
		
		// -- shadow
		
		if (this.myStyle.dropShadow && this.myStyle.dropShadow != "")
		{
			var buf = this.myStyle.dropShadow.split(" ");
			var offX = parseInt(buf[1]);
			var offY = parseInt(buf[2]);
			this.divEffectShadow.style.left = (this.divEffective.offsetLeft + offX) + "px";
			this.divEffectShadow.style.top = (this.divEffective.offsetTop + offY) + "px";
			this.divEffectShadow.style.width = this.divEffective.offsetWidth;
			this.divEffectShadow.style.height = this.divEffective.offsetHeight;
			
			
			this.divBorderShadow.style.left = (this.divBorder.offsetLeft + offX) + "px";
			this.divBorderShadow.style.top = (this.divBorder.offsetTop + offY) + "px";
			this.divBorderShadow.style.width = this.divBorder.style.width;
			this.divBorderShadow.style.height = this.divBorder.style.height;
			
			this.divBgShadow.style.left = (this.divBackground.offsetLeft + offX) + "px";
			this.divBgShadow.style.top = (this.divBackground.offsetTop + offY) + "px";
			this.divBgShadow.style.width = this.divBackground.offsetWidth;
			this.divBgShadow.style.height = this.divBackground.offsetHeight;
			
			this.divHolder.style.width = (this.iOuterWidth + offX) + "px";
			this.divHolder.style.height = (this.iOuterHeight + offY) + "px";
			
			this.adjustShadowColor();
		}
		
		if (!inTree)
		{
			document.bal.body.removeChild(this.divHolder);
			if (curHost) curHost.appendChild(this.divHolder);
			if (isVisible) this.divHolder.style.visibility = "visible";
		}
		
	}
);

jsContainer.addMethod("setTotalOpacity",
	function (op)
	{
		if (typeof(op) == 'number')
		{
			var eff_op = op;
			if (eff_op < 0) eff_op = 0;
			else if (eff_op > 100) eff_op = 100;
			document.bal.setObjOpacity(this.divHolder, eff_op);
		}
	}
);

jsContainer.addMethod("setEffectOfs",
	function(dx, dy)
	{
		this.divEffective.style.left = (this.effDivX + dx) + "px";
		this.divEffective.style.top = (this.effDivY + dy) + "px";
	}
);

jsContainer.addMethod("adjustShadowColor",
	function ()
	{
		
		if (this.myStyle.dropShadow)
		{
			var buf = this.myStyle.dropShadow.split(" ");
			
			this.divEffectShadow.style.backgroundColor = buf[0];
			document.bal.setObjOpacity(this.divEffectShadow, (this.myStyle.bodyOpacity / 4).toFixed());
			
			this.divBorderShadow.style.borderTop = this.divBorder.style.borderTop;
			this.divBorderShadow.style.borderRight = this.divBorder.style.borderRight;
			this.divBorderShadow.style.borderBottom = this.divBorder.style.borderBottom;
			this.divBorderShadow.style.borderLeft = this.divBorder.style.borderLeft;
			this.divBorderShadow.style.borderColor = buf[0];
			this.divBorderShadow.style.borderStyle = "solid";
			if (this.divBorder.style.backgroundColor != "" || this.divBorder.style.backgroundImage != "") this.divBorderShadow.style.backgroundColor = buf[0];
			else this.divBorderShadow.style.backgroundColor = "";
			document.bal.setObjOpacity(this.divBorderShadow, (this.myStyle.borderOpacity / 4).toFixed());
			
			if (this.divBackground.style.backgroundColor != "" || this.divBackground.style.backgroundImage != "") this.divBgShadow.style.backgroundColor = buf[0];
			else this.divBgShadow.style.backgroundColor = "";
			document.bal.setObjOpacity(this.divBgShadow, (this.myStyle.bgOpacity / 2).toFixed());
		}
	}
);

jsContainer.addMethod("isFloating",
	function ()
	{
		return this.oHostNode == document.bal.body && this.divHolder.style.position == "absolute";
	}
);

jsContainer.addMethod("show",
	function (iDelay)
	{
		if (iDelay && typeof(iDelay) == 'number' && iDelay > 0)
		{
			if (this.iTidShow) clearTimeout(this.iTidShow);	//clear unfinished countdown
			// -- setup countdown. which will call this function without delay
			this.iTidShow = setTimeout(this.fnDelayedShow, iDelay);
		}
		else
		{
			this._show();
		}
	}
);

jsContainer.addMethod("_show",
	function ()
	{
		var bDoShow = true;
		if (this.showCallBack && typeof(this.showCallBack) == 'function')
		{
			bDoShow = this.showCallBack();
		}
		if (bDoShow)
		{
			this.adjustDisplay();
			if (this.fnMaxDispAdjust && typeof(this.fnMaxDispAdjust) == 'function')
			{
				this.fnMaxDispAdjust(document.bal.getObjPosX(this.divHolder), document.bal.getObjPosY(this.divHolder), this.divHolder.offsetWidth, this.divHolder.offsetHeight);
			}
			this.divHolder.style.visibility = "visible";
			if (this.myStyle.dropShadow && this.myStyle.dropShadow != "")
			{
				this.divEffectShadow.style.visibility = "visible";
				this.divBorderShadow.style.visibility = "visible";
				this.divBgShadow.style.visibility = "visible";
			}
			
			// -- deal with ActiveXObject bug
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("hide",
	function (iDelay)
	{
		if (iDelay && typeof(iDelay) == 'number' && iDelay > 0)
		{
			if (this.iTidHide) clearTimeout(this.iTidHide);	//clear unfinished countdown
			// -- setup countdown. which will call this function without delay
			this.iTidHide = setTimeout(this.fnDelayedHide, iDelay);
		}
		else	//display
		{
			this._hide();
		}
	}
);

jsContainer.addMethod("_hide",
	function ()
	{
		var bDoHide = true;
		if (this.hideCallBack && typeof(this.hideCallBack) == 'function')
		{
			bDoHide = this.hideCallBack();
		}
		if (bDoHide)
		{
			this.divBgShadow.style.visibility = "hidden";
			this.divBorderShadow.style.visibility = "hidden";
			this.divEffectShadow.style.visibility = "hidden";
			this.divHolder.style.visibility = "hidden";
			// -- restore hidden selects
			for (var i = 0; i < this.dimHiddenSelects.length; ++i)
			{
				this.dimHiddenSelects[i].style.visibility = "visible";
			}
			this.dimHiddenSelects.length = 0;
		}
	}
);

jsContainer.addMethod("cancelShow",
	
	function ()
	{
		if (this.iTidShow)
		{
			clearTimeout(this.iTidShow);
			this.iTidShow = null;
			return true;
		}
		else return false;
	}
);

jsContainer.addMethod("cancelHide",
	function ()
	{
		if (this.iTidHide)
		{
			clearTimeout(this.iTidHide);
			this.iTidHide = null;
			return true;
		}
		else return false;
	}
);


jsContainer.addMethod("hideOverlapSelects",
	function ()
	{
		if (window.ActiveXObject && this.divHolder.style.visibility == "visible" && document.bal.isInTree(this.divHolder))
		{
			var iZoneLeft = document.bal.getObjPosX(this.divHolder);
			var iZoneTop = document.bal.getObjPosY(this.divHolder);
			var iZoneRight = iZoneLeft + this.divHolder.offsetWidth - 1;
			var iZoneBottom = iZoneTop + this.divHolder.offsetHeight - 1;
		
			var dimAllSelects = document.getElementsByTagName("select");
			if (dimAllSelects.length > 0)
			{
				for (var i = 0; i < dimAllSelects.length; ++i)
				{
					
					var selLeft = document.bal.getObjPosX(dimAllSelects[i]);
					var selTop = document.bal.getObjPosY(dimAllSelects[i]);
					var selRight = selLeft + dimAllSelects[i].offsetWidth - 1;
					var selBottom = selTop + dimAllSelects[i].offsetHeight - 1;
					
					for (var j = 0; j < this.dimHiddenSelects.length; ++j)
					{
						if (this.dimHiddenSelects[j] == dimAllSelects[i])
						{
							if (!((selLeft >= iZoneLeft && selLeft <= iZoneRight && selTop >= iZoneTop && selTop <= iZoneBottom) ||
							(selRight >= iZoneLeft && selRight <= iZoneRight && selTop >= iZoneTop && selTop <= iZoneBottom) ||
							(selLeft >= iZoneLeft && selLeft <= iZoneRight && selBottom >= iZoneTop && selBottom <= iZoneBottom) ||
							(selRight >= iZoneLeft && selRight <= iZoneRight && selBottom >= iZoneTop && selBottom <= iZoneBottom)))
							{
								dimAllSelects[i].style.visibility = "visible";
								this.dimHiddenSelects.splice(j, 1);	//remove from array
							}
							return;
						}
					}
					// -- not found
					if ((selLeft >= iZoneLeft && selLeft <= iZoneRight && selTop >= iZoneTop && selTop <= iZoneBottom) ||
					(selRight >= iZoneLeft && selRight <= iZoneRight && selTop >= iZoneTop && selTop <= iZoneBottom) ||
					(selLeft >= iZoneLeft && selLeft <= iZoneRight && selBottom >= iZoneTop && selBottom <= iZoneBottom) ||
					(selRight >= iZoneLeft && selRight <= iZoneRight && selBottom >= iZoneTop && selBottom <= iZoneBottom))	//overlap
					{
						if (dimAllSelects[i].style.visibility != "hidden")	//visible
						{
							dimAllSelects[i].style.visibility = "hidden";
							this.dimHiddenSelects.push(dimAllSelects[i]);
						}
					}
				}  
			}
		}
	}
);

jsContainer.addMethod("parentChanged",
	function (newParent)
	{
		var lastHost = this.oHostNode;
		this.oHostNode = newParent;
		return lastHost;
	}
);

jsContainer.addMethod("childNodeChanged",
	function ()
	{
		this.adjustDisplay();
		if (this.divHolder.parentNode && this.divHolder.parentNode.wrapObj && this.divHolder.parentNode.wrapObj.childNodeChanged)
			this.divHolder.parentNode.wrapObj.childNodeChanged();
	}
);

jsContainer.addMethod("makeParent",
	function (oNode)
	{
		if (this.oHostNode == oNode) return;
		var lastHost = this.oHostNode;
		if (this.oHostNode)
		{
			if (this.oHostNode.removeNode)
			{
				this.oHostNode.removeNode(this);
			}
			else if (this.oHostNode.tagName)
			{
				this.oHostNode.removeChild(this.divHolder);
			}
		}
		
		if (oNode)
		{
			if (oNode.addNode)
				oNode.addNode(this);
			else if (oNode.tagName)
			{
				oNode.appendChild(this.divHolder);
				if (oNode.wrapObj && oNode.wrapObj.childNodeChanged)
					oNode.wrapObj.childNodeChanged();
				this.parentChanged(oNode);
					
			}
			
			// -- setup zindex 
			if (oNode != document.bal.body)	//non-top
				this.incZIndex(NONTOPOBJLAYER);
			else
				this.incZIndex(STATICFLOATINGLAYER);
		}
		return lastHost;
	}
);



jsContainer.addMethod("addNode",
	
	function (oNode)
	{
		if (oNode)
		{
			if (oNode.divHolder)
			{
				this.divEffective.appendChild(oNode.divHolder);
				if (oNode.parentChanged)
					oNode.parentChanged(this);
			}
			else if (oNode.tagName)
			{
				this.divEffective.appendChild(oNode);
				if (oNode.wrapObj && oNode.wrapObj.parentChanged)
					oNode.wrapObj.parentChanged(this);
			}
			this.childNodeChanged();
		}
	}
); 

jsContainer.addMethod("removeNode",
	
	function (oNode)
	{
		
		var dispNode = oNode.divHolder ? oNode.divHolder : oNode;
		for (var i = 0; i < this.divEffective.childNodes.length; ++i)
		{
			if (this.divEffective.childNodes[i] == dispNode)
			{
				this.divEffective.removeChild(oNode);
				
				if (oNode.parentChanged)
					oNode.parentChanged(null);
				else if (oNode.wrapObj && oNode.wrapObj.parentChanged)
					oNode.wrapObj.parentChanged();
				
				this.childNodeChanged();
				return;
			}
		}
	}
); 

jsContainer.addMethod("writeHTML",
	function (strHTML)
	{
		this.divEffective.innerHTML = strHTML;
		this.childNodeChanged();
	}
); 

jsContainer.addMethod("appendHTML",
	
	function (strHTML)
	{
		this.divEffective.innerHTML += strHTML;
		this.childNodeChanged();
	}
); 


jsContainer.addMethod("setPosType",
	function (strType)
	{
		var effective = strType.toLowerCase();
		if (effective == "absolute") this.divHolder.style.position = "absolute";
		else this.divHolder.style.position = "relative";
		
	}
);

jsContainer.addMethod("setPositionX",
	function (x)
	{
		var x0 = document.bal.getObjPosX(this.divHolder);
		if (typeof(x) == 'number')
		{
			this.divHolder.style.left = x + "px";
		}
		else if (x)
		{
			this.divHolder.style.left = x;
		}
		this.hideOverlapSelects();
		if (this.moveCallBack)
			this.moveCallBack(document.bal.getObjPosX(this.divHolder) - x0, 0);
	}
);

jsContainer.addMethod("setPositionY",
	function (y)
	{
		var y0 = document.bal.getObjPosY(this.divHolder);
		if (typeof(y) == 'number')
		{
			this.divHolder.style.top = y + "px";
		}
		else if (y)
		{
			this.divHolder.style.top = y;
		}
		this.hideOverlapSelects();
		if (this.moveCallBack)
			this.moveCallBack(0, document.bal.getObjPosY(this.divHolder) - y0);
	}
);

jsContainer.addMethod("setPosition",
	function (x, y)
	{
		var x0 = document.bal.getObjPosX(this.divHolder);
		var y0 = document.bal.getObjPosY(this.divHolder);
		
		if (typeof(x) == 'number')
		{
			this.divHolder.style.left = x + "px";
		}
		else if (x)
		{
			this.divHolder.style.left = x;
		}
		if (typeof(y) == 'number')
		{
			this.divHolder.style.top = y + "px";
		}
		else if (y)
		{
			this.divHolder.style.top = y;
		}
		this.hideOverlapSelects();
		// -- notify move
		if (this.moveCallBack)
			this.moveCallBack(document.bal.getObjPosX(this.divHolder) - x0, document.bal.getObjPosY(this.divHolder) - y0);
	}
);

jsContainer.addMethod("setOuterWidth",
	function (w)
	{
		
		if (!(this.myStyle.autoSize & 1))
		{
			if (typeof(w) == 'number')
			{
				this.iOuterWidth = w;
			}
			else
			{
				this.iOuterWidth = document.bal.getLengthInPx(w);
			}
			var miniSize = this.dimPadding[1] + this.dimPadding[3] + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3];
			if (this.iOuterWidth < miniSize) this.iOuterWidth = miniSize;
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("setOuterHeight",
	function (h)
	{
		
		if (!(this.myStyle.autoSize & 2))
		{
			if (typeof(h) == 'number')
			{
				this.iOuterHeight = h;
			}
			else
			{
				this.iOuterHeight = document.bal.getLengthInPx(h);
			}
			var miniSize =  this.dimPadding[0] + this.dimPadding[2] + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2];
			if (this.iOuterHeight < miniSize) this.iOuterHeight = miniSize;
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("setOuterSize",
	function (w, h)
	{
				
		if (!(this.myStyle.autoSize & 1))
		{
			if (typeof(w) == 'number')
			{
				this.iOuterWidth = w;
			}
			else
			{
				this.iOuterWidth = document.bal.getLengthInPx(w);
			}
		}
		if (!(this.myStyle.autoSize & 2))
		{
			if (typeof(h) == 'number')
			{
				this.iOuterHeight = h;
			}
			else
			{
				this.iOuterHeight = document.bal.getLengthInPx(h);
			}
		}
		if (!(this.myStyle.autoSize & 3))
		{
			var miniSize = this.dimPadding[1] + this.dimPadding[3] + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3];
			if (this.iOuterWidth < miniSize) this.iOuterWidth = miniSize;
			
			miniSize =  this.dimPadding[0] + this.dimPadding[2] + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2];
			if (this.iOuterHeight < miniSize) this.iOuterHeight = miniSize;
			
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("setInnerWidth",
	
	function (w)
	{
		
		if (!(this.myStyle.autoSize & 1))
		{
			if (typeof(w) == 'number')
			{
				this.iOuterWidth = w + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3] + this.dimPadding[1] + this.dimPadding[3];
			}
			else
			{
				this.iOuterWidth = document.bal.getLengthInPx(w) + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3] + this.dimPadding[1] + this.dimPadding[3];
			}
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("setInnerHeight",
	function (h)
	{
		
		if (!(this.myStyle.autoSize & 2))
		{
			if (typeof(h) == 'number')
			{
				this.iOuterHeight = h + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2] + this.dimPadding[0] + this.dimPadding[2];
			}
			else
			{
				this.iOuterHeight = document.bal.getLengthInPx(h) + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2] + this.dimPadding[0] + this.dimPadding[2];;
			}
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("setInnerSize",
	
	function (w, h)
	{
		
		if (!(this.myStyle.autoSize & 1))
		{
			if (typeof(w) == 'number')
			{
				this.iOuterWidth = w + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3] + this.dimPadding[1] + this.dimPadding[3];
			}
			else
			{
				this.iOuterWidth = document.bal.getLengthInPx(w) + this.dimMargin[1] + this.dimMargin[3] + this.dimBorderWidth[1] + this.dimBorderWidth[3] + this.dimPadding[1] + this.dimPadding[3];
			}
		}
		if (!(this.myStyle.autoSize & 2))
		{
			if (typeof(h) == 'number')
			{
				this.iOuterHeight = h + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2] + this.dimPadding[0] + this.dimPadding[2];
			}
			else
			{
				this.iOuterHeight = document.bal.getLengthInPx(h) + this.dimMargin[0] + this.dimMargin[2] + this.dimBorderWidth[0] + this.dimBorderWidth[2] + this.dimPadding[0] + this.dimPadding[2];;
			}
		}
		
		if (!(this.myStyle.autoSize & 3) && document.bal.isInTree(this.divHolder))
		{
			this.adjustDisplay();
			this.hideOverlapSelects();
		}
	}
);

jsContainer.addMethod("getPosX",
	
	function ()
	{
		if (this.oHostNode)	// in tree
			return document.bal.getObjPosX(this.divHolder);
		else
			return NaN;
	}
);

jsContainer.addMethod("getPosY",
	function ()
	{
		if (this.oHostNode)	// in tree
			return document.bal.getObjPosY(this.divHolder);
		else
			return NaN;
	}
);

jsContainer.addMethod("getRelativePosX",
	function ()
	{
		if (this.oHostNode)	// in tree
			return this.divHolder.offsetLeft;
		else
			return NaN;
	}
);

jsContainer.addMethod("getRelativePosY",
	function ()
	{
		if (this.oHostNode)	// in tree
			return this.divHolder.offsetTop;
		else
			return NaN;
	}
);

jsContainer.addMethod("getWidth",
	function ()
	{
		if (this.oHostNode)	// in tree
			return this.divHolder.offsetWidth;
		else
			return NaN;
	}
);

jsContainer.addMethod("getHeight",
	function ()
	{
		if (this.oHostNode)	// in tree
			return this.divHolder.offsetHeight;
		else
			return NaN;
	}
);



jsContainer.addMethod("setZIndex",
	function (idx)
	{
		if (typeof(idx) == 'number')
		{
			this.divHolder.style.zIndex = idx;
		}
	}
);

jsContainer.addMethod("changeZIndex",
	function (inc)
	{
		if (this.isFloating())
		{
			var curZ = parseInt(this.divHolder.style.zIndex);
			this.divHolder.style.zIndex = curZ + inc;;
		}
	}
);

jsContainer.addMethod("incZIndex",
	function (topZIdx)
	{
		if (typeof(topZIdx) == 'number')
		{
			var curZ = parseInt(this.divHolder.style.zIndex);
			if (topZIdx > curZ) this.divHolder.style.zIndex = topZIdx;
		}
	}
);

jsContainer.addMethod("set_borderTop",
	function (_val, _noAdj)
	{
		var buf = _val.split(" ");
		this.dimBorderWidth[0] = document.bal.getLengthInPx(buf[0]);
		this.myStyle.borderTop = _val;
		this.divBorder.style.borderTop = _val;
		if (_noAdj) return;
		this.adjustDisplay();
	}
);
jsContainer.addMethod("set_borderRight",
	function (_val, _noAdj)
	{
		var buf = _val.split(" ");
		this.dimBorderWidth[1] = document.bal.getLengthInPx(buf[0]);
		this.myStyle.borderRight = _val;
		this.divBorder.style.borderRight = _val;
		if (_noAdj) return;
		this.adjustDisplay();
	}
);
jsContainer.addMethod("set_borderBottom",
	function (_val, _noAdj)
	{
		var buf = _val.split(" ");
		this.dimBorderWidth[2] = document.bal.getLengthInPx(buf[0]);
		this.myStyle.borderBottom = _val;
		this.divBorder.style.borderBottom = _val;
		if (_noAdj) return;
		this.adjustDisplay();
	}
);
jsContainer.addMethod("set_borderLeft",
	function (_val, _noAdj)
	{
		var buf = _val.split(" ");
		this.dimBorderWidth[3] = document.bal.getLengthInPx(buf[0]);
		this.myStyle.borderLeft = _val;
		this.divBorder.style.borderLeft = _val;
		if (_noAdj) return;
		this.adjustDisplay();
	}
);

jsContainer.addMethod("setBorder",
	function (_sel, _val)
	{
		if (typeof(_sel) == 'string')
		{
			for (var i = 0; i < _sel.length; ++i)
			{
				switch (_sel.charAt(i))
				{
					case 'T':
					case 't':	//top
						this.set_borderTop(_val, 'noadjust');
						break;
					case 'R':
					case 'r':	//top
						this.set_borderRight(_val, 'noadjust');
						break;
					case 'B':
					case 'b':	//top
						this.set_borderBottom(_val, 'noadjust');
						break;
					case 'L':
					case 'l':	//top
						this.set_borderLeft(_val, 'noadjust');
						break;
					
				}
			}
			this.adjustDisplay();
		}
	}
);
jsContainer.addMethod("set_margin",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.margin = _val;
			var buf = this.myStyle.margin.split(" ");
			this.dimMargin.length = 4;
			for (var i = 0; i < 4; ++i)
			{
				this.dimMargin[i] = document.bal.getLengthInPx(buf[i]);
			}
			if (_noAdj) return;
			this.adjustDisplay();
		}
		
	}
);

jsContainer.addMethod("set_padding",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.padding = _val;
			var buf = this.myStyle.padding.split(" ");
			this.dimPadding.length = 4;
			for (var i = 0; i < 4; ++i)
			{
				this.dimPadding[i] = document.bal.getLengthInPx(buf[i]);
			}
			
			if (_noAdj) return;
			this.adjustDisplay();
		}
		
	}
);

jsContainer.addMethod("set_bgExtend",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.bgExtend = _val;
					
			var buf = this.myStyle.bgExtend.split(" ");
			this.dimBgExtend.length = 4;
			for (var i = 0; i < 4; ++i)
			{
				this.dimBgExtend[i] = parseInt(buf[i]);
			}
			if (_noAdj) return;
			this.adjustDisplay();
		}
		
	}
);

jsContainer.addMethod("set_bgColor",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.bgColor = _val;
			this.divBackground.style.backgroundColor = this.myStyle.bgColor;
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_bodyBgColor",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.bodyBgColor = _val;
			this.divEffective.style.backgroundColor = this.myStyle.bodyBgColor;
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_borderBgColor",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.borderBgColor = _val;
			this.divBorder.style.backgroundColor = this.myStyle.borderBgColor;
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_bgImage",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.bgImage = _val;
			if (this.myStyle.bgImage != "")
			{
				var buf = this.myStyle.bgImage.split(" ");
				this.divBackground.style.backgroundImage = "url(" + buf[0] + ")";
				this.divBackground.style.backgroundRepeat = buf[1];
				this.divBackground.style.backgroundAttachment = buf[2];
				var pos = "";
				for (var i = 3; i < buf.length; ++i)
				{
					pos += buf[i] + " ";
				}
				this.divBackground.style.backgroundPosition = pos;
			}
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_borderBgImage",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.borderBgImage = _val;
			if (this.myStyle.borderBgImage != "")
			{
				var buf = this.myStyle.borderBgImage.split(" ");
				this.divBorder.style.backgroundImage = "url(" + buf[0] + ")";
				this.divBorder.style.backgroundRepeat = buf[1];
				this.divBorder.style.backgroundAttachment = buf[2];
				var pos = "";
				for (var i = 3; i < buf.length; ++i)
				{
					pos += buf[i] + " ";
				}
				this.divBorder.style.backgroundPosition = pos;
			}
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_bodyBgImage",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.bodyBgImage = _val;
			if (this.myStyle.bodyBgImage != "")
			{
				var buf = this.myStyle.bodyBgImage.split(" ");
				this.divEffect.style.backgroundImage = "url(" + buf[0] + ")";
				this.divEffect.style.backgroundRepeat = buf[1];
				this.divEffect.style.backgroundAttachment = buf[2];
				var pos = "";
				for (var i = 3; i < buf.length; ++i)
				{
					pos += buf[i] + " ";
				}
				this.divEffect.style.backgroundPosition = pos;
			}
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_bgOpacity",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'number')
		{
			var eff_op = _val;
			if (eff_op < 0) eff_op = 0;
			else if (eff_op > 100) eff_op = 100;
			
			this.myStyle.bgOpacity = eff_op;
			document.bal.setObjOpacity(this.divBackground, this.myStyle.bgOpacity);
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_bodyOpacity",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'number')
		{
			var eff_op = _val;
			if (eff_op < 0) eff_op = 0;
			else if (eff_op > 100) eff_op = 100;
			this.myStyle.bodyOpacity = eff_op;
			document.bal.setObjOpacity(this.divEffective, this.myStyle.bodyOpacity);
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_borderOpacity",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'number')
		{
			var eff_op = _val;
			if (eff_op < 0) eff_op = 0;
			else if (eff_op > 100) eff_op = 100;
			this.myStyle.borderOpacity = eff_op;
			document.bal.setObjOpacity(this.divBorder, this.myStyle.borderOpacity);
			if (_noAdj) return;
			this.adjustShadowColor();
		}
		
	}
);

jsContainer.addMethod("set_dropShadow",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'string')
		{
			this.myStyle.dropShadow = _val;
			if (this.myStyle.dropShadow)
			{
				this.divBgShadow.style.visibility = this.divHolder.style.visibility;
				this.divBorderShadow.style.visibility = this.divHolder.style.visibility;
				this.divEffectShadow.style.visibility = this.divHolder.style.visibility;	
			}
			else
			{
				this.divBgShadow.style.visibility = "hidden";
				this.divBorderShadow.style.visibility = "hidden";
				this.divEffectShadow.style.visibility = "hidden";	
			}
			if (_noAdj) return;
			this.adjustDisplay();
		}
		
	}
);

jsContainer.addMethod("set_autoSize",
	function (_val, _noAdj)
	{
		if (typeof(_val) == 'number')
		{
			if (_val <0)
				this.myStyle.autoSize = 0;
			else if (_val >3)
				this.myStyle.autoSize = 3;
			else
				this.myStyle.autoSize = _val.round();
			if (_noAdj) return;
			this.adjustDisplay();
		}
	}
);


jsContainer.addMethod("applyStyle",
	function (myStyle, noAdj)
	{
		if (!this.myStyle)
			this.myStyle = new Object();
		
		if (myStyle)
			for (var prop in myStyle)
			{
				var fnName = "set_" + prop;
				if (this[fnName])
				{
					eval("this.set_" + prop + "(myStyle." + prop + ", true)");
				}
			}
					
		
		if (noAdj) return;
		this.adjustDisplay();
	}
);

jsContainer.addMethod("setDefaultStyle",
	function ()	//just apply statically, no adjustment
	{
		if (!this.myStyle)
			this.myStyle = new Object();
		
		var protoStyle = eval(this.thisClass + ".prototype.protoStyle");
		for (var prop in protoStyle)
		{
			var setFn = eval(this.thisClass + ".prototype.set_" + prop);
			if (setFn)
			{
				eval(this.thisClass + ".staticCall('set_" + prop + "', this, protoStyle[prop], true)");
			}
		}

	}
);

/*********************************************************************************
//	create 3D separator
*********************************************************************************/
var JSSEPARATOR = "$$SEPARATOR$$";
function create3DSeparator(strColor, strLength, strSize, bVertical)
{
	var newSep = null;
	
	//newSep.style.borderStyle = "solid"
	newSep = document.createElement("div");
	newSep.style.margin = "0px";
	newSep.style.fontSize = "0px";
	newSep.style.backgroundColor = strColor;
	
	newSep.style.padding = "0px";
	var sepSize = document.bal.getLengthInPx(strSize);
	
	if (bVertical)
	{
		newSep.style.height = strLength;
		if (document.bal.bW3CPadding)	//outward
		{
			newSep.style.width = "0px";
		}
		else
		{
			newSep.style.width = (2 * sepSize) + "px";
		}
		
		
		newSep.style.borderLeft = strSize + " solid " + strColor;
		newSep.style.borderRight = strSize + " solid white";
		
		newSep.style.borderTop = newSep.style.borderBottom = "0px none white";
		
		
	}
	else
	{
		newSep.style.width = strLength;
		if (document.bal.bW3CPadding)	//outward
		{
			newSep.style.height = sepSize + "px";
		}
		else
		{
			newSep.style.height = (2 * sepSize) + "px";
		}
		//newSep.style.height = strSize;
		
		newSep.style.borderBottom = strSize + " solid white";
		
		newSep.style.borderLeft = newSep.style.borderRight = newSep.style.borderTop = "0px none white";
		
		
	}
	
	
	newSep.thisClass = "jsSeparator";
	
	return newSep;
}



