// This script is not freeware!
//
// Multi-Level Drop-Down Menu 2.82
// You can find and buy latest version of the script
// at the http://spicebrains.com/multi-level-drop-down-menu/
//
// Copyright 2008 SpiceBrains.com
////////////////////////////////////////////////////////////////////////////////////////////////////

var _debug = 0;

// global initializations parameters
if (!mlddm_effect)
{
	var mlddm_shiftx = 0;
	var mlddm_shifty = 0;
	var mlddm_timeout = 500;
	var mlddm_effect = 'none';
	var mlddm_effect_speed = 300;
	var mlddm_orientation = 'h';
	var mlddm_direction = true;
	var mlddm_delay = 0;
	var mlddm_highlight = true;
	var mlddm_closeonclick = false;
	var mlddm_md = 375;
}

// global variables
var MLDDM_CLASS = 'mlddm';  //	menu identifier
var obj_menu = new Array(); //	for store menu objects

// initialize all menus identified by <ul class="mlddm">
function mlddminit(md7)
{
	//mlddm_md = md7;

	// fill the array with all <ul> objects
	var candidates = document.getElementsByTagName('ul');
	var index = 0;

	// check all candidates
	for (var i = 0; i < candidates.length; i++)
	{
		// creating menu objects
		if (candidates[i].className == MLDDM_CLASS)
		{
			// show menu
			candidates[i].style.visibility = 'visible';

			// read initialization parameters
			var obj = candidates[i];
			var value = obj.getAttribute('params');

			// create an object and store the handler
			obj_menu[index] = new menu(obj, index, value);
			index++;
		}
	}
}

