/* 
 * 
 * LIBRARY A 
 * description: exerpt from <base.js> and <utility.js>
 * 
 */
if (!Function.prototype.apply) {
	Function.prototype.apply = function (o,a) {
		var r;
		if(!o){ o = {}; } // in case func.apply(null, arguments).
		o.___apply=this;
		switch((a && a.length) || 0) {
			case 0: r = o.___apply(); break;
			case 1: r = o.___apply(a[0]); break;
			case 2: r = o.___apply(a[0],a[1]); break;
			case 3: r = o.___apply(a[0],a[1],a[2]); break;
			case 4: r = o.___apply(a[0],a[1],a[2],a[3]); break;
			case 5: r = o.___apply(a[0],a[1],a[2],a[3],a[4]); break;
			case 6: r = o.___apply(a[0],a[1],a[2],a[3],a[4],a[5]); break;
			default: 
				for(var i=0, s=""; i<a.length;i++){
					if(i!=0){ s += ","; }
					s += "a[" + i +"]";
				}
				r = eval("o.___apply(" + s + ")");
		};
		o.__apply = null;
		return r;
	};
};
_String_trim = function(_this, str) {
	if (!str) str = _this;
	return str.replace(/^\s*/, "").replace(/\s*$/, "");
};
_String_normalize_space = function(_this, str) {
	if (!str) str = _this;
	return _String_trim(str).replace(/\s+/g, " ");
};
_Array_each = function(_this, block) {
	for (var index = 0; index < _this.length; ++index) {
		var item = _this[index];
		block(item, index)
	}
	return _this;
};
_Array_indexOf = function(_this, x) {
	for (var i=0; i<_this.length; i++) {
		if (_this[i] == x) {
			return i;
		}
	}
	return -1;
};
_Array_push = function(_this, obj) {
	for (var i=1; i<arguments.length; i++) {
		_this[_this.length] = arguments[i];
	}
	return _this.length;
}
function browserReport() {
	var b = navigator.appName.toString();
	var up = navigator.platform.toString();
	var ua = navigator.userAgent.toString();
	this.mozilla = this.ie = this.opera = r = false;
	var re_opera = /Opera.([0-9\.]*)/i;
	var re_msie = /MSIE.([0-9\.]*)/i;
	var re_gecko = /gecko/i;
	var re_safari = /safari\/([\d\.]*)/i;
	if (ua.match(re_opera)) {
		r = ua.match(re_opera);
		this.opera = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_msie)) {
		r = ua.match(re_msie);
		this.ie = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_safari)) {
		this.mozilla = true;
		this.safari = true;
		this.version = 1.4;
	} else if (ua.match(re_gecko)) {
		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
		r = ua.match(re_gecko_version);
		this.mozilla = true;
		this.version = parseFloat(r[1]);
	}
	this.windows = this.mac = this.linux = false;
	this.Platform = ua.match(/windows/i) ? "windows" :
					(ua.match(/linux/i) ? "linux" :
					(ua.match(/mac/i) ? "mac" :
					ua.match(/unix/i)? "unix" : "unknown"));
	this[this.Platform] = true;
	this.v = this.version;
	this.valid = this.ie && this.v >= 6 || this.mozilla && this.v >= 1.4;
	if (this.safari && this.mac && this.mozilla) {
		this.mozilla = false;
	};
};
var is = new browserReport();
getElRef = function(elem) {
	var d;
	if (typeof(elem) == "string") {
		d = document.getElementById(elem);
	} else {
		d = elem;
	}
	return d;
};
getClasses = function(o) {
	o = getElRef(o);
	if (!o) return false;
	var cn = _String_trim(_String_normalize_space(o.className));
	if (cn == '') {
		return [];
	}
	return cn.split(" ");
}
_getAllChildren = function(e) {
	return e.all ? e.all : e.getElementsByTagName('*');
};
_getOwnChildrenOnly = function(e){
	var response = [];
	var children = e.childNodes;
	for(var i=0; i<children.length; i++) {
		var current = children[i];
		if(current.nodeType == 1) {
			_Array_push(response, current);
		};
	};
	return response;
};
_getElementsByTagName = function(o, sTagName) {
	var el;
	if (typeof o == 'undefined') {
		o = document;
	} else {
		o = getElRef(o);
	};
	if (sTagName == '*' || typeof sTagName == 'undefined') {
		el = _getAllChildren(o);
	} else {
		el = o.getElementsByTagName(sTagName.toLowerCase());
	};
	return el;
}
_attachEvent2 = function(where, type, what, when) {
	_attachEvent_base(where, type, what, when, 1);
}
_attachEvent = function(where, type, what, when) {
	_attachEvent_base(where, type, what, when, 0);
}
_attachEvent_base = function(where, type, what, when, add_first) {
	if (typeof(when) == 'undefined') when = 1;
	var doNotAdd = type.match(/unload$/i);
	var real_type = type.match(/^on/) ? type : 'on' + type ;
	var logical_type = type.replace(/^on/, '');
	if (typeof where.__eventHandlers == 'undefined') {
		where.__eventHandlers = {};
	}
	var place = null;
	if (typeof where.__eventHandlers[logical_type] == 'undefined') {
		where.__eventHandlers[logical_type] = [];
		place = where.__eventHandlers[logical_type];

		var raiseEvent = function(e) {
			if (!e && window.event) {
				e = window.event;
			}
			for (var i=0;i < where.__eventHandlers[logical_type].length; i++) {
				var f = where.__eventHandlers[logical_type][i];
				if (typeof f == 'function') {
					f.apply(where, [e]);
					f = null;
				}
			}
		}
		if (where.addEventListener) {
			where.addEventListener(logical_type, raiseEvent, false);
		}
		else if (where.attachEvent) {
			where.attachEvent("on" + logical_type, raiseEvent);
		}
		else {
			where["on" + logical_type] = raiseEvent;
		}
		if ( (! (is.ie && is.mac)) && !doNotAdd) {
			_EventCache.add(where, logical_type, raiseEvent, 1);
		}
	} else {
		place = where.__eventHandlers[logical_type];
	}
	for (var i=0;i<place.length;i++) {
		if (place[i] == what) {
			return;
		}
	}
	place[place.length] = what;
}
var _EventCache = function(){
	var listEvents = [];
	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler, bCapture){
			_Array_push(listEvents, arguments);
		},
		flush : function(){
			var i, item;
			
			if(listEvents) {
				for(i = listEvents.length - 1; i >= 0; i = i - 1){
					item = listEvents[i];
					if(item[0].removeEventListener){
						item[0].removeEventListener(item[1], item[2], item[3]);
					};
					/* From this point on we need the event names to be prefixed with 'on" */
					var logical_type = '';
					if(item[1].substring(0, 2) != "on") {
						logical_type = item[1];
						item[1] = "on" + item[1];
					} else {
						logical_type = item[1].substring(2, event_name_without_on.length);
					};
					//delete from __eventHandlers
					if (typeof item[0].__eventHandlers != 'undefined' && typeof item[0].__eventHandlers[logical_type] != 'undefined') {
						item[0].__eventHandlers[logical_type] = null;
					}
					if(item[0].detachEvent){
						item[0].detachEvent(item[1], item[2]);
					};
					item[0][item[1]] = null;
				};
				listEvents = null;
			}
		}
	};
}();
_attachEvent(window, 'unload', function(){_EventCache.flush()});
_boxOverlap = function(b1, b2) {
	if((b1.x + b1.width) < b2.x) return false;
	if(b1.x > (b2.x + b2.width)) return false;
	if((b1.y + b1.height)< b2.y) return false;
	if(b1.y > (b2.y + b2.height)) return false;	
	return true;
};
getCSSProperty = function(el, property, type) {
	try {
		var value = el.style[property];
		if (!value) {
			if ((typeof el.ownerDocument != 'undefined') && 
			    (typeof el.ownerDocument.defaultView != 'undefined') && 
				(typeof (el.ownerDocument.defaultView.getComputedStyle) == "function")){
				// moz, opera
				value = el.ownerDocument.defaultView.getComputedStyle(el,
				        "").getPropertyValue(property);
			} else if (el.currentStyle) {
				// IE
				var m = property.split(/-/);
				if (m.length>0) {
					property = m[0];
					for(var i=1;i<m.length;i++) {
						property += m[i].charAt(0).toUpperCase() + m[i].substring(1);
					};
				};
				value = el.currentStyle[property];
			} else if (el.style) {
				value = el.style[property];
			};
		};
		type = type || 'string';
		if(type == 'number'){
			if(/\./.test(value)) {
				value = parseFloat(value);
			} else {
				value = parseInt(value);
			};
			value = isNaN(value)? 0: value;
		} else if(type == 'boolean'){
			value = (type && (type != 'none') && (type != 'auto'))? true: false;
		} else if(type == 'string'){
			value = (!value || (value == 'none') || (value == 'auto'))? '' : value;
		};
		return value;
	} catch(err) {
			if(property == 'width'){ value = el.width || 0 };
			if(property == 'height'){ value = el.height || 0 };
			return value;
	};
};
var first_getAbsolutePos_caller_element = null;
getLayoutOldWay = function(el, recursiveFlag) {
	var scrollleft = 0;
	var scrolltop  = 0;
	var tn = el.tagName.toUpperCase();
	
	if (!recursiveFlag) {
		first_getAbsolutePos_caller_element = el;
	};
	
	if (_Array_indexOf(['BODY', 'HTML'], tn) == -1 && 
	    first_getAbsolutePos_caller_element !== el) {
		if (el.scrollLeft) { scrollleft = el.scrollLeft };
		if (el.scrollTop) { scrolltop = el.scrollTop };
	};
	var r = { 
			  x: !isNaN(el.offsetLeft)? (el.offsetLeft- scrollleft) : 
			  	 el.offsetParent? el.offsetParent.offsetLeft? el.offsetParent.offsetLeft: 0: 0,
			  	 
	          y: !isNaN(el.offsetTop)? (el.offsetTop - scrolltop) :
	          	 el.offsetParent? el.offsetParent.offsetTop? el.offsetParent.offsetTop: 0: 0
	        };
	if (el.offsetParent && tn != 'BODY') {
		var tmp  = getLayoutOldWay(el.offsetParent, true);
		r.x += isNaN(tmp.x)? 0: tmp.x;
		r.y += isNaN(tmp.y)? 0: tmp.y;
	};
	return r;
};
var strictm;
getLayout = function(el) {
	var box = { "x"     : 0,
				"y"     : 0,
				"width" : 0,
				"height": 0 
			  };
	strictm = ((typeof el.ownerDocument != 'undefined') &&
	           (typeof el.ownerDocument.compatMode != 'undefined') &&
	    	   (el.ownerDocument.compatMode == "CSS1Compat"));
	
	if((typeof el.ownerDocument != 'undefined') &&
	   (typeof el.ownerDocument.getBoxObjectFor != 'undefined')){
		var rect   = el.ownerDocument.getBoxObjectFor(el);
		box.x 	   = rect.x - el.parentNode.scrollLeft;
		box.y      = rect.y - el.parentNode.scrollTop;
		box.width  = rect.width;
		box.height = rect.height;
		box.scrollLeft = (strictm? 
		                  el.ownerDocument.documentElement:
		                  el.ownerDocument.body).scrollLeft;
		box.scrollTop  = (strictm?
		                  el.ownerDocument.documentElement:
		                  el.ownerDocument.body).scrollTop;
		box.x -= box.scrollLeft;
		box.y -= box.scrollTop;
	}else if(typeof el.getBoundingClientRect != 'undefined'){
	  	var rect   = el.getBoundingClientRect();
		box.x 	   = rect.left;
		box.y 	   = rect.top;
		box.width  = rect.right - rect.left;
		box.height = rect.bottom - rect.top;
	}else{
		var tmp    = getLayoutOldWay(el);
		box.x      = parseInt(tmp.x) - parseInt(el.parentNode.scrollLeft);
		box.y      = parseInt(tmp.y) - parseInt(el.parentNode.scrollTop);
		
		box.width  = (typeof el.offsetWidth != 'undefined')? 
					  el.offsetWidth: getCSSProperty(el, 'width', 'number');
		
		box.height = (typeof el.offsetHeight != 'undefined')?
					  el.offsetHeight: getCSSProperty(el, 'height', 'number');
	};
	return box;
};
addClassName = function(obj, toadd) {
	var cls = getClasses(obj);
	if (typeof toadd == 'string') {
		toadd = toadd.split(',');
	}
	_Array_each(toadd, function(item, i){
		if (_Array_indexOf(cls, item) == -1) {
			_Array_push(cls, item);
		}
	});
	cls = _String_trim(cls.join(' '));
	if (_String_trim(obj.className) != cls) {
		obj.className = cls;
	}
}
_removeClass = function(obj, toremove) {
	var cls = getClasses(obj);
	var result = [];
	if (typeof toremove == 'string') {
		toremove = toremove.split(',');
	}
	_Array_each(cls, function(item, i){
		if (_Array_indexOf(toremove, item) == -1) {
			_Array_push(result, item);
		}
	});
	cls = _String_trim(result.join(' '));
	if (_String_trim(obj.className) != cls) {
		obj.className = cls;
	};
};
/* 
 * 
 * 
 * 
 * 
 * LIBRARY B 
 * name:
 * 		associative array
 * autor:
 * 		claudiu iacob ("CIA")
 * description:
 * 		-> holds elements both in numeric and string keys
 *		-> can convert one key type to an other 
 * 		-> can  return an element by either key
 *  	-> can perform a "each" returning <VALUE>, <NUMBER KEY>, <STRING KEY> -- in <NUMBER KEY>
 *   	   order (just like an array) and using them as arguments to a custom function.
 *		-> can return the first/last elements
 * 		-> needless to say, can do basics: SET, GET, PUSH elements  
 * 
 * 
 */
