// Object.prototype.getType = function () {
// 	var o = this;
// 	if (o == undefined) return undefined;
// 	if (o.getType) return o.getType();
// 	var type = typeof(o); 
// 	if (o.tagName) return "tag";
// 	switch (type) {
// 		case 'object' :
// 			if (o.constructor){
// 				var t = o.constructor.toString();
// 						if (t.match(/function\s+Date\(\)/)) { return "date"   }
// 				else if (t.match(/function\s+String\(\)/))  { return "string" }
// 				else if (t.match(/function\s+RegExp\(\)/))  { return "regexp" }
// 				else if (t.match(/function\s+Array\(\)/))   { return "array"  }
// 				else if (t.match(/function\s+Number\(\)/))  { return "number" }
// 				//else if (t.match(/function\s+Object\(\)/))  { return "object" }
// 			}
// 			return type;
// 			break;
// 		default :
// 			return type;
// 	}
// }

function ref(o) {
	if (o == undefined) return undefined;
	var type = typeof(o); 
	if (o.tagName) return "tag";
	switch (type) {
		case 'object' :
			if (o.constructor){
				var t = o.constructor.toString();
						if (t.match(/function\s+Date\(\)/)) { return "date"   }
				else if (t.match(/function\s+String\(\)/))  { return "string" }
				else if (t.match(/function\s+RegExp\(\)/))  { return "regexp" }
				else if (t.match(/function\s+Array\(\)/))   { return "array"  }
				else if (t.match(/function\s+Number\(\)/))  { return "number" }
				//else if (t.match(/function\s+Object\(\)/))  { return "object" }
			}
			return type;
			break;
		default :
			return type;
	}
}

function unionHash(h1,h2){
		var h = {};
		if (isHash(h1)) {
				$H(h1).keys().each(function(k){
						h[k] = h1[k];
				});
		}
		if (isHash(h2)) {
				$H(h2).keys().each(function(k){
						h[k] = h2[k];
				});
		}
		return h;
}

function isHash(o){
		return ref(o) == 'object';
}

function isArray(o){
		return ref(o) == 'array';
}

var html_entity = {
	/*
	entity     :   code, // description */
	quot       :     34, // quotation mark
	amp        :     38, // ampersand
	lt         :     60, // less-than
	gt         :     62, // greater-than
	nbsp       :    160, // non-breaking space
	iexcl      :    161, // inverted exclamation mark
	curren     :    164, // currency
	cent       :    162, // cent
	pound      :    163, // pound
	yen        :    165, // yen
	brvbar     :    166, // broken vertical bar
	sect       :    167, // section
	uml        :    168, // spacing diaeresis
	copy       :    169, // copyright
	ordf       :    170, // feminine ordinal indicator
	laquo      :    171, // angle quotation mark (left)
	not        :    172, // negation
	shy        :    173, // soft hyphen
	reg        :    174, // registered trademark
	trade      :   8482, // trademark
	macr       :    175, // spacing macron
	deg        :    176, // degree
	sup2       :    178, // superscript 2
	sup3       :    179, // superscript 3
	acute      :    180, // spacing acute
	micro      :    181, // micro
	para       :    182, // paragraph
	middot     :    183, // middle dot
	cedil      :    184, // spacing cedilla
	sup1       :    185, // superscript 1
	ordm       :    186, // masculine ordinal indicator
	raquo      :    187, // angle quotation mark (right)
	frac14     :    188, // fraction 1/4
	frac12     :    189, // fraction 1/2
	frac34     :    190, // fraction 3/4
	iquest     :    191, // inverted question mark
	times      :    215, // multiplication
	divide     :    247, // division
	Agrave     :    192, // capital a, grave accent
	Aacute     :    193, // capital a, acute accent
	Acirc      :    194, // capital a, circumflex accent
	Atilde     :    195, // capital a, tilde
	Auml       :    196, // capital a, umlaut mark
	Aring      :    197, // capital a, ring
	AElig      :    198, // capital ae
	Ccedil     :    199, // capital c, cedilla
	Egrave     :    200, // capital e, grave accent
	Eacute     :    201, // capital e, acute accent
	Ecirc      :    202, // capital e, circumflex accent
	Euml       :    203, // capital e, umlaut mark
	Igrave     :    204, // capital i, grave accent
	Iacute     :    205, // capital i, acute accent
	Icirc      :    206, // capital i, circumflex accent
	Iuml       :    207, // capital i, umlaut mark
	ETH        :    208, // capital eth, Icelandic
	Ntilde     :    209, // capital n, tilde
	Ograve     :    210, // capital o, grave accent
	Oacute     :    211, // capital o, acute accent
	Ocirc      :    212, // capital o, circumflex accent
	Otilde     :    213, // capital o, tilde
	Ouml       :    214, // capital o, umlaut mark
	Oslash     :    216, // capital o, slash
	Ugrave     :    217, // capital u, grave accent
	Uacute     :    218, // capital u, acute accent
	Ucirc      :    219, // capital u, circumflex accent
	Uuml       :    220, // capital u, umlaut mark
	Yacute     :    221, // capital y, acute accent
	THORN      :    222, // capital THORN, Icelandic
	szlig      :    223, // small sharp s, German
	agrave     :    224, // small a, grave accent
	aacute     :    225, // small a, acute accent
	acirc      :    226, // small a, circumflex accent
	atilde     :    227, // small a, tilde
	auml       :    228, // small a, umlaut mark
	aring      :    229, // small a, ring
	aelig      :    230, // small ae
	ccedil     :    231, // small c, cedilla
	egrave     :    232, // small e, grave accent
	eacute     :    233, // small e, acute accent
	ecirc      :    234, // small e, circumflex accent
	euml       :    235, // small e, umlaut mark
	igrave     :    236, // small i, grave accent
	iacute     :    237, // small i, acute accent
	icirc      :    238, // small i, circumflex accent
	iuml       :    239, // small i, umlaut mark
	eth        :    240, // small eth, Icelandic
	ntilde     :    241, // small n, tilde
	ograve     :    242, // small o, grave accent
	oacute     :    243, // small o, acute accent
	ocirc      :    244, // small o, circumflex accent
	otilde     :    245, // small o, tilde
	ouml       :    246, // small o, umlaut mark
	oslash     :    248, // small o, slash
	ugrave     :    249, // small u, grave accent
	uacute     :    250, // small u, acute accent
	ucirc      :    251, // small u, circumflex accent
	uuml       :    252  // small u, umlaut mark
};

