﻿/*
DAPMX core 0.1.9
Copyright 2008,2009 Maxim Sajin <joox@dapmx.org>
Regarding licensing information please refer http://dapmx.org
*/

if(!window.onload)window.onload=function(){dapDocument(document.body,daQueryString())};

function daQueryString(){
	var href=location.href.split("#"),an=href[1],qs=href[0].split("?")[1];
	var nv,hash={};
	if(qs)for(var i in qs=qs.split("&"))nv=qs[i].split("="),hash[nv[0]]=decodeURI(nv[1]);
	if(an)for(var i in an=an.split(";"))nv=an[i].split(":"),hash[nv[0]]=decodeURI(nv[1]);
	return hash;
};


function daFail(reason,node){throw new Error("dap error <"+(node&&node.nodeName)+"> :: "+reason,false,0)};
function daTitle(text){document.title=text};

//node creation shortcuts
function newElem(e){return document.createElement(e)};
function newText(t){return document.createTextNode(t)};
function newElemText(e,t){var e=newElem(e);if(t)e.appendChild(newText(t));return e};
function newStub(c){return document.createComment(c)};
function insertBefore(newnode,refnode){if(!refnode)return;refnode.parentNode.insertBefore(newnode,refnode)};
function insertAfter(newnode,refnode){if(!refnode)return;if(refnode.nextSibling)refnode.parentNode.insertBefore(newnode,refnode.nextSibling);else refnode.parentNode.appendChild(newnode)};
function insertInstead(newnode,refnode){if(!refnode)return;refnode.parentNode.replaceChild(newnode,refnode)};
function daCut(node){return node.parentNode?node.parentNode.removeChild(node):node};

function newNode(e){return XMLdocument.createElement(e)};
function newTextNode(t){return XMLdocument.createTextNode(t)};

//some cross-browserity magic (i hate ie)
var	isIE=(navigator.appName == 'Microsoft Internet Explorer'),
	isIE6=navigator.appVersion.indexOf("MSIE 6")>0;

//if(isIE6)alert(navigator.appVersion);

daAddEventListener=document.addEventListener
	?function(node,event,handler){node.addEventListener(event,handler,false)}
	:function(node,event,handler){node["on"+event]=handler}

newElemNS=document.createElementNS
	?function(ns,e){return document.createElementNS(ns,e)}
	:function(ns,e){return document.createElement(e)};

daParseXML=window.DOMParser
	?function(str){
		var x=new DOMParser().parseFromString(str,"text/xml").documentElement;
		return (x.nodeName!="parsererror")?x:newElemText("value",str);
	}:function(str){
		var x=new ActiveXObject("Microsoft.XMLDOM");
		x.async="false";
		x.loadXML(str);
		return (x.parseError)?newElemText("value",str):x.documentElement; 
	};
	
daSerialize=window.XMLSerializer
	?function(node){return "<?xml version='1.0' encoding='UTF-8'?>" + new XMLSerializer().serializeToString(node)}
	:function(node){
		var x=new ActiveXObject("Microsoft.XMLDOM");
		x.async="false";
		//x.loadXML(str);
		//return (x.parseError)?newElemText(alt,str):x.documentElement; 
	};
	
function daDumbXML(obj,tag){
	var node=newNode(tag);
	if(obj instanceof Object)for(var i in obj)node.appendChild(daDumbXML(obj[i],i));
	else if(obj!="")node.appendChild(newTextNode(obj));
	return node;
};

var XMLdocument;
if(window.DOMParser)XMLdocument=new DOMParser().parseFromString("<xml/>","text/xml");
else {XMLdocument=new ActiveXObject("Microsoft.XMLDOM");XMLdocument.async="false";XMLdocument.loadXML("<xml/>");}
	
function xhrExecute(async,method,url,post,ctype){
	if(isIE6)async=false;//
	var req=window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Msxml2.XMLHTTP');
	if(async)req.onreadystatechange=xhrProgress;
	switch(method.toUpperCase()){
	//	case"soap":
		case"POST":
			req.open(method,url,async);
			req.setRequestHeader("Content-Type",ctype||"application/x-www-form-urlencoded");
			req.setRequestHeader("Content-Length",post?post.length:0);
			req.send(post);
			break;
		case"GET":
			req.open(method,url,async);
			req.setRequestHeader("Content-Type",ctype||"text/xml");
			req.send(null);
			break;
	}
	if(async){
		if(isIE)ieXHRsucks.push(req={xhr:req,readyState:1});
		else req.daURL=url;
		throw req;
	}
	else return xhrGetXML(req);
};