function Assoc_Array(){
	this.length = 0;
	this.doubles = 0;
	this.sRef = {};
	this.nRef = [];
	this.runEach = true;
};
Assoc_Array.prototype.push = function(el, key) {
	var num = this.length++;
	var key = key || ('unnamed_el_'+num);
	this.doubles = 0;
	while(this.sRef[key]) {
		key += '_' + this.doubles++;
	};
	var _rf = {'index': num, 'key': key, 'content': el}
	this.sRef[key] = _rf;
	this.nRef[num] = _rf;
};
Assoc_Array.prototype.get = function(selector) {
	return (typeof selector == 'number')? 
				(typeof this.nRef[selector] != 'undefined')? 
					this.nRef[selector].content: null :
		   (typeof selector == 'string')? 
		   		(typeof this.sRef[selector] != 'undefined')?
		   			this.sRef[selector].content: null :
		   null;
};
Assoc_Array.prototype.isSet = function(selector) {
	return (typeof selector == 'number')? 
				((typeof this.nRef[selector] != 'undefined') && (this.nRef[selector] !== null))? 
					true: false:
		   (typeof selector == 'string')? 
		   		((typeof this.sRef[selector] != 'undefined') && (this.nRef[selector] !== null))?
		   			true: false: false;
};
Assoc_Array.prototype.set = function(el, nSel, sSel) {
	var num = nSel;
	var key = sSel;
	if((typeof num == 'undefined') || (num === null)) {
		if(this.sRef[key]) {
			num = this.sRef[key].index;
		};
	};
	if((typeof key == 'undefined') || (key === null)) {
		if(this.nRef[num]) {
			key = this.nRef[num].key
		};
	};
	var have_number = ((typeof num == 'number') && (num >= 0))? true: false;
	var have_string = ((typeof key == 'string') && (key.length > 0))? true: false;
	if( !have_number && have_string) {
		this.push(el, key);
		return;
	};
	if( have_number && !have_string) {
		this.push(el, num);
		return;
	};
	if(!have_number && !have_string){
		this.push(el);
		return;
	};
	var _rf = {'index': num, 'key': key, 'content': el};
	this.sRef[key] = _rf;
	if((typeof this.nRef[num] == 'undefined') || (this.nRef[num] === null)) {
		this.length++;	
	};
	this.nRef[num] = _rf;
};
Assoc_Array.prototype.getFirst = function(){
	return (typeof this.nRef[0] != 'undefined')? this.nRef[0].content: null;
};
Assoc_Array.prototype.getLast = function(){
	return (typeof this.nRef[this.nRef.length-1] != 'undefined')?
	        this.nRef[this.nRef.length-1].content: null;
};
Assoc_Array.prototype.getAssoc = function(selector){
	return (typeof selector == 'number')? 
				(typeof this.nRef[selector] != 'undefined')? 
					this.nRef[selector].key : null :
		   (typeof selector == 'string')? 
		   		(typeof this.sRef[selector] != 'undefined')? 
		   			this.sRef[selector].index : null :
		   null;	
};
Assoc_Array.prototype.each = function(functor){
	for(var i=0; i<this.length; i++){
		if(!this.runEach) {
			this.runEach = true;
			break;
		};
		var _rf = this.nRef[i];
		var _index = _rf.index;
		var _key = _rf.key;
		var _content = _rf.content;
		var response = functor(_content, _index, _key);
		if(response) {
			return response;
		};
	};
};
Assoc_Array.prototype.reverseEach = function(functor){
	for(var i=this.length-1; i>=0; i--){
		if(!this.runEach) {
			this.runEach = true;
			break;
		};
		var _rf = this.nRef[i];
		var _index = _rf.index;
		var _key = _rf.key;
		var _content = _rf.content;
		var response = functor(_content, _index, _key);
		if(response) {
			return response;
		};
	};
};
Assoc_Array.prototype.Break = function(){
	this.runEach = false;
};
Assoc_Array.prototype.getFirstDefined = function() {
	for (var i=0; i<this.nRef.length; i++){
		var _test = this.nRef[i];
		if((_test.content != 'undefined') && (_test.content !== null)) {
			return _test.content
		};
	};
	return null;
};
Assoc_Array.prototype.getHash = function() {
	var response = {};
	for (var i=0; i< this.nRef.length; i++){
		response[this.nRef[i].key] = this.nRef[i].content;
	}
	return response;
};
/* 
 * 
 * 
 * 
 * LIBRARY C
 * name: 
 * 		recursive HTML parser
 * author:
 * 		claudiu iacob ("CIA")
 * description:
 * 		-> recursively checks a given HTML tree, executing custom registered functions "on start", 
 * 		   "on node" & "on complete";
 *      -> fail safe: overcomes "stack overflow" issues in IE, by running some of the recursive 
 * 		   threads asynchronous.
 *		   
 * 
 * 
 */
function PARSER() {
	this.run = true;
	this.counter = 0;
	this.root = null;
	this.currentParent = null;
	this.nodeFilter = null;
	this.onStartCallback = null;
	this.onNodeCallback = null;
	this.onCompleteCallback = null;
	this.runs = 0;
	this.small_memory_stack = true; //"false": instant output, but unsafe for large HTML blocks
};
PARSER.prototype.registerRoot = function(root){
	this.root = root;
};
PARSER.prototype.registerNodeFilter = function(filter){
	this.nodeFilter = filter.toLowerCase();
};
PARSER.prototype.registerOnStartCallback = function(functor){
	this.onStartCallback = functor;
};
PARSER.prototype.registerOnNodeCallback = function(functor){
	this.onNodeCallback = functor;
};
PARSER.prototype.registerOnCompleteCallback = function(functor){
	this.onCompleteCallback = functor;
};
PARSER.prototype.start = function(){
	this.run = true;
	if(typeof this.onStartCallback == 'function'){
		this.onStartCallback();
	};
	var NODE = this.Get_First_Child(this.root);
	if(NODE){
		this.PARSE(NODE);
	};
};
PARSER.prototype.abort = function(){
	this.run = false;
};
function Restart(NODE) {
	if( !this.small_memory_stack ) {
		this.PARSE(NODE);
		return;
	};
	var _this = this;
	if(this.runs > 10) {
		this.runs = 0;
		window.setTimeout( function(){_this.PARSE(NODE)}, 0);
	} else {
		this.runs++;
		this.PARSE(NODE);
	};
};
PARSER.prototype.Restart = Restart;
function Get_First_Child(NODE) {
	var child = NODE.firstChild;
	if(child) {
		var isHtmlNode = (child.nodeType == 1);
		while(!isHtmlNode) {
			child = child.nextSibling;
			if(!child){ break };
			isHtmlNode = (child.nodeType == 1);
		};
		if(isHtmlNode) {
			return child;
		};
	};
	return null;
};
PARSER.prototype.Get_First_Child = Get_First_Child;
function Get_Next_Sibling(NODE) {
	var next = NODE.nextSibling;
	if(next) {
		var isHtmlNode = (next.nodeType == 1);
		while(!isHtmlNode) {
			next = next.nextSibling;
			if(!next) { break };
			isHtmlNode = (next.nodeType == 1);
		};
		if(isHtmlNode) {
			return next;
		};
	};
	return null;
};
PARSER.prototype.Get_Next_Sibling = Get_Next_Sibling;
function get_parent(NODE) {
	var parentElement = NODE.parentNode;	
	if(parentElement) {
		return parentElement;
	};
	return null;
};
PARSER.prototype.get_parent = get_parent;
function get_sibling_of_parent(NODE) {
	var _parent = this.get_parent(NODE);
	if(_parent) {
		var _sibling = this.Get_Next_Sibling(_parent);
		if(_sibling) {
			return _sibling;
		};
	};
	return null;
};
PARSER.prototype.get_sibling_of_parent = get_sibling_of_parent;
function Get_Next_Sibling_Of_Parent(NODE) {
	var _nextParentSibling = this.get_sibling_of_parent(NODE);
	while(!_nextParentSibling) {
		NODE = this.get_parent(NODE);
		_nextParentSibling = this.get_sibling_of_parent(NODE);
	};
	if(_nextParentSibling) {
		return _nextParentSibling;
	};
	return null;
};
PARSER.prototype.Get_Next_Sibling_Of_Parent = Get_Next_Sibling_Of_Parent;
function Check_Node_Against_Filter(NODE) {
	var _name = NODE.nodeName.toLowerCase();
	if(_name != this.nodeFilter){
		return false;
	};
	return true;
};
PARSER.prototype.Check_Node_Against_Filter = Check_Node_Against_Filter;
function Index_Item(NODE) {
	if(!this.Check_Node_Against_Filter(NODE)) { return };
	var _parent = this.currentParent;
	if(this.onNodeCallback !== null){
		this.onNodeCallback (NODE, _parent, this.counter++);
	};
};
PARSER.prototype.Index_Item = Index_Item;
function Register_As_Parent(NODE) {
		this.currentParent = NODE;
};
PARSER.prototype.Register_As_Parent = Register_As_Parent;
function PARSE(NODE) {
	if(!this.run) {
		return null;
	};
	if(NODE.nodeName && (NODE.nodeName.toLowerCase() == 'br') ){
		if(typeof this.onCompleteCallback == 'function') {
			this.onCompleteCallback();
		};
		return;
	};
	this.Index_Item(NODE);
	var firstChildOfNODE = this.Get_First_Child(NODE);
	if(firstChildOfNODE){
		this.Register_As_Parent(NODE);
		this.Restart(firstChildOfNODE);
		return;
	} else {
		var nextSiblingOfNODE = this.Get_Next_Sibling(NODE);
		if(nextSiblingOfNODE){
			this.Restart(nextSiblingOfNODE);
			return;
		} else {
			var nextLowerLevelNODE = this.Get_Next_Sibling_Of_Parent(NODE);
			if(nextLowerLevelNODE) {
				this.Restart(nextLowerLevelNODE);
				return;
			};		
		};
	};
};
PARSER.prototype.PARSE = PARSE;


/************************************************************************************************
 *                                                                                              *
 *                                                                                              *
 *                                                                                              *
 *                                                                                              *
 * CSS MENUS 2                                                                  				* 
 * (c) Interakt Online, all rights reserved                                                     *
 *                                                                                              *
 * JS code developped by Claudiu Iacob ("CIA")                                                  *
 *                                                                                              *
 *                                                                                              *
 *                                                                                              *
 *                                                                                              *
 ***********************************************************************************************/
 
 
/// menuItem:
/// The constructor of the "menuItem" class. Every single item inside a menu instantiates it.
function menuItem(_id, _element, parent_node){
	this.owner = null;
	this.id = _id;
	this.element = _element;
	this.parent_node = parent_node;
	this.parent_item = null;
	this.children = new Assoc_Array();
	this.isHeader = null;
	this.isParent = null;
	this.image = null;
	this.link = null;
	this.holder = null;
	this.gotHolder = null;
	this.selected = null;
	this.mouse_state = 'out';
	this.expandedState = false;
	this.visibleState = false;
	this.path = null;
};


