/* CSV:$Revision: 1.12 $ */

if (typeof G=="undefined"){G={};};

var CONSOLE;

var doc=document;

/*********************** CONSOLE for debug (firebug alternative) ********************/

if (location.href.match(/DEBUG$/)){
	G._DEBUG=true;
	if (typeof CONSOLE == "undefined") {
		CONSOLE={_buf:[],_cnt:0};
		CONSOLE.clear=CONSOLE.clear||function(){CONSOLE._cnt=0;CONSOLE._buf=[];};
		CONSOLE.show=CONSOLE.show||function(){status="";var w=open("","");
			w.document.write("<html><head><title>CONSOLE</title><style type='text/css'>pre {white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap;white-space: pre-wrap;word-wrap: break-word;}</style>"
				+"<meta name='viewport' content='width=device-width' />"
				+"</head><body style='font-size:12px;font-family:\"MS Gothic\",courier,osaka,monospace;'><pre style=''>"
				+(G.esc(CONSOLE._buf.join("\n--\n")))
					.split("ERROR:").join("<span style='background-color:red;font-weight:bold;'>ERROR:</span>")
					.split("WARNING:").join("<span style='background-color:yellow;font-weight:bold;'>WARNING:</span>")
					.split("INFO:").join("<span style='color:blue;font-weight:bold;'>INFO:</span>")
				+"</pre></body></html>"); w.document.close();
			CONSOLE.clear();
		};
		CONSOLE.show2=CONSOLE.show2||function(){
			if(CONSOLE._console2&&!CONSOLE._console2.closed){
				CONSOLE._console2.focus();
				return;
			}
			status="";var w=window.open("about:blank","");
			CONSOLE._console2=w;
			w.document.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"><html><head><title>CONSOLE</title>"
				+"<meta name='viewport' content='width=device-width' />"
				+"<script type='text/javascript' src='"+G._BASEPATH+"base.js' charset='utf-8'></script>"
				+"<script type='text/javascript' src='"+G._BASEPATH+"base-debug.js' charset='utf-8'></script>"
				+"</head><body></body></html>");
			w.document.close();
			//CONSOLE.clear();
		};
	}
	CONSOLE.log=CONSOLE.log||function(str){
		if(CONSOLE._console2&&CONSOLE._console2.addmsg){
			CONSOLE._console2.addmsg(str);
		}else{
			CONSOLE._buf[CONSOLE._buf.length]=str;
		}
	};
	CONSOLE.info=CONSOLE.info||function(str){CONSOLE.log("INFO:"+str);};
	CONSOLE.warn=CONSOLE.warn||function(str){CONSOLE.log("WARNING:"+str);status="WARNING:CONSOLE:Shift+Ctrl+D";};
	CONSOLE.error=CONSOLE.error||function(str){CONSOLE.log("ERROR:"+str);status="ERROR:CONSOLE:Shift+Ctrl+D";};
	CONSOLE.exec=function(){
		var a=prompt("eval expression",CONSOLE.exec._l||""); if(a==null){return;} CONSOLE.exec._l=a;
		try{CONSOLE.log("EXEC:"+a+"\n"+eval(a));}
		catch(ex){CONSOLE.error(G.dump(ex));}
		CONSOLE.show()};
	CONSOLE.dump=function(){var a=prompt("dump object",CONSOLE.dump._l||""); if(a==null){return;} CONSOLE.dump._l=a;
		try{CONSOLE.log("DUMP:"+a+"\n"+G.dump(eval(a)));}
		catch(ex){CONSOLE.error(G.dump(ex));}
		CONSOLE.show()};
} else {
	if(typeof console != "undefined"){_CONSOLE=console;}
	CONSOLE={
		log:function(){},
		warn:function(){},
		debug:function(){},
		info:function(){},
		error:function(){},
		show:function(){},
		dump:function(){}
	};
}

/*
if (typeof console == "undefined"){
	try{
		console=CONSOLE;
	}catch(ex){}
}
*/