function xhrGetXML(req){
	var xml;
	if(req.status==200)
		try{xml=req.responseXML?req.responseXML.documentElement:req.responseText}
		catch(e){}
	else daFail("Problem with URL: ["+req.daURL+"]\n"+e.description);
	return xml||emptyXML;
};

function xhrProgress(){
	if(this.readyState==4){
		daResume((isIE?ieXHRsuck(this):this).postponed,xhrGetXML(this));
		//delete this;
	}
};

var ieXHRsucks=[];
function ieXHRsuck(xhr){
	for(var i in ieXHRsucks)if(ieXHRsucks[i].xhr==xhr){
		var a=ieXHRsucks[i];
		ieXHRsucks.splice(i,1);
		return a;
	}
};

function daGET(base,feed){return base+dap.flatten.url(feed)};
function daPOST(base,feed,contentType){var req=dap.flatten.req(feed);req.url=base+req.url;req.contentType=contentType;return req};


var allws=/[\r\n\t]/g, comments=/\s+\([^\)]*\)/g, pilot_junk=/^\s*;\s/g, step_sep="; ", token_sep=" ",
spaces=/\s+/g, leadspace=/^\s+/, tailspace=/\s+$/, splitdigits=/\B(?=(...)*$)/g,
xLFW=/\n\s*/, xWSC=/\s*:/;