/// CSSMenu:
/// The constructor of the "CSSMenu" class. Every menu within a page instantiates this class.
function CSSMenu(menuID) {
	//id, container, root and first element:
	this.id = menuID;
	this.container  = document.getElementById(this.id);
	if(!this.container){
		return;
	};
	//declare this menu:
	allCSSMENUS2.push(this, this.id);
	this.root = this.container.getElementsByTagName('ul')[0];
	this.first = this.root.getElementsByTagName('li')[0];
	if(!this.root){
		return;
	};
	//layout, default parameters, class names string table
	this.type = getMenuType(this.root);
	this.config = {
		'showTimeout' : 400,
		'hideTimeout' : 200,
		'exitTimeout' : 1000,
		'hoverPattern' : '{name}_hover.{ext}',
		'highliteCurrentFlag' : true,
		'highliteCurrentPattern' : '{name}_selected.{ext}',
		'hideOverlayObjects' : true,
		'persistentTab' : false,
		'expandableBehaviour': 'accordion',
		'animationEffect' : null,
		'safeBox' : [0, 0],
		'offset_X_level_1' : 0,
		'offset_Y_level_1' : 0,
		'offset_X_level_2_plus'	: 0,
		'offset_Y_level_2_plus' : 0
	};
	this.classes = {
		'hover' : 'hover',
		'selected' : 'selected',
		'arrow' : 'arrow',
		'selected_server_side' : 'ktselected'
	};
	//holders & helpers:
	this.isTwoLevel = ((this.type == 'tab')||(this.type == 'expandable'));
	this.allItems = new Assoc_Array();
	this.headers = new Assoc_Array();
	this.visibles = new Assoc_Array();
	this.expandedHeight = new Assoc_Array();
	this.parser	= {};
	this.attachOffset = null;
	this.lastModified = null;
	var FIREFOX_FLAG = navigator.userAgent.match(/firefox.([\d\.]{3,8})/i);
	if(FIREFOX_FLAG){
		this.isSomeFirefox = true;
		var FIREFOX_VERSION = parseFloat(FIREFOX_FLAG[1]);
		if(FIREFOX_VERSION) {
			this.ff_flag = true;
			this.ff_vers = FIREFOX_VERSION;
		};
	};
	this.lastHighlightedPath = new Assoc_Array();
	//browser familly specific offsets
	this.bfBox = {};
	this.bfBox.Static   = {};
	this.bfBox.Absolute = {};
	this.bfBox.Static.x1   = is.ie? -2: is.mozilla? -1: is.opera? 0: is.safari? -8: 0;
	this.bfBox.Static.y1   = is.ie? -2: is.mozilla? -1: is.opera? 0: is.safari? -6: 0;
	this.bfBox.Static.x2   = is.ie?  0: is.mozilla?  0: is.opera? 0: is.safari? -7: 0;
	this.bfBox.Static.y2   = is.ie?  0: is.mozilla?  0: is.opera? 0: is.safari? -8: 0;
	this.bfBox.Absolute.x1 = is.ie? -2: is.mozilla? -1: is.opera? 0: is.safari?  0: 0;
	this.bfBox.Absolute.y1 = is.ie? -2: is.mozilla? -1: is.opera? 0: is.safari?  0: 0;
	this.bfBox.Absolute.x2 = is.ie?  0: is.mozilla?  0: is.opera? 0: is.safari?  0: 0;
	this.bfBox.Absolute.y2 = is.ie?  0: is.mozilla?  0: is.opera? 0: is.safari?  0: 0;
	// Children's position: 
	// Some browsers need single check on the first levels's children
	this.sg_Pos_Check_Flag = (is.ie && is.version < 5.5)? true:
							 (is.ie && is.version >= 5.5)? false:
							 (is.mozilla && !is.safari)? false:
							 (is.opera && is.version < 8.4)? true:
							 (is.opera && (is.version > 8.4) && (is.version < 9))? false:
							 (is.opera && is.version >= 9)? true:
							 (is.safari)? true: true;
	// All browsers require double position check if first level is absolute positioned.
	this.abs_Pos_Flag = false;
	var __DWLayer = this.container.parentNode;
	while(__DWLayer && !this.abs_Pos_Flag) {
		var hdAbsPos = /absolute/i.test(getCSSProperty(__DWLayer, 'position', 'string'));
		if(hdAbsPos){
			this.abs_Pos_Flag = true;
			break;
		};
		__DWLayer = __DWLayer.parentNode;
		if(!__DWLayer) { break };
	};
	if(this.abs_Pos_Flag) { this.sg_Pos_Check_Flag = false };
//	// Safari absolutelly positions elements in regard to BODY recipient, when running in 
//	// standard compliants mode. We must fix this:
//	if(is.safari){
//		// get top & left warmfull offsets of the html element:
//		var _html = document.getElementsByTagName('html')[0];
//		var L_html_m = getCSSProperty(_html, 'margin-left', 'number');
//		var T_html_m = getCSSProperty(_html, 'margin-top', 'number');
//		var L_html_b = getCSSProperty(_html, 'border-left-style', 'boolean')?
//					   getCSSProperty(_html, 'border-left-width', 'number'): 0;
//		var T_html_b = getCSSProperty(_html, 'border-top-style', 'boolean')?
//					   getCSSProperty(_html, 'border-top-width', 'number'): 0;
//		// get top & left harmfull offsets of the body element:
//		var L_body_m = getCSSProperty(document.body, 'margin-left', 'number');
//		var T_body_m = getCSSProperty(document.body, 'margin-top', 'number');
//		
//		var L_body_b = getCSSProperty(document.body, 'border-left-style', 'boolean')?
//					   getCSSProperty(document.body, 'border-left-width', 'number'): 0;
//		var T_body_b = getCSSProperty(document.body, 'border-top-style', 'boolean')?
//					   getCSSProperty(document.body, 'border-top-width', 'number'): 0;		
//		// 'border-width:auto' gives unpredictable results, so we disable it:
//		_html.style.borderLeftWidth = L_html_b + 'px';
//		_html.style.borderTopWidth = T_html_b + 'px';
//		document.body.style.borderLeftWidth = L_body_b + 'px';
//		document.body.style.borderTopWidth = T_body_b + 'px';
//		//safe the total SAFARI offset
//		var __horz_total_offset = L_html_b + L_html_m + L_body_b + L_body_m;
//		var __vert_total_offset = T_html_b + T_html_m + T_body_b + T_body_m;
//		this.SAFARI_x_offset = __horz_total_offset;
//		this.SAFARI_y_offset = __vert_total_offset;
//	};
	//setters:
	this.setTimeouts = function(show, hide, exit) {
		this.config.showTimeout = show;
		this.config.hideTimeout = hide;
		this.config.exitTimeout = exit;
	};
	this.setImageHoverPattern = function(pattern) {
		this.config.hoverPattern = pattern || null;
	};
	this.setHighliteCurrent = function(flag, pattern) {
			this.config.highliteCurrentFlag = flag? true: false;
			this.config.highliteCurrentPattern = flag? (pattern || ''): null;
	};
	this.setAnimation = function (effectName) {
		var brswOK = false;
		if(is.ie && (is.version >= 6) ) { brswOK = true };
		if(is.mozilla) { brswOK = true };
		if(this.ff_flag && (this.ff_vers < 1.5)) { brswOK = false };
		if(!brswOK){ return };
		this.config.animationEffect = effectName || null;
	};
	this.setSubMenuOffset = 
		function( offset_X_level_1, offset_Y_level_1,
		          offset_X_level_2_plus, offset_Y_level_2_plus ) {
			this.config.offset_X_level_1 = offset_X_level_1;
			this.config.offset_Y_level_1 = offset_Y_level_1;
			this.config.offset_X_level_2_plus = offset_X_level_2_plus;
			this.config.offset_Y_level_2_plus = offset_Y_level_2_plus;
	};
	this.setHideOverlayObjects = function(flag) {
		this.config.hideOverlayObjects = flag? true: false;
	};
	this.setPersistentTab = function(flag) {
		this.config.persistentTab = flag? true: false;
	};
	this.setExpandableBehaviour = function(behaviour){
		this.expandableBehaviour = (behaviour == 'multiple')? 'multiple': 'accordion';
	};
	/// <menuObject>.checkReadyState:
	/// The application entry point.
	this.show = function() { 
		this.checkReadyState();
	};
};


/// <menuObject>.checkReadyState:
/// The application entry point. Checks if the element that holds the menu has been given
/// layout by the browser, or else any box/position calculations will crash. Execution is
/// deffered until detecting layout.
function checkReadyState() {
	var testBox = getElBox(this.root);
	var testVal = testBox.width;
	if(!testVal){
		var menu_object = this;
		window.setTimeout( function() {menu_object.checkReadyState()}, 1 );
		return;
	};
	this.beforeALL();
	var _this = this;
	this.parser = new PARSER();
	this.parser.registerNodeFilter('a');
	this.parser.registerRoot(this.root);
	this.parser.registerOnNodeCallback(function(a,b,c){_this.nodeCallbackRoutine(a,b,c)});
	this.parser.registerOnCompleteCallback(function(){_this.onTreeParseComplete()});
	this.parser.start();
};
CSSMenu.prototype.checkReadyState = checkReadyState;


/// <menuObject>.nodeCallbackRoutine:
/// Executes on every LI html object, at tree parse time. It performes a series of general-use
/// tasks, such as filling each item children list, marking parents, user images, etc.
function nodeCallbackRoutine(nodeEL, nodeParent, nodeID){
	var _nodeID     = this.id + '_item_' + nodeID;
	var _nodeEL     = nodeEL.parentNode;
	var _nodeParent = ( nodeParent && nodeParent.parentNode && 
	                    nodeParent.parentNode.parentNode ) ?
                        nodeParent.parentNode.parentNode: null;
	_nodeParent     = ( _nodeParent && (_nodeParent.nodeName.toLowerCase() == 'li') )? 
	                    _nodeParent: null;
	_nodeEL.id = _nodeID; 
	addClassName(_nodeEL, (this.id + '_el'));
	var item = new menuItem(_nodeID, _nodeEL, _nodeParent);
	this.allItems.push(item, _nodeID);
	item.owner = this;
	if(_nodeParent) {
		var parentId = _nodeParent.id;
		if(parentId){
			item.parent_item = this.allItems.get(parentId);
			item.parent_item.isParent = true;
			item.parent_item.children.push(item, _nodeID);
			item.parent_item.holder = _nodeEL.parentNode;
		};
	} else {
		this.headers.push(item, _nodeID);
		item.isHeader = true;
		var img = _nodeEL.getElementsByTagName('img')[0];
		if(img){ addClassName(img, (this.id + '_el')) }; 
		item.image = img || null;
	};
	var link = _nodeEL.getElementsByTagName('a')[0];
	addClassName(link, (this.id + '_el')); //mark
	item.link = link;
};
CSSMenu.prototype.nodeCallbackRoutine = nodeCallbackRoutine;


/// <menuObject>.onTreeParseComplete:
/// Executes as callback, when tree parsing is complete. Will trigger specific-use tasks, for
/// the first level of the menu (the other levels are dealt with deffered).
function onTreeParseComplete(){
	if(this.type == 'tab') {
		this.config.exitTimeout *= 2;
	};
	this.MAIN();
	var _this = this;
};
CSSMenu.prototype.onTreeParseComplete = onTreeParseComplete;


/// <menuObject>.MAIN:
/// The last step performed before the menu is ready to use. Fixes first level items in terms
/// of dimensions, final CSS applied specific hierarchic classes.
function MAIN() {
	var _this = this;
	this.headers.each (function(header, index, id) {
		var _li    = header.element;
		var _a     = header.link;
		var _img   = header.image;
		//user images support (level 1 only)
		if(_img) { 
			var width  = _img.getAttribute('width')  || null;
			var height = _img.getAttribute('height') || null;
			if(width && height) {
				_li.style.width      = (width + 'px');
				_li.style.height     = (height + 'px');
				_a.style.width      = (width + 'px');
				_a.style.height     = (height + 'px');
			} else {
				_li.style.width = 'auto';
				_a.style.width = 'auto';
				_a.style.height = 'auto';
			}
			_removeClass(_li, 'hasImg');
			_li.style.padding = '0px';
			_li.style.margin = '0px';
			_li.style.border = 'none';
			_li.style.backgroundImage = 'none';
			_li.style.backgroundColor = 'transparent';
			_img.style.padding = '0px';
			_img.style.margin = '0px';
			_img.style.border = 'none';
			_a.style.padding = '0px';
			_a.style.margin = '0px';
			_a.style.border = 'none';
			addClassName(_li, 'imgFlag');
		};
		//perform regular menuitem operations
		_this.menuItemCallback(header);
		header.visibleState = true;
		//for some reasons, I need to patch the holders for IE, on the EXPANDABLE layout...
		if(_this.type == 'expandable'){
			var ie6max = (is.ie && (is.version <=6));
			var holder = (header.gotHolder)? header.holder: _this.makeSubs(header);
			if(holder){
				if(ie6max){
					holder.style.display = 'none';
				};
			};
		};
	});
	//mark first & last headers: some skins need those...
	var firstHeader = this.headers.getFirst();
	addClassName(firstHeader.element, 'first');
	var lastHeader = this.headers.getLast();
	addClassName(lastHeader.element, 'last');
	//highlight current path
	var _mnuObj = this;
	window.setTimeout(function(){_mnuObj.makeHighlight()}, 10);
};
CSSMenu.prototype.MAIN = MAIN;