(function(G){

G.toString=function(){return "[object G on "+location.href+" base.js]";}

G.isMSIE=/*@cc_on!@*/false;
G.isSafari=(navigator.appVersion.indexOf("KHTML")>-1); // or Konqueror
//G.isOpera=(navigator.appVersion.indexOf("Opera")>-1);
G.isOpera=window.opera;
G.isMac=(navigator.appVersion.indexOf("Mac OS")>-1);
G.isFirefox=(navigator.userAgent.indexOf("Firefox/")>-1);

G.isMSIE8=G.isMSIE&&(document.documentMode >= 8);
G.isMSIE7=G.isMSIE&&window.XMLHttpRequest&&!G.isMSIE8;
G.isMSIE6=G.isMSIE&&(!G.isMSIE7)&&(!G.isMSIE8);

G.isSafari3=G.isSafari && window.getMatchedCSSRules && typeof CharacterData != 'function';
G.isGoogleChrome=G.isSafari3 && typeof CharacterData == 'function';
G.isSafari2=G.isSafari&&(!G.isSafari3);

//G.isIPhone=(navigator.userAgent.match(/Mozilla\/5.0 \((.*)\) AppleWebKit\/(.*) \(KHTML, like Gecko\) Version\/.* Mobile\/(.*) Safari\/(.*)/)[3]);
G.isIPhone=(navigator.userAgent.match(/Mozilla\/5.0 \((.*)\) AppleWebKit\/(.*) \(KHTML, like Gecko\) Version\/.* Mobile\/(.*) Safari\/(.*)/));

CONSOLE.log("MSIE:"+G.isMSIE+",MSIE7:"+G.isMSIE7+",MSIE8:"+G.isMSIE8+",FireFox:"+G.isFirefox+",Safari:"+G.isSafari+",Opera:"+G.isOpera+",Mac:"+G.isMac+",iPhone:"+G.isIPhone);

G.refreshElement=function ie6refreshelem(e){
	//CONSOLE.log("G.refreshElement:"+G.getXPath(e));
	//if(!e){return;}
	if(!e){e=document.body;}
	// 特にIE6 で描画が乱れるときの再描画
	if(G.isMSIE6||G.isSafari){
		var id=e.id;
		if(!id){id="refresh-"+new Date().valueOf();e.id=id;}
		var s=G.setStyleSheet("#"+id+" { visibility:hidden; }");
		//G.removeStyleSheet.later(1,null,s);
		G.removeStyleSheet(s);
	}
};

var me;
var s=doc.getElementsByTagName("script");
for (var i=s.length-1; i>=0; i--){
	if(s[i].src){
		if (s[i].src.split("?")[0].split("/").pop()=="base.js"){
			me=s[i]; break;
		}
	}
}
//if (me){clearInterval(_baset);}else{return;}
if (!me){throw new Error("<script src='base.js' /> is not found."+"\n"+doc.getElementsByTagName("head")[0].innerHTML);}

var m=me.src.match(/^(.*\/)?base.js(\?.*)?$/);
var _BASEPATH=m[1]||"";
if (_BASEPATH!=""){_BASEPATH+="";}

G._BASEPATH=_BASEPATH;
CONSOLE.info("base.js BASEPATH:"+G._BASEPATH)

var isBackCompat=doc.compatMode=="BackCompat"; // Safariにはない
if (isBackCompat) { CONSOLE.warn("document is rendered with backword compatible mode!"); }
else { CONSOLE.info("document is rendered with standard mode."); }

/**
 * dump object
 * @param {object} o target
 * @param {boolean} f optional: own property only (default:false)
 */
function dump(o,f) {
	f=(f===undefined)?false:f;
	var r=o; if (typeof o=="object"){r=""; for (var p in o) {
		try {
			if (f&&o.hasOwnProperty(p)) { continue; }
			var v=o[p];
			//if(o[p] instanceof Function){v=((o[p]).toSource|(o[p]).toString)().replace(/^([^\{]+)\{.*$/,"$1");}
			if(v instanceof Array){v="["+v+"]"}
			r+=p+":"+v+"\n";
		} catch (e){ r+=p+":[ERROR:"+e.toString()+"]\n";}
	}}
	return r;
};
G.dump=dump;

function dumpStack() {
	var r=[], cnt=1;
	for (var c=arguments.callee.caller; c; c=c.arguments.callee.caller) {
		var sa=[], a=c.arguments;
		for (var i=0; i<a.length; i++) { sa.push( (typeof a[i] == "object") ? "["+dump(a[i])+"]" : a[i] ); }
		r.push(cnt + ":" + a.callee.toString().replace(/\t/g,"  ").replace(/^(function[^{]+?{)[\u0000-\uffff]+$/m,"$1 ... }") + " called with ("+sa.join(",")+")");
		if (cnt++>5) { r.push("..... more"); break; }
	}
	return "------- stack -------------\n"+r.join("\n-\n") + "\n---------------------\n";
};
G.dumpStack=dumpStack;


/********************** requires ****************************/

/**
 * dynamic include js
 * @param {string} p relative path to include js file. base is this script
 * @param {string} c optional:charset default:UTF-8
 * @return {htmlScriptElement} &lt;script&gt; element
 * @param {boolean} f force load (ignore loaded }
 */
function requireJs(p,c,f,id,onload,onerror) {
	if (G.requireJs._i===false){
		G.requireJs._i={}; var ss=doc.getElementsByTagName("script");
		G.each(ss,function(s,i){if (s.src){CONSOLE.info("G.requireJs:"+s.src + " is already preloaded");G.requireJs._i[s.src]=true;}});
	}
	if(p.match(/^https?:/)||p.indexOf("/")===0) {} else {p=G._BASEPATH+p;}
	if (!f&&(p in requireJs._i)){return;}
	var s=doc.createElement("script"); s.type="text/javascript";s.charset=(c||"UTF-8"); s.src=p; if(id){s.id=id};
	if(onload){
		s.onload=(function(s,onload){return function(){
			onload.apply(s,arguments);
		}})(s,onload);
		if(G.isMSIE){
			s.onreadystatechange=(function(s,onload){
				return function(){
					switch(s.readyState){
						case 4: case "complete": case "loaded":
							if(s.status==200||s.status==0){
								try{onload.apply(s,arguments);}finally{s.onreadystatechange=null;}
							}
					}
				};
			})(s,onload);
		}
	}
	if(onerror){
		s.onabort=(function(s,onerror){return function(){onerror.apply(s,arguments);}})(s,onerror);
		s.onerror=(function(s,onerror){return function(){onerror.apply(s,arguments);}})(s,onerror);
	}

	G.requireJs._i[s.src]=true; CONSOLE.info("G.requireJs:"+p+" required");
	doc.getElementsByTagName("head")[0].appendChild(s);
	return s;
};
requireJs._i = false;
G.requireJs=requireJs;

/**
 * dynamic include CSS
 * @param {string} p relative path to include css file. base is this script
 * @param {string} c optional:charset default:UTF-8
 * @return {htmlLinkElement} &lt;link&gt; element
 */
function requireCss(p,c,e) {
	var s=doc.createElement("link"); s.rel="stylesheet";s.type="text/css";s.charset=c||"UTF-8";
	if (p.match(/^https?:\/\//)||p.match(/^[\/\.]/)) { s.href = p; }
	else { s.href = G._BASEPATH + p; }
	if(e){
		doc.getElementsByTagName("head")[0].insertBefore(s,e);
		removeElement(e);
	}else{
		if (G.isMSIE6) {
			if (document.readyState!="complete"){
				G.addEvent(window, "load", function(){
					document.getElementsByTagName("head")[0].appendChild(s);
				});
			} else {
				document.getElementsByTagName("head")[0].appendChild(s);
			}
		} else {
			document.getElementsByTagName("head")[0].appendChild(s);
		}
	}
	return s;
};
G.requireCss=requireCss;

/**
 * んー、IEでは.txtしかつかえない
 * load file as text (restricted in same domain)
 * @param {Object} url
 * @param {Object} f onload(txt,iframe,document)
 */
function ifrLoadText(url,f){
	var ifr=doc.createElement("iframe");
	ifr.style.cssText="border:none;width:0;height:0;"
	doc.body.appendChild(ifr);
	function ifronload(ifr,f){
		var doc=ifr.contentDocument||ifr.document;
		doc.close();
		var txt="";
		try{
			if(G.isMSIE){
				txt=ifr.document.body.innerText||"";
			}else{
				txt=ifr.contentDocument.body.textContent||"";
			}
		}catch(ex){
			txt=null;
		}
		f(txt,ifr,doc);
		(function(ifr){
			doc.body.removeChild(ifr);
		}).bindArgs(ifr).later(100);
	};
	var onloadf=ifronload.bindArgs(ifr,f);
	if(G.isMSIE){
		ifr.onreadystatechange=function(){
			if(this.readyState=="complete"){
				onloadf();
				this.onreadystatechange=null;
			}
		}
	}else{
		ifr.onload=onloadf;
	}
	ifr.src=url;
};
G.ifrLoadText=ifrLoadText;

/**
 * load <stylepath>/tmpl.css and
 * 	replace:TMPLID__ to <id> and __IMGPATH__ to <stylepath>/img
 * @param {string} stylepath
 * @param {string} id
 * @param {function} f onsetstyle(linkelement,setstylestring)
 */
function requireCssTmpl(stylepath,params,f){
	params=(typeof params=="string")?{id:params}:params;
	var stmpl = requireCssTmpl._tmpl[stylepath];
	if (!stmpl) {
		G.requireCssTmpl._tmpl[stylepath]="loading";
		CONSOLE.log("G.requireCssTmpl:"+stylepath+"/tmpl.css");

		if(!G.isMSIE6){
	
			var st=G.requireCss(stylepath + "/tmpl.css","utf-8");
			G.requireCssTmpl._e[stylepath]=st;
		
			(function(){
				
			function setRequireCssTmpl(stylepath){
				var stmpl = G.getStyleSheetText(G.requireCssTmpl._e[stylepath]);
				if(stmpl===null||stmpl==""){
					setRequireCssTmpl.bindArgs(stylepath).later(500);return;
				}
				CONSOLE.log("G.requireCssTmpl:get tmpl:"+stylepath+":\n\""+stmpl+"\"");
				G.requireCssTmpl._tmpl[stylepath] = stmpl;
				//G.removeStyleSheet.bindArgs(st).later(3000);
			};
			setRequireCssTmpl.bindArgs(stylepath).later(500);
	
			}).bindArgs(stylepath).later(500);
			
			//setTmpl.later(500);
	
		}else{
			// IE6 でgetStyleSheetTextが落ちることがあるから
			var aj=new G.Ajax();
			
			aj.get(stylepath+"/tmpl.css",{},function(txt){
				if(txt===null){
					CONSOLE.error("G.requireCssTmpl:cannot load "+stylepath+"/tmpl.css");
					return;
				}
				CONSOLE.log("G.requireCssTmpl:stmpl:"+stylepath+":\n"+txt);
				G.requireCssTmpl._tmpl[stylepath]=txt;
			});
		}

	}
	((function(stylepath,f,params){
		var imgpath=G.isSafari?"img":stylepath+"/img";
		var news = G.requireCssTmpl._tmpl[stylepath].replace(/\*\|/g, "")
				.replace(/TMPLID__/g, params.id);
		delete params.id;
		G.each(params,function(v,p){
			news=news.replace(new RegExp("__"+p.toUpperCase()+"__","g"),v);
		});
		if(!G.isSafari){
			news=news.replace(/(url\(|src=)([^\),]+)/g,function(all,a1,a2){
				var m=a2.match(/^\s?["']?(https?|\/):/);
				if(!m){
					var m=a2.match(/^(\s?["']?)(.*)$/)
					return a1+(m[1]||"")+stylepath+"/"+(m[2]||"");
				} else return all;
			});
		}
				//.replace(/__IMGPATH__/g, imgpath)
		CONSOLE.log("G.requireCssTmpl:set:"+news);
		var s=G.setStyleSheet(news);
		f&&f(s,news);
	}).bindArgs(stylepath,f,params)).poll((function(stylepath){
		return G.requireCssTmpl._tmpl[stylepath]&&G.requireCssTmpl._tmpl[stylepath]!="loading";
	}).bindArgs(stylepath));
}
requireCssTmpl._tmpl={};
requireCssTmpl._e={};
G.requireCssTmpl=requireCssTmpl;


/**************** misc ********************/

/**
 * func(for each o) { return isbreak;}
 * <p>NOTE:don't modify o in func();</p>
 * @param {object} o target object or array
 * @param {function} func process function(elem,index, o) for each obj element. if return true, break loop
 */
function each(o, func, thisobj) {
	var i,l;
	thisobj=(thisobj===undefined)?this:thisobj;
	if(o===null||o===undefined){return;}
	if ("length" in o && "item" in o) { for (i=0,l=o.length; i<l; i++){ if(func.apply(thisobj,[o.item(i),i,o])){break;}} }
	else if ("length" in o) { for(i=0,l=o.length;i<l;i++) { if(func.apply(thisobj,[o[i],i,o])){break;}} }
	//if (o.hasOwnProperty&&o.hasOwnProperty("length")&&o.hasOwnProperty("item")) { for (i=0,l=o.length; i<l; i++){ if(func(o.item(i),i,o)){break;}} }
	//else if (o.hasOwnProperty&&o.hasOwnProperty("length")) { for(i=0,l=o.length;i<l;i++) { if(func(o[i],i,o)){break;}} }
	else { for (var p in o) { if(func.apply(thisobj,[o[p],p,o])){break;}} }
	return o;
};
G.each=each;

function eachLater(o,func,oncomp,seq,autostart){
	if(seq===undefined){seq=new G.Seq();}
	G.each(o,function(v,p,o){
		seq.add(func.bindThis(this).bindArgs(v,p,o),autostart);
	});
	seq.add(oncomp);
	seq.start();
	return seq;
}
G.eachLater=eachLater;

//Array.prototype.each = function(func){G.each(this,func)};

/**
 * clone object (own property only).
 * <p>NOTE: DONT USE WITH reference of parent,self (ex, .parentNode)</p>
 * @param{o} target
 * @return new cloned object;
 */
function clone(o) {
	var r;
	if(o instanceof Array || typeof(o)=="array"){
		r=[];
		for(var i=0;i<o.length;i++){
			r[i]=G.clone(o[i]);
		}
	} else if (typeof(o)=="object"){
		r={}; for (var p in o) {
			if (!o.hasOwnProperty(p)) {continue;}
			r[p]=G.clone(o[p]);
		}
	} else {
		r=o;
	}
return r;
};
/* function clone(a){function Cloned(){};Cloned.prototype=a;return new Cloned();} */
G.clone=clone;

/**
 * obj={aaa:{p1:?,p2:?},bbb:{p1:?,p2:?},...}
 * sort(obj,"p1");
 */
function sortObj(o,p,desc){
	o=G.clone(o);
	desc=desc?1:-1;
	var sorted=[];
	G.each(o,function(v,p){
		sorted[sorted.length]=v;
	});
	function numsort(a,b){return a[p]<b[p]?desc:0-desc;}
	sorted=sorted.sort(numsort);
	return sorted;
}
G.sortObj=sortObj;

function isString(o){ return typeof o == "string" || o instanceof String; };
function isNumber(o){ return typeof o == "number" || o instanceof Number || !isNaN(o); };
function isFunction(o){ return typeof o == "function" || o instanceof Function; };
function isBoolean(o){ return typeof o == "boolean" || o instanceof Boolean; };
function isDate(o){ return o instanceof Date; };
function isArray(o){ return o instanceof Array; };
function isObject(o){ // not function
	switch(typeof o){
		case "string": case "number": case "boolean": case "undefined": case "function": return false;
	}
	switch(typeof o.valueOf()){
		case "string": case "number": case "boolean": case "undefined": case "function": return false;
	}
	return true;
};
G.isString = isString;
G.isNumber = isNumber;
G.isFunction = isFunction;
G.isBoolean = isBoolean;
G.isDate = isDate;
G.isArray = isArray;
G.isObject = isObject;

/**
 * replace all occurence of "${NAME}" in s to v["NAME"].
 * <p>ex) G.tmpl("value1 is ${v1}, value2 is ${v2}",{v1:"aaa", v2:"bbb"}) -&lt; "value1 is aaa, value2 is bbb"</p>
 * @param {string} s target string
 * @param {object} o variables container
 * @return replaced string
 */
//function tmpl(s,v) {s=(s===undefined)?"":s;G.each(v,function(v,p){s=s.split("${"+p+"}").join(v);});return s;};
function tmpl(s,v) {s=(s===undefined)?"":s;
	G.each(v,function(v,p){s=s.split("${"+p+"}").join(v===undefined?"":v);});
	return s;
};
G.tmpl=tmpl;

String.prototype.tmpl = function(v){return tmpl(this,v);};

/**
 * template object.
 * <%= ... %>,${...} and <% ... %> is available.context variable is cx;
 * @param {String} str template
 */
function Template(str){
	str=str.replace(/\$\{([^\}]+)\}/g,"<%=$1%>");
	var fs=["with(cx) { var _r=[];"];
	G.each(str.split("%>"),function(a){
		var b=a.split("<%"); fs.push("_r[_r.length]=\""+G.esc(b[0],"J")+"\";");
		if(b[1]){if(b[1].indexOf("=")==0){fs.push("_r[_r.length]="+b[1].substring(1)+";");}else{fs.push(b[1]);}}
	}); fs.push("} return _r.join(\"\");");
	//CONSOLE.log("Template():"+fs.join("\n"));
	this._f=new Function("cx",fs.join("\n"));
}
/**
 * apply context to template str; 
 * @param {Object} cx context
 */
Template.prototype.apply=tmplapply;
function tmplapply(cx){return this._f(cx);}
G.Template=Template;

/**
 * bind obj as "this" to function
 * @param {function} f source function
 * @param {object} o object to bind func
 * @return {function} o binded new function
 */
function bindThis(o,f) {
	var _f=f,_o=(o===undefined)?this:o;
	var _r=function boundThis(){
		return _f.apply(_o,arguments);
	};/*_f=null;_o=null*/;
	_r._bound="this";
	_r._this=_o;
	_r._f=_f;
	/*
	this.toString=function(){
		return _f.toString()+"\n bound:this:"+G.dump(_o);
	};
	*/
	return _r;
};
G.bindThis=bindThis;
Function.prototype.bindThis=function(o){return G.bindThis(o,this);};

Function.prototype.bind = function(o){
	var _f=this,_a=Array.prototype.slice.call(arguments,1);
	var _r=function boundThis(){
		return _f.apply(o, _a);
	};
	_r._bound="all";
	_r._f=_f;
	_r._this=o;
	_r._args=_a;
	/*
	this.toString=function(){
		return _f.toString()+"\n bound:this:"+G.dump(o)+"\n     :args:"+G.dump(_a);
	};
	*/
	return _r;
};

Function.prototype.bindArgs = function(){
	var _f=this,_a=Array.apply(null,arguments);
	var _r=function boundArgs(){
		return _f.apply(this,_a);
	};
	_r._bound="args";
	_r._f=_f;
	_r._args=_a;
	/*
	this.toString=function(){
		return _f.toString()+"\n bound:args:"+G.dump(_a);
	};
	*/
	return _r;
};

function findArgumentsFromStack(func) {
	for (var a=arguments; a.callee.caller; a=a.callee.caller.arguments) {
		for (var i=0; i<a.length; i++) { if (func(a[i])) { return a[i]; } }
	}
};
G.findArgumentsFromStack=findArgumentsFromStack;

Function.prototype.later=function(time,thisobj){
	time=(time===undefined)?10:time;
	var _f=this, _a=Array.prototype.slice.call(arguments,2);
	if(typeof _f != "function" && ! _f instanceof Function){
		CONSOLE.error("Function.later:this is not function:"+(_f.toSource||_f.toString)()+":"+G.dumpStack());
		throw new Error("Function.later:this is not function:"+_f+":"+G.dumpStack());
		return;
	}
	var lf=(function(f,a){
		var _f=f,_a=a;
		return function doLater(){
			try{
				_f.apply(thisobj,_a);
			}catch(ex){
				CONSOLE.error("base.js:Function.later:\n"+G.dump(ex)+"\n--function--\n"+(_f.toSource||_f.toString)());
				//CONSOLE.error(G.dumpStack());
				//CONSOLE.error((_f.toSource||_f.toString)());
			}
		}
	})(_f,_a);
	lf.toString=function(){
		return "Function.later:"+_f.toString();
	};
	return setTimeout(lf,time);
};
G.later=function later(f,time,thisobj){
	return f.later.apply(this,Array.prototype.slice.apply(arguments,3));
};

/**
 * polling function
 * @param {function} condition function
 * @param {function} call function when condition function return true
 * @param {number} timespan for polling (ms) : default 50
 */
Function.prototype.poll=function poll(checkfunc,interval,thisObj){
	interval=(interval==undefined)?50:interval;
	if(checkfunc()){this();}
	else{
		var _f=this, _a=Array.apply(null,arguments);
		setTimeout(function(){
			/*
			try{
				_f.poll.apply(_f,_a);
			}catch(ex){
				CONSOLE&&CONSOLE.error("base.js:Function.poll:"+G.dump(ex));
			}
			*/
			_f.poll.apply(_f,_a);
		},interval);
	}
};
G.poll=function(c,f,t){f.poll(c,t);};

/**
 * func orgfunc(arg1,arg2)
 * func hook(orgf,arg1,arg2){ some process ... orgf(arg1,arg2)... some process }
 * orgfunc.hook(hookfunc)(arg1,arg2)
 * 
 * @param {Object} func1
 * @param {Object} func2
 */
Function.prototype.hook=function(hookf,thisObj){
	var _f=this; // function
	return function hooked(){
		var _a=Array.apply(null,arguments); _a.unshift(_f);
		return hookf.apply(thisObj||this,_a);
	}
};

Function.prototype.chain=function(chainf,thisObj){
	var _f=this; // function;
	return function chained(){
		var _a=Array.apply(null,arguments);
		_a.unshift(_f.apply(thisObj||this,arguments));
		return chainf.apply(thisObj||this,_a);
	}
}

/**
 * (function(a,b,c){ ... }).defaults(1,2,3);
 */
Function.prototype.defaults = function(){
	//var def=[]; for (var i=0; i<arguments.length; i++) { def[i]=arguments[i]; }
	var def=Array.apply(null,arguments);
	return (function(_d,_f){return function(){
		var _a=[]; for (var i=0; i<_d.length; i++) {_a[i]=(arguments[i]===undefined)?_d[i]:arguments[i];}
		_f.apply(this,_a);
	};})(def,this);
};

/**
 * var seq=new G.Seq();
 * seq.add(function(){...});
 *   :
 * seq.start();
 * 
 * var seq=new G.Seq();
 * var f1=seq.add(function(arg){...},false);
 * var f2=seq.add(function(arg){...},false);
 *   :
 * seq.start();
 * f2.enable(arg);
 * f1.enable(arg);
 * 
 */
function Seq(interval){
	this._seq=[];
	this._interval=interval||10;
	this._stat="init";
}
Seq.prototype.add=function(addfunc,autostart){
	autostart=(autostart===undefined)?true:autostart;
	if(!addfunc){return;}
	addfunc._seq=this;
	addfunc._enabled=autostart;
	addfunc.enable=function(){
		this._enabled=true;
		this._enabledargs=arguments;
	};
	this._seq.push(addfunc);
	if(autostart&&!this._timer){
		this.start();
	}
	return addfunc;
};
/*
 * 待ってるseqfuncがenable済みだったら実行。さらに次も同様にチェーン。
 * seqがtrueを返したらabort?
 */
Seq.prototype.next=function(){
	if(this._seq.length==0){
		clearInterval(this._timer);
		this._timer=null;
		this._oncomp&&this._oncomp();
		this._stat="complete";
		return;
	}
	if(this._seq[0]._enabled){
		var r,f=this._seq.shift();
		if(f._enabledargs){
			r=f.apply(this,f._enabledargs);}
		else{
			//r=f(this);
			r=f.call(this,this);
		}
		if(r){this.abort();}
	}
};
Seq.prototype.start=function(oncomp){
	this._oncomp=oncomp;
	this._stat="running";
	this._timer=setInterval(
		this.next.bindThis(this),
		this._interval
	);
};
Seq.prototype.pause=function(ms){
	this._stat="pausing";
	this._seq[0]._enabled=false;
	ms=(ms==undefined)?-1:ms;
	if(ms>=0){
		(function(){this.resume();}).later(ms,this);
	}
};
Seq.prototype.resume=function(){
	this._stat="running";
	this._seq[0]._enabled=true;
};
Seq.prototype.abort=function(){
	this._stat="aborted";
	clearTimeout(this._timer);
	this._timer=null;
	this._seq=[];
};

G.Seq=Seq;


/**
 * escapes.
 * @param {string} str target
 * @param {string} type optional: "H":HTML chars, "J":javascript string (default:"H")
 */
function esc(str,type){
	type=type||"H";
	if(type.length>1){
		var ret=""
		for(var i=0;i<type.length;i++){
			ret=G.esc(str,type[i]);
		}
		return ret;
	}
	var STR2="string";
	str=new String((str===undefined||str===null)?"":str);
	var r,p;
	/*
	for (p in G.esc[type]){
		r=G.esc[type][p];
		if(typeof r[0]==STR2){str=str.split(r[0]).join(r[1]);}
		else{str=r[0](str);}
	}
	*/
	G.each(G.esc[type],function(r){
		if(typeof r[0]==STR2){str=str.split(r[0]).join(r[1]);}
		else{str=r[0](str);}
	});
	/*
	G.each(G.esc[type],function(r){
		if (typeof r[0] == STR2){str=str.split(r[0]).join(r[1]);} else {str=r[0](str);}
	});
	*/
	
	return str;
};
esc._unescentities=function(s){
	var div=esc._unescentities.div;
	if(!div){
		esc._unescentities.div=div=document.createElement("div");
	}
	return s.replace(/&[^;]+;/g,function(a){
		div.innerHTML=a;
		return div.textContent||div.innerText;
	});
};
// HTML (and more...)
esc.H=[["&","&amp;"],["<","&lt;"],[">","&gt;"],
	[function(s){return s;}, 
	 esc._unescentities]];
	 /*
	 function(s){return s.replace(/&#x([0-9a-fA-F]+);/g,function(a,b){String.fromCharCode(parseInt(b,16));})
	 					 .replace(/&#([0-9]+);/g, function(a,b){String.fromCharCode(parseInt(b,10));});}] ];
	*/
// JS String
esc.J=[["\\","\\\\"],["\f","\\f"],["\n","\\n"],["\v","\\v"],["\t","\\t"],["\r","\\r"],["\"","\\\""],["\'","\\\'"]];
// XML
esc.X=[["&","&amp;"],["<","&lt;"],[">","&gt;"],["\"","&quot;"],["'","&apos;"], /* XML */
			[function(s){return s;},
			 esc._unescentities]];
			 /*
			 function(s){return s.replace(/&#x([0-9a-fA-F]+);/g, function(a,b){String.fromCharCode(parseInt(b,16));})
								 .replace(/&#([0-9]+);/g, function(a,b){String.fromCharCode(parseInt(b,10));});}] ]; 
			*/
esc.A=esc.X;
esc.A=[["&","&amp;"],["<","&lt;"],[">","&gt;"],["\"","&quot;"],["'","&apos;"], /* XML */
		["\r","&#xD;"],["\n","&#xA;"],[" ","&#32;"],["\t","&#9;"],
			[function(s){return s;},
			 esc._unescentities]];
			 /*
			 function(s){return s.replace(/&#x([0-9a-fA-F]+);/g, function(a,b){String.fromCharCode(parseInt(b,16));})
								 .replace(/&#([0-9]+);/g, function(a,b){String.fromCharCode(parseInt(b,10));});}] ]; 
			*/
// URI enc/dec
//G.esc.U=[[" ","+"],[function(s){return encodeURIComponent(s);},function(s){return decodeURIComponent(s);}]];
esc.U=[[function(s){return encodeURIComponent(s).replace(/-/g,"%2D");},function(s){return decodeURIComponent(s);}]];
// RegExp
esc.R=[["$","\\$"],["{","\\{"],["}","//}"],["[","\\["],["]","\\]"],["(","\\("],[")","\\)"],[".","\\."],["*","\\*"],["+","\\+"],["?","\\?"]];

function unesc(str,type){
	var STR="string";
	G.each(G.esc[type||"H"],function(r){
		if (typeof r[1] == STR){str=(str||"").split(r[1]).join(r[0]);} else {str=r[1](str||"");}
		if(r[1]===esc._unescentities){return true;}
	}); return str;
}

G.esc=esc;
G.unesc=unesc;

function atoi(str,isNaNValue){isNaNValue=(isNaNValue===undefined)?NaN:isNaNValue;var r=parseInt(str,10); return isNaN(r)?(CONSOLE.warn("G.atoi:isNaN:\""+str+"\"")||isNaNValue):r;};
function atof(str,isNaNValue){isNaNValue=(isNaNValue===undefined)?NaN:isNaNValue;var r=parseFloat(str,10);return isNaN(r)?(CONSOLE.warn("G.atof:isNaN:\""+str+"\"")||isNaNValue):r;};
G.atoi=atoi;
G.atof=atof;

String.prototype.toInt = function(isNaNValue){return atoi(this,isNaNValue);};
String.prototype.toFloat = function(isNaNValue){return atof(this,isNaNValue);};
String.prototype.esc = function(t){return G.esc(this,t);};
String.prototype.unesc = function(t){return G.unesc(this,t);};

function pad(a,l,s){var r=((s!==undefined?s:"0000")+a); return r.substring(r.length-l,r.length);}

function strftime(f,d){var r=f; 
	for(var i=0;i<strftime._fmt.length;i++){
		var v=strftime._fmt[i];
		r=r.split(strftime._fmt[i][0]).join((strftime._fmt[i][1])(d));
	} return r;
}

strftime._fmt=[
	["%%",function(d){return "\u0001"}],
	["%n",function(d){return "\n"}],
	["%t",function(d){return "\t"}],
	["%F",function(d){ /* %Y-%m-%d */ return "%Y-%m-%d";}],
	["%r",function(d){ /* %I:%M:%S %p' */ return "%I:%M:%S %p";}],
	["%R",function(d){ /* %H:%M */ return "%H:%M";}],
	["%T",function(d){ /* %H:%M:%S */ return "%H:%M:%S";}],
	["%C",function(d){ /* YY */ return pad(d.getFullYear(),4).substring(0,2);}],
	["%G",function(d){ /* 0 padded YYYY ? (ISO8601) */ return pad(d.getYear(),4);}],
	["%g",function(d){ /* 0 padded YY ? (ISO8601) */ return pad(d.getYear(),4);}],
	["%y",function(d){ /* YY 00-99 */ return pad(d.getFullYear(),4).substring(2,4);}],
	["%Y",function(d){ /* YYYY 0000-?*/ return pad(d.getFullYear(),4);}],
	["%m",function(d){ /* 0 padded month 00-12 */ return pad(d.getMonth()+1,2);}],
	//["%b",function(d){ /* short month string with locale */ }],
	//["%h",function(d){ /* equal %b */ }],
	//["%B",function(d){ /* long month string with locale */ }],
	["%d",function(d){ /* 0 padded day of month */ return pad(d.getDate(),2);}],
	["%e",function(d){ /* space padded day of month */ return pad(d.getDate(),2," ");}],
	//["%a",function(d){ /* short day of week string with locale */ }],
	//["%A",function(d){ /* long day of week string with locale */ }],
	["%u",function(d){ /* number of day of week 1-7. Monday=1 */ var w=d.getDay(); return (w==0?7:w);}],
	["%w",function(d){ /* number of day of week 0-6. Sunday=0 */ return d.getDay();}],
	["%x",function(d){ /* yyyymmdd with locale */ return d.toLocaleDateString();}],
	["%H",function(d){ /* 0 padded hour 00-23 */ return pad(d.getHours(),2);}],
	["%I",function(d){ /* 0 padded hour 00-11 */ return pad(d.getHours()%12,2);}],
	["%p",function(d){ /* AM,PM with locale */ return ["AM","PM"][Math.floor(d.getHours()/12)];}],
	["%P",function(d){ /* am,pm with locale */ return ["am","pm"][Math.floor(d.getHours()/12)];}],
	["%M",function(d){ /* 0 padded minutes 00-59 */ return pad(d.getMinutes(),2);}],
	["%S",function(d){ /* 0 padded second 00-59*/ return pad(d.getSeconds(),2);}],
	["%c",function(d){ /* date,time with locale */ return d.toLocaleDateString()+" "+d.toLocaleTimeString();}],
	["%X",function(d){ /* hhmmss with locale */ return d.toLocaleTimeString();}],
	//["%j",function(d){ /* 0 padded day of year 000-366 */ }],
	//["%U",function(d){ /* number of week of year 00-53 (1 is first Sunday-Saturday ) */}],
	//["%V",function(d){ /* number of weeks of year 00-53 (1 is first Monday-Sunday have over 4 days ) ISO8601 */ }],
	["%W",function(d){ /* number of week of year 00-53 (1 is forst Monday-Sunday) */}],
	["%z",function(d){ /* timezone offset hour */ var r=d.getTimezoneOffset()/60; return (r<0?"-":"+")+r;}],
	//["%Z",function(d){ /* timezone str */ }],
	["%s",function(d){ /* unix time sec */ return d.valueOf();}],
	["\u0001",function(d){return "%"}]
];
G.strftime=strftime;

Date.prototype.format=function(f){return strftime(f,this);}

/********************* cookie ***************************/

function getCookies(){
	var r={};
	G.each(doc.cookie.split(";"),function(v){
		var a=v.split("=");r[a.shift().replace(/^\s*/,"")]=a.join(",");
	});
	return r;
}
G.getCookies=getCookies;

function getCookie(n){ return getCookies()[n]; }
G.getCookie=getCookie;

/**
 * 
 * @param {string} n name
 * @param {string} v value
 * @param {number} t life time (days), negative for clear;
 */
function setCookie(n,v,t,dom,path,secureonly){
	t=(t===undefined)?30:t;
	dom=(dom===undefined)?location.hostname:dom;
	path=(path===undefined)?location.pathname.replace(/[^\/]*$/,""):path;
	secureonly=secureonly?";secure":""
	var d; if (t<0){d=new Date(0);} else{ d=new Date();d.setTime(d.getTime() + 24*60*60*1000*t); }
	doc.cookie=n+"="+v+";expires="+d.toGMTString()+";domain="+dom+";path="+path+secureonly;
}
G.setCookie=setCookie;

function clearCookie(n,dom,path){setCookie(n,"",-1,dom,path);}
G.clearCookie=clearCookie;


/********************* Cache *************************/
function Cache(defaultTimeoutSec,gcIntervalSec) {
	defaultTimeoutSec=(defaultTimeoutSec === undefined)?-1:defaultTimeoutSec;
	gcIntervalSec=(gcIntervalSec===undefined)?10*60:gcIntervalSec;
	this._pool = {};
	this.timeout = defaultTimeoutSec;
	this._GCInterval = setInterval((function() { // 10分ごとにGCする
		this._GC();
	}).bindThis(this),gcIntervalSec*1000);
};
Cache.disable = false;

Cache.prototype.set = function(key, obj, timeoutSec) {

	if (Cache.disable || timeoutSec === 0) { return; }

	var timeout = this.timeout;
	if (timeoutSec !== undefined) {
		if (timeoutSec < 0) {
			timeout = -1;
		} else {
			timeout = timeoutSec;
		}
	}
	timeout = new Date((new Date()).valueOf() + (timeout * 1000));
	this._pool[key] = {timeout:timeout, obj:obj};
};

Cache.prototype.get = function(key, getfunc) {
	if (Cache.disable) { return; }
	var cached = this._pool[key],ret;
	if (cached) {
		if (cached.timeout != -1 && new Date() > cached.timeout ) {
			this._pool[key] = undefined;
			delete(this._pool[key]);
		} else {
			ret = cached.obj;
		}
	} else {
		if (getfunc) {
			var ret = getfunc();
			this.set(key, ret);
		}
	}
	return ret;
};

Cache.prototype.clear = function () {
	this._pool = {};
};

Cache.prototype._GC = function () {
	for (var key in this._pool) {
		var cached = this._pool[key];
		if (cached.timeout != -1 && new Date() > cached.timeout ) {
			this._pool[key] = undefined;
			delete(this._pool[key]);
		}
	}
};

G.Cache=Cache;

// TODO:キャッシュサイズの最大値?


/********************* DOM ***************************/

/**
 * getElementsById (with cache)
 */
//function G.$(e){return $[e]||($[e]=(doc.getElementById(e)||null));};
//function G.$(e){return $[e]||($[e]=(doc.getElementById(e)||e||{}));};
//function $(e,f){return !f&&$[e]||($[e]=(doc.getElementById(e)||{}));};
function $(e,f){
	var r;
	if(f){
		r=doc.getElementById(e);
	}else if($[e]){
		r=$[e]; 
	}else{
		r=doc.getElementById(e);
	}
	$[e]=r;
	return r;
};
if(!window.$){window.$=$;}
G.$=$;

/**
 * getElementsBy some conditinos. (alias G.$C(cond, e))
 * @param {object} cond conditions for find.
 * cond = {
 *   t:"tagname lowercase or regex"
 *   i:"id str or regex",
 *   n:"name str or regex",
 *   c:"className str or regex",
 *   f:function(elem) { return true or false; },
 *   d:maxdepth, 0:only children of e
 * }
 * @param {htmlElement} optional: top element (default:doc.body)
 * @return {array of htmlElement} results
 */
function getElementsBy(cond, e, d) {
	var r=[]; e=e||doc.body; d=(d===undefined?0:d); 
	function m(s,p) {if (!s) {return false;} else {return (!(p instanceof RegExp)?(s==p):s.match(p));}}
	for (var c=e.firstChild;c;c=c.nextSibling) {
		if (c&&c.tagName
			&&((!("i" in cond))||m(c.id,cond.i))
			&&((!("t" in cond))||m(c.tagName.toLowerCase(),cond.t))
			&&((!("n" in cond))||m(c.name||c.getAttribute("name"),cond.n))
			&&((!("c" in cond))||G.isClass(c,cond.c))
			&&((!("f" in cond))||(cond.f)(c))){
			r.push(c);
		}
		if (c.firstChild) {r=r.concat(G.getElementsBy(cond,c,d+1));}
	} return r;
};
G.getElementsBy=getElementsBy; 
if (!window.$C) {window.$C = getElementsBy;}
G.$C=getElementsBy;



/**
 * search htmlelements match with selector
 * @param {string} s CSS selector like expression
 * @param {HtmlElement} c top element for search
 * @return {[HtmlElement]} found elements array (include c / no elements = [])
 */
function getElementsBySelector(s,c){
	var s=s.split(","),r=[],c=c||document;
	if (! (c instanceof Array)) { c=[c]; }
	if (s.length>1){ while(s[0]){r=r.concat(getElementsBySelector(s[0],c));s.shift();} return r; }
	var t=s[0].split(/\s+/);
	while(t.length!=0){
		var ct=t.shift(), m=ct.match(/([a-zA-Z0-9]+)?(#([-_a-zA-Z0-9]+))?((\.[-_a-zA-Z0-9]+)+)?/);
		if (m==null){throw("getElementsBySelector():\""+ct+"\" is not valid selector");}
		var tg=m[1],id=m[3],cs=m[4],fs=[],fs2=[],fs3=[],tg=tg||"*";
		G.each(c,function(ce){
				if (tg=="*"||(ce.tagName&&tg.toLowerCase()==ce.tagName.toLowerCase())) {fs[fs.length]=ce;}
				var ces=ce.getElementsByTagName(tg);
				for (var i=0,l=ces.length;i<l;i++) {fs[fs.length]=ces[i];}
		});
		if (id) { G.each(fs,function(e){ if (e.id==id) { fs2.push(e); return true;} }); } else { fs2=fs; }
		if (cs) { cs=cs.split("."); cs.shift(); G.each(fs2, function(e){ if(G.isClass(e,cs)){ fs3.push(e);}});}
		else { fs3=fs2; }
		c=fs3;
	}
	return fs3;
}
G.getElementsBySelector=getElementsBySelector;
if (!window.$S) {window.$S = getElementsBySelector;}
G.$S=getElementsBySelector;

/**
 * G.findAncestor some conditinos.
 * @param {htmlElement} target element
 * @param {object} cond conditions for find.
 * cond = {
 *   e:htmlElement,
 *   i:"id str or regex", n:"name str or regex",
 *   t:"tagname", c:"className str or regex",
 *   f:function(elem) { return true or false; },
 *   d:maxdepth, 0:only children for e
 * }
 * @return {htmlElement} result element or undefined;
 */
function findAncestor(e, cond){
	if (!e) {return;}
	function m(s,p) {if (!s) {return false;} else {return (!(p instanceof RegExp)?(s==p):s.match(p));}}
	for (var c=e.parentNode;c;c=c.parentNode) {
		if ("e" in cond){if(cond.e==c){return cond.e}}
		else if (c
			&&((!("i" in cond))||m(c.id,cond.i))
			&&((!("t" in cond))||m(c.tagName,cond.t))
			&&((!("n" in cond))||m(c.name||c.getAttribute("name"),cond.n))
			&&((!("c" in cond))||G.isClass(c,cond.c))
			&&((!("f" in cond))||(cond.f)(c))){
			return c;
		}
	} return;
};
G.findAncestor=findAncestor;

function findAncestorBySelector(e,s){
	function matchSelector(e,selector){
		var s=selector.replace(/^\s*/,"").replace(/\s*$/,""),ret=false,cr=true;
		if(s.indexOf(",")>=0){
			var ret=false;
			G.each(s.split(","),function(v){
				ret=matchSelector(e,v.replace(/^\s*/,"").replace(/\s*$/,""));
				if(ret){return true;}
			});
			return ret;
		}
		var m=s.match(/^([^#\.]+)?(#([^.]+))?(\..*)?$/); // 1:tagname, 3:id, 4:classnames
		if(m[4]){
			var cns=m[4].split("."); cns.shift();
			while(cns[0]){cr=G.isClass(e,cns.shift())&&cr;}
		}
		var ret=cr;
		if(m[1]){ret=ret&&m[1]==e.tagName.toLowerCase();}
		if(m[3]){ret=ret&&m[3]&&e.id==m[3];}
		return ret;
	}
	var te=e.parentNode;
	while(te&&te.tagName){
		if(matchSelector(te,s)){
			break;
		}
		te=te.parentNode;
	}
	if(!te||!te.tagName){return;}
	return te;
}
G.findAncestorBySelector=findAncestorBySelector;
G.$SA=findAncestorBySelector;

/**
 * remove element and $() cache
 * @param {htmlElement} e target element
 */
function removeElement(e) {
	if(!e){return;}
	if(e.id){delete $[e.id];}
	G.each(addEvent._list,function(e,i){if (e.e==e) { G.removeEvent(i); }});
	if(e&&e.parentNode){e.parentNode.removeChild(e);e=null;}
};
G.removeElement=removeElement;

/**
 * get htmlElement XPath expression /ELEM[num]/ELEM[num]/.../ELEM[@id='ID'].
 * element node only.
 * @param {htmlElement} e target element
 * @param {htmlElement} re optional: root element (default:html)
 * @param {array} a attributes array
 */
function getXPath(e,re,at){
	re=(re)?re:doc.getElementsByTagName("html")[0];
	at=(at===undefined)?["id","class"]:((typeof at == "string")?[at]:at);
	var r=[],a; for(var c = e;c;c=c.parentNode){
		a="";
		switch (c.nodeType) {
			case 1: case c.ELEMENT_NODE:
				if(c.parentNode){
					for(var b=c.parentNode.firstChild,d=0;b;b=b.nextSibling){
						if(b.tagName==c.tagName){d++;} if(b==c){var f=d;}
					}
					a="["+f+"]";
				}
				G.each(at,function(p,i){
					var av;
					if(p=="class"){
						av=c.className; //for IE
					}else{
						av=c[p]||c.getAttribute(p);
					}
					if(av!==null&&av!==undefined&&av!==""){
						a=a+"[@"+p+"=\""+av+"\"]";
					}
				});
				r.unshift(c.tagName.toLowerCase()+a);
				break;
			case 2: case c.ATTRIBUTE_NODE: r.unshift("#attr"); break;
			case 3: case c.TEXT_NODE: r.unshift("#text"); break;
			case 4: case c.CDATA_SECTION: r.unshift("#cdata-section"); break;
			case 5: case c.ENTITY_REFERENCE_NODE: r.unshift("#entity-ref"); break;
			case 6: case c.ENTITY_NODE: r.unshift("#entity"); break;
			case 7: case c.PROCESSING_INSTRUCTION_NODE: r.unshift("#proc"); break;
			case 8: case c.COMMENT_NODE: r.unshift("#comment"); break;
			case 9: case c.DOCUMENT_MODE: r.unshift("#document"); break;
			case 10: case c.DOCUMENT_TYPE_NODE: r.unshift("#doctype"); break;
			case 11: case c.DOCUMENT_FRAGMENT_NODE: r.unshift("#documentflagment"); break;
			case 12: case c.NOTATION_NODE: r.unshift("#note"); break;
		}
		if (c.parentNode==re) {break;}
	} return /*"/"+*/r.join("/");
};
G.getXPath=getXPath;

function getSelectorPath(e){
	return G.getXPath(e,["id","class"]).split("/").join(" > ")
		.replace(/\[\d\]/g,"").replace(/\[@id="([^"]*)"\]/g,"#$1")
		.replace(/\[@class="([^"]*)"\]/g,function(a,b){return "."+b.replace(/\s+/g," ").split(" ").join(".");})
}
G.getSelectorPath=getSelectorPath;

function getXhtml(e){
	var e=e||document,tn="",haschild=false,r="";
	switch(e.nodeType){
		case 1: case e.ELEMENT_NODE:
			tn=e.tagName.toLowerCase();
			//if(tn=="br"&&e.className=="khtml-block-placeholder"){continue;}
			var atrs=e.attributes,ar=[],an="",av="";
			for (var i=0,l=atrs.length;i<l;i++){
				an=atrs[i].nodeName.toLowerCase();av=null;
				if(!atrs[i].specified
					&&(an!="selected"||!e.selected)&&(an!="checked"||!e.checked)
					&&(an!="style"||e.style.cssText=="")&&an!="value"){continue;}
				if(an=="_moz_dirty"||tn=="br"&&an=="type"&&e.getAttribute("type")=="_moz"){continue;}
				if(tn=="br"&&an=="class"&&e.className=="khtml-block-placeholder"){continue;}
				switch(an){
					case "style": av=e.style.cssText; break;
					case "class": av=e.className; break;
					case "http-equiv": av=e.httpEquiev; break;
					case "noshade":case "checked":case "selected":case "multiple": case "nowrap": case "disabled": av=an; break;
					case "src":
						av=e.getAttribute("src");
						if(av&&!av.match(/^https?:/)){
							av=(e.ownerDocument||e.document).location.href.replace(/[^\/]*$/,"")+av; break;
						}
						av=av.replace(/^https:/,"http:");
						break;
					case "href":
						av=e.getAttribute("href");
						if(av&&!av.match(/^https?:/)){
							av=(e.ownerDocument||e.document).location.href.replace(/[^\/]*$/,"").replace(/^https:/,"http:")+av; break;
						}
						av=av.replace(/^https:/,"http:");
						break;
					default: try{av=e.getAttribute(an);}catch(ex){CONSOLE.error("G.getXHtml:getAttribute("+an+"):"+dump(ex));}; break;
				}
				ar.push(an+"=\""+esc(av,"X")+"\"");
			}
			for(var cs=[],c=e.firstChild;c;c=c.nextSibling){ cs.push(getXhtml(c)); }
			r="<"+tn+(ar.length==0?"":(" "+ar.join(" ")+" "))+(cs.length=="0"?" />":">"+cs.join("")+"</"+tn+">");
			break;
		case 3: case e.TEXT_NODE: r=esc(e.nodeValue,"X"); break;
		case 4: case e.CDATA_SECTION: r="<![CDATA["+e.nodeValue+"]]>"; break;
		case 8: case e.COMMENT_NODE: r="<!-- "+e.nodeValue+" -->"; break;
		default: break;
	}
	return r;
};
G.getXhtml=getXhtml;

/**
 * set object properties to value of named elements.
 * ex) obj.name1="aaa" to <input name="name1" value="aaa"/> 
 * obj.name2=true to <input name="name2" type="checkbox" checked/>
 * obj.name3="aaa<br/>bbb" to <span name="name3">aaa&lt;br/&gt;</span>
 * obj.name4="aaa<br/>bbb" to <span name="name4" class="noesc">aaa<br/></span>
 * obj.name5=12345 to <span name="name5" class="nc3">12,345</span>
 * @param {htmlElement} e top element
 * @param {Object} o value object. {<name>:<value>,....} or {<name>:{_value:<value>,@<attrname>:<attrvalue>,...},...}
 * @param {boolean} f optional: if true, set "" for undefined properties
 */
function setElementValues(e,o,f){
	f=(f===undefined?false:f);
	var so={};
	function SEVObj(v){
		if(v===null){v="";}
		G.each([String,Number,Boolean,Function,Array,Date,RegExp],function(c){
			if(v instanceof c){v=v.toString();return true;}
		});
		switch(typeof v){
			case "string": case "number": case "boolean":
				this._value=v; break;
			default:
				if(v===null){this._value="";}
				else{
					G.each(v,function(v,p){
						this[p]=v;
					},this);
				}
		}
	}
	SEVObj.prototype.toString=function(){return this._value;};
	G.each(o,function(v,p){
		if(v&&v.push){
			var i,l;
			so[p]=[];
			for(i=0,l=v.length;i<l;i++){
				so[p][i]=new SEVObj(v[i]);
			}
		}else{
			so[p]=new SEVObj(v);
		}
	});
	o=so;
	function c(a,v){
		if(a.push){
			for(var i=0;i<a.length;i++){if(a[i]._value==v){return true;}}
			return false;
		}else{return a._value==v;}
	}
	G.$C({n:/^\S+$/,f:function(e){
		var n=e.name||e.getAttribute("name"),v=o[n];
		if(v===undefined||v===null){if(f){v="";}else{return;}}
		switch(e.tagName.toUpperCase()){
			case "SELECT":
				G.each(e.options,function(op){if(v._value!==null&&v._value!==undefined&&c(v,op.value)){op.selected="selected";}else{op.selected=false;}}); break;
			case "INPUT":
				if(e.type=="checkbox"||e.type=="radio"){
					if(c(v,e.value)){
						e.checked=true;
					}else{
						e.checked=false;
					}
				break;}
			case "TEXTAREA": // or INPUT type!=(button|checkbox|radio)
				if(!v.push){
					G.each(v,function(v,p){
						if(p.indexOf("@")==0){
							var cn=p.replace(/^@/,"");
							switch(cn){
								case "class":
									e.className=v; break;
								case "style":
									e.style.cssText=v; break;
								default:
									e.setAttribute(p.replace(/^@/,""),v);
							}
						}
					});
				}
				if(v._value===undefined){break;}
				e.value=v._value;
				break;
			default:
				G.each(v,function(v,p){
					if(p.indexOf("@")==0){
						var cn=p.replace(/^@/,"");
						switch(cn){
							case "class":
								e.className=v; break;
							case "style":
								e.style.cssText=v; break;
							default:
								e.setAttribute(p.replace(/^@/,""),v);
						}
					}
				});
				if(v._value===undefined){break;}
				if(G.isClass(e,"noesc")){
					e.innerHTML=v._value;
				}else if(G.isClass(e,"nc3")){ // 正の整数3カンマ
					e.innerHTML=G.esc((""+v._value).split("").reverse().join("").replace(/(\d\d\d)/g,"$1,").split("").reverse("").join("").replace(/^([+-])?,/,"$1"));
				}else{
					e.innerHTML=G.esc(v._value);
				}
		}
	}},e);
};
G.setElementValues=setElementValues;

/**
 * get values of form elements
 * @param {htmlElement} e top element
 * @param {object} optional: base values object
 * @param {boolean} optional: true then "" as undefined
 * @return {object} {name1:<value>, name2:[<value1>,<value2>,...]...} in top element children
 */
function getElementValues(e,o,f){
	o=(o===undefined)?{}:o;f=(f===undefined)?false:true;
	function a(o,p,v){if(o[p]===undefined){o[p]=v;}else if(!o[p].push){o[p]=[o[p],v];}else{o[p].push(v);}}
	G.$C({n:/^\S+$/,t:/^(input|select|textarea)$/i,f:function(e){
		if(e.type=="button"||e.type=="submit"||e.type=="reset"){return;}
		var n=e.name||e.getAttribute("name"),v=e.value;
		if(f&&v==""){}else{
			if(e.tagName.toLowerCase()=="select"){G.each(e.options,function(op){if(op.selected){a(o,n,op.value);}})}
			else if(e.type=="radio"||e.type=="checkbox"){if(e.checked){a(o,n,v);}}
			else{a(o,n,v);}
		}
	}},e);
	return o;
};
G.getElementValues=getElementValues;

/**
 * <pelem>
 *  <somelem>....</somelem><somelem>....</somelem><somelem>....</somelem>
 *  <tmplelem class="tmplate">.${value}..</tmplelem>
 *  <tmplelem class="tmplate">..${__cnt}.</tmplelem>
 *  <tmplelem class="tmplate">..$A{attrescv}..$H{htmlescv}..$J{jsescv}..</tmplelem>
 *  <notfoundelem class="for-template-notfound">...</notfoundelem>
 *  <busyfoundelem class="for-template-processing">...</busyelem>
 *  <busyfoundelem class="for-template-abort">...</busyelem>
 *  <somelem>....</somelem><somelem>....</somelem><somelem>....</somelem>
 * </pelem>
 * 
 * var a = new HtmlElementTemplater(<pelem>,{tmpl:"tmplate",gened:"template-gen",notfound:"template-notfound",processsing:"template-processing",vh:"$");
 * a.start();
 * G.each(a,function(o){a.insertApplied(o)})
 * a.complete();
 * 
 * NOTICE:<table> cannot be pelem. use <tbody>.
 * NOTICE:<a __href="${AAA}" ...> -> <a href="${AAA}">
 * NOTICE:<img __src="${AAA}" ...> -> <img __src="${AAA}">
 * 
 * @param {HtmlElement} e
 * @param {object} {tmpl:<tmplclass>,gened:<genedclass>,notfound:<notfoundclass>,processing:<processingclass>,error:<errorclass>,vh:<tmplvaluehead>}
 */
function HtmlElementTemplater(e,tmplclass,genedclass,notfoundclass,processingclass,abortclass){

	this.params={
		tmpl:"template",
		gened:"template-gen",
		notfound:"template-notfound",
		processing:"template-processing",
		abort:"template-abort",
		vh:"$"
	};
	if(!HtmlElementTemplater._s){
		HtmlElementTemplater._s=G.setStyleSheet(
			G.tmpl(
				".${tmpl}, .for-${notfound}, .for-${processing}, .for-${abort} {display:none;} "+
				".${processing} .for-${processing} { display:block; } "+
				".${notfound} .for-${notfound} { display:block; } "+
				".${abort} .for-${abort} { display:block; } "
				,this.params
			)
		);
	}

	if(tmplclass && typeof tmplclass == "object"){
		G.each(tmplclass,function(v,p){
			this.params[p]=v;
		},this);
	}else{
		this.params.tmpl=(tmplclass===undefined)?"template":tmplclass;
		this.params.gened=(genedclass===undefined)?"template-gen":genedclass;
		this.params.notfound=(notfoundclass===undefined)?"template-notfound":notfoundclass;
		this.params.processing=(processingclass===undefined)?"template-processing":processingclass;
		this.params.abort=(abortclass===undefined)?"template-abort":abortclass;
	}

	var dummies=HtmlElementTemplater._dummies;
	if(!dummies){
		dummies=doc.createElement("div");
		dummies.style.cssText="display:none;position:absolute;width:0;height:0;top:0;left:0;font-size:0;line:height:0;";
		dummies.id="hetr-templates";
		doc.body.appendChild(dummies);
		HtmlElementTemplater._dummies=dummies;
	}
	var a=e.cloneNode(true);var t=e.cloneNode(false);var l;
	t.id="hetr-"+(t.id||HtmlElementTemplater._cnt++);
	G.each(G.$S("."+this.params.tmpl,a),function(e){
		G.removeClassName(e,this.params.tmpl);
		G.addClassName(e,this.params.gened);
		t.appendChild(e);
	},this);
	this.e=e;
	this._l=(G.$S("."+this.params.tmpl,e)[0]);
	this._tmplstr=t.innerHTML.replace(/(\s+)__([a-z]+)=\"([^\"]+)\"/gim,"$1$2=\"$3\"");

	//var re=new RegExp("\\$"+"[HAJU]?\\{([^\\}]+)\\}","g"),m,ps={};
	var re=new RegExp(G.esc(this.params.vh,"R")+"[HAJU]?\\{([^\\}]+)\\}","g"),m,ps={};
	while((m=re.exec(this._tmplstr))){
		if(m==null){break;}
		ps[m[1]]=m[1];
		//console.log(m[1]);
	}
	this._tmplvals=ps;

	this._box=t;
	this._fragment=doc.createDocumentFragment();
	t.style.display="none"; dummies.appendChild(t);

	if(t.tagName.toLowerCase()=="tbody"){
		var dummy=doc.createElement("table");
		dummy.style.display="none";
		dummy.appendChild(t);
		dummies.appendChild(dummy);
		this._istable=true;
	}

	while(t.firstChild){t.removeChild(t.firstChild)}

	this.appliedCnt=0;
	this._genedElements=[];

	// compat with HtmlElementTemplaterSeq
	this.tmpl=this;
	this.seq={add:function(f){return f.apply(this,arguments);}};
	
	this.ongenerate&&this.ongenerate();
}
HtmlElementTemplater._cnt=0;
HtmlElementTemplater.prototype.start=function(f){// onbusyで中段してる場合は待たねばならない
	f=(f===undefined)?true:f;
	if(f){
		this.reset();
		this.onbusy=true;
	}
	G.addClassName(this.e,this.params.processing);
	this.onstart&&this.onstart();
};
HtmlElementTemplater.prototype.reset=function(){
	this.appliedCnt=0;
	while(this._genedElements[0]){removeElement(this._genedElements.shift());}
	G.removeClassName(this.e,this.params.notfound);
	G.removeClassName(this.e,this.params.processing);
	G.removeClassName(this.e,this.params.abort);
};

HtmlElementTemplater.prototype.insertApplied=function(v,tmpv){

	var ob=window.offscreenBuffering;window.offscreenBuffering=true;

	//var o=G.clone(v),p;
	var o=(function clone(a){function Cloned(){};Cloned.prototype=a;return new Cloned();})(v),p;
	o.__cnt=this.appliedCnt;
	if(tmpv!==undefined){
		for (p in tmpv){ o[p]=tmpv[p]; }
	}

	var vh=this.params.vh,a=this._tmplstr;
	var rx=this._rx||new RegExp(G.esc(vh,"R")+"([HAJU]*)\\{([^}]+)\\}","g");
	this._rx=rx;
	a=a.replace(rx,function(all,esc,param){
		var v=o[param]; v=(v===undefined)?"":v;
		if(esc==""){ return v; } else return G.esc(v,esc);
	});

	var t=this._box;
	if(G.isMSIE&&this._istable){
		var div=document.createElement("div");
		div.innerHTML="<table><tbody>"+a+"</tbody></table>";
		t.appendChild(div.getElementsByTagName("tr")[0]);
		div=null;
	}else{
		t.innerHTML=a;
	}

	var r=this._fragment;//doc.createDocumentFragment();
	while(t.firstChild){this._genedElements.push(t.firstChild);r.appendChild(t.firstChild);}
	this._l.parentNode.insertBefore(r,this._l);

	window.offscreenBuffering=ob;

	this.appliedCnt++;
};
HtmlElementTemplater.prototype.apply=HtmlElementTemplater.prototype.insertApplied;
HtmlElementTemplater.prototype.complete=function(oncomplete){
	if(this.appliedCnt==0){G.addClassName(this.e,this.params.notfound);}
	G.removeClassName(this.e,this.params.processing);
	this.onbusy=false;

	// compat with HtmlElementTemplaterSeq
	this.oncomplete&&this.oncomplete();
	oncomplete&&oncomplete();
};
HtmlElementTemplater.prototype.remove=function(){
	removeElement(this.t); this.t=null;
};
// compat with HtmlElementTemplaterSeq
HtmlElementTemplater.prototype.abort=function(f){
	G.removeClassName(this.e,this.params.processing);
	G.addClassName(this.e,this.params.abort);
	f&&f(this);
	this.onbusy=false;
	//this.complete();
};
G.HtmlElementTemplater=HtmlElementTemplater;

function HtmlElementTemplaterSeq(e,tmplclass,genedclass,notfoundclass,processingclass,seq){
	if(seq===undefined){seq=new G.Seq();}
	this.seq=seq;
	this.tmpl=new HtmlElementTemplater(e,tmplclass,genedclass,notfoundclass,processingclass);
	this.e=this.tmpl.e;
}
HtmlElementTemplaterSeq.prototype.start=function(f){
	this.seq.add((function(f){this.tmpl.start(f);}).bindThis(this).bindArgs(f));
};
HtmlElementTemplaterSeq.prototype.apply=function(v){
	this.seq.add((function(v){this.tmpl.apply(v);}).bindThis(this).bindArgs(v));
};
HtmlElementTemplaterSeq.prototype.complete=function(oncomplete){
	this.seq.add((function(oncomp){
		this.tmpl.complete();
		this.oncomplete&&this.oncomplete();
		oncomp&&oncomp();
	}).bindThis(this).bindArgs(oncomplete));
};
HtmlElementTemplaterSeq.prototype.abort=function(f){
	this.seq.abort();
	this.tmpl.abort(f);
};
G.HtmlElementTemplaterSeq=HtmlElementTemplaterSeq;


/******************** pos / size **********************/

var dedb=doc.documentElement||doc.body; // IE doc...size

// G.body = function body() {return doc.compatMode=="CSS1Compat"?doc.documentElement:doc.body;}

/**
 * get element page position (origin:body content) and border-box size in px
 * @param {htmlElement} e target Element
 * @param {boolean} f optional: calc content w/h (.cw, .ch) (default:false)
 * @return {object} ret.{left,top,width,height}
 */

var _getpos = _gotpos;
function _gotpos(e){ // offsetWidth/Height is undefined with display:none
	try{
		var t=0, l=0, p=e, w=e.offsetWidth, h=e.offsetHeight;
		t+=p.offsetTop;
		l+=p.offsetLeft;
		p=p.offsetParent;
		while (p!=doc.body) {
			/*CONSOLE.log("pos-top+"+p.offsetTop+":"+G.getXPath(p));*/
			t+=p.offsetTop-(p.scrollTop||0);
			l+=p.offsetLeft-(p.scrollLeft||0);
			p=p.offsetParent;
		}
		return {left:l||0,top:t||0,width:w||0,height:h||0};
	}catch(ex){
		return {error:ex};
	}
};
function _getpos_gecko(e){
	try{
		var b=doc.getBoxObjectFor(e), w=b.width, h=b.height;
		//var b=(e.getBoundingClientRect?e.getBoundingClientRect():doc.getBoxObjectFor(e));
		//var w=b.width, h=b.height;
		var l=b.x-atoi(currentStyle(e,"borderLeftWidth")),t=b.y-atoi(currentStyle(e,"borderTopWidth"));
		if(currentStyle(doc.body,"position")!="static"){
			l-=atoi(currentStyle(doc.body,"marginLeft"),0)+atoi(currentStyle(doc.body,"paddingLeft"),0);
			t-=atoi(currentStyle(doc.body,"marginTop"),0)+atoi(currentStyle(doc.body,"paddingTop"),0);
		}
		var c;
		for(c=e.parentNode;c!=doc.body;c=c.parentNode){
			l-=c.scrollLeft||0;
			t-=c.scrollTop||0;
		}
		return {left:l,top:t,width:w,height:h};
	}catch(ex){
		return {error:ex};
	}
};
function _getpos_ie(e){
	try{
		var b=e.getBoundingClientRect(), w=b.right-b.left, h=b.bottom-b.top;
		//var d=doc.documentElement||doc.body;
		var l=b.left+(dedb.scrollLeft)-2, t=b.top+(dedb.scrollTop)-2;
		if(currentStyle(doc.body,"position")!="static"){
			l-=atoi(currentStyle(doc.body,"marginLeft"),0)+atoi(currentStyle(doc.body,"paddingLeft"),0);
			t-=atoi(currentStyle(doc.body,"marginTop"),0)+atoi(currentStyle(doc.body,"paddingTop"),0);
		}
		return {left:l,top:t,width:w,height:h};
	}catch(ex){
		return {error:ex};
	}
};
if (doc.getBoxObjectFor){_getpos = _getpos_gecko; CONSOLE.log("use pos gecko");}
else if (G.isMSIE) {_getpos = _getpos_ie; CONSOLE.log("use pos IE");}
else {CONSOLE.log("use pos offset*");}

function pos(e,f) { // origin=body content top-left
	var ret=_getpos(e);
	if(ret.error){return ret;}
	if (f) {
		var w=ret.width, h=ret.height;
		G.each(["borderLeftWidth","paddingLeft","paddingRight","borderRightWidth"],function(s){w-=atoi("0"+currentStyle(e,s));});
		G.each(["borderTopWidth","paddingTop","paddingBottom","borderBottomWidth"],function(s){h-=atoi("0"+currentStyle(e,s));});
		ret.cw=w; ret.ch=h;
	}
	ret.bottom=ret.top+ret.height; ret.right=ret.left+ret.width;
	return ret;
}

G.pos=pos;

/**
 * get cordinate for "position:absolute" or "position:relative"
 */
function getAbsPos(e){
	for (var p=e.parentNode,m,o; (!m)&&p&&p!=doc.body; p=p.parentNode){
		switch (currentStyle(p,"position")) {
			case "absolute": case "relative":
				m=pos(e); o=G.pos(p);
				m.top-=o.top; m.left-=o.left;
				m.left-=G.atoi("0"+currentStyle(p,"borderLeftWidth"));
				m.top -=G.atoi(currentStyle(p,"paddingTop"))+G.atoi("0"+currentStyle(p,"borderTopWidth"));
		}
	}
	return m||(pos(e));
};
G.getAbsPos=getAbsPos;

/**
 * visible area width/height (without scrollbar)
 */
/*
function _clientSize(w,d) { // http://www.quirksmode.org/js/doctypes.html
	w=w?w:window; d=w.document; var ret={};
	return { // ie:standard docElm, ie:trans d.body, others w.in*=with scrollbar
		height:(d.documentElement&&d.documentElement.clientHeight)||d.body.clientHeight,
		width: (d.documentElement&&d.documentElement.clientWidth )||d.body.clientWidth
	};
};
*/
function _clientSize(w,d) { // http://d.hatena.ne.jp/onozaty/20060802/p1
	w=w?w:window; d=w.document; var ret={};
	return { // ie:standard docElm, ie:trans d.body, others w.in*=with scrollbar
		height:dedb.clientHeight, width: dedb.clientWidth
	};
};
function _clientSize_safari(w,d) { // http://www.quirksmode.org/js/doctypes.html
	return { // ie:standard docElm, ie:trans d.body, others w.in*=with scrollbar
		height:window.innerHeight, width: window.innerWidth
	};
};
var clientSize=G.isSafari?_clientSize_safari:_clientSize;
G.clientSize=clientSize;

/**
 * scrollable area widht/height
 * @return {object} ret.{width,height} in px
 */
function documentSize(d) { // standard mode only?
	d=d||document;
	return {
		height:d.body.offsetHeight+atoi(currentStyle(d.body,"marginTop")) +atoi(currentStyle(d.body,"marginBottom")),
		width: d.body.offsetWidth +atoi(currentStyle(d.body,"marginLeft"))+atoi(currentStyle(d.body,"marginRight"))
	};
};
G.documentSize=documentSize;

/************* scroll **************/

// scrollTo(pageX, pageY) -> move (pageX, pageY) to client left top
// scrollBy(dx, dy) -> scroll dx, dy 
/*
function getPageXOffset() {return atoi(window.pageXOffset||doc.documentElement.scrollLeft||doc.body.scrollLeft||0);};
function getPageYOffset() {return atoi(window.pageYOffset||doc.documentElement.scrollTop||doc.body.scrollTop||0);};
*/
function getPageXOffset() {return G.atoi(window.pageXOffset||dedb.scrollLeft||0);};
function getPageYOffset() {return G.atoi(window.pageYOffset||dedb.scrollTop||0);};
G.getPageXOffset=getPageXOffset;
G.getPageYOffset=getPageYOffset;

function hasScrollBar(e,f){
	e=e||document;
	if(f){
		return (e==document.body.parentNode)
			||(e.tagName.toLowerCase()=="iframe")
			||(G.currentStyle(e,"overflow").match(/^(auto|scroll(-[xy])?)$/));
	}
	if(e==document||e.contentWindow){
		var idoc=e.contentWindow?(e.contentDocument||e.contentWindow.document):e;
		if(idoc.compatMode=="BackCompat"){
			scw=idoc.body.scrollWidth;
			sch=idoc.body.scrollHeight;
			clw=idoc.body.clientWidth;
			clh=idoc.body.clientHeight;
		}else{
			scw=idoc.documentElement.scrollWidth;
			sch=idoc.documentElement.scrollHeight;
			clw=idoc.documentElement.clientWidth;
			clh=idoc.documentElement.clientHeight;
		}
		return (sch>clh)||(scw>clw);
	}
	var ofw=e.offsetWidth-G.atoi(G.currentStyle(e,"borderLeftWidth"),0)-G.atoi(G.currentStyle(e,"borderRightWidth"),0)
	var ofh=e.offsetHeight-G.atoi(G.currentStyle(e,"borderTopWidth"),0)-G.atoi(G.currentStyle(e,"borderBottomWidth"),0)
	return (e.clientWidth<ofw)||(e.clientHeight<ofh);
}
G.hasScrollBar=hasScrollBar;

/************************* CSS *************************/

/**
 * get current element css style
 * @param {htmlElement} e target Element
 * @param {string} style CSS style parameter ex) "borderTopStyle"
 * @param {string} err optional: return str when exception occurred (default:"")
 */
function currentStyle(e, style, err) {
	err=(err===undefined)?"":err;
	try {
		//if (window.getComputedStyle) {return window.getComputedStyle(e, null).getPropertyValue(style.replace(/([A-Z])/g,"-$1").toLowerCase());}
		if (doc.defaultView&&doc.defaultView.getComputedStyle) {return doc.defaultView.getComputedStyle(e, null).getPropertyValue(style.replace(/([A-Z])/g,"-$1").toLowerCase());}
		else if (e.currentStyle) { return e.currentStyle[style]; } // IE returns "auto","middle",..etc...
		else {return eval("[e.style." + style + "]");}
	} catch(ex){
		CONSOLE.warn("G.currentStyle("+getXPath(e)+","+style+"):"+ex); return err;
	}
};
var _cs=_cs_raw;
function _cs_raw(e,s,err){try{return eval("e.style[\"+s+\"]")}catch(ex){return err;};}
function _cs_dom(e,s,err){try{return window.getComputedStyle(e, null).getPropertyValue(s.replace(/([A-Z])/g,"-$1").toLowerCase());}catch(ex){return err;}};
function _cs_safari(e,s,err){
	var cs=doc.defaultView.getComputedStyle(e,null);
	if(cs){
		return cs.getPropertyValue(s.replace(/([A-Z])/g,"-$1").toLowerCase());
	} else if(s=="display"){ return "none"; }
	else {
		var o=e.style.display; e.style.display="block";
		try {
			var r=doc.defaultView.getComputedStyle(e, null).getPropertyValue(s.replace(/([A-Z])/g,"-$1").toLowerCase());
		}catch(ex){
			CONSOLE.warn("G.currentStyle("+getXPath(e)+","+s+"):"+ex); r=err;
		}
		e.style.display=o;
		return r;
	}
};
function _cs_ie(e,s){return e.currentStyle[s];};

if(G.isMSIE){
	_cs=_cs_ie;
} else if(G.isSafari){
	_cs=_cs_safari;
} else {
	_cs=_cs_dom;
}

function currentStyle(e, style, err) {
	return _cs(e,style);
};
G.currentStyle=currentStyle;

/*
 * MEMO:
 * doc.styleSheets[i];
 * htmlStyleElement.sheet(DOM),.styleSheet(IE)
 * sheet.disabled(for alternative stylesheet)
 * sheet.href, sheet.title
 * sheet.cssRules(DOM),sheet.rules(IE/without @import=sheet.imports)
 * sheet.cssText(IE)
 * * doc.styleSheetsはonload後のみ(Safari,Opera)
 */

/**
 * set &lt;style&gt; at &lt;head&gt; 
 * @param {string} cssText content of new style tag in header
 * @param {number} optional: sheetNo for css (default:new sheet)
 * @return styleElement
 */
function setStyleSheet(cssText, styleElement){
	var h=doc.getElementsByTagName("head")[0];
	var s=styleElement;
	if (!s){s=doc.createElement("style");s.type="text/css";h.appendChild(s);}
	var ss=s.sheet||s.styleSheet; // CSSStyleSheet object;
	try{
		if (G.isMSIE){/* IE init only? */
			ss.cssText=cssText;
		} else {
			while(s.firstChild){s.removeChild(s.firstChild);}
			s.appendChild(doc.createTextNode(cssText));
		}
	}catch(ex){
		CONSOLE.error("G.setStyleSheet:"+G.dump(ex)+":"+cssText);
	}
	return s;
};
G.setStyleSheet=setStyleSheet;

function getStyleSheetText(styleElement){
	try{
	var ss=styleElement.sheet||styleElement.styleSheet,i,l,ret=[];
	var rs=ss.rules||ss.cssRules;
	
	for(i=0,l=rs.length;i<l;i++){
		if(rs[i].selectorText&&rs[i].style&&rs[i].style&&rs[i].style.cssText){
			ret[ret.length]=rs[i].selectorText+"  { "+rs[i].style.cssText+" }";
		}
	}
	return ret.join(" \n");
	}catch(ex){CONSOLE.error("G.getStyleSheetText:"+G.dump(ex));return null;}
};
G.getStyleSheetText=getStyleSheetText;

/**
 * remove stylesheet
 * @param {number} sheetNo
 */
/*
function _removeStyleSheet(sheetNo){
	// IEだとコントロールの背景の反映が遅い
	//try{
		var s=doc.styleSheets[sheetNo];
		if (s) {
			s.cssText=""; s.disabled=true;
			s.ownerNode&&removeElement(s.ownerNode);    // DOM
			s.owingElement&&removeElement(s.owningElement); // IE
		} else { CONSOLE.warn("removeStyleSheet("+sheetNo+"):"+sheetNo+" is not found"); }
	//}catch(e){;}
};*/
function removeStyleSheet(styleElement){
	if (styleElement){
		styleElement.disabled=true; if(G.isMSIE){styleElement.cssText="";}
		styleElement.ownerNode&&removeElement(styleElement.ownerNode); // DOM
		styleElement.owingElement&&removeElement(styleElement.owingElement);
		styleElement.parentNode&&styleElement.parentNode.removeChild(styleElement); // Safari2
		styleElement=null;
	}
};
G.removeStyleSheet=removeStyleSheet;

/**
 * add className to element
 * @param {htmlElement} e target element
 * @param {string} className target css class
 */
function addClassName(e, className) {
	if(!e||(!e.tagName)){return;} if(!(" "+(e.className.replace(/\s+/g," "))+" ").match(" "+className+" ")){e.className+=" "+className;}
};
G.addClassName=addClassName;

/**
 * remove className from element
 * @param {htmlElement} e target element
 * @param {string} className target css class
 */
function removeClassName(e, className) {
	if(!e||(!e.tagName)){return;}
	var c=e.className.replace(/\s+/," ").split(" "),n=[];
	for (var i=0,l=c.length;i<l;i++){ if(c[i]!=className){n[n.length]=c[i];}}
	e.className=n.join(" "); if(n.length==0){e.removeAttribute("class");}
};
G.removeClassName=removeClassName;

/**
 * isClass
 * @param {htmlElement} element 
 * @param {string} className
 */
function isClass(e, className) {
	var m=function(a,b){return a==b};
	if (className instanceof RegExp){
		m=function(t,r){
			return t.match(r)!=null;
		}
	}
	if(className instanceof Array){ var r=true;
		G.each(className,function(c){
			if(!G.isClass(e,c)){r=false;return true;}
		});
		return r;
	}
	var r=false; // G.each((e.className||"").split(/\s+/),function(s){ r=m(s,className); return r;});
	var a=(e.className||"").replace(/\s+/g," ").replace(/^ /,"").replace(/ $/,"").split(" "); while(a[0]){if(a.shift()==className){return true;}}
	return r;
};
G.isClass=isClass;

function setStyles(e,v){
	for(var p in v){
		var s=p.replace(/-([a-z])/g,function(m){return m[1].toUpperCase()});
		switch(p){
			case "float": s="cssFloat"; break;
		}
		e.style[s]=v[p];
	};
};
G.setStyles=setStyles;

function getStyles(e){
	var ret={};
	for(var p in e.style){
		var s=e.style[p];
		switch(p){
			case "cssText": continue; break;
			case "cssFloat": case "styleFloat": p="float";
			default: ret[p]=e.style[v]; break;
		}
		ret[v]=s;
	}
	return ret;
}
G.getStyles=getStyles;

/*********************** events *********************/

/**
 * addEvent, bubbling (parent -> this) only. if parent eventhandler stopbubbled, block. (because IE supports bubbling only)
 * @param {htmlElement} e target element
 * @param {string} type event type string. ex) "click", "keyup", ...
 * @param {function} func event handler function
 * @param {object} thisObj optional:when exist, thiObj is usable as "this" in func.
 * @return {number} id for G.removeEvent()
 */
function addEvent(e, type, func, thisObj) {
	if(type=="keypress"&&!addEvent._keydown){
		addEvent._keydown=addEvent(document,"keydown",function(ev){
			ev=G.parseEvent(ev);
			addEvent._lastKeyDownEvent=ev;
		});
	}
	if(type=="keypress"&&(G.isSafari||G.isMSIE)){
		type="keydown";
	}
	if(type=="mousewheel"&&G.isFirefox){
		type="DOMMouseScroll";  // Firefox
	}
	func=(thisObj?bindThis(thisObj,func):func);
	if (e.addEventListener){e.addEventListener(type,func,false);} // bubble up only : element -> parent -> body
	else if (e.attachEvent){e.attachEvent("on"+type,func);}
	else {e["on"+type]=func;}
	var id=addEvent._cnt;addEvent._cnt++;
	addEvent._list[id]={id:id,e:e,t:type,f:func};
	return id;
};
addEvent._list = {};
addEvent._cnt=0;

G.addEvent=addEvent;

/**
 * removeEvent by id
 * @param {number} id target event for remove
 */
function removeEvent(id) {
	var t = addEvent._list[id];
	if (t&&t.e) {
		if (t.e.removeEventListener) {t.e.removeEventListener(t.t,t.f,false);}
		else if (t.e.detachEvent) {t.e.detachEvent("on"+t.t,t.f);}
		else {delete t.e["on"+t.t];}
	}
	delete addEvent._list[id];
};
G.removeEvent=removeEvent;

function garbageCollection(){
	// TODO: 使われてないイベントリスト、G.$()キャッシュあたりの消去?
}

function WrappedEvent(ev){
	var p; for(p in ev){this[p]=ev[p];}
	this._org=ev;
}

/**
 * parse events for cross browser.
 * for cross browser, please use "keypress" only
 * @param {Event} ev event object(by DOM model)
 * @return {Event} ev:
 * ev.type,
 * ev.target, ev.retedTarget, originalTarget?, currentTarget? currentTarget for IE is not impremented
 * ev.click.{l,m,r},
 * ev.pos.{x,y,clientX,clientY},
 * ev.keyCode, (String.fromCharCode)
 * ev.keyAsc
 * ev.{shiftKey,ctrlKey,altKey}
 */
var SAFARI_ARROW={"63232":38,"63233":40,"63234":37,"63235":39};
function parseEvent(ev,pev) {
	ev=ev||window.event;
	if(G.isOpera){
		ev=new WrappedEvent(ev);
	}
	if(ev.srcElement){ev.target=ev.srcElement;}
	switch(ev.type){
		case "mouseout": if(ev.toElement){ev.relatedTarget=ev.toElement;} break;
		case "mouseover":if(ev.fromElement){ev.relatedTarget=ev.fromElement;} break;
		// http://unixpapa.com/js/key.html
		case "keypress": case "keyup": case "keydown":
			ev.keyAsc=ev.keyCode||ev.which;
			ev.keyAsc=SAFARI_ARROW[ev.keyAsc]||ev.keyAsc;
			break;
		case "DOMMouseScroll": // FireFox
			ev.wheel={count:ev.detail>0?-1:1}
			break;
		case "mousewheel":  // IE,Safari
			ev.wheel={count:ev.wheelDelta>0?1:-1};
			break;
	}
	if(G.isMSIE){ev.click={l:ev.button==0||ev.button==1,r:ev.button==2,m:ev.button==4};} // or Konquerer
	else {ev.click={l:ev.which===1,r:ev.which===3,m:ev.which===2};} // DOM
	ev.pos = {
		clientX:ev.clientX, clientY:ev.clientY, // page?Offset:DOM, scroll*:IE ()
		x:dedb.scrollLeft+ev.clientX, y:dedb.scrollTop+ev.clientY
	};
	return ev;
};
G.parseEvent=parseEvent;

/**
 * stop event bubbling in event handler. ex) return G.stopBubble(e,true);
 * @param {Event} ev event object
 * @param {boolean} flag stop flag
 */
function stopBubble(ev,flag) {
	flag=(flag===undefined)?true:flag; ev=ev||window.event;
	if(ev._org){ev=ev._org;}
	if(flag){
		if(G.isMSIE){
			ev.cancelBubble=true; // IE  stopPropagation
			ev.returnValue=false; // IE5 !preventDefault
		} else {
			if(ev.stopPropagation) {ev.stopPropagation();}
			if(ev.preventDefault) {ev.preventDefault();} // DOM2
		}
		//return true;
	}
	//return;
};
G.stopBubble=stopBubble;

function stopDefault(ev,flag) {
	flag=(flag===undefined)?true:flag; ev=ev||window.event;
	if(ev._org){ev=ev._org;}
	if(flag){
		if(ev._org){ev=ev._org;}
		if(G.isMSIE){
			ev.returnValue=false; // IE5 !preventDefault
		} else {
			if(ev.preventDefault) {ev.preventDefault();} // DOM2
		}
		//return true;
	}
	//return;
};
G.stopDefault=stopDefault;


// TODO:まだへん
function setCapture(e,c) {
	if (c){setCapture._s=setStyleSheet("* {cursor:"+c+"}");}
	if (e.setCapture){e.setCapture (e);}
/*
	else if(window.captureEvent){
		window.captureEvent(
		//Event.ABORT, Event.BLUR, Event.CLICK, Event.CHANGE, Event.DBLCLICK, Event.DRAGDDROP, Event.ERROR, Event.FOCUS, Event.KEYDOWN, Event.KEYPRESS, Event.KEYUP, Event.LOAD, Event.MOUSEDOWN, Event.MOUSEMOVE, Event.MOUSEOUT, Event.MOUSEOVER, Event.MOUSEUP, Event.MOVE, Event.RESET, Event.RESIZE, Event.SELECT, Event.SUBMIT, Event.UNLOAD.
			Event.CLICK|Event.DBLCLICK|Event.DRAGDDROP|Event.FOCUS|Event.KEYDOWN|Event.KEYPRESS|Event.KEYUP|Event.MOUSEDOWN|Event.MOUSEMOVE|Event.MOUSEOUT|Event.MOUSEOVER|Event.MOUSEUP
		);
	}
*/
	else{
		if (setCapture._ce) {CONSOLE.warn("setCapture():already capturing"); return false;}
		var ce=[];
		G.each(["mousemove","mouseover","mouseout","mousedown","mousedown","click","dblclick",
				"contextmenu","keyup","keydown","keypress"], function(t){
				ce[ce.length-1] = G.addEvent(document,t,
					bindThis(document,function(e){
						if(e.dispatched){return stopBubble(e,false);}
						e.dispatched=true;
						this.dispatchEvent(e);
						return stopBubble(e);
					}));
			});
		setCapture._ce=ce;
	}
};
G.setCapture=setCapture;

// TODO:まだへん
function releaseCapture(e){
	if (setCapture._s){removeStyleSheet(setCapture._s);delete setCapture._s;}
	if (e.releaseCapture){e.releaseCapture();}
	else { G.each(setCapture._ce,function(i){G.removeEvent(i);}); setCapture._ce=null;}
};
G.releaseCapture=releaseCapture;

/**
 * find native event argument from ancestors (callers).
 * useful to get native events object in HTML event handler.
 * ex) &lt;input onclick="this.value=(findEvent()).type"&gt;
 */
function findEvent() {
	if (window.event) { return window.event; }
	for (var a=arguments; a.callee.caller; a=a.callee.caller.arguments) {
		for (var i=0; i<a.length; i++) { if (a[i] instanceof Event) { return a[i]; } }
	}
	return;
};
G.findEvent=findEvent;

function dispatchEvent(e,ev){
	if (e.dispatchEvent) {return e.dispatchEvent(ev)}
	else {
		ev.element=function(){return ev.srcElement;}
		return e.fireEvent("on"+ev.type,ev);
	}
}
G.dispatchEvent=dispatchEvent;

function click(e){
	if(G.isMSIE){
		//e.click();
		var event=doc.createEventObject();
		event.type="click";
		//event
		e.fireEvent("onclick",event);
	}else{
		var event=doc.createEvent("MouseEvents");
		if(event.initMouseEvent){
			//type,bubbles,cancelable,view,detail,scX,scY,clX,clY,ctrl,alt,shift,meta,button,relTgt
			event.initMouseEvent("click",true,true,doc.defaultView,1,0,0,0,0,false,false,false,false,0,null);
		}else{
			event.initEvent("click",true,true);
		}
		e.dispatchEvent(event);
	}
}
G.click=click;

/**
 * onmouseover(event)/this=elem without from child element,
 * onmouseout(event)/this=elem without to child element
 * @param {Object} e
 * @param {Object} mouseover
 * @param {Object} mouseout
 */
function setHover(e,mouseover,mouseout){
	var ret=[];
	if(mouseover){
		ret.push(G.addEvent(e,"mouseover",(function(ev){
			ev=G.parseEvent(ev);
			if(!G.findAncestor(ev.relatedTarget,{e:this})){
				mouseover.call(this,ev);
			}
		}).bindThis(e)));
	}
	if(mouseout){
		ret.push(G.addEvent(e,"mouseout",(function(ev){
			ev=G.parseEvent(ev);
			if(ev.relatedTarget!=e&&!G.findAncestor(ev.relatedTarget,{e:this})){
				mouseout.call(this,ev);
			}
		}).bindThis(e)));
	}
	return ret;
};
G.setHover=setHover;

function setOnScrollBottom(e,f,margin,interval){
	margin=(margin===undefined)?20:margin;
	interval=(interval===undefined)?300:interval;
	setInterval((function(e,f,margin){
		if(e.scrollTop+e.offsetHeight>e.scrollHeight-margin){
			f();
		}
	}).bindArgs(e,f,margin),interval);
}
G.setOnScrollBottom=setOnScrollBottom;

/**
 * cross browser event handler : DOMContentLoaded
 * @param {Object} f
 */
G.setOnLoadHtml=function(f){
	if(G.setOnLoadHtml._loaded){
		window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:already loaded:"+f);
		f();
		return;
	}

	if(document.readyState&&(G.isWebkit||G.isIPhone)){
		window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:Webkit:waiting readyState");
		function waitfunc(){
			switch(document.readyState){
				case "loaded": case "complete":
					CONSOLE.info("G.setOnLoadHtml:DOM load complete:Webkit");
					f(); break;
				default:
					setTimeout(waitfunc,50);
			}
		}
		waitfunc();
	}else if(document.readyState&&G.isMSIE&&!G.isMSIE8){
		/*
		window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:IE:waiting doScroll enable");
		(function(){
			try{
				// throws errors until after ondocumentready
				document.documentElement.doScroll('left');
			} catch (e) {
				setTimeout(arguments.callee, 50);
				return;
			}
			window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:DOM load complete:IE");
			f();
		})();
		*/
		
		window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:IE:waiting behavior");
		/* http://www.nabble.com/Re%3A-document.ready-firing-too-early-within-iframe-p13376590s27240.html */
		//G._IECheck;
		function IEContentLoaded(w,f){
		    // document has loaded (IE method 2) using behavior
		    var load=false,d=w.document,s=d.createStyleSheet().owningElement;
		    s.styleSheet.cssText='body{behavior:expression(G._IECheck(this));}';
		    var fire=function(e){
				if(!load){
					window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:IE:done");
					load=true;f.call(d,e);
					setTimeout(function(){
						s.parentNode.removeChild(s);
					},10);
				}
			};
			G._IECheck=function(n){
				window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:IE:behavior enabled");
				try{
					d.documentElement.doScroll('left');
					n.runtimeStyle.behavior='none';
					window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:IE:doScroll enabled,disable behavior");
				}catch(e){return;}
				fire(null);
			};
			//d.attachEvent("onload",fire);
		}
		if(!G.setOnLoadHtml._fs){
			G.setOnLoadHtml._fs=[f];
			IEContentLoaded(window,function(){while(G.setOnLoadHtml._fs[0]){
				(G.setOnLoadHtml._fs.shift())();
			}});
		}else{
			G.setOnLoadHtml._fs.push(f);
		}
	}else{
		if(window.addEventListener){
			window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:use DOMContentLoaded");
			window.addEventListener("DOMContentLoaded",f,false);
			//document.addEventListener("load",f,false);
		}else if(window.attachEvent){
			window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:use attachEvent onload");
			window.attachEvent("onload",f);
		}else{
			window.CONSOLE&&CONSOLE.info("G.setOnLoadHtml:use window.onload");
			var f2=G.setOnLoadHtml._f||(function(){G.setOnLoadHtml._loaded;});
			window.onload=function(){
				f2();
				f&&f();
			}
		}
	}
};
G.setOnLoadHtml._f=function(){};
/*
G.setOnLoadHtml(function(){
	G.setOnLoadHtml._loaded=true;
});
*/

/************************ http(ajax) ***********************/

/**
 * Ajax prototype.
 * ex)
 * var obj=new Ajax(); elem.innerHTML = "now Loading...";
 * obj.get("hoge.php", [{n:"a",v:"value of a"}],
 *   G.bindThis(function(txt){
 *     this.innerHTML=txt;
 *   },elem),
 *   function(txt,code){
 *     elem.innerHTML="Error!";
 *     alert("ERR on hoge.php:"+code+"\n");
 *   }
 * );
 * responseTextはSafariでは文字コードがおかしくなる。<?xml version="1.0" encoding=".."?>で1要素XMLにすべしか？
 */
function Ajax() {
	this.status="init";
	this.req = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("Msxml2.XMLHTTP");
	this.id=Ajax.cnt++;
}
Ajax.prototype.REDIRECTOR=G._BASEPATH+"proxyget.php";
Ajax.useRedirector=false;
Ajax.prototype.timeout=30;
Ajax.cnt=0;
Ajax.status=[];

Ajax.prototype.waitHtml="Loading...";

/**
 * url, method, params, func(text, xmlHttpReq), errorHandler(text,httpcode,xmlHttpReq), presend func(xmlHttpReq)
 * .status=(connecting|processing|)
 * @param {string} u URL
 * @param {string} m method ("POST"|"GET"|...?);
 * @param {string} a parameters(encoded)
 * @param {function} f oncomplete function(text, xmlHttpRequest)
 * @param {function} e onerror function(text, httpStatusCode, xmlHttpRequest, exception)
 * @param {function} p pre send function(xmlHttpRequest);
 */
var _safaribug=function(t){return t;}
if (G.isSafari2){
	CONSOLE.log("Ajax:use _safaribug");
	_safaribug=function(t){
		//CONSOLE.log("_safaribug:"+t);
		var e=escape(t); if (e.indexOf("%u")<0&&e.indexOf("%")>-1){t=decodeURIComponent(e);} return t;
	}
}
Ajax.prototype.send = function(u,m,a,f,e,p) {
	this.status="sending";
	var ua = u.split("/");
	if (Ajax.useRedirector){
	if (this.REDIRECTOR&&(ua[0]=="http:"||ua[0]=="https:")&&ua[2].split(":")[0]!=location.host) {
			var ou=u; u=this.REDIRECTOR+(this.REDIRECTOR.indexOf("?")>=0?"&":"?")+"_u="+esc(u,"U");
			CONSOLE.info("Ajax:'"+ou+"' redirect to " + u );
		}
	}

	e=(e!==undefined)?e:function(txt, status, x, ex){
		if(ex){CONSOLE.error("Ajax.send(${u},${m},${a}):\nexception----\n${e}".tmpl({u:u,m:m,a:a,e:"| "+dump(ex).replace(/\n/g,"\n| ")}));}
		if(txt){CONSOLE.error("Ajax.send(${u},${m},${a}):\nstatus=${s}\n${t}".tmpl({u:u,m:m,a:a,s:status}));}
	};
	var x=this.req; var async=(f!==null);
	try {
		x.open(m,u,async);
		x.setRequestHeader('If-Modified-Since', 'Wed, 15 Nov 1995 00:00:00 GMT'); // for Safari
		//x.setRequestHeader("Accept-Charset","UTF-8,*");
		if (!async) {
			if(m&&m.toUpperCase()=="POST"){x.setRequestHeader("Content-Type","application/x-www-form-urlencoded");}
			x.send(a||null);
			this.status="complete";
			return _safaribug(x.responseText);
		}
	} catch (ex) {
		x.abort();
		CONSOLE.error("G.AJax.send:"+G.dump(ex));
		this.status="error";
		if(e){e(null,null,null,ex);return;}
		else{alert(ex);return;}
	} // async
	//CONSOLE.info("Ajax:async");
	this._timer=setTimeout((function(e,t){
		t.status="timeout";
		t.req.abort();
		CONSOLE.error("G.AJax.send:timeout");
		e&&e(null,t.req.status,"timeout");
	}).bindArgs(e,this),this.timeout*1000);
	if(false&&doc.body){var ind=new Indicator(this.waitHtml, 300); setOpacity(ind.e, 0.7);}
	x.onreadystatechange=bindThis({x:x,f:f,e:e,t:this,m:ind},function(){
		if(x&&x.readyState&&x.readyState==4){ switch(this.x.status) {
			case 0: case 200:
				clearTimeout(this.t._timer);
				this.m&&this.m.remove();
				this.status="processing";
				this.f(_safaribug(this.x.responseText), this.x);
				this.status="complete";
				break;
			default:
				clearTimeout(this.t._timer);
				this.m&&this.m.remove("Error!", 3000);
				if(this.e){this.e(_safaribug(this.x.responseText), this.x.status, x, "timeout");}
				this.status="error";
				break;
		}}
	})
	if (p) {p(x);}
	try { x.send(a); } 
	catch (ex) { 
		clearTimeout(this._timer)
		x.abort();
		this.status="error";
		if(e){e(null,null,null,ex);}
	}
};

/**
 * encode param name and value to string (&amp;joined)
 * @param {array or object} params {name:value, name:value,...} or [{n:name,v:value},{n:name,v:value},...]
 */
Ajax.prototype._enc = function(params) {
	var r=[],p,e=encodeURIComponent;
	if (params instanceof Array){for (var i=0;i<params.length;i++){p=params[i];r.push(e(p.n)+"="+e(p.v));}}
	else {for (p in params) {
		if(params[p] instanceof Array){G.each(params[p],function(v){r.push(e(p)+"="+e(v));});}
		else {r.push(e(p)+"="+e(params[p]));};
		}
	}
	return r.join("&");
};

/**
 * async GET
 * @param {string} url URL for GET
 * @param {array or object} params {name:value, name:value,...} or [{n:name,v:value},{n:name,v:value},...]
 * @param {function} func async handler function(responseText, requestObj)
 * @param {function} err error handler function(responseText, httpcode, requestObj)
 */
Ajax.prototype.get = function(url,params,func,err) {return this.send(url+(params?(url.indexOf("?")>0?"&":"?")+this._enc(params):""),'GET',null,func,err);};

/**
 * async POST
 * @param {string} url URL for POST (form urlencoded)
 * @param {array or object} params {name:value, name:value,...} or [{n:name,v:value},{n:name,v:value},...]
 * @param {function} func async handler function(responseText, requestObj)
 * @param {function} err error handler function(responseText, httpcode, requestObj)
 */
Ajax.prototype.post = function(url,params,func,err) {
	return this.send(url,"POST",this._enc(params),func,err,function(x) {x.setRequestHeader('Content-type','application/x-www-form-urlencoded');});
};

/**
 * async POST form
 * @param {string} url url URL for POST
 * @param {htmlFormElement} e form element
 * @param {function} func async handler function(responseText, requestObj)
 * @param {function} err error handler function(responseText, httpcode, requestObj)
 */
Ajax.prototype.postForm = function(url,e,func,err) {return this.post(url,"POST",this.formToParams(e),func,err);};

/**
 * FORM values to params for Ajax.post/get (not support for multiple select)
 * @param {htmlFormElement} e target FORM element 
 */
Ajax.prototype.formToParams = function(e){
	var r=[]; G.each(G.$C({t:/^INPUT|SELECT|TEXTAREA$/i,n:/^\S+$/},e),function(e){
		if (!((e.type=="radio"||e.type=="checkbox")&&e.checked)){r.push({n:e.name,v:e.value});}
	}); return r;
};

G.Ajax=Ajax;


/*********************** JSON ************************/

/**
 * any variable to JSON string
 * @param {any} o target
 * @param {boolean} optional: format (default:false)
 */
function toJSON(o,f) {
	var F=f?"\n":"", t=typeof o, r, i, p, p2;
	if (o===undefined||o===null||o===true||o===false||t=="number") {return ""+o;}
	else if (t=="string"||o instanceof String) {return "\""+esc(o,"J")+"\"";}
	else if (t=="function"||o instanceof Function) {return o.toString().replace(/^function\s+anonymous\s*\(/,"function(");}
	else if (o instanceof Date) {return "new Date(\""+esc(o.toString(),"J")+"\")";}
	else if (o instanceof RegExp) {return o.toString();}
	else if (o instanceof Array) {
		for(i=0,r=[]; i<o.length; i++) {r.push(toJSON(o[i],f));} return "["+r.join(","+F)+"]";
	} else { // object  // prototypeの値はひきつがない
		r=[]; for(var p in o) {
			if (o.hasOwnProperty(p)){
				p2=p;
				if(!p.match(/^[a-zA-Z_][a-zA-Z0-9_]+$/)){p2="\""+esc(p,"J")+"\"";}
				r.push(p2+":"+toJSON(o[p],f));
			}
		}
		return "{"+r.join(","+F)+"}";
	}
};
G.toJSON=toJSON;

/**
 * JSON string to any variable in secure(?)
 * @param {string} str JSON string
 * @return {object} result
 */
function fromJSON(str,onerror){
	try{
		var window=null,document=null;
		eval("var o="+str);
		return o;
	}catch(e){
		CONSOLE.error("fromJSON()\n"+dump(e)+"\n"+str);
		onerror&&onerror(str);
		return e;
	}
}
G.fromJSON=fromJSON;

var JSONP={};
/**
 * call jsonp
 * @param {string} u URL
 * @param {string} c callback parameter name. "callback", "_callback", .. etc
 * @param {function} f callback function
 * @param {Object} p additional parameters [{n:NAME,v:VALUE},..] or {NAME:VALUE,...}
 * @param {function} err erro handler function(excetpion)
 */
function JSONPCall(u,c,f,p,err) {
	JSONP.callback = bindThis(f,function(){
		//var _oa=["var window=null;var document"]; for (var _p in window){if(_p){_oa[_oa.length]=_p;}} _oa[_oa.length]="=null;"; eval(_oa.join("=null;var ")); _oa=null;
		var window=null,document=null;
		this.apply(null, arguments);
	});
	try { var s=requireJs(u+"?"+c+"=G.JSONP.callback&"+Ajax.prototype._enc(p));
		//setTimeout(bindThis(s,function(){removeElement(this)}),10000);
	} catch (e) {CONSOLE.error("JSONP.call():"+dump(e)); if (err) {err(e);}}
};
JSONP.call=JSONPCall

G.JSONP=JSONP;

/*
 * var jsonp=new JSONPCall("http://www.example.com?_callback=${callbackname}&${params}",p,function(arg){...});
 * @param {function} e onerror function(null, null, scriptelem, exception||"timeout")
 */

function JSONPCall() {
	if(arguments.length>1){
		this.send.apply(this,arguments);
	}
}
JSONPCall.prototype.timeout=30;

JSONPCall.prototype.send=function jsonpsend(u,p,f,e) {
	this.status="init";
	if(!JSONPCall.seq){JSONPCall.seq=new Seq();JSONPCall.seq.start();}
	JSONPCall._cnt=JSONPCall._cnt+1;
	this.id=JSONPCall._cnt;
	var v={
		callbackname:"f"+this.id,
		params:G.Ajax.prototype._enc(p)
	};
	this.u=u;
	this.v=v;
	this.f=f;
	JSONPCall.f[v.callbackname]=(function(o){
		clearTimeout(this._timer);
		this.status="processing";
		JSONPCall.seq.add((function(f,o){
			f(o);
		}).bindArgs(this.f,o));
		G.removeElement(this._s);
		this.status="complete";
	}).bindThis(this);
	this._timer=setTimeout((function(e){
		this.status="timeout";
		CONSOLE.warn("G.JSONPCall:timeout:"+G.unesc(url,"U")+"\n"+G.dump(this.v));
		e&&e(null,null,this._s,"timeout");
	}).bind(this,e),this.timeout*1000);
	
	v.callbackname="G.JSONPCall.f."+v.callbackname;
	var url=G.tmpl(u,v);
	CONSOLE.log("G.JSONPCall:"+G.unesc(url,"U"));
	try {
		this.status="sending";
		this.onerrorfunc=e;
		this._s=requireJs(url,"utf-8",true,"jsonpcall-"+this.id,null,(function(){
			clearTimeout(this._timer);
			this.onerrorfunc&&this.onerrorfunc();
		}).bindThis(this));
	} catch (ex) {
		clearTimeout(this._timer);
		CONSOLE.error("JSONPCall:requireJs exception:"+G.dump(ex));
		this.status="error";
		if (e) {e(null,null,this._s,ex);}
	}
};
JSONPCall._cnt=0;
JSONPCall.f={};
G.JSONPCall=JSONPCall;

JSONPCall.prototype.abort=function(){
	this.f = function(){};
}

/************************* xhr *****************************/
/* needs xhr.js on callee html */
/* param:{m:"getbodyhtml"},{m:"call",f:funcnameOnCaleeeWindow}  */
function XHRCall(url,param,callback){
	this.status="init";
	this.id=XHRCall._cnt++;
	var ifr=doc.createElement("iframe");
	ifr.id="xfr-"+this.id;
	ifr.style.cssText="visibility:hidden;position:absolute;width:0;height:0;margin:0;padding:0;border:none;";
	var src=["c=XHR"+this.id];
	if(param){
		G.each(param,function(v,p){
			src.push(encodeURIComponent(p)+"="+encodeURIComponent(v));
		});
	}
	window["XHR"+this.id]=(function(callback,ifr,id,obj){
		return function(){
			obj.status="processing";
			callback.apply(this,arguments);
			(function(ifr){G.removeElement(ifr);window["XHR"+id]=null;}).bindArgs(ifr).later(100);
			obj.status="complete";
		};
	})(callback,ifr,this.id,this);
	this.status="sending";
	ifr.src=url+"?"+src.join("&");
	doc.body.appendChild(ifr);
}
XHRCall._cnt=0;
G.XHRCall=XHRCall;

/*****/
function parseUri(uri){
	var params={};
	var RX=/^([^:]+):\/\/([^\/]*)([^\?#]+)(\?([^#]*))?(#(.*))?$/;
	var m=uri.match(RX);
	if(!m){
		var full=parseUri(location.href);
		full.params={};uri.hash="";
		if(uri.indexOf("/")==0){
			full.path=uri;
		}else{
			full.path=full.path.replace(/\/[^\/]*$/,"/")+uri;
		}
		var m=full.toString().match(RX);
		if(!m){return {}};
	}
	var ret={original:uri,protocol:m[1],hostname:m[2],path:m[3]||"",search:m[5]||"",hash:decodeURIComponent(m[7]||"")};
	function dummy(v){return v;}
	G.each((ret.search||"").split("&"),function(v){
		v=v.split("=");
		var p=v.shift();
		if(p!=""){
			v=(v||"").join("="); 
			// decodeURIComponentはUTF8前提。unescape使うのもちょっとやっつけ。
			G.each([decodeURIComponent,dummy],function(f){
				try{
					params[p]=f(v);
					return true;
				}catch(ex){
					//params[p+"_raw"]=v;
					CONSOLE.warn("G.parseUri():parse error:"+f.toString().split("{")[0]+":"+v);
					params[p]=v;
				}
			});
		}
	});
	ret.params=params;
	ret.toString=function(){
		var s=[];
		G.each(this.params,function(v,p){
			s.push(p+"="+encodeURIComponent(v));
		});
		return this.protocol+"://"+this.hostname+this.path
			+(s.length>0?("?"+s.join("&")):"")
			+(this.hash?("#"+encodeURIComponent(this.hash)):"");
	}
	return ret;
}
G.parseUri=parseUri;

/************************* xml *****************************/

/**
 * toXML converts E4X like object to XML string (without xml header)
 * @param {object} o source e4xlike object
 * {"name":"value", "name2":{"@attr":"attrval","#text":"value"},"multi":["value",{"@attr":"atv","#text":"val"}]}
 * @param {string} name root element name
 * @param {boolean} f optional: format (default:false)
 */
function toXML(o,name,f) {
	if (o&&o["-seq"]) { var seq=o["-seq"]; delete o["-seq"]; }
	var F=f?"\n":"",a=[],c=[],t=typeof o;
	if (o===null||o===undefined) {return "<"+name+" />";}
	if (t!="object"){return "<"+name+">"+o+"</"+name+">";}
	if (o instanceof Array) {G.each(o,function(e,i){c.push(toXML(e,name,f));});return c.join(F);}
	else {
		G.each(o,function(v,p){
			if(p.indexOf("@")===0){a.push(p.substring(1)+"=\""+esc(v,"X")+"\"");}
			else if(p=="#text"){c.push(esc(v,"X"));}
			else if(p=="#cdata-section"){c.push("<![CDATA["+v+"]]>");}
			else if(p=="#comment"){c.push("<!-- "+v+" -->");}
			else {c.push(toXML(v,p,f));}
		});
		if (!name) { return c.join(F); }
		return "<"+name+(a.length?(" "+a.join(" ")):"")+(c.length?(">"+c.join(F)+"</"+name):" /")+">";
	}
};
G.toXML=toXML;

/**
 * fromXML converts XML string to E4X like object (without xml header).
 * @param {string} str source XML string
 * @param {boolean} optional: not shrink array and #text
 */
function fromXML(str,n) {
	n=(n===undefined)?false:n;
	var ret = {},m,s=0,a,c=ret,p=[],t,pn=[];
	function addF(o,p,v){ if(p in o){ if(o[p].push){o[p].push(v);}else{o[p]=[o[p],v];}}else{o[p]=v;}}
	function addN(o,p,v){ if(p in o){ o[p].push(v); } else { o[p]=[v]; } }
	var add=n?addN:addF;
	function addAttrs(o,str){
		var m,r=new RegExp("\\s*(([^\\s=]+?)\\s*=\\s*\"(.*?)\"|([^\\s=]+?)\\s*=\\s*'(.*?)')\\s*","gm");
		while((m=r.exec(str))){if(m===null){break;} o["@"+(m[2]||m[4])]=unesc((m[3]||m[5]),"X");}
	}
	var r = new RegExp("("+[fromXML.XMLDECL_STR,fromXML.COMMENT_STR,fromXML.CDATA_STR,
							fromXML.OPTAGRX_STR,fromXML.CLTAGRX_STR,fromXML.OCTAGRX_STR].join("|")+")", "gm");
	var no;
	while((m=r.exec(str))){
		if (m===null) {break;}
		t=str.substring(s,r.lastIndex-m[0].length); if(t&&t.length>0){ add(c,"#text",unesc(t,"X")); }
		if(m[5]!==undefined){no={};if(m[6]){addAttrs(no,m[6]);} add(c,m[5],no); p.push(c); pn.push(m[5]); c=no; }//OP
		else if(m[7]!==undefined){ //CL
			if (!n) {
				var cn=0; for (var pr in c){ if (c.hasOwnProperty(pr)){cn++;} }
				if (cn==1&&("#text" in c)) {p[p.length-1][pn[pn.length-1]]=c["#text"];}
			}
			c=p.pop(); pn.pop();
		}
		else if(m[8]!==undefined){no={};if(m[9]){addAttrs(n,m[9]);} add(c,m[8],no);}//OPCL
		else if(m[3]!==undefined){add(c,"#comment",m[3]);}//COMMENT
		else if(m[4]!==undefined){add(c,"#cdata-section",m[4]);}//CDATA
		else if(m[2]){}//DECL
		s=r.lastIndex;
	}
	//CONSOLE.log(toJSON(ret,true));
	return ret;
};
fromXML.XMLDECL_STR = '^<\\?xml(\\s*[\u0000-\uffff]*)\\?>';
// DTDには対応しない
fromXML.COMMENT_STR = '<!--([\u0000-\uffff]*?)-->';
fromXML.CDATA_STR	  = '<!\\[CDATA\\[([\u0000-\uffff]*?)\\]\\]>';
fromXML.OPTAGRX_STR = '<([^!/\\?][^\\s/<>]*)(\\s*[\u0000-=\?-\uffff]+[^/])?\s*>'; 
fromXML.CLTAGRX_STR = '<(/[^\\s/<>]+)\s*>';
fromXML.OCTAGRX_STR = '<([^!\\?][^\\s/<>]*)(\\s*[\u0000-=\?-\uffff]+)?\s*/>';

G.fromXML=fromXML;

// TODO:ツリー構造をまともに実装…？それならDOMっちゃった方がとも思う。Java6はjavaのなにか、rhinoはE4Xで?。

/*
 * どう使いたいか
 * var wk=new G.ObjectWalker(o);
 * wk.cd("test");
 * var p=wk.ls(); 
 */
function ObjectWalker(o){this.current=o; this._os=[]; this._ns=[]; };
ObjectWalker.prototype.pwd = function(){return "/"+this._ns.join("/");};
ObjectWalker.prototype.get = function(p){return (p===undefined)?this.current:this.current[p];}
ObjectWalker.prototype.ls = function(){var ret=[];for (var p in this.current){if (this.current.hasOwnProperty(p)){ret.push({name:p,type:(typeof this.current[p]),value:this.current[p]});}} return ret;};
ObjectWalker.prototype.cdc = function(p){
	if (!(p in this.current)){ throw new Error("ObjectWalker.cdc():no such property:\""+p+"\""); } 
	this._os.push(this.current); this._ns.push(p); this.current = this.current[p];
	return this.current;
};
ObjectWalker.prototype.cdp = function(){ this.current = this._os.pop(); this._ns.pop();};

G.ObjectWalker=ObjectWalker;

/****************/
function IFrame(e) {
	if(!e){
		e=document.createElement("iframe");e.src="about:blank";
		e.style.cssText="position:absolute; width:0; height:0; top:-10000px; left:-10000px; ";
		document.body.appendChild(e);
	}else{
		this.window=e.contentWindow;
		this.document=e.contentDocument||e.contentWindow.document;
	}
	this.element=e;
};

IFrame.prototype.load=function(u, f) {
	//if (!this.element.readyState) { // DOM (Gecko)
	if (!G.isMSIE) { // DOM (Gecko)
		CONSOLE.log("IFrame:load:use elm.onload:"+u);
		this.element.onload=(function(f,obj){
			obj.window=obj.element.contentWindow;
			obj.document=obj.element.contentDocument;
			if(f){CONSOLE.log("IFrame:onload:"+G.dump(f));}
			f&&f.call(obj,obj.window,obj.document);
			CONSOLE.log("IFrame:onload:done");
		}).bind(this.element,f,this);
	} else {
		CONSOLE.log("IFrame:load:use elm.onreadystatechange:"+u);
		this.element.onreadystatechange=(function(f,obj){
			if(this.readyState=="complete"){
				obj.window=obj.element.contentWindow;
				obj.document=obj.element.contentWindow.document;
				if(f){CONSOLE.log("IFrame:onload:"+G.dump(f));}
				f&&f.later(50,obj,obj.window,obj.document);
				this.onreadystatechange=null;
				CONSOLE.log("IFrame:onload:done");
			}
		}).bind(this.element,f,this);
	}
	this.element.src=u;
	if(!this.element.parentNode){
		// for opera onload
		document.body.appendChild(this.element);
		this.window=this.element.contentWindow;
		this.document=this.element.contentDocument||this.element.contentWindow.document;
	}
};

IFrame.prototype.write=function(str){
	this.load("about:blank",function(w,d){
		d.open();
		d.write(str);
		d.close();
	});
};

// see http://d.hatena.ne.jp/onozaty/20060802/p1
//     http://d.hatena.ne.jp/onozaty/20060803/p1

IFrame.prototype.getSizes=function(){
	this.sizetarget=this.document.compatMode=="BackCompat"?this.document.body:this.document.documentElement;
	var s=this.sizetarget;
	var r={
		content:{w:s.scrollWidth,h:s.scrollHeight},
		viewport:{w:s.clientWidth,h:s.clientHeight},
		bar:{h:0,v:0},
		scroll:{t:s.scrollTop,l:s.scrollLeft}
	};
	r.bar.v=G.atoi(G.currentStyle(this.element,"width"),0)-r.viewport.w;
	r.bar.h=G.atoi(G.currentStyle(this.element,"height"),0)-r.viewport.h;
	return r;
};

IFrame.prototype.resizeToContent=function(f){
	// need iframe frameborder="0" scrolling="no"
	var s=this.getSizes();
	this.element.height=s.content.h;
	this.element.width=s.content.w;
	if(f){
		return setInterval((function(){
			this.resizeToContent();
		}).bindThis(this),500);
	}
};

IFrame.prototype.createElement=function(){
	return this.document.createElement.apply(this.window,arguments);
};

G.IFrame=IFrame;


/************************* simple effects ********************/

/**
 * show Indicator.
 * 
 * @param {Object} str Indicate HTML string
 * @param {Object} delay show delay
 * @param {Object} h horizontal position l|c|r
 * @param {Object} v vertical position t|c|b
 */
function Indicator(str, delay, h, v) {
	delay=(delay===undefined)?1:Math.max(delay,1);
	var marker=doc.createElement("div"); this.marker = marker;
	marker.className="indicator";
	marker.innerHTML="<div style='padding:2px; margin:2px; border-style:none; position:absolute; /* background-color:#800;color:#fff; */'></span>";
	marker.style.cssText="position:absolute; margin:0; padding:0; background-color:transparent; border-style:none; font-size:small;z-index:1000; width:100%";
	var cs=clientSize(); var d=document;
	marker.style.marginLeft="-"+ (atoi(currentStyle(doc.body,"marginLeft"),0)+atoi(currentStyle(doc.body,"borderLeftWidth"),0)+atoi(currentStyle(doc.body,"paddingLeft"),0))+"px";
	marker.style.top=getPageYOffset()+2; marker.style.visibility="hidden"; doc.body.appendChild(marker);
	this.e = marker.firstChild;

	this.set(str); this._d = setTimeout(bindThis(marker,function(){this.style.visibility="visible";}),delay);
	this._t = setInterval(
		bindThis(this, function(){
			var cs=clientSize();
			(function(c,s){
				switch(v) {
					case "c": s.top=getPageYOffset()+Math.round((cs.height-this._pos.height)/2) + "px"; break;
					case "b": s.top=getPageYOffset()+cs.height-this._pos.height+"px"; break;
					case "t": default: s.top=getPageYOffset()+"px"; break;
				}
				switch(h) {
					case "l": c.left="0"; break;
					case "c": c.left=getPageXOffset()+Math.round(cs.width/2-this._pos.width/2)+"px"; break;
					case "r": default: c.left=getPageXOffset()+cs.width-this._pos.width+"px"; break;
				}
			})(this.marker.firstChild.style,this.marker.style);
/*
			with ({c:this.marker.firstChild.style, s:this.marker.style}) {
				switch(v) {
					case "c": s.top=getPageYOffset()+Math.round((cs.height-this._pos.height)/2) + "px"; break;
					case "b": s.top=getPageYOffset()+cs.height-this._pos.height+"px"; break;
					case "t": default: s.top=getPageYOffset()+"px"; break;
				}
				switch(h) {
					case "l": c.left="0"; break;
					case "c": c.left=getPageXOffset()+Math.round(cs.width/2-this._pos.width/2)+"px"; break;
					case "r": default: c.left=getPageXOffset()+cs.width-this._pos.width+"px"; break;
				}
			}
*/
		}),10);
};

Indicator.prototype.set = function(str) {
	this.e.innerHTML=(str===undefined?"":str);
	this._pos=pos(this.e, true);
};

Indicator.prototype.remove = function(str, delay) {
	delay=(delay===undefined)?(str?1000:1):Math.max(delay,1); if (str) this.set(str); clearTimeout(this._d);
	setTimeout(bindThis(this, function() { clearInterval(this._t); this._t=null; removeElement(this.marker)}), delay);
};

G.Indicator=Indicator;

/*
 * G.PHistory.add(on back function?); TODO
 */

G.PHistory = function(){
	var fr=doc.createElement("iframe");
	fr.id="phistory"; fr.name="phistory";
};


/**
 * make mask div element (z-index:e+1 or 100);
 * @param {htmlElement} e optional: target element (default:whole client area)
 * @param {string} cssText optional: cssText for mask
 * @param {string} className optional: class for mask element (default:mask)
 */
function createMask(e,cssText,className) {
	className=className||"mask"; cssText=cssText||""; var z=(e)?(atoi("0"+currentStyle(e,"zIndex"))):99, p;
	if(e){p=pos(e); p.z=z+1;}
	else{var c=clientSize(),d=documentSize(); p={top:0,left:0,width:Math.max(c.width,d.width),height:Math.max(c.height,d.height),z:z+1};}
	var m=doc.createElement("div"); doc.body.appendChild(m);
	m.className=className;
	m.style.cssText=cssText+";padding:0;margin:0;border-style:none;position:absolute;zoom:1;"
					+tmpl("width:${width}px;height:${height}px;top:${top}px;left:${left}px;z-index:${z};",p);
	return m;
};
G.createMask=createMask;

/**
 * make dummy div element for effects. <div><copy of htmlElement e /></div>
 * @param {htmlElement} e source element;
 */
function createDummy(e){
	var c=e.cloneNode(true), n=doc.createElement("div"), p=pos(e); n.appendChild(c);
	n.style.cssText="padding:0;margin:0;";
	/*
	for (var s in e.style) {
		var ss=s;
		switch(s) {
			case "length": case "cssText": case "parentRule": case "item": break;
			case "cssFloat": case "styleFloat": ss="float";
			default: try{var cs=currentStyle(e,ss); if (typeof cs=="string") {n.style[s]=cs;}}catch(ex){CONSOLE.error("createDummy():style="+s+":"+dump(ex));}
		}
	}
	n.style.width=p.width+"px"; n.style.height=p.height+"px"; n.style.padding="0"; n.style.borderStyle="none";
	//c.style.margin="0";
	c.style.left="0"; c.style.top="0";
	*/
	return n;
};
G.createDummy=createDummy;

/**
 * calculate inartia like start-end point
 * @param {number} s start number
 * @param {Object} e end number
 * @param {Object} t ticks count
 */
function calcAnim(s,e,t) {
	var ret=[]; for(var i=Math.PI; i<Math.PI*2; i+=Math.PI/t){ret.push(Math.round(s+(1+Math.cos(i))/2*(e-s)));} ret.push(e); return ret;
};
G.calcAnim=calcAnim;


/**
 * 
 * @param {number} s start number
 * @param {number} e end number
 * @param {Function} f on tick function(currentnumber)
 * @param {Function} c on complete function(currentnumber)
 * @param {number} t tick (default:10);
 * @param {number} i interval (default:50);
 */
function anim(s,e,f,c,t,i){
	t=(t===undefined)?10:t; i=(i===undefined)?50:i;
	var a=G.calcAnim(s,e,t);
	//CONSOLE.log("anim:"+a.join(","));
	var t=setInterval(function(){
		f(a.shift()); if (a.length==0){clearInterval(t);if(c){c();}}
	},i);
	return t;
};
G.anim=anim;


/**
 * e.style.display="none" and shutter up effect with dummy element
 * @param {htmlElement} e source element
 * @param {function} f on sutter complete functoin(e)
 */
function shadeup(e,f,tick){ // TODO: shading elements with srollbar
	tick=(tick===undefined)?8:tick;
	var p=pos(e,true), ctnr=createDummy(e); e.parentNode.insertBefore(ctnr,e); e.style.display="none";
	switch(ctnr.style.position) { case "absolute": case "relative": break; default: ctnr.style.position="relative";}
	var c=ctnr.firstChild; c.style.width=p.cw+"px"; c.style.position="absolute"; // clip は absoluteでないと効かない
	var an=calcAnim(0,p.height,tick);
	var doanim = bindThis({e:e, c:c, an:an, p:p, ctnr:ctnr, f:f},function(){
		var t=this.an.shift();
		var ob=window.offscreenBuffering;window.offscreenBuffering=true;
		this.ctnr.style.height=Math.max(0,this.p.ch-t)+"px";
		this.c.style.marginTop=(-1)*t+"px";
		this.c.style.clip=tmpl("rect(${t}px,${r}px,${b}px,${l}px)",{t:t,b:this.p.height,l:0,r:this.p.width});
		window.offscreenBuffering=ob;
		if (this.an.length==0){ clearInterval(tm); removeElement(this.ctnr); if (this.f){this.f(this.e); }}
	});
	var tm=setInterval(doanim,50);
};
G.shadeup=shadeup;

/**
 * e.style.display="none" -> e.style.display="" and shutter up effect with dummy element
 * @param {htmlElement} e source element
 * @param {object} p {width:(px),height:(px)}
 * @param {function} f on sutter complete functoin(e)
 * @param {object} pos for display  
 */
function shadedown(e,f,tick,p){
	//MEMO: IE has window.offscreenBuffering? http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/offscreenbuffering.asp
	//MEMO: Safari cannot get styles with display:none;
	tick=(tick===undefined)?8:tick;
	if (p===undefined) {
		var ob=window.offscreenBuffering; window.offscreenBuffering = true;
		e.style.display="block"; p=pos(e,true); e.style.display="none";
		window.offscreenBuffering = ob;
	}
CONSOLE.log("shadedown():pos="+p);
	var ctnr=createDummy(e); e.parentNode.insertBefore(ctnr,e);
	switch(ctnr.style.position) { case "absolute": case "relative": break; default: ctnr.style.position="relative";}
	var c=ctnr.firstChild; c.style.width=p.cw+"px"; c.style.position="absolute"; // clip は absoluteでないと効かない
	var an=calcAnim(p.height,0,tick);
	//ctnr.style.cssText+="visibility:visible;display:block;";
	ctnr.style.visibility="visible";ctnr.style.display="block";
	var doanim = bindThis({e:e, c:c, an:an, p:p, ctnr:ctnr, f:f},function(){
		var t=this.an.shift();
		var ob=window.offscreenBuffering; window.offscreenBuffering=true;
		this.ctnr.style.height=Math.max(0,this.p.ch-t)+"px";
		this.c.style.marginTop=(-1)*t+"px";
		this.c.style.clip=tmpl("rect(${t}px,${r}px,${b}px,${l}px)",{t:t,b:this.p.height,l:0,r:this.p.width});
		window.offscreenBuffering=ob;
		//c.style.cssText+="visibility:visible;display:block";
		c.style.visibility="visible";c.style.display="block";
		if (this.an.length==0){ clearInterval(tm); 
			var ob=window.offscreenBuffering; window.offscreenBuffering=true;
			//this.e.style.cssText+="visibility:visible;display:block";
			this.e.style.visibility="visible";this.e.style.display="block";
			//this.ctnr.parentNode.replaceChild(e,this.ctnr); 
			this.ctnr.parentNode.insertBefore(e,this.ctnr);
			G.removeElement(this.ctnr); this.ctnr=null;
			window.offscreenBuffering=ob;
			if (this.f){this.f(this.e);}
		}
	});
	var tm=setInterval(doanim,50);
};
G.shadedown=shadedown;

/**
 * toggle block element by another block
 * @param {htmlElement} s switch element
 * @param {htmlElement} t target element
 * @param {function} f on complete toggle function(ishidden)
 * @param {number} tick optional: tick count for animation
 */
function toggleBlock(s,t,f,tick){
	if (!toggleBlock._ctn) { toggleBlock._ctn=setStyleSheet(".tbctnr {padding:0;margin:0;border-style:none;overflow:hidden;} ");}
	return G.addEvent(s,"click", bindThis({s:s,t:t,f:f,tick:tick},function(e){
CONSOLE.log("toggleBlock():display="+currentStyle(this.t,"display"));
		if (toggleBlock._toggling){return stopBubble(G.parseEvent(e));}
		e=G.parseEvent(e); /*var p=pos(this.t);*/
		if (currentStyle(this.t,"display")=="none"){
			toggleBlock._toggling=true;
			shadedown(this.t, bindThis({f:this.f},function(e){toggleBlock._toggling=false; if(this.f){this.f(true)};}),this.tick);
		} else {
			toggleBlock._toggling=true;
			shadeup(this.t, bindThis({f:this.f},function(e){toggleBlock._toggling=false;if(this.f){this.f(false);}}),this.tick);
		}
		return stopBubble(e);
	}));
};
G.toggleBlock=toggleBlock;

/**
 * cross browser opacity css string.
 * @param {number} o opacity 0(transparent) to 1
 */
function opacity(o) {return tmpl("opacity:${o};-moz-opacity:${o};zoom:1;filter:alpha(opacity=${op})",{o:o,op:Math.floor(o*100)});};
G.opacity=opacity;

/**
 * cross browser opacity setting.
 * @param {htmlElement} e target element
 * @param {number} o opacity (0 to 1)
 */
function setOpacity(e,o){
	if (window.ActiveXObject){if(!e.currentStyle.hasLayout){e.style.zoom=1;} e.style.filter="alpha(opacity="+Math.floor(o*100)+")";}
	else {e.style.opacity=o; e.style.MozOpacity=o;}
};
G.setOpacity=setOpacity;

/**
 * G.fadeout element to visibility:hidden
 * @param {htmlElement} e target element
 * @param {number} ms optional: msec for G.fadeout (defalut:500)
 * @param {function} f optional: function(e,orgCssText) execute after G.fadeout completed
 * @return {function} css reset function(e,originalCssText)
 */
function fadeout(e,ms,f) {
	ms=ms||1000;var o=e.style.cssText, n=createDummy(e);
	setTimeout(bindThis({e:e,n:n},function(){this.e.style.display="none";this.e.parentNode.insertBefore(this.n,this.e);}),1); 
	var t=setInterval(bindThis({e:e,n:n,o:o,f:f}, function(){
		ms-=100;if(ms<5){clearInterval(t);
			e.style.cssText=this.o+";visibility:hidden;"; this.n.style.display="none";
			setTimeout(function(){removeElement(this);}.bindThis(this.n),10);if(this.f){this.f(this.e,o);}
			return;}
		setOpacity(this.n,(1-100/ms));
	}),100);
	return bindThis({e:e,o:o},function(){this.e.style.cssText=this.o;});
};
G.fadeout=fadeout; 

/**
 * G.fadein visibility:hidden element to visibility:visible
 * @param {htmlElement} e target element
 * @param {number} ms optional: msec for G.fadein (default:500)
 * @param {function} f optional: function(e,orgCssText) execute after G.fadein completed
 * @return {function} css reset function
 */
function fadein(e,ms,f) {
	ms=ms||1000;var r, a, o=e.style.cssText;
	(r?r.e:e).style.visibility="visible"; setOpacity(e,0);
	var t=setInterval((function(e,r,ms,o,f){
		return function(){
			ms=ms-100;if(ms<5){clearInterval(t);if(r){r();} e.style.cssText=o+";visibility:visible;";if(f){f(e,o);} return;}
			setOpacity((r?r.e:e),(100/ms));
		};})(e,r,ms,o,f),100);
	return (function(e,o){return function(){if(r){r();} if(e){e.style.cssText=o;e=null;o=null;}};})(a,o,r);
};
G.fadein=fadein;

/**
 * vibration element
 * @param {htmlElement} e target element
 * @param {number} ms optional: msec for G.vibrate (default:500)
 * @param {function} optional: function(e) execute after vibration complete
 */
function vibrate(e,ms,f) {
	ms=(ms===undefined)?500:ms;var ot=atoi("0"+currentStyle(e,"top")),ol=atoi("0"+currentStyle(e,"left"));
	var oc=e.style.cssText, cnt=0, P=vibrate._P;
	if (currentStyle(e,"position")!="absolute") {e.style.position="relative";}
	var it=setInterval((function(e,f){return function(){
		if(cnt*50>ms){clearInterval(it);e.style.cssText=oc;if(f){f(e);} return;}
		e.style.top=ot+P[cnt%P.length][0]+"px"; e.style.left=ol+P[cnt%P.length][1]+"px"; cnt++;
	};})(e,f),50);
};
vibrate._P = [[-3,0],[0,-3],[0,3],[3,0]];
G.vibrate=vibrate;

/**
 * add drop shadow divs.
 * insert a div element as firstchild
 * @param {htmlElement} e target
 */
function addShadow(e) {
	if(!addShadow._s) {addShadow._s = G.setStyleSheet(
			".dropshadow {margin:0;padding:0;line-height:0;font-size:0;position:relative;border-style:none;width:0;height:0;}"+
			".dropshadow * { left:10px; top:10px; "+
			" border-style:none;margin:0;padding:0;line-height:0;font-size:0;position:absolute;" +
			" background:url("+G._BASEPATH+"dropshadow.png) no-repeat right bottom; background-color:transparent; " +
			" opacity:0.3; -moz-opacity:0.3; filter:alpha(opacity=30),progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+G._BASEPATH+"dropshadow.png')} "
	);}
	switch(e.style.position){ case "absolute": case "relative": break; default: e.style.positon="relative"; }
	var s=doc.createElement("div"); s.className="dropshadow"; s.innerHTML="<div></div><div></div>";
	e.insertBefore(s, e.firstChild);
	var resizeFunc=bindThis({s:s,e:e},function(){
		var e=this.e,s=this.s,p=pos(e),zi=atoi(currentStyle(e,"zIndex"),0)-1;
		s.style.cssText="left:-"+(atoi(currentStyle(e,"paddingLeft"),0)+atoi(currentStyle(e,"borderLeftWidth",0)))+"px;"
			+"top:-"+(atoi(currentStyle(e,"paddingTop"),0)+atoi(currentStyle(e,"borderTopWidth"),0))+"px;z-index:"+zi+";";
		s.firstChild.style.cssText="width:10px;height:"+p.height+"px;left:"+p.width+"px";
		s.lastChild.style.cssText="width:"+(p.width-10)+"px;height:10px;background-position:left bottom;top:"+(p.height)+"px";
		//CONSOLE.log("shadow resize");
	});
	resizeFunc();
	//G.addEvent(window,"resize",resizeFunc); // 動きがいまいち
	//G.addEvent(e,"resize",resizeFunc); // 動きがいまいち
	s._resizeNotify=resizeFunc;
	return s;
};
G.addShadow=addShadow;

/* test */
function Marquee(b,c){
	this.box=b;
	switch(G.currentStyle(b,"positon")){
		case "relative": case "absolute":
			break;
		default:
			b.style.position="relative";
	}
	this.cont=c;
	c.style.whiteSpace="nowrap;";
	c.style.position="absolute";
	this._orgleft=c.style.left;
}
Marquee.prototype.start=function(interval){
	interval=interval||200;
	this._timer=setInterval((function(){
		if(!this.cont){clearInterval(this._timer);return;}
		var left=G.atoi((G.currentStyle(this.cont,"left")||"0px").replace("px",""));
		this.cont.style.left=left-4+"px";
	}).bindThis(this),interval);
};
Marquee.prototype.reset=function(){
	clearInterval(this._timer);
	this.cont.style.left=this._orgleft;
};
G.Marquee=Marquee;

/**
 * create popupmenu (display:none)
 * @param {object} md object for menu.
 * [
 *  {l:"label", // or lh:"label html"
 *   f:function(e){clicked process}, // onclick
 *   s:true, // ispmenusep
 *   m:[ <submenudef> ] // submenu
 *  },
 * ]
 * sample css .pmenu { list-style-type:none; font-size:x-small;  }, .focuseditem { }
 * @param {string} css width for menu
 */
function PopupMenu(md, w) {
	w=(w===undefined)?"7em":w;
	if (!PopupMenu._s) { PopupMenu._s = G.setStyleSheet(
		".pmenu { text-align:left; cursor:default; z-index:10000; margin:0; padding:0; position:absolute; list-style-type:none; /* font-size:small; */ font-family:sans-serif; } " +
		".pmenu li { padding:2px 0.5em; position:relative; white-space:nowrap; } " +
		".pmenu li.pmenusep { padding:0; margin:2px auto; height:0; width:95%; font-size:0px; line-height:0px; } " +
		".pmenu img { vertical-align:middle; border:none; }"+
		".pmenu .pmenu { display:none; } " +
		".pmenu .focusedpmitem .pmenu { display:block; } " +
		".pmenu .pmsub { background: url("+G._BASEPATH+"tricl12.png) no-repeat right center; } " +
		"" +
		"/* windows classic style */ " +
		".pmenu { background-color:#bbb; color:black; border-top:2px solid #ddd; border-left:2px solid #ddd; border-bottom:2px solid #888; border-right:2px solid #888; } " +
		".pmenu li.pmenusep { border-top:1px solid #999; border-bottom:1px solid #ddd; } " +
		".pmenu li.focusedpmitem { color:white; background-color:#009;} " +
		".pmenu li.focusedpmitem .pmenu { background-color:#bbb;} " +
		"" +
		"/* windows XP style */ " +
		".pmenu { background-color:white; color:black; border:1px solid #bb9; padding:2px; } " +
		".pmenu li.pmenusep { border-style:none; border-top:1px solid #bb9; } " +
		".pmenu li.focusedpmitem .pmenu { background-color:white;} "
	);}
	var m=doc.createElement("ul"), sms=[];
	m.id="pmenu-"+(PopupMenu._cnt++);
	m.className="pmenu"; m.style.position="absolute"; m.style.width=w;
	G.each(md, function(v){
		var l=doc.createElement("li"); m.appendChild(l);
		if ("l" in v || "lh" in v){
			l.innerHTML=v.l?G.esc(v.l):v.lh;
			if(v.f){
				G.setHover(l,
					function(e){G.addClassName(this,"focusedpmitem");},
					function(e){G.removeClassName(this,"focusedpmitem");}
				);
			}
		}
		if ("m" in v){
			var cm=new PopupMenu(v.m); sms.push(cm); l.appendChild(cm.e); G.addClassName(l, "pmsub");
			G.setHover(l,(function(l,cm){return function(e){
				var p=G.pos(l,true);
				cm.show(0,p.width-8);
			};})(l,cm));
		}
		if ("f" in v){var cf=function(e){e=G.parseEvent(e);v.f(e);return stopBubble(e);}; G.addEvent(l,"mouseup",cf); G.addEvent(l,"click",function(e){return stopBubble(G.parseEvent(e));}); G.addEvent(l,"mousedown",function(e){return stopBubble(G.parseEvent(e));});}
		if ("s" in v){l.className="pmenusep";}
	});
	doc.body.appendChild(m); 
	this.e=m;
	/*
	G.setHover(m,null,(function(pm){return function(e){
		pm.hide();
	};})(this));
	*/
	
	//(function (){this._shadow=addShadow(m);}).bindThis(this).later(1000);
	//return m;
};
PopupMenu._cnt=0;
PopupMenu.prototype.show=function(x,y){
	this.e.style.top=y+"px";
	this.e.style.left=x+"px";
	if(this.e.style.display=="block"){return;}
	this.e.style.display="block";
	this._eh=[
		G.addEvent(document,"click",(function(ev){
			ev=G.parseEvent(ev);
			if(!ev.click.l){return;}
			if(!G.$SA(ev.target,"#"+this.e.id)){
				this.hide();
				return G.stopBubble(ev,true);
			}
		}).bindThis(this)),
		G.addEvent(document,"keypress",(function(ev){
			ev=G.parseEvent(ev);
			if(ev.keyAsc==27){
				this.hide();
				return G.stopBubble(ev,true);
			}
		}).bindThis(this))
	];
};
PopupMenu.prototype.hide = function(){
	this.e.style.display="none";
	while(this._eh&&this._eh[0]){
		G.removeEvent(this._eh.pop());
	}
	G.$C({c:"focusedpmitem",f:function(e){G.removeClassName(e,"focusedpmitem");}});
};

G.PopupMenu=PopupMenu;

/**
 * create tree
 * @param {object} td object for tree.
 * [{l:"label",f:function(e){clicked process},c:[childtree td] },...]
 * sample css .pmenu { list-style-type:none; font-size:x-small;  }, .focuseditem { }
 * @param {string} css width for menu
 * @param {boolean} optional:expandall defalult:false
 * @return {htmlUlElement} element
 */
function tree(td,w,f) {
	w=(w===undefined)?"":w; f=(f===undefined)?false:f;
	if (!tree._s) { tree._s = setStyleSheet(
		".tree { list-style:none } " +
		".tree, .tree * { cursor:default; margin:0; padding:0; font-family:sans-serif; } " +
		".tree .treelabel { }" +
		".tree .tree {margin-left:1em}"
	);}
	var d=doc.createElement("ul"); d.className="tree"; d.style.width=w;
	G.each(td, function(v) {
		var sd=doc.createElement("li"); d.appendChild(sd);
		if ("l" in v){
			var a=doc.createElement("label"); a.className="treelabel"; a.innerHTML=v.l;
			sd.appendChild(a);
		}
		if ("c" in v){
			G.addClassName(sd.firstChild,"treefolderlabel")
			var ct=tree(v.c); sd.appendChild(ct);
			if(!f){ct.style.display="none";}
			toggleBlock(a,ct,null,3);
		}
		if ("f" in v){var cf=function(e){e=G.parseEvent(e);if(e.currentTarget==e.target)v.f(e);return stopBubble(e);}; G.addEvent(a,"click",cf);}
	});
	return d;
};
G.tree=tree;

function genTreeDefFromObj(o,fo,fn){
	fo=(fo===undefined)?function(p,v){return {l:"["+p+"]"};}:fo;
	fn=(fn===undefined)?function(p,v){return {l:" "+p+":"+v}}:fn;
	var r=[];
	G.each(o,function(v,p){
		if(isObject(v)){ var d=fo(p,v,o); d.c=genTreeDefFromObj(v,fo,fn); r.push(d);}
		else{var d=fn(p,v,o); r.push(d);}
	});
	return r;
}
G.genTreeDefFromObj=genTreeDefFromObj;

/**
 * genTreeDefFromXML converts XML string to E4X like object (without xml header).
 * @param {string} str source XML string
 */
function genTreeDefFromXML(str) {
	var ret=[],m,s=0,a,c=ret,p=[],t,pn=[];
	function addN(o,p,v){ if(!(v instanceof Array)){o.push({l:p,v:v,f:function(){alert(this.v);}});}else{o.push({l:"&lt;"+p+"&gt;", c:v});} }
	var add=addN;
	function addAttrs(o,str){
		var m,r=new RegExp("\\s*(([^\\s=]+?)\\s*=\\s*\"(.*?)\"|([^\\s=]+?)\\s*=\\s*'(.*?)')\\s*","gm");
		while((m=r.exec(str))){if(m===null){break;} o.push({l:"@"+(m[2]||m[4]),v:unesc((m[3]||m[5]),"X"),f:function(){alert(this.v)}}) ;}
	}
	var r = new RegExp("("+[fromXML.XMLDECL_STR,fromXML.COMMENT_STR,fromXML.CDATA_STR,
							fromXML.OPTAGRX_STR,fromXML.CLTAGRX_STR,fromXML.OCTAGRX_STR].join("|")+")", "gm");
	var no;
	while((m=r.exec(str))){
		if (m===null) {break;}
		t=str.substring(s,r.lastIndex-m[0].length); if(t&&t.length>0){ add(c,"#text",unesc(t,"X")); }
		if(m[5]!==undefined){no=[];if(m[6]){addAttrs(no,m[6]);} add(c,m[5],no); p.push(c); pn.push(m[5]); c=no; }//OP
		else if(m[7]!==undefined){ //CL
			/*
			if (!n) {
				var cn=0; for (var pr in c){ if (c.hasOwnProperty(pr)){cn++;} }
				if (cn==1&&("#text" in c)) {p[p.length-1][pn[pn.length-1]]=c["#text"];}
			}
			*/
			c=p.pop(); pn.pop();
		}
		else if(m[8]!==undefined){no=[];if(m[9]){addAttrs(no,m[9]);} add(c,m[8],no);}//OPCL
		else if(m[3]!==undefined){add(c,"#comment",m[3]);}//COMMENT
		else if(m[4]!==undefined){add(c,"#cdata-section",m[4]);}//CDATA
		else if(m[2]){}//DECL
		s=r.lastIndex;
	}
	//CONSOLE.log(toJSON(ret,true));
	return ret;
};
G.genTreeDefFromXML=genTreeDefFromXML;

/**
 *  document auto scroll vertical
 * @param {boolean} f optional: true/false
 */
function autoscroll(f) {
	if (f||f===undefined) {
		function scrollin(cx, cy, cs) {
			var ox=getPageXOffset(),oy=getPageYOffset()
			if (cy < 15) {scrollBy(0,Math.round((cy-15)/1.5)) } else if (cy > cs.height - 15) {scrollBy(0,Math.round((15-cs.height+cy)/1.5)) }
			//if (cx < 15) {scrollBy(Math.round((cx-15)/1.5),0) } else if (cx > cs.width - 15) {scrollBy(Math.round((15-cs.width+cx)/1.5),0) }
			if (ox!=getPageXOffset()||oy!=getPageYOffset()) autoscroll._t=setTimeout(bindThis({cx:cx, cy:cy, cs:cs }, function(){scrollin(this.cx, this.cy, this.cs)}), 15);
		}
		autoscroll._e=G.addEvent(document, "mousemove", function(e) {
			clearTimeout(autoscroll._t); var cs = clientSize(); e=G.parseEvent(e); scrollin(e.clientX, e.clientY, cs);
		});
	} else { autoscroll._e && G.removeEvent(autoscroll._e); delete autoscroll._e; }
};
G.autoscroll=autoscroll; 

/**
 * element resizable
 * @param {htmlElement} e target element;
 * @param {string} css cursor style for resizable mark ()
 * @param {function} optional: onresizestart on resize start function(event, element, maskElement)
 * @param {function} optional: onresizing on resizing function(event, element, maskElement);
 * @param {function} optional: onresizefix on fix function(event, elment);
 */
function setResizable(e,cursor,onresizestart, onresizing,onresizefix) {
	cursor=(cursor)?cursor:"se-resize"; var redo;

	G.addEvent(e, "mousemove", bindThis({e:e, c:cursor}, function(ev) {
		ev=G.parseEvent(ev); var p=pos(this.e,true), ox=p.left+p.width, oy=p.top+p.height;
		if (ox-8 < ev.pos.x && ev.pos.x <= ox && oy-8 < ev.pos.y && ev.pos.y <= oy) { this.e.style.cursor=this.c;}
		else { this.e.style.cursor=""}
		return stopBubble(ev);
	}));

	G.addEvent(e, "mousedown", bindThis({e:e, cursor:cursor, onresizestart:onresizestart, onresizing:onresizing, onresizefix:onresizefix },function(ev) {
		ev=G.parseEvent(ev);
		if (currentStyle(this.e, "cursor")!=this.cursor) { return stopBubble(ev,false); }
		var os=this.e.style.cssText, m=createMask(); m.style.cursor="se-resize";
		m.style.backgroundColor="white"; setOpacity(m,0.5); 

		// this.epos: pos(e) when mouse down, this.o: ev.pos when mouse down 
		var e1 = G.addEvent(m, "mousemove",
		bindThis({m:m, e:this.e, epos:pos(this.e,true), o:ev.pos, f:this.onresizing }, function(ev) {
			ev=G.parseEvent(ev); var w= this.epos.cw + (ev.pos.x - this.o.x), h=this.epos.ch + (ev.pos.y - this.o.y);
			this.e.style.width=w+"px"; this.e.style.height=h+ "px";
			var c=documentSize();
			m.style.height=c.height+"px"; m.style.width=c.width+"px";
			if (this.f){this.f(ev,this.e,this.m)}
			return stopBubble(ev);
		}));

		// this.m: mask element,  this.e:e, this.e1:event, this.e2:event
		var e2 = G.addEvent(m, "mouseup",
		bindThis({m:m, e:this.e, e1:e1, e2:e2, cursor:this.cursor, f:this.onresizefix }, function(ev) {
			ev=G.parseEvent(ev); G.removeEvent(this.e1); G.removeEvent(this.e2); removeElement(this.m);
			this.e.style.cursor="auto"; if (this.f) {this.f(ev,this.e);} // onresizefix()
			return stopBubble(ev);
		}));

		if (this.onresizestart) {this.onresizestart(ev, this.e, m)}
		return stopBubble(ev);
	}))
};
G.setResizable=setResizable;

/**
 * edit inner text (or html).
 * focus out : fix, esc key : cancel
 * @param {htmlElement} e target element
 * @param {boolean} f optional: if true, edit HTML source. (default:false)
 * @param {function} sf optional: function onstartedit(inputelement,originalelement);
 * @param {function} ef optional: function onendedit(originalelement,newvalue,inputelement);
 */
function editInnerText(e,f,sf,ef) {
	if (e._editing) {return;} e._editing=true;
	f=(f===undefined)?false:f; var p=pos(e,true), nt="textarea";
	var ed={cw:Math.max(p.cw,150),ch:p.ch};
	switch(currentStyle(e,"display")){ case "inline": case "run-in": case "inline-table": nt="input";}
	if(nt=="textarea"){ed.ch=Math.max(p.ch,50);}
	var n=e.cloneNode(false),ie=doc.createElement(nt),os=e.style.cssText;
	ie.style.cssText=
		"margin:-2px;padding:0;font-family:inherit;font-style:inherit;background-color:inherit;color:inherit;font-size:inherit;"
		+"overflow:visible;"
		+tmpl("width:${cw}px;height:${ch}px;",ed);
	if (f) {ie.value=e.innerHTML;}
	else {
		n.innerHTML=e.innerHTML.replace(/\r?\n/g,"").replace(/<(br|\/h\d+|p|\/div|\/tr)\s*\/?>/ig,"\u0001");
		ie.value=(n.textContent||n.innerText||"").replace(/\u0001/g,"\n");
		n.innerHTML="";
	}
	n.appendChild(ie); e.style.display="none"; e.parentNode.insertBefore(n,e);
	setResizable(ie); ie.focus();
	var e1=G.addEvent(ie, "blur", bindThis({e:e,n:n,ie:ie,os:os,ef:ef}, function(){
		e=G.parseEvent(e); var v=this.ie.value; this.e.innerHTML=esc(v).replace(/\n/g,"<br/>");
		this.e.style.cssText=this.os; removeElement(this.n); this.e._editing=null;
		if (this.ef){this.ef(this.e,v,this.ie);}
		return stopBubble(e,false);
	}));
	var e2=G.addEvent(ie, "keyup", bindThis({e:e,n:n,ie:ie,os:os}, function(e){
		e=G.parseEvent(e);var r=false;
		if (e.keyCode===27 /* ESC */) {r=true; removeElement(this.n); this.e.style.cssText=this.os; this.e._editing=null;}
		return stopBubble(e,r);
	}));
	if (sf){sf(ie,e);}
};
G.editInnerText=editInnerText;

/**
 * select all text in INPUT type=text
 * @param {htmlInputElement} e
 */
function inputSelectAll(e){
		if (e.createTextRange){ //IE
			var r=e.createTextRange();e.focus();
			r.move("character", (-1)*e.value.length); // んー…
			r.moveStart("character", 0);
			r.moveEnd("character", e.value.length-0);
			r.select();
			e.focus();
		} else if (e.setSelectionRange) {
			e.focus(); e.setSelectionRange(0, e.value.length);
		}
};
G.inputSelectAll=inputSelectAll;

function setAutoInputSelectAll(e){
	G.each(G.$C({t:/^(input|textarea)$/i},e),function(e){
		switch(e.tagName.toLowerCase()){
			case "input":
				if(e.type!="password"&&e.type!="text"&&e.type!=""){return;}
			case "textarea":
				G.addEvent(e,"focus",G.inputSelectAll.bindArgs(e));
		}
	});
}
G.setAutoInputSelectAll=setAutoInputSelectAll;

/**
 * usage:
 * <div id="wizelem">
 *   <div class="wizpage">...page1....<input name="_wizcancel"><input name="_wiznext"></div>
 *   <div class="wizpage">...page2....<input name="_wizcancel"><input name="_wizprev"><input name="_wiznext"></div>
 *   <div class="wizpage">...page3....<input name="_wizcancel"><input name="_wizprev"><input name="_wiznext"></div>
 *   <div class="wizpage">...page4....<input name="_wizcancel"><input name="_wizprev"><input name="_wizcomplete"></div>
 * </div>
 * var wiz=new Wizard(G.$("wizelem"));
 * wiz.onNext=function(idx){if(err){return function(wiz){onerror}}}; // onPrev,onCancel,onComplete ,onEnable
 * wiz.onCancel=function(idx){if(err){return function(wiz){onerror}}}; // true -> break cancel;
 * wiz.onComplete=function(idx){if(err){return function(wiz){onerror}}}; // true -> break complete;
 * wiz.start();
 * @param {Object} e
 */

function Wizard(e){
	if(!Wizard._s){Wizard._s=setStyleSheet(".wizpage { display:none } ")}
	this.e=e; this.seq=G.$S(".wizpage",e); this.cur=0; this.last=-1;
	G.addEvent(e,"click",G.bindThis(this,wizClickHandler));
	function wizClickHandler(e){
		e=G.parseEvent(e);
		var btn;
		if(e.target.tagName.toLowerCase()=="input"){
			btn=e.target.name;
		}
		switch(btn){
			case "_wiznext": this.next(); break;
			case "_wizprev": this.prev(); break;
			case "_wizcancel": this.cancel(); break;
			case "_wizcomplete": this.complete(); break;
			default: return G.stopBubble(e,false);
		}
		return G.stopBubble(e,true);
	}
}
Wizard.prototype.onEnable=wizonenable;function wizonenable(idx,wiz,lastidx){};
Wizard.prototype.onNext=wizonnext;function wizonnext(idx,wiz){};
Wizard.prototype.onPrev=wizonprev;function wizonprev(idx,wiz){};
Wizard.prototype.onCancel=wizoncancel;function wizoncancel(idx,wiz){};
Wizard.prototype.onComplete=wizoncomplete;function wizoncomplete(idx,wiz){};

Wizard.prototype.start=function wizstart(f){
	f&&f(this);
	this.last=-1;
	this.enable(0);
};
Wizard.prototype.enable=function wizenable(idx,f){
	this.seq[this.cur].style.display="none";
	this.cur=idx;
	this.seq[idx].style.display="block";
	if(idx>this.last){
		this.onEnable(idx,this,this.last);
	}
	this.last=idx;
	if(f){f(idx,this);}
};
Wizard.prototype.next=function wiznext(f){
	var self=this;
	((f||this.onNext)(this.cur,this)||function(){self.enable(self.cur+1);})(this);
};
Wizard.prototype.prev=function wizprev(f){
	var self=this;
	((f||this.onPrev)(this.cur,this)||function(){self.enable(self.cur-1);})(this);
	//var f=this.onPrev(this.cur,this);if(typeof f=="function"){f(this);}else{this.enable(this.cur-1);}
};
Wizard.prototype.cancel=function wizcancel(f){
	var self=this;
	((f||this.onCancel)(this.cur,this)||function(){self.enable(0);})(this);
	//var f=this.onCancel(this.cur,this);if(typeof f=="function"){f(this);}else{this.enable(0);}
};
Wizard.prototype.complete=function wizcomplete(f){
	((f||this.onComplete)(this.cur,this)||function(){})(this);
	//var f=this.onComplete(this.cur,this);if(typeof f=="function"){f(this);}else{}
};

G.Wizard=Wizard;

/**
 * usage:
 * <body>.......<div id="idforwizard">dialog content</div></body>
 * var dlg=new Dialog(G.$("idforwizard"));
 * dlg.onShow=function(elem){}; dlg.onHide=function(elem){};
 * dlg.show(); dlg.hide();
 * @param {htmlElement} e target block element
 */
function Dialog(e){
	if(!Dialog._s){Dialog._s=setStyleSheet(
			".dialog { position:absolute; width:50%; height:auto; background-color:white; top:0; left:0;border:1px solid black; z-index:200; display:none; } "+
			".dialogmask {position:absolute; background-color:#000;"+opacity(0.25)+"; z-index:199; display:none; } "+
			"/* body.showingdialog select, body.showingdialog embed, body.showingdialog object {visibility:hidden;} */ "+
			"/* body.showingdialog .dlgshowing select, body.showingdialog .dlgshowing embed, body.showingdialog .dlgshowing object {visibility:visible;} */ "
		);
		var im=doc.createElement("iframe");
		im.src=G._BASEPATH+"dummy.html";
		im.style.cssText="z-index:199;display:none;border:none;margin:0;padding:0;";
		im.className="dialog";
		doc.body.appendChild(im);
		Dialog.prototype.im=im;
	}
	var ob=window.offscreenBuffering;window.offscreenBuffering=true;
	var d=documentSize(), c=clientSize();
	G.addClassName(e,"dialog");e.style.display="block"; /*this._shadow=addShadow(e);*/ e.style.display="none";
	window.offscreenBuffering=ob;
	this.e=e; //this.m=m;
};
Dialog.prototype.show = function(){
	Dialog.showing=true;
	G.addClassName(this.e,"dlgshowing");
	G.addClassName(doc.body,"showingdialog");
	var ob=window.offscreenBuffering;window.offscreenBuffering=true;
	//this.m.style.display="block";
	var m=createMask(); G.addClassName(m,"dialogmask"); m.style.display="block"; this.m=m;
	this.e.style.display="block";
	function centerize(e){
		var c=clientSize(),p=pos(e);
		var t=Math.max(0,getPageYOffset()+Math.floor((c.height-p.height)/2));
		var l=Math.max(0,getPageXOffset()+Math.floor((c.width-p.width)/2));
		e.style.top=t+"px"; e.style.left=l+"px";
		return {top:t,left:l,width:p.width,height:p.height};
	}
	var a=centerize(this.e);
	if(this.im){
		this.im.style.display="block";
		this.im.style.width=a.width+"px";this.im.style.height=a.height+"px";
		this.im.style.top=a.top+"px";this.im.style.left=a.left+"px";
	}
	this.e.focus(); if(this.onShow){this.onShow(this.e);}
	window.offscreenBuffering=ob;
};
Dialog.prototype.hide = function(){
	Dialog.showing=false;
	G.removeClassName(this.e,"dlgshowing");
	G.removeClassName(doc.body,"showingdialog");
	var ob=window.offscreenBuffering;window.offscreenBuffering=true;
	removeElement(this.m); this.e.style.display="none"; if(this.im){this.im.style.display="none";}
	if(this.onHide){this.onHide(this.e);}
	window.offscreenBuffering=ob;
};
Dialog.prototype.resizeNotify = function(){
	function centerize(e){
		var c=clientSize(),p=pos(e);
		var t=Math.max(0,getPageYOffset()+Math.floor((c.height-p.height)/2));
		var l=Math.max(0,getPageXOffset()+Math.floor((c.width-p.width)/2));
		e.style.top=t+"px"; e.style.left=l+"px";
		return {top:t,left:l,width:p.width,height:p.height};
	}
	var a=centerize(this.e);
	if(this.im){
		this.im.style.display="block";
		this.im.style.width=a.width+"px";this.im.style.height=a.height+"px";
		this.im.style.top=a.top+"px";this.im.style.left=a.left+"px";
	}
};
G.Dialog=Dialog;

/**
 * tab and tab contents
 * <elem id="NAME">
 *  <elem id="NAME_SUB1">...</elem>
 *  <elem id="NAME_SUB2">...</elem>
 * </elem>
 * <elem id="NAME_SUB1_cont">...</elem>
 * <elem id="NAME_SUB2_cont">...</elem>
 * new Tabs(G.$("NAME"),{ "NAME_SUB1":function(contElem,tabElem){...} });
 * class:"tabselected", "tabselectedcont"
 * 
 * @param {htmlElement} e element include tab elements
 * @param {Object} fs { "tabid":onEnableFunction(tebcontElem,tabElem),... } 
 */
function Tabs(e,fs,style){
	if (Tabs._s == undefined) {
		Tabs._s = setStyleSheet(".tabselected { font-weight:bold; } .tabcont { display:none; } .tabcont.tabselectedcont { display:block; } ");
	}
	this.baseId=e.id; this.tabs=[]; this.contents={}; this.onenable=fs;
	this._initializedtab={};
	G.each(G.$C({i:new RegExp(esc("^"+e.id+"_","R"))},e),bindThis(this,function(te){
		//CONSOLE.log("Tabs:found tab:"+getXPath(te));
		this.tabs.push(te); 
		if(G.$(te.id+"_cont")){
			this.contents[te.id]=G.$(te.id+"_cont");
			//CONSOLE.log("Tabs:found cont:"+getXPath(G.$(te.id+"_cont")));
			G.addClassName(G.$(te.id+"_cont"),"tabcont");
			G.addEvent(G.$(te.id),"click",bindThis({t:this,te:te},function(e){
				e=G.parseEvent(e);
				if(!e.click.l){return;}
				//if(e.target!=te){return;}
				this.t.enable(this.te);
				//return stopBubble(e,true);
			}));
		}
	}));
}
Tabs._tmpcnt=0;
Tabs.prototype.add = tabsadd;
function tabsadd(tabelm, tabcontelm){
	if(!tabelm.id){tabelm.id="tmptab-"+Tabs._tmpcnt++;}
	this.tabs.push(tabelm);
	G.addClassName(tabcontelm,"tabcont");
	G.addEvent(tabelm,"click",bindThis({t:this,te:te},function(e){
		e=G.parseEvent(e);
		if(!e.click.l){return;}
		if(e.target!=te){return;}
		this.t.enable(this.te);
		//return stopBubble(e,true);
		//return stopDefault(e,true);
	}));
};
/**
 * @param {htmlElement} tab element for enable
 * @param {boolean} c cancel on enable (default false)
 */
Tabs.prototype.enable = tabsenable;
function tabsenable(e,c){
	c=(c===undefined?false:c);
	this._lastenabled=this._enabled;
	this._enabled=e; this._cancelenable=c;
	G.each(this.tabs, G.bindThis(this,function(te){
		if(te.id==this._enabled.id){
			G.addClassName(this.contents[te.id],"tabselectedcont");
			G.addClassName(te,"tabselected");
			if(this.onenable&&!this._cancelenable){
				var initid=te.id+":init";
				if(!this._initializedtab[initid]){
					this._initializedtab[initid]=true;
					if(this.onenable["*:init"]){
						this.onenable["*:init"].later(1,this,this.contents[te.id],te,this);
					}
					if(this.onenable[initid]){
						this.onenable[initid].later(1,this,this.contents[te.id],te,this);
					}
				}
				if(this.onenable["*"]){
					this.onenable["*"].later(1,this,this.contents[te.id],te,this);
				}
				if(this.onenable[te.id]){
					this.onenable[te.id].later(1,this,this.contents[te.id],te,this);
				}
			}
		} else {
			G.removeClassName(this.contents[te.id],"tabselectedcont");
			G.removeClassName(te,"tabselected");
		}
	}));
	//e.scrollIntoView();
};
Tabs.prototype.remove=function(){
	G.each(this.contents,function(v,p,o){
		G.removeElement(v); delete o[p];
	});
	G.each(this.tabs,function(v,p,o){
		G.removeElement(v); delete o[p];
	});
};
G.Tabs=Tabs;

function normalizeHtml(str,mode,f){
	if(G.isIPhone&&mode=="html"){return str;}
	var div=normalizeHtml.doc || doc.createElement("div"),ret="";
	div.style.cssText="visibility:hidden;position:absolute;background:none transparent;width:0;height:0;";
	if(mode=="text"){
		str=str.replace(/<[^<]*$/,"");
		str=str.replace(/<(img[^>]*)>/gi,"");
	}
	div.innerHTML=str;
	f&&f(div);
	switch(mode){
		case "xhtml": ret=G.getXhtml(div); break;
		case "dom": ret=div.cloneNode(true); break;
		//case "text": ret=G.isMSIE?div.innerText.replace(/<[^<]*$/,""):div.textContent; break;
		case "text": ret=G.isMSIE?div.innerText:div.textContent; break;
		default: ret=div.innerHTML;
	}
	//div=null;
	return ret;
}
G.normalizeHtml=normalizeHtml;

function scrollIntoView(e,scr,margin){
	margin=margin||0;
	/*
	if(!scr){
		scr=document.documentElement;
		if(e.scrollIntoView){
			e.scrollIntoView();
			return;
		}
	}*/
	if(!scr){
		scr=G.findAncestor({f:function(e){
			var of=G.currentStyle("overflow");
			switch(of){
				case "hidden": case "visible":
					return;
			}
			var ofY=G.currentStyle("overflowY");
			switch(ofY){
				case "hidden": case "visible":
					return;
			}
			return true;
		}});
	}
	if(!scr){
		scr=dedb;
		var spos={
			"top":0-G.getPageYOffset(),
			"bottom":G.clientSize().height-G.getPageYOffset()
		}
	}else{
		var spos=G.pos(scr);
	}
	var pos=G.pos(e);
	if(pos.bottom>spos.bottom){
		scr.scrollTop+=pos.bottom-spos.bottom+margin;
		pos.top-=pos.bottom-spos.bottom+margin;
	}
	if (pos.top < spos.top) {
		scr.scrollTop-=spos.top-pos.top+margin;
	}	
}
G.scrollIntoView=scrollIntoView;

function setwait(){
	setwait._cnt++;
	if (setwait._s){return;}
	setwait._s=setStyleSheet("* {cursor:wait!important;}");
}
function clearwait(){
	setwait._cnt--;
	if(setwait._cnt==0){removeStyleSheet(setwait._s); delete setwait._s;}
}
setwait._cnt=0;
G.setwait=setwait;
G.clearwait=clearwait;

// 登録したイベントの後処理
G.addEvent(document,"beforeunload",function(e){G.each(addEvent._list, function(i){G.removeEvent(G.addEvent._list[i]);});});
G.addEvent(document,"unload",function(e){G.each(G.addEvent._list, function(i){G.removeEvent(G.addEvent._list[i]);});});

// エラーはコンソールに → eがイベントになるのがつらいのでやめておく？
//G.addEvent(window,"error",function(e){CONSOLE.error(e + "\n"+dumpStack());return G.stopBubble(e)});
//window.onerror=function(m,u,l){CONSOLE.error([m,u,l].join("\n") + "\n"+G.dumpStack());return true};

// Shift+Ctrl+Dでコンソールバッファ表示
if(G._DEBUG){
	//G.addEvent(window,"load",function(e){
	function showDebugMk(e){
		var div=doc.createElement("div");
		div.id="g-debug";
		G.setStyleSheet(
			"#g-debug {position:fixed;top:0;right:0;z-index:32767; "+
			" background:red; color:white; cursor:default; font-family:monospace; } "+
			"* html #g-debug { position:absolute; }"+
			"#g-debug a { cursor:pointer; color:white; } "+
			"#domins-disp {position:absolute;top:0;right:0;z-index:32766; "+
			" background:white; color:black; font-family:monospace; "+
			" width:200px; font-size:12px; border:1px solid blue; } "+
			".domins-marker { position:absolute; z-index:32766; "+
			" font-size:0px; line-height:0px; width:0; height:0; "+
			" border:0px dashed red; } "+
			""
		);
		div.innerHTML=
			"[<a title='DOM Inspector' onclick='G.toggleDI()'>I</a>]"+
			"[<a title='Execute statement'    onclick='CONSOLE.exec()'>E</a>]"+
			"[<a title='Dump valiable'    onclick='CONSOLE.dump()'>D</a>]"+
			"[<a title='Show CONSOLE' onclick='CONSOLE.show()'>C</a>]"+
			"[<a title='Show CONSOLE 2' onclick='CONSOLE.show2()'>C</a>]"+
			"";
		(function(doc,div){
			doc.body.appendChild(div);
		}).bindArgs(doc,div).poll((function(){
			return this.body
		}).bind(doc));
	};
	G.showDebugMk=showDebugMk;
	
	if(location.hash=="#S_DEBUG"){
		showDebugMk();
	}else{
		//G.setOnLoadHtml(showDebugMk);
		G.addEvent(window,"load",showDebugMk);
	}

	G.addEvent(document,"keyup",function(e){
		e=G.parseEvent(e);
		if(e.ctrlKey&&e.shiftKey){
			switch(e.keyAsc){
				case 68: case 100:
					CONSOLE.show();
					showDebugMk();
					return stopBubble(e,true);
			}
		}
	});
	
	function toggleDomInspector(){
		if(!G.domins){
			G.domins={};
			//G.domins.id="domins"+(new Date()).valueOf();

			if(!G.domins.div){
				var div=doc.createElement("div");
				div.id="domins-disp";
				G.domins.div=div;
				doc.body.appendChild(div);
				G.domins.marker={};
				G.each(["top","left","right","bottom"],function(v){
					div=doc.createElement("div");
					div.id="domins-marker-"+v;
					div.className="domins-marker";
					doc.body.appendChild(div);
					G.domins.marker[v]=div;
				});
			}else{
				G.domins.div.style.display="block";
			}
		}
		if(!G.domins.eh){
			G.domins.eh=G.addEvent(document,"mouseover",function(e){
				e=G.parseEvent(e);
				//var pos=G.pos(e.target);
				if(e.target.id.indexOf("domins-")>=0){return;}
				//if(e.relatedTarget.id=="domins-disp"||e.relatedTarget.id=="domins-marker"){return;}
				var cs=G.clientSize();
				var x=G.getPageXOffset();
				var y=G.getPageYOffset();
				if(e.pos.clientX<200){x+=200;}
				if(e.pos.clientY<100){y+=100;}
				G.domins.div.style.left=x+"px";
				G.domins.div.style.top=y+"px";
				var pos=G.pos(e.target);
				clearTimeout(G.domins.timer);
				G.setStyles(G.domins.marker.left,{
					display:"block",
					left:pos.left-2+"px",top:pos.top-2+"px",height:pos.height+"px",
					borderRightWidth:"2px"
				});
				G.setStyles(G.domins.marker.top,{
					display:"block",
					left:pos.left-2+"px",top:pos.top-2+"px",width:pos.width+"px",
					borderBottomWidth:"2px"
				});
				G.setStyles(G.domins.marker.right,{
					display:"block",
					left:pos.right+"px",top:pos.top-2+"px",height:pos.height+"px",
					borderLeftWidth:"2px"
				});
				G.setStyles(G.domins.marker.bottom,{
					display:"block",
					left:pos.left-2+"px",top:pos.bottom+"px",width:pos.width+"px",
					borderTopWidth:"2px"
				});
				G.domins.timer=setTimeout(function(){
					G.each(["left","top","right","bottom"],function(v){
						G.domins.marker[v].style.display="none";
					});
				},3000);
				var m={};G.each(["Top","Right","Bottom","Left"],function(v){m[v]=G.currentStyle(e.target,"margin"+v);});
				G.domins.div.innerHTML=
					"pos:"+G.currentStyle(e.target,"position")+",fl:"+G.currentStyle(e.target,"float")+" "+
					G.tmpl("P[${left}x${top}+${width}x${height}]",pos)+" "+
					G.tmpl("M[${Top} ${Right} ${Bottom} ${Left}]",m)+
					"<br/>---<br/>"+
					G.getSelectorPath(e.target,doc.body).split(">").reverse().join("<br/>-").replace(/\./g," .");
			});
		}else{
			G.removeEvent(G.domins.eh);
			delete G.domins.eh;
			G.domins.div.style.display="none";
		}
	}
	G.toggleDI=toggleDomInspector;
}

G.initialized=true;

})(G);

