/**
* Filename................: mel.js
* Project.................: web pages SDK
* Last Modified...........: $Date: 08/05/2010 21:22:12 $
* CVS Revision............: $Revision: 0.0.47 $
* Idea and Developed by...: Maxim Bulygin (sailormax@gmail.com)
*/

if (typeof MEL != "object") var MEL = {};

// aliases
	MEL.d = document;
	MEL.de = MEL.d.documentElement;
	MEL.ds = MEL.d.selection;
	MEL.dc = MEL.d.cookie;
	MEL.w = window;

	MEL.d.getEl = MEL.d.getElementById;
	MEL.d.getEls = MEL.d.getElementsByName;
	MEL.d.getTags = MEL.d.getElementsByTagName;
//

	MEL.now = new Date();

// browser name and version
	var ua = MEL.ua = {
		str:		navigator.userAgent,
		other:		true,
		is_crawler:	(null != navigator.userAgent.match(/(Yahoo!|Crawler|Google|MSNBot|Slurp|Teoma|Gigabot|Scrubby|Robozilla|BecomeBot|Nutch|Yandex|Rambler|Aport|Spider|MJ12bot|KalamBot|genieBot|Latnet-search-engine|Letonika.lv|ia_archiver|findlinks|Mail.Ru|Snapbot|PycURL|psbot|larbin|Exabot|libwww-perl|Jakarta|voyager|MSRBOT|Jyxobot|Scooter|accelobot|yetibot|Yeti\/|heritrix|eBolot)/i))
	}
//

// small init
	new function()
	{
		// detect browser
		var i, tmp, uas = [["opera"], ["safari"], ["konqueror", "konq"], ["msie", "ie"], ["mozilla"]];
		for (i in uas)
		{
			i = uas[i];
			if (tmp = ua.str.match(new RegExp(i[0]+".([0-9\.]+)", "i")))
			{
				ua[i[1] || i[0]] = parseFloat(tmp[1]);
				ua.other = false;
				break;
			}
			else
				ua[i[1] || i[0]] = false;
		}
		//

		// detect timeshift + daylight time
//		var locale_date = new Date(2010, 8, 7, 19, 6, 5);
		var locale_date = new Date(2010, 4, 13, 19, 6, 5);
		var locale_str = locale_date.toLocaleString();
		var re_time = /[0-9]{1,2}:[0-9]{1,2}/;
		var delim_pos = locale_str.search(re_time);
		// time
			var time_mask = "";
			var hour = locale_str.substr(delim_pos).split(':', 2)[0];
			if (hour == "19")
			{
				var tmp_date = locale_date;
				tmp_date.setHours(7);
				hour = tmp_date.toLocaleString().substr(delim_pos).split(':', 2)[0];
				time_mask += (hour == "7" ? 'H:mm' : "HH:mm");
			}
			else
				time_mask += (hour == "7" ? 'h:mm' : "hh:mm");
		//

		// date
			var item, words = [];
			var short_weekday = false;
			var date_mask = locale_str.substr(0, delim_pos);
			var re_word = /[^,\.\- 0-9][^,\.\-0-9]+/g;
			while ((item = re_word.exec(date_mask)) != null) words.push(item);

			// remove week day
				var shift = 0;
				while (words.length > 1)
				{
					item = words.shift();
					item[0] = item[0].replace(/[ ,\.\-]+$/, "");
					if ((item.index > 0) && (!isNaN(parseInt(date_mask.substr(shift+item.index-1, 1)))))	// japan dates
					{
						date_mask = date_mask.substring(0, shift+item.index) + "/" + date_mask.substr(shift+item.index+item[0].length);
						shift -= item[0].length-1;
					}
					else
					{
						short_weekday = (item[0].length <= 3);
						date_mask = date_mask.substring(0, shift+item.index) + date_mask.substr(shift+item.index+item[0].length+1);
						shift -= item[0].length+1;
					}
				}
			//

			if (words.length)
			{
				if (!isNaN(parseInt(date_mask.substr(shift+words[0].index-1, 1))))	// japan dates
					date_mask = date_mask.substring(0, shift+words[0].index) + date_mask.substr(shift+words[0].index+words[0][0].length);
				else
					date_mask = date_mask.replace(words[0][0].replace(/[ ,\.\-]+$/, ""), (short_weekday ? "MMM" : "MMMM"));
			}

			date_mask = date_mask.replace(/([0-9]+)/g, function(num)
				{
					inum = num-0;
					if (num == locale_date.getFullYear())
						return "yyyy";
					else if (num == (locale_date.getFullYear()+"").substr(-2))
						return "yy";
					else if (inum == (locale_date.getMonth()+1))
						return (num.length > 1 ? "MM" : "M");
					else if (inum == locale_date.getDate())
						return (num.length > 1 ? "dd" : "d");
					return "";
				});
		//
		date_mask = date_mask.replace(/^[ ,.-]+/, "").replace(/[ ,.-]+$/, "");

		if (/[^dMy ,\.\-]/.test(date_mask))	// exception
			date_mask = "d.MM.yyyy";

		var exp = new Date();
		exp.setFullYear(MEL.now.getFullYear()+10);
		document.cookie = "MEL_UTC=" + escape(-MEL.now.getTimezoneOffset()) + ";expires="+exp.toGMTString()+";path=/";
		var winter = new Date(MEL.now.getFullYear(), 1, 1);
		var summer = new Date(MEL.now.getFullYear(), 6, 1);
		if (winter.getTimezoneOffset() != summer.getTimezoneOffset())
		{
			document.cookie = "MEL_DST=" + escape((MEL.now.getTimezoneOffset()!=winter.getTimezoneOffset())-0) + ";expires="+exp.toGMTString()+";path=/";
			document.cookie = "MEL_DTS=" + escape(-(summer.getTimezoneOffset()-winter.getTimezoneOffset())) + ";expires="+exp.toGMTString()+";path=/";
		}
		else
		{
			document.cookie = "MEL_DST=;expires="+exp.toGMTString()+";path=/";		// Daylight saving time
			document.cookie = "MEL_DTS=0;expires="+exp.toGMTString()+";path=/";		// Daylight time shift
		}
		document.cookie = "MEL_DATE_FORMAT=" + escape(date_mask) + ";expires="+exp.toGMTString()+";path=/";
		document.cookie = "MEL_TIME_FORMAT=" + escape(time_mask) + ";expires="+exp.toGMTString()+";path=/";
	}();