/// <menuObject>.makeHover:
/// The function is responsible of yelding the skin-specific appearance on mouse-over/mouse-out
/// events. Also this handles image changing for the custom images on first level case.
function makeHover(menuItem, direction){
	//for items that USE IMAGES:
	if(menuItem.image){
		var el        = menuItem.element;
		var selected  = menuItem.selected;
		var img       = el.getElementsByTagName('img')[0];
		var src       = img.src;
		//fail safe extracting the two patterns: OVER & SELECTED:
		if(this.config.hoverPattern){
			var h_pattern = this.config.hoverPattern.match(/\}(\w+)/)[1];
		};
		if(this.config.highliteCurrentFlag && this.config.highliteCurrentPattern) {
			var s_pattern = this.config.highliteCurrentPattern.match(/\}(\w+)/)[1];
		};
		switch(direction){
			case 'in':
				if(s_pattern) { 
					src = src.replace(new RegExp(s_pattern, 'g'), ''); 
				};
				if(h_pattern) { 
					src = src.replace(new RegExp(h_pattern, 'g'), '');
					src = src.replace(/([^\.]+)(\.\w+)$/, '$1'+h_pattern+'$2');
					el.getElementsByTagName('img')[0].src = src;
				};
				break;
			case 'out':
				if(h_pattern) {
					src = src.replace(new RegExp(h_pattern, 'g'),
						  (selected? (s_pattern || ''): ''));
					el.getElementsByTagName('img')[0].src = src;
				};
				break;
		};
		return;
	};
	//for items that DO NOT USE IMAGES:
	var box            = menuItem.element;
	var content        = menuItem.link;
	switch(direction) {
	 	case 'in':
				addClassName (box, 'hover');
				addClassName (content, 'hover');
			break;
	 	case 'out':
			    _removeClass(box, 'hover');
			    _removeClass(content, 'hover');
			break;
	};
};
CSSMenu.prototype.makeHover = makeHover;


/// <menuObject>.mouse_in:
/// This is invoked on any valid "mouse over" events. It takes layout specific decisions and 
/// calls layout specific actions (such as showing the children of an item on mouse over).
function mouse_in(menuItem) {
	var _this = this;
	this.lastModified = menuItem;
	//layout-dependant decisions are taken here:
	switch(this.type) {
		case 'horizontal':
			var sub_delayed = menuItem.isHeader? false: true;
			var use_HIDE_flag = true;
			break;
		case 'vertical':
			var sub_delayed = true;
			var use_HIDE_flag = true;
			break;
		case 'tab':
			var discard_children_flag = menuItem.isHeader? false: true;
			var use_HIDE_flag = true;
			break;
		case 'expandable':
			var discard_children_flag = true;
			var use_HIDE_flag = false;
			break;
	};
	// this produces the mouse-over effect:
	this.makeHover(menuItem, 'in');
	menuItem.mouse_state = 'in';
	// "hanging" behaviour / mouse out effect:
	// when leaving the menu, the entire highlighted path should stay highlighted on menu exit;
	this.lastHighlightedPath.each(function(item, index, id){
		if( !menuItem.path.get(id) ){
			_this.makeHover(item, 'out');
		};
	});
	this.lastHighlightedPath = menuItem.path;
	// "highlight track" behaviour:
	// when highlighting a menu Item, the entire path to it should be highlighted:
	menuItem.path.each(function(item, index, id){
		_this.makeHover(item, 'in');
	});
	// This clears the timeout of "hide the entire menu", if such a timeout has been set:
	var hideTimerID = _this.id + '_HIDDING';
	if(window[hideTimerID]) {
		window.clearTimeout(window[hideTimerID]);
		window[hideTimerID] = null;
	};
	// This clears the timeout of "remove highlight from all menu items", if such a timeout has
	// been set:
	var hOutTimerID = this.id + '_HOVER_OUT';
	if(window[hOutTimerID]) {
		window.clearTimeout(window[hOutTimerID]);
		window[hOutTimerID] = null;
	};
	// This clears the timeout of "show the children of other items", if such a timeout has been
	// set:
	var showSubTimerID = _this.id + '_SHOWING_SUB_TIMER';
	if(window[showSubTimerID]) {
		window.clearTimeout(window[showSubTimerID]);
		window[showSubTimerID] = null;
	};
	// "hide others" behaviour (a):
	// hide children of other items and remove any highlighting:
	if(use_HIDE_flag){
		var hideSubPanelsID = this.id + '_HIDING_SUB_PANNEL';
		if(sub_delayed) {
			window[hideSubPanelsID] = setTimeout(function() {
				_this.hideAll(_this.lastModified);
			}, _this.config.hideTimeout);
		} else {
			this.hideAll(menuItem);
		};
	};
	// This prevents showing the children of the current menu item (usefull for "two-level"
	// layouts).
	if(discard_children_flag) {
		return;
	};
	// This pops up the children of the current menu item.
	var holder = (menuItem.gotHolder)? menuItem.holder: this.makeSubs(menuItem);
	if(holder) {
		if(sub_delayed) {
			var showSubTimerID = this.id + '_SHOWING_SUB_TIMER';
			window[showSubTimerID] = window.setTimeout(function() {
				_this.showSub(menuItem);
			}, _this.config.showTimeout);
		} else {
			this.showSub(menuItem);
		};
	};
};
CSSMenu.prototype.mouse_in = mouse_in;


/// <menuObject>.mouse_out:
/// This is invoked on any valid "mouse out" events. It takes layout specific decisions and 
/// calls layout specific actions (such as hidding the children of an item on mouse out, or
/// setting a timeout for closing the menu).
function mouse_out(menuItem) {
	var _this = this;
	//layout-dependant decisions are taken here
	switch(this.type) {
		case 'horizontal':
			var use_HIDE_flag = true;
			break;
		case 'vertical':
			var use_HIDE_flag = true;
			break;
		case 'tab':
			var use_HIDE_flag = true;
			var persistent_tab_flag = this.config.persistentTab? true: false;
			break;
		case 'expandable':
			var use_HIDE_flag = false;
			break;
	};
	// This clears the timeout of "show the children of current menu item", if such a timeout
	// is set:
	var showSubTimerID = this.id + '_SHOWING_SUB_TIMER';
	if(window[showSubTimerID]) {
		window.clearTimeout(window[showSubTimerID]);
	};
	// "auto-blur" behaviour:
	// When mouse leaves menu for more than "exit_time", all highlight is removed from the menu:
	var hOutTimerID = this.id + '_HOVER_OUT';
	window[hOutTimerID] = window.setTimeout( function() {
		_this.lastHighlightedPath.each (function(item, index, id) {
			_this.makeHover(item, 'out');
		});
	}, this.config.exitTimeout);
	// This makes a persistent tab to cancel the default "auto-close" behaviour:
	if(persistent_tab_flag){
		return;
	};
	// "auto-close" behaviour:
	// When mouse leaves menu for more than "exit_time", all visible children are hidden:
	if(use_HIDE_flag){
		var hideTimerID = this.id + '_HIDDING';
		window[hideTimerID] = window.setTimeout( function() {
			_this.hideAll();
			_this.handleOverlays(menuItem, true);
		}, this.config.exitTimeout);
	};
};
CSSMenu.prototype.mouse_out = mouse_out;


/// <menuObject>.mouse_click:
/// This is invoked on any valid "mouse click" events. It takes layout specific decisions and 
/// calls layout specific actions (such as hidding all children of the menu when clicked one
/// item, or unfolding children -- on an expandable layout).
function mouse_click(menuItem, clickPoint) {
	var _this = this;
	//layout-dependant decisions are taken here
	switch(this.type) {
		case 'horizontal':
			break;
		case 'vertical':
			break;
		case 'tab':
			break;
		case 'expandable':
			var do_expand = true;
			break;
	};
	//this will expand the children of a menu Item in an expandable layout:
	if(do_expand) {
		this.changeExpandable(menuItem);
		if(menuItem.isHeader) {
			if(this.config.expandableBehaviour == 'accordion'){
				this.headers.each(function(headerItem, index, id){
						if(id != menuItem.id){
							if(headerItem.isParent){
								headerItem.expandedState = true;
								_this.changeExpandable(headerItem);
							};
						};
				});
			};
		};
		this.lastRequestedAction = null;
	};
	//this will hide children of all menu Items on mouse click (Windows native behaviour):
	this.hideAll();
	//highlight the current entry on demand; second parameter will prevent "expand"
	//action to take place twice on an expandable layout.
	this.makeHighlight(menuItem, true);
	// this will "click" a link inside of a menu Item, even if the click point was outside text
	// (ie 6+ issue); special care for the expandable layout, so that items that have
	// children, will expand those, instead of navigating to the embeded link:
	var ie6max = (is.ie && (is.version <=6));
	if(ie6max){
		if( clickPoint != 'a' ) {
            var link = menuItem.link;
            var may_sim_click = !do_expand ||
            					(do_expand && !menuItem.isHeader) ||
            					(do_expand && menuItem.isHeader && !menuItem.isParent);
            if(may_sim_click) {
            	link.click();
            };
		};
	};
};
CSSMenu.prototype.mouse_click = mouse_click;


/// <menuObject>.computeExpandedHeight:
/// Helper function. This is used by "<menuObject>.changeExpandable", and will help some browsers
/// -- notably Opera & Safari -- render the expandable layout correctly.
function computeExpandedHeight(menuItem, expandedState) {
	this.expandedHeight.set( (expandedState? menuItem.holderBox.height: 0), null, menuItem.id );
	var expandedHeight = 0;
	this.expandedHeight.each(function(height){
		expandedHeight += height;
	});
	var totalHeight = this._height + expandedHeight;
	return totalHeight;
};
CSSMenu.prototype.computeExpandedHeight = computeExpandedHeight;


/// <menuObject>.changeExpandable:
/// This is the main crossbrowser routine, responsible of the folding/unfolding behaviour of 
/// the expandable layout.
function changeExpandable(menuItem) {
	var ie6max = (is.ie && (is.version <=6));
	var _menuObj = this;
	if(menuItem.isHeader) {
		if(!menuItem.gotHolder){
			menuItem.holder = _menuObj.makeSubs(menuItem);
			setBox(menuItem.holder, menuItem.holderBox, 'width height');
		};
		if(menuItem.holder) {
			if(!menuItem.expandedState){
				if(!ie6max) {
					var _width = getCSSProperty(menuItem.element, 'width', 'number');
					_width = Math.round(_width) + 'px';
					menuItem.element.style.minWidth = _width;
					menuItem.element.style.width = '';
					if(is.opera || is.ie && is.v == 7){
						var totalHeight = _menuObj.computeExpandedHeight(menuItem, true);
						_menuObj.root.style.height = totalHeight + 'px';
						_menuObj.container.style.height = totalHeight + 'px';
					};
				};
				_menuObj.showSub(menuItem);
				menuItem.expandedState = true;
			} else {
				if(!ie6max) {
					var _mw = _menuObj.expandableWidth ||
							  (_menuObj.expandableWidth = getCSSProperty(menuItem.element, 
							  'min-width', 'number'));
					if(_mw > 0){
						menuItem.element.style.minWidth = '0px';
						menuItem.element.style.width = _mw + 'px';
					};
					if(is.opera || is.ie && is.v == 7){
						var totalHeight = _menuObj.computeExpandedHeight(menuItem, false);
						_menuObj.root.style.height = totalHeight + 'px';
						_menuObj.container.style.height = totalHeight + 'px';
					};
				};
				menuItem.holder.style.marginTop = '-5000px';
				if(ie6max){
					menuItem.holder.style.display = 'none';
				};
				menuItem.expandedState = false;
			};
		};
	};
};
CSSMenu.prototype.changeExpandable = changeExpandable;


/// <menuObject>.collapseAll:
/// Public use. This will be invoked when the user clicks the "Collapse all" link that may be 
/// generated in page along with an expandable menu.
function collapseAll() {
	if(this.type != 'expandable') { return };
	var _this = this;
	this.headers.each(function(headerItem){
		if(headerItem.isParent){
			headerItem.expandedState = true;
			_this.changeExpandable(headerItem);
		};
	});
	this.config.expandableBehaviour = 'accordion';
};
CSSMenu.prototype.collapseAll = collapseAll;


/// <menuObject>.expandAll:
/// The complementary functionality of <CSSMenu>.collapseAll. This will be invoked when the user
/// clicks the "Expand all" link that may be generated in page along with an expandable menu.
function expandAll() {
	if(this.type != 'expandable') { return };
	var _this = this;
	this.headers.each(function(headerItem){
		if(headerItem.isParent){
			headerItem.expandedState = false;
			_this.changeExpandable(headerItem);
		};
	});
	this.config.expandableBehaviour = 'multiple';
};
CSSMenu.prototype.expandAll = expandAll;