function entity (ent,name) {
	var code;
	if (code = html_entity[name])
		return String.fromCharCode(code);
	return ent;
}
function entity_c (ent,code) {
	return String.fromCharCode(code);
}

function $dce(name){
		return document.createElement(name);
}

function $dctn(text){
	var nt = text && text.replace
		? text.replace(/&(\w+);/g,entity).replace(/&#(\d+);/g,entity_c)
		: '';
	return document.createTextNode(nt);
}

function $node(){
		var args = $A(arguments);
		var name,opts = {},childs = [];
		name = args.shift();
		var init = true;
		while (init) {
				init = false;
				if (isHash(args[0])) { opts = unionHash(opts,args.shift()); }
				if (opts._args) {args = opts._args;opts._args = undefined; init = true; }
		}
		if (isArray(args[0])) {
				childs = args.shift();
		}else{
				childs = args;
		}
		var n = $dce(name);
		if (!isHash(opts) && isArray(opts)){ var childs = opts; }

		if (isHash(opts)) {
				$H(opts).keys().each(function(k){
						Try.these(
								function(){ n[k] = opts[k]; },
								function(){ n.setAttribute(k,opts[k]); }
						);
				});
		}
		if (isArray(childs)){
				for (var i = 0; i < childs.length; i++) {
						var E = childs[i];
						if (typeof E == 'object' && E.tagName){
							n.appendChild(E);
						}else{
							n.appendChild($dctn(E));
						}
				}
		}
		//alert ("OK: " + name);
		return n;
}
function $h()   {
		var args = $A(arguments);
		var i = args.shift();
		return $node("h" + i,{_args: args});
}

function $div()   { return $node("div",{_args: $A(arguments)}); }
function $span()  { return $node("span",{_args: $A(arguments)}); }

function $ul()    { return $node("ul",{_args: $A(arguments)}); }
function $li()    { return $node("li",{_args: $A(arguments)}); }
function $sub()   { return $node("sub",{_args: $A(arguments)}); }
function $sup()   { return $node("sup",{_args: $A(arguments)}); }

function $td()    { return $node("td",{_args: $A(arguments)}); }
function $th()    { return $node("th",{_args: $A(arguments)}); }
function $tr()    { return $node("tr",{_args: $A(arguments)}); }
function $thead() { return $node("thead",{_args: $A(arguments)}); }
function $tbody() { return $node("tbody",{_args: $A(arguments)}); }
function $tfoot() { return $node("tfoot",{_args: $A(arguments)}); }
function $table() { return $node("table",{_args: $A(arguments), border: 1}); }
function $label(id,name,opts) {
		return $node("label",unionHash({"htmlFor" : id},opts),name );
}
function $radio(id,name,value,chk,opts) {
	var p = {};
	p['type'] = 'radio';
	if (name)  p['name']  = name;
	if (id)    p['id']    = id;
	if (value) p['value'] = value;
	var i = $node("input",unionHash(p,opts));
	if (chk) i.setAttribute("checked",true);
	return i;
}
function $check(id,name,value,chk,opts) {
	var p = {};
	p['type'] = 'checkbox';
	if (name)  p['name']  = name;
	if (id)    p['id']    = id;
	if (value) p['value'] = value;
	var i = $node("input",unionHash(p,opts));
	if (chk) i.setAttribute("checked",true);
	return i;
}
function $input(id,name,value,opts) {
	var p = {};
	p['type'] = 'text';
	if (id)    p['id']    = id;
	if (name)  p['name']  = name;
	if (value) p['value'] = value;
	var i = $node("input",unionHash(p,opts));
	return i;
}
function $hidden(id,name,value,opts) {
	var p = {};
	p['type'] = 'hidden';
	if (id)    p['id']    = id;
	if (name)  p['name']  = name;
	if (value) p['value'] = value;
	var i = $node("input",unionHash(p,opts));
	return i;
}
function $file(id,name,opts) {
	var p = {};
	p['type'] = 'file';
	if (id)    p['id']    = id;
	if (name)  p['name']  = name;
	var i = $node("input",unionHash(p,opts));
	return i;
}
function $button(id,name,value,opts) {
	var i = $node("input",unionHash({
		"type": "button",
		"name": name,
		"id"  : id,
		"value":value
	},opts));
	return i;
}
function $submit(id,name,value,opts) {
	var p = {};
	p['type'] = 'submit';
	if (id)    p['id']    = id;
	if (name)  p['name']  = name;
	if (value) p['value'] = value;
	var i = $node("input",unionHash(p,opts));
	return i;
}
function $link(href,opts) {
	var args = $A(arguments);
	var href = args.shift();
	var i = $node("a",{_args: args});
	i.href = href;
	return i;
}
function $img(src,alt,opts) {
	var args = $A(arguments);
	var src = args.shift();
	var alt  = args.shift();
	var i = $node("img",{_args: args});
	i.src = src;
	i.alt = i.title = alt;
	return i;
}
function $linkicon(href,src,alt,w,h) {
	var args = $A(arguments);
	var href = args.shift();
	var src = args.shift();
	var alt  = args.shift();
	var w  = args.shift();
	var h  = args.shift();
	var i = $node("img",{_args: args});
	i.src = src;
	i.alt = i.title = alt;
	i.width = w;
	i.height = h;
	i.border = 0;
	var l = $link(href,i);
	l.target = '_blank';
	return l;
}

function $br () { return $node("br"); }

function $form(){ return $node("form",{_args: $A(arguments)}); }

function $select(id,name,opts,itms) {
	var p = {};
	var args = $A(arguments);
	var id = args.shift() || '';
	var name = args.shift() || '';
	
	if (id)    p['id']    = id;
	if (name)  p['name']  = name;
	if (args.length) p['_args'] = args;
	var opts = unionHash(p,args.shift() || {});
	var i = $node("select",opts);
	return i;
}

/*
function unionHash(h1,h2){
	var h = {};
	if (isHash(h1)) {
		$H(h1).keys().each(function(k){
			h[k] = h1[k];
		});
	}
	if (isHash(h2)) {
		$H(h2).keys().each(function(k){
			h[k] = h2[k];
		});
	}
	return h;
}
function isHash(o){
	return ref(o) == 'object';
}
function isArray(o){
	return ref(o) == 'array';
}

function $dce(name){
	return document.createElement(name);
}
function $node(){
	var args = $A(arguments);
	var name,opts = {},childs = [];
	name = args.shift();
	var init = true;
	while (init) {
		init = false;
		if (isHash(args[0])) { opts = unionHash(opts,args.shift()); }
		if (opts._args) {args = opts._args;opts._args = undefined; init = true; }
	}
	if (opts && opts.onclick) alert("OnClick "+opts.onclick+" for "+name);
	if (isArray(args[0])) {
		childs = args.shift();
	}else{
		childs = args;
	}
	var n = $dce(name);
	if (!isHash(opts) && isArray(opts)){ var childs = opts; }
	
	if (isHash(opts)) {
		$H(opts).keys().each(function(k){
			Try.these(
				function(){ n[k] = opts[k]; },
				function(){ n.setAttribute(k,opts[k]); }
			);
		});
	}
	if (isArray(childs)){
		for (var i = 0; i < childs.length; i++) {
			var E = childs[i];
			if (typeof E == 'object' && E.tagName){
				n.appendChild(E);
			}else{
				n.innerHTML = E;
			}
		}
	}
	return n;
}

function $h()   {
	var args = $A(arguments);
	var i = args.shift();
	return $node("h" + i,{_args: args});
}

function $div()   { return $node("div",{_args: $A(arguments)}); }

function $ul()    { return $node("ul",{_args: $A(arguments)}); }
function $li()    { return $node("li",{_args: $A(arguments)}); }
function $sub()   { return $node("sub",{_args: $A(arguments)}); }
function $sup()   { return $node("sup",{_args: $A(arguments)}); }

function $th()    { return $node("th",{_args: $A(arguments)}); }
function $td()    { return $node("td",{_args: $A(arguments)}); }
function $tr()    { return $node("tr",{_args: $A(arguments)}); }
function $thead() { return $node("thead",{_args: $A(arguments)}); }
function $tbody() { return $node("tbody",{_args: $A(arguments)}); }
function $tfoot() { return $node("tfoot",{_args: $A(arguments)}); }
function $table() { return $node("table",{_args: $A(arguments)}); }
function $label(id,name,opts) {
	return $node("label",unionHash({"htmlFor" : id},opts),name );
}
function $radio(id,name,value,chk,opts) {
	var i = $node("input",unionHash({
		"type": "radio",
		"name": name,
		"id"  : id,
		"value":value
	},opts));
	if (chk) i.setAttribute("checked",true);
	return i;
}
function $check(id,name,value,chk,opts) {
	var i = $node("input",unionHash({
		"type": "checkbox",
		"name": name,
		"id"  : id,
		"value":value
	},opts));
	if (chk) i.setAttribute("checked",true);
	return i;
}
function $button(id,name,value,opts) {
	var i = $node("input",unionHash({
		"type": "button",
		"name": name,
		"id"  : id,
		"value":value
	},opts));
	return i;
}
function $input(id,name,value,opts) {
	var i = $node("input",unionHash({
		"type": "text",
		"name": name,
		"id"  : id,
		"value":value
	},opts));
	return i;
}

function handle_event (e) {
	var code,targ;
	if (!e) var e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;
	if (e.target) targ = e.target;
	else if (e.srcElement) targ = e.srcElement;
	if (targ.nodeType == 3) // defeat Safari bug
	targ = targ.parentNode;
	return {
		"e"      : e,
		"type"   : e.type,
		"code"   : code,
		"target" : targ
	};
}

function checkTab(evt) {
	var tab = "\t";
    var t = evt.target;
    var ss = t.selectionStart;
    var se = t.selectionEnd;

    // Tab key - insert tab expansion
    if (evt.keyCode == 9) {
        evt.preventDefault();
        
        // Special case of multi line selection
        if (ss != se && t.value.slice(ss,se).indexOf("\n") != -1) {
            // In case selection was not of entire lines (e.g. selection begins in the middle of a line)
            // we ought to tab at the beginning as well as at the start of every following line.
            var pre = t.value.slice(0,ss);
            var sel = t.value.slice(ss,se).replace(/\n/g,"\n"+tab);
            var post = t.value.slice(se,t.value.length);
            t.value = pre.concat(tab).concat(sel).concat(post);
            
            t.selectionStart = ss + tab.length;
            t.selectionEnd = se + tab.length;
        }
        
        // "Normal" case (no selection or selection on one line only)
        else {
            t.value = t.value.slice(0,ss).concat(tab).concat(t.value.slice(ss,t.value.length));
            if (ss == se) {
                t.selectionStart = t.selectionEnd = ss + tab.length;
            }
            else {
                t.selectionStart = ss + tab.length;
                t.selectionEnd = se + tab.length;
            }
        }
    }
    
    // Backspace key - delete preceding tab expansion, if exists
    else if (evt.keyCode==8 && t.value.slice(ss - 4,ss) == tab) {
        evt.preventDefault();
        
        t.value = t.value.slice(0,ss - 4).concat(t.value.slice(ss,t.value.length));
        t.selectionStart = t.selectionEnd = ss - tab.length;
    }
    
    // Delete key - delete following tab expansion, if exists
    else if (evt.keyCode==46 && t.value.slice(se,se + 4) == tab) {
        evt.preventDefault();
        
        t.value = t.value.slice(0,ss).concat(t.value.slice(ss + 4,t.value.length));
        t.selectionStart = t.selectionEnd = ss;
    }
    
    // Left/right arrow keys - move across the tab in one go
    else if (evt.keyCode == 37 && t.value.slice(ss - 4,ss) == tab) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss - 4;
    }
    else if (evt.keyCode == 39 && t.value.slice(ss,ss + 4) == tab) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss + 4;
    }
    
}
*/