//

// cross browser debug
	if (opera && !console)
		var console = { log: opera.postError };
	else if (console && !opera)
		var opera = { postError: console.log };
	else if (!console)
	{
		var console = { }, opera = { };
		console.log = opera.postError = function(str)
		{
			var el = MEL.d.createElement("DIV");
			el.className = "debug";
			el.style.zIndex = 1000;
			el.style.position = "relative";
			el.style.backgroundColor = "white";
			el.innerHTML = str;
			MEL.d.body.appendChild(el);
		}
	}
//

// URL
	MEL.url = MEL.d.location;
	MEL.url.URI = MEL.url.href.replace(/#.*$/, ""),
	MEL.url.anchors_arr = [],
	MEL.url.anchors_of = "";
	MEL.url.getAnchors = function()
	{
		if (this.anchors_of != this.href)
		{
			var str = this.href.replace("##", "#");
			this.anchors_arr = str.search(/#.+/) > 0 ? str.replace(/^[^#]+#?/, "").split("#") : [];
		}
		return this.anchors_arr;
	}
	MEL.url.appendAnchor = function(name)
	{
		if (MEL.inArray(name, this.getAnchors()) < 0)
			this.replace(MEL.url.URI + "#" + this.getAnchors().concat([name]).join("#"));
	}
	MEL.url.removeAnchor = function(name)
	{
		var i = MEL.inArray(name, this.getAnchors());
		if (i >= 0)
		{
			var new_list = this.getAnchors();
			new_list.splice(i, 1);
			this.replace(MEL.url.URI + "#" + new_list.join("#"));	// keep empty "#" for deny reloading
		}
	}
//

// DOM functions
	MEL.dom = {

		getStyle: function(el, name)
		{
			if (name)
			{
				if (MEL.d.defaultView && MEL.d.defaultView.getComputedStyle)
					return MEL.d.defaultView.getComputedStyle(el, "").getPropertyValue(name);
				else if (el.currentStyle)
				{
					name = name.replace(/-(\w)/g, function(){ return arguments[1].toUpperCase(); });
					return el.currentStyle[name];
				}
			}
			else
			{
				var style;
				if (el.style.getAttribute)
					style = el.style.getAttribute("cssText");
				else
					style = el.getAttribute("style");

				if (style)
					return style;
			}
			return "";
		},


		setStyle: function(el, str)
		{
			if (el.style.setAttribute)
				el.style.setAttribute("cssText", str);
			else
				el.setAttribute("style", str);
		},


		hasClass: function(el, name)
		{
			return ((" "+el.className+" ").search(" "+name+" ") > -1);
		},

		appendClass: function(el, name)
		{
			if ((" "+el.className+" ").search(" "+name+" ") < 0)
				el.className += " " + name;
		},

		removeClass: function(el, name)
		{
			el.className = (" "+el.className+" ").replace(" "+name+" ", " ").replace(/^ +/, "").replace(/ +$/, "").replace(/ +/, " ");
		},

		replaceClass: function(el, name, new_name)
		{
			el.className = (" "+el.className+" ").replace(" "+name+" ", " "+new_name+" ").replace(/^ +/, "").replace(/ +$/, "");
		},


		setAttribute: function(el, name, val)
		{
			if (val-0 == val) val -= 0;
			var items = name.split('.');
			if (items.length == 1)
			{
				if (el.setAttribute)
					el.setAttribute(name, val);
				else
					el[name] = val;
			}
			else
			{
				if (items[0] == "filter") items[0] = "filters";
				if (items[0] == "filters" && el.filters)
				{
					if (!el[items[0]][items[1]])
					{
						var filter = " " + items[1] + "(" + items[2] + "=" + val + ")";
						var re = new RegExp(" " + items[1] + "\\(" + items[2] + "=([^\\)]+)\\)", "i");
						if (el.style.filter.search(re) >= 0)
							el.style.filter = el.style.filter.replace(re, filter);
						else
							el.style.filter += filter;
					}

					if (/^filters?\.alpha\.opacity$/.test(name.toLowerCase()))
					{
						if (el.filters.alpha)
							el.filters.alpha.enabled = (val >= 100 ? "false" : "true");
						if (val >= 100)
						{
//							el.style.filter = el.style.filter.replace(/ alpha\([^\)]+\)/, "");
						}
					}
				}

				var i = 0;
				while (el[items[i]] && (i < (items.length-1)))
					el = el[items[i++]];
				if (i == (items.length-1))
					el[items[i]] = val;
			}
		},


		getSelectedText: function()
		{
			return window.getSelection ? window.getSelection().toString() : MEL.ds.createRange().text;
		},


		getAbsolutePos: function(el, regarding_element)
		{
			var pnt = {x:0, y:0, ox:0, oy:0, oxoyParent:null};
			var start_el = el;
			var next_el, prev_el, deep = 0;
			while (el)
			{
				if (regarding_element == el) return pnt;

				pnt.x += el.offsetLeft;
				pnt.y += el.offsetTop;
				prev_el = el;

				// minus all scrolls
				next_el = el.offsetParent;
				if (next_el)
				{
					while ((el = el.parentNode) && (el != next_el))
					{
						pnt.x -= el.pageXOffset || el.scrollLeft;
						pnt.y -= el.pageYOffset || el.scrollTop;
					}
				}
				else
					el = null;

				if (!pnt.oxoyParent)
				{
					var is_rel = (MEL.inArray(this.getStyle(prev_el, "position"), ["fixed", "relative", "absolute"]) >= 0);

					// stop offer coords, if we have not static element
					if (deep && is_rel)
						pnt.oxoyParent = prev_el;
					else
					{
						pnt.ox = pnt.x;
						pnt.oy = pnt.y;
					}

					if (is_rel && !next_el && (MEL.ua.ie == 8))			// ie8 fix
					{
						el = prev_el.parentNode;
						while (el)
						{
							if (MEL.inArray(this.getStyle(el, "position"), ["fixed", "relative", "absolute"]) >= 0)
							{
								pnt.x += el.offsetLeft;
								pnt.y += el.offsetTop;
							}
							el = el.parentNode;
						}
					}
//					else if (is_rel && !next_el && (MEL.ua.opera >= 9.8))			// opera 10 beta fix
//					{
//						pnt.y -= MEL.d.getTags("html")[0].scrollTop;
//					}
//					else if (is_rel && !next_el && MEL.ua.safari)			// safari and chrome
//					{
//						pnt.y += MEL.d.getTags("body")[0].scrollTop;
//					}
				}
				deep++;
			}

			if (this.getStyle(pnt.oxoyParent||start_el, "position") == "fixed")
			{
				pnt.x += MEL.de.scrollLeft;
				pnt.y += MEL.de.scrollTop;
			}

			return pnt;
		},


		getElementSize: function(el, with_borders, content_size)
		{
			if (!el) return [];
			var wnd = ((el.tagName == "BODY") || (el == MEL.w) ? MEL.w : null);
			var de = MEL.de;

			var res = {
				sw: el.scrollWidth,
				sh: el.scrollHeight,	// + (wnd ? wnd.scrollMaxY || 0 : 0)
				sx: -1, sy: -1,
				w: -1, h: -1
			};

			if (el.tagName == "SCRIPT" || el.tagName == "STYLE")
				return { sw:0, sh:0, sx:0, sy:0, w:0, h:0 };

			if (wnd)
			{
				if (de && de.clientHeight)
				{
					res.w = de.clientWidth;		res.h = de.clientHeight;
					res.sx = de.scrollLeft || self.pageXOffset || el.scrollLeft || 0;
					res.sy = de.scrollTop || self.pageYOffset || el.scrollTop || 0;
				}
				else if (self.innerHeight)									// IE6 (Strict)
				{
					res.w = self.innerWidth;	res.h = self.innerHeight;
					res.sx = self.pageXOffset;	res.sy = self.pageYOffset;
				}

				// scrollHeight problem with windows, where BODY.height = 100%...
				// how it detect???
//				if ((window != parent))	// if iframe, fix bug of Firefox, Opera or... web standart ;)
				{
					res.sh = 0;
					var i, size, root_childs = wnd.document.body.childNodes;
					for (i=0; i<root_childs.length; i++) if (root_childs[i].tagName)
						res.sh += this.getElementSize(root_childs[i]).h;
				}

			}
			if (res.h < 0)
			{
				if (MEL.ua.safari)
				{
					res.w = el.offsetWidth;
					res.h = el.offsetHeight;
				}
				else
				{
					if (with_borders === false)
					{
						res.w = el.clientWidth || el.offsetWidth || 0;
						res.h = el.clientHeight || el.offsetHeight || 0;
					}
					else

					{
						res.w = el.offsetWidth || el.clientWidth || 0;
						res.h = el.offsetHeight || el.clientHeight || 0;
					}
				}
				res.sx = el.scrollLeft;		res.sy = el.scrollTop;
			}

			if (res.sw < res.w) res.sw = res.w;
			if (res.sh < res.h) res.sh = res.h;
//			if (wnd && (window != parent)) res.sh = res.h;

			if (content_size)
			{
				res.w -= (parseInt(MEL.dom.getStyle(el, "padding-left")) + parseInt(MEL.dom.getStyle(el, "padding-right")));
				res.h -= (parseInt(MEL.dom.getStyle(el, "padding-top")) + parseInt(MEL.dom.getStyle(el, "padding-bottom")));
			}

			return res;
		},

		getOpenedTags: function(node)
		{
			var tags = [];
			while (node)
			{
				tags.push(node);
				var node = node.parentNode;
			}
			return tags;
		},
		
		insertRow2Table: function(tbl, row, idx, cp_attrs)
		{
			var i, nr = tbl.insertRow(idx);
			nr.className = row.className;
			this.setStyle(nr, this.getStyle(row));
			if (typeof cp_attrs == "undefined" || cp_attrs)		// IE very strange copy attrs of TR and other tags...
				MEL.copyElAttrs(nr, row);
			var cln, arr = row.childNodes;
			for (i=0; i<arr.length; i++)
				nr.appendChild(arr[i].cloneNode(true));
			return nr;
		},

		getInnerText: function(el)
		{
			var res = "";
			var childs = el.childNodes;
			var i, cnt = childs.length;
			for (i=0; i<cnt; i++) if (childs[i].nodeValue) res += childs[i].nodeValue;
			return res;
		}
	}
//


// MEL events
	MEL.event = {

		__onmouseinout: [],

		addListener: function(el, evtType, func)
		{
			if (el.addEventListener)
				el.addEventListener(evtType, func, false);
			else if (el.attachEvent)
				return el.attachEvent("on"+evtType, func);
			else
				return false;
			return true;
		},


		removeListener: function(el, evtType, func)
		{
			if (el.removeEventListener)
				el.removeEventListener(evtType, func, false);
			else if (el.detachEvent)
				return el.detachEvent("on"+evtType, func);
			else
				return false;
			return true;
		},


		addMouseInOut: function(obj, over, out)
		{
			var i, list = this.__onmouseinout;
			for (i in list) if (list[i] && (list[i][0] === obj)) return;
			if (!list.length)
			{
				this.addListener(MEL.d, "mouseout", this.__hMouseInOut);
				this.addListener(MEL.d, "mouseover", this.__hMouseInOut);
			}
			for (i in list) if (list[i] === null)
			{
				list[i] = [obj, true, out, over];
				return;
			}
			list.push([obj, true, out, over]);
		},

		hasMouseInOut: function(obj)
		{
			var i, list = this.__onmouseinout;
			for (i in list) if (list[i] && (list[i][0] === obj)) return true;
			return false;
		},

		removeMouseInOut: function(obj)
		{
			var i, list = this.__onmouseinout;
			for (i in list) if (list[i] && (list[i][0] === obj)) { list[i] = null; return; }
		},


		__hMouseInOut: function(e)
		{
			e = e || event;
			var i, j, pos, size, out, objs, list = MEL.event.__onmouseinout;
			var sx = e.clientX + (MEL.de.scrollLeft || window.pageXOffset);
			var sy = e.clientY + (MEL.de.scrollTop || window.pageYOffset);
			for (i in list) if (list[i])
			{
				out = true;
				objs = (list[i][0].concat ? list[i][0] : [list[i][0]]);
				for (j in objs)
				{
					pos = MEL.dom.getAbsolutePos(objs[j]);
					size = MEL.dom.getElementSize(objs[j]);
					out &= ((sx < pos.x) || (sy < pos.y) || (sx > pos.x+size.sw) || (sy > pos.y+size.sh));
				}
				if (out == list[i][1])
				{
					MEL.exec(list[i][(out ? 2 : 3)], list[i][0], e);
					if (list[i]) list[i][1] = out;
				}
			}
		},


		cancel: function(e)
		{
			if (e.stopPropagation) e.stopPropagation();
			if (e.preventDefault) e.preventDefault();
			e.cancelBubble = true;
			e.returnValue = false;
			return false;
		}
	}

	MEL.event.addListener(window, "error", function(err, url, line)
	{
		if (typeof MEL.errorHandler == "function")
			MEL.errorHandler(err, url, line);
		else if (typeof MEL.errorHandler == "string")
			console.log(err, url, line);	// TODO: send to url error
	});
//

// selection functions
MEL.selection = {

	setSelectedText: function(el, start, end)
	{
		if (el.setSelectionRange)
			el.setSelectionRange(start, end);
		else if (el.createTextRange)
		{
			var rng = el.createTextRange();
			rng.collapse(true);
			rng.moveEnd("character", end);
			rng.moveStart("character", start);
			rng.select();
		}
	},

	
	getStartSelection: function(el)
	{
		if (el.setSelectionRange)
		{
			return el.selectionStart;
		}
		else if (MEL.ds.createRange)
		{
			var rng = MEL.ds.createRange();
			if (rng.parentElement() != el)
				return -1;

			var rng2 = rng.duplicate();
			if (el.tagName == "TEXTAREA")
				rng2.moveToElementText(el)
			else
				rng2.expand("textedit");
			rng2.setEndPoint("EndToStart", rng);
			var pos = rng2.text.length;
			if (MEL.ua.ie && (el.value.substr(pos, 2) == "\r\n")) pos += 2;	// ie bug fix
			if (pos > el.value.length)
				return -1;
			return pos;
		}
		else
			return el.value.length;
	},


	getCaretPosition: function(el)
	{
		return this.getStartSelection(el);
	},


	setCaretPosition: function(el, pos)
	{
		this.setSelectedText(el, pos, pos);
	},


	getEndSelection: function(el)
	{
		if (el.setSelectionRange)
		{
			return el.selectionEnd;
		}
		else if (MEL.ds.createRange)
		{
			var rng = MEL.ds.createRange();
			if (rng.parentElement() != el)
				return -1;

			var rng2 = rng.duplicate();
			if (el.tagName == "TEXTAREA")
				rng2.moveToElementText(el)
			else
				rng2.expand("textedit");

			rng2.setEndPoint("EndToEnd", rng);
			var pos = rng2.text.length;
			if (MEL.ua.ie && (el.value.substr(pos, 2) == "\r\n")) pos += 2;	// ie bug fix
			if (pos > el.value.length)
				return -1;
			return pos;
		}
		else
			return el.value.length;
	},

	getParentElement: function(oWnd)
	{
		var sel, range;
		if (oWnd.getSelection)
			sel = oWnd.getSelection();
		else
			sel = oWnd.document.selection;

		if (sel.getRangeAt)
			range = sel.getRangeAt(0);
		else if (sel.createRange)
			range = sel.createRange();
		else
			range = sel;

		if (sel.type)
		{
			switch (sel.type)
			{
				case "Text":
				case "None":
					return range.parentElement();
				case "Control":
					return range.item(0);
				default:
					return oWnd.document.body;
			}
		}
		else
			try
			{
				var p = range.commonAncestorContainer;
				if (!range.collapsed && range.startContainer == range.endContainer
					&& range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes()
					)
					p = range.startContainer.childNodes[range.startOffset];

				while (p.nodeType == 3)
					p = p.parentNode;
				return p;
			}
			catch (e)
			{
				return null;
			}
	},

	getOpenedTags: function(node)
	{
		var tags = [];
		while (node)
		{
			tags.push(node);
			var node = node.parentNode;
		}
		return tags;
	}

}
//

// date functions
	MEL.date = {

		getFormatted: function(dt, tpl)
		{
			tpl = tpl.replace(/j/, dt.getDate());
			tpl = tpl.replace(/d/, (dt.getDate() < 10 ? "0" : "") + dt.getDate());
			tpl = tpl.replace(/m/, (dt.getMonth() < 9 ? "0" : "") + (dt.getMonth()+1));
			tpl = tpl.replace(/y/, dt.getYear());
			tpl = tpl.replace(/Y/, dt.getFullYear());

			tpl = tpl.replace(/s/, (dt.getSeconds() < 10 ? "0" : "") + dt.getSeconds());
			tpl = tpl.replace(/i/, (dt.getMinutes() < 10 ? "0" : "") + dt.getMinutes());
			tpl = tpl.replace(/H/, (dt.getHours() < 10 ? "0" : "") + dt.getHours());
			return tpl;
		},


		getUTC: function(dt)
		{
			if (!dt) dt = new Date();
			return new Date(dt-dt.getTimezoneOffset()*60000);
		}
	}
//


// timer functions
	MEL.timer = {

		in_use: [],

		__cb: function(i)
		{
			if (MEL.timer.in_use[i][1])
				MEL.timer.in_use[i][1][MEL.timer.in_use[i][2]]();
			else
				MEL.timer.in_use[i][2]();
		},


		setTimer: function(interval, obj, func_name, msec)
		{
			var i = -1; while (this.in_use[++i]);
			var fb = new Function("MEL.timer.__cb(" + i + ")");
			this.in_use[i] = [null, obj, func_name, interval];
			this.in_use[i][0] = ( interval ? window.setInterval(fb, msec) : window.setTimeout(fb, msec) );
			return this.in_use[i][0];
		},


		clearTimer: function(timer)
		{
			for (var i=0; i<this.in_use.length; i++)
				if (this.in_use[i] && (this.in_use[i][0] == timer))
				{
					if (this.in_use[i][3])
						window.clearInterval(timer);
					else
						window.clearTimeout(timer);
					this.in_use[i] = null;
					return;
				}
		},


		setTimeout: function(obj, func_name, msec)
		{
			return this.setTimer(false, obj, func_name, msec);
		},

		setInterval: function(obj, func_name, msec)
		{
			return this.setTimer(true, obj, func_name, msec);
		}
	}
	MEL.timer.clearTimeout = MEL.timer.clearTimer;
	MEL.timer.clearInterval = MEL.timer.clearTimer;
//


// Popup functions
	MEL.popup = {

		cfg: {
			X: false,
			Y: false,
			MOVE2CENTER: true,
			WIDTH: "320px",
			HEIGHT: "200px",
			Z_INDEX: 11000,
			PARENT: null,

			BACKGROUND: "#000",
			OPACITY: 0.5,
			FIXED: true,
			DRAGDROP: true,
			MODAL: true,
			SCROLLING: "auto",

			CLOSE: "X"
		},

		show: function(div, cfg, funcInit, funcParams)
		{
			var i, tmp, url;

			if (cfg && (cfg != null))
			{
				for (i in this.cfg)
					if (typeof cfg[i] == "undefined") cfg[i] = this.cfg[i];
			}
			else
				cfg = this.cfg;
			if (!cfg.PARENT) cfg.PARENT = MEL.d.body;
			if (cfg.FIXED && MEL.ua.ie) cfg.FIXED = false;


			if (div && (typeof div != "object"))
			{
				if (div.search && (div.search(/:\/\//) > 0))
				{
					url = div;
					div = MEL.d.createElement("DIV");
					MEL.dom.setStyle(div, "width:" + cfg.WIDTH + "; background-color:white; border:1px solid gray; padding:3px;");

					tmp = MEL.d.createElement("P");
					MEL.dom.setStyle(tmp, "float:right; font-color:red; font-size:12px; margin:3px; height:12px; cursor:pointer;");
					tmp.appendChild(MEL.d.createTextNode(cfg.CLOSE));
					tmp.onclick = MEL.popup.close;
					div.appendChild(tmp);

					tmp = MEL.d.createElement("IFRAME");
					MEL.dom.setStyle(tmp, "clear:both; width:" + cfg.WIDTH + "; height:" + (parseInt(cfg.HEIGHT)-12) + ";");
					tmp.scrolling = cfg.SCROLLING;
					tmp.frameBorder = "0";
					tmp.src = url;
					div.appendChild(tmp);
				}
				else
					div = MEL.d.getEl(div);
			}
			if (!div) return false;

  			var psize = MEL.dom.getElementSize(cfg.PARENT);
			var pos = MEL.dom.getAbsolutePos(cfg.PARENT);

			if (cfg.MODAL)
			{
				var popup_div = MEL.d.createElement("DIV");
				popup_div.onmousedown = function() { return false; }

				var ss = "z-index:"+cfg.Z_INDEX+"; position:"+(cfg.FIXED ? "fixed" : "absolute")+"; top:" + pos.y + "px; left:" + pos.x + "px; width:" + psize.sw + "px; height:" + psize.sh + "px; background:" + cfg.BACKGROUND + ";";
				MEL.dom.setStyle(popup_div, ss);
				popup_div.className = "popup_div";

				if (cfg.OPACITY < 1)
				{
					if (MEL.ua.ie)
						popup_div.style.filter = "alpha(opacity=" + (cfg.OPACITY*100) + ")";
					else
						popup_div.style.opacity = cfg.OPACITY;
				}

				if (MEL.ua.ie && MEL.ua.ie < 7)
				{
					var sels = MEL.d.getTags("SELECT");
					for (i=0; i<sels.length; i++)
					{
						MEL.dom.appendClass(sels[i], "hide_from_popup");
						sels[i].style.visibility = "hidden";
					}
				}
			}
			else
				var popup_div = false;


			var popup_form = div;
			if (!url)
			{
				if ((popup_form.style.display == "none") && (!div.offsetWidth || !div.offsetHeight))
					throw "popup:\n Source element shouldn't have 'display: none'! Use 'visibility: hidden'.";

				// fix selected in IE
					var tmp = div.getElementsByTagName("SELECT");
					var tmp2 = popup_form.getElementsByTagName("SELECT");
					for (i=0; i<tmp.length; i++) tmp2[i].selectedIndex = tmp[i].selectedIndex;
				//
			}

			if (cfg.DRAGDROP && MEL.dragdrop)
				MEL.dragdrop.init(popup_form);

			if (!popup_form.parentNode || !popup_form.parentNode.tagName)
			{
				if (popup_div)
					MEL.d.body.appendChild(popup_div);
				MEL.d.body.appendChild(popup_form);
			}
			else if (popup_div)
				popup_form.parentNode.insertBefore(popup_div, popup_form);

			var ss = "; visibility:visible; position:"+(cfg.FIXED ? "fixed" : "absolute")+"; z-index:"+cfg.Z_INDEX+";";
			if (cfg.MOVE2CENTER)
			{
				var top = (cfg.Y !== false ? cfg.Y : Math.round((psize.h / 2) - ((div.offsetHeight || parseInt(MEL.dom.getStyle(div, "height"))) / 2) + psize.sy));
				var left = (cfg.X !== false ? cfg.X : Math.round((psize.w / 2) - ((div.offsetWidth || parseInt(MEL.dom.getStyle(div, "width"))) / 2) + psize.sx));
				ss += " top:" + top + "px; left:" + left + "px;"
			}
			MEL.dom.setStyle(popup_form, MEL.dom.getStyle(popup_form) + ss);

			if (typeof funcInit == "function") funcInit(popup_form, funcParams);
			return popup_form;
		},


		hide: function(el)
		{
			if (!el || !el.tagName)
			{
				var e = el || event;
				el = e.target || e.srcElement;
			}
			while (el && el.style.zIndex < 1000) el = el.parentNode;

			if (el.previousSibling && (el.previousSibling.className == "popup_div"))
				el.parentNode.removeChild(el.previousSibling);

			el.style.visibility = "hidden";
			if (MEL.ua.ie && MEL.ua.ie < 7)
			{
				var sels = MEL.d.getTags("SELECT");
				for (i=0; i<sels.length; i++)
					if (MEL.dom.hasClass(sels[i], "hide_from_popup"))
						sels[i].style.visibility = "visible";
			}
		}

	}
	MEL.popup.close = MEL.popup.hide;						// back compatibility
//


// Status bar
	MEL.statusBar = {

		cfg: {
			IMG: "",

			BAR_STYLE: "position:absolute; top:0; right:50px; width:50px; height:13px; overflow:hidden; background-color:yellow; padding:3px; text-align:center; font-size:9px;",
			BAR_CLASS: "status_bar",
			ANIMATE: true
		},
		__hBar: null,
		__hAnimate: null,

		show: function(text, owner)
		{
			if (typeof owner == "undefined") owner = this;
			if (typeof owner.cfg == "undefined") owner.cfg = {};
			if (typeof owner.cfg.ANIMATE == "undefined") owner.cfg.ANIMATE = this.cfg.ANIMATE;

			if (!this.__hBar)
			{
				var bar = MEL.d.createElement("DIV");
				MEL.dom.setStyle(bar, this.cfg.BAR_STYLE);
				MEL.dom.setAttribute(bar, "class", this.cfg.BAR_CLASS);
				if (this.cfg.IMG)
				{
					var img = MEL.d.createElement("IMG");
					MEL.dom.setAttribute(img, "src", this.cfg.IMG);
					bar.appendChild(img);
				}
				else
					bar.appendChild(MEL.d.createTextNode(text || "Loading..."));
			}
			else
				var bar = this.__hBar;

			if (owner.cfg.ANIMATE)
			{
				if (owner.cfg.ANIMATE.tagName)
					MEL.dom.appendClass(owner.cfg.ANIMATE, "active");
				else if (MEL.animation)
				{
					if (!owner.__hAnimate)
					{
						var dot = MEL.d.createElement("DIV");
						MEL.dom.setStyle(dot, "float:left; width:5px; height:2px; background-color:#ff9191; border-left:5px solid #FFE1E1; border-right:5px solid red; margin-right:20px;");
						bar.appendChild(dot);
						MEL.d.body.appendChild(bar);

						var anim = MEL.animation.Create(dot, 0, 50);
						anim.addParam("style.marginLeft", -15, MEL.dom.getStyle(bar, "width"), "3px");
						anim.onFinish = function()
						{
							if (!this.__status)
								this.start();
							else
								this.__status = 0;
						}
						owner.__hAnimate = anim;
					}
					bar.style.visibility = "visible";
					owner.__hAnimate.start();
				}
			}
			this.__hBar = bar;
		},


		hide: function(owner)
		{
			if (typeof owner == "undefined") owner = this;
			if (typeof owner.cfg == "undefined") owner.cfg = {};
			if (typeof owner.cfg.ANIMATE == "undefined") owner.cfg.ANIMATE = this.cfg.ANIMATE;

			if (owner.cfg.ANIMATE.tagName)
				MEL.dom.removeClass(owner.cfg.ANIMATE, "active");
			if (owner.__hAnimate)
				owner.__hAnimate.stop();
			if (this.__hBar)
				this.__hBar.style.visibility = "hidden";
		},


		free: function()
		{
			this.hide();
			this.__hAnimate = null;
			if (this.__hBar)
				this.__hBar.parentNode.removeChild(this.__hBar);
			this.__hBar = null;
		}
	}
//


// Utils
	MEL.exec = function(func, obj, e)
	{
		var t = typeof func;
		if (t == "function") return func(obj, e);
		else if (t == "string") return eval(func);
	}

	MEL.getCopy = function(obj, ignProp, withHTML, replaceKeys)
	{
		var i, ret = obj;
		if (obj && (typeof obj == "object"))
		{
			ret = (obj.pop ? [] : {} );
			for (i in obj)
				if ((!ignProp || (MEL.inArray(i, ignProp) < 0)) && (withHTML || !obj[i] || !obj[i].tagName))
				{
					if (replaceKeys && (typeof replaceKeys == "object") && replaceKeys[i])
						ret[replaceKeys[i]] = MEL.getCopy(obj[i], ignProp, withHTML);
					else
						ret[i] = MEL.getCopy(obj[i], ignProp, withHTML);
				}
		}
		return ret;
	}

	MEL.toArray = function(list)
	{
		var i, arr = [], len = list ? (list.length || 0) : 0;
		for (i=0; i<len; i++) arr.push(list.charAt ? list.charAt(i) : list[i]);
		return arr;
	}
	MEL.to_array = MEL.toArray;		// back compatibility

	MEL.copyElSize = function(el, source)
	{
		var size = MEL.dom.getElementSize(source || el);
		el.style.width = (size.w - parseInt(0+MEL.dom.getStyle(el, "padding-left")) - parseInt(0+MEL.dom.getStyle(el, "padding-right")) - parseInt(0+MEL.dom.getStyle(el, "border-left-width")) - parseInt(0+MEL.dom.getStyle(el, "border-right-width"))) + "px";
		el.style.height = (size.h - parseInt(0+MEL.dom.getStyle(el, "padding-top")) - parseInt(0+MEL.dom.getStyle(el, "padding-bottom")) - parseInt(0+MEL.dom.getStyle(el, "border-top-width")) - parseInt(0+MEL.dom.getStyle(el, "border-bottom-width"))) + "px";
		el.style.padding = MEL.dom.getStyle(el, "padding");
	}
	MEL.setupElSize = MEL.copyElSize;						// back compatibility

	MEL.copyElAttrs = function(el, source)
	{
		for (var i=0; i<source.attributes.length; i++)
			if ((source.attributes[i].value != "") && (source.attributes[i].value != "null"))
				MEL.dom.setAttribute(el, source.attributes[i].name, source.attributes[i].value);
	}

	MEL.findPopupBestPosition = function(btn, popup, over_button)
	{
		var pos = MEL.dom.getAbsolutePos(btn);

		btn			= {x:pos.x,	y:pos.y,	width:btn.offsetWidth,		height:btn.offsetHeight};	// + (btn.offsetHeight < 20 ? 10 : 0)
		popup		= {x:btn.x,	y:0,		width:popup.offsetWidth,	height:popup.offsetHeight};
		var pg_size = MEL.dom.getElementSize(MEL.d.body);

		// find X (default is button.x)
			if ((pg_size.w + pg_size.sx) < (btn.x + popup.width))	// if over screen at right
				popup.x = pg_size.w - popup.width;					// snap to right border

			if (popup.x < pg_size.sx)					// if over screen at left
				popup.x = pg_size.sx;					// snap to left border

			if (popup.x + popup.width > pg_size.sw)		// if over document at right
				popup.x = pg_size.sw - popup.width;		// move to the left

			if (popup.x < 0) popup.x = 0;				// if over document at left => x = 0
		//

		// find Y
/*
//			if ((pg_size.h < (btn.y + btn.height + popup.height))	// don't have space at bottom
			if (((pg_size.h + pg_size.sy) < (btn.y + btn.height + popup.height))	// don't have space at bottom
				&& (pg_size.sy < (btn.y - popup.height)))							// and have upper on screen
				popup.y = btn.y - popup.height;				// upper
			else if (((btn.y - popup.height) >= 0)							// have space upper
					&& (pg_size.sh > (btn.y + btn.height + popup.height)))	// and under button in document
			{
				if ((pg_size.h < (btn.y + btn.height + popup.height))							// button+popup > windows size
					&& ((btn.y - pg_size.sy) > (pg_size.h + pg_size.sy - btn.y - btn.height)))	// 	
					popup.y = btn.y - popup.height;			// upper
				else
					popup.y = btn.y + btn.height;			// under
			}
			else if (!over_button && (popup.h > btn.x + btn.height))	// if not over_button, but popup over
				popup.y = btn.y + btn.height;

			if (popup.y < 0)
			{
				if (over_button)
					popup.y = 0;
				else
					popup.y = btn.y + btn.height;
			}
*/
			if ((btn.y + btn.height + popup.height) < (pg_size.sy + pg_size.h))	// space under the button
				popup.y = btn.y + btn.height;
			else if ((btn.y - popup.height) > pg_size.sy)	// space upper above the button
				popup.y = btn.y - popup.height;
			else if (over_button)
			{
				if ((pg_size.sy + pg_size.h - popup.height) > pg_size.sy)	// space under + over button
					popup.y = pg_size.sy + pg_size.h - popup.height;
				else
					popup.y = pg_size.sy;
			}
			else
				popup.y = btn.y - popup.height;

			if ((popup.y + popup.height) > pg_size.sh)	// over the document
			{
				if (over_button && ((pg_size.sh - popup.height) < (btn.y + btn.height)))
				popup.y = btn.y - pg_size.sh - popup.height;
			}
		//

		return {x:popup.x, y:popup.y, dir:(popup.y<btn.y ? 0 : 2)};
	}

	MEL.setPopupBestPosition = function(btn, popup, type2class, over_button)
	{
		var pos = this.findPopupBestPosition(btn, popup, over_button);
		popup.style.top	= pos.y + "px";
		popup.style.left= pos.x + "px";

		if (typeof type2class == "undefined") type2class = true;
		if (type2class)
		{
			var cl = popup.className.replace(/ (top|bottom)/i, "");
			cl += (pos.dir == 0 ? " top" : (pos.dir == 2 ? " bottom" : ""));
			MEL.dom.setAttribute(popup, "class", cl);
		}
	}

	MEL.isCursorOverEl = function(e, el)
	{
		var pos = MEL.dom.getAbsolutePos(el);
		var size = MEL.dom.getElementSize(el);

		var sx = e.clientX + MEL.de.scrollLeft;
		var sy = e.clientY + MEL.de.scrollTop;
		var res = ((sx >= pos.x) && (sx < pos.x + size.w) && (sy >= pos.y) && (sy < pos.y + size.h));

		if (res) return {mx:sx, my:sy, ex:pos.x, ey:pos.y, ew:size.w, eh:size.h};
		return false;
	}

	MEL.rgba2arr = function(rgba)
	{
		var i, arr=[], len = rgba.length;
		var piece = (len > 6 ? 2 : 1);
		for (i=0; i<len; i+=piece)
			arr.push(parseInt(rgba.substr(i, piece) + (piece<2 ? rgba.substr(i, piece) : ""), 16));
		return arr;
	}

	MEL.arr2rgba = function(arr)
	{
		var i, rgba = "";
		for (i in arr)
			rgba += (Math.round(arr[i])<16 ? "0" : "") + Math.round(arr[i]).toString(16);
		return rgba;
	}

	MEL.inArray = function(el, arr)
	{
		for (var i in arr) if (arr[i] == el) return i-0;		// convert to number
		return -1;
	}

	MEL.searchSomething = function(el, linkAttr, func)
	{
		while (el && !func(el)) el = el[linkAttr];
		if (el && func(el)) return el;
		return false;
	}
	MEL.searchSomethingUpTheTree = function(el, func) { return MEL.searchSomething(el, "parentNode", func); }

	MEL.searchAttr = function(el, linkAttr, attr, value)
	{
		if (arguments.length > 3)
		{
			while (el && (el[attr] != value)) el = el[linkAttr];
			if (el && (el[attr] == value)) return el;
		}
		else
		{
			while (el && (typeof el[attr] == "undefined")) el = el[linkAttr];
			if (el && (typeof el[attr] != "undefined")) return el;
		}
		return false;
	}
	MEL.searchAttrUpTheTree = function(el, attr, value) { return MEL.searchAttr(el, "parentNode", attr, value); }

	MEL.searchClass = function(el, linkAttr, clName)
	{
		while (el && !MEL.dom.hasClass(el, clName)) el = el[linkAttr];
		if (el && MEL.dom.hasClass(el, clName))
			return el;
		return false;
	}
	MEL.searchClassUpTheTree = function(el, clName) { return MEL.searchClass(el, "parentNode", clName) }

	MEL.searchFirstTag = function(box, tags)
	{
		var els;
		if (typeof tags == "string")
		{
			els = box.getElementsByTagName(tags);
			return els.length ? els[0] : false;
		}

		els = box.childNodes;
		var res, i, cnt = els.length;
		for (i=0; i<cnt; i++)
			if (els[i].tagName)
			{
				if (MEL.inArray(els[i].tagName, tags) >= 0)
					return els[i];
				else
				{
					res = MEL.searchFirstTag(els[i], tags);
					if (res) return res;
				}
			}
		return false;
	}

	MEL.searchAllTags = function(box, tags)
	{
		var els, res = [];
		if (typeof tags == "string")
			return MEL.toArray(box.getElementsByTagName(tags));

		els = box.childNodes;
		var i, cnt = els.length;
		for (i=0; i<cnt; i++)
			if (els[i].tagName)
			{
				if (MEL.inArray(els[i].tagName, tags) >= 0)
					res.push(els[i]);
				else
					res = res.concat(MEL.searchAllTags(els[i], tags));
			}
		return res;
	}


	MEL.selects_status = true;
	MEL.switchSelects = function()
	{
		MEL.selects_status = !MEL.selects_status;
		var i, els = MEL.d.getTags("SELECT");
		for (i=0; i<els.length; i++)
		{
			if (MEL.selects_status)
			{
				if (MEL.dom.hasClass(els[i], "tmpHide"))
				{
					MEL.dom.removeClass(els[i], "tmpHide");
					els[i].style.visibility = "visible";
				}
			}
			else if (els[i].style.visibility != "hidden")
			{
				MEL.dom.appendClass(els[i], "tmpHide");
				els[i].style.visibility = "hidden";
			}
		}
	}


	MEL.joinObjects = function(trg, src)
	{
		for (var i in src)
			if (typeof trg[i] == "undefined")
				trg[i] = src[i];
	}


	MEL.removeAttrs = function(el, attrs, recur)
	{
		if (!attrs.join) attrs = [attrs];
		var i, cnt = attrs.length;
		for (i=0; i<cnt; i++)
			if (typeof el[attrs[i]] != "undefined")
				el[attrs[i]] = null;				// why not delete???
		if (recur && el.childNodes)
		{
			cnt = el.childNodes.length;
			for (i=0; i<cnt; i++)
				arguments.callee(el.childNodes[i], attrs, true);
		}
	}


	MEL.swapElements = function(el1, el2)
	{
		// el2 -> before el1 (don't need it, if el2 already before el1)
		// el1 -> before el2_before
		var el1_box = el1.parentNode;
		var el2_box = el2.parentNode;
		var el2_before = el2.nextSibling;
		if (el2_before != el1)
			el1_box.insertBefore(el2_box.removeChild(el2), el1);
		else
			el2_before = el2;

		el1 = el1_box.removeChild(el1);
		if (el2_before)
			el2_box.insertBefore(el1, el2_before);
		else
			el2_box.appendChild(el1);
	}


	MEL.moveColumnBefore = function(col1, col2, tbl)
	{
		if ((typeof col1 == "number") && !tbl) return;
		if (!tbl) tbl = MEL.searchAttrUpTheTree(col1, "tagName", "TABLE");
		if (typeof col1 != "number") col1 = col1.cellIndex;
		if (col2 && typeof col2 != "number") col2 = col2.cellIndex;
		if (col2 > col1) col2--;

		var rows = tbl.rows;
		var row, cell;
		var i, cnt = rows.length;
		for (i=0; i<cnt; i++) if (rows[i].cells.length >= col1)
		{
			row = rows[i];
			cell = row.cells[col1];

			if (col2 < 0)
				row.appendChild( row.removeChild(cell) );
			else
				row.insertBefore( row.removeChild(cell), row.cells[col2] );
		}
	}


	MEL.__callbacks = {};
	MEL.loadExternalScript = function(url, callback_param_name, callback, onload)
	{
		var i, script = MEL.d.createElement("SCRIPT");
		script.type = "text/javascript";
		if (callback_param_name)
		{
			for (i = MEL.date.getUTC()-0; MEL.__callbacks["x"+i.toString(36)]; i++);
			var cb_uniq_name = "x"+i.toString(36);

			MEL.__callbacks[cb_uniq_name] = function()
			{
				if (typeof callback == "function") callback.apply(null, arguments);
				delete MEL.__callbacks[cb_uniq_name];
				script.parentNode.removeChild(script);
			};
			url += (url.indexOf("?") > 0 ? "&" : "?") + callback_param_name + "=MEL.__callbacks." + cb_uniq_name;
		}
		if (onload) MEL.event.addListener(script, "load", onload);
		script.src = url;
		(MEL.d.getTags("head")[0] || MEL.d.getTags("body")[0]).appendChild(script);
	}
//