/// <menuObject>.makeSubs:
/// This function is responsible for preparing the children of an item, so that they can be
/// shown in page. It has a one-time-only run for each parent item, and performs children group
/// specific computations -- such as enforcing the box dimensions for some browsers, attaching 
/// animators, if user choose to use any, and placing CSS classes for complex skins support.
function makeSubs(menuItem){
	var _this = this;
	menuItem.children.each(function(subItem){
		_this.menuItemCallback(subItem);
	});
	var firstItem = menuItem.children.getFirst();
	var lastItem = menuItem.children.getLast();
	if(firstItem){addClassName(firstItem.element, 'first')};
	if(lastItem){addClassName(lastItem.element, 'last')};
	var holder = menuItem.holder;
	if(holder){
		addClassName(holder, (this.id + '_el'));
		var placement = (this.type != 'tab')? 'V' : 'H';
		menuItem.holderBox = getHolderBox(holder, menuItem.children.getHash(), placement);
		if(!is.ie || (is.ie && (this.type == 'tab')) ) {
			setBox(holder, menuItem.holderBox, 'width');
			if(this.type == 'tab') {
				var functor = function(){
					if((typeof holder.clientHeight != 'undefined') &&
					    (holder.clientHeight > menuItem.holderBox.height)){
						menuItem.holderBox.width += 1;
						setBox(holder, menuItem.holderBox, 'width');
						if(holder.offsetHeight > menuItem.holderBox.height){
						window.setTimeout( functor, 0);
						};
					};
				};
				window.setTimeout( functor, 0);
			};
		};
		//ANIMATION support
		if(typeof ANIMATOR != 'undefined') {
			if((this.type == 'horizontal') || (this.type == 'vertical')) {
				if(this.config.animationEffect) {
					menuItem.animator = new ANIMATOR(this.config.animationEffect);
					if(menuItem.animator) {
						menuItem.animator.attachTo(menuItem.holder);
						menuItem.animator.relateTo(menuItem.element);
					};
				};
			};
		};
	};
	menuItem.gotHolder = true;
	return holder;
};
CSSMenu.prototype.makeSubs = makeSubs;


/// <menuObject>.applySubOffs:
/// This function allows the user to specify an offset to children groups that pop-up in page
/// (i.e., they can overlap their parent, or open at a distance from it). Also this compensates
/// for borders, for skins that use them.
function applySubOffs(menuItem) {
	var response = {'x': 0, 'y': 0}
	var horz_flow = (this.type == 'horizontal') || (this.type == 'tab');
	var level_1 = menuItem.isHeader;
	//implicit offsets
	if(horz_flow){
		if(level_1){ 
			response.y += this.attachOffset.borders.ROOT.BOTTOM 
		} else {
			response.x += this.attachOffset.borders.HOLDER.LEFT;
		};
	} else {
		response.x += this.attachOffset.borders.HOLDER.LEFT;
		if(level_1){ response.x += this.attachOffset.borders.ROOT.RIGHT };
	};
	//explicit (user) offsets
	if(level_1) {
		response.x += this.config.offset_X_level_1;
		response.y += this.config.offset_Y_level_1;
	} else {
		response.x += this.config.offset_X_level_2_plus;
		response.y += this.config.offset_Y_level_2_plus;
	};
	return response;
};
CSSMenu.prototype.applySubOffs = applySubOffs;



/// <menuObject>.showSub
/// The core display engine of the menu, the one that actually provides the menu behaviour. It
/// computes where a certain children group should display in page, apply all offsets to this
/// position and displays the group. Also, this handles some advanced features, such as "put into
/// view" -- children groups will try to allways stay in the visible area of the page.
function showSub(menuItem) {
	/*
	 * module 1: "I must check for any offsets that can influence the positioning, such as
	 * 			 borders, margins, etc."
	 * 
	 * */
	if(this.attachOffset === null) {
		this.attachOffset = {};
		this.attachOffset.borders = {};
		this.attachOffset.borders.HOLDER = {};
		this.attachOffset.borders.ROOT = {};
				
		if( getCSSProperty(menuItem.holder, 'border-left-style', 'boolean') ) {
			this.attachOffset.borders.HOLDER.LEFT = getCSSProperty(menuItem.holder,
			'border-left-width', 'number');
		} else { menuItem.holder.style.borderLeftWidth = '0px' };

		if( getCSSProperty(menuItem.holder, 'border-top-style', 'boolean') ) {
			this.attachOffset.borders.HOLDER.TOP = getCSSProperty(menuItem.holder,
			'border-top-width', 'number');
		} else { menuItem.holder.style.borderTopWidth = '0px' };
		
		if( getCSSProperty(this.root, 'border-right-style', 'boolean') ){
			this.attachOffset.borders.ROOT.RIGHT = getCSSProperty(this.root, 
			'border-right-width', 'number');
		} else { this.root.style.borderRightWidth = '0px' };
		
		if( getCSSProperty(this.root, 'border-bottom-style', 'boolean') ) {
			this.attachOffset.borders.ROOT.BOTTOM = getCSSProperty(this.root, 
			'border-bottom-width', 'number');
		} else { this.root.style.borderBottomWidth = '0px' };
	};
	
	/*
	 * module 2: "I must determine the point to show the sub-menu at, relative to parent
	 * 			 position and the menu type (not appliable to expandable layout). Also
	 * 			 vertical & horizontal layouts may have animation."
	 * 
	 */
	switch (this.type) {
		case "horizontal":
		case "vertical":
		case "tab":
			var LI_cor = menuItem.corner || (menuItem.corner = getCorner(menuItem));
			var LI_zTh = menuItem.stack || (menuItem.stack = getStack(menuItem));
			var LI_box = getElBox(menuItem.element);
			var LI_anc = getAtPoint(LI_box, LI_cor, menuItem);
			
			menuItem.holder.style.zIndex = LI_zTh;
			menuItem.holder.style.visibility = 'hidden';
			
			LI_anc = getBoxesSum( LI_anc, this.applySubOffs(menuItem) );
			
			// positioning the children of current menuItem object
			// The <sg_Pos_Check_Flag>:
			// * normally, a double position check must be done for all children positioning;
			// * however, some browsers crash if double checking children of headers
			// * all browsers will crash if double checking children of headers, and the menu is
			//   absolutely positioned.
			//
			// The <bfBox>:
			// * some erratic offsets may arrise, they are browser dependant. bfBox is a tests
			//   based matrix that should fix this.
			
			var _fixOffsetsLev1 =  menuItem.isHeader && (is.safari || this.sg_Pos_Check_Flag);
			var _fixOffsetsLev2 = !menuItem.isHeader && (is.safari);
			if(_fixOffsetsLev1){
				LI_anc.x += this.abs_Pos_Flag? this.bfBox.Absolute.x1: this.bfBox.Static.x1;
				LI_anc.y += this.abs_Pos_Flag? this.bfBox.Absolute.y1: this.bfBox.Static.y1;
			};
			if(_fixOffsetsLev2){
				LI_anc.x += this.abs_Pos_Flag? this.bfBox.Absolute.x2: this.bfBox.Static.x2;
				LI_anc.y += this.abs_Pos_Flag? this.bfBox.Absolute.y2: this.bfBox.Static.y2;
			};
			if(menuItem.isHeader) {
				if(this.sg_Pos_Check_Flag) {
					setBox(menuItem.holder, LI_anc, 'x y');
				} else {
					setBox(menuItem.holder, LI_anc, 'x y');
					setBox(menuItem.holder, dblCheck(menuItem, LI_anc), 'x y');
				}
			} else {
				setBox(menuItem.holder, LI_anc, 'x y');
				setBox(menuItem.holder, dblCheck(menuItem, LI_anc), 'x y');
			};
			
			//"put into view" feature; works on certain browsers only
			var ie50 = (is.ie && is.version < 5.5);
			var op9 = (is.opera && is.version <= 9);
			if(!ie50 && !is.safari && !op9){
				var inView = putIntoView(menuItem);
			   	if(inView) {
			    	setBox(menuItem.holder, inView, 'x y');
				  	setBox(menuItem.holder, dblCheck(menuItem, inView), 'x y');
				};
			};
			
			menuItem.visibleState = true;
			break;
		case "expandable":
			menuItem.holder.style.margin = '0px';
			var ie6max = this.isIe6Max || ( this.isIe6Max = (is.ie && (is.version <=6)) );
			if(ie6max){
				menuItem.holder.style.display = 'block';
			};
			if(is.opera) {
				menuItem.holder.style.marginTop = '0px'
				if(!menuItem.expandedOnce){
					menuItem.children.each(function(item){
						item.element.style.position = 'static';
					});
					menuItem.expandedOnce = true;
				};
			};
			break;
	};
	/*
	 * module 3: "Common tasks: hide objects that one cannot draw above, play animation
	 * (if any), and list sub-panels shown as being visible"
	 */
	this.handleOverlays(menuItem);
	if(menuItem.animator) { menuItem.animator._start(true) };
	menuItem.holder.style.visibility = 'visible';
	this.visibles.set(menuItem, null, menuItem.id);
};
CSSMenu.prototype.showSub = showSub;


/// <menuObject>.hideAll:
/// This function is responsible of hidding a children group when it is not needed anymore.
function hideAll(exeption){
	//"hide anything but EXEPTION and the path that leads to it":
	var path = exeption? getPath(exeption): null;
	var _this = this;
	this.visibles.each(function(item, index, id){
		if(item.visibleState){
			if(!path || (path && !path.get(id)) ) {
				_this.makeHover(item, 'out');
				item.mouse_state = 'out';
				//expandable layout does not supports this type of hidding:
				if(_this.type != 'expandable'){
					item.holder.style.visibility = 'hidden';
					if(item.animator) {
						item.animator.state = -1;
					};
					setBox(item.holder, {'x':-5000,'y': -5000}, 'x y');
					item.visibleState = false;
				};
			};
		};
	});
};
CSSMenu.prototype.hideAll = hideAll;


/// <menuObject>.makeHighlight:
/// This is ment to provide a "highlight" effect for the item that points to the current page
/// -- and also to the path that leads to it. However, the server-side highlight class can be 
/// used to highlight any desired item.
function makeHighlight(response, silent) {
	//rules:
	//	"server side highlight always take precedence"
	//	"client side highlight returns first item in the menu that matches"
	//  "on client side, smallest possible substring is matched"
	if(!this.config.highliteCurrentFlag) { return };
	var _menuObj  = this;
	if (response == null) {
		//fail safe: 
		// 	"if using images, but no highlight pattern was specified, exit"
		var __first = this.allItems.getFirst();
		var __useImages = __first.image? true: false;
		var __haveHiPatt =  this.config.highliteCurrentPattern? true: false;
		if(__useImages && ! __haveHiPatt) { return };
		//find the item to be highlighted:
		var response;
		var currHref = window.location.href.toLowerCase();
		var response = null;
		var hiliteSERVER = null;
		var hiliteCLIENT = null;
		this.allItems.reverseEach ( function(item) {
			var LI = item.element;
			if ( new RegExp(_menuObj.classes['selected_server_side']).test(LI.className)) {
				 hiliteSERVER = item;
			};
			var A = item.link;
			var href = A.href.toLowerCase();
			if(!(/#$/.test(href))) {
				if( href.indexOf(currHref) >= 0 ) {
					 hiliteCLIENT = item;
				};
			 };
		});
		response = hiliteSERVER? hiliteSERVER: hiliteCLIENT;
	}
	//highlight the item:
	if(response) {
		//If already have a selected path, clear that path:
		if (this.selected != null) {
			var path_to_highlight = getPath(this.selected);
			path_to_highlight.each(function(item, index, id){
				if(item.image){
					var el = item.element;
					var img = item.image;
					var src = img.src;
					if(item.mouse_state != 'in') {
						if(_menuObj.config.highliteCurrentPattern){
							var s_pattern =
								_menuObj.config.highliteCurrentPattern.match(/\}(\w+)/)[1];
							src = src.replace(new RegExp(s_pattern, 'g'), '');
							el.getElementsByTagName('img')[0].src = src;
						};
					};
				} else {
					var LI = item.element;
					var A = item.link;
					_removeClass(LI, _menuObj.classes['selected']);
					_removeClass(A, _menuObj.classes['selected']);
				};
			});
		};
		//Now that there's no highlight anymore, we may highlight the current path:
		this.selected = response;
		var path_to_highlight = getPath(response);
		path_to_highlight.each(function(item, index, id){
			item.selected = true;
			if(item.image){
				var el = item.element;
				var img = item.image;
				var src = img.src;
				// Items that are currently "mouse-hovered" are not highlighted;
				// instead, their "highlighted" appeareance	is restored on 
				// mouse out:
				if(item.mouse_state != 'in') {
					//start from a clear file name
					if (_menuObj.config.hoverPattern) {
						var h_pattern = _menuObj.config.hoverPattern.match(/\}(\w+)/)[1];
					};
					if (h_pattern) {
						src = src.replace(new RegExp(h_pattern, 'g'), '');
					};
					if(_menuObj.config.highliteCurrentPattern){
						var s_pattern = 
							_menuObj.config.highliteCurrentPattern.match(/\}(\w+)/)[1];
						src = src.replace(new RegExp(s_pattern, 'g'), '');	
						//switch to the 'selected' file
						src = src.replace(/([^\.]+)(\.\w+)$/, '$1'+s_pattern+'$2');
						el.getElementsByTagName('img')[0].src = src;
					};
				};
			} else {
				var LI = item.element;
				var A = item.link;
				addClassName(LI, _menuObj.classes['selected']);
				addClassName(A, _menuObj.classes['selected']);
			};
			// some custom behaviours:
			//	"the layout expandable must auto-expand a header if it is selected"
			//	"a persistent tab will auto open its selected item:"
			if(item.isHeader){
				if(_menuObj.type == 'expandable'){
					if(!silent){
						_menuObj.changeExpandable(item);
					};
				};
				if((_menuObj.type == 'tab') && _menuObj.config.persistentTab){
					_menuObj.mouse_in(item);
				};
			};
		});
	};
};
CSSMenu.prototype.makeHighlight = makeHighlight;