var dap={

	pun	:{concat:"",space:" ",comma:",",colon:":",semi:";",dot:".",bar:"|",mesh:"#",star:"*",lf:"\n",lf2:"\n\n"},

	model	:{
		raw	:daL([daRaw]),
		hash	:daL([daHash]),
		list	:daL([daList,daRaw]),
		rset	:daL([daList,daHash]),
		tree	:daL([daList]),
		proto	:daL([daProto]),
		daplist	:daL([daList,daProto]),
		library	:daL([daHash,daTemplate])
	},

	convert	:{
		""	:function(value){return String(value)},
		
		esc	:function(value){return escape(value)},		/// escape
		usc	:function(value){return unescape(value)},	/// unescape
		safe	:function(value){return value.replace(/\W/g,"-")},
		
		xmlenc	:function(value){return value.replace(/\&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gr;")},
		ext	:function(fname){if(!fname)return null;var s=fname.split(".");return s.length>1?("."+s[s.length-1]):""},	/// file extension
		pun	:function(value){return dap.pun[value]},
				
		"?"	:function(bool){return bool?true:false},	/// test
		"!"	:function(bool){return bool?false:true},	/// test inverse
		"#"	:function(bool){return bool?"+":"-"},		/// test as +/-
		
		"+?"	:function(num){return parseFloat(num)>0},	/// test positive
		"-?"	:function(num){return parseFloat(num)<0},	/// test negative
		"0?"	:function(num){return parseFloat(num)==0},	/// test zero
		
		"+"	:function(num){return (num=parseFloat(num))?String(Math.abs(num)):""},	/// abs
		"-"	:function(num){return (num=parseFloat(num))?String(-num):""},		/// neg
		"~"	:function(num){return (num=parseFloat(num))?(num>0?"+":"-"):"0"},	/// sgn
		
		count	:function(ds){if(ds instanceof Array && ds.length>0)return ds.length},	/// rowset length
//		attrs	:function(node){var a={},na;if(node&&(na=node.attributes))for(var i=na.length;i-->0;a[na[i].nodeName]=na[i].nodeValue);return a},

		space	:function(value){return daSplit(daTrim(value)," ")},
		lf	:function(value){return daSplit(value,"\n")},				///(line feed)
		csv	:function(value){return daSplit(value,",")},				/// x1,x2,x3 (comma-separated values)
		bar	:function(value){return daSplit(value,"|")},				/// x1|x2|x3 (bar-separated values)
		nvp	:function(value){return daSplit(daSplit(value,";"),":")},		/// x1:y1:z1;xN:yN:zN (named after "name:value"-pairs)
		lfc	:function(cdata){return daSplit(daSplit(daTrim(cdata),xLFW),xWSC)},	/// linefeed-colon
			
		xml2dom	:function(value){return daParseXML(value)},
		dom2xml	:function(value){return daSerialize(value)},
		obj2dom	:function(value){return daDumbXML(value,"object")},
		obj2xml	:function(value){return daSerialize(daDumbXML(value,"object"))},
		
		GET	:function(url){return xhrExecute(true,"GET",url)},
		POST	:function(req){return xhrExecute(false,"POST",req.url,req.post,req.contentType||"text/plain")},

		list	:function(value){return daModel(value,dap.model.list)},
		hash	:function(value){return daModel(value,dap.model.hash)},
		rset	:function(value){return daModel(value,dap.model.rset)},
		dapx	:function(value){return dapxParse(value)},
		
		"#get"	:function(url){return xhrExecute(false,"GET",url)},
		"#list"	:function(url){return daModel(xhrExecute(false,"GET",url),dap.model.list)},		/// XML as ordered list
		"#hash"	:function(url){return daModel(xhrExecute(false,"GET",url),dap.model.hash)},		/// XML as hash tree
		"#rset"	:function(url){return daModel(xhrExecute(false,"GET",url),dap.model.rset)},		/// XML as a rowset (ordered list of hash trees)

		"#js"	:function(url){try{return eval(xhrExecute(false,"GET",url))}catch(e){fail("Bad js: "+url+"\n"+e)}}, /// JSON, or any other javascript
		"#dapx"	:function(url){return dapxregistry[url]||(dapxregistry[url]=dapxParse(xhrExecute(false,"GET",url)))}	/// XML as dap extension library
	},
	
	flatten	:{
		"void"	:function(feed){},
		"" 	:function(feed){var d={},a;for(var i in feed)if(a=feed[i].alias)d[a]=feed[i].value;return d},	/// flat datum {@a:v1,@b:v2}

		"+"	:function(feed){var sum=0;for(var i in feed)sum+=parseFloat(feed[i].value);return String(sum)},
		"-"	:function(feed){var sub=parseFloat(feed[0].value)*2;for(var i in feed)sub-=parseFloat(feed[i].value);return String(sub)},

		"?"	:function(feed){for(var i in feed)if(feed[i].value)return feed[i].value;return false},		/// first non-empty
		"!"	:function(feed){for(var i in feed)if(!feed[i].value)return true; return false},			/// succeeds if empty token found

		"?@"	:function(feed){for(var i in feed)if(feed[i].value==feed[i].alias)return true;return false},	/// any match
		"!@"	:function(feed){for(var i in feed)if(feed[i].value!=feed[i].alias)return false;return true},	/// all match
		
		eq	:function(feed){for(var i in feed)if(feed[i].value!=feed[0].value)return false;return true},
		dsc	:function(feed){var a=parseInt(feed[0].value);for(var i in feed)if(a<(a=parseInt(feed[i].value)))return false;return true},
		asc	:function(feed){var a=parseInt(feed[0].value);for(var i in feed)if(a>(a=parseInt(feed[i].value)))return false;return true},
		
		concat	:function(feed){var string="";for(var i in feed)if(feed[i].value)string+=feed[i].value;return string},
		space	:function(feed){return daConcat(feed," ")},
		
		csv	:function(feed){return daConcat(feed,",")},	/// x1,x2,x3 (comma-separated values)
		bar	:function(feed){return daConcat(feed,"|")},	/// x1|x2|x3 (bar-separated values)
		nvp	:function(feed){return daFlattenRowsets(feed,":",";")},
		
		url	:function(feed){
				var url="",a,n;
				for(var i in feed)if(a=feed[i].value)
					url+=(n=feed[i].alias)?"&"+n+"="+encodeURIComponent(a):a;
				return url;
			},
			
		req	:function(feed){
				var url="",post="",a,n;
				for(var i in feed)if(a=feed[i].value)
					if(n=feed[i].alias)url+="&"+n+"="+encodeURIComponent(a);
					else post+=a;
				return {url:url,post:post};
			},
		
		/// selectors
		"~"	:function(feed){return daConvey(feed,dap.convey["~"],{out:""}).$},
		"#"	:function(feed){return daConvey(feed,dap.convey["#"],{out:""}).out},
		"@"	:function(feed){return daConvey(feed,dap.convey["@"],{out:[]}).out},
		"##"	:function(feed){return daConvey(feed,dap.convey["##"],{out:[]}).out},
		"@@"	:function(feed){return daConvey(feed,dap.convey["@@"],{out:[]}).out},

		/// rowset shuffle
		insert	:function(feed){return daConvey(feed,dap.convey["insert"],{out:""}).$}
	},

	execute	:{ /// see dap executes reference at http://dapmx.org/0.1.9/#execute
		"_"	:function(){return E},
		""	:function(value,alias,node){return value},
		"!"	:function(value,alias,node,D,$){daPhase.d(node,value,$)},
		"+!"	:function(value,alias,node,D,$){return daSibling(value,alias,node,$)},
		"-!"	:function(value,alias,node){daAbandon(value,alias,node)},
		"u!"	:function(value,alias,node){daPhase.u(value||node,alias)},
		"init"	:function(value,alias,node,D,$){daPhase.d(node,value.init,$); return value;},
		
		"-"	:function(value,alias,node,D){D[alias]=D[alias]?false:value||true},
		"~"	:function(value,alias,node,D){var a=D[alias];return(!a)?(value||true):(!value)?(!a):(a==value)?false:a},

		"?"	:function(value,alias,node){return alias?(value!=alias&&F):(!value&&F)},
		"*"	:function(value,alias,node){return value?daMapGrid((value instanceof Array)?value:[value],alias):E},
		"+"	:function(value,alias,node,D){var a=D[alias];if(!a||a==E)return[value];if(!(a instanceof Array))return[a,value];a.push(value);return a},//
		shift	:function(value,alias,node,D){daShiftRow(value,alias,node)},
		
		own	:function(value,alias,node,D){return D[alias]||value||""},
		"^"	:function(value,alias,node,D){return value&&daLookup(D,value)},
		"%"	:function(value,alias,node,D){
				if(alias)value=daMap(value,alias.split(","));
				for(var i in value)D[i]=value[i];
				return value;
			},
		
		"`"	:function(value,alias,node){return node.$.P},
		"#"	:function(value,alias,node){return daRoute(node,value)},
		
		attr	:function(value,alias,node){if(value)node.setAttribute(alias,value)},
		
		u	:function(value,alias,node){
				try{daActivateNode(node,alias,value)}
				catch(e){alert("can' assign "+alias+" listener",node)}
			},
		ui	:function(value,alias,node){
				enstyle(node,"ui");
				daAddEventListener(node,"mouseover",daOver);
				daAddEventListener(node,"mouseout",daOut);
				try{daActivateNode(node,alias,value)}
				catch(e){alert("can' assign "+alias+" listener",node)}
			},
		"ui?"	:function(value,alias,node){if(value)try{daActivateNode(null,alias,node)}catch(e){alert("can' assign "+alias+" listener",node)}}
		
	},
	
	convey	:{
	
		"~"	:{	///alternate
			next	:function(bin,value){var a=bin.$;if(a instanceof Array)for(var i=0;i<a.length;i++){if(value==a[i])bin.$=a[i++ % a.length]}},
			"#"	:function(bin,value){if(bin.$)bin.$=bin.$[value]}
		},
		
		"@"	:{	///select first match by value
			$	:function(bin,value,alias){if(alias==bin.$)bin.out=value},
			"!"	:function(bin,value){bin.out.push(value)}, //joker
			"default":function(bin,value){if(!bin.out)bin.out=value}
		},
		
		"#"	:{	///select first match by name
			$	:function(bin,value){bin.out=bin.$[value]},
			"?"	:function(bin,value){if(bin.$[value])bin.out=bin.$[value]}, //reject empties
			"default":function(bin,value){if(!bin.out)bin.out=value}
		},
		
		"@@"	:{	///select all matches by value
			"!"	:function(bin,value){bin.out.push(value)}, //joker
			$	:function(bin,value,alias){if(alias==bin.$)bin.out.push(value)}
		},
		
		"##"	:{	///select all matches by name
			"?"	:function(bin,value){if(bin.$[value])bin.out.push(bin.$[value])}, //reject empties
			$	:function(bin,value){bin.out.push(bin.$[value]||"")}
		}
		
	}
	
},
emptyPath=[""],emptyXML=document.createElement("empty"),
dapx={},dapxregistry={},dapaliases={},
E=[],T={},F={};

//convey
function daConvey(feed,convey,subj){
	var op,alias,value;
	for(var i in feed)if((op=feed[i])&&(value=op.value))
		if(alias=op.alias)
			if(op=convey[alias]||convey.$)subj=op(subj,value,alias)||subj;
			else fail("unknown op: "+alias+":"+value);
		else subj.$=value;
	return subj;
};

//postprocessing
var dapost=[];
function daPostProcess(node,handler){dapost.push({node:node,handler:handler})}

//ui highlight
function enstyle(node,cls){if(node.className)node.className+=" "+cls;else node.className=cls;return node};
function destyle(node,cls){if(node.className)node.className=node.className.replace(new RegExp("\\s*"+cls,"g"),"");return node};
function evStop(e){if(e&&e.stopPropagation)e.stopPropagation();else event.cancelBubble=true};
function daOver(e){evStop(e);enstyle(this,"over")};
function daOut (e){evStop(e);destyle(this,"over")};

function daActivateNode(node,alias,value){
	try{
		if(!alias)alias="click";
		if(!value)value=node.P;
		if(!value.rules)daEngage(value);
		daAddEventListener(node,alias,daEvent);
		node.P.rules[alias]=value.rules.u;
	}
	catch(e){daFail("no rule for "+alias,node)}
}

function daEvent(e){
	if(!e)e=window.event;
	evStop(e);
	daPhase.u(this,e.type);
	return true;
}

//string works
function daReplaceMulti(value,regs){
	if(value)for(var i=regs.length;i-->0;)value=value.replace(regs[i][0],regs[i][1]);
	return value;
};
function daConcat(feed,separator){
	var a,out=[];
	for(var i in feed)if(a=feed[i].value)out.push(a);
	return out.join(dap.pun[separator]||separator);
};
function daSplit(value,separator){
	if(value instanceof Array)for(var i in value)value[i]=daSplit(value[i],separator);
	else if(value&&value.split)value=value.split(separator);
	return value;
};
function daTrim(str){
	if(str&&str.replace)return str.replace(leadspace,"").replace(tailspace,"");
};
function daSplitDigits(n){
	return String(n).replace(splitdigits," ");
};
function daFlattenRowsets(feed,fsep,rsep){
	var out=[];
	for(var i=0;i<feed.length;i++)if(feed[i]){
		var rows=feed[i].value, flds=feed[i].alias;
		if(flds)flds=flds.split(",");
		if(rows)for(var r=0;r<rows.length;r++){
			var row=rows[r], unrow=[];
			if(flds)for(var f=0;f<flds.length;f++)unrow.push(row[flds[f]]);
			else for(var f in row)unrow.push(row[f]);
			out.push(unrow.join(fsep));
		}
	}
	return out.join(rsep);
};

//rowset works
function daMap(datarow,columns){
	var entry={};
	if(datarow instanceof Array)for(var i=datarow.length;i-->0;entry[columns[i]]=datarow[i]);
	else entry[columns[0]]=datarow;
	return entry;
};
function daMapGrid(grid,alias){
	if(!alias)return grid;
	var rowset=[];
	var columns=alias.split(",");
	for(var row in grid)rowset.push(daMap(grid[row],columns));
	return rowset;
};

function daShiftRow(value,alias,node){
	for(var rowset=daHD(node),row=daDC(node),i=rowset.length;i-->0&&rowset[i]!=row;);//locate the row
	if(i>=0){
		for(var base=node;(node=base.parentNode)&&(daDC(node)==row);base=node);//locate row base
		switch(value){
			case "up"	:if(i>0) rowset[i]=rowset[i-1], rowset[i-1]=row, insertBefore(base,base.previousSibling);break;
			case "down"	:if(i<rowset.length-1) rowset[i]=rowset[i+1], rowset[i+1]=row, insertAfter(base,base.nextSibling);break;
			case "top"	:rowset.splice(i,1), rowset.unshift(row), insertBefore(base,base.parentNode.firstChild);break;
			case "bottom"	:rowset.splice(i,1), rowset.push(row), insertAfter(base,base.parentNode.lastChild);break;
		}
	}
	return rowset;
};
function daSibling(value,alias,node,$){
	var rowset=daHD(node),row=daDC(node);
	for(var place;(place=node.parentNode)&&(daDC(place)==row);node=place);//locate row root node and its place
	var sibling=daPhase.d(place,node.P,{S:node.$.S,D:[value,node.$.D[1],rowset]});
	if(sibling){
		for(var i=rowset.length;i-->0&&rowset[i]!=row;);//locate the row
		switch(alias){
			case "instead"	:rowset[i]=value;insertInstead(sibling,node);break;
			case "before"	:rowset.splice(i,0,value),insertBefore(sibling,node);break;
			case "after"	:
			default		:rowset.splice(i+1,0,value),insertAfter(sibling,node);break;
		}
	}
	return sibling;
};
function daAbandon(value,alias,node){
	var rowset=daHD(node),row=daDC(node);
	for(var place;(place=node.parentNode)&&(daDC(place)==row);node=place);
	for(var i=rowset.length;i-->0&&rowset[i]!=row;);//locate the row
	rowset.splice(i,1);
	return place.removeChild(node);
}

//direct access to node's own contexts
function daSC(node){return node.$&&node.$.S[0]};	/// node's own status context
function daDC(node){return node.$&&node.$.D[0]};	/// node's own data context
function daHD(node){return node.$&&node.$.D[2]};	/// node's host dataset


//data models
function daL(a){for(var i=a.length,L=[a[--i]];i-->0;L=[a[i],L]);return L};
function daModel(node,model){return model[0](node,model[1]||model)};
function daRaw(node){return node};
function daProto(node){return {markup:node}};

function daTemplate(node,model){
	if(node.markup)return node; //already parsed
	if(node.getAttribute("d")||node.getAttribute("u"))return{inline:true,markup:node};
	var m=daList(node,dap.model.proto);
	return(m.length==1)?m[0]:m;
};
function daList(node,model){
	var list=[],n=node.childNodes,m0,m1,a;
	if(model)m0=model[0],m1=model[1]||model;
	if(n)for(var i=0;i<n.length;i++){
		switch(n[i].nodeType){
			case 1:list.push(m0?m0(n[i],m1):n[i]);break;
			case 3:
			case 4:if((a=n[i].nodeValue).replace(spaces,""))list.push(a);break;
		}
	}return list;
};
function daHash(node,model){
	var hash={},n=node.childNodes,t=null,text="",m0,m1,a;
	if(model)m0=model[0],m1=model[1]||model;
	for(var a=node.attributes,i=0;i<a.length;i++)hash[t=a[i].nodeName.toLowerCase()]=a[i].nodeValue;
	if(n)for(var i=0;i<n.length;i++)switch(n[i].nodeType){
		case 1:
			t=n[i].nodeName.toLowerCase(),a=m0?m0(n[i],m1):n[i]
			if(hash[t])((hash[t]instanceof Array)?hash[t]:(hash[t]=[hash[t]])).push(a);
			else hash[t]=a;
			break;
		case 3:
		case 4:if((a=n[i].nodeValue).replace(spaces,""))text+=a;break;
	}
	if(!t)return text;
	hash[""]=daTrim(text);
	return hash;
};

function dapxParse(xml){
	var dapns=xml.getAttribute("dapns")||xml.nodeName,a,v;
	if(a=xml.getAttribute("dap-aliases"))for(var i in a=a.split(" "))v=a[i].split("="),dapaliases[dapns+"/"+v[0]]=dapns+"/"+(v[1]||v[0]);
	var lib=daModel(xml,dap.model.library);
	//if(xml.ownerDocument==document)
	xml.setAttribute("dapns",dapns);//ownerDocument.documentElement.
	if((a=lib[""])&&(a=eval(a)))for(var i in a)if(dap[i])dap[i][dapns]=a[i];//try{}catch(e){daFail("problem with lib: "+url+"\n"+e)}
	return lib;
};

//dap launch
function dapDocument(root,data){
	var stub=newElem("dap"),place=root.parentNode,dap=place.replaceChild(stub,root);
	place.$={};
	place.replaceChild(daClone(daProto(dap),{S:[{}],D:[data]}),stub);
};

function daReach(path,o){
	var i=path.length;
	while(o&&(i-->0))
	o=o[path[i]];
	return o};
function daRoute(o,str){return str?daReach(daPath(str),o):o};


//dap engine (compressed)
function daChain(chainstring){return chainstring.split(",")};
function daChainReach(paths,domain,chain,dapns){
	var paths=daChain(paths),i=paths.length,a;		
	while(i-->0)if(a=daReach(daPath(paths[i],dapns),domain))chain=[a,chain];else return;
	return chain;
};

function daPath(pathstring,dapns){
	if(!pathstring)return emptyPath;
	if(pathstring=="..")return[dapns];
	var path=pathstring.split("."),a;
	if(!path[0]){
		if(a=dapaliases[dapns+"/"+path[1]])path.shift(),path[0]=a;
		else path[0]=dapns;
	}
	return path.reverse();
};

function daUsed(a,b){if(a&&b)for(var i in a)if(a[i]==b[i])return true};
function daMute(node){var n=newStub(node.nodeName);n.P=node.P;n.$=node.$;n.dn=node.dn;return n};

function daLookup($,alias){
	if(!$)return;
	//if(!alias)return $[0];
	var ref;
	if($[0]&&((ref=$[0][alias])!=null))return ref;
	if(ref=daLookup($[1],alias))return $[0][alias]=ref;
};

function daGet($,path,dn,th){
	var i=path.length;
	var alias=path[--i],d=daLookup($,alias);
	if(!d)return;
	if(dn)dn[alias]=d;
	while(d&&(i-->th))d=d[path[i]];//while(i-->th)d=d[path[i]]||d;
	return d;
};

function daSet($,path,up,value){
	var i=path.length;
	var alias=path[--i],d=up?(daLookup($,alias)):$[0][alias],a;
	if(!d)d=$[0][alias]={};
	for(a=d;i-->0;a=a[path[i]]||(a[path[i]]={}));
	if(a[path[0]]!=value||value==null){
		if(value!=null)a[path[0]]=value;
		if(up)up[alias]=d;
	}
	return a;
};

function daPut(obj,path,value){
	for(var i=path.length,alias=path[--i];i-->0;obj=obj[path[i]]||(obj[path[i]]={}));
	obj[alias]=value;
};

function daConvert(value,convert){
	if(convert)for(var i=convert.length;i-->0;)value=convert[i](value);
	return value;
};

var daStackDepth=0;

function daExecRule(node,R,up,$){

	if(!R)return !up;//false;//
	
	if(++daStackDepth>50)return daFail("Suspicious recursion depth",node);
	
	if(!$)$=node.$;
	var S=$.S,D=$.D,D0=D[0],nS,step,convert,procede=true,done=false,a;
	while(R&&!done)if(step=R[0])//try
	{
		var head=step[0], target=null, token;
		var t=step.length,feed=null,operate=null,convert; //resumables
		if(head){
			a=head.target;
			if(a!=null){
				if(a)target=daSet((up||nS)?S:S=($=node.$={S:[nS={},S],D:$.D}).S,a,up);
				else target=D0;
			}
			feed=head.flatten?[]:null;
			operate=head.operate;
		}
		
		while(t-->0){
			var alias,value,convert=null;
			if(token=step[t]){
				alias=token.alias,value=token.value,convert=token.convert;
				if(a=token.field)value=daGet(D,a,null,0)||value||"";
				if(a=token.local)
					if(value!=null)daSet((up||nS)?S:S=($=node.$={S:[nS={},S],D:$.D}).S,a,up,value);//
					else value=(daGet(S,a,!up&&(node.dn||(node.dn={})),1)||daFail(a+" unaccessible :: "+R[2],node))[a[0]];//;//
			}else alias=null,value=node.P.content;
			
			if(!t){if(feed)value=head.flatten(feed),feed=null;else feed=true;}
			
			try{while(convert)value=convert[0](value),convert=convert[1]}
			catch(e){
				daStackDepth--;
				if(e.readyState)return e.postponed=daPostpone(node,R,t,feed,alias,convert&&convert[1]);
				else throw(e);
			}
			
			if(t){if(feed)feed.push({alias:alias,value:value});}
			
			if(!feed)if(operate){
				value=operate(value,alias,node,target,$);
				if(target)target[alias]=value;
				else	// no destination - use result as flow control
					if(value==F)procede=false,done=true;
					else if(done=value instanceof Array){
						procede=false;
						for(var r=0; r<value.length; r++)
							procede=daExecRule(node,R[1],up,{S:S,D:[value[r],D,value]})||procede;
					}
			}
		}
		R=R[1];
	}
/* */	else done=true, procede=false; // empty step
	daStackDepth--;
	if(up)procede=procede?null:"u";
	return procede;
};


function daPostpone(node,R,t,feed,alias,convert){
	var step=feed||[],R0=R[0],head=R0[0],token={alias:alias,convert:convert};
	head=(t>0)?head:{operate:head.operate,target:head.target,alias:head.alias};
	step.unshift(head);
	step.push(token);
	while(--t>0)step.push(R0[t]);
	return{node:node,R:[step,R[1]],token:token};
};

function daResume(postponed,value){
//if(!postponed.node.ownerDocument)alert("lost target");
	if(!postponed)return;
	postponed.token.value=value;
	daExecRule(postponed.node,postponed.R);
};

function daParseRule(rulestring,dapns,R,P){
	if(!rulestring)return R;
	var steps=rulestring.replace(allws," ").replace(comments,"").replace(pilot_junk,"").split(step_sep),a;
	for(var s=steps.length;s-->0;R=[step,R,steps[s]])if(a=steps[s].replace(tailspace,"")){
		var step=[],tokens=a.replace(spaces," ").split(token_sep);
		var head=null,alias=null,convert=null;
		
		if(a=tokens[0]){ //step head
			head={};
			if((a=a.split("=")).length>1)head.flatten=daReach(daPath(a[1],dapns),dap.flatten)||daFail("missing flattener "+token.value+" :: "+rulestring);
			if((a=a[0].split("@")).length>1)alias=a[1],head.target=false;
			if((a=a[0].split(":")).length>1)convert=daChainReach(a[1],dap.convert,null,dapns)||daFail("missing converter "+a[1]+" :: "+rulestring);
			if((a=a[0].split("$")).length>1)head.target=daPath(a[1]);
			if(!alias&&head.target)alias=head.target[0];
			if(a=a[0])head.operate=daReach(daPath(a,dapns),dap.execute)||daFail("missing execute"+a+" : "+rulestring);//booc();//
			else head.operate=dap.execute[""];
			
			if(head.flatten)
				head.alias=alias,alias=null,
				head.convert=convert,convert=null;
		}
		step.push(head);
		
		for(var t=tokens.length;t-->1;step.push(token))if(a=tokens[t]){
			var token={};
			if((a=a.split("=")).length>1)token.value=a[1];
			if((a=a[0].split("@")).length>1)token.alias=a[1];
			if((a=a[0].split(":")).length>1)token.convert=daChainReach(a[1],dap.convert,convert,dapns)||daFail("missing converter "+a[1]+" :: "+rulestring);
			else if(convert)token.convert=convert;
			if((a=a[0].split("$"))[0])switch(a[0]){
				case "'"	:token.value=P.content;break;
				case "."	: //parse-time resolve
				default		:token.field=daPath(a[0],dapns);
			}
			if(a.length>1)token.local=a[1]?daPath(a[1]):[token.field[0]]||emptyPath;//(token.field&&)
			if(token.alias=="")token.alias=false;
			else if(!token.alias)
				if(a=token.local||token.field)token.alias=a[0]; //entry tail as alias
				else if(alias)token.alias=alias; //finally, try head alias
		};
		if(step.length==1)step.push(alias?{alias:alias}:T);//stub token for empty feed
	}else step=null;
	return R;
};

function daParseRules(P,rules){

	//if(!markup.ownerDocument)alert("Этот браузер не поддерживается");

	var	markup=P.markup,
		dapns=markup.ownerDocument.documentElement.getAttribute("dapns"),
		a;
	for(var i in rules)
		if(a=markup.getAttribute(i))
			rules[i]=daParseRule(a,dapns,rules[i],P),
			markup.removeAttribute(i);
	return rules;
};

function daEngage(P){
	var d=daModel(P.markup,dap.model.daplist);
	if(d.length)P.content=d,d=[[daDown,{value:d}]];else d=false;
	P.rules=daParseRules(P,{d:d,u:null});
	P.markup=daAdopt(P.markup);
};

function daAdopt(node){
	if(node.ownerDocument==document)return node;//daCut()
	var n=newElemNS(node.namespaceURI,node.nodeName);
	for(var a=node.attributes,i=0;i<a.length;i++)n.setAttribute(a[i].nodeName,a[i].nodeValue);
	if(isIE&&(a=node.getAttribute("class")))n.className=a;//I hate IE
	return n;
};

function daClone(P,$,node){
	if(!P.rules)daEngage(P);
	if(!P.inline)node=P.markup.cloneNode(false),node.$=$,node.P=P;
	if(!daExecRule(node,P.rules.d)&&!node.childNodes.length)node=daMute(node);
	return(!P.inline)&&node;
};

function daCheckDn(node,ch){
	if(daUsed(ch,node.dn)){
		var n=daClone(node.P,node.$);//
		try{node.parentNode.replaceChild(n,node);}catch(e){if(!e.lineNumber)daFail(e.message)};//
	}else if(daUsed(ch,node.$.S[0]))
		for(var i=0,nodes=node.childNodes,n;i<nodes.length;i++)
			if((n=nodes[i])&&n.$)daCheckDn(n,ch);
};

var daPhase={
	
	d:function(place,P,$){
		if(!P)return;
		var n;
		if(P instanceof Array)for(var i=0;i<P.length;i++)daPhase.d(place,P[i],$);
		else if(n=P.nodeType?P:P.markup?daClone(P,$,place):newText(P))place.appendChild(n);
		return n;
	},
	
	u:function(node,event,up){
		if(node&&node.P){
			for(var top=node,S,nS,rule,n,up={};node&&(n=node.parentNode)&&n.$;node=n){
				if(event&&(rule=node.P.rules[event]))event=daExecRule(node,rule,up);
				if(n.$.S!=S && daUsed(up,(S=node.$.S)[0]))top=node;
			}daCheckDn(top,up);
			for(var i=dapost.length;i-->0;)dapost[i].handler(dapost[i].node);
			dapost=[];
		}
	}
	
},daDown={operate:dap.execute["!"]};	// normal completion of d-rule: run children