// single layer prototype
function layer(handler)
{
	this.handler = handler;       // pointer to an object
	this.showed = false;          // showed/hidden flag
	this.level = 0;               // level
	this.x = 0;                   // x relative position
	this.y = 0;                   // y relative position
	this.xa = 0;                  // x absolute position
	this.ya = 0;                  // y absolute position
	this.outerwidth = 0;          // layer's width (outer)
	this.outerheight = 0;         // layer's height (outer)
	this.innerwidth = 0;          // layer's width (inner)
	this.innerheight = 0;         // layer's height (inner)
	this.border = 0;              // border width
	this.topmargin = 0;           // top margin
	this.shifter = 0;             // height of the block of inner nodes up to child layer
	this.parentindex = 0;         // parent's layer index
	this.reverse = false;         // default or reverse position (if not enough horizontal space)
	this.timeouts = new Array();  // pointers to the background open/hide timeout functions
	this.degree = 0;              // current degree of slide/fade effect
	this.button = null;           // parent button of the current layer
	this.buttoncss = new Array(); // default and hover css of the parent button
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// main menu class
// receive the object handler, object number, and initialization parameters string
function menu(obj, obj_n, params)
{
	// variables declaration ************************************************************/
	var _handler = obj;       // mlddm obj
	var _obj_num = obj_n;     // quantity of menu objects (if there are more than one)
	var _me = this;           // alternative pointer to itself
	var _opentimer = null;    // open timer handler
	var _closetimer = null;   // close timer handler
	var _mouseout = true;     // flag (to avoid multi-triggering)
	var _currentlayer = null; // active layer (mouseover)
	var _activestate = false; // at least one layer are showed

	// default parameters
	var _shiftx = mlddm_shiftx;             // ?orizontal submenu shifting (in pixels)
	var _shifty = mlddm_shifty;             // vertical submenu shifting (in pixels)
	var _timeout = mlddm_timeout;           // default timeout
	var _effect = mlddm_effect;             // default effect (can be none, slide or fade)
	var _effect_speed = mlddm_effect_speed; // specifies the visual effect speed
	var _orientation = mlddm_orientation;   // specifies the horizontal or vertical orientation (can be 'h' or 'v')
	var _direction = mlddm_direction;       // on/off automatic submenus direction (submenus on left side then not enoght right space)
	var _delay = mlddm_delay;               // delay before top-level menus appears
	var _highlight = mlddm_highlight;       // on/off highlight of the active items
	var _closeonclick = mlddm_closeonclick; // on/off closing menu when onclick event happens

	// read parameters from html and change local variables
	var params_array;

	if (params)
	{
		params_array = params.split(",");

		if (params_array[0])
			_shiftx = params_array[0] * 1; // *1 - string to numeral convert

		if (params_array[1])
			_shifty = params_array[1] * 1;

		if (params_array[2])
			_timeout = params_array[2] * 1;

		if (params_array[3])
			_effect = params_array[3];

		if (params_array[4])
			_effect_speed = params_array[4] * 1;

		if (params_array[5])
			_orientation = params_array[5];

		if (params_array[6])
			_direction = params_array[6] * 1;

		if (params_array[7])
			_delay = params_array[7] * 1;

		if (params_array[8])
			_highlight = params_array[8] * 1;

		if (params_array[8])
			_closeonclick = params_array[9] * 1;

		// it is not allowed if effect speed is equal to zero
		if (!_effect_speed)
			_effect_speed = 1000;
	}

	// pointer to all layers array
	this._layer = new Array();

	// methods declaration **************************************************************/
	// private:

	// fade in/fade out effect
	function opacity(index, opac_start, opac_end, speed)
	{
		var current_layer = _me._layer[index];

		//clear timeouts for current layer and get current degree
		for (var z = 0; z < current_layer.timeouts.length; z++)
		clearTimeout(current_layer.timeouts[z]);

		var degree = current_layer.degree;

		// speed for each frame
		var speed = Math.round(1000 / speed);
		var timer = 0;

		// determine the direction for the blending,
		// if 'start' and 'end' are the same nothing happens
		if (degree < opac_end) // show
		{
			for (var i = degree; i <= opac_end; i = i + 4)
			{
				current_layer.timeouts[timer] = setTimeout("changeOpac(" + _obj_num + "," + index + "," + i + ")", (timer * speed));
				timer++;
			}
		}
		else if (degree > opac_end) // hide
		{
			for (var i = degree; i >= opac_end; i = i - 4)
			{
				current_layer.timeouts[timer] = setTimeout("changeOpac(" + _obj_num + "," + index + "," + i + ")", (timer * speed));
				timer++;
			}
		}
	}

	// slide effect
	function slide(index, direction, speed)
	{
		var current_layer = _me._layer[index];

		//clear timeouts for current layer and get current degree
		for (var z = 0; z < current_layer.timeouts.length; z++)
		clearTimeout(current_layer.timeouts[z]);

		var degree = current_layer.degree;

		// speed for each frame
		var speed = Math.round(1000 / speed);
		var timer = 0;

		if (_orientation == 'h')
			_ori = 0; // horizontal
		else
			_ori = 1; // vertical

		// determine the direction
		if (direction == 'show')
		{
			for (i = degree; i <= 100; i = i + 2)
			{
				current_layer.timeouts[timer] = setTimeout("changePOS(" + _obj_num + "," + index + "," + i + "," + _ori + ")", (timer * speed));
				timer++;
			}
		}
		else if (direction == 'hide')
		{
			for (i = degree; i >= 0; i = i - 2)
			{
				current_layer.timeouts[timer] = setTimeout("changePOS(" + _obj_num + "," + index + "," + i + "," + _ori + ")", (timer * speed));
				timer++;
			}
		}
	}

	// return level of the layer
	function getlevel(layer)
	{
		var level = 0;
		var currentobj = layer;

		while (currentobj.className != MLDDM_CLASS)
		{
			if (currentobj.nodeName == 'UL')
				level++;
			currentobj = currentobj.parentNode;
		}
		return level;
	}

	// check the state of the menu (active/passive)
	// and store it in the global variable
	function updateglobalstate()
	{
		_activestate = false;

		for (var i = 0; i < _me._layer.length; i++)
			if (_me._layer[i].showed)
			{
				_activestate = true;
				break;
			}
	}

	// open hidden layer
	function mopen(index)
	{
		if (!_me._layer[index].showed && (mlddm_md == 375)) // proceed only if layer is hidden
		{
			if (_effect == 'fade')
				opacity(index, 0, 100, _effect_speed); // show using fade effect
			else if (_effect == 'slide')
				slide(index, 'show', _effect_speed);   // show using slide effect
			else
				_me._layer[index].handler.style.visibility = 'visible';

			highlight_button(index, true);
			_me._layer[index].showed = true; // change status in the hash
			_activestate = true;             // at least one layer is visible
		}
	}

	// close showed layer
	function mclose(index)
	{
		if (_me._layer[index].showed) // proceed only if layer is visible
		{
			if (_effect == 'fade')
				opacity(index, 100, 0, _effect_speed); // hide using fade effect
			else if (_effect == 'slide')
				slide(index, 'hide', _effect_speed);   // hide using slide effect
			else
				_me._layer[index].handler.style.visibility = 'hidden';

			highlight_button(index, false);
			_me._layer[index].showed = false; // change status in the hash
		}

		// if first level going to close - update global 'active state'
		if (_me._layer[index].level == 1)
			updateglobalstate();
	}

	// activate/passivate item while child layer is visible
	function highlight_button(index, activate)
	{
		var cl = _me._layer[index]; // current layer

		if (activate && _highlight && cl.button)
			cl.button.style.cssText = cl.buttoncss[1];
		else if (_highlight && cl.button)
			cl.button.style.cssText = cl.buttoncss[0];
	}

	// return index of the layer by handler
	function getlayerindex(obj)
	{
		for (i = 0; i < _me._layer.length; i++)
		{
			if (_me._layer[i].handler == obj)
				return i;
		}
		return -1;
	}

	// return index of the parent layer
	function getparentindex(layer)
	{
		while (layer.className != MLDDM_CLASS)
		{
			layer = layer.parentNode;

			if (layer.nodeName == 'UL')
				return getlayerindex(layer);
		}

		return -1;
	}

	// get top margin
	function gettopmargin(obj)
	{
		var top = obj.offsetTop;
		obj.style.marginTop = '0px';
		var margintop = top - obj.offsetTop;
		obj.style.marginTop = margintop + 'px';
		return margintop;
	}

	// get height of the parent item
	function getparentheight(obj)
	{
		while (obj.className != MLDDM_CLASS)
		{
			obj = obj.parentNode;

			if (obj.nodeName == 'LI')
				break;
		}

		return obj.getElementsByTagName("a")[0].offsetHeight; // return height of parent <a> node
	}

	// find parent li node, return first button within li node
	function getparentbutton(obj)
	{
		if (obj.className == MLDDM_CLASS)
			return null;

		while (obj.nodeName != 'LI')
			obj = obj.parentNode;
		return getchildnode(obj, 'A');
	}

	// cancel onstart delay timer
	function canceldelay()
	{
		if (_opentimer)
		{
			window.clearTimeout(_opentimer);
			_opentimer = null;
		}
	}

	// set close timer
	function mclosetime()
	{
		_closetimer = window.setTimeout(_me.pcloseall, _timeout);
	}

	// cancel close timer
	function mcancelclosetime()
	{
		if (_closetimer)
		{
			window.clearTimeout(_closetimer);
			_closetimer = null;
		}
	}

	// get and store current and active style of the button
	function storebuttoncss()
	{
		// find style of the active button by selector string and store it
		var noin_selector = '.' + MLDDM_CLASS + ' > li > a:hover'.toLowerCase(); // noinheritance selector
		var root_selector = '.' + MLDDM_CLASS + ' li a:hover'.toLowerCase();     // regular root selector
		var next_selector = '.' + MLDDM_CLASS + ' ul li a:hover'.toLowerCase();  // inner selector
		var noin_style = '';                                                     // container for the style code
		var root_style = '';                                                     // container for the style code
		var next_style = '';                                                     // container for the style code

		// find stylesheets
		var cssrules = new Array();

		for (var i = 0; i < document.styleSheets.length; i++)
		{
			try
			{
				cssrules[cssrules.length] = document.styleSheets[i].cssRules || document.styleSheets[i].rules;
			}
			catch (err)
			{
			}
		}

		// pass through all cssrules of the current stylesheet and store required style
		for (var j = 0; j < cssrules.length; j++)
		{
			for (var k = 0; k < cssrules[j].length; k++)
			{
				var rule = cssrules[j][k];

				if (!rule.selectorText)
					continue;

				if (rule.selectorText.toLowerCase() == noin_selector)
					noin_style = rule.style.cssText;
				else if (rule.selectorText.toLowerCase() == root_selector)
					root_style = rule.style.cssText;
				else if (rule.selectorText.toLowerCase() == next_selector)
					next_style = rule.style.cssText;
			}
		}

		// pass through all layer's parent buttons
		var cl = _me._layer; // current layer

		for (var z = 0; z < cl.length; z++)
		{
			if (cl[z].button)
				cl[z].buttoncss[0] = cl[z].button.style.cssText;    // store default style

			if (cl[z].button && cl[z].level == 1)
				cl[z].buttoncss[1] = root_style + ';' + noin_style; // store active style

			if (cl[z].button && cl[z].level > 1)
				cl[z].buttoncss[1] = root_style + ';' + next_style; // store active style
		}
	}

	// recalculate and set new position for all layers
	function setpositions(client_width, scroll_left)
	{
		var max_right = client_width + scroll_left;

		// reset all positions to default state
		for (var i = 0; i < _me._layer.length; i++)
		{
			if (_me._layer[i].level > 1)
			{
				_me._layer[i].handler.style.left = _me._layer[i].x + 'px';
				_me._layer[i].reverse = false;
			}
		}

		// if not enought horizontal space for layer - change positon of the layer to reverse
		for (var i = 0; i < _me._layer.length; i++)
		{
			var current_layer = _me._layer[i];

			if (current_layer.level > 1)
			{
				var layer_width = current_layer.outerwidth;
				var border_width = current_layer.border;
				var layer_absx = findPos(current_layer.handler)[0];

				if ((layer_absx + layer_width + border_width * current_layer.level - border_width) > max_right && _direction)
				{
					current_layer.handler.style.left = -layer_width - _shiftx + 'px';
					current_layer.reverse = true;
				}
			}
		}
	}

	//public methods:
	// public menu open method with timer
	this.pmopentime = function(index)
	{
		if (!_activestate)
		{
			_activestate = index;
			_opentimer = setTimeout("openLayer(" + _obj_num + "," + index + ")", _delay);
		}
		else
			mopen(index);
	};

	// mouseover event handler (current object is li-node)
	this.eventover = function()
	{
		if (_mouseout)            // to avoid multi-triggering
		{
			_mouseout = false;    // reset flag
			mcancelclosetime();   // cancel timeout
			var currentli = this; // current li node

			// if current li node have child layer, it will be shown
			var layer = currentli.getElementsByTagName("ul")[0];
			var ind = getlayerindex(layer);

			if (ind >= 0)
				_me.pmopentime(ind);

			// collect pointers to all layers that will be shown
			var open_layers = new Array();

			// try to find first layer within current li node
			open_layers[0] = currentli.getElementsByTagName("ul")[0];

			if (!open_layers[0])
				open_layers[0] = 0;

			// collect
			var currobj = currentli.parentNode;
			var num = 0;

			while (currobj.className != MLDDM_CLASS)
			{
				if (currobj.nodeName == 'UL')
				{
					num++;
					open_layers[num] = currobj;
				}
				currobj = currobj.parentNode;
			}

			// layers to hide
			var layers_to_hide = new Array(_me._layer.length);

			// fill with false values
			for (var i = 0; i < layers_to_hide.length; i++)
			layers_to_hide[i] = false;

			// set true flags to all visible layers
			for (var i = 0; i < open_layers.length; i++)
			layers_to_hide[getlayerindex(open_layers[i])] = true;

			// hide all layers with false flag
			for (var i = 0; i < layers_to_hide.length; i++)
				if (!layers_to_hide[i] && (_currentlayer != open_layers[0]))
					mclose(i);

			// show and save current layer
			_currentlayer = open_layers[1];
		}
	};

	this.eventclick = function()
	{
		if (getchildnode(this, null).nodeName == 'A')
		{
			_mouseout = true;
			_me.pcloseall();
		}
	};
	this.eventout = function()
	{
		_mouseout = true;
	}; // set mouseout flag
	this.allout = function()
	{
		mclosetime();
		canceldelay();
	}; // turn on close timer / turn off onstart delay
	this.allover = function()
	{
		mcancelclosetime();
	}; // cancel close timer
	this.eventresize = function()
	{
		setpositions(getClientWidth(), getScrollLeft());
	}; // re-set on resize
	this.eventscroll = function()
	{
		setpositions(getClientWidth(), getScrollLeft());
	}; // re-set on scroll
	this.pcloseall = function()
	{
		for (var i = 0; i < _me._layer.length; i++)
		{
			if (_mouseout)
				mclose(i);
		}
	}; // public close all layers

	// constructor **************************************************************************/
	if (document.getElementById('debug'))
		_debug = document.getElementById('debug');
	_debug.value = '';

	// find all li nodes and set mouse event handlers
	// also create all layer objects
	var all_li = _handler.getElementsByTagName("li");
	this._layer[0] = new layer(_handler); // create zero-level layer (root ul)

	for (var z = 0; z < all_li.length; z++)
	{
		// find <ul>-nodes and create layer objects
		var layer_handler = all_li[z].getElementsByTagName("ul")[0];

		if (layer_handler)
			this._layer[this._layer.length] = new layer(layer_handler);

		// set mouse event handlers
		all_li[z].onmouseover = this.eventover;
		all_li[z].onmouseout = this.eventout;

		if (_closeonclick)
			all_li[z].onclick = this.eventclick;
	}

	// setup event handlers
	_handler.onmouseout = this.allout;      // set global mouseout event handler
	_handler.onmouseover = this.allover;    // set global onmouseover event handler

	if (_direction)
		window.onresize = this.eventresize; // set onresize event handler

	if (_direction)
		window.onscroll = this.eventscroll; // set onmove event handler
	document.onclick = this.pcloseall;

	// calculate inner width of current layer
	// and set width though css for current layer (for avoid some incompatibility bugs)
	for (var num = 1; num < this._layer.length; num++)
	{
		var nodesww = this._layer[num].handler.childNodes; // all nodes (with whitespaces) within current layer
		var nodes = new Array();                           // all nodes (without whitespaces) within current layer
		var specific_nodes = new Array();                  // non <a>-tags within li (deviders, etc)
		var maxwidth = 0;                                  // width of widest <a>-tag

		// clear array from whitespaces
		for (var x = 0; x < nodesww.length; x++)
		{
			if (!is_ignorable(nodesww[x]))
				nodes[nodes.length] = nodesww[x];
		}

		// temporary disable all <li> where non-<a> nodes (deviders, etc) (ie6 fix)
		// and store to specific_nodes array for following enable
		for (var y = 0; y < nodes.length; y++)
		{
			var dnodes = nodes[y].getElementsByTagName("*");

			if (dnodes.length && !is_ignorable(dnodes[0]) && dnodes[0].nodeName != 'A')
			{
				dnodes[0].style.display = 'none';
				specific_nodes[specific_nodes.length] = dnodes[0];
			}
		}

		// calculate inner width (width of widest <a>-tag)
		for (var z = 0; z < nodes.length; z++)
		{
			var anodes = nodes[z].getElementsByTagName("a");

			if (anodes[0])
			{
				var width = anodes[0].offsetWidth;

				if (width > maxwidth)
					maxwidth = width;
			}
		}

		// make visible specific nodes
		for (var s = 0; s < specific_nodes.length; s++)
		specific_nodes[s].style.display = 'block';

		// set width though css for current layer
		this._layer[num].handler.style.width = maxwidth + 'px';
	}

	// calculate and store specific parameters for each layer
	for (var num = 0; num < this._layer.length; num++) // pass all layers
	{
		try
		{
			var cl = this._layer[num];                     // current layer

			cl.level = getlevel(cl.handler);
			cl.parentindex = getparentindex(cl.handler);
			cl.outerwidth = cl.handler.offsetWidth;
			cl.outerheight = cl.handler.offsetHeight;
			cl.innerwidth = getchildnode(cl.handler.getElementsByTagName("li")[0], null).offsetWidth;
			cl.innerheight = 0;
			cl.border = (cl.outerwidth - cl.innerwidth) / 2;
			cl.topmargin = gettopmargin(cl.handler);
			cl.shifter = getparentheight(cl.handler);
			cl.button = getparentbutton(cl.handler);
		}
		catch (Exception)
		{
			return false;
		}
	};

	// pass all layers set and store default positions
	for (var num = 0; num < this._layer.length; num++)
	{
		var level = this._layer[num].level; // get level of current layer
		var cl = this._layer[num];          // get current layer

		// if horizontal orientation: first level layer already have correct position
		if ((_orientation == 'h' && level > 1) || (_orientation == 'v' && level > 0))
		{
			// store default relative position
			// Note: offsetTop returns vertical layer position without top-margin
			cl.x = this._layer[cl.parentindex].innerwidth + _shiftx;
			cl.y = cl.handler.offsetTop - cl.topmargin - cl.shifter + _shifty;

			// setup new positions
			cl.handler.style.left = cl.x + 'px';
			cl.handler.style.top = cl.y + 'px';
		}
		else // store coordinates to all other layers
		{
			cl.x = cl.handler.offsetLeft;
			cl.y = cl.handler.offsetTop - cl.topmargin;
		}

		//store default absolute positions
		cl.xa = findPos(cl.handler)[0];
		cl.ya = findPos(cl.handler)[1];
	}

	// scan style sheet for 'hover' pseufo classes for provide "keeping active parent items" feature
	storebuttoncss();

	// onstart recalculate and set new position for all layers
	setpositions(getClientWidth(), getScrollLeft());
}

// end class menu

// call public method of the basic class to open specified layer
function openLayer(obj_num, layer_num)
{
	obj_menu[obj_num].pmopentime(layer_num);
}

// change the opacity for different browsers
function changeOpac(obj_num, layer_num, opacity)
{
	var object = obj_menu[obj_num];
	var layer = object._layer[layer_num];

	layer.degree = opacity; // current layer state

	layer.handler.style.opacity = (opacity / 100);
	layer.handler.style.MozOpacity = (opacity / 100);
	layer.handler.style.KhtmlOpacity = (opacity / 100);
	layer.handler.style.filter = "alpha(opacity=" + opacity + ")";

	if (opacity > 98)
		layer.handler.style.filter = 'none';

	if (opacity > 0)
		layer.handler.style.visibility = 'visible';

	if (opacity <= 0)
		layer.handler.style.visibility = 'hidden';
}

// change the POSition for different browsers
function changePOS(obj_num, layer_num, pos, ori)
{
	var object = obj_menu[obj_num];
	var layer = object._layer[layer_num];

	var level = layer.level;
	var xa = layer.xa;
	var ya = layer.ya;
	var width = layer.outerwidth;
	var height = layer.outerheight;
	var margintop = layer.topmargin;
	var reverse = layer.reverse;

	layer.degree = pos; // current layer position state

	// prevent ie8 bug: clip must not exceed client window
	var maxclip_w = getClientWidth() - xa;
	var maxclip_h = getClientHeight() - ya;

	// left to right slide or top to bottom
	if (!reverse)
	{
		if (level == 1 && ori == 0)
		{
			var h = height - pos * height / 100;
			uniclip(layer.handler, h, maxclip_w, maxclip_h, 0);
			layer.handler.style.marginTop = -h + margintop + 'px';
		}
		else
		{
			var w = width - pos * width / 100;
			uniclip(layer.handler, 0, maxclip_w, maxclip_h, w);
			layer.handler.style.marginLeft = -w + 'px';
		}
	}
	else                                   // reverse moving
	{
		var w = width - pos * width / 100; // w: width->0
		var mw = width - w;                // mw: 0->width
		uniclip(layer.handler, 0, mw, maxclip_h, 0);
		layer.handler.style.marginLeft = w + 'px';
	}

	// on/off drawn layers
	if (pos <= 0)
	{
		layer.handler.style.visibility = 'hidden'; // make hidden
		uniclip(layer.handler, 0, 0, 0, 0);        // reset clip
		layer.handler.style.marginLeft = 'auto';   // reset margin-left
	}

	if (pos > 0)
	{
		layer.handler.style.visibility = 'visible'; // make visible
	}

	if (pos > 98)
	{
		uniclip(layer.handler, 0, 0, 0, 0);      // reset clip
		layer.handler.style.marginLeft = 'auto'; // reset margin-left
	}
}

// independent functions ///////////////////////////////////////////////////////////////////////////
// Bypass whitespaces. Read more at http://developer.mozilla.org/en/docs/Whitespace_in_the_DOM
function is_all_ws(nod)
{
	return !(/[^\t\n\r ]/.test(nod.data));
}

function is_ignorable(nod)
{
	return(nod.nodeType == 8) || ((nod.nodeType == 3) && is_all_ws(nod));
}

function node_after(sib)
{
	while ((sib = sib.nextSibling))
	{
		if (!is_ignorable(sib))
			return sib;
	}
	return null;
}

// return real child node
function getchildnode(handler, nodename)
{
	try
	{
		var node = handler.childNodes[0];
		
		while (node.nodeName != nodename)
		{
			if (!is_ignorable(node) && !nodename)
				break;

			node = node_after(node);
		}
		return node;
	}
	catch (err)
	{
		return null;
	}
}

// univesal css clip
function uniclip(handler, x1, y1, x2, y2)
{
	// reset clip
	if ((x1 == 0) && (y1 == 0) && (x2 == 0) && (y2 == 0))
	{
		// cut off clip style (prevent IE8 bug)
		var csstext = handler.style.cssText;
		handler.style.cssText = csstext.replace(/clip: {0,2}.*\);{0,1}/i, '');
		;
		return;
	}

	// setup clip
	handler.style.clip = 'rect(' + x1 + 'px, ' + y1 + 'px, ' + x2 + 'px, ' + y2 + 'px)';
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function getClientWidth()
{
	return document.documentElement.clientWidth;
}

function getClientHeight()
{
	return document.documentElement.clientHeight;
}

function getScrollLeft()
{
	return document.documentElement.scrollLeft;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
function findPos(obj)
{
	var curleft = curtop = 0;

	if (obj.offsetParent)
	{
		do
		{
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}

	return [
		curleft,
		curtop
	];
}

// automatic loader ////////////////////////////////////////////////////////////////////////////////
/*
_LOADERS = Array();

function callAllLoaders()
{
	var i, loaderFunc;

	for (i = 0; i < _LOADERS.length; i++)
	{
		loaderFunc = _LOADERS[i];

		if (loaderFunc != callAllLoaders)
			loaderFunc();
	}
}

function appendLoader(loaderFunc)
{
	if (window.onload && window.onload != callAllLoaders)
		_LOADERS[_LOADERS.length] = window.onload;

	window.onload = callAllLoaders;
	_LOADERS[_LOADERS.length] = loaderFunc;
}

// auto start script
appendLoader(mlddminit);
*/