/// <menuObject>.incrementRootWidth:
/// Helper function. Used by <menuObject>.beforeALL, to *desperately* put on the same line
/// menu items that wrap, while they shouldn't. Hovever this is a *last* resort, and generally
/// if this get run, there's something wrong with either the skin, either the browser.
CSSMenu.prototype.incrementRootWidth = function(){
	var testY;
	if(!this.dropped) { return };
	if( ((typeof this.dropped.offsetTop != 'undefined')? 
	    this.dropped.offsetTop: getElBox(current).y) >= this.currentY ){
		this.root.style.width = (this._width += 1) + 'px';
		var _this = this;
		if(!is.mac && (is.ie || is.mozilla)) {
			_this.incrementRootWidth();
		} else {
			window.setTimeout(function() {
				_this.incrementRootWidth();
			} , 0);
		};
	} else {
		this.root.style.overflow = 'visible';
		this.container.style.overflow = 'visible';
	};
};

/// <menuObject>.beforeALL:
///
/// This function runs *before* any tree parsing, therefor any modifications it performs take
/// effect instantly. It is used to fix miscelaneous things, mostly browser CSS related issues
/// (enforcing dimensions, setting CSS temporar classes, monitoring images progress).
function beforeALL() {
	//
	// 1. handles the appearence of the first level menu, making sure 
	//    TAB & HORIZONTAL items do not ever wrap, rather produce 
	//    a horizontal scroolbar. 
	// 2. handles the loading of the first level images, when used
	// 3. adds the FIRST & LAST classes (needed by some skins) on the 
	//    first level, before the menu is actually parsed
	// 4. Firefox crashes when using expandable layout with images on first level, AND images 
	// 	  have explicit dimensions via the width/height attributes. To avoid inconsitancy across,
	//    browsers, images will allways have their natural dimensions only. Couldn't find a way 
	//	  around this...
	
	//values to operate with:	
	this._width          = 0;
	this._height         = 0;
	this._margins		 = 0;
	this.imageRecipients = [];
	this.cachedImageList = false;
	this.gotMargins      = false;
	this.allImagesLoaded = true;
	var last             = null;
	var lastWidth        = 0;
 	var _this            = this;
	var current          = this.first;
	var imgFlag          = /(hasImg)|(imgFlag)/.test(current.className);
	
	//go trough the first level items:
	while(current){
		if((current.nodeType == 1) && 
		   (current.nodeName.toLowerCase() == 'li')) {
			last = current;
			if(!imgFlag) {
				//for non-image first levels, add widths of item boxes (height is fixed):
				if((this.type == 'horizontal') || (this.type == 'tab')) {
					//adding the "FIRST" class:
					if(!this.addedFirst) {
						addClassName(current, 'first');
						this.addedFirst = true;
						this._width += 
							(typeof current.offsetWidth != 'undefined')? current.offsetWidth: 
					         getElBox(current).width;
					} else {
						this._width += (
									   lastWidth = (
									   (typeof current.offsetWidth != 'undefined')? 
									   current.offsetWidth: getElBox(current).width));
					};
				} else {
					if(!is.safari && !is.mozilla){
						this._width = Math.max(this._width, 
									  (typeof current.offsetWidth != 'undefined')? current.offsetWidth: 
						              getElBox(current).width);
					};
				};
				//same fancy skins use margins on the first level LIs...
				if(!this.gotMargins){
					var mL = getCSSProperty(current, 'margin-left', 'number');
					var mR = getCSSProperty(current, 'margin-right', 'number');
					var mB = mL + mR;
					this._margins = mB;
					this.gotMargins = true;
				};
				if((this.type == 'horizontal') || (this.type == 'tab')) {
					this._width += this._margins;
					if(!this._height){
						this._height += (typeof current.offsetHeight != 'undefined')?
					    	             current.offsetHeight: getElBox(current).height;
					};
				} else {
					if(!is.safari && !is.mozilla) {
						this._height += (typeof current.offsetHeight != 'undefined')?
						    	             current.offsetHeight: getElBox(current).height;
					};
				};
			} else {
				//for first levels that use images, cache a list of them
				if(!this.cachedImageList){
					_Array_push(this.imageRecipients, [current, false]);
				};
			};
		};
		current = current.nextSibling;
	};
	this.cachedImageList = true;
	
	//adding the "LAST" class
	if(!this.addedLast) {
		addClassName(last, 'last');
		this.addedLast = true;
		if((this.type == 'horizontal') || (this.type == 'tab')){
			this._width -= lastWidth;
			this._width += this.widthOfLastClass || (
						   this.widthOfLastClass = ((typeof last.offsetWidth != 'undefined')?
							last.offsetWidth: getElBox(last).width) );
		};
	};
	
	//go through the cached image list and succesivelly check if a particular image has loaded;
	//once it has, update the recipient with the total width so far (height is fixed):
	if(imgFlag) {
		this._width -= this.widthOfLastClass;
		this.widthOfLastClass = 0;
		_Array_each(this.imageRecipients, function(record, index){
			var did_load = record[1];
			var image = record[0].getElementsByTagName('img')[0];
			if(image.getAttribute('width')){ image.removeAttribute('width') };
			if(image.getAttribute('height')){ image.removeAttribute('height') };			
			if(!did_load){
				if(image.complete){
					_this.imageRecipients[index][1] = true;
					var __w = image.width;
					var __h = image.height;
					if((_this.type == 'horizontal') || (_this.type == 'tab')) {
						_this._width += __w;
					} else {
						if(!is.safari && !is.mozilla){
							_this._width = Math.max(_this._width, __w);
						};
					};
					if((_this.type == 'horizontal') || (_this.type == 'tab')) {
						if(!_this._height){ _this._height = __h };
					} else {
						if(!is.safari && !is.mozilla){
							_this._height += __h;
						};
					};
					if(__w){
						record[0].style.width = __w + 'px';
						image.setAttribute('width', __w);
					};
					if(__h){
						if(!(_this.type == 'expandable' && (is.mozilla || is.opera))){
							record[0].style.height = __h + 'px';
							image.setAttribute('height', __h);
						} else {
							record[0].getElementsByTagName('a')[0].style.height = __h + 'px';
						};
					};
				} else {
					_this.allImagesLoaded = false;
				};
			};
		});
		if(!this.allImagesLoaded){
			window.setTimeout(function(){_this.beforeALL()}, 10);
		};
	} else {
		//for non-image first level, take into account the quirks mode on IE, before 
		//applying the computed width to the recipient:
		var quirksDelta  = (is.ie && !strictm)?
		                   (this.root.offsetWidth - this.root.clientWidth): 0;
		var quirksDelta2 = (is.ie && !strictm)?
		                   (this.root.offsetHeight - this.root.clientHeight): 0;
		                   
		                   
		if(this._width) {this._width += quirksDelta};
		if(this._height) { this._height += quirksDelta2 };
		
	};
	if(this._width && this.allImagesLoaded){
		this.root.style.width = this._width + 'px';	
		this.container.style.width = this._width + 'px';
	};
	if(this._height && this.allImagesLoaded){
		_this.root.style.height = _this._height + 'px';
		_this.container.style.height = _this._height + 'px';
	};
	
	//perform a final, double check: should the computed width be wrong for some reasons, and
	//some items DID wrap, this check should make the recipient large enough to fit them on one 
	//line.
	if((this.type != 'horizontal') && (this.type != 'tab')) {return};
	if(!imgFlag || (imgFlag && this.allImagesLoaded)){
		var y = null;
		this.dropped = null;
		this.currentY = null;
		var current = this.first;
		while(current) {
			if((current.nodeType == 1) && (current.nodeName.toLowerCase() == 'li')) {
				this.currentY = (typeof current.offsetTop != 'undefined')?
					       current.offsetTop: getElBox(current).y;
				if( y === null ){ y = this.currentY };
				if(this.currentY != y) {
					this.dropped = current;
				};
			};
			current = current.nextSibling;
		};
		if(this.dropped){
			if(!is.mac && is.mozilla) {
				_this.incrementRootWidth();
			} else { window.setTimeout(function() {_this.incrementRootWidth()}, 0) };
		};
	};
};
CSSMenu.prototype.beforeALL = beforeALL;


/// <menuObject>.processEvent:
/// Event manager. Every event that fires on a menu item passes through this function, that 
/// decides wheter the event must be followed, and what function to run for that event. This 
/// reduces the load on the CPU.  
function processEvent(e) {
	// handles all mouse actions:
	// 	- stops event propagation down the DOM tree
	// 	- gets the function to call
	// 	- gets the <menuItem> argument to that call
	// 	- performs low level filtering:
	// 		- disregards current event if it cannot provide a valid menu Item
	// 		- disregards IN/OUTs of type "LI" -> "A own child" / "A -> LI own parent"
	// 		- no consecutive same type actions on same menu Item
	// 	- dispatches the call to the executant
	if(typeof e.stopPropagation == 'function') { e.stopPropagation() };
	if(typeof e.cancelBubble != 'undefined') { e.cancelBubble = true };

	var toRun;
	switch(e.type){
		case 'mouseover':
			toRun = 'mouse_in';
			break;
		case 'mouseout':
			toRun = 'mouse_out';
			break;
		case 'click':
			toRun = 'mouse_click';
			var send_click_point = true;
			break;
	};
	
	var menuElement = e.currentTarget || e.srcElement;
	if(menuElement && menuElement.nodeName){
		switch(menuElement.nodeName.toLowerCase()){
			case 'li':
				var _LI = menuElement;
				break;
			case 'a':
				var _LI = menuElement.parentNode;
				break;
			case 'img':
				var _LI = menuElement.parentNode.parentNode;
		};
		if(_LI) { var menuItem = this.allItems.get(_LI.id) };
		if(send_click_point) { var clickPoint = menuElement.nodeName.toLowerCase() };
	};
	
	if(!menuItem){ return };
	// NOTE: Safari seems to handle different the click event, so I do not filter two consecutive
	// click events on Safari.
	var elementTarget = e.relatedTarget || e.toElement;
	if(!is.safari){
		if(this.lastRequestedItem && (this.lastRequestedItem.link == elementTarget)) { return };
	} else {
		if(toRun != 'mouse_click') {
			if(this.lastRequestedItem && (this.lastRequestedItem.link==elementTarget)){return};
		};
	};
	if(this.lastRequestedItem && (this.lastRequestedItem.element == elementTarget)) { return };
	this.lastRequestedItem = menuItem;
	
	if( this.lastRequestedItem && (this.lastRequestedItem === menuItem) &&
	    this.lastRequestedAction &&(this.lastRequestedAction === toRun) ) { return };
	if( this.safetyRequestDelay ) { return };
	this.lastRequestedAction = toRun;
	
	if(e.type == 'mouseout'){ this.lastRequestedItem = null	};
	if(send_click_point) {
		this[toRun](menuItem, clickPoint);
	} else {
		this[toRun](menuItem);
	};
};
CSSMenu.prototype.processEvent = processEvent;


/// <menuObject>.menuItemCallback:
/// Similar with the "on node" callback routine of the parser. Gets called on menuItems before
/// a group is shown in the page. Attaches mouse events and performs general last fixes/settings.
function menuItemCallback(menuItem) {
	//save each menu Item's path:
	if(!menuItem.path){ menuItem.path = getPath(menuItem) };
	//disable '#' links
	this.disableLink(menuItem); 
	//set mouse events
	var _menuObj = this;
	_attachEvent(menuItem.element, 'mouseover', function(e){_menuObj.processEvent(e)} );
	_attachEvent(menuItem.element, 'mouseout' , function(e){_menuObj.processEvent(e)} );
	_attachEvent(menuItem.element, 'click'    , function(e){_menuObj.processEvent(e)} );
	//add arrows
	if(!menuItem.image) {
		if(menuItem.isParent){
			if(!this.isTwoLevel||(this.isTwoLevel && menuItem.isHeader)){
				addClassName(menuItem.link, _menuObj.classes['arrow']);
			};
		};
	};
	//hide focus rectangle
	concealLink(menuItem.link);
	//no menuItem will be selectable
	if(is.mozilla){
		menuItem.element.style.MozUserSelect = 'none';
	} else if(is.ie){
		_attachEvent(menuItem.element, 'selectstart', function(e){
			e.returnValue = false;
			return false
		})
	};
};
CSSMenu.prototype.menuItemCallback = menuItemCallback;


/// getPageBox:
/// Helper function. Returns the box of the view port, as reported by the browser.
function getPageBox(){
	var response = {
		'x':	  0,
		'y':      0,
		'width':  0,
		'height': 0
	};
	//get width
	if(typeof self.innerWidth != 'undefined') {
		response.width = self.innerWidth;

	};
	if(!response.width) {
		if((typeof document.documentElement != 'undefined') && 
			(typeof document.documentElement.clientWidth != 'undefined')) {
	  		response.width  = document.documentElement.clientWidth;
		};
	};
	if(!response.width) {
		if(typeof document.body != 'undefined') {
			response.width = document.body.clientWidth;
		};
	};
	//get height
	if(typeof self.innerHeight != 'undefined') {
		response.height = self.innerHeight;

	};
	if(!response.height) {
		if((typeof document.documentElement != 'undefined') && 
			(typeof document.documentElement.clientHeight != 'undefined')) {
	  		response.height  = document.documentElement.clientHeight;
		};
	};
	if(!response.height) {
		if(typeof document.body != 'undefined') {
			response.height = document.body.clientHeight;
		};
	};
	return response;
};


/// getBoxesDelta:
/// Helper function. will, respectivelly, substract values of boxB from values of boxA.
function getBoxesDelta(oBoxA, oBoxB){
	var oResponse = {};
	for(var k in oBoxA){
		if(!isNaN(parseInt(oBoxB[k]))){
			oResponse[k] = oBoxA[k]-oBoxB[k];
		};
	};
	return oResponse;
};


function getBoxesSum(oBoxA, oBoxB){
	/// -->
	/// will, respectivelly, add values of boxA and boxB.
	/// -->
	var oResponse = {};
	for(var k in oBoxA){
		if(typeof oBoxB[k] != 'undefined');
		oResponse[k] = oBoxA[k] + oBoxB[k];
	};
	return oResponse;
}


function getBoxesMin(oBoxA, oBoxB){
	/// -->
	/// will return a new box containing, respectivelly, the smallest
	/// values found in each one of the two.
	/// -->
	var oResponse = {};
	for(var k in oBoxA){
		if(typeof oBoxB[k] != 'undefined');
		oResponse[k] = Math.min(oBoxA[k], oBoxB[k]);
	};
	return oResponse;
};


function getBoxesMax(oBoxA, oBoxB){
	/// -->
	/// will return a new box containing, respectivelly, the greatest
	/// values found in each one of the two.
	/// -->
	var oResponse = {};
	for(var k in oBoxA){
		if(typeof oBoxB[k] != 'undefined');
		oResponse[k] = Math.max(oBoxA[k], oBoxB[k]);
	};
	return oResponse;
};


function getElBox(el) {
	/// -->
	/// gets an element's position relative to the view port
	/// -->
	var SAFARI_FLAG = is.safari? true: false;
	
	var posAttribute  = getCSSProperty(el, 'position', 'string');
	var topAttribute  = getCSSProperty(el, 'top', 'string');
	var leftAttribute = getCSSProperty(el, 'left', 'string');
	var boxBefore, boxAfter;
	switch(posAttribute){
		case '':
		case 'static':
		case 'relative':
		case 'absolute':
		case 'fixed':
			boxBefore = getLayout(el);
			for (var k in boxBefore){
				boxBefore[k] = parseInt(boxBefore[k]);
			};
			if(SAFARI_FLAG){
				return boxBefore; 
			};
			
			el.style.top = 'auto';
			el.style.left = 'auto';
			el.style.position = 'absolute';
			
			boxAfter = getLayout(el);
			for(var L in boxAfter){
				boxAfter[L] = parseInt(boxAfter[L]);
			};
			
			el.style.position = posAttribute;
			el.style.top = topAttribute;
			el.style.left = leftAttribute;
			break;
	};

	var delta = getBoxesDelta(boxBefore, boxAfter);
	var newBox = getBoxesSum(boxAfter, delta);
	return newBox;
};


function setBox(el, box, crt){
	/// -->
	/// sets the specified coordinates of the given box
	/// on the target element. The third parameter can be 'all',
	/// or a space separated coordinate names list, i.e 
	/// 'x y width height'.
	/// -->
	
	if(!box){ return };
	
	var toSet = {
		'x': 		['left',	false],
		'y': 		['top',		false],
		'z':		['zIndex',  false],
		'width': 	['width', 	false],
		'height': 	['height', 	false]
	};
	
	for (var k in toSet){
		var pattern = new RegExp('\\b'+k+'\\b|\\ball\\b','i');
		if( pattern.test(crt) ){
		toSet[k][1] = true;
		}
	};
	
	for (var L in toSet){
		if(toSet[L][1]){
			el.style[toSet[L][0]] = box[L] + 'px';
		};
	};	
};



function getBoxInc(boxA, boxB){
	/// 
	/// 
	/// checks if the 'B' box is visually 'included' in the 'A' box;
	/// that is, if the first is entirely painted on screen inside 
	/// the area occupied by the second. 
	/// 
	var response = {'horizontal': false, 'vertical': false};
	var B_starts_at_A_start_horrizontally = (boxB.x == boxA.x)? 
		true: false;
	var B_starts_at_A_start_vertically = (boxB.y == boxA.y)?
		true: false;
	var B_ends_at_A_end_horrizontally = 
		( (boxB.x + boxB.width) == (boxA.x + boxA.width) )?
		true: false;
	var B_ends_at_A_end_vertically =
		( (boxB.y + boxB.height) == (boxA.y + boxA.height))?
		true: false;
	var B_starts_inside_A_horrizontally = 
		B_XstartsInside = ( (boxB.x > boxA.x) && 
		                    (boxB.x < boxA.x + boxA.width) )?
							true: false;
	var B_starts_inside_A_vertically = 
		( (boxB.y > boxA.y) && (boxB.y < boxA.y + boxA.height) )?
		true: false;
	var B_ends_inside_A_horrizontally =
		( ( (boxB.x+boxB.width)>boxA.x) && 
		  ( (boxB.x + boxB.width)<(boxA.x+boxA.width) ) )?
		true: false;
	var B_ends_inside_A_vertically = 
		( ( (boxB.y + boxB.height) > boxA.y) && 
		  ( (boxB.y+boxB.height) < (boxA.y + boxA.height) ) )? 
		true: false;
	if( (B_starts_inside_A_horrizontally ||
	     B_starts_at_A_start_horrizontally) &&
		(B_ends_inside_A_horrizontally || 
		 B_ends_at_A_end_horrizontally) ){
		response.horizontal = true;
	};
	if( (B_starts_inside_A_vertically || 
	     B_starts_at_A_start_vertically) &&
		(B_ends_inside_A_vertically || 
		 B_ends_at_A_end_vertically)){
		response.vertical = true;
	};
	return response;
};


function getAtPoint(box, corner, menuItem){
	/// 	
	/// gets the attachement point for a sub-menu. generally, 
	/// a sub-menu will be positioned at one of the four corners of 
	/// it's parent box. Thge function returns the actual x,y values of
	/// the selected corner. Corners are refered as: 'TL', 'TR', 'BL',
	/// 'BR'.
	/// -->
	var SAFARI_FLAG = is.safari? true: false;
	var owner = menuItem.owner;
	var response = { 'x': null, 'y': null };
	switch(corner){
		case 'TL':
			response.x = box.x;
			response.y = box.y;
			break;
		case 'TR':
			response.x = (box.x + box.width);
			response.y = box.y;
			break;
		case 'BR':
			response.x = (box.x + box.width);
			response.y = (box.y + box.height);
			break;
		case 'BL':
			response.x = box.x;
			response.y = (box.y + box.height)
			break;
		case 'FBL':
			var firstEl = owner.first;
			var tmpBox  = getElBox(firstEl);
			response.x  = tmpBox.x;
			response.y  = (tmpBox.y + tmpBox.height);
	};
	
	if(SAFARI_FLAG){
		response.x += getCSSProperty(document.body, 'margin-left', 'number');
		response.y += getCSSProperty(document.body, 'margin-top', 'number');
	};
	
	return response;
};


function getCorner(menuItem){
	/// -->
	/// tells the parent corner name a sub-items panel should
	/// attach to, based on the menu type and the parent position 
	/// (top, down the tree).
	/// -->
	var response;
	var menuType     = menuItem.owner.type;
	var isFirstLevel = menuItem.isHeader;
	if(isFirstLevel){
		switch(menuType){
			case 'vertical':
				response = 'TR';
				break;
			case 'horizontal':
			case 'expandable':
				response = 'BL';
				break;
			case 'tab':
				response = 'FBL'
				break;
		};
	} else {
		response = 'TR';
	};
	return response;
};




function getPath(menuItem){
	/// 
	/// returns a linear path to 'el', starting from the first 
	/// parent LI, that can be found.
	/// 
	var response = new Assoc_Array();
	var _menuObj = menuItem.owner;
	var EL = menuItem;
	while(EL){
		if(typeof EL.nodeType != 'undefined') {
			//this is HACK!!! 
			//why is this happening? I get an HTML node as parent...
			EL = _menuObj.allItems.get(EL.id);
		};
		response.push(EL, EL.id);
		EL = EL.parent_node
	};
	return response;
};





function getMenuType (root){
	/// -->
	/// gets the type of the menu
	/// -->
	var response;
	var classes = root.parentNode.className;
	response = classes.split(' ')[0];
	response = response.replace(/^kt/, '');
	response = response.toLowerCase();
	return response;
};





function disableLink(menuItem){
	var link = menuItem.link;
	var href = link.href;
	var enforce = ((this.type == 'expandable') && menuItem.isParent && menuItem.isHeader);
	if(enforce || (/#$/.test(href))) {
		menuItem._href = href;
		link.removeAttribute('href');
		link.style.cursor = 'default';
		menuItem.element.style.cursor = 'default';
	} else {
		if(is.ie){
			link.style.cursor = 'hand';
			menuItem.element.style.cursor = 'hand';
		} else {
			link.style.cursor = 'pointer';
			menuItem.element.style.cursor = 'pointer';
		};
	};
};
CSSMenu.prototype.disableLink = disableLink;


function concealLink(el){
	/// -->
	/// hides the thin dotted gray border, that links receive in most
	/// browsers when they have focus.
	/// -->
	if(is.mozilla){ el.style.MozOutline = 'none' };
	if(is.ie)     { el.hideFocus = true };
	el.style.outline = 'none';
	
};





function putIntoView(menuItem){

	/// -->
	/// this will eventually keep the entire menu whithin the viewport
	/// -->
	
	var elBox    = getElBox(menuItem.holder);
	var pageBox  = getPageBox();
	var _menuObj = menuItem.owner;
	pageBox.width  += _menuObj.config.safeBox[0];
	pageBox.height += _menuObj.config.safeBox[1];	
	var elFitReport = getBoxInc(pageBox, elBox);
	
	var elFits = (elFitReport.horizontal && elFitReport.vertical);
	if(elFits){
		return null;
	};

	var response = {'x': elBox.x, 'y': elBox.y};
	var placement = (_menuObj.type != 'tab')? 'V' : 'H';
	var holderBox = menuItem.holderBox || 
	               (menuItem.holderBox = getHolderBox(menuItem.holder, 
	                                                  menuItem.children.getHash(), 
	                                                  placement));
	if(!elFitReport.horizontal){
	    elBox.width = holderBox.width;
		var elEnd   = elBox.x + elBox.width;
		var pgEnd   = pageBox.width;
		var delta   = elEnd - pgEnd;
		response.x -= delta;
		response.x = Math.max(0, response.x);
	};
	if(!elFitReport.vertical){
		elBox.height = holderBox.height;
		var elEnd    = elBox.y + elBox.height;
		var pgEnd    = pageBox.height;
		var delta    = elEnd - pgEnd;
		response.y  -= delta;
		response.y = Math.max(0, response.y);
	};
	return response;
};


function dblCheck( menuItem, attachPoint, enforcedTest ){
	/// -->
	/// double checks if the final targeted LIs inside the 'holder'
	/// element are positioned at the very point there were intended 
	/// to. Some browsers generate positioning errors even at 
	/// this final stage.
	/// Safari seems to crash if double checking the position of a header's direct child...
	/// -->
	var holder    = menuItem.holder;
	var testEl    = enforcedTest || holder.getElementsByTagName('li')[0];
	if(!testEl){ return };
	var testBox   = is.safari? getLayoutOldWay(testEl): getElBox(testEl);
	var testDelta = getBoxesDelta(testBox, attachPoint);
	if(is.safari){
		menuItem.DELTA = testDelta;
	};
	
	var response  = getBoxesDelta(attachPoint, testDelta );
	return response;
};


function getStack (menuItem) {
	/// -->
	/// returns the stack index 'el' should have, so that it draws
	/// above all its ascendants.
	/// -->
	var path = getPath(menuItem);
	response = path.length * 100;
	return response;
};





function getTargEl(event){
	/// -->
	/// returns the target element of the 'event', crossbrowser wise.
	/// -->
	var response = 
		(typeof event.relatedTarget != 'undefined')?
			event.relatedTarget: 
		(typeof event.toElement != 'undefined')?
			event.toElement: null;
	return response;
};





function getSubHold (el, groups){
	/// -->
	/// gets the holder (DIV element) that contains the sub-items of
	/// the current item ('el').
	/// -->
	var holder = null;
	if( getSubs(el, groups) ){
		for(var i=0; i<groups.length; i++){
			var group = groups[i];
			if(group[0] === el){
				holder = group[2];
				break;
			};
		};	
	};
	return holder;
};


function getHolderBox(container, elements, placement){
	var box = { 'width':0, 'height':0 };
	if(is.safari){
		var borders = { 'T':null, 'R':null, 'B':null, 'L':null};
	};
	if(placement == 'H'){
		for(var k in elements) {
			var LI = elements[k].element;
			var currBox = getElBox(LI);
			if(is.safari) {
				var bLeft  = (borders.L !== null)? borders.L: 
							 (borders.L = getCSSProperty(LI, 'margin-left-width', 'number'));
				var bRight = (borders.R !== null)? borders.R: 
							 (borders.R = getCSSProperty(LI, 'margin-right-width', 'number'));
			};
			box.width += currBox.width;
			box.height = Math.max(box.height, currBox.height);
		};
	} else if(placement == 'V'){
		for(var k in elements){
			var LI = elements[k].element;
			var currBox = getElBox(LI);
			if(is.safari){
				var bLeft  = (borders.L !== null)? borders.L: 
							 (borders.L = getCSSProperty(LI, 'border-left-width', 'number'));
				var bRight = (borders.R !== null)? borders.R: 
							 (borders.R = getCSSProperty(LI, 'border-right-width', 'number'));
			};
			box.width = Math.max(box.width, currBox.width);
			box.height += currBox.height;
		};
	};
	if(is.safari) { box.width += (bLeft + bRight) };
	return box;
};
function getCurrEl(event){
	/// 
	/// returns the LI that current 'event' operates on, in a 
	/// crossbrowser manner.
	/// 
	var el = (typeof event.currentTarget != 'undefined')?
	         event.currentTarget:
	         (typeof event.srcElement != 'undefined')? 
		     event.srcElement: null;
	return el || null;
};

function handleOverlays(menuItem, restore_hidden_FLAG) {
	/**
	 * The purpose of this function is to hide a set of HTML objects known 
	 * not to allow anything else to be drawn over (this includes FLASH, IFRAMES, etc).
	 * @member CSSMenu
	 * @version 2.0 (rewritten from scratch)
	 * @param {CSSMenu.menuItem} menuItem The object linked to the expanded item beneath
	 * @return void
	 */
	var _this = this;
	if( !menuItem ){ return };
	if( !this.config.hideOverlayObjects ){ return };

	if(!restore_hidden_FLAG) {
		
		/*
		 * MODULE 1:
		 * cache the areas occupied by each menu holder (expandedPathRegions).
		 */ 
		var expandedPath = getPath(menuItem);
		var expandedPathRegions = new Assoc_Array();
		expandedPath.each( function( expandedItem, index, id ) {
			var holder = expandedItem.holder;
			var holderBox = getLayout(holder);
			var holderRegion = new Assoc_Array();
			holderRegion.push( parseInt(holderBox.y), 'top' );
			holderRegion.push( parseInt(holderBox.x), 'left' );
			holderRegion.push( parseInt(holderBox.y + holderBox.height), 'bottom' );
			holderRegion.push( parseInt(holderBox.x + holderBox.width), 'right' );
			expandedPathRegions.push(holderRegion, id);
		});
		 
		 /*
		  * MODULE 2:
		  * Define the veto-able handlers
		  */
		 var checkFlashWmode = function(flashObject) {
			var browserWmodeMatrix = {
				'pc': {
					'ie': { 
						'50100': ['OPAQUE', 'TRANSPARENT'],'55000':['OPAQUE', 'TRANSPARENT'],
						'60000': ['OPAQUE', 'TRANSPARENT'],'70000':['OPAQUE', 'TRANSPARENT'],
						'W3C_compliant': true},
					'firefox': {
						'10000'  : ['OPAQUE', 'TRANSPARENT'], '15000': ['OPAQUE'],
						'W3C_compliant': false},
					'opera': {
						'85000': ['OPAQUE', 'TRANSPARENT'],'90000':['OPAQUE', 'TRANSPARENT'],
						'W3C_compliant': true},
					'netscape': {
						'17000': ['OPAQUE'],
						'W3C_compliant': false}
					 },
				'mac': {
					'safari': {
						'13200': ['OPAQUE', 'TRANSPARENT'],'14000':['OPAQUE', 'TRANSPARENT'],
						'W3C_compliant': true},
					'mozilla': {
						'17000': ['OPAQUE', 'TRANSPARENT'],
						'W3C_compliant': false},
					'firefox': {
						'15000': ['OPAQUE', 'TRANSPARENT'],
						'W3C_compliant': true}
				}
			};
			
			/*
			 * I also need the "browserWmodeMatrix" outside this function, but I'd rather not
			 * keep it in memory -- as it's large and expected to grow -- so I use
			 * a trick: calling "checkFlashWmode" without parameters will just return 
			 * "browserWmodeMatrix" and then exit.
			 */
			if(!flashObject) { return browserWmodeMatrix };
			
			var WMODE = 'none';
			var allObjectParams = _this.allObjectParams || (
								  _this.allObjectParams=document.getElementsByTagName('param'));
			if(flashObject.nodeName.toLowerCase() == 'object'){
				for(var i=0; i<allObjectParams.length; i++){
					/* OR ELSE, it won't work, a single OBJECT object will 
					 * return ALL params in the page -- how weird...
					 */
					if(allObjectParams[i].parentNode.id == flashObject.id) {
						var ownParam = allObjectParams[i];
						if( ownParam.getAttribute('name') &&
							ownParam.getAttribute('name').toLowerCase() == 'wmode' ) {
							var wmodeParam = ownParam;
							if(wmodeParam.getAttribute('value')){
								var WMODE = wmodeParam.getAttribute('value').toLowerCase();
							};
						};
						
					};
				};
			} else {
				if(flashObject.nodeName.toLowerCase() == 'embed'){
					WMODE = flashObject.getAttribute('wmode') || WMODE;
				};
			};
			var _platform = _this._platform || (_this._platform = (is.mac? 'mac': 'pc'));
			var _browser = _this._browser || (_this._browser = (_this.isSomeFirefox? 
				'firefox': (navigator.userAgent.match(/netscape.([\d\.]{3,8})/i))?
				'netscape': function(){
					for( var testName in browserWmodeMatrix[_platform]){
						if( is[testName] ) {return testName };
					};
				}()));
			var _version = _this._version || (_this._version = (function() {
				var returnVersion = '0';
				var raw_vers = (_this.ff_vers || is.version).toString().replace(/\./g, '');
				while (raw_vers.length < 5){ raw_vers += '0' };
				var processed_vers = parseInt(raw_vers.substr(0,5));
				for (var recognized_version in browserWmodeMatrix[_platform][_browser]){
					var rV = parseInt(recognized_version);
					if(rV <= processed_vers){
						returnVersion = rV;
					};
				};
				return returnVersion.toString();
			}()));
			var allowedWmodeValues = browserWmodeMatrix[_platform][_browser][_version];
		 	var vetoResponse = new RegExp(WMODE,'i').test(allowedWmodeValues);
		 	return vetoResponse;
		 };
		 var checkIeVersion = function() {
		 	var vetoResponse = (!is.ie)? false: (is.version < 7)? true: false;
		 	return vetoResponse;
		 };
		 var checkForIeMozilla = function() {
		 	var vetoResponse = (is.ie || (is.mozilla && !is.safari))? true: false;
		 	return vetoResponse;
		 };
	
		/*
		 * MODULE 3:
		 * define the objects to be handled and the handler to be used for each. The handler 
		 * provides a "veto" response on the question of hidding or not the element, based upon
		 * intrinsic element properties (i.e. will only hide SELECT elements on IE <= 6).
		 */
		 var overlayElementsList = new Assoc_Array();
		 overlayElementsList.push(checkFlashWmode, 'object');
		 overlayElementsList.push(checkFlashWmode, 'embed');
		 overlayElementsList.push(checkIeVersion, 'select');
		 overlayElementsList.push(checkForIeMozilla, 'iframe');
		 
		 /*
		  * MODULE 4:
		  * Take decision, by passing trough all overlay elements, and checking wheter 
		  * they overlap the expanded menu, and whether the veto-able handler doesn't 
		  * enforce the overlay element to be shown.
		  */ 
		overlayElementsList.each( function(vetoAbleFunctor, counter, elTagName) {
			var ELEMENTS = document.getElementsByTagName(elTagName);
			var VETO = vetoAbleFunctor;
			for(var i=0; i<ELEMENTS.length; i++){
				var EL = ELEMENTS[i];
				
				/*
				 * Generally, a given browser knows to render flash using either old
				 * (non W3C_compliant) <EMBED> tag, either the new generic <OBJECT> tag,
				 * but not both. However, Opera "supports" both, but ignores <EMBED> tags
				 * when nested inside <OBJECT> tags.
				 * 
				 * I also must programatically ignore them, or they'll ruin positioning 
				 * calculation -- these nested EMBEDs will always have X/Y at 0/0.
				 */
				if(_this._browser == 'opera'){
					if(/embed/i.test(EL.nodeName)){
						if(/object/i.test(EL.parentNode.nodeName)){
							var matrix = checkFlashWmode();
							var w3c = matrix[_this._platform][_this._browser]['W3C_compliant'];
							if(w3c){ continue };
						};
					};
				};
				
				var EL_BOX = getLayout(EL);
				var EL_REGION = new Assoc_Array();
				EL_REGION.push( parseInt(EL_BOX.y), 'top' );
				EL_REGION.push( parseInt(EL_BOX.x + EL_BOX.width), 'right' );
				EL_REGION.push( parseInt(EL_BOX.y + EL_BOX.height), 'bottom' );
				EL_REGION.push( parseInt(EL_BOX.x), 'left' );
				
				var EL_overlaps_any = function(){
					var toret = false;
					expandedPathRegions.each( function(menuRegion) {
				    	var t = Math.max(menuRegion.get('top'), EL_REGION.get('top'));
				    	var r = Math.min(menuRegion.get('right'), EL_REGION.get('right'));
				    	var b = Math.min(menuRegion.get('bottom'), EL_REGION.get('bottom'));
				    	var l = Math.max(menuRegion.get('left'), EL_REGION.get('left'));
				    	if (b >= t && r >= l) {
				    		toret = true
				    	} else {
				    		toret = false
				    	};
					});
					return toret;
				}();

				if(EL_overlaps_any){
					var vetoResult = VETO(EL);
					if(!vetoResult){
						EL.style.visibility = 'hidden';
					};
				} else {
					EL.style.visibility = '';
				};
			};
		});
	} else {
		var overlayElementsList = new Array('object', 'embed', 'select', 'iframe');
		_Array_each(overlayElementsList, function(EL){
			var tmpCollection = document.getElementsByTagName(EL);
			_Array_each(tmpCollection, function(htmlObj){
				htmlObj.style.visibility = '';
			});
		});
	}
};
CSSMenu.prototype.handleOverlays = handleOverlays;

//some public interface goes here (for now...)
var allCSSMENUS2 = new Assoc_Array();
function getMenuObjectById(id){
	return allCSSMENUS2.get(id);
};


function Expandable_hideAll(menuId) {
	var _mnu = getMenuObjectById(menuId);
	_mnu.collapseAll();
};

function Expandable_showAll(menuId) {
	var _mnu = getMenuObjectById(menuId);
	_mnu.expandAll();
};
