// file: 000-compatibility.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
var userAgent = navigator.userAgent;
if (userAgent.indexOf('Safari') >=0)
{
	window.browser = 'Safari';
}
else if (userAgent.indexOf('Gecko') >=0)
{
	window.browser = 'Mozilla';
}
else if (userAgent.indexOf('MSIE') >=0)
{
	window.browser = 'IE';
}
else 
{
	window.browser = 'Unknown';
}

function createXMLHTTPRequest()
{
	//TODO: better error reporting when XMLHTTPRequest is not supported
	if (window.XMLHttpRequest)
		return new XMLHttpRequest(); // Works on Mozilla and others
	else
		return new ActiveXObject("Microsoft.XMLHTTP"); // Works on IE
};

function createAnIFrame(parentWindow,name,url)
{
	if (window.browser == 'IE')
	{
		// Creating an iframe in the standard way doesn't work because IE somehow
		// Doesn't recogmize the newly created iframe (submitting a form targeted 
		// To the new iframe causes a new window to be created.
		var styleClause = '';
		if (! window.showServiceInvocations)
		{
			styleClause = 'class="hidden"';
		}
		var srcClause = url ? ' src="'+url+'"' :'';
		var html = '<iframe name="' + name + '" id="'+name+'"'+styleClause+srcClause+'></iframe>';
    	parentWindow.document.body.insertAdjacentHTML( "beforeEnd", html);
    	var iframe = parentWindow.frames[ name ];
    	return iframe;
    }
    else
    {
    	// Standard DOM implementation
    	var iframe = parentWindow.document.createElement('iframe');
		iframe.name = name;
		iframe.id = name;
		iframe.src=url?url:"blank.html";
		if (! window.showServiceInvocations)
			iframe.className = 'hidden';
		var body = parentWindow.document.body;
		body.appendChild(iframe);
		return iframe;
    }
}

function getIFrameWindow(iframe)
{
	if (iframe.contentWindow)
		return iframe.contentWindow;
	else
		return iframe;
};
function getIFrameDocument(iframe)
{
	if (iframe.contentWindow)
		return iframe.contentWindow.document;
	else
		return iframe.document;
};

function setCssFloat(node,value)
{
	if (window.browser == 'IE')
	{
		node.style.styleFloat=value;
	}
	else
	{
		node.style.cssFloat=value;
	};
	
};

function setEncType(form, enctype)
{
	// Althogh 'enctype' and 'encoding' are supposed to be synonyms, 
	// Setting 'enctype' (the DOM standard) doesn't work in IE
	if (window.browser == 'IE')
	{
		form.encoding = enctype;
	}
	else
	{
		form.enctype = enctype;
	};
	
}
function getStackTrace()
{
	var stack = '';
	var e;
	try
	{
		x.x;
	}
	catch(ex)
	{
		e = ex;
	}
	if (e.stack)
	{
		var tmp =  e.stack;
		var frames = tmp.split('\n');
		frames.splice(0,2);
		stack = frames.join('\n');
	}
	else
	{
		for (var func = arguments.caller; func != null; func = func.caller)
		{
			stack += '\n' + getFunctionName(func.callee) + '\n';
		}
	}
	return stack;
  };
  
  // Returns the position of the current event, relative to the window
  // On IE, the event is taken from the window
  // On other browsers, it is supplied as an argument
  function getEventPosition(win,e)
  {
  	var pos = new Position();
	if (window.browser != 'IE')
	{
  		pos.x = e.clientX;
  		pos.y = e.clientY;
  	}
	else
	{
  	 	pos.x = win.event.clientX;
  	 	pos.y = win.event.clientY;
  	 }
  	 return pos;
  };
  function Position() {};
  Position.prototype.equals = function (other)
  {
  	return other.x == this.x && other.y == this.y;
  };
  
  
function setScrollableTable(bodyNode, width, height)
{
	if (window.browser=='Mozilla')
	{
		bodyNode.style.overflow='auto';
		if (width)
			bodyNode.style.width = width;
		if (height)
			bodyNode.style.height = height;
	};
};
  
function isScrollable(node)
{
	return node.scrollHeight != node.offsetHeight || node == node.ownerDocument.body;
};  
function getOffsets(node)
{
	var x = 0;
	var y = 0;
	var currentNode = node;
	do
	{
		x+=currentNode.offsetLeft;
		y+=currentNode.offsetTop;
		currentNode = currentNode.offsetParent;
	}
	while (currentNode);
	return {'left':x, 'top':y};
};
// Returns the position of a node relative to the screen (taking scrolling into account)
function getScreenPosition(node)
{
	var x = 0;
	var y = 0;
	var currentNode = node;
	do
	{
		x+=currentNode.offsetLeft;
		y+=currentNode.offsetTop;
		currentNode = currentNode.offsetParent;
	}
	while (currentNode);
	currentNode = node;
	do
	{	
		if (currentNode.scrollLeft != undefined)
		{	
	  		x -= currentNode.scrollLeft;
  			y -= currentNode.scrollTop;
	  		currentNode = currentNode.parentNode;
	  	}
	  	else
	  		currentNode = null;
	}
	while (currentNode);
	return {'left':x, 'top':y};
};

function getScroll(node)
{
	var p = getScreenPosition(node);
	p.top -= node.offsetTop;
	p.left -= node.offsetLeft;
	return p;
};
function contains(node,position)
{
	var offsets = getScreenPosition(node);
	var size = getVisibleSize(node);
	return position.x >= offsets.left && position.y >= offsets.top && position.x <=offsets.left + size.width &&
	position.y <= offsets.top + size.height;
};

function getVisibleSize(node)
{
	var width = node.offsetWidth;
	var height = node.offsetHeight;
	if (node == node.ownerDocument.body && node.clientHeight)
	{
		height = node.clientHeight;
	};
	//TODO handle width
	return {'height':height,'width':width};
};
function getHeight(node)
{
	return node.offsetHeight;
};
function html2Node(t, document)
{
	var p;
	var pref3 = t.substring(0,3);
	if (pref3 == '<tr')
	{
		p = document.createElement('DIV');
		p.innerHTML='<table><tbody>'+t+'</tbody></table>';
		return p.firstChild.tBodies[0].firstChild;
	}
	if (pref3 == '<td' || pref3 == '<th')
	{
		p = document.createElement('DIV');
		p.innerHTML='<table><tbody><tr>'+t+'</tr></tbody></table>';
		return p.firstChild.tBodies[0].firstChild.firstChild;
	}
	else
	{
		p = document.createElement('DIV');
		p.innerHTML=t;
		return p.firstChild;
	}
}
function importNode(document, node)
{
	if (document.importNode)
		return document.importNode(node,true);
	else if (node.outerHTML)
	{
		var tmpNode = document.createElement('DIV');
		tmpNode.innerHTML = node.outerHTML;
		return tmpNode.firstChild;
	}
	else
	{
		alert('importNode not implemented for this browser');
		return null;
	}
	
};
function getActualBackground(node)
{
	var current = node;
	while (current)
	{
		var background = getActualStyle(current,'background-color');
		if (background != 'transparent')
		{
			 return background;
		}
		current = current.parentNode;
	}
	return null;
};
tersus.getJsAttributeName = function(name)
{
	var parts = name.split('-');
	if (parts.length == 1)
		return parts[0];
	else
	{
		var t = parts[1];
		return parts[0]+t.charAt(0).toUpperCase()+t.substr(1);
	}
}; 

function getActualStyle(node,styleProp)
{
	var y=null;
	if (node.currentStyle)
	{
		var prop = tersus.getJsAttributeName(styleProp);
		if (prop == undefined)
			prop = styleProp;
		y = node.currentStyle[prop];
	}
	else if (window.getComputedStyle)
		y = node.ownerDocument.defaultView.getComputedStyle(node,null).getPropertyValue(styleProp);
	return y;
};
getActualStyle.propertyMap = {};
getActualStyle.propertyMap['background-color']='backgroundColor';
getActualStyle.propertyMap['margin-top']='marginTop';
getActualStyle.propertyMap['margin-bottom']='marginBottom';
function isVisible(node)
{
	if (node.tagName && node.tagName == 'HTML')
		return true;
	if (getActualStyle(node,'visibility')=='hidden')
		return false;
	else if (getActualStyle(node,'display') == 'none')
		return false;
	else if (node.parentNode)
		return isVisible(node.parentNode);
	else 
		return true;
};
function getPageSize(w)
{
	var size = {};
	if (w.innerHeight) 
	{
		size.width = w.innerWidth;
		size.height = w.innerHeight;
	}
	else if (w.document.documentElement && w.document.documentElement.clientHeight)
	{
		size.width = w.document.documentElement.clientWidth;
		size.height = w.document.documentElement.clientHeight;
	}
	else if (w.document.body) 
	{
		size.width = w.document.body.clientWidth;
		size.height = w.document.body.clientHeight;
	}
	return size;
};

function getPageScroll(w)
{
	var scroll = {};
	if (w.pageYOffset) 
	{
		scroll.x = w.pageXOffset;
		scroll.y = w.pageYOffset;
	}
	else if (w.document.documentElement && w.document.documentElement.scrollTop)
	{
		scroll.x = w.document.documentElement.scrollLeft;
		scroll.y = w.document.documentElement.scrollTop;
	}
	else if (w.document.body) // all other Explorers
	{
		scroll.x = w.document.body.scrollLeft;
		scroll.y = w.document.body.scrollTop;
	}
	return scroll;
};

function getParentWindow(node)
{
	if (node.parentWindow)
		return node.parentWindow;
	else if (node.defaultView)
		return node.defaultView;
	else if (node.ownerDocument)
		return getParentWindow(node.ownerDocument);
};

function clearSelection(w)
{
	if (w.document.selection && w.document.selection.empty)
		w.document.selection.empty();
	else if (w.getSelection && w.getSelection().removeAllRanges)
		w.getSelection().removeAllRanges();
};

function getEventAttributes(e)
{
	var atts = {};
	atts.type = e.type;
	if (e.type.substring(0,3)=='key')
	{
		if (e.keyCode)
			atts.keyCode = e.keyCode;
		else 
			atts.keyCode = e.which;
	}
	var buttonCode = e.button;
	if (this.browser=='Mozilla')
	{
		if (buttonCode == 0)
			atts.button = 'Left';
		else if (buttonCode == 1)
			atts.button = 'Middle';
		else if (buttonCode == 2)
			atts.button = 'Right';
	}
	else
	{
		if (buttonCode == 1)
			atts.button = 'Left';
		else if (buttonCode == 4)
			atts.button = 'Middle';
		else if (buttonCode == 2)
			atts.button = 'Right';
	}
	atts.clientX  = e.clientX;
	atts.clientY = e.clientY;
	
	atts.targetElement = e.target ? e.target : e.srcElement;
	return atts;
};
// Javascript escaping/quoting: based on http://www.json.org/json2.js (public domain)
js_escapeable = /[\\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
	js_meta = {    // table of character substitutions
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                "'" : "\\'",
                '\\': '\\\\'
            };
function js_quote(string) {
js_escapeable.lastIndex = 0;
return js_escapeable.test(string) ?
    '"' + string.replace(js_escapeable, function (a) {
        var c = js_meta[a];
        if (typeof c === 'string') {
            return c;
        }
        return '\\u' + ('0000' +
                (+(a.charCodeAt(0))).toString(16)).slice(-4);
    }) + '"' :
    '"' + string + '"';
}
// file: 000-gwtutil.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function tersus_gwt_Util(){var l='',F='" for "gwt:onLoadErrorFn"',D='" for "gwt:onPropertyErrorFn"',n='"><\/script>',p='#',r='/',ub='<script defer="defer">tersus_gwt_Util.onInjectionDone(\'tersus.gwt.Util\')<\/script>',zb='<script id="',A='=',q='?',C='Bad handler "',sb='CE42C2EF9950144E4D89663A8785CC78.cache.html',tb='DOMContentLoaded',o='SCRIPT',yb='__gwt_marker_tersus.gwt.Util',s='base',nb='begin',cb='bootstrap',u='clear.cache.gif',z='content',xb='end',lb='gecko',mb='gecko1_8',vb='gwt.hybrid',E='gwt:onLoadErrorFn',B='gwt:onPropertyErrorFn',y='gwt:property',rb='hosted.html?tersus_gwt_Util',kb='ie6',ab='iframe',t='img',bb="javascript:''",pb='loadExternalRefs',v='meta',eb='moduleRequested',wb='moduleStartup',jb='msie',w='name',gb='opera',db='position:absolute;width:0;height:0;border:none',ib='safari',qb='selectingPermutation',x='startup',m='tersus.gwt.Util',ob='unknown',fb='user.agent',hb='webkit';var Bb=window,k=document,Ab=Bb.__gwtStatsEvent?function(a){return Bb.__gwtStatsEvent(a)}:null,pc,fc,ac,Fb=l,ic={},sc=[],oc=[],Eb=[],lc,nc;Ab&&Ab({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(),type:nb});if(!Bb.__gwt_stylesLoaded){Bb.__gwt_stylesLoaded={}}if(!Bb.__gwt_scriptsLoaded){Bb.__gwt_scriptsLoaded={}}function ec(){try{return Bb.external&&(Bb.external.gwtOnLoad&&Bb.location.search.indexOf(vb)==-1)}catch(a){return false}}
function hc(){if(pc&&fc){var c=k.getElementById(m);var b=c.contentWindow;b.__gwt_initHandlers=tersus_gwt_Util.__gwt_initHandlers;if(ec()){b.__gwt_getProperty=function(a){return bc(a)}}tersus_gwt_Util=null;b.gwtOnLoad(lc,m,Fb);Ab&&Ab({moduleName:m,subSystem:x,evtGroup:wb,millis:(new Date()).getTime(),type:xb})}}
function cc(){var j,h=yb,i;k.write(zb+h+n);i=k.getElementById(h);j=i&&i.previousSibling;while(j&&j.tagName!=o){j=j.previousSibling}function f(b){var a=b.lastIndexOf(p);if(a==-1){a=b.length}var c=b.indexOf(q);if(c==-1){c=b.length}var d=b.lastIndexOf(r,Math.min(c,a));return d>=0?b.substring(0,d+1):l}
;if(j&&j.src){Fb=f(j.src)}if(Fb==l){var e=k.getElementsByTagName(s);if(e.length>0){Fb=e[e.length-1].href}else{Fb=f(k.location.href)}}else if(Fb.match(/^\w+:\/\//)){}else{var g=k.createElement(t);g.src=Fb+u;Fb=f(g.src)}if(i){i.parentNode.removeChild(i)}}
function mc(){var f=document.getElementsByTagName(v);for(var d=0,g=f.length;d<g;++d){var e=f[d],h=e.getAttribute(w),b;if(h){if(h==y){b=e.getAttribute(z);if(b){var i,c=b.indexOf(A);if(c>=0){h=b.substring(0,c);i=b.substring(c+1)}else{h=b;i=l}ic[h]=i}}else if(h==B){b=e.getAttribute(z);if(b){try{nc=eval(b)}catch(a){alert(C+b+D)}}}else if(h==E){b=e.getAttribute(z);if(b){try{lc=eval(b)}catch(a){alert(C+b+F)}}}}}}
function bc(d){var e=oc[d](),b=sc[d];if(e in b){return e}var a=[];for(var c in b){a[b[c]]=c}if(nc){nc(d,a,e)}throw null}
var dc;function gc(){if(!dc){dc=true;var a=k.createElement(ab);a.src=bb;a.id=m;a.style.cssText=db;a.tabIndex=-1;k.body.appendChild(a);Ab&&Ab({moduleName:m,subSystem:x,evtGroup:wb,millis:(new Date()).getTime(),type:eb});a.contentWindow.location.replace(Fb+qc)}}
oc[fb]=function(){var d=navigator.userAgent.toLowerCase();var b=function(a){return parseInt(a[1])*1000+parseInt(a[2])};if(d.indexOf(gb)!=-1){return gb}else if(d.indexOf(hb)!=-1){return ib}else if(d.indexOf(jb)!=-1){var c=/msie ([0-9]+)\.([0-9]+)/.exec(d);if(c&&c.length==3){if(b(c)>=6000){return kb}}}else if(d.indexOf(lb)!=-1){var c=/rv:([0-9]+)\.([0-9]+)/.exec(d);if(c&&c.length==3){if(b(c)>=1008)return mb}return lb}return ob};sc[fb]={gecko:0,gecko1_8:1,ie6:2,opera:3,safari:4};tersus_gwt_Util.onScriptLoad=function(){if(dc){fc=true;hc()}};tersus_gwt_Util.onInjectionDone=function(){pc=true;Ab&&Ab({moduleName:m,subSystem:x,evtGroup:pb,millis:(new Date()).getTime(),type:xb});hc()};cc();mc();Ab&&Ab({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(),type:qb});var qc;if(ec()){qc=rb}else{try{qc=sb}catch(a){return}}var kc;function jc(){if(!ac){ac=true;hc();if(k.removeEventListener){k.removeEventListener(tb,jc,false)}if(kc){clearInterval(kc)}}}
if(k.addEventListener){k.addEventListener(tb,function(){gc();jc()},false)}var kc=setInterval(function(){if(/loaded|complete/.test(k.readyState)){gc();jc()}},50);Ab&&Ab({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(),type:xb});Ab&&Ab({moduleName:m,subSystem:x,evtGroup:pb,millis:(new Date()).getTime(),type:nb});k.write(ub)}
tersus_gwt_Util.__gwt_initHandlers=function(i,e,j){var d=window,g=d.onresize,f=d.onbeforeunload,h=d.onunload;d.onresize=function(a){try{i()}finally{g&&g(a)}};d.onbeforeunload=function(a){var c,b;try{c=e()}finally{b=f&&f(a)}if(c!=null){return c}if(b!=null){return b}};d.onunload=function(a){try{j()}finally{h&&h(a);d.onresize=null;d.onbeforeunload=null;d.onunload=null}}};tersus_gwt_Util();// file: 001-NumberFormat.js
/**  domain Javascript formatting utility.
Published in http://www.mredkj.com/javascript/nfdocs.html as a public domain work (no Copyright)
9-November-2005 - Modified by Tersus (Youval Bronicki):
	Move properties to the prototype to prevent each instance from being a big object
12-May-2008  - Modified by Tersus (Youval Bronicki):
    Added support for setting decimal point without separators
16-Nov-2008  - Modified by Tersus (Youval Bronicki):
    Changed toPercentage to use same formatting as toFormatted 
*/
/*
 * NumberFormat 1.5.3
 * v1.5.3 - 29-September-2004
 * v1.5.2 - 27-August-2004
 * v1.5.1 - 13-February-2004
 * v1.5.0 - 20-December-2002
 * v1.0.3 - 23-March-2002
 * v1.0.2 - 13-March-2002
 * v1.0.1 - 20-July-2001
 * v1.0.0 - 13-April-2000
 * http://www.mredkj.com
 */
  
/*
 * NumberFormat -The constructor
 * num - The number to be formatted.
 *  Also refer to setNumber
 * inputDecimal - (Optional) The decimal character for the input
 *  Also refer to setInputDecimal
 */
function NumberFormat() {};
	// constants
	NumberFormat.prototype.COMMA = ',';
	NumberFormat.prototype.PERIOD = '.';
	NumberFormat.prototype.DASH = '-'; // v1.5.0 - new - used internally
	NumberFormat.prototype.LEFT_PAREN = '('; // v1.5.0 - new - used internally
	NumberFormat.prototype.RIGHT_PAREN = ')'; // v1.5.0 - new - used internally
	NumberFormat.prototype.LEFT_OUTSIDE = 0; // v1.5.0 - new - currency
	NumberFormat.prototype.LEFT_INSIDE = 1;  // v1.5.0 - new - currency
	NumberFormat.prototype.RIGHT_INSIDE = 2;  // v1.5.0 - new - currency
	NumberFormat.prototype.RIGHT_OUTSIDE = 3;  // v1.5.0 - new - currency
	NumberFormat.prototype.LEFT_DASH = 0; // v1.5.0 - new - negative
	NumberFormat.prototype.RIGHT_DASH = 1; // v1.5.0 - new - negative
	NumberFormat.prototype.PARENTHESIS = 2; // v1.5.0 - new - negative
	NumberFormat.prototype.NO_ROUNDING = -1 // v1.5.1 - new

	// member variables
	NumberFormat.prototype.num = null;
	NumberFormat.prototype.numOriginal = null;
	NumberFormat.prototype.hasSeparators = null;  // v1.5.0 - new
	NumberFormat.prototype.separatorValue = NumberFormat.prototype.COMMA;  // v1.5.0 - new
	NumberFormat.prototype.inputDecimalValue = NumberFormat.prototype.PERIOD; // v1.5.0 - new
	NumberFormat.prototype.decimalValue = NumberFormat.prototype.PERIOD;  // v1.5.0 - new
	NumberFormat.prototype.negativeFormat = NumberFormat.prototype.LEFT_DASH; // v1.5.0 - new
	NumberFormat.prototype.negativeRed = false; // v1.5.0 - new
	NumberFormat.prototype.hasCurrency = false;  // v1.5.0 - modified
	NumberFormat.prototype.currencyPosition = NumberFormat.prototype.LEFT_INSIDE;  // v1.5.0 - new
	NumberFormat.prototype.currencyValue = '$';  // v1.5.0 - modified
	NumberFormat.prototype.places = NumberFormat.prototype.NO_ROUNDING;
	NumberFormat.prototype.roundToPlaces = null; // v1.5.1 - new

	// external methods
	NumberFormat.prototype.setNumber = setNumberNF;
	NumberFormat.prototype.toUnformatted = toUnformattedNF;
	NumberFormat.prototype.setInputDecimal = setInputDecimalNF; // v1.5.0 - new
	NumberFormat.prototype.setSeparators = setSeparatorsNF; // v1.5.0 - new - for separators and decimals
	NumberFormat.prototype.setCommas = setCommasNF;
	NumberFormat.prototype.setNegativeFormat = setNegativeFormatNF; // v1.5.0 - new
	NumberFormat.prototype.setNegativeRed = setNegativeRedNF; // v1.5.0 - new
	NumberFormat.prototype.setCurrency = setCurrencyNF;
	NumberFormat.prototype.setCurrencyPrefix = setCurrencyPrefixNF;
	NumberFormat.prototype.setCurrencyValue = setCurrencyValueNF; // v1.5.0 - new - setCurrencyPrefix uses this
	NumberFormat.prototype.setCurrencyPosition = setCurrencyPositionNF; // v1.5.0 - new - setCurrencyPrefix uses this
	NumberFormat.prototype.setPlaces = setPlacesNF;
	NumberFormat.prototype.toFormatted = toFormattedNF;
	NumberFormat.prototype.toPercentage = toPercentageNF;
	NumberFormat.prototype.getOriginal = getOriginalNF;
	NumberFormat.prototype.moveDecimalRight = moveDecimalRightNF;
	NumberFormat.prototype.moveDecimalLeft = moveDecimalLeftNF;

	// internal methods
	NumberFormat.prototype.getRounded = getRoundedNF;
	NumberFormat.prototype.preserveZeros = preserveZerosNF;
	NumberFormat.prototype.justNumber = justNumberNF;
	NumberFormat.prototype.expandExponential = expandExponentialNF;
	NumberFormat.prototype.getZeros = getZerosNF;
	NumberFormat.prototype.moveDecimalAsString = moveDecimalAsStringNF;
	NumberFormat.prototype.moveDecimal = moveDecimalNF;
	NumberFormat.prototype.addSeparators = addSeparatorsNF;



/*
 * setInputDecimal
 * val - The decimal value for the input.
 *
 * v1.5.0 - new
 */
function setInputDecimalNF(val)
{
	this.inputDecimalValue = val;
}

/*
 * setNumber - Sets the number
 * num - The number to be formatted
 * inputDecimal - (Optional) The decimal character for the input
 *  Also refer to setInputDecimal
 * 
 * If there is a non-period decimal format for the input,
 * setInputDecimal should be called before calling setNumber.
 *
 * v1.5.0 - modified
 */
function setNumberNF(num, inputDecimal)
{
	if (inputDecimal != null) {
		this.setInputDecimal(inputDecimal); // v.1.5.1 - new
	}
	
	this.numOriginal = num;
	this.num = this.justNumber(num);
}

/*
 * toUnformatted - Returns the number as just a number.
 * If the original value was '100,000', then this method will return the number 100000
 * v1.0.2 - Modified comments, because this method no longer returns the original value.
 */
function toUnformattedNF()
{
	return (this.num);
}

/*
 * getOriginal - Returns the number as it was passed in, which may include non-number characters.
 * This function is new in v1.0.2
 */
function getOriginalNF()
{
	return (this.numOriginal);
}

/*
 * setNegativeFormat - How to format a negative number.
 * 
 * format - The format. Use one of the following constants.
 * LEFT_DASH   example: -1000
 * RIGHT_DASH  example: 1000-
 * PARENTHESIS example: (1000)
 *
 * v1.5.0 - new
 */
function setNegativeFormatNF(format)
{
	this.negativeFormat = format;
}

/*
 * setNegativeRed - Format the number red if it's negative.
 * 
 * isRed - true, to format the number red if negative, black if positive;
 *  false, for it to always be black font.
 *
 * v1.5.0 - new
 */
function setNegativeRedNF(isRed)
{
	this.negativeRed = isRed;
}

/*
 * setSeparators - One purpose of this method is to set a
 *  switch that indicates if there should be separators between groups of numbers.
 *  Also, can use it to set the values for the separator and decimal.
 *  For example, in the value 1,000.00
 *   The comma (,) is the separator and the period (.) is the decimal.
 *
 * Both separator or decimal are not required.
 * The separator and decimal cannot be the same value. If they are, decimal with be changed.
 * Can use the following constants (via the instantiated object) for separator or decimal:
 *  COMMA
 *  PERIOD
 * 
 * isC - true, if there should be separators; false, if there should be no separators
 * separator - the value of the separator.
 * decimal - the value of the decimal.
 *
 * v1.5.0 - new
 */
function setSeparatorsNF(isC, separator, decimal)
{
	this.hasSeparators = isC;
	
	// Make sure a separator was passed in
	if (separator == null) separator = this.COMMA;
	
	// Make sure a decimal was passed in
	if (decimal == null) decimal = this.PERIOD;
	
	// Additionally, make sure the values aren't the same.
	//  When the separator and decimal both are periods, make the decimal a comma.
	//  When the separator and decimal both are any other value, make the decimal a period.
	if (separator == decimal) {
		this.decimalValue = (decimal == this.PERIOD) ? this.COMMA : this.PERIOD;
	} else {
		this.decimalValue = decimal;
	}
	
	// Since the decimal value changes if decimal and separator are the same,
	// the separator value can keep its setting.
	this.separatorValue = separator;
}

/*
 * setCommas - Sets a switch that indicates if there should be commas.
 * The separator value is set to a comma and the decimal value is set to a period.
 * isC - true, if the number should be formatted with separators (commas); false, if no separators
 *
 * v1.5.0 - modified
 */
function setCommasNF(isC)
{
	this.setSeparators(isC, this.COMMA, this.PERIOD);
}

/*
 * setCurrency - Sets a switch that indicates if should be displayed as currency
 * isC - true, if should be currency; false, if not currency
 */
function setCurrencyNF(isC)
{
	this.hasCurrency = isC;
}

/*
 * setCurrencyPrefix - Sets the symbol for currency.
 * val - The symbol
 */
function setCurrencyValueNF(val)
{
	this.currencyValue = val;
}

/*
 * setCurrencyPrefix - Sets the symbol for currency.
 * The symbol will show up on the left of the numbers and outside a negative sign.
 * cp - The symbol
 *
 * v1.5.0 - modified - This now calls setCurrencyValue and setCurrencyPosition(this.LEFT_OUTSIDE)
 */
function setCurrencyPrefixNF(cp)
{
	this.setCurrencyValue(cp);
	this.setCurrencyPosition(this.LEFT_OUTSIDE);
}

/*
 * setCurrencyPosition - Sets the position for currency,
 *  which includes position relative to the numbers and negative sign.
 * cp - The position. Use one of the following constants.
 *  This method does not automatically put the negative sign at the left or right.
 *  They are left by default, and would need to be set right with setNegativeFormat.
 *	LEFT_OUTSIDE  example: $-1.00
 *	LEFT_INSIDE   example: -$1.00
 *	RIGHT_INSIDE  example: 1.00$-
 *	RIGHT_OUTSIDE example: 1.00-$
 *
 * v1.5.0 - new
 */
function setCurrencyPositionNF(cp)
{
	this.currencyPosition = cp
}

/*
 * setPlaces - Sets the precision of decimal places
 * p - The number of places.
 *  -1 or the constant NO_ROUNDING turns off rounding to a set number of places.
 *  Any other number of places less than or equal to zero is considered zero.
 *
 * v1.5.1 - modified
 */
function setPlacesNF(p)
{
	this.roundToPlaces = !(p == this.NO_ROUNDING); // v1.5.1
	this.places = (p < 0) ? 0 : p; // v1.5.1 - Don't leave negatives.
}

/*
 * v1.5.2 - new
 *
 * addSeparators
 * The value to be formatted shouldn't have any formatting already.
 *
 * nStr - A number or number as a string
 * inD - Input decimal (string value). Example: '.'
 * outD - Output decimal (string value). Example: '.'
 * sep - Output separator (string value). Example: ','
 */
function addSeparatorsNF(nStr, inD, outD, sep)
{
	nStr += '';
	var dpos = nStr.indexOf(inD);
	var nStrEnd = '';
	if (dpos != -1) {
		nStrEnd = outD + nStr.substring(dpos + 1, nStr.length);
		nStr = nStr.substring(0, dpos);
	}
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(nStr)) {
		nStr = nStr.replace(rgx, '$1' + sep + '$2');
	}
	return nStr + nStrEnd;
}

/*
 * toFormatted - Returns the number formatted according to the settings (a string)
 *
 * v1.5.0 - modified
 * v1.5.1 - modified
 */
function toFormattedNF(v)
{	
	var pos;
	var nNum = v!=null ? v : this.num; // v1.0.1 - number as a number
	var nStr;            // v1.0.1 - number as a string
	var splitString = new Array(2);   // v1.5.0
	
	// round decimal places - modified v1.5.1
	// Note: Take away negative temporarily with Math.abs
	if (this.roundToPlaces) {
		nNum = this.getRounded(nNum);
		nStr = this.preserveZeros(Math.abs(nNum)); // this step makes nNum into a string. v1.0.1 Math.abs
	} else {
		nStr = this.expandExponential(Math.abs(nNum)); // expandExponential is called in preserveZeros, so call it here too
	}
	
	// v1.5.3 - lost the if in 1.5.2, so putting it back
	if (this.hasSeparators) {
		// v1.5.2
		// Note that the argument being passed in for inD is this.PERIOD
		//  That's because the toFormatted method is working with an unformatted number
		nStr = this.addSeparators(nStr, this.PERIOD, this.decimalValue, this.separatorValue);
	}
	else
	{
		// still need to set the decimal period (which could have been overridden)
		nStr = nStr.replace(/\./g,this.decimalValue);
	}
	
	// negative and currency
	// $[c0] -[n0] $[c1] -[n1] #.#[nStr] -[n2] $[c2] -[n3] $[c3]
	var c0 = '';
	var n0 = '';
	var c1 = '';
	var n1 = '';
	var n2 = '';
	var c2 = '';
	var n3 = '';
	var c3 = '';
	var negSignL = (this.negativeFormat == this.PARENTHESIS) ? this.LEFT_PAREN : this.DASH;
	var negSignR = (this.negativeFormat == this.PARENTHESIS) ? this.RIGHT_PAREN : this.DASH;
		
	if (this.currencyPosition == this.LEFT_OUTSIDE) {
		// add currency sign in front, outside of any negative. example: $-1.00	
		if (nNum < 0) {
			if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
			if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
		}
		if (this.hasCurrency) c0 = this.currencyValue;
	} else if (this.currencyPosition == this.LEFT_INSIDE) {
		// add currency sign in front, inside of any negative. example: -$1.00
		if (nNum < 0) {
			if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
			if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
		}
		if (this.hasCurrency) c1 = this.currencyValue;
	}
	else if (this.currencyPosition == this.RIGHT_INSIDE) {
		// add currency sign at the end, inside of any negative. example: 1.00$-
		if (nNum < 0) {
			if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
			if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
		}
		if (this.hasCurrency) c2 = this.currencyValue;
	}
	else if (this.currencyPosition == this.RIGHT_OUTSIDE) {
		// add currency sign at the end, outside of any negative. example: 1.00-$
		if (nNum < 0) {
			if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
			if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
		}
		if (this.hasCurrency) c3 = this.currencyValue;
	}

	nStr = c0 + n0 + c1 + n1 + nStr + n2 + c2 + n3 + c3;
	
	// negative red
	if (this.negativeRed && nNum < 0) {
		nStr = '<font color="red">' + nStr + '</font>';
	}

	return (nStr);
}

/*
 * 2008-11-16 (Tersus - uses same formatting as toFormatted)
 * toPercentage - Format the current number as a percentage.
 * This is separate from most of the regular formatting settings.
 * The exception is the number of decimal places.
 * If a number is 0.123 it will be formatted as 12.3%
 *
 * !! This is an initial version, so it doesn't use many settings.
 * !! should use some of the formatting settings that toFormatted uses.
 * !! probably won't want to use settings like currency.
 *
 * v1.5.0 - new
 */
function toPercentageNF()
{
	nNum = this.num * 100;
	
	// round decimal places
	nNum = this.toFormatted(nNum);
	
	return nNum + '%';
}

/*
 * Return concatenated zeros as a string. Used to pad a number.
 * It might be extra if already have many decimal places
 * but is needed if the number doesn't have enough decimals. 
 */
function getZerosNF(places)
{
		var extraZ = '';
		var i;
		for (i=0; i<places; i++) {
			extraZ += '0';
		}
		return extraZ;
}

/*
 * Takes a number that JavaScript expresses in notational format
 * and makes it the full number (as a string).
 * e.g. Makes -1e-21 into -0.000000000000000000001
 *
 * If the value passed in is not a number (as determined by isNaN),
 * this function just returns the original value.
 *
 * Exponential number formats can include 1e21 1e+21 1e-21
 *  where 1e21 and 1e+21 are the same thing.
 *
 * If an exponential number is evaluated by JavaScript,
 * it will change 12.34e-9 to 1.234e-8,
 * which is a benefit to this method, because
 * it prevents extra zeros that occur for certain numbers
 * when using moveDecimalAsString
 *
 * Returns a string.
 *
 * v1.5.1 - new
 */
function expandExponentialNF(origVal)
{
	if (isNaN(origVal)) return origVal;

	var newVal = parseFloat(origVal) + ''; // parseFloat to let JavaScript evaluate number
	var eLoc = newVal.toLowerCase().indexOf('e');

	if (eLoc != -1) {
		var plusLoc = newVal.toLowerCase().indexOf('+');
		var negLoc = newVal.toLowerCase().indexOf('-', eLoc); // search for - after the e
		var justNumber = newVal.substring(0, eLoc);
		
		if (negLoc != -1) {
			// shift decimal to the left
			var places = newVal.substring(negLoc + 1, newVal.length);
			justNumber = this.moveDecimalAsString(justNumber, true, parseInt(places));
		} else {
			// shift decimal to the right
			// Check if there's a plus sign, and if not refer to where the e is.
			// This is to account for either formatting 1e21 or 1e+21
			if (plusLoc == -1) plusLoc = eLoc;
			var places = newVal.substring(plusLoc + 1, newVal.length);
			justNumber = this.moveDecimalAsString(justNumber, false, parseInt(places));
		}
		
		newVal = justNumber;
	}

	return newVal;
} 

/*
 * Move decimal right.
 * Returns a number.
 *
 * v1.5.1 - new
 */
function moveDecimalRightNF(val, places)
{
	var newVal = '';
	
	if (places == null) {
		newVal = this.moveDecimal(val, false);
	} else {
		newVal = this.moveDecimal(val, false, places);
	}
	
	return newVal;
}

/*
 * Move decimal left.
 * Returns a number.
 *
 * v1.5.1 - new
 */
function moveDecimalLeftNF(val, places)
{
	var newVal = '';
	
	if (places == null) {
		newVal = this.moveDecimal(val, true);
	} else {
		newVal = this.moveDecimal(val, true, places);
	}
	
	return newVal;
}

/*
 * moveDecimalAsString
 * This is used by moveDecimal, and does not run parseFloat on the return value.
 * 
 * Normally a decimal place is moved by multiplying by powers of 10
 * Multiplication and division in JavaScript can result in floating point limitations.
 * So use this method to move a decimal place left or right.
 *
 * Parameters:
 * val - The value to be shifted. Can be a number or a string,
 *  but don't include special characters. It should evaluate to a number.
 * left - If true, then move decimal left. If false, move right.
 * places - (optional) If not included, then use the objects this.places
 *  The purpose is so this method can be used independent of the state of the object.
 *
 * The regular expressions:
 * re1
 * Pad with zeros in case there aren't enough numbers to cover the spaces shift.
 * A left shift pads to the left, and a right shift pads to the right.
 * Can't just concatenate. There might be a negative sign or the value could be an exponential.
 *
 * re2
 * Switch the decimal.
 * Need the first [0-9]+ to force the search to start rightmost.
 * The \.? and [0-9]{} criteria are the pieces that will be switched
 *
 * Other notes:
 * This method works on exponential numbers, e.g. 1.7e-12
 * because the regular expressions only modify the number and decimal parts.
 *
 * Mozilla can't handle [0-9]{0} in the regular expression.
 *  Fix: Since nothing changes when the decimal is shifted zero places, return the original value.
 *
 * IE is incorrect if exponential ends in .
 *  e.g. -8500000000000000000000. should be -8.5e+21
 *  IE counts it as -8.5e+22
 *	Fix: Replace trailing period, if there is one, using replace(/\.$/, '').
 *
 * Netscape 4.74 cannot handle a leading - in the string being searched for the re2 expressions.
 *  e.g. /([0-9]*)(\.?)([0-9]{2})/ should match everything in -100.00 except the -
 *  but it matches nothing using Netscape 4.74.
 *  It might be a combination of the * ? special characters.
 *  Fix: (-?) was added to each of the re2 expressions to look for - one or zero times.
 *
 * Returns a string.
 *
 * v1.5.1 - new
 * v1.5.2 - modified
 */
function moveDecimalAsStringNF(val, left, places)
{
	var spaces = (arguments.length < 3) ? this.places : places;
	if (spaces <= 0) return val; // to avoid Mozilla limitation
			
	var newVal = val + '';
	var extraZ = this.getZeros(spaces);
	var re1 = new RegExp('([0-9.]+)');
	if (left) {
		newVal = newVal.replace(re1, extraZ + '$1');
		var re2 = new RegExp('(-?)([0-9]*)([0-9]{' + spaces + '})(\\.?)');		
		newVal = newVal.replace(re2, '$1$2.$3');
	} else {
		var reArray = re1.exec(newVal); // v1.5.2
		if (reArray != null) {
			newVal = newVal.substring(0,reArray.index) + reArray[1] + extraZ + newVal.substring(reArray.index + reArray[0].length); // v1.5.2
		}
		var re2 = new RegExp('(-?)([0-9]*)(\\.?)([0-9]{' + spaces + '})');
		newVal = newVal.replace(re2, '$1$2$4.');
	}
	newVal = newVal.replace(/\.$/, ''); // to avoid IE flaw
	
	return newVal;
}

/*
 * moveDecimal
 * Refer to notes in moveDecimalAsString
 * parseFloat is called here to clear away the padded zeros.
 *
 * Returns a number.
 *
 * v1.5.1 - new
 */
function moveDecimalNF(val, left, places)
{
	var newVal = '';
	
	if (places == null) {
		newVal = this.moveDecimalAsString(val, left);
	} else {
		newVal = this.moveDecimalAsString(val, left, places);
	}
	
	return parseFloat(newVal);
}

/*
 * getRounded - Used internally to round a value
 * val - The number to be rounded
 * 
 *  To round to a certain decimal precision,
 *  all that should need to be done is
 *  multiply by a power of 10, round, then divide by the same power of 10.
 *  However, occasional numbers don't get exact results in most browsers.
 *  e.g. 0.295 multiplied by 10 yields 2.9499999999999997 instead of 2.95
 *  Instead of adjusting the incorrect multiplication,
 *  this function uses string manipulation to shift the decimal.
 *
 * Returns a number.
 *
 * v1.5.1 - modified
 */
function getRoundedNF(val)
{
	val = this.moveDecimalRight(val);
	val = Math.round(val);
	val = this.moveDecimalLeft(val);
	
	return val;
}

/*
 * preserveZeros - Used internally to make the number a string
 * 	that preserves zeros at the end of the number
 * val - The number
 */
function preserveZerosNF(val)
{
	var i;

	// make a string - to preserve the zeros at the end
	val = this.expandExponential(val);
	
	if (this.places <= 0) return val; // leave now. no zeros are necessary - v1.0.1 less than or equal
	
	var decimalPos = val.indexOf('.');
	if (decimalPos == -1) {
		val += '.';
		for (i=0; i<this.places; i++) {
			val += '0';
		}
	} else {
		var actualDecimals = (val.length - 1) - decimalPos;
		var difference = this.places - actualDecimals;
		for (i=0; i<difference; i++) {
			val += '0';
		}
	}
	
	return val;
}

/*
 * justNumber - Used internally to parse the value into a floating point number.
 * Replace all characters that are not 0-9, a decimal point, or a negative sign.
 *
 *  A number can be entered using special notation.
 *  For example, the following is a valid number: 0.0314E+2
 *
 * v1.0.2 - new
 * v1.5.0 - modified
 * v1.5.1 - modified
 * v1.5.2 - modified
 */
function justNumberNF(val)
{
	newVal = val + '';
	
	var isPercentage = false;
	
	// check for percentage
	// v1.5.0
	if (newVal.indexOf('%') != -1) {
		newVal = newVal.replace(/\%/g, '');
		isPercentage = true; // mark a flag
	}
		
	// Replace everything but digits - + ( ) e E
	var re = new RegExp('[^\\' + this.inputDecimalValue + '\\d\\-\\+\\(\\)eE]', 'g');	// v1.5.2	
	newVal = newVal.replace(re, '');
	// Replace the first decimal with a period and the rest with blank
	// The regular expression will only break if a special character
	//  is used as the inputDecimalValue
	//  e.g. \ but not .
	var tempRe = new RegExp('[' + this.inputDecimalValue + ']', 'g');
	var treArray = tempRe.exec(newVal); // v1.5.2
	if (treArray != null) {
	  var tempRight = newVal.substring(treArray.index + treArray[0].length); // v1.5.2
		newVal = newVal.substring(0,treArray.index) + this.PERIOD + tempRight.replace(tempRe, ''); // v1.5.2
	}
	
	// If negative, get it in -n format
	if (newVal.charAt(newVal.length - 1) == this.DASH ) {
		newVal = newVal.substring(0, newVal.length - 1);
		newVal = '-' + newVal;
	}
	else if (newVal.charAt(0) == this.LEFT_PAREN
	 && newVal.charAt(newVal.length - 1) == this.RIGHT_PAREN) {
		newVal = newVal.substring(1, newVal.length - 1);
		newVal = '-' + newVal;
	}
	
	newVal = parseFloat(newVal);
	
	if (!isFinite(newVal)) {
		newVal = 0;
  }
	
	// now that it's a number, adjust for percentage, if applicable.
  // example. if the number was formatted 24%, then move decimal left to get 0.24
  // v1.5.0 - updated v1.5.1
  if (isPercentage) {
  	newVal = this.moveDecimalLeft(newVal, 2);
  }
		
	return newVal;
}
// file: 002-cookies.js
/* cookies.js */
/*
     Example File From "JavaScript and DHTML Cookbook"
     Published by O'Reilly & Associates
     Copyright 2003 Danny Goodman
*/

// utility function to retrieve a future expiration date in proper format;
// pass three integer parameters for the number of days, hours,
// and minutes from now you want the cookie to expire; all three
// parameters required, so use zeros where appropriate
function getExpDate(days, hours, minutes) {
    var expDate = new Date();
    if (typeof days == "number" && typeof hours == "number" && typeof hours == "number") {
        expDate.setDate(expDate.getDate() + parseInt(days));
        expDate.setHours(expDate.getHours() + parseInt(hours));
        expDate.setMinutes(expDate.getMinutes() + parseInt(minutes));
        return expDate.toGMTString();
    }
}

// utility function called by getCookie()
function getCookieVal(offset) {
    var endstr = document.cookie.indexOf (";", offset);
    if (endstr == -1) {
        endstr = document.cookie.length;
    }
    return unescape(document.cookie.substring(offset, endstr));
}

// primary function to retrieve cookie by name
function getCookie(name) {
    var arg = name + "=";
    var alen = arg.length;
    var cookie = document.cookie;
    var clen = cookie.length;
    var i = 0;
    while (i < clen) {
        var j = i + alen;
        if (cookie.substring(i, j) == arg) {
            return getCookieVal(j);
        }
        i = cookie.indexOf(" ", i) + 1;
        if (i == 0) break; 
    }
    return null;
}

// store cookie value with optional details as needed
function setCookie(name, value, expires, path, domain, secure) {
    document.cookie = name + "=" + escape (value) +
        ((expires) ? "; expires=" + expires : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

// remove the cookie by setting ancient expiration date
function deleteCookie(name,path,domain) {
    if (getCookie(name)) {
        document.cookie = name + "=" +
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}

// file: 005-tersus.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 if (!window.tersus) window.tersus  = {};
if (!tersus.settings) tersus.settings = {};
window.tlog = null;
tersus.ANYTHING = 'Common/Data Types/Anything';
tersus.loadScript = function loadScript(url,w)
{
	if (!w)
		w = window;
    var loadScript = w.document.createElement("script");
    
    // Add script object attributes
    loadScript.setAttribute("type", "text/javascript");
    loadScript.setAttribute("charset", "utf-8");
    loadScript.setAttribute("src", url);
	var head = w.document.getElementsByTagName("head").item(0);
	head.appendChild(loadScript);

};
tersus.topZindex = 10;
tersus.alertMode = {interactive:true};
tersus.invokeAction=function(eventName,parameters, domEvent, targetNode)
{
	if (!targetNode)
	targetNode = window.currentRootDisplayNode;
	if (targetNode)
	{
		var eventAttributes = null;
		if (domEvent)
			eventAttributes = getEventAttributes(domEvent);

		var eventSpec = null;
		for (var eventKey in Events)
		{
			if (Events[eventKey].elementName == eventName)
			eventSpec = Events[eventKey];
		}
		if (!eventSpec)
			eventSpec = new tersus.Event(eventName); // Ad-hoc event
	
		window.engine.handleEvent(targetNode,eventSpec,parameters,eventAttributes);
	}
};
window.tersus.clearLog = function()
{
	window.tersus._log = [];
	window.tlog  = window.tersus.log;
};
tersus.formatTime = function(time)
{
	var p2 = tersus.DateAndTime.pad2;
	return  p2(time.getHours())+':'+p2(time.getMinutes())+':'+p2(time.getSeconds());
};

tersus.useXMLHTTPRequest = true;
tersus.autoLogout = true;
window.tersus.log = function(msg1, msg2, msg3)
{
	var now=new Date();
	var time = now.getTime();
	if (l = window.tersus._log)
	{
		l.push(time);
		l.push('\t');
		l.push(tersus.escapeHTML(msg1));
		if (msg2 != null)
		{
			l.push('\t');
			l.push(msg2);
		}			
		if (msg3 != null)
		{
			l.push('\t');
			l.push(msg3);
		}		
		l.push('\n');	
	}
};
window.tersus.showLog = function()
{
	if (window.tersus._log)
	{
		var w = window.open();
		w.document.write('<pre>');
		w.document.write(window.tersus._log.join(''));
		w.document.close();
	}
	window.tersus.clearLog();
};
window.tersus.escapeHTML = function(s)
{
	if (s == null)
		return '';
	if (typeof(s) != 'string')
		s = s.toString();
	s = s.replace(/&/g, '&amp;');
	s = s.replace(/</g, '&lt;');
	s = s.replace(/>/g, '&gt;');
	s = s.replace(/\n/g, '<br/>');
	return s;	
};
tersus.onUnload = function()
{
	if (tersus.Subscribe && tersus.Subscribe.xhr)
	{
		tersus.Subscribe.xhr.abort();
	}
	if (! tersus.reloading) // the onunload event should not be fired when we're reloading
	{
		tersus.isUnloading = true;
		if (window.rootDisplayNode)
			window.engine.handleEvent(window.rootDisplayNode,Events.ON_UNLOAD);
		if (tersus.autoLogout)
			tersus.logout();
	}
};
tersus._disabled = false;
tersus.createClassNameList = function()
{
	var list = [];
	var sheets = document.styleSheets;
	var count = 0;
	for (var i=0;i<sheets.length;i++)
	{
		var sheet = sheets[i];
		var rules = sheet.cssRules;
		if (rules == undefined)
			rules = sheet.rules; //IE
		if (rules == undefined)
			break;
		for (var j=0;j<rules.length;j++)
		{
			var rule = rules[j];
			var selectorText = rule.selectorText; 
			/* Adding ' ' to make sure we have somthing before the .,
			 so we can always ignore the first part after splitting */
			var classNames = (' '+selectorText).split('.');
			classNames.shift();
			list = list.concat(classNames);
		}
	}
	tersus.styleClassNames  = new Set(list);
};
tersus.logout = function logout()
{
	var req = createXMLHTTPRequest();
	
	var url=tersus.rootURL+'Logout';
	req.open('GET', url, false);
	req.send(null);
};
tersus.KEEP_ALIVE_INTERVAL=600000; //10 minutes
tersus.DEV_UPDATE_CHECK_INTERVAL = 2000; // 2 seconds
tersus.PROD_UPDATE_CHECK_INTERVAL = 60000; // 1 minute
tersus.init = function()
{
	window.onfocus = tersus.checkUpdate;
	tersus.async.exec(tersus.initServiceResponseFrames);
	if (window.browser == 'IE')
		window.document.body.onunload = tersus.onUnload;
	else
		window.onunload = tersus.onUnload;
		
	tersus.createClassNameList();
	tersus.repository = new ConstructorRepository();
	window.onresize = tersus.onResize;
	if (tersus.settings.dev_mode)
		tersus.updateCheckInterval = tersus.DEV_UPDATE_CHECK_INTERVAL;
	else
		tersus.updateCheckInterval = tersus.PROD_UPDATE_CHECK_INTERVAL;
	setInterval(tersus.keepAlive, tersus.KEEP_ALIVE_INTERVAL);
//	tersus.clearLog();
};
tersus.noop = function()
{
};
tersus.keepAliveReq = null;
tersus.keepAlive = function()
{
	var req = tersus.keepAliveReq;
	if (!req)
		req = tersus.keepAliveReq = createXMLHTTPRequest();
	var url = tersus.rootURL+'blank.html?'+(new Date()).getTime();
	req.open('GET', url, true);
	req.onreadystatechange = tersus.noop;
	req.send(null);
};
tersus.getTimestampReq = null;
tersus.lastCheckUpdateTime = 0;
tersus.checkUpdate = function()
{
	var time = (new Date()).getTime();
	if (time < tersus.lastCheckUpdateTime + tersus.updateCheckInterval)
		return; // We don't want to check too often
	tersus.getTimestamp(tersus.handleCheckUpdateResponse);
}
tersus.getTimestamp = function (callback)
{
	var time = (new Date()).getTime();
	tersus.lastCheckUpdateTime = time;
	var path = 'Timestamp';
 	var url = tersus.rootURL+path;
	var req = tersus.getTimestampReq;
	if (!req)
		req = tersus.getTimestampReq = createXMLHTTPRequest();
	req.open('POST',url, true);
	req.onreadystatechange = callback;
	req.send(null);
	
}
if (tersus.lastTimestamp == undefined)
	tersus.lastTimestamp = 0;
tersus.setLastTimestamp = function(timestamp)
{
	if (timestamp > tersus.lastTimestamp)
		tersus.lastTimestamp = timestamp;
};
tersus.handleCheckUpdateResponse = function(responseText)
{
	if (!window.tersus)
		return; // This can happen, at least in Firefox, when navigating away from the application
	var req = tersus.getTimestampReq;
	if (req.readyState != 4)
		return;
	if (req.status == 200 || req.responseText)
	{
		var currentTimestamp = parseInt(req.responseText);
		if (tersus.lastTimestamp && currentTimestamp && currentTimestamp > tersus.lastTimestamp)
		{
			if (tlog) tlog("Application Updated -> Reloading");
			tersus.progress.set('Reloading Application ...');
//			tersus.progress.show();
			setTimeout(tersus.reloadApplication,1000);
		}
		else
			if (tlog) tlog("No update");
		tersus.setLastTimestamp(currentTimestamp);
	}
};
tersus.reloadApplication = function()
{
	tersus.reloading = true;
	var windows = tersus.getWindows();
	for (var i=0;i<windows.length;i++)
	{
		if (window != windows[i])
			windows[i].close();
	}
	location.replace('reload.html?'+encodeURIComponent(location.href));
};
tersus.initServiceResponseFrames = function ()
{
	tersus.serviceResponseFrames = [];
	for (var i=0; i<10; i++)
	{
		var f = tersus.serviceResponseFrames[i] = createAnIFrame(window,'_service_'+i);
		f.src  = 'blank.html';
	};
	tersus.nextResponseFrameIndex = 0;
};

tersus.nextServiceResponseFrame = function ()
{
	var iframe = tersus.serviceResponseFrames[tersus.nextResponseFrameIndex++];
	if (tersus.nextResponseFrameIndex >= tersus.serviceResponseFrames.length)
		tersus.nextResponseFrameIndex = 0;
	return iframe;
};
tersus.windows = [self];
tersus.getWindows = function()
{
	if (tersus.windows.length > 1)
		tersus.unregisterClosedWindows();
	return tersus.windows;
};
tersus.registerWindow = function (w)
{
	tersus.windows.push(w);
	if (tlog) tlog("registerWindow:"+w.name+" current:"+tersus.windows.length);
};
tersus.unregisterWindow = function (w)
{
	for (var i=0; i <tersus.windows.length; i++)
	{
		if (tersus.windows[i] == w)
		{
			tersus.windows.splice(i,1); // remove
			if (tlog) tlog("unregisterWindow:"+w.name+" index:"+i);
			return;
		}
		if (tlog) tlog("unregisterWindow:"+w.name+" ** not found **");
	}
	
}
tersus.popupNodes = {}; 
tersus.checkWindow = function (w)
{
	try
	{
		return w && !w.closed;
	}
	catch (e)
	{
		return false;
	}
}
tersus.unregisterPopupNodes = function()
{
	for (var id in tersus.popupNodes)
	{
		var node = tersus.popupNodes[id];
		var alive = false;
		try
		{
			alive = node.currentWindow && ! node.currentWindow.closed && (node.isPopIn || (id == node.currentWindow.popupId));
		}
		catch (e)
		{
		}
		if (! alive)
		{
			delete tersus.popupNodes[id];
		}
	};
};
tersus.unregisterClosedWindows = function ()
{
	if (tlog) tlog("unregisterClosedWindows - before:"+tersus.windows.length);
	var temp = [];
	for (var i=0;i<tersus.windows.length;i++)
	{
		var w = tersus.windows[i];
		try
		{
			if ((! w.closed) && w.document && w.document.body)
				temp.push(w);
			else
				if (tlog) tlog(w.name + ' closed:'+w.closed + ' body:'+w.document.body);
		}
		catch (e)
		{
			if (tlog) tlog(e);
		};
	}
	tersus.windows = temp;
	if (tlog) tlog("unregisterClosedWindows - after:"+tersus.windows.length);
};
tersus.progress = {};
tersus.progress.setStatus = function (msg)
{
	var windows = tersus.getWindows();
	for (var i=0;i<windows.length;i++)
		windows[i].status = msg;
};
/** Threshold for forcing the progress bar to open when handling a service response */
tersus.progress.responseLengthThreshold = 10000;
tersus.progress.set = function (msg, cancellationFunc)
{
	if (tlog) tlog("tersus.progress.set('"+msg+"')");
	
	var p = tersus.progress;
	setTimeout(function(){tersus.progress.setStatus(msg);},0);
	var windows = tersus.getWindows();
	for (var i=0;i<windows.length;i++)
	{
		// Create or Update a progress bar for each window of the applications
		var w = windows[i];
		var body;
		try
		{
			var doc = w.document;
			var body = doc.body;
		}
		catch (e)
		{
			body = null;
		}
		if (body)
		{
			if (window.browser == 'IE')
				body.style.cursor='wait';
			if (!body.className)
				body.className = 'progress';
			else if (body.className.search(/progress/) < 0)
				body.className += ' progress';
	/*		var b = doc.getElementById('progressBar');
			var m = doc.getElementById('progressMessage');
			var c = doc.getElementById('progressCancel');
			if (!b)
			{
				b = doc.createElement('div');
				b.id = 'progressBar';
				b.className = 'progressBar';
				b.style.display='none';
				doc.body.appendChild(b); 
				var img = doc.createElement('img');
				img.id='progressAnimation';
				img.src="images/progress.gif";
				b.appendChild(img);
				m = doc.createElement('div');
				m.id = 'progressMessage';
				b.appendChild(m);
				c = doc.createElement('a');
				c.innerHTML='Cancel';
				c.href='javascript:tersus.progress.cancel()';
				c.id='progressCancel';
				b.appendChild(c);
			}
			m.innerHTML = tersus.escapeHTML(msg);
			if (cancellationFunc)
				c.style.display = '';
			else
				c.style.display='none';
			tersus.progress.cancel = cancellationFunc; */
		}
	}
	tersus.progress.message = msg;
/*	if (!p.active)
	{
		p.active = true;
		window.setTimeout(p.show, tersus.progress.delay);
	} */
	p.active = true; 
};
tersus.progress.delay = 1000; // 1000 milliseconds until progress bar appears
/*tersus.progress.show = function()
{
	if (!tersus.progress.active)
		return;
	var windows = tersus.getWindows();
	for (var i=0;i<windows.length;i++)
	{
		var w = windows[i];
		var b = w.document.getElementById('progressBar');
		if (b)
		{
			b.style.display = '';
			var size = getVisibleSize(b);
			var scroll = getPageScroll(w);
			var pageSize = getPageSize(w);
			b.style.top = scroll.y + (pageSize.height - size.height -30)/2;
			b.style.left = scroll.x + (pageSize.width - size.width)/2;
		}
	};
};*/
tersus.progress.clear = function()
{
	if (tlog) tlog("tersus.progress.clear()");
	var p = tersus.progress;
	if (isBusy())
	{
		if (tlog) tlog("tersus.progress.clear() : still busy ..");
		return;
	}
	setTimeout(function(){tersus.progress.setStatus('Done');},0);
	// Hide progress bar in each window
	var windows = tersus.getWindows();
	var bodies = [];
	for (var i=0;i<windows.length;i++)
	{
		var w = windows[i];
		var body;
		try
		{
			body = w.document.body;
		}
		catch (e)
		{
			body = null; // Exception means window is not accessible
		}
		if (body)
		{
			bodies.push(body);
			var c = body.className;
			if (c == 'progress')
				body.className = '';
			else
				body.className = c.replace(/ progress/, '');
			if (window.browser == 'IE')
				body.style.cursor = '';	
			var b = w.document.getElementById('progressBar');
			if (b)
			{
				b.style.display = 'none';
				if (tlog) tlog("hiding progress bar in "+w.name);
			}
		}
		
	}
//	w.setTimeout(function(){for (var i=0;i<bodies.length;i++) bodies[i].style.cursor='';},0);
	
	p.active = false;
};

tersus.gotoURL = function(url, replace, reload)
{
	if (tlog) tlog("gotoURL: '"+url+"' reload="+reload);
	if (replace)
		window.location.replace(url)
	else
		window.location.href=url;
	if (!reload)
	{
		tersus.history.location = url;
		tersus.loadParams();
	}
	if (window.browser=='IE' && url.indexOf('mailto:')!=0) // In IE, we add the new URL to the history stack using a special IFRAME
	{
		var historyFrame = document.getElementById('_history');
		if (historyFrame)
		{
			var src = 'history.html?'+encodeURIComponent(url);
			if (replace)
				getIFrameWindow(historyFrame).location.replace(src);
			else
				historyFrame.src =src ;
		}
	}
	else
	{
		// The following code loads a dummy page - this makes firefox "understand" that there is nothing more to wait for
		// (the behavior looks like a Firefox bug, but hasn't been fully analyzed)
		var f= tersus.nextServiceResponseFrame()
		if (f)
		{
			getIFrameWindow(f).location.replace('blank.html?u='+encodeURIComponent(url));
		}
	}
};


tersus.history = {};
tersus.history.fixedURL = null;
tersus.history._checkLocation = function()
{
	var current = window.location.href;
	if (current != tersus.history.location)
	{
		if (tlog) tlog("New location:"+current);
		tersus.history.location = current;
		tersus.loadParams();
		tersus.history.locationChanged();
	};
};
tersus.history.checkLocation = function()
{
	if (window.location.href != tersus.history.location)
 		tersus.async.exec(tersus.history._checkLocation, false /* don't wait */);
};


tersus.history.locationChanged = function()
{
	if (tersus.history.fixedURL) /* The 'fixedURL' property is used to disable navigation */
	{
		tersus.gotoURL(tersus.history.fixedURL, false/*replace*/, false/*reload*/);
		return;
	}
	var newPerspectiveName = tersus.searchParams[tersus.PERSPECTIVE];
	if (newPerspectiveName == null && window.perspectives && window.perspectives.length > 0)
		newPerspectiveName = window.perspectives[0].name;
	var newViewName = tersus.searchParams[tersus.VIEW];
	if (newViewName == null && newPerspectiveName)
	{
		var p = getPerspective(newPerspectiveName);
		if (p && p.views && p.views.length>0)
			newViewName = p.views[0].name;
    }

	var perspectiveChanged = window.perspectives && window.perspectives.length > 1 && window.perspective.name != newPerspectiveName;
	var viewChanged = window.view == null || window.view.name != newViewName;
	if (perspectiveChanged || viewChanged)
	{
			window.engine.handleEvent(window.rootDisplayNode,Events.ON_LEAVE_VIEW);
			queueEvent(tersus, tersus.reloadView, [], null,null, -1);
	}
	else
		tersus.updateView();
};

tersus.locationChangeListeners = [];
tersus.updateView = function()
{
	if (tersus.locationChangeListeners.length > 0)
	{
		for (var i =0 ; i< tersus.locationChangeListeners.length; i++)
		{
			var listenerId = tersus.locationChangeListeners[i];
			var listenerNode = tersus.findNode(listenerId);
			if (listenerNode)
				window.engine.handleEvent(listenerNode,Events.ON_LOCATION_CHANGE);
		}
	}
	else
	{
		window.rootDisplayNode.refresh();
		resumeRoot();
	}

}
// Extract search parameters
tersus.loadParams = function()
{
	tersus.searchParams = {};
	var terms = [];
	var search = window.location.search;
	if (search && search.length > 1)
		terms = terms.concat(search.substring(1).split('&'));
		
	// Extract the part that follows the hash ('#').  
	// We can't use window.location.hash because some bad decoding happens there
	var hashIndex = location.href.indexOf('#');
	if (hashIndex >=0)
	{
		var hash = location.href.substring(hashIndex+1);
		terms = terms.concat(hash.split('&'));	
	}
	for (var i=0; i< terms.length; i++)
	{
		var term = terms[i];
		var keyValuePair = term.split('=');
		var key = decodeURIComponent(keyValuePair[0]);
		var value = decodeURIComponent(keyValuePair[1]);
		tersus.searchParams[key]=value;
	}
}

tersus.history.init = function ()
{
	tersus.history.location = window.location.href;
	tersus.loadParams();
	setInterval(tersus.history.checkLocation,100);
}

tersus.getInternalParameters = function()
{
	var params = {};
	for (var p in tersus.searchParams)
		params[p] = tersus.searchParams[p];
	return params;
};
tersus.history.init();	

// tersus.async - a mechanism for preventing concurrency
tersus.async = {};
tersus.async.queue = [];
tersus.async.isBusy = function () { return tersus.async.queue.length > 0;};
tersus.async.nowait = function()
{
	// Returns true if any of the items on queue requires waiting (i.e. is a blocking operation)
	for (var i=0;i<tersus.async.queue.length;i++)
		if (tersus.async.queue[i].wait)
			return false;
	return true;
};
tersus.async.exec = function(f, waitIfBusy)
{
	var item = {func:f, wait:waitIfBusy?true:false};
	if (item.wait && ! tersus.progress.active)
		tersus.progress.set('..');
		
	tersus.async.queue.push(item);
};

tersus.async.worker = function()
{
	while (tersus.async.queue.length > 0 || window.rootDisplayNode && window.rootDisplayNode.status == FlowStatus.READY_TO_RESUME)
	{
		if (window.rootDisplayNode && window.rootDisplayNode.status == FlowStatus.READY_TO_RESUME)
			resumeRoot();
		else if (tersus.async.queue.length > 0)
		{
			var busy = isBusy(); // Root system busy
			if (! busy)
			{
				var item = tersus.async.queue.shift();
				try
				{
					if (tlog) tlog("tersus.async.worker: start");
					item.func();
				}
				finally
				{
					if (tlog) tlog("tersus.async.worker: end");
				}
			}
			else // if the root system is busy, we search for items on the queue that don't need to wait
			{
				var found = false;
				for (var i=0;i<tersus.async.queue.length;i++)
				{
					var item = tersus.async.queue[i];
					if (!item.wait)
					{
						tersus.async.queue.splice(i,1);
						try
						{
							if (tlog) tlog("tersus.async.worker: start");
							item.func();
						}
						finally
						{
							if (tlog) tlog("tersus.async.worker: end");
						}
						found = true;
					}
				}
				if (!found)
					break; // Try again later
			}
		}
	}
	//Since we're here - any queue are waiting for the root system to complete. So if the root system is not busy it means that the queue is empty and we can clear progress
	if (tersus.progress.active)
	{
		if ( ! isBusy())
		{
			debugAssertion(tersus.async.queue.length == 0, 'tersus.async.queue expected to be empty when root system not busy');
			tersus.progress.clear();
		}
	}
	
};
setInterval(tersus.async.worker, 100);
tersus.unescapeString = function unescape_string(s)
{
	return s.replace(/\\n/g, '\n').replace(/\\t/g,'\t').replace(/\\\\/g,'\\');
};
tersus.setDirection = function tersus_setDirection(direction)
{
	var windows = tersus.getWindows();
	window.textDirection = direction;
	for (var i=0; i< windows.length;i++)
	{
		windows[i].document.body.className=direction;
	}
	
};
tersus.getDirection = function tersus_getDirection()
{
	return window.textDirection == 'rtl'? 'rtl':'ltr';
};
tersus.translateResource = function (s)
{
	if (tersus.resourceMap && tersus.resourceMap[s])
		return tersus.resourceMap[s];
	else
		return s;
};
tersus.Conventions = {};
tersus.Conventions.isEventHandler = function (subflow)
{
	return subflow && (subflow.role.match(/^<On .*>$/) || subflow.role == '<Open>') ;
};
window.engine = {};
FlowStatus = {};
FlowStatus.NOT_READY_TO_START = 'Not Ready to Start';
FlowStatus.READY_TO_START = 'Ready to Start';
FlowStatus.READY_TO_RESUME = 'Ready to Resume';
FlowStatus.WAITING_FOR_INPUT = 'Waiting for Input';
FlowStatus.STARTED = 'Started';
FlowStatus.RESUMED = 'Resumed';
FlowStatus.PAUSED = 'Paused';
FlowStatus.DONE = 'Done';

BuiltinNames = {};
BuiltinNames.DONE_EXIT_NAME = '<Done>';

tersus.Event = function(elementName, jsName, methodName)
{
	this.elementName = elementName;
	this.jsName = jsName;
	this.methodName = methodName;
};
Events = {};
Events.ON_CLICK = new tersus.Event('<On Click>', 'onclick', 'onClick');
Events.ON_CONTEXT_MENU = new tersus.Event('<On Context Menu>', 'oncontextmenu', 'onContextMenu');
Events.ON_FOCUS = new tersus.Event('<On Focus>', 'onfocus', 'onFocus');
Events.ON_BLUR = new tersus.Event('<On Blur>', 'onblur','onBlur');
Events.ON_MOUSEOVER = new tersus.Event('<On Mouse Over>','onmouseover','onMouseOver');
Events.ON_MOUSEOUT = new tersus.Event('<On Mouse Out>','onmouseout','onMouseOut');
Events.ON_MOUSEDOWN = new tersus.Event('<On Mouse Down>','onmousedown','onMouseDown');
Events.ON_MOUSEUP = new tersus.Event('<On Mouse Up>','onmouseup','onMouseUp');
Events.ON_MOUSEMOVE = new tersus.Event('<On Mouse Move>','onmousemove','onMouseMove');
Events.ON_KEYPRESS = new tersus.Event('<On Key Press>','onkeypress','onKeyPress');
Events.ON_KEYDOWN = new tersus.Event('<On Key Down>','onkeydown','onKeyDown');
Events.ON_KEYUP = new tersus.Event('<On Key Up>','onkeyup','onKeyUp');
Events.ON_DOUBLE_CLICK = new tersus.Event('<On Double Click>','ondblclick','onDoubleClick');
Events.ON_BROWSE = new tersus.Event('<On Browse>',null,null);
Events.ON_CHANGE = new tersus.Event('<On Change>','onchange','onChange');
Events.ON_EXPAND = new tersus.Event('<On Expand>');
Events.ON_COLLAPSE = new tersus.Event('<On Collapse>');
Events.ON_SELECT = new tersus.Event('<On Select>');
Events.ON_LOCATION_CHANGE = new tersus.Event('<On Location Change>');
Events.ON_UNLOAD = new tersus.Event('<On Unload>');
Events.ON_LEAVE_VIEW = new tersus.Event('<On Leave View>');
Events.ON_SORT = new tersus.Event('<On Sort>');
Events.OPEN = new tersus.Event('<Open>');
Events.ON_DELETE = new tersus.Event('<On Delete>');
Events.ON_ELEMENT_CHANGE = new tersus.Event('<On Element Change>');
BuiltinModels = {};
BuiltinModels.TEXT_ID='Common/Data Types/Text';
BuiltinModels.NUMBER_ID='Common/Data Types/Number';
BuiltinModels.NOTHING_ID='Common/Data Types/Nothing';

function compareValues(value1, value2, recursionMap)
{
	//recursionMap holds a list all comparisons already made (or in progress) - we don't want to comapre the same objects twice
	if (value1 && value1.isDataNode)
		value1 = value1.value;
	if (value2 && value2.isDataNode)
		value2 = value2.value;

	if( value1==value2)
		return true;
	if (! value1 || ! value2)
		return false;
	
	if (! value1.isNode || !value2.isNode)
		return false;
	if (value1.constructor != value2.constructor && ! (value1.isLeaf && value2.isLeaf && value1.pluginFunc == value2.pluginFunc))
		return false;
	if (! value1.elementList)
	{
		var l1 = value1.leafValue;
		var l2 = value2.leafValue;
		return l1 == l2 || l1 && l1.equals && l1.equals(l2);
	}
	
	var id1  = value1.getNodeId();
	var id2 = value2.getNodeId();
	var key = id1+':'+id2;
	if (!recursionMap)
		recursionMap = {};
	if (recursionMap[key])
		return true; // already compared (or comparison in progress) - no need to comapre again
	recursionMap[key]=true;

	for (var i=0; i<value1.elementList.length; i++)
	{
		var e = value1.elementList[i];
//		if (e.isDisplayElement || e.isDataElement || e.isMethodElement)
		{
			var children1;
			var children2;
			if (e.isRepetitive)
			{
				children1 = e.getChildren(value1);
				children2 = e.getChildren(value2);
			}
			else
			{
				children1 = [e.getChild(value1)];
				children2 = [e.getChild(value2)];
			}
			if (children1.length != children2.length)
				return false;
			for (var j=0; j<children1.length; j++)
			{
				if (! compareValues(children1[j], children2[j], recursionMap))
					return false;
			}
		}
	}
	return true;
};
function escapeHTML(value)
{
	return value.replace(/&/g, '&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;').replace(/\n/g, '<br>');
};
HTMLProperties = {};


// Creates a set

function loadBooleanOption(name)
{
	var value = getCookie(name);
	window[name] = (value == 'true');
//	alert('Option:'+name+' value:'+value+'('+window[name]+')');
};
function loadOptions()
{
	loadBooleanOption('autoReload');
	loadBooleanOption('serverTracing');
	loadBooleanOption('showServiceInvocations');
	loadBooleanOption('clientTracing');
};

tersus.loadFile = function(path, callback, ignoreErrors)
{
	var storageKey = null;
	if (window.localStorage && tersus.useLocalStorage)
	{
		storageKey = "File?"+path;
		var text = localStorage.getItem(storageKey);
		if (text != null)
		{
			if (callback)
			{
				setTimeout(function() {callback(text);},0);
				return;
			}
			else
				return text;
		}
	}
	return tersus.loadURL(tersus.rootURL+path, callback, ignoreErrors, null/*error callback*/, storageKey);
};
tersus.loadURL = function(url, callback, ignoreErrors, errorCallback, storageKey)
{
	var req = createXMLHTTPRequest();
	
	if (callback)
	{
		req.open('GET',url, true);
		req.onreadystatechange = function()
		{
			var responseText = null;
			var status = null;
			var statusText = null;
			try
			{
				if (req.readyState != 4)
					return;
				var status = req.status;
				var statusText = req.statusText;
				if (status == 200)
				{
					responseText = req.responseText;
					if (storageKey && window.localStorage)
					{
						if (tlog)
							tlog('Storing '+storageKey+ ' in local storage.');
						localStorage.setItem(storageKey, responseText);
					}
				}
			}
			catch (e)
			{
				if (ignoreErrors)
					callback(null);
				else if (errorCallback)
					errorCallback(status, statusText, e);
				else
					alert('Failed to load "'+url+'"');
				return;
				
			}
			if (status == 200)
				 callback(responseText);
			else if (ignoreErrors)
				callback(null);
			else if (errorCallback)
					errorCallback(status, statusText, null);
			else
				alert('Failed to load "'+url+'"');
		};
		req.send(null);
		return req;
	}
	else
	{
		req.open('GET', url, false);
		req.send(null);
		if (req.status != 200)
		{
			alert('Missing resource '+url+ '\nerror code='+req.status+' error message='+req.statusText);
			if (parent && parent.notLoaded)
				parent.notLoaded();
		
			return;
		}
		if (storageKey && window.localStorage)
		{
			if (tlog)
				tlog('Storing '+storageKey+ ' in local storage.');
			localStorage.setItem(storageKey, req.responseText);
		}
		return req.responseText;
	}
};

tersus.getCurrentViewURL = function()
{
	return tersus.rootURL;
};
function addHiddenField(form, name, value)
{
	
	var field = form.ownerDocument.createElement('input');
	field.type = 'hidden';
	field.value =value;
	field.name = name;
	form.appendChild(field);
	return field;
}

loadOptions();
function set(list)
{
	var out = {};
	for (var i=0; i< list.length; i++)
	{
		out[list[i]] = list[i];
	}
	return out;
}
function Set(list)
{
	this.members = {};
	if (list) 
	{
		for (var i=0; i< list.length; i++)
		{
			this.members[list[i]] = true;
		}
	}
};
Set.prototype.contains = function (member) 
{
	return this.members[member];
};
Set.prototype.add = function(obj)
{
	this.members[obj]=true;
};
Set.prototype.toList = function()
{
	var list = [];
	for (var memeber in this.members)
		list.push(memeber);
	return list;
};

Set.prototype.remove = function(member)
{
	delete this.members[member];
};
HTMLProperties['table']=set(['width']);
HTMLProperties['TABLE']=set(['width']);
STYLE_PROPERTIES = set(['width', 'height', 'overflow']);

Operation = {};
Operation.REPLACE = 'Replace';
Operation.ADD = 'Add';
Operation.REMOVE = 'Remove';
function internalError(message)
{
		alert ('Error:\n'+message);
		this.undefined();
};
function modelError(message, model)
{
	if (model && model.modelId)
		message = 'Invalid Model: '+model.modelId+'\n'+message;
	if (tlog)
		tlog(message);
	throw new tersus.Exception(message);
};
function debugAssertion(expression, message)
{
	//Default implemenation is a no-op. Should be overridden in test settings
}
function modelExecutionError(message, node)
{
	if (node)
		message += '\nLocation:'+new tersus.RuntimeLocation(node);
	alert ('Model Execution Error:\n'+message);
};

function makeAssertion(flag, description)
{
	if (! description)
		var description = '';
	if ( !flag)
	{
		alert ('Assertion Failed ' + description);
		this.undefined();
	}
};

function debugMessage(message)
{
	if (window.clientTracing)
		alert('DEBUG: '+message);
}

tersus.RuntimeLocation = function(node,element, suffix)
{
	var segments = [];
	// Collecting path segments in reverse order
	if (suffix)
		segments.push(suffix);
	if (element)
		segments.push(element.role);
	var current = node;
	while (current)
	{
		if (!current.isBackground)
		{
			var currentModelId = current.getModelId();
			if (! current.element  || current.element.modelId != currentModelId)
			{
				this.baseModelId = currentModelId;
				if (!currentModelId)
					error("No currentModelId id");
				break;
			}
			else
				segments.push(current.element.role);
		}
		current = current.parent;
	}
	segments.reverse();
	this.path = new Path();
	this.path.setSegments(segments);
};
tersus.RuntimeLocation.prototype.toString = function()
{
	return this.baseModelId + '['+this.path.str+']';
};
/*
	Handles a user event (mouse click etc.)
	displayNode: the displayNode on which the event was registered
	eventType: the type of the event (see Events.ON_XXX)
	parameters: parameters that will be passed to the event handler action
*/
window.engine.handleEvent = function handleEvent(displayNode, eventType , parameters, domEventAttributes) 
{
	if (tlog) tlog ('handleEvent '+eventType.elementName + ' on '+displayNode.modelName + ' ( '+displayNode.getPath().str+')');
	tersus.currentEventAttributes = domEventAttributes;

	var subFlow = displayNode.getEventHandler(eventType);
	if (!subFlow)
		return;
	var child = subFlow.createChild(displayNode);
	if (parameters)
	{
		for (var parameterName in parameters)
		{
			var trigger = child.getElement(parameterName);
			if (trigger)
			{
				var value = parameters[parameterName];
				if (value)
				{
					if (trigger.isRepetitive)
					{
						var v = value.length? value : [value];
						for (var i=0;i<v.length;i++)
						{
							trigger.addAChild(child,trigger.getValueNode(v[i]));
						}
					}
					else
						trigger.replaceChild(child, trigger.getValueNode(value));
				}
			}
		}
	}
	if (subFlow.isRepetitive)
		subFlow.addAChild(displayNode,child);
	else
		subFlow.replaceChild(displayNode,child);
	child.readyToStart();
	resumeRoot();
};

function isBusy()
{
	return(window.rootDisplayNode && window.rootDisplayNode.status != FlowStatus.WAITING_FOR_INPUT)
};
function checkBusy()
{
	if (isBusy())
	{
		if (tersus.alertMode.interactive)
			alert('The application is busy, please wait (or refresh)');
		return true;
	}
	else
		return false;
};

function resumeRoot()
{
	var start = new Date();
	if (tlog) tlog('resumeRoot');
	if (! tersus.progress.active)
		tersus.progress.set('Busy...');
	if (tlog) tlog ('resumeRoot: resuming root node');
	window.rootDisplayNode.resume();
	if (window.trace)
	{
		if (tlog) tlog("resumeRoot: flushing trace");
		window.trace.flush();
	}
	var end = new Date();
	if (tlog) tlog("resumeRoot: duration: " + (end - start) + " ms.");
	window.duration = "Action duration: " + (end - start) + " ms.";

};

tersus.queueEventDelay = 5000;
function queueEvent(object, method, args, startTime,description, maxDelay)
{
	if (!maxDelay)
		maxDelay=tersus.queueEventDelay;
	if (isBusy())
	{
		var now = new Date();
		var delay = now - startTime;
		if (tlog) 
		{
			if (!description)
				description = method.name;
			tlog('QE: Busy ('+delay+' ms) - '+description);
		}
		if (delay < maxDelay || maxDelay<0)
		{
			tersus.progress.set('Busy ...');
			setTimeout(function() {queueEvent(object,method, args, startTime, description,maxDelay);},100);
			return;
		}
	}
	//TODO - provide a nice visual indication that the system is waiting for something, and 
	// a way for the user to abort the running operation (or refresh the screen).
	// In the meantime, we use 'checkBusy()', that shows a warning message.
	if (checkBusy())
	{
		if (tlog)
			tlog('QE: Giving up - '+description);
		return;
	}
	if (tlog)
		tlog('QE: Invoking - '+description);
	/* TODO prevent concurrent operation:
	
	-- If we have a single user gesture triggering multiple events, we want them all to run, even if the first one takes a long time
	-- However, we don't want them to run "in parallel" (in simulated parallel)
	-- Therefore, putting them in the async queue is not good enough (they will run "in parallel")
	-- We may need to add a pre-queue (maybe a variant of queueEvent that runs for ever)
	
	*/
	tersus.async.exec (function () {method.apply(object,args);}, true /* wait if busy */);
};

tersus.traverseHierarchy = function traverseHierarchy(root, iterator, operation)
{
	var alreadyScanned = {};
	var iteration = function(node)
	{
		var id = node.getNodeId();
		if (alreadyScanned[id])
			return;
		alreadyScanned[id] = true;
		var stop = operation(node);
		if (stop == true)
			return true;
		iterator(node,iteration);
	}
	iteration(root);
}
tersus.scanHierarchy = function scanHierarchy(root, iterator, filter)
{
	var alreadyScanned = {};
	var out = [];
	var operation = function(node)
	{
		if (filter(node))
			out.push(node);
	};
	traverseHierarchy(root,iterator, operation);
	return out;
}
tersus.sqlize = function(str)
{
	return str.replace(/[^a-zA-Z0-9]/g, "_");
};



function stats()
{
	var packages = {};
	var nModels = 0;
	var nPackages = 0;
	for (var modelId in tersus.repository.constructors)
	{
		++nModels;
		var packageId = tersus.getPackageId(modelId);
		if (packages[packageId])
			++packages[packageId];
		else
		{
			packages[packageId]=1;
			++nPackages;
		}
	}
	var message = 'Total models:'+nModels;
	message += 'Total packages:'+nPackages;
	for (var packageId in packages)
	{
		message += '\n'+packageId+':'+packages[packageId];
	}
	var w = window.open();
	w.document.write('<pre>');
	w.document.write(message);
	w.document.write('</pre>');
	w.document.close();

}
tersus.getPackageId = function(modelId)
{
	var i = modelId.lastIndexOf('/');
	return modelId.substring(0,i);
};
Function.prototype.__subclass = function(name, c)
{
	if (!c)
		c = function(){};
	c.name=name;
	c.prototype = new this();
	c.prototype.constructor = c;
	return c;
};

tersus.newAction = function(name, startFunc)
{
	var c = ActionNode.__subclass('tersus.'+name);
	c.prototype.start = startFunc;
	tersus[name]=c;
};

tersus.findChildNodesByClassName = function(node, className, out)
{
	if (!out) out = [];
	if (node.className && node.className==className)
		out.push(node);
	var children = node.childNodes;
	for( var i = 0; i<children.length; i++)
	{
		tersus.findChildNodesByClassName(children[i], className, out);
	}
	return out;
};
tersus.adjustHeight = function (domNode, delta)
{
	var currentHeight =  getVisibleSize(domNode).height ;
	if (window.browser != 'IE')
	{
		var paddingBottom = parseInt(getActualStyle(domNode,'padding-bottom'));
		var paddingTop = parseInt(getActualStyle(domNode,'padding-top'));
		currentHeight -= (paddingBottom + paddingTop);
	}
	domNode.style.height = (currentHeight + delta);
}

tersus.foreach = function(array, f)
{
	if (array && array.length)
		for (var i=0;i<array.length; i++)
		{
			f(array[i]);
		}
}

tersus.preventDefaultEventHandling = function()
{
	var ev = tersus.currentEvent;
	if (ev)
	{
		if (ev.preventDefault)
			ev.preventDefault();
		else
			ev.returnValue=false;
			
	    if (ev.stopPropagation)
            ev.stopPropagation();
		else
            ev.cancelBubble = true;
	}		
}
tersus.isIPhone =  navigator.userAgent.toLowerCase().indexOf('iphone') >=0 || tersus.searchParams.UserAgent == 'iPhone';
tersus.isIPhoneSafari =  navigator.userAgent.toLowerCase().indexOf('iphone') >=0 && navigator.userAgent.toLowerCase().indexOf('safari') >=0 ;

tersus.foreach = function(a, func, contextObj)
{
	if (a == null)
		return;
	for (var i=0;i<a.length;i++)
	{
		func.call(contextObj, a[i], i);
	};
};
tersus.addAll = function (a1, a2)
{
	tersus.foreach(a2, function(x) {a1.push(x);});
};// file: 006-errors.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Exception = function(message,cause)
{
	this.message = message;
	this.cause = cause;
};
tersus.Exception.prototype = new tersus.Exception(null,null);
tersus.Exception.prototype.toString = function()
{
	return this.message;
}
tersus.errors = null;
tersus.error = function(m)
{
	if (tersus.errors)
		tersus.errors.push(m);
	else
		alert(m);
};

tersus.getErrors = function()
{	
	if (tersus.errors == null || tersus.errors.length == 0)
		return null;
	else
		return tersus.errors.join('\n');
};

tersus.clearErrors = function()
{
	tersus.errors=[];
};

tersus.serverError = function(msg)
{
	tersus.error(msg);
	if (tersus.pendingServiceCalls)
	{
		var list = tersus.pendingServiceCalls.toList();
		if (list.length == 1)
		{
			var node = tersus.findNode(list[0]);
			if (node && node.handleResponse)
			{
				node.handleResponse({});
			}
		}
		else if (length > 1)
		{
			tersus.error("Can't identify caller.  Please refresh.");
		}
	}
};// file: 009-Repository.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function ConstructorRepository()
{
	this.constructors = {};
	this.htmlTemplates = {};
	this.preloaded = {};
	this.loadedPackages = [];
	this.packageTexts = {};
	this.parsedPackages = {};
};
ConstructorRepository.prototype.add = function add(c)
{
	this.constructors[c.prototype.modelId]=c;
};

ConstructorRepository.prototype.get = function get(id)
{
	if (!this.constructors[id])
	{
		this.parsePackage(tersus.getPackageId(id));
	}
	if (! this.constructors[id])
	{
		if (tlog) tlog('Not preloaded:'+id);
		this.loadPackages([tersus.getPackageId(id)]);
		this.parsePackage(tersus.getPackageId(id));
	}
	var c =  this.constructors[id];
	return c;
};
ConstructorRepository.prototype.isLoaded = function(modelId)
{
	this.parsePackage(tersus.getPackageId(modelId));
	// Check again - maybe the package was parsed and now the constructor is there
	return (this.constructors[modelId]!=undefined);
};
ConstructorRepository.prototype.parsePackage = function(packageId)
{
	if (this.packageTexts[packageId] && !this.parsedPackages[packageId])
	{
		var t0 = new Date();
		this.parsedPackages[packageId] = true;
		var text = this.packageTexts[packageId];
		var models = eval(text);
		var t1 = new Date();
		for (var i=0;i<models.length;i++)
		{
			this.loadModel(packageId, models[i]);
		}
		var t2 = new Date();
		if (tlog)
			tlog('LOADER: ' + packageId+ ': '+models.length+' models loaded in '+(t2-t0) + ' ms ( eval time='+(t1-t0) + ' ms)');
	}
	
};

ConstructorRepository.prototype.loadModel = function (packageId, m)
{
	var c = function(){this.init();};
	var p = c.prototype = eval ('new '+m.c + '()');
	p.constructor = c;
	p.modelId = packageId + '/'+m.n;
	p.modelName = m.n;
	p.plugin = m.p;
	if (m.sp != null) p.sharedProperties = m.sp;
	if (m.pv != null) p.pluginVersion = m.pv;
	if (m.cc != null) p.cancellable = m.cc;
	if (m.runImmediately != null) p.runImmediately=m.runImmediately;
	if (m.pm != null) p.progressMessage = m.pm;
	if (m.progressMessage != null) p.progressMessage = m.progressMessage;
	if (m.v != null)
		p.setLeafStr(m.v);
	if (m.tableName)
		p.tableName=m.tableName;
	if (m.e)
	{
		for (var i=0;i<m.e.length;i++)
		{
			var me = m.e[i];
			var e = null;
			switch (me.t)
			{
				case 'sf':
				  e = p.addSubFlow(me.r,me.ref);
				  break;
				case 'l':
			      e = p.addLink(me.r, me.src, me.tgt);
			      break;
			    case 'ctx':
			      e = p.addAncestorReference(me.r,me.ref);
			      break;
			    case 'const':
			      e = p.addConstant(me.r,me.ref);
			      break;
			    case 'var':
			      e = p.addIntermediateDataElement(me.r,me.ref);
			      break;
			    case 'da':
			      e = p.addDataElement(me.r,me.ref);
			      break;
			    case 'di':
			      e = p.addDisplayElement(me.r,me.ref,me.ep);
			      break;
			    case 'tr':
			      e = p.addTrigger(me.r, me.ref);
			      break;
			    case 'ex':
			    case 'er':
			      e = p.addExit(me.r,me.ref);
			      break;
			    default:
			      throw new tersus.Exception('Invalid Model ('+p.modelId+'): unknown element type "'+me.t+'"');
			      
			}
			if (e)
			{
				if (me.rep != null)	e.isRepetitive = me.rep;
				if (me.rk != null)	e.dependencyRank = me.rk;
				if (me.m != null)	e.mandatory = me.m;
				if (me.ac != null)	e.alwaysCreate = me.ac;
				if (me.v != null)	e.valueStr = me.v;
				if (me.ct != null)	e.isConstantTrigger = me.ct;
				if (me.op != null)	e.operation = me.op;
				if (me.sr != null)	e.isSelfReady = me.sr;
				if (me.primaryKey != null) e.isPrimaryKey = me.primaryKey;
				if (me.columnName != null) e.columnName = me.columnName;
			}
		}
	}
	this.add(c);
	if (p.onload)
		p.onload();
	
	
};
ConstructorRepository.prototype.checkLoaded = function(modelId)
{
	if (this.isLoaded(modelId))
		return true;
	for (var i=0;i<this.loadedPackages.length;i++)
	{
		var packageId = this.loadedPackages[i];
		if (modelId.substring(0,packageId.length) == packageId
			&& modelId.charAt(packageId.length) == '/')
		{
			modelError("Missing model "+modelId + "\n(pakcage "+packageId + " already loaded)");
			break;
		}
	}
	return false;
		
}

var MAX_URL_LENGTH=1024;
tersus.packageLoader = function(){};
tersus.packageLoader.prototype.onload = function(packages)
{
	tersus[this.scriptCallback] = null; //Drop reference to allow garbage collection
	for (var id in packages)
	{
		tersus.repository.packageTexts[id] = packages[id];
	}
	this.runAsync();
};
tersus.packageLoader.error = function(msg)
{
	alert('An error has occurred while loading the application:\n'+msg);
};
tersus.nextPackageLoaderId = 1;
tersus.packageLoader.prototype.runAsync = function runAsync()
{
	var loader=this;
	if (loader.currentIndex == loader.packageIds.length)
	{
		setTimeout(loader.callback,0);
		return;
	}
	if (window.localStorage && tersus.useLocalStorage) // new mechanism - packages stored in local storage 
	{
		var url = tersus.rootURL+'Code';
        var paramString='packages=';
        while (this.currentIndex<this.packageIds.length)
        {
        	paramString += encodeURIComponent(':'+loader.packageIds[this.currentIndex]);
        	++ this.currentIndex;
        }
        var storageKey='Code?timestamp='+tersus.lastTimestamp+'&user='+encodeURIComponent(window.userName)+'&'+paramString;
        if (tersus.lastTimestamp == localStorage.getItem('LAST_TIMESTAMP'))
        {
        	var text = localStorage.getItem(storageKey);
        	if (text != null)
        	{
        		var packages = eval(text);
        		loader.onload(packages);
        		loader.callback();
        		if (tlog) tlog('Loaded from local Storage');
       			return; 	
        	}
        }
        else
        {
        	for (var i=localStorage.length -1; i>=0 ;i--)
        	{
        		var key=localStorage.key(i);
        		if (key.search(/^(Code|File)\?/) >= 0)
        		{
	       			localStorage.removeItem(key);
	       			if (tlog) tlog('Removing '+key + ' from local storage');
	       		}
        	}
        	localStorage.removeItem('LAST_TIMESTAMP');
        	
        }
 		var req = createXMLHTTPRequest();
        req.onreadystatechange= function(){
        	if (req.readyState ==4)
        	{
        		if (req.status==200)
        		{
        			var text = req.responseText;
	        		var packages=eval(text);
	        		localStorage.setItem(storageKey, text);
	        		localStorage.setItem('LAST_TIMESTAMP',tersus.lastTimestamp);
	        		loader.onload(packages);
	        		loader.callback();
	        		if (tlog) tlog('Loaded from server');
	        	}
	        	else
	        	{
	        		tersus.error("Failed to load models from server");
	        	}
	        }
	        	
        };
        req.open('POST', url, true);
        req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
        req.send(paramString);
		return;
	}
	else // old mode
	{
		loader.scriptCallback = 'loadPackages'+(tersus.nextPackageLoaderId ++);
		tersus[loader.scriptCallback] = function(constructors) { loader.onload(constructors);};
		var url = tersus.rootURL+'Code?timestamp='+tersus.lastTimestamp+'&_js_callback='+'tersus.'+loader.scriptCallback+'&user='+encodeURIComponent(window.userName)+'&packages=';
			
		// We may need to split the request into multiple requests if the url ends up too long
		for (var nextIndex=loader.currentIndex;nextIndex<loader.packageIds.length;nextIndex++)
		{
			var nextURL = url+encodeURIComponent(':'+loader.packageIds[nextIndex]);
			if (nextURL.length > MAX_URL_LENGTH)
				break;
			else
				url = nextURL;
		}		
		if (nextIndex==loader.currentIndex)
		{
			modelError("Package id "+loader.packageIds[nextIndex] + " is too long to load");
			return;
		}
		if (tersus.progress.active)
			tersus.progress.set("Loading application components");
		loader.currentIndex = nextIndex;
		tersus.loadScript(url);
	}
};
tersus.packageLoader.prototype.runSync = function runSync()
{
	var loader = this;
	var url = tersus.rootURL+'Code?timestamp='+tersus.lastTimestamp+'&user='+encodeURIComponent(window.userName)+'&packages=';
	
	// We work hard to retrieve packages using 'GET', as this will enable caching
	// This means we sometimes have to split the list into multiple requests
	if (tersus.progress.active)
		tersus.progress.set("Loading application components");
	while (loader.currentIndex < loader.packageIds.length)
	{
		for (var nextIndex=loader.currentIndex;nextIndex<loader.packageIds.length;nextIndex++)
		{
			var nextURL = url+encodeURIComponent(':'+loader.packageIds[nextIndex]);
			if (nextURL.length > MAX_URL_LENGTH)
				break;
			else
				url = nextURL;
		}		
		if (nextIndex==loader.currentIndex)
		{
			modelError("Package id "+loader.packageIds[nextIndex] + " is too long to load");
			return;
		}
		loader.currentIndex = nextIndex;
		var jsText = tersus.loadURL(url);
		if (jsText)
		{
			var packages = eval(jsText);	
			for (var id in packages)
			{
				tersus.repository.packageTexts[id] = packages[id];
			}
		}
	}
};
ConstructorRepository.prototype.loadPackages = function loadPackages(packageIds, callback) 
{
	if (tlog) tlog('Loading packages: '+packageIds.join(';'));
	for (var i=0;i<packageIds.length;i++)
	{
		this.loadedPackages.push(packageIds[i]);
	}

	var loader = new tersus.packageLoader();
	
	loader.packageIds = packageIds;
	loader.callback = callback;
	loader.currentIndex = 0;
	if (loader.callback)
		loader.runAsync();
	else
		loader.runSync();
};


ConstructorRepository.prototype.content = function content()
{
	var content = null;
	for (var id in this.constructors)
	{
		if (! content)
			content = id;
		else
			content = content + '\n'+id;
	}
	return content;
};
ConstructorRepository.prototype.templateNumber = 0;

//TODO - change loading mechanism so that html snippets are loaded with model
tersus.preloadedTemplates = {};
tersus.preloadTemplate = function(name,text)
{
	tersus.preloadedTemplates[name]=text;
};
ConstructorRepository.prototype.loadHTMLTemplate = function (path)
{
	if (this.htmlTemplates[path])
		return; //Already loaded
	if (tersus.preloadedTemplates[path])
	{
		var text = tersus.preloadedTemplates[path];
		var template = document.createElement('DIV');
		template.innerHTML = text;
		this.saveTemplate(path, template);
		return;
	}
	if (tersus.progress.active)
	{
		var message;
		if (tersus.progressMessage)
			message = tersus.progressMessage;
		else
			message = 'Loading template '+path + '...';
		tersus.progress.set(message);
	}
	var html = tersus.loadFile(path);
	if (tersus.progress.active)
		tersus.progress.set('Template loaded.');
	var name = 'templateFrame_'+ (++this.templateNumber);
	var iframe = window.createAnIFrame(window, name);
	var iframeNode = window.document.getElementById(name);
	var repository=this;
	var count=0;
	var cont1 = function()
	{
		++count;
		var d = iframeNode.contentDocument;
		var w = iframeNode.contentWindow;
		if ( d == null && w == null)
		{
			if (count < 50)
				setTimeout(cont1,50);
			else
				alert('Failed to load template '+path);
			return;
		}
		if (d == null)
		{
			d = iframeNode.contentWindow.document;
		}
		d.write(html);
		d.close();
		var cont2 = function() 
		{
			var templateNode = d.getElementById('content');
			if (!templateNode)
				templateNode = d.body;
			templateNode.id='';
			var template;
			if (templateNode.tagName == 'BODY')
			{
				template = document.createElement('DIV');
				template.innerHTML = templateNode.innerHTML;
			}
			else
			{
			  template =  importNode(window.document,templateNode);
			}
			repository.processTemplate(template);
			iframeNode.parentNode.removeChild(iframeNode);
			repository.htmlTemplates[path]=template;
		};
		setTimeout(cont2,50);
	}
	setTimeout(cont1,50);
};
ConstructorRepository.prototype.saveTemplate = function saveTemplate(path,template)
{
	this.processTemplate(template);
	this.htmlTemplates[path]=template;
};
//TODO move this mechanism to "Embedded HTML" so that it isn't loaded unnecessarity
ConstructorRepository.prototype.getHTMLTemplate = function (path)
{
	var template = this.htmlTemplates[path];
	if (!template)
	{
		var wasInProgress = tersus.progress.active;
		var progressMessage;
		if (tersus.progressMessage)
			message = tersus.progressMessage;
		else
			message = 'Loading template '+path + '...';
		
		tersus.progress.set(message);
		var html = tersus.loadFile(path);
		if (wasInProgress)
			tersus.progress.set('Template loaded.');
		else
			tersus.progress.clear();
		var name = 'templateFrame';
		var iframe = window.createAnIFrame(window, name);
		var iframeNode = window.document.getElementById(name);
		var d = iframeNode.contentWindow.document;
		d.write(html);
		d.close();
		var templateNode = d.getElementById('content');
		if (!templateNode)
			templateNode = d.body;
		var template;
		if (templateNode.tagName == 'BODY')
		{
			template = document.createElement('DIV');
			template.innerHTML = templateNode.innerHTML;
		}
		else
		{
		  template =  importNode(window.document,templateNode);
		}
		this.processTemplate(template);
		iframeNode.parentNode.removeChild(iframeNode);
		this.htmlTemplates[path]=template;
	}
	return template;
};
/**
 * Perform the following processing for a template:
 *
 * 1) Remove sample nodes
 * 2) Hide repetitive template nodes
*/
ConstructorRepository.prototype.processTemplate = function(template)
{
	var elements = template.getElementsByTagName('*');
	for (var i=0; i<elements.length; i++)
	{
		var e = elements[i];
		var repetitive  = e.getAttribute('repetitive');
		if (repetitive == 'sample')
		{
			if (e.parentNode)
				e.parentNode.removeChild(e);
		}
		else if (repetitive == true)
			e.style.display='none';
	}
};
// file: 011-Path.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
//Path
function Path(pathStr)
{
	if (pathStr != null && pathStr != undefined)
	{
		this.str = pathStr;
	 	if (pathStr.length == 0)
			this.segments = [];
		else
			this.segments = pathStr.split('/');
	}
};

Path.prototype.setSegments = function(segments)
{
	this.segments = segments;
	this.str = segments.join('/');
};
Path.prototype.toString = function toString() {return this.str;};
Path.prototype.addSegment = function addSegment(role) 
{
	this.segments.push(role);
	this.str += '/' + role;
};

Path.prototype.getElement = function (parent)
{
	var currentModel = parent;
	var currentElement = null;
	for (var i=0; i<this.segments.length;i++)
	{
		if (currentModel == null)
			return null;
		currentElement = currentModel.getElement(this.segments[i]);
		if (currentElement == null)
			return null;
		if (currentElement.modelId)
			currentModel = tersus.repository.get(currentElement.modelId).prototype;
		else
			currentModel = null;
		
	};
	return currentElement;
};
Path.prototype.clone = function()
{
	var clone = new Path();
	clone.segments = this.segments.concat();
	clone.str = this.str;
	return clone;	
};

// file: 012-Node.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 //Generic Runtime Node
tersus.Node = function tersus_Node() {};
tersus.Node.prototype.type='Node';
tersus.Node.prototype.textTranslation = true;
tersus.Node.prototype.getPrototype = function()
{
	if (this.modelId)
		return tersus.repository.get(this.modelId).prototype;
}
tersus.Node.prototype.getNodeId = function()
{
	if (!this.nodeId)
	{
		this.nodeId = window.nextNodeId ? window.nextNodeId : 1;
		window.nextNodeId = this.nodeId + 1;
	}
	return this.nodeId;
};
tersus.Node.prototype.getModelId = function()
{
	return this.modelId;
};
tersus.Node.prototype.isInstance = function(value)
{
	return value && value.isNode && value.modelId == this.modelId;
};
tersus.Node.prototype.init = function() {}; // Called when a concrete instance is created
tersus.findNodeOld = function findNodeOld(id)
{
	if (tlog) tlog("Trying to find node "+id);

	var node = window.rootDisplayNode.findById(id);
	if (node)
	{
		if (tlog) tlog("Node "+id + " found.");
		return node;
	}
	tersus.unregisterPopupNodes();
	for (var popupId in tersus.popupNodes)
	{
		node = tersus.popupNodes[popupId].findById(id);
		if (node)
		{
			if (tlog) tlog("Node "+id + " found.");
			return node;
		}
	}
	return null;
		
};
tersus.Node.prototype.findById = function(id, alreadyScanned, depth)
{
	if (!depth)
	   depth=1;
		
	if (this.nodeId == id)
		return this;
	if (! this.elementList)
		return null;
	if (!alreadyScanned)
		alreadyScanned = {};
	var thisNodeId = this.getNodeId();
	if (alreadyScanned[thisNodeId])
		return null;
	alreadyScanned[thisNodeId]=true;
	for (var i=0; i<this.elementList.length; i++)
	{
		var e = this.elementList[i];
		if (e.isRepetitive)
		{
			var children = e.getChildren(this);
			for (var j=0; j<children.length;j++)
			{
				var child = children[j];
				if (child)
				{
					var node = child.findById(id, alreadyScanned, depth+1);
					if (node)
						return node;
				}
			}
		}
		else
		{
			var child = e.getChild(this);
			if (child)
			{
				var node = child.findById(id, alreadyScanned, depth+1);
				if (node)
					return node;
			}
		}
	}
	return null;
};

tersus.Node.prototype.scanChildren = function(filter, alreadyScanned, outputList)
{
	var id = this.getNodeId();
	if (alreadyScanned[id])
		return;
	alreadyScanned[id]=true;
	if (this.currentWindow && this.currentWindow.closed)
		return;
	if (filter.match(this))
		outputList.push(this);
	if (! this.elementList)
		return null;
	for (var i=0; i<this.elementList.length; i++)
	{
		var e = this.elementList[i];
		if (e.isDisplayElement || e.isDataElement || e.isMethodElement)
		{
			if (e.isRepetitive)
			{
				var children = e.getChildren(this);
				for (var j=0; j<children.length;j++)
				{
					var child = children[j];
					if (child)
					{
						child.scanChildren(filter, alreadyScanned, outputList);
					}
				}
			}
			else
			{
				var child = e.getChild(this);
				if (child)
				{
					child.scanChildren(filter, alreadyScanned, outputList);
				}
			}
		}
	}
	return null;
};
tersus.Node.prototype.countHierarchy = function()
{
	var count = 1
	if (this.elementList)
	{
		for (var i=0; i<this.elementList.length; i++)
		{
			var e = this.elementList[i];
			if (e.isRepetitive)
			{
				var children = e.getChildren(this);
				for (var j=0; j<children.length;j++)
				{
					var child = children[j];
					if (child)
					{
						count += child.countHierarchy();
					}
				}
			}
		
			else
			{
				var child = e.getChild(this);
				if (child)
				{
					count += child.countHierarchy();
				}
			}
		}
	}
	return count;
};

tersus.Node.prototype.invokeLinks = function invokeLinks()
{
	var links = this.element.outgoingLinks;
	if (links)
	{
		for (var i=0; i<links.length; i++)
		{
			var link = links[i];
			link.invoke(this);		
		}
	}
};
tersus.Node.prototype.isNode = true;
tersus.Node.prototype.isReady = function isReady()
{
	return true;
};

tersus.Node.prototype.addElement = function addElement(element)
{
	if (!this.elements)
		this.elements = {};
	this.elements[element.role]=element;
	if (!this.elementList)
		this.elementList = [];
	this.elementList.push(element);
	element.owner = this;
	return element;
};

tersus.Node.prototype.getElement = function getElement(role)
{
	var element = null;
	if (this.elements)
		element = this.elements[role];
	if (element)
		return element;
	else
		return null;
};
tersus.Node.prototype.addGetter = function(role, getter)
{
	this['getter_'+role] = getter;
};
tersus.Node.prototype.addSetter = function(role, setter)
{
	this['setter_'+role] = setter;
};
tersus.Node.prototype.addRemover = function(role, remover)
{
	this['remover_'+role] = remover;
};

tersus.Node.prototype.getGetter = function getGetter(role)
{
	if (this['getter_'+role])
		return this['getter_'+role];
	else if (role.charAt(0)=='<')
		return this['get'+role];// Obsolete mode (still widely used as of June 2009)
	else return null;
};
tersus.Node.prototype.getSetter = function getSetter(role)
{
	if (this['setter_'+role])
		return this['setter_'+role];
	else if (role.charAt(0)=='<') 
		return this['set'+role]; // Obsolete mode (still widely used as of June 2009)
	else
		return null;
};
tersus.Node.prototype.getAdder = function getAdder(role)
{
	return this['add'+role];
};
tersus.Node.prototype.getRemover = function getRemover(role)
{
	if ( this['remover_'+role])
		return this['remover_'+role];
	else if (role.charAt(0)=='<') 
		return this['remove'+role]; // Obsolete mode (still widely used as of June 2009)
	else
		return null;
};

tersus.Node.prototype.getChild = function getChild(role)
{
	var element = this.getElement(role);
	if (element)
		return element.getChild(this);
	else
		return null;
};

tersus.Node.prototype.getChildren = function getChildren(role)
{
	var element = this.getElement(role);
	return element.getChildren(this);
};
/*
	Returns an array of all values at given path.
	path - a Path containing the required path
	index - an optional number indicating which segment in the path should be deemed first 
	         (the first 'index' segments are ignored.)
*/
tersus.Node.prototype.getValues = function getValues(path, index)
{
	if (!index)
		var index = 0;
	var values = [];
	this._getValues(path, index, values);
	return values;
};


/*
	Adds all values at a given path to a given array of values
	This method is used internally to implement 'getValues'/
	path - a Path containing the required path
	index - an optional number indicating which segment in the path should be deemed first 
	         (the first 'index' segments are ignored.)
	values - an array to which all values will be added.
	 
*/
tersus.Node.prototype._getValues = function _getValues(path, index, values)
{
	if (path.segments.length < index)
	{
		internalError('Bad path in _getValues');
		return;
	}
	var role = path.segments[index];
	if (path.segments.length == index )
	{ 
		values.push(this);
	}
	else
	{
		var element = this.getElement(role);
		if (!element)
			return; // The path links to a non-existant element (as of Feb 26, this can happen because of the way the permission mechanism works)
		if (element.isRepetitive)
		{
			var children = element.getChildren(this);
			for (var i=0; i<children.length; i++)
			{
				var child = children[i];
				if (child)
					child._getValues(path, index+1, values);
			}
		}
		else
		{
			var child = element.getChild(this);
			if (child)
				child._getValues(path, index+1, values);
			
		}
	}
}
/**
	Sets the value of a descendant, specified by path
	The index specifies a number of initial segments of the path that should be ignored
	(index = 0 means using the whole path, index = 1 means starting from the second segment).
*/
tersus.Node.prototype.setValue = function setValue(path, value, operation, index)
{
	if (! operation)
	{
		internalError('Operation not specified');
	}
	if (! index)
		var index = 0;
	if (path.segments.length <= index)
	{
		internalError('Bad path in setValue');
	}
	var role = path.segments[index];
	if (path.segments.length-1 == index)
	{
		var element = this.getElement(role);
		if (!element)
			return;// The path links to a non-existant element (as of 0.9.49, this can happen because of the way the permission mechanism works)
		element.setChild(this, value, operation);
	}
	else if (path.segments.length > index)
	{
		var element = this.getElement(role);
		if (! element)
			return; // The path links to a non-existant element (as of 0.9.49, this can happen because of the way the permission mechanism works)
		var child = element.getChild(this);
		if (! child)
			child = element.createChild(this); // Creating an intermediate level
		child.setValue(path, value, operation, index+1);
	}
};


tersus.Node.prototype.getPath = function getPath()
{
	if (this.parent)
	{
		var path = this.parent.getPath();
		path.addSegment(this.element.role);
		return path;
	}
	else
		return new Path(tersus.viewPath);
};
tersus.Node.prototype.setAlwaysCreate = function setAlwaysCreate(role, alwaysCreate)
{
	this.elements[role].alwaysCreate = alwaysCreate;
};
// Performs any operation needed when this node is deleted
tersus.Node.prototype.onDelete = function onDelete() 
{
};

// Performs a 'set' operation with a leafValue
// Returns true if the operation is sucessful, false if there is no element with the given role
tersus.Node.prototype.setLeafChild = function setLeafChild(role, leafValue, operation)
{
	var element = this.getElement(role);
	if (!element)
		return false;
	var value = element.createChildInstance();
	value.setLeaf(leafValue);
	element.setChild(this, value, operation);
	return true;
};

tersus.Node.prototype.getLeafChild = function getLeafChild(role)
{
	var child = this.getChild(role);
	if (child)
		return child.leafValue;
	else
		return null;
};
tersus.Node.prototype.setChild = function setChild(role, value, operation)
{
	var element = this.getElement(role);
	if (!element)
		return false;
	element.setChild(this, value, operation);
	return true;
};
tersus.Node.prototype.setLeaf = function setLeaf(value)
{
	this.leafValue = value;
};
tersus.Node.prototype.setLeafStr = function(str)
{
	this.leafValue = str;
};
tersus.Node.prototype.copyObject = function copyObject(value)
{
	if (this.isLeaf)
		this.setLeaf(value);
	else if (this.elements)
	{
		for (var elementRole in this.elements)
		{
			var element = this.getElement(elementRole);
			if (element.isRepetitive)
			{
				var values = value[elementRole];
				if (values)
				{
					for (var i=0; i< values.length; i++)
					{
						var child = element.createChild(this);
						child.copyObject(values[i]);
					}
				}
			}
			else
			{
				var childValue = value[elementRole];
				if (childValue || childValue == 0 || childValue == '')
				{
					if (childValue ==0)
						var x=0;
					var child = element.createChild(this);
					child.copyObject(childValue);
				}
			}
		}
	}
};
tersus.Node.prototype.getTranslation = function(key)
{
	if (tersus.labelMap)
		return tersus.labelMap[key];
};

tersus.Node.prototype.translate = function (s)
{
	if (! this.textTranslation)
		return s;
	return this.forceTranslate(s);
};
tersus.Node.prototype.forceTranslate = function (s)
{
	var t = this.getTranslation(s);
	if (t != undefined)
		return t;
	else
		return s;
};
tersus.Node.prototype.preloadOnStart = true;
tersus.Node.prototype.preload = function(callback)
{
	if (tersus.repository.preloaded[this.modelId])
		return true;
	var packageSet = new Set();
	if (tlog) var startTime = new Date();
	var	alreadyChecked = new Set();
	this.addPreloadPackages(packageSet,alreadyChecked);
	this.addMissingLinkTargets(packageSet,alreadyChecked);
	if (tlog)
	{
		var endTime = new Date();
		if (tlog) tlog("Package scan took "+(endTime-startTime) +" milliseconds");
	}
	var packageList = packageSet.toList();
	if (packageList.length == 0)
	{
		tersus.repository.preloaded[this.modelId] = true;
		return true;
	}
	else
	{
		if (tlog) tlog('Preloading '+this.modelId);
		packageList.sort();
		var mainPackages = [];
		var last = null;
		for (var i=0;i<packageList.length;i++)
		{
			var current = packageList[i];
			if (last && last == current.substring(0,last.length))
				continue;
			mainPackages.push(current);
			last = current;
		}
		this.pause();
		tersus.repository.loadPackages(mainPackages, callback);
		return false;
	}
};
tersus.Node.prototype.addPreloadPackages = function (packageSet, alreadyChecked)
{
	if (tersus.repository.preloaded[this.modelId])
		return;
	if (alreadyChecked.contains(this.modelId))
		return;
	alreadyChecked.add(this.modelId);
	if (this.elementList)
	{
		for (var i=0;i<this.elementList.length;i++)
		{
			var e = this.elementList[i];
			if (e.modelId)
			{
				if (!tersus.repository.checkLoaded(e.modelId))
				{
					var packageId = tersus.getPackageId(e.modelId);
					packageSet.add(packageId);
				}
				else 
				{
					if (e.isDisplayElement || e.isFlowDataElement || ! this.isDisplayNode )
					{
						var childConstructor = tersus.repository.get(e.modelId);
						var childModel = childConstructor.prototype;
//						if (childModel.preloadOnStart)
//							childModel.addPreloadPackages(packageSet, alreadyChecked);
					}
				}
			}
		}
	}
};
tersus.Node.prototype.addMissingLinkTargets = function (packageSet, alreadyChecked)
{
	if (!this.links)
		return;
	for (var i=0;i<this.links.length; i++)
	{
		var link = this.links[i];
		var currentModel = this;
		var segments = link.target.segments;
		for (var j=0; j< segments.length; j++)
		{
			var element = currentModel.getElement(segments[j]);
			if (!element)
				continue; // This can happen if there is no permission
			var id = element.modelId;
			if (!id)
				continue; 
			if (! tersus.repository.checkLoaded(id))
			{
				if (tlog) tlog('Need to preload '+id);
				var packageId = tersus.getPackageId(id);
				packageSet.add(packageId);
				break;
			}
			else
			{
				currentModel = tersus.repository.get(id).prototype;	
				if (currentModel.preloadOnStart)
					currentModel.addPreloadPackages(packageSet,alreadyChecked);
			}
		}
	}
	return true;
};	
tersus.Node.prototype.destroyHierarchy = function()
{
	this.destroyChildren();
        if (this.destroy)
                this.destroy();
};
tersus.Node.prototype.destroyChildren = function()
{
        tersus.Node.subFlowIterator(this,function(node) {node.destroyHierarchy()});
};

tersus.Node.childIterator = function (node,iteration)
{
	if (node && node.elements)
	{
		for (var i=0; i<node.elementList.length; i++)
		{
			var e = node.elementList[i];
			if ( e.isRepetitive)
			{
				var children  = e.getChildren(node);
				for (var j=0;j<children.length;j++)
				{
					var stop = iteration(children[j]);
					if (stop == true)
						return;
				}
			}
			else
			{
				var child = e.getChild(node);
				if (child)
				{
					var stop = iteration(child);
					if (stop == true)
						return;
				}
			}
		}
	}
	
};
tersus.Node.subFlowIterator = function (node,iteration)
{
	if (node && node.subFlowList)
	{
		for (var i=0; i<node.subFlowList.length; i++)
		{
			var e = node.subFlowList[i];
			if ( e.isRepetitive)
			{
				var children  = e.getChildren(node);
				for (var j=0;j<children.length;j++)
				{
					var stop = iteration(children[j]);
					if (stop == true)
						return;
				}
			}
			else
			{
				var child = e.getChild(node);
				if (child)
				{
					var stop = iteration(child);
					if (stop == true)
						return;
				}
			}
		}
	}
	
};
// file: 013-Element.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Element() {};
/**
	createChildInstance - creates an instance of the model refered by this element.
	 
	Note: the instance is not added to the parent node (which is not specified).

	
*/
Element.prototype.dependencyRank = -1;
Element.prototype.isRemovable = true;
Element.prototype.alwaysCreate = true;
Element.prototype.getChildConstructor = function (explicitModelId)
{
	var modelId = explicitModelId ? explicitModelId : this.modelId;
	var childConstructor;
	if (modelId)
		childConstructor = tersus.repository.get(modelId);
	else
		childConstructor = DataValue;
	if (! childConstructor)
	{
		var message ="'"+ this.modelId + "' not found in constructor repository.\n";
		message += "Existing consructors:\n";
		for (var modelId in tersus.repository.constructors)
		{
			message += "'" + modelId + "'\n";
		}
		tersus.error(message);
	}
	return childConstructor;
};
Element.prototype.createChildInstance = function createChildInstance(modelId)
{
	var childConstructor = this.getChildConstructor(modelId);
	var childInstance = new childConstructor();
	childInstance.prototype = childConstructor.prototype;
	return childInstance;
}

/*
	Creates a child instance, and stores it as a child.
	(This implementation is used by DataElements and Exits. Display Elements have a different implementation).
*/
Element.prototype.createChild = function createChild(parent)
{
	var childInstance = this.createChildInstance();
	this.addChild(parent, childInstance);
	return childInstance;
};	
Element.prototype.addChild = function addChild(parent, child)
{
	if (! parent.children)
		parent.children = {};
	if (this.isRepetitive)
	{
		if (! parent.children[this.role])
			parent.children[this.role] = [];
		parent.children[this.role].push(child);
	}
	else
	{
		parent.children[this.role] = child;
	}
};
Element.prototype.isEmpty = function isEmpty(parent)
{
	if (this.isRepetitive)
	{
		var children = this.getChildren(parent);
		return (! children || children.length ==0);
	}
	else
	{
		var child = this.getChild(parent);
		return (! child);
	}
};
Element.prototype.getChild = function getChild(parent)
{
	if ( this.isRepetitive)
		internalError("getChild(parent) called on repetitive element");
	var child = null;
	if (parent.children)
		child = parent.children[this.role];
	return child;
};

/*
	returns a list of children (child instances) of a given parent.
	If there are no such children, an empty list is returned.
	IMPORTANT:  The caller must not modify the returned list 
*/
Element.prototype.getChildren = function getChildren(parent)
{
	if ( ! this.isRepetitive)
		internalError("getChildren(parent) called on non repetitive element");
	var children = null;
	if (parent.children)
		children = parent.children[this.role];
	if (! children)
		children = [];
	return children;
};

Element.prototype.removeChildren = function removeChildren(parent)
{
	makeAssertion( this.isRepetitive);
	var children = this.getChildren(parent);
	for (var i=0; i< children.length; i++)
	{
		var child = children[i];
		if (child && child.parent == parent)
			child.onDelete();
	}
	if (parent.children)
		parent.children[this.role] = [];
};
Element.prototype.setChildren = function setChildren(parent, values, operation)
{
	if ( ! this.isRepetitive)
		internalError("setChildren(parent, values, operation) called on non repetitive element");
	if (operation ==  Operation.REPLACE)
		this.removeChildren(parent);
	for (var i=0; i<values.length; i++)
	{
		var value = values[i];
		this.setChild(parent, value, Operation.ADD);
	}
};


Element.prototype.addAChild = function addAChild(parent,value)
{
	if (! parent.children)
		parent.children = {};
	makeAssertion( this.isRepetitive);
	if (! parent.children[this.role])
		parent.children[this.role] = [];
	parent.children[this.role].push(value);
};
Element.prototype.replaceChild = function replaceChild(parent, value)
{
	makeAssertion( ! this.isRepetitive);
	if (! parent.children)
		parent.children = {};
	if (this.modelId && tersus.repository.get(this.modelId).prototype.isNothing && ! value.isNothing)
		this.createChild(parent); // Creates a new instance of Nothing
	else
		parent.children[this.role]=value;	
}
Element.prototype.removeChild = function removeChildren(parent)
{
	makeAssertion( ! this.isRepetitive);
	if (! parent.children)
		return;
	var child = this.getChild(parent);
	if (child != null)
	{
		if (parent.hasElementChangeHandler)
		{
			var oldValue = child.isDataNode ? child.value : child;
			parent.handleElementChange(this.role, oldValue, null);
		}
		delete parent.children[this.role];
		if (child && child.parent == parent)
			child.onDelete();
	}
};



Element.prototype.setChild = function setChild(parent, value, operation)
{
	if (! parent.children)
		parent.children = {};
	if (this.isRepetitive)
	{
		if (operation == Operation.ADD)
			this.addAChild(parent, value);
		else if (operation == Operation.REMOVE)
			this.removeChildren(parent);
		else
			internalError('Operation '+operation+' not supported for repetitive elements');
		
	}
	else
	{
		if (operation == Operation.REPLACE)
			this.replaceChild(parent, value,true);
		else if (operation == Operation.REMOVE)
			this.removeChild(parent);
		else
			
			internalError('Operation '+operation+' not supported for non-repetitive elements');
	}
};
Element.prototype.moveChild = function (parent, fromIndex, toIndex)
{
	var children = this.getChildren(parent);
	var child = children.splice(fromIndex, 1)[0];
	children.splice(toIndex,0,child);
	return child;
};
Element.prototype.getValueNode = function(value)
{
	var valueNode;
	if (value.isNode)
		valueNode=value;
	else
	{
		valueNode=this.createChildInstance();
		valueNode.setLeaf(value);
	}
	return valueNode;
};// file: 015-DataNode.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
//DataNode (of a Flow)
//A DataNode holds a reference to some value, and participates in the flow
// (it can be invoked).
function DataNode() {};
DataNode.prototype = new tersus.Node();
DataNode.prototype.constructor = DataNode;
DataNode.prototype.isDataNode = true;
DataNode.prototype.invoke = function()
{
	if (window.trace)
		window.trace.activated(this);
	this.invokeLinks();
}
DataNode.prototype.toString = function toString()
{
	return this.leafValue + '['+this.modelId +']';
};
DataNode.prototype.copyObject = function copyObject(obj)
{
	this.value.copyObject(obj);
};
DataNode.prototype._getValues = function _getValues(path, index, values)
{
	if (index == path.segments.length)
		values.push(this.value);
	else
		return this.value._getValues(path, index, values);
}
DataNode.prototype.setValue = function setValue(path, value, operation, index)
{
	this.value.setValue(path, value, operation, index);
	//TODO we probably need a special case for leaf data nodes
};
DataNode.prototype.scanChildren = function(filter, alreadyScanned, outputList)
{
// Do nothing - we don't want to scan variables 
//	this.value.scanChildren(filter, alreadyScanned, outputList);
};
DataNode.prototype.getModelId = function()
{
	return this.value.getModelId();
};// file: 020-FlowNode.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
//FlowNode - an instance of FlowModel (implements composite behavior)

function FlowNode() {};
FlowNode.prototype = new tersus.Node();
FlowNode.prototype.constructor = FlowNode;

FlowNode.prototype.addSubFlow = function addSubFlow(role, modelId)
{
	// Adds a representation of the sub-flow both to a list of sub-flows
	// and to a map of sub-flows
	var subFlow = new SubFlow(role, modelId);
	this.registerSubFlow(subFlow);
	return this.addElement(subFlow);
}
FlowNode.prototype.registerSubFlow = function registerSubFlow(subFlow)
{
	if (! this.subFlowMap)
		this.subFlowMap = {};
	this.subFlowMap[subFlow.role] = subFlow;
	if (! this.subFlowList)
		this.subFlowList = [];
	this.subFlowList.push(subFlow);
};
/**
	Returns the sole DisplayElement of this Flow.
	Returns null if there are 0 or multiple DisplayElements.
*/
FlowNode.prototype.addAncestorReference = function addAncestorReference(role, modelId)
{
	var reference = new FlowDataElement(role, modelId);
	reference.isAncestorReference = true;
	if (! this.ancestorReferenceList)
		this.ancestorReferenceList = [];
	
	this.ancestorReferenceList.push(reference);
	return this.addElement(reference);
};

FlowNode.prototype.addIntermediateDataElement = function addIntermediateDataElement(role, modelId)
{
	if (this.getGetter(role))
	{
		var element = new MethodElement(this, role, modelId);
		element.modelId = modelId;
	}
	else
		var element = new FlowDataElement(role, modelId);
	return this.addElement(element);
};

FlowNode.prototype.addConstant = function addConstant(role, modelId)
{
	var constantReference = new FlowDataElement(role, modelId);
	constantReference.type = 'Constant';
	if (!this.constantList)
		this.constantList = [];
	this.constantList.push(constantReference);
	return this.addElement(constantReference);
};

FlowNode.prototype.addLink = function addLink(role, source, target)
{
	if (!this.elements)
		return null; // If there are no elements, there is nothing to link. This can happen because of permission issues  
		
	var link = new Link(role, source,target);
	var sourceElement;
	if (!this.links)
		this.links = [];
	this.links.push(link);
	var sourceElement = this.elements[link.source.segments[0]];
	if (! sourceElement)
		return;
	if (! sourceElement.outgoingLinks)
		sourceElement.outgoingLinks = [];
	sourceElement.outgoingLinks.push(link);
	return link;
};

FlowNode.prototype.getLink = function getLink(role)
{
	if (! this.links)
		return null;
	for (var i=0; i<this.links.length; i++)
	{
		var link = this.links[i];
		if (link.role == role)
			return link;
	}
	return null;
};

/*
	Called before a FlowNode is started
*/
FlowNode.prototype.started = function started()
{
	this.setStatus(FlowStatus.STARTED);
	if (window.trace)
		window.trace.started(this);
};
FlowNode.prototype.resumed = function ()
{
	this.setStatus(FlowStatus.RESUMED);
};

FlowNode.prototype.finished = function ()
{
	/* Because actions can contain pop-up windows, finish() may be called more than once,
	 * but we don't want the <Done> exit to be charged again, or the trace to contain an additional event*/
	
	if (! this.alreadyFinished)
	{
		var doneExit = this.getElement(BuiltinNames.DONE_EXIT_NAME);
		if (doneExit)
			this.chargeEmptyExit(doneExit);
		if (window.trace)
			window.trace.finished(this);
		if (this.whenDone)
			this.whenDone();
	}
	this.setStatus(FlowStatus.DONE);
	this.alreadyFinished = true;
}
FlowNode.prototype.waiting = function ()
{
	this.setStatus(FlowStatus.WAITING_FOR_INPUT);
	if (window.trace)
		window.trace.waiting(this);
}
FlowNode.prototype.doStart = function()
{
	var node = this;
	var	resume = function()
	{
		if (tlog) tlog(node.modelName,'resumed after preload', node.modelId);
		node.resumeAfterPause();
		node.setStatus(FlowStatus.READY_TO_START);
		var executionContext = node.getExecutionContext();
		executionContext.resume();
		if (window.trace)
			window.trace.flush();
	};
	if (! this.preloadOnStart || this.preload(resume))
	{
		if (tlog) tlog(node.modelName,'started (already loaded)', node.modelId);
		if (tersus.failOnScriptErrors)
		{
			this.started();
			this.start();
			if (tlog) tlog(node.modelName,'started done', node.modelId);
		}
		else
		{
			try
			{
				this.started();
				this.start();
				if (tlog) tlog(node.modelName,'started done', node.modelId);
			}
			catch (e)
			{
				var m ="An error has occurred: "+e.message;
				if (!tersus.checkWindow(this.currentWindow))
				{
					m += "\n\nThe problem may have been caused by closing a pop-up window while it was being populated."
				}
				tersus.error(m);
			}
		}
		if (this.status != FlowStatus.PAUSED)
		{
			if (this.isAction)
			{
				this.finished();
			}
			else
			{
				this.waiting();
			}
		}
	}
	else
		if (tlog) tlog(node.modelName,'paused(waiting for models to load)', node.modelId);
};


FlowNode.prototype.start = function()
{
	var element; //represents a model element
	var child; // represents a child instance (sub-flow instance)
	var role;
	// add trigger values to the ready queue
	if (this.triggers)
		for (var i = 0; i < this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			
			if (trigger.isRepetitive)
			{
				var values = trigger.getChildren(this);
				trigger.removeChildren(this);
				for (var j=0; j< values.length; j++)
				{
					var value = values[j];
					this.createReference(trigger, value);
				}
			}		
			else
			{
				var value = this.getChild(trigger.role);
				if (value)
					this.createReference(trigger, value);
			}
		}
			
			
		//create instances for constants
		if (this.constantList)
		{
			for (var i=0; i< this.constantList.length; i++)
			{
				element = this.constantList[i];
				if (element.isSelfReady)
					child = element.createChild(this);
			}
		}
		
		if (this.ancestorReferenceList)
		{
			var ancestor;
			var ancestorData;
			var referenceNode;
			for (var i=0; i< this.ancestorReferenceList.length; i++)
			{
				element = this.ancestorReferenceList[i];
				role = element.role;
				ancestor = this.parent;
				var child = null;
				while (ancestor)
				{
					var parentElement = ancestor.getElement(role);
					if ( parentElement && parentElement.modelId == element.modelId) // In the direct ancestor we will find the referring element
					{
						var parentObj = parentElement.getChild(ancestor);
						if (parentObj)
							child = this.createReference(element, parentObj);
						ancestor = null;
					}
					else if (ancestor.modelId == element.modelId)
					{
						child = this.createReference(element, ancestor);
						ancestor = null; //No need to continue searching
					}
					else
					{
						ancestor = ancestor.parent;
					}
				}
				if (! child)
					if (tlog)
						tlog("Missing ancestor reference for "+role + " in "+ this.modelId);

			}
		}
		this.createSubFlows();
		this.runLoop();
	};
FlowNode.prototype.createSubFlows = function()
{
	//initializes sub flows
	if (this.subFlowList)
	{
		for (var i=0;i<this.subFlowList.length; i++)
		{
			var subFlow = this.subFlowList[i];
			subFlow.init(this);
		}
	}
};


FlowNode.prototype.createReference = function createReference(element, value)
{
	var child = new DataNode();
	child.type = element.type;
	child.mainWindow = this.mainWindow;
	child.currentWindow = this.currentWindow;
	child.parent = this;
	child.element = element;
	if (value.isDataNode)
		child.value = value.value;
	else
		child.value = value;
	element.addChild(this, child);
	if (child.isReady())
		this.addReadyElement(child);
	return child;
};




FlowNode.prototype.readyToResume = function readyToResume()
{
		this.setStatus(FlowStatus.READY_TO_RESUME);
		var parent = this.getParentContext();
		if (parent == null)
			return;
		parent.addReadyElement(this);
		if (parent.status == FlowStatus.WAITING_FOR_INPUT || parent.status == FlowStatus.DONE)
			parent.readyToResume();
};

/*
	Marks this FlowNode and its ancestors as ready to resume from the point of pause:
	(The paused processes are added to the beginning of the run-queue)
	
*/
FlowNode.prototype.resumeAfterPause = function resumeAfterPause()
{
	this.setStatus(FlowStatus.READY_TO_RESUME);
	var parent = this.getParentContext();
	if (parent == null)
		return;
	if ( ! parent.readyElements)
		parent.readyElements = [];
	parent.readyElements.splice(0,0, this); // insert at the beginning
	parent.resumeAfterPause();
}	

FlowNode.prototype.pause = function pause()
{
	this.setStatus(FlowStatus.PAUSED);
	if (window.trace)
		window.trace.paused(this);
	var parent = this.getParentContext();
	if (parent)
		parent.pause();
};

FlowNode.prototype.readyToStart = function readyToStart()
{
		this.setStatus(FlowStatus.READY_TO_START);
		var parent = this.getParentContext();
		if (parent == null)
			return;
		parent.addReadyElement(this);
		if (parent.status == FlowStatus.WAITING_FOR_INPUT || parent.status == FlowStatus.DONE)
			parent.readyToResume();
};
FlowNode.prototype.setInitialStatus = function setInitialStatus()
{
	this.setStatus(FlowStatus.NOT_READY_TO_START);
	this.checkReady();
};

FlowNode.prototype.checkReady = function checkReady()
{
	if (this.status == FlowStatus.NOT_READY_TO_START && this.isReady())
	{
		this.readyToStart();
	}
		
};

/*
	Adds 'child' to the run-queue, while preserving the dependency rank order
	('child' is added at the largest index that will result in a non-decreasing 
	dependency rank order)
*/
FlowNode.prototype.addReadyElement = function addReadyElement(child)
{
	
	
	
	var childRank = child.element.dependencyRank;
	
	
	if (!this.readyElements)
		this.readyElements = [];
	var targetIndex = this.readyElements.length;
	if (child.element.role == '<Init>')
		targetIndex = 0;
	else
	{
		while (targetIndex > 0)
		{
			var node = this.readyElements[targetIndex-1];
			var nodeRank = node.element.dependencyRank;
			if (nodeRank <= childRank)
			{
				// child should be inserted at targetIndex
				break;
			}
			--targetIndex;
		}
	}
	// Calling splice adds 'child' at targetIndex
	this.readyElements.splice(targetIndex, 0, child);
	
};

FlowNode.prototype.setStatus = function setStatus(status)
{
	this.status = status;
};

FlowNode.prototype.resume = function resume(message)
{
//	if (tlog) tlog(this.modelName + ' resumed\t' + this.modelId);

		//TODO: handle data on input slots	(see Java implementation)
		// Handle waiting elements
		if (tersus.failOnScriptErrors)
		{
			this.resumed();
			this.runLoop();
		}
		else
		{
			try
			{
				this.resumed();
				this.runLoop();
			}
			catch (e)
			{
				var m ="An error has occurred: "+e.message;
				if (!tersus.checkWindow(this.currentWindow))
				{
					m += "\n\nThe problem may have been caused by closing a pop-up window while it was being populated."
				}
				tersus.error(m);
				if (this.isAction)
				{
					this.finished();
				}
				else
				{
					this.waiting();
				}
			}
		}
		
		if (this == window.rootDisplayNode && 	this.status == FlowStatus.WAITING_FOR_INPUT)
			if (tersus.async.nowait())
				tersus.progress.clear();
};
FlowNode.prototype.isReady = function isReady()
{
	if (this.triggers)
	{
		for (var i=0; i<this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			if (trigger.mandatory)
			{
				if (trigger.isEmpty(this))
				{
					return false;
				}
			}
		}
	}
	return true;
};
FlowNode.prototype.runLoop = function run()
{
	var child;
//		createParentElementReferences(context, flow);
	while (this.status != FlowStatus.PAUSED && this.hasReadyElements())
	{
		child = this.readyElements.shift();
		child.invoke(); //Start or resume
	}
	if (this.status != FlowStatus.PAUSED)
	{
		if (this.isAction)
		{
			this.finished();
		}
		else
		{
			this.waiting();
		}
	}
		

};

FlowNode.prototype.hasReadyElements = function hasReadyElements()
{
	return (this.readyElements && this.readyElements.length > 0);
};

FlowNode.prototype.invoke = function invoke ()
{
	switch(this.status)
	{
		case FlowStatus.READY_TO_START:
			this.doStart();
			break;
		case FlowStatus.READY_TO_RESUME:
			this.resumed();
			this.resume();
			break;
		default:
			internalError('Child with invalid status invoked '+ this.status);
	}
	if (this.status != FlowStatus.PAUSED)
		this.invokeLinks();
	//TODO - remove exit values / input values
};

FlowNode.prototype.chargeEmptyExit = function chargeEmptyExit(exit)
{
	if (! exit.isExit)
		exit = this.getExit(exit); // exit given by name
	if (exit)
	{
		exit.createChild(this);
		if (window.trace)
		{
			window.trace.charged(this, exit);
		};
	}
};

FlowNode.prototype.getExit = function (name)
{
	if (!this.exits)
		return null;
	var exit = this.getElement(name);
	if (exit && exit.isExit)
		return exit;
	else if (name.search(/^<.*>$/)>=0) // Distinguished name - allow perfixes
	{
		for (var i=0; i<this.exits.length; i++)
		{
			var current = this.exits[i];
			var matches = current.role.match(/<.*>$/);
			if (matches.length && matches.length == 1 && matches[0] == name)
			{
				if (exit)
					return null; //ambigous
				exit = current;
			}
		}
	}
	return exit;
};

FlowNode.prototype.getTrigger = function (name)
{
	if (!this.triggers)
		return null;
	var trigger = this.getElement(name);
	if (trigger)
		return trigger;
	else if (name.search(/^<.*>$/)>=0) // Distinguished name - allow perfixes
	{
		for (var i=0; i<this.triggers.length; i++)
		{
			var current = this.triggers[i];
			var matches = current.role.match(/<.*>$/);
			if (matches && matches.length && matches.length == 1 && matches[0] == name)
			{
				if (trigger)
					return null; //ambigous
				trigger = current;
			}
		}
	}
	return trigger;
};
FlowNode.prototype.getTriggerLeafValue = function(role)
{
	var trigger = this.getTrigger(role);
	var value = null;
	if (trigger)
	{
		value = trigger.getChild(this);
		if (value != null)
			value = value.leafValue;
	}
	return value;
};
FlowNode.prototype.chargeExit = function (exit, value)
{
	if (! exit.isExit)
		exit = this.getExit(exit);
	if (exit)
	{
		exit.replaceChild(this,value);
		if (window.trace)
			window.trace.charged(this, exit, value);
	}
};
FlowNode.prototype.accumulateExitValue = function(exit, value)
{
	if (! exit.isExit)
		exit = this.getExit(exit);
	if (exit)
	{
		exit.addAChild(this,value);
		if (window.trace)
			window.trace.charged(this, exit, value);
	}
};

FlowNode.prototype.chargeLeafExit = function chargeLeafExit(exit, leafValue)
{

	if (! exit.isExit)
		exit = this.getExit(exit); // exit given by name
	if (exit && (leafValue != null) )
	{
		var child = exit.createChild(this);
		child.setLeaf(leafValue);
		if (window.trace)
			window.trace.charged(this, exit, child);
		
	};
};

FlowNode.prototype.getExecutionContext = function getExecutionContext()
{
	if (this.getParentContext())
		return this.getParentContext().getExecutionContext();
	else
		return this;
};

FlowNode.prototype.getParentContext = function getParentContext()
{
	return this.parent;
};

FlowNode.prototype.addTrigger = function addTrigger(role, modelId)
{
	if (! this.triggers)
		this.triggers = [];
	var trigger = new Trigger(role, modelId);
	this.triggers.push( trigger);
	return this.addElement(trigger);
};

FlowNode.prototype.addExit = function addExit(role, modelId)
{
	if (! this.exits)
		this.exits = [];
	var exit = new Exit(role, modelId);
	this.exits.push( exit);
	return this.addElement(exit);
};

FlowNode.prototype.getTriggerValues = function getTriggerValues(excludedTriggerName)
{
	var values = [];
	for (var i=0; i<this.triggers.length; i++)
	{
		var trigger = this.triggers[i];
		if (trigger.modelId != BuiltinModels.NOTHING_ID && trigger.role != excludedTriggerName )
		{
			if (trigger.isRepetitive)
			{
				values = values.concat(trigger.getChildren(this));
			}
			else
			{
				var value = trigger.getChild(this);
				if (value != null && value != undefined)
					values.push(value);	
			}
			
		}
	}
	return values;
};

FlowNode.prototype.getEventHandler = function(eventType)
{
	if (! this.subFlowMap)
		return null;
	var handler = this.subFlowMap[eventType.elementName];
	if (handler == undefined)
		return null;
	return handler;
};
FlowNode.prototype.hasEventHandler = function(eventType)
{
	return (this.getEventHandler(eventType) != null);
};

FlowNode.prototype.queueEvent = function (eventType, params)
{
	var description = null;
	if (tlog)
	{
		description = eventType.methodName + ' ['+ this.getPath().str+']';
		tlog('queuing event:'+eventType.jsName);
		if (tersus.currentEventAttributes)
			tlog('keyCode='+tersus.currentEventAttributes.keyCode+' type='+tersus.currentEventAttributes.type);
	}
	var handler = this.getEventHandler(eventType);
	if (handler)
	{
		var c = handler.getChildConstructor();
		
		if (c && c.prototype.runImmediately)
		{
			// Run a "background process" in current thread
			var process = new BackgroundProcess(this, handler, params);
			process.start(); 
		}
		else
			queueEvent(window.engine, window.engine.handleEvent, [this,eventType,  params, tersus.currentEventAttributes], new Date(), description);
	}

};

FlowNode.map = {};
FlowNode.prototype.getNodeId = function()
{
        if (!this.nodeId)
        {
                this.nodeId = window.nextNodeId ? window.nextNodeId : 1;
                FlowNode.map[this.nodeId]=this;
                window.nextNodeId = this.nodeId + 1;
        }
        return this.nodeId;
};
FlowNode.prototype.destroy = function()
{
	if (this.nodeId)
		delete FlowNode.map[this.nodeId]
}
tersus.findNode = function findNode(id)
{
	return FlowNode.map[id];
}
// file: 021-ActionNode.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function ActionNode() {};
ActionNode.prototype = new FlowNode();
ActionNode.prototype.constructor = ActionNode;
ActionNode.prototype.isAction = true;
ActionNode.prototype.type="Action";
ActionNode.prototype.runImmediately=false;// file: 024-BackgroundProcess.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 

function BackgroundProcess (parent, subflow, params)
{
	if (parent && subflow)
	{
		this.parent = parent;
		this.process = subflow.createChildInstance();
		this.context = new BackgroundProcessContext(parent);
		this.process.mainWindow = parent.mainWindow;
		this.process.currentWindow = parent.currentWindow;
		this.process.parent = this.context;
		this.process.element = subflow;
		if (params)
		{
			for (var key in params)
			{
				this.process.setChild(key, params[key], Operation.REPLACE);
			} 
		}
	}
};

BackgroundProcess.prototype.setTriggerValue = function setTriggerValue(role, value)
{
	this.process.setChild(role,value, Operation.REPLACE);
};
BackgroundProcess.prototype.setTriggerLeafValue = function setTriggerValue(role, value)
{
	this.process.setLeafChild(role,value, Operation.REPLACE);
};


BackgroundProcess.prototype.getExitValues = function getExitValues(role)
{
	return this.process.getChildren(role);
};

BackgroundProcess.prototype.start = function()
{
	if (this.process.isReady())
		this.process.doStart();
	if (window.trace)
		window.trace.flush();
	
};
BackgroundProcess.prototype.whenDone = function whenDone(callback)
{
	this.process.whenDone = callback;
};
function BackgroundProcessContext(context)
{
	this.context = context;
	this.parent = context;
	this.setStatus(FlowStatus.WAITING_FOR_INPUT);
};
BackgroundProcessContext.prototype = new FlowNode();
BackgroundProcessContext.prototype.constructor = BackgroundProcessContext;
BackgroundProcessContext.prototype.getPath = function getPath()
{
	return this.context.getPath();
};
BackgroundProcessContext.prototype.getParentContext = function getParentContext()
{
	return null;
};
BackgroundProcessContext.prototype.isBackground = true;
// file: 025-DisplayNode.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
// DisplayNode (a FlowNode that displays soemthing)
function DisplayNode()
{
};


DisplayNode.prototype = new FlowNode();
DisplayNode.prototype.visible = true;
DisplayNode.prototype.constructor = DisplayNode;
DisplayNode.prototype.type='Display';
DisplayNode.prototype.isDisplayNode=true;
  
DisplayNode.prototype.explicitReadOnly = false;
DisplayNode.prototype.VALIDATION_MESSAGE = '<Validation Message>';

DisplayNode.prototype.setViewNode = function DisplayNode_setViewNode(viewNode)
{
	this.viewNode = viewNode;
};
DisplayNode.prototype.getValidationContext = function DisplayNode_getValidationContext()
{
	if (this.parent && this.parent.getValidationContext)
		return this.parent.getValidationContext();
	else
		return this;
};
DisplayNode.findNodeForDocumentNode = function(viewNode)
{
	var nodeId = null;
	while (viewNode && viewNode.getAttribute && !nodeId)
	{
		nodeId = viewNode.getAttribute("lid"); // logic node id
		if (! nodeId)
			nodeId = viewNode.id;
		if (nodeId)
			return tersus.findNode(nodeId);
		viewNode = viewNode.parentNode;
	}
	return null; 
};
DisplayNode.prototype.escapeHTML = function(s)
{
	if (this.sharedProperties.allowHTMLTags != true && ! this.allowHTMLTags)
		return tersus.escapeHTML(s);
	else
		return s;
};
DisplayNode.prototype._onFocus = function()
{
	var parent = this.parent;
	while (parent)
	{
		if (parent.onChildFocus)
			parent.onChildFocus();
		parent = parent.parent;
	}
};

tersus.createEventHandler = function(eventType)
{
	// Default event handler method on DisplayNode
	if (eventType.methodName)
	{
		DisplayNode.prototype[eventType.methodName] = function()
		{
			if (window.trace)
			{
				window.trace.event(this, eventType);
			}
			var baseMethodName = '_'+eventType.methodName;
			if (this[baseMethodName])
				this[baseMethodName]();
			this.queueEvent(eventType);
		
		}
	}
};

for (var key in Events)
{
	tersus.createEventHandler(Events[key]);
};

tersus.createEventDispatcher = function(eventType, w)
{
	// Event dispatching global function
	if (eventType.jsName && eventType.methodName)
	{
		w.tersus_dispatchers[eventType.jsName] = function(e)
		{
			var ev = e;
			if (ev == null)
			{
				var w = getParentWindow(this);
				ev = w.event;
			}
			if (tersus.disabled)
				return true;
			if (ev)
				tersus.currentEventAttributes = getEventAttributes(ev);
			tersus.currentEvent = ev;
			try
			{
				var node = DisplayNode.findNodeForDocumentNode(this);
				if (tlog)
				{
					
					tlog('Captured event: '+ eventType.methodName + ' on ['+ node.getPath().str+']');
				}
				
				if (node)
				{
					return node[eventType.methodName](this);
				}
				else
					return true;
			}
			finally
			{
				tersus.currentEvent = null;
			}
		};
	}
};


tersus.createEventDispatchers = function t_addEvents(w)
{
	w.tersus_dispatchers = {};
	for (var key in Events)
	{
		tersus.createEventDispatcher(Events[key], w);
	}
};

tersus.createEventDispatchers(window);
DisplayNode.prototype.registerEventHandler = function(eventType, domNode)
{
	if (!domNode)
		domNode = this.viewNode;
	domNode.setAttribute('lid',this.getNodeId());
	if (!eventType.jsName)
	{
		internalError('No event dispatcher defined for '+eventType.elementName);
		return;
	}
	
	var dispatcher = this.currentWindow.tersus_dispatchers[eventType.jsName];
	if (dispatcher)
		domNode[eventType.jsName] = dispatcher;
	else
		internalError('No event dispatcher defined for '+eventType.jsName);
	
};
DisplayNode.prototype.checkBooleanProperty = function (name)
{
	return this.sprop(name) == true;
}
DisplayNode.prototype.sprop = function (name) // Can be made redundant if we prevent blanks on loading
{
	if (!this.sharedProperties) 
		return null;
	var p = this.sharedProperties[name];
	return (p != ' ' ? p :null);
}
DisplayNode.prototype.copyValue = function(value)
{
	this.deepCopy(value);
};
DisplayNode.prototype.create = function DisplayNode_create(value)
{
	if (! (tersus.preferHTMLCreation && this.checkBooleanProperty('optimizeHTML')) )
	{
		this.createViewNode();
		this.attachViewNode();
		this.initViewNode();
		this.createChildren();
	}
	if (value != null)
		this.copyValue(value);
	
};
DisplayNode.prototype.createChildren = function DisplayNode_createChildren()
{
	if (this.displayElements)
	{
		for (var i=0; i<this.displayElements.length; i++)
		{
			var e = this.displayElements[i];
			if ( !e.isRepetitive && ! e.isMethodElement && e.alwaysCreate)
			{
				var child = e.createChild(this);
			}
		}
	}
	
};
DisplayNode.prototype.setDisplayOrder = function setDisplayOrder()
{
	var displayOrder = this.element? this.element.displayOrder:1;
	this.viewNode.setAttribute('display_order',displayOrder);
};
DisplayNode.prototype.attachViewNode = function DisplayNode_attachViewNode()
{
	if (! this.viewNode)
		return;
	if (this.parent)
	{
		this.setDisplayOrder();
		this.parent.appendChildViewNode(this, this.element);
	}
};
DisplayNode.prototype.initViewNode = function DisplayNode_initViewNode()
{
	if (this.defaultStyleClass)
		this.setStyleClass(this.defaultStyleClass);
	this.setProperties();
	this.setEventHandlers();

}
tersus.removeEventHandlers = function(domNode)
{
	for (key in Events)
	{
		var eventType = Events[key];
		if (eventType.jsName)
			domNode[eventType.jsName] = null;
	}
	
};
DisplayNode.prototype.setEventHandlers = function DisplayNode_setEventHandlers()
{
	for (var key in Events)
	{
		var eventType = Events[key];
		if (this.hasEventHandler(eventType) && eventType.jsName)
		{
			if (this.element)
				this.registerEventHandler(eventType);
			else
				this.registerEventHandler(eventType,document.body);
		}
	}
	if (this.hasEventHandler(Events.ON_LOCATION_CHANGE))
		tersus.locationChangeListeners.push(this.getNodeId());
}
DisplayNode.prototype.removeChildViewNode = function(child)
{
	if (child)
	{
		var top = child.wrapperNode ? child.wrapperNode : child.viewNode;
		if (top && top.parentNode)
			top.parentNode.removeChild(top);
	}
};
DisplayNode.prototype.appendChildViewNode = function appendChildViewNode(child, childElement)
{
	var childNode;
	if (child.wrapperNode)
	{
		childNode = child.wrapperNode; // Child wrapper already created - no need to wrap again 
	}
	else if (child.sharedProperties && (child.sharedProperties.wrapperTag != null) && (child.sharedProperties.wrapperTag != ' ') )
	{
		childNode = this.createHTMLElement(child.sharedProperties.wrapperTag, child.sharedProperties.wrapperStyleClass);
		childNode.setAttribute('display_order', child.viewNode.getAttribute('display_order'));
		childNode.appendChild(child.viewNode);
		child.wrapperNode = childNode;
	}
	else
		childNode = child.viewNode;
	if (child.placeHolderNode)
	{
		this.viewNode.replaceChild(childNode, child.placeHolderNode);
		child.placeHolderNode = null;
	}
	else	
	{
		DisplayNode.appendChildNode(this.viewNode, childNode);
	}
		
};

DisplayNode.appendChildNode = function(parent, newChild)
{
	var displayOrder = parseFloat(newChild.getAttribute('display_order'));
	var children = parent.childNodes;
	for( var i = 0; i<children.length; i++)
	{
		var child = children[i];
		if (child.getAttribute && parseFloat(child.getAttribute('display_order')) > displayOrder)
		{
			parent.insertBefore(newChild, child);
			return;
		}
	}
	parent.appendChild(newChild);
};
DisplayNode.prototype.forDisplayChildren = function (f)
{
	if (this.displayElements)
	{
		for (var i=0;i<this.displayElements.length;i++)
		{
			var e = this.displayElements[i];
			if (e.isRepetitive)
			{
				var list = e.getChildren(this);
				for (var j=0;j<list.length;j++)
				{
					var child = list[j];
					if (child)
						f.call(null,child);
				}
			}
			else
			{
				child = e.getChild(this);
				if (child)
					f.call(null,child);
			}
		}
	}
}	

DisplayNode.prototype.deleteMe = function()
{
	var element = this.element;
	var parent= this.parent;
	if (! parent)
		return;
	if (element.isRepetitive)
	{
		var siblings = element.getChildren(parent);
		for (var i=0;i<siblings.length;i++)
		{
			if (siblings[i] == this)
			{
				siblings.splice(i,1); // removes element at index i
				this.onDelete();
				return;
			}
		}
	}
	else
		element.removeChild(parent);
};
DisplayNode.prototype.destroy = function()
{
	FlowNode.prototype.destroy.call(this);
	// Remove event listener
	if (this.hasEventHandler(Events.ON_LOCATION_CHANGE))
	{
		// Remove this node's id from the tersus.locationChangeListeners
		var listeners = [];
		for (var i=0;i<tersus.locationChangeListeners.length;i++)
		{
			if (tersus.locationChangeListeners[i] != this.getNodeId())
				listeners.push(tersus.locationChangeListeners[i]);
		}
		tersus.locationChangeListeners = listeners;
	};
	
	if (this.hasEventHandler(Events.ON_DELETE))
	{
		var process = new BackgroundProcess(this, this.getEventHandler(Events.ON_DELETE));
		tersus.async.exec(function(){process.start()}, false /* don't wait */); 
	};
};
DisplayNode.prototype.onDelete = function onDelete()
{
	this.destroyHierarchy();
	if (this.parent)
		this.parent.removeChildViewNode(this);
};

DisplayNode.prototype.createHTMLElement = function createHTMLElement(tag, styleClass)
{
	var element = this.currentWindow.document.createElement(tag);
	if (styleClass && styleClass != ' ')
		element.className=styleClass;
	return element;
};
DisplayNode.prototype.createHTMLChildElement = function createHTMLChildElement(parentNode,tag, styleClass)
{
	var childNode = this.createHTMLElement(tag, styleClass);
	parentNode.appendChild(childNode);
	return childNode;
};
DisplayNode.prototype.getTag = function getTag()
{
	var t = this.sprop('tag');
	if (!t)
		t = this.defaultTag;
	return t;
};
DisplayNode.prototype.createViewNode = function DisplayNode_createViewNode()
{
	var tag = this.getTag();
	this.viewNode = this.createHTMLElement(tag);
	this.viewNode.setAttribute('lid',this.getNodeId());
};
DisplayNode.prototype.setProperties = function setProperties()
{
	var props = this.sharedProperties;
	if (!props)
		return;
	if (props.styleClass && props.styleClass != ' ')
		this.setStyleClass(props.styleClass);
	else if (this.defaultStyleClass)
		this.setStyleClass(this.defaultStyleClass);
	this.setStyle(props.style);
	if (props.label)
		this.viewNode.innerHTML = props.label;
	if (props.textTranslation != undefined)
	{
		if (props.textTranslation == 'false')
			this.textTranslation = false;
		else
			this.textTranslation = true;
	}
	var tag = this.viewNode.tagName;
	for (var p in props)
	{
		var value = props[p];
		if ( value != ' ')
		{
			if (HTMLProperties[tag] && HTMLProperties[tag][p])
				this.viewNode[p]=value;
			else if (STYLE_PROPERTIES[p])
				this.viewNode.style[STYLE_PROPERTIES[p]]=value;
		}
	}

};
DisplayNode.prototype.removeAll = function DisplayNode_removeAll()
{
	if (this.elements)
	{
		for (var i=0; i<this.elementList.length; i++)
		{
			var e = this.elementList[i];
			if (e.isRemovable)
			{
				if (e.isRepetitive)
				{
					e.removeChildren(this);
				}
				else
				{
					e.removeChild(this);
				}
			}
		}
	}
}
DisplayNode.prototype.sharedProperties = DisplayNode.prototype.NO_PROPERTIES = {};
DisplayNode.prototype.addDisplayElement = function addElement(role, modelId, properties)
{
	if (this.getGetter(role))
	{
		var element = new MethodElement(this, role, modelId);
		element.modelId = modelId;
	}
	else
		var element = new DisplayElement(role, modelId);
	if (! this.displayElements)
		this.displayElements = [element];
	else
		this.displayElements.push(element);
	element.displayOrder = this.displayElements.length;
	this.registerSubFlow(element);
	element.properties = properties ? properties : this.NO_PROPERTIES;
	return this.addElement(element);
};
DisplayNode.prototype.optimizeFormatString = false;
DisplayNode.prototype.onload = function()
{
	this.optimizeFormatString = 
		(this.sprop('decimalPlaces') == null || this.sprop('decimalPlaces') == -1)
		&&
	 	this.sprop('useThousandsSeparator') == null &&
	 	this.sprop('currencySymbol') == null;
	 this.htmlTagSuffix = '</'+this.getTag()+'>';
	 this.hasElementChangeHandler =  this.hasEventHandler(Events.ON_ELEMENT_CHANGE);
}
DisplayNode.prototype.handleElementChange = function (role, oldValue, newValue)
{
	var parameters = {'<Element Name>':role, '<Previous Value>':oldValue, '<New Value>':newValue};
	window.engine.handleEvent(this,Events.ON_ELEMENT_CHANGE,parameters,null /* No GUI Attributes */);
	
}

DisplayNode.prototype['set<Value>'] = function setValue(value)
{
	this.value = value;
	this.setValueString();
};
DisplayNode.prototype['set<Value>'].requiresNodes = true;
DisplayNode.prototype.setValueString = function()
{
	this.valueStr = '';
	if (this.value != null)
	{
		if (this.optimizeFormatString)
			this.valueStr = this.value.leafValue;
		else if (this.value.formatString)
			this.valueStr = this.value.formatString(this.sharedProperties);
		else
			this.valueStr = this.value.toString();
	}
	if (this.viewNode)
		this.viewNode.innerHTML = this.escapeHTML(this.valueStr);
};
DisplayNode.prototype['remove<Value>'] = function removeVaule()
{
	this.value = null;
	if (this.viewNode)
		this.viewNode.innerHTML='';
};
DisplayNode.prototype['set<Labels>'] = function setLabels(map)
{
	tersus.labelMap = map;
	var op = function(node)
	{
		if (node.captionChanged && node.viewNode)
			node.captionChanged();
	};
	tersus.traverseHierarchy(window.rootDisplayNode, tersus.Node.childIterator, op);
};
DisplayNode.prototype['get<Labels>'] = function getLabels()
{
	return tersus.labelMap;
};
DisplayNode.prototype['set<Resources>'] = function setLabels(map)
{
	tersus.resourceMap = map;
};
DisplayNode.prototype['get<Resources>'] = function getLabels()
{
	return tersus.resourceMap;
};
DisplayNode.prototype['set<Direction>'] = function DisplayNode_setDirection(direction)
{
	tersus.setDirection(direction);
};
DisplayNode.prototype['get<Direction>'] = function getDirection()
{
	return tersus.getDirection();
};

DisplayNode.prototype['get<Visible>'] = function ()
{
	return this.visible;
};

DisplayNode.prototype['set<Visible>'] = function (visible)
{
	this.visible = visible;
	this.refreshVisibility();
};
DisplayNode.prototype.refreshVisibility = function()
{
	if (this.viewNode)
	{
		var visible = this.visible;
		var parent = this.parent;
		while (visible && parent && parent.isGroup)
		{
			visible = parent.visible;
			parent = parent.parent;
		}
		if (!visible)
			this.viewNode.style.display='none';
		else
		{
			this.viewNode.style.display='';
			this.onResize();
		}
	}
};

DisplayNode.prototype.styleClass = '';
// baseClassName - the class name defined by the application, not taking into account special conditions like selection
DisplayNode.prototype.baseClassName = ''; 
DisplayNode.prototype.extraClassName = ''; 
DisplayNode.prototype.setStyleClass = function setStyleClass(value)
{
	if (this.viewNode)
	{
		var className = value;
		var rtlClassName = value+'_rtl';
		if (window.textDirection == 'rtl' && tersus.styleClassNames.contains(rtlClassName))
			className = rtlClassName;
		if (this.viewNode.className == this.baseClassName)
			this.viewNode.className = className + this.extraClassName;
		this.baseClassName = this.viewNode.className;
	}
	this.styleClass = value;
};
DisplayNode.prototype['set<Style Class>'] = function(value)
{
	this.setStyleClass(value);
};
 DisplayNode.prototype['get<Style Class>'] = function getStyleClass()
{
	return this.styleClass;
};
DisplayNode.prototype.setStyle =  DisplayNode.prototype['set<Style>'] = function(value)
{
	if (this.viewNode && value != null)
	{
		try
		{
			return this.viewNode.style.cssText = value;
		}
		catch (e)
		{
			modelExecutionError('Failed to set style "'+value+'"  (HTML tag='+this.viewNode.tagName+')',this);
		}
	}
};
DisplayNode.prototype['get<Style>'] = function getStyleClass()
{
	if (this.viewNode)
		return this.viewNode.style.cssText;
};
DisplayNode.prototype['get<Value>'] = function getValue()
{
	return this.value;
}
DisplayNode.prototype.getBaseCaption = DisplayNode.prototype['get<Caption>'] = function()
{
	if (this.caption != undefined)
		return this.caption;
	var c = this.sprop('caption');
	if (c != null)
		return c;
	else
		return this.element.role;
	
};
DisplayNode.prototype.getCaption = function()
{
	var idTranslation = this.getTranslation(this.modelId);
	if(idTranslation != undefined)
		return idTranslation; 
	else
		return this.translate(this.getBaseCaption());
};
DisplayNode.prototype.captionChanged = function() {};
DisplayNode.prototype['set<Caption>'] = function(caption)
{
	this.caption = caption;
	this.captionChanged();
};
DisplayNode.prototype['get<Read Only>'] = function ()
{
	return this.explicitReadOnly;
};
DisplayNode.prototype['set<Read Only>'] = function (readOnly)
{
	if (this.explicitReadOnly != readOnly)
	{
		var originalState = this.computedReadOnly();
		this.explicitReadOnly = readOnly;
		var newState = this.computedReadOnly();
		if (this.newState != originalState) 
		{
			this.updateSelfReadOnly(newState);
			this.updateChildrenReadOnly(newState);
		}
		
	}
};
DisplayNode.prototype.updateSelfReadOnly = function ()
{
};
DisplayNode.prototype.updateChildrenReadOnly = function DisplayNode_updateChildrenReadOnly(readOnly)
{
	if (! this.displayElements)
		return;
	for (var i=0; i<this.displayElements.length; i++)
	{
		var element = this.displayElements[i];
		if (element.isRepetitive)
		{
			var children = element.getChildren(this);
			for (var j=0; j<children.length;j++)
			{
				var child = children[j];
				if (! child.explicitReadOnly) // If the child is explicitly read only, its state won't change
					child.parentReadOnlyChanged(readOnly);
			}
		}
		else
		{
			var child = element.getChild(this);
			if (child && ! child.explicitReadOnly) // If the child is explicitly read only, its state won't change
				child.parentReadOnlyChanged(readOnly);
		}
	}
};
DisplayNode.prototype.parentReadOnlyChanged = function(readOnly)
{
	this.updateSelfReadOnly(readOnly);
	this.updateChildrenReadOnly(readOnly)
};
/**
 * Computes the read only state of this node.  A node is in read only mode if it's explicitly
 * marked as read only, or if its ancestor is read only
 */	
DisplayNode.prototype.computedReadOnly = function DisplayNode_computedReadOnly()
{
	if (this.explicitReadOnly)
		return true;
	else if (this.parent && this.parent.computedReadOnly)
		return this.parent.computedReadOnly();
	else
		return false;
};
DisplayNode.prototype.onResizeChildren = function onResizeChildren()
{
	if (this.displayElements)
	{
		for (var i=0; i<this.displayElements.length; i++)
		{
			var element = this.displayElements[i];
			if (element.isRepetitive)
			{
				var children = element.getChildren(this);
				for (var j=0; j<children.length;j++)
				{
					var child = children[j];
					child.onResize();
				}
			}
			else
			{
				var child = element.getChild(this);
				if (child)
					child.onResize();
			}
		}
	}
};
DisplayNode.prototype.onResize = DisplayNode.prototype.onResizeChildren;

DisplayNode.prototype.isDisplayNode = true;
/******************************************************************
 *  reset() is called before replacing a display element, and does not trigger initialization processes
 *  refresh() is called when refreshing a display element, and includes initiailization processes (createSubFlows).
 *
 *  If reset triggered initialization processes, we might end up in strange situations, like double initialization
 *   (e.g. If a chooser initializes itself, and then a different chooser is copied onto it)
 *
 *
 ****************************************************************** */
DisplayNode.prototype.reset = function DisplayNode_reset()
{
	this.removeAll();
	this.initViewNode();
	this.createChildren(); // TODO(x) eliminate redundant creation of children (not sure whether this really is redundant as reset() is overridden in HTMLTag)
};
DisplayNode.prototype.refresh = function DisplayNode_refresh()
{
	this.reset();
	this.createSubFlows();
};


DisplayNode.prototype.deepCopy = function deepCopy(value)
{
	if (tlog) tlog("start deepCopy:"+value.modelId);
	for (var elementRole in value.elements)
	{
		var element = this.getElement(elementRole);
		if (element)
		{
			if (element.isRepetitive)
			{
				var childValues = value.getChildren(elementRole);
				element.setChildren(this, childValues, Operation.REPLACE);
			}
			else
			{
				var childValue = value.getChild(elementRole);
				if (childValue != null)
				{
					element.replaceChild(this, childValue);
				}
			}
		}
	}
	if (tlog) tlog("end deepCopy:"+value.modelId);
};
DisplayNode.prototype.tooltip = null;
DisplayNode.prototype.setTooltip = DisplayNode.prototype['set<Tooltip>'] = function (tooltip)
{
	this.tooltip = tooltip;
	if (this.viewNode && tooltip != undefined && tooltip != null)
	{
		this.viewNode.title = this.translate(tooltip);
	};
};
DisplayNode.prototype.getTooltip = DisplayNode.prototype['get<Tooltip>'] = function ()
{
	return this.tooltip;
};
DisplayNode.prototype.setValidationMessage = DisplayNode.prototype['set<Validation Message>']= function (message)
{
	this.validationMessage = message;
	if (this.currentWindow && this.viewNode)
	{
		if (message != null)
		{
			this.viewNode.className = this.styleClass + ' invalid';
			this.viewNode.title = this.forceTranslate(message);
		}
		else
		{
			this.viewNode.className = this.styleClass;		
			this.viewNode.title='';
		}
	}
};
DisplayNode.prototype['remove<Validation Message>']= function ()
{
	this.setValidationMessage(null);
};
DisplayNode.prototype.getValidationMessage = DisplayNode.prototype['get<Validation Message>']= function (message)
{
	return this.validationMessage;
};

DisplayNode.prototype.showValidationMessage = function (message)
{
	this.currentWindow.alert(message);
};
DisplayNode.prototype.validate = function validate()
{
	var message = this.getValidationMessage();
	if (message != null)
	{
		this.showValidationMessage(this.forceTranslate(message));
		return false;
	}
	if (! this.elementList)
		return true;
	for (var j=0; j<this.elementList.length; j++)
	{
		var element = this.elementList[j];
		if (element.isRepetitive)
		{
			var values = element.getChildren(this);
			for (var i=0; i< values.length; i++)
			{
				var value = values[i];
				if (value && value.validate && ! value.validate())
					return false;
				
					
			}
		}
		else
		{
			var value = element.getChild(this);
			if (value && value.validate && ! value.validate())
				return false;
		}
	}
	return true;
};
DisplayNode.prototype.findDisplayElementIndex = function (role)
{
	for (var i=0; i<this.displayElements.length;i++)
	{
		var e = this.displayElements[i];
		if (e.role ==role)
			return i;
	}
	return null;
};
DisplayNode.prototype.findPreviousSibling = function (child)
{
	var role = child.element.role;
	
	// Find the last child among the preceding display elements
	var index = this.findDisplayElementIndex(role);
	if (index == null)
		return null;
	for (var i=index;i>=0;i--)
	{
		var e = this.displayElements[i];
		if (e.isRepetitive)
		{
			var children = e.getChildren(this);
			for (var j=children.length-1; j>=0; j--)
			{
				var sibling = children[j];
				if (sibling && sibling != child)
					return sibling;
			}
		}
		else
		{
			var sibling = e.getChild(this);
			if (sibling && sibling != child)
				return sibling;
		}
	}
	return null;
};
DisplayNode.prototype.focusOnFirstField = function()
{
	var elements = this.viewNode.getElementsByTagName('*');
	for (var i=0; i<elements.length; i++)
	{
		var e = elements[i];
		if (e.tagName == 'INPUT' || e.tagName == 'TEXTAREA')
		{
			if (isVisible(e) && !e.disabled)
			{
				this.currentWindow.setTimeout(function(){if (isVisible(e) && !e.disabled) e.focus();},0);
				break;
			}
		}
	}
};


DisplayNode.prototype.addGetter('<Screen X>', function()
{
	if (!this.viewNode)
		return null;
	return getScreenPosition(this.viewNode).left;
});
DisplayNode.prototype.addSetter('<Screen X>', function(x)
{
	this.viewNode.style.position='absolute';
	this.viewNode.style.left = x - getScroll(this.viewNode).left;
});

DisplayNode.prototype.addGetter('<Screen Y>', function()
{
	if (!this.viewNode)
		return null;
	if (this.viewNode.tagName == 'SPAN')
	{
		if (this.inputField) // This happens in input fields
			return getScreenPosition(this.inputField).top;
		else
			internalError("Getting the vertical position of 'SPAN' elements not supported yet");
	}
	else
		return getScreenPosition(this.viewNode).top;
});
DisplayNode.prototype.addSetter('<Screen Y>', function(y)
{
	this.viewNode.style.position='absolute';
	this.viewNode.style.top = y - getScroll(this.viewNode).top;
});

DisplayNode.prototype.addGetter('<URL>', function()
{
	if (this.viewNode)
		return this.viewNode.href;
});
DisplayNode.prototype.addSetter('<URL>', function(url)
{
	if (this.viewNode)
		this.viewNode.href = url;
});
DisplayNode.prototype.addGetter('<Target Window>', function()
{
	if (this.viewNode)
		return this.viewNode.target;
});
DisplayNode.prototype.addSetter('<Target Window>', function(target)
{
	if (this.viewNode)
		this.viewNode.target = target;
});
DisplayNode.prototype.addGetter('<Width>', function()
{
	if (this.viewNode)
		return getVisibleSize(this.viewNode).width;
	else
		return this.width;
});
DisplayNode.prototype.addSetter('<Width>', function(width)
{
	this.width = width;
	if (this.viewNode)
		this.viewNode.style.width = width;
});
DisplayNode.prototype.addGetter('<Height>', function()
{
	if (! this.viewNode)
		return this.height;
	if (this.viewNode.tagName == 'SPAN')
	{
		if (this.inputField) // This happens in input fields
			return getVisibleSize(this.inputField).height;
		else
			internalError("Getting the height of 'SPAN' elements not supported yet");
	}
	else
		return getVisibleSize(this.viewNode).height;
});
DisplayNode.prototype.addSetter('<Height>', function(height)
{
	this.height = height;
	if (this.viewNode)
		this.viewNode.style.height = height;
});
DisplayNode.prototype.addGetter('<Col Span>', function()
{
	if (this.viewNode && this.viewNode.parentNode && this.viewNode.parentNode.colSpan)
		return this.viewNode.parentNode.colSpan;
	else
		return this.colSpan;
});
DisplayNode.prototype.addSetter('<Col Span>', function(span)
{
	this.colSpan = span;
	if (this.viewNode && this.viewNode.parentNode && this.viewNode.parentNode.colSpan)
		this.viewNode.parentNode.colSpan = span;
});

DisplayNode.displayChildrenIterator = function (node,iteration)
{
	if (node && node.displayElements)
	{
		for (var i=0; i<node.displayElements.length; i++)
		{
			var e = node.displayElements[i];
			if ( e.isRepetitive)
			{
				var children  = e.getChildren(node);
				for (var j=0;i<children.length;j++)
				{
					var stop = iteration(children[j]);
					if (stop == true)
						return;
				}
			}
			else
			{
				var child = e.getChild(node);
				if (child)
				{
					var stop = iteration(child);
					if (stop == true)
						return;
				}
			}
		}
	}
	
};// file: 026-DataValue.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function DataValue() {};
DataValue.prototype = new tersus.Node();
DataValue.prototype.constructor = DataValue;
DataValue.prototype.isDataValue = true;
DataValue.prototype.sqlType = 'NONE';
DataValue.prototype.toString = function toString()
{
	if (this.leafValue)
	{
		return ''+this.leafValue;
	}
	else
		return 'Composite Value: '+this.modelId;
};
DataValue.prototype.formatString = function (props)
{
	return this.toString();
};
DataValue.prototype.formatInput = function (props)
{
	return this.formatString(props);
};
DataValue.prototype.parseInput = function()
{
	internalError("parseInput not implemented for "+this.constructor.name);
};
DataValue.prototype.addDataElement = function addDataElement(role,modelId)
{
	var element;
	var getter = this.getGetter(role);
	if (getter)
		element = new MethodElement(this, role, modelId);
	else
		element = new DataElement(role, modelId);
	return this.addElement(element);
};

// file: 026-ServiceNode.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 

//Service Node

function ServiceNode() {};
ServiceNode.prototype = new FlowNode();
ServiceNode.prototype.constructor = ServiceNode;
ServiceNode.prototype.type = 'Service';
ServiceNode.prototype.excludedTriggers=new Set(['<URL>']);
ServiceNode.prototype.start = function startService()
{	
	this.pause();
	this.callService();
};
ServiceNode.prototype.started = function serviceStarted()
{
	this.setStatus(FlowStatus.STARTED);
	if (window.trace)
	{
		window.trace.invoked(this);
		window.trace.flush();
	}
};
ServiceNode.prototype.isService = true;
/*
	Invokes a service that contains file arguments.
	This is a special case for the following reasons:
	(1) We must use the orginial "File Input Node" to send the file 
	(2) For this reason, we use the "Form" node that is already part of the document
	(3) We need to use "form/multipart" encoding
	
	
	In this case, we can't create a separate form, 
	because there is no way to copy the FileInput node's content to another
	file input node (it is possible in Mozilla, but not in IE)
	
	Using XMLHTTPRequest is out of the question because JavaScript can't read
	local files.
*/

ServiceNode.prototype.callService = function  callService()
{
	if (navigator.onLine == false)
	{
		var host = document.domain;
		var url = this.getLeafChild('<URL>');
		if (url)
			host = url.match(/\/\/([^:/]+)[:/]/)[1];
		if (host != 'localhost' && host != '127.0.0.1' && host != '0:0:0:0:0:0:0:1%0')
		{
			tersus.error("Offline - can't access server");
			this.handleResponse({});
			return;
		}
	}
	if (tlog)
		tlog("Calling service:"+this.modelName);
	if (this.findFileTrigger() || !tersus.useXMLHTTPRequest) 
		this.callFileService();
	else
		this.callRegularService();
};
ServiceNode.prototype.cancellable = true;
ServiceNode.prototype.getCancellationFunc = function getCancellationFunc()
{
	if (this.cancellable == 'false' || !this.cancellable)
		return null;
	var serviceNode = this;
	var cancellation = function () { 
			tersus.progress.set('Request cancelled.');
			serviceNode.cancel();
			};
	return cancellation;
};
ServiceNode.prototype.cancel = function cancel()
{
	if (this.responseReceived)
		return;
	this.abort();
	if (this.responseReceived)
		return;
	this.handleResponse({});
	this.cancelled = true;
};
ServiceNode.prototype.abort = function abort()
{
	var req = createXMLHTTPRequest();
	var serviceNode = this;
	var url = tersus.rootURL+'Abort';
	req.open('POST', url, true);
	req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	req.send('_userRequestId='+window.encodeURIComponent(this.getNodeId()));
};
ServiceNode.prototype.setProgressMessage = function()
{
	if (tersus.progress.active)
	{
		var message = null;
		if (this.progressMessage && this.progressMessage != ' ')
			message = this.progressMessage;
		else if (tersus.progressMessage)
			message = tersus.progressMessage;
		else
			message = 'Service: '+this.modelName;
		tersus.progress.set(message, this.getCancellationFunc());
	}
};
ServiceNode.prototype.callRegularService = function getService()
{
	var url = this.getLeafChild('<URL>');
	var paramString = this.getParamString(url);
	if (!url)
		var url = tersus.rootURL+'Service';
	this.nodesToRemove = [];
	
	// We wrap the call to XMLHTTPRequest in setTimeout to avoid a firefox bug:
	// see http://www.highdots.com/forums/javascript/xmlhttprequest-firefox-problem-577724.html
	// However, we suppress this behavior if we're inside 'onUnload' (or the service will never be invoked)
	var serviceNode = this;
	var f = function() {
		serviceNode.setProgressMessage();
		serviceNode.callXMLHTTPService(url, paramString);
	};
	if (tersus.isUnloading)
		f();
	else
		tersus.async.exec(f, false/* don't wait */);
};

ServiceNode.prototype.callXMLHTTPService = function callXMLHTTPService(url, paramString)
{
	var req = createXMLHTTPRequest();
	var serviceNode = this;
	if (! tersus.isUnloading) // If we're unloading we won't be able to process the response
	{
		req.onreadystatechange= function(){
			ServiceNode.handleXMLHTTPResponse(req, url, serviceNode);
		};
	}
	req.open('POST', url, true);
	req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	req.send(paramString);
};
ServiceNode.dummy = function () {};
ServiceNode.handleXMLHTTPResponse = function(req, url, serviceNode)
{
	if (serviceNode.cancelled)
		return;
	if (req.readyState != 4)
		return;
	req.onreadystatechange = ServiceNode.dummy;
	var status  = 'Error';
	var message = 'Unknown';
	try
	{
		status = req.status;
		message = req.statusText;
	}
	catch (e)
	{
	}
	 
	if (status != 200)
	{
		alert('Failed to execute service (url='+url+',status='+status+',message='+message+')');
		setTimeout(function() {serviceNode.handleResponse({});},0);
		return;
	}

	if (tersus.progress.active)
		tersus.progress.set('Processing service response ...');
	var responseText = req.responseText;
	
	/* If there is a sizeable response, we expect processing to take significant time
	   (during which there is no opportunity for the progress bar to appear, so we make
	   force progress bar to be visible  */
//	if (responseText.length > tersus.progress.responseLengthThreshold)
//		tersus.progress.show();
	setTimeout( function()
		{
			var exitValues = eval("var output = "+responseText+";output;");
			if (exitValues._ERROR)
			{
				alert(exitValues._ERROR);
				serviceNode.handleResponse({});
			}
			else
				serviceNode.handleResponse(exitValues);
		},0);
};

	
ServiceNode.prototype.getParamString = function(url)
{
	var location = new tersus.RuntimeLocation(this);
	var serializer = new Serializer();
	if (!url)
	{
		var paramString = "_baseModelId="+encodeURIComponent(location.baseModelId);
		paramString += "&_path="+encodeURIComponent(location.path.str);
		paramString+='&_userRequestId='+this.getNodeId();
	}
	else
	{
		var paramString = '_output=json';
	}
	if (window.trace)
	{
		paramString+='&_traceFileName='+encodeURIComponent(this.getTraceFileName());
	}	
	if (this.triggers)
	{
		for (var i=0; i< this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			var paramName = trigger.role;
			var paramValue = null;
			if (trigger.isRepetitive)
			{
				var values = trigger.getChildren(this);
				if (values.length > 0)
				{
					paramValue = serializer.serialize(values); 
				}
			}
			else
			{
				var value = trigger.getChild(this);
				if (value != null)
				{
					if (value.isLeaf)
						paramValue = value.serialize ? value.serialize() : value.leafValue;
					else
						paramValue = serializer.serialize(value);
				}
			}
			if (paramValue != null)
			{	
				if (paramString.length > 0)
					paramString+= '&';
				paramString += encodeURIComponent(paramName);
				paramString += '=';
				paramString += encodeURIComponent(paramValue);
			}
		}
	}
	return paramString;
};
ServiceNode.prototype.callFileService = function callFileService()
{
	var form = this.prepareForm(new Set(['<URL>']));
	if ( ! form)
	{
		this.resumeAfterPause();
		var executionContext = this.getExecutionContext();
		executionContext.resume();
		return;
	};
	this.addTersusParameters(form);
	
	var iframe = this.getResponseFrame();
	
	form.action = tersus.rootURL+'Service';
	form.method = 'POST';
	form.target  = iframe.name;
	this.callbackName = iframe.name;
	var serviceNode = this;
	this.mainWindow[this.callbackName] = function callback(exitValues)
	{
		serviceNode.mainWindow[serviceNode.callbackName] = null;
		if (serviceNode.cancelled)
			return;
		tersus.progress.set('Processing service response ...');
		setTimeout( function()
		{
			if (exitValues._ERROR)
			{
				alert(exitValues._ERROR);
				serviceNode.handleResponse({});
			}
			else
				serviceNode.handleResponse(exitValues);
		},0);
	};
	var callbackField = addHiddenField(form, '_js_callback', 'parent.'+iframe.name);
	form.appendChild(callbackField);
	this.nodesToRemove.push(callbackField);
	if (tersus.IFRAME_SERVICE_TIMEOUT)
	{
		setTimeout(function (){
			if (!serviceNode.responseReceived)
			{
				serviceNode.currentWindow.alert('Server Error: Timeout');
				serviceNode.cancel();
			}
		}
		,tersus.IFRAME_SERVICE_TIMEOUT);
	};
	try
	{
		var nodeId = this.getNodeId();
		if (!tersus.pendingServiceCalls)
			tersus.pendingServiceCalls = new Set([nodeId]);
		else
			tersus.pendingServiceCalls.add(nodeId);
		form.submit();
		this.setProgressMessage();	
	}
	catch (e)
	{
		var msg;
		var fileTrigger = this.findFileTrigger();
		var fileName = this.getChild(fileTrigger.role).getFileName();
		if (e.name=='TypeError') // This happens in IE when a user types an invalid file name
			msg = 'Please check the file name "'+fileName + '"';
		else
			msg = 'An error occurred when invoke the service ('+e.message+').';
		alert(msg);
		this.resumeAfterPause();
		var executionContext = this.getExecutionContext();
		executionContext.resume();
	}
	for (var i=0; i< this.nodesToRemove.length; i++)
	{
		var node = this.nodesToRemove[i];
		node.parentNode.removeChild(node);
	}
};
ServiceNode.prototype.prepareForm = function prepareForm()
{
	var serializer = new Serializer();
	var form;
	var fileTrigger = this.findFileTrigger();
	this.nodesToRemove = [];
	
	if (fileTrigger)
	{
		var fileInputDisplayNode = this.getChild(fileTrigger.role).inputFieldDisplayNode;
		if ( fileInputDisplayNode.currentWindow.closed)
		{
			alert('Tersus Application Error: Reference to a file input field in closed popup window.\n');
			return null;
		}
		
		form = fileInputDisplayNode.viewNode;
		setEncType(form,'multipart/form-data'); 
		var fileInputNode = fileInputDisplayNode.fileNode;
		fileInputNode.name = fileTrigger.role;
	}
	else
	{
		form = this.mainWindow.document.createElement('form');
		if (! window.showServiceInvocations)
		{
			this.nodesToRemove.push(form);
		}
		this.mainWindow.document.body.appendChild(form);
	}

	if (this.triggers)
	{
		for (var i=0; i< this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			if (this.excludedTriggers .contains(trigger.role))
				continue;
			if (trigger != fileTrigger) // If fileTrigger is non-null, it is already part of the form
			{
				if (trigger.isRepetitive)
				{
					var values = trigger.getChildren(this);
					if (values.length > 0)
					{
						var serialization = serializer.serialize(values); 
						var inputField = form.ownerDocument.createElement('input');
						inputField.type = 'text';
						inputField.name = trigger.role;
						inputField.size = serialization.length;
						inputField.value = serialization;
						form.appendChild(inputField);
						if (fileTrigger)
							this.nodesToRemove.push(inputField);
					}
				}
				else
				{
					var value = trigger.getChild(this);
					if (value != null)
					{
						var serialization = serializer.serialize(value);
						var inputField = form.ownerDocument.createElement('input');
						inputField.type = 'text';
						inputField.name = trigger.role;
						inputField.size = serialization.length;
						inputField.value = serialization;
						form.appendChild(inputField);
						if (fileTrigger)
							this.nodesToRemove.push(inputField);
					}
				}	
			}
		}
	}	
	return form;
};

ServiceNode.prototype.addTersusParameters = function(form)
{
	var location = new tersus.RuntimeLocation(this);
	var baseModelIdField = addHiddenField(form, '_baseModelId', location.baseModelId);
	form.appendChild(baseModelIdField);
	this.nodesToRemove.push(baseModelIdField);
	var pathField = addHiddenField(form, '_path', location.path.str);
	form.appendChild(pathField);
	this.nodesToRemove.push(pathField);
	if (window.trace)
	{
		window.trace.flush();
		var traceFileField = addHiddenField(form, '_traceFileName', this.getTraceFileName());
		form.appendChild(traceFileField);
		var requestIdField = addHiddenField(form, '_userRequestId', this.getNodeId());
		form.appendChild(traceFileField);
		this.nodesToRemove.push(traceFileField);
		this.nodesToRemove.push(requestIdField);
	}
};
ServiceNode.prototype.getTraceFileName = function()
{
	return window.trace.filename;
};
ServiceNode.prototype.handleResponse = function handleResponse(response)
{
	if (tlog) tlog('Processing response for service: '+	this.modelName);
	if (tersus.pendingServiceCalls)
		tersus.pendingServiceCalls.remove(this.getNodeId());
	var start = new Date();
	this.responseReceived = true;
	if (window.trace)
		window.trace.responded(this);
		
	for (var exitRole in response)
	{
        var exit = this.getElement(exitRole);
        if (!exit)
        	continue; // It's possible that the exit is missing because of permission issues
        if (exit.isRepetitive)
        {
        	var values = response[exitRole];
        	for (var i=0; i< values.length; i++)
        	{
        		var dataValue  = exit.createChild(this);
        	    dataValue.copyObject(values[i]);
        	}
        }
        else
        {
        	var value = response[exitRole];
        	var dataValue  = exit.createChild(this);
       	    dataValue.copyObject(value);
        }
        			
	};
	if (this.status != FlowStatus.PAUSED)
		debugMessage('Unexpected status "'+this.status+'" for ' + this.getPath());
	this.resumeAfterPause();
	var executionContext = this.getExecutionContext();
	executionContext.resume();
	if (window.trace)
		window.trace.flush();
	var end = new Date();
	window.duration = "Response processed in " + (end - start) + " ms";
	
};

ServiceNode.prototype.resume = function resume()
{
	this.setStatus(FlowStatus.DONE);
};
/* Creates an iframe for invoking the service */

ServiceNode.prototype.getResponseFrame = function getResponseFrame()
{
	var iframe = tersus.nextServiceResponseFrame();
	this.iframeId =iframe.id;
	return iframe;
};
/*
	returns the unique trigger that holds a 'File Input' value
	If there is no such trigger, returns null.
	If there is more than one trigger, an error is reported.
*/
ServiceNode.prototype.findFileTrigger = function findFileTrigger()
{
	var fileTrigger = null;
	if (this.triggers)
	{
		for (var i=0; i<this.triggers.length; i++)
		{
			//TODO consider using the modelId of the trigger to identify the file
			var trigger = this.triggers[i];
			if (trigger.isRepetitive)
				continue;
			var child = this.getChild(trigger.role); 
			if (child && child.isFile)
			{
				if (fileTrigger)
				{
					modelError("Too many file input values");
					return null;
				}
				else
					fileTrigger = trigger;
			}
		}
	}
	return fileTrigger;
};
// file: 030-DataElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function DataElement(role, modelId)
{
	this.role = role;
	if (modelId)
		this.modelId = modelId;
};
DataElement.prototype = new Element();
DataElement.prototype.constructor = DataElement;
DataElement.prototype.type = 'Data Element';
DataElement.prototype.isDataElement = true;// file: 031-SubFlow.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function SubFlow(role, modelId)
{
	this.role = role;
	this.modelId = modelId;
};
SubFlow.prototype = new Element();
SubFlow.prototype.constructor = SubFlow;
SubFlow.prototype.isSubFlow = true;
SubFlow.prototype.createChild = function createChild(parent, modelId)
{
	debugAssertion(modelId == null, "Expecting SubFlow.createChild to always receive null modelId");
	var child = this.createChildInstance(modelId);
	child.mainWindow = parent.mainWindow;
	child.currentWindow = parent.currentWindow;
	child.parent = parent;
	child.element = this;
	if (child.initialize)
		child.initialize();
	return child;
};
SubFlow.prototype.init = function SubFlow_init(parent)
{
	if (! this.isRepetitive && ! tersus.Conventions.isEventHandler(this))
	{
		var child = this.createChild(parent);
		this.addChild(parent, child);
		child.setInitialStatus();
	}
};// file: 032-DisplayElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function DisplayElement(role, modelId)
{
	this.role = role;
	this.modelId = modelId;
}
DisplayElement.prototype = new SubFlow();
DisplayElement.prototype.constructor = DisplayElement;
DisplayElement.prototype.isDisplayElement = true;
DisplayElement.prototype.type = 'Display Element';
DisplayElement.prototype.addAChild = function addChild(parent, value)
{
	if (parent.currentWindow)
	{
		this.createChild(parent, value.modelId, value);
	}
	else
	{
		Element.prototype.addAChild.call(this, parent, value);
	}
};

DisplayElement.prototype.replaceChild = function replaceChild(parent, value, reset)
{
	if (parent.currentWindow) // parent is a real display node
	{
		var oldChild = this.getChild(parent);
		if (oldChild)
		{
			if (oldChild.modelId == value.modelId)
			{
				if (reset)
					oldChild.reset();
				child = oldChild;
				child.copyValue(value);
			}
			else
			{
				var oldViewNode = null;
				if (oldChild != null)
				{
					var placeHolder = oldChild.wrapperNode ? oldChild.wrapperNode: oldChild.viewNode;
					oldChild.viewNode = null;
					placeHolder.style.display = 'none';
					this.removeChild(parent);
				}
				child = this.createChild(parent,value.modelId, value, placeHolder);
			}
		}
		else
			child = this.createChild(parent,value.modelId, value);
	}
	else
	{
		Element.prototype.replaceChild.call(this, parent, value);
	}
}
DisplayElement.prototype.moveChild = function (parent, fromIndex, toIndex)
{
	var children = this.getChildren(parent);
	var currentChild = null;
	if (children.length > 0)
		currentChild = children[toIndex];
		
	var child = Element.prototype.moveChild.call(this,parent,fromIndex,toIndex);
	if (child.viewNode && currentChild)
	{
		// Move the new child before the current child
		child.viewNode.parentNode.insertBefore(child.viewNode, currentChild.viewNode);
	}
	return child;
};


// As opposed to regular SubFlows, DisplayElements are added to the parent node
DisplayElement.prototype.createChildWithoutVisuals = function createChildWithoutVisuals(parent, modelId)
{
	var child = SubFlow.prototype.createChild.call(this, parent, modelId);
	this.addChild(parent, child);
	if (parent.currentWindow && ! child.isPopup)
	{
		child.setInitialStatus();
	}
	return child;
};
DisplayElement.prototype.createChild = function createChild(parent, modelId, value, placeHolderNode)
{
	var child = this.createChildWithoutVisuals(parent,modelId);
	if (parent.currentWindow && ! child.isPopup)
	{
		child.placeHolderNode = placeHolderNode;
		child.create(value);
	}
	return child;
};
DisplayElement.prototype.init = function DisplayElement_init(parent)
{
	// There is no need to initialize display elements, as the whole  hierarchy is created in advance
	// Except for popups (which are more like regular subflows)
	// TODO clean this up (the generic DisplayElement should not know about popups)
	if (tersus.repository.get(this.modelId).prototype.isPopup)
	{
		SubFlow.prototype.init.call(this,parent);
	}
	
};

DisplayElement.prototype.prop = function(name)
{
	
	 var local = this.properties[name];
	 if (local != null)
	 	return local;
	 var childConstructor = this.getChildConstructor();
	 if (!childConstructor)
	 	return null;
	 return childConstructor.prototype.sharedProperties[name];
};
// file: 033-Trigger.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Trigger(role, modelId)
{
	this.role = role;
	if (modelId)
		this.modelId = modelId;
};
Trigger.prototype = new Element();
Trigger.prototype.constructor = Trigger;
Trigger.prototype.type='Trigger';

Trigger.prototype.replaceChild = function(parent, value)
{
	if (parent.isInputSet) // Special case: trigger of a repetitive sub-process - we accumulate the value
	{
		if (! parent.children[this.role])
			parent.children[this.role] = [];
		parent.children[this.role].push(child);
		
	}
	else
		Element.prototype.replaceChild.call(this, parent, value);
};
Trigger.prototype.removeChildren = function(parent)
{
	makeAssertion( this.isRepetitive);
	if (parent.children)
		parent.children[this.role] = [];
};// file: 034-Exit.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Exit(role, modelId)
{
	this.role = role;
	if (modelId)
		this.modelId = modelId;
};
Exit.prototype = new Element();
Exit.prototype.constructor = Exit;
Exit.prototype.isExit=true;
Exit.prototype.type='Exit';// file: 035-FlowDataElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function FlowDataElement(role, modelId)
{
	this.role = role;
	if (modelId)
		this.modelId = modelId;
};
FlowDataElement.prototype = new Element();
FlowDataElement.prototype.isFlowDataElement = true;
FlowDataElement.prototype.constructor = FlowDataElement;
FlowDataElement.prototype.type = 'Data Element';
FlowDataElement.prototype.createChild = function createChild(parent, modelId)
{
	var dataValue = this.createChildInstance(modelId);
	return parent.createReference(this, dataValue);
};
	
FlowDataElement.prototype.replaceChild = function replaceChild(parent, value)
{
	var oldValue;
	if (parent.hasElementChangeHandler)
		oldValue = this.getChild(parent);
	parent.createReference(this, value);
	if (parent.hasElementChangeHandler)
	{
		if (oldValue && oldValue.isDataNode)
			oldValue = oldValue.value;
		if (oldValue != value)
		{
			// handle the case of different leaf instances with same leaf value
			if (oldValue == null || value == null || !oldValue.isLeaf || ! value.isLeaf || (oldValue.leafValue != value.leafValue && ! (oldValue.leafValue != null && oldValue.leafValue.equals && oldValue.leafValue.equals(value.leafValue))))
				parent.handleElementChange(this.role, oldValue, value);
		}
	}
};
FlowDataElement.prototype.addAChild = function addAChild(parent, value)
{
	var reference = parent.createReference(this,value);
}
// file: 036-InputSet.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function InputSet(parent, subFlow)
{
	this.parent = parent;
	this.subFlow=subFlow;
	this.element=subFlow;
	this.childConstructor = tersus.repository.get(subFlow.modelId);
	this.triggers = this.childConstructor.prototype.triggers;
	this.setStatus(FlowStatus.NOT_READY_TO_START);
	
};
InputSet.prototype = new FlowNode();
InputSet.prototype.constructor = InputSet;
InputSet.prototype.invoke = function ()
{
	this.explode();
};
InputSet.prototype.createInstance = function()
{
	var instance =  this.subFlow.createChild(this.parent);
	instance.setStatus(FlowStatus.NOT_READY_TO_START);
	return instance;
};
InputSet.prototype.explode = function ()
{
	var instances = [];
	instances.push(this.createInstance()); 
	for (var i=0; i<this.triggers.length; i++)
	{
		var trigger = this.triggers[i];
		var values = this.children[trigger.role];
		var nPrototypes = instances.length;
		for (var j=0; j<nPrototypes; j++)
		{
			//TODO handle the case of repetitive triggers (no cartesian product is needed)
			var prototypeInstance = instances[j];
			if (values)
			{
				for (var k=0; k<values.length; k++)
				{
					var value = values[k];
					if (k==0)
					{
						trigger.replaceChild(prototypeInstance, value);
					}
					else
					{
						var newInstance = this.createInstance();
						for (var l=0; l<i; l++)
						{
							// copy values of preceding triggers
							var previousTrigger = this.triggers[l];
							previousTrigger.replaceChild(newInstance, previousTrigger.getChild(prototypeInstance));
						}
						// set current value
						trigger.replaceChild(newInstance, value);
						instances.push(newInstance);
					}
				}
			}	
		}
	}
	for (var i=0; i<instances.length; i++)
		instances[i].checkReady();
};
InputSet.prototype.addValue = function (role, value)
{
	if (! this.children)
		this.children = {};
	if (! this.children[role])
		this.children[role]= [];
	this.children[role].push(value);
};// file: 037-Link.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Link(role, source, target)
{	
	this.role = role;
	this.source = new Path(source);
	this.target = new Path(target);
};
Link.prototype.type= 'Flow';
Link.prototype.invoke = function invoke(sourceNode)
{
	var values;
	var parent = sourceNode.parent;
	// get source value
	values = sourceNode.getValues(this.source, 1);
	var targetElement = parent.getElement(this.target.segments[0]);
	if (! targetElement)
		return; // The target element may be null if acccess control excluded it from the user's application
	if (window.trace && values.length > 0)
			window.trace.flow(this, parent, values.length + " values");
	for (var i=0; i<values.length; i++)
	{
		var value = values[i];
		
		if (this.isConstantTrigger)
		{
			var constantElement = targetElement;
			constantElement.createChild(parent);
		}
		else
		{
			if (window.trace)
			{
				window.trace.flowValue(this, parent, value);
			}
			if (targetElement.isSubFlow && targetElement.isRepetitive)
			{
				var inputSet = parent.children[targetElement.role];
				if (!inputSet)
				{
					inputSet = new InputSet(parent, targetElement);
					parent.children[targetElement.role] = inputSet;
				}
				makeAssertion(this.target.segments.length == 2);
				var triggerRole = this.target.segments[1];
				inputSet.addValue(triggerRole, value);
				inputSet.checkReady();
			}
			else
			{
				// set target value
				sourceNode.parent.setValue(this.target, value, this.operation);
			
				if (! targetElement.isRepetitive)
				{
					var targetNode = targetElement.getChild(parent);
					if (targetNode && targetNode.checkReady)
						targetNode.checkReady();
				}
			}
		}
		
	}
};
// file: 038-MethodElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function MethodElement(owner, role, modelId)
{
	this.owner = owner;
	this.role = role;
	debugAssertion(modelId != null, "Expecting MethodElements to always have a model Id");
	if (modelId)
		this.modelId = modelId;
	else
		this.modelId = BuiltinModels.TEXT_ID; //TODO - remove this once we're sure that modelId is always given
	if (owner.getAdder(role)) // TODO - this should be a validation
		this.isRepetitive = true;
	else
		this.isRepetitive = false;
	
	if (! owner.getRemover(this.role))
		this.isRemovable = false;
};
MethodElement.prototype = new Element();
MethodElement.prototype.constructor = MethodElement;
MethodElement.prototype.type = 'Data Element';
MethodElement.prototype.isMethodElement = true;
MethodElement.prototype.replaceChild = function replaceChild(parent, value)
{
	if (parent.currentWindow) // parent is a real display node
	{
		var setter = parent.getSetter(this.role);
		if (setter == null)
			return;
		if (setter.requiresNodes)
			setter.call(parent, value);
		else
		{
			var  leafValue = value.leafValue;
			setter.call(parent, leafValue);
		}
	}
	else
		Element.prototype.replaceChild.call(this, parent,value);
	
};
MethodElement.prototype.addAChild = function addAChild(parent, value)
{
	if (parent.currentWindow) // parent is a real display node
	{
		var adder = parent.getAdder(this.role);
		if (adder.requiresNodes)
			adder.call(parent, value);
		else
		{
			var  leafValue = value.leafValue;
			adder.call(parent, leafValue);
		}
	}
	else
		Element.prototype.addAChild.call(this, parent,value);
	
};
MethodElement.prototype.removeChild = function removeChild(parent)
{
	if (parent.currentWindow) // parent is a real display node
	{
		var remover = parent.getRemover(this.role);
		if (remover)
			remover.call(parent);
	}
	else
		Element.prototype.removeChild.call(this, parent);
};

MethodElement.prototype.getChild = function getChild(parent)
{
	if (parent.currentWindow || parent.isDataValue) // parent is a real display node or a DataValue
	{
		var getter = parent.getGetter(this.role);
		var value = getter.call(parent);
		if (value || value == 0 || value == '')
		{
			if (value.isNode)
				return value;
			else
			{
				//This is a primitive value - wrap it as a DataValue
				var dataValue = this.createChildInstance();
				dataValue.setLeaf(value);
				return dataValue;
			}
		}
		else
		return null;
	}
	else // parent is a 'temporary' display-data node
	{
		return Element.prototype.getChild.call(this, parent);
	}
};

MethodElement.prototype.getChildren = function getChildren(parent)
{
	if (parent.currentWindow || parent.isDataValue) // parent is a real display node
	{
		var getter = parent.getGetter(this.role);
		var values = getter.call(parent);
		if (values.length > 0 && ! values[0].isNode) // The getter returned raw(leaf) values, not nodes
		{
			var leafValues = values
			values = [];
			if (leafValues.length)
			{
				for (var i=0; i<leafValues.length; i++)
				{
					var leafValue = leafValues[i];
					if (leafValue || leafValue == 0 || leafValue == '')
					{
						var dataValue = this.createChildInstance();
						dataValue.setLeaf(leafValue);
						values.push(dataValue);
					}
				}
			}
		}
		return values;
	}
	else // parent is a 'temporary' display-data node
	{
		return Element.prototype.getChildren.call(this, parent);
	}
	
};
MethodElement.prototype.removeChildren = function removeChildren(parent)
{
	if (parent.currentWindow) // parent is a real display node
	{
		var remover = parent.getRemover(this.role);
		remover.call(parent);
	}
	else // parent is a 'temporary' display-data node
	{
		Element.prototype.removeChildren.call(this, parent);
	}
		
};

// file: 040-DataTypes.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 DATE_FORMAT='mmmm dd yyyy';
if (! tersus) tersus = {};
tersus.DECIMAL_POINT='.';
tersus.THOUSANDS_SEPARATOR=',';
if (! tersus.Messages) tersus.Messages = {};
tersus.Messages.INVALID_NUMBER = 'Please type a valid number';
tersus.Messages.INVALID_DATE = 'Please type a valid date in format '+DATE_FORMAT;

tersus.Nothing = function tersus_Nothing() {};
tersus.Nothing.prototype = new DataValue();
tersus.Nothing.prototype.constructor = tersus.Nothing;
tersus.Nothing.prototype.pluginFunc = tersus.Nothing;
tersus.Nothing.prototype.isLeaf = true;
tersus.Nothing.prototype.isNothing = true;
tersus.Nothing.prototype.toString = function toString()
{
	return '<Nothing>';
}

tersus.Nothing.prototype.isInstance = function(value)
{
	return value != null && value.isNothing;
};

tersus.Text = function tersus_Text() {};
tersus.Text.prototype = new DataValue();
tersus.Text.prototype.constructor = tersus.Text;
tersus.Text.prototype.isLeaf = true;
tersus.Text.prototype.pluginFunc = tersus.Text;
tersus.Text.prototype.isText = true;
tersus.Text.prototype.sqlType = 'TEXT';
tersus.Text.prototype.parseInput = function tersus_Text_parseInput(str)
{
	if (str == '')
		return null;
	
	var constructor = this.constructor;
	var text = new constructor();
	text.leafValue = str.replace (/\r/g,'');
	return text;
};
tersus.Text.prototype.isInstance = function(value)
{
	return value != null && value.isText;
};
tersus.Text.prototype.formatString = function tersus_Text_formatString(properties)
{
	if (this.leafValue == null)
		return '';
	var s = this.leafValue.toString();
	return s;
};
tersus.Text.prototype.formatInput = function tersus_Text_formatInput(properties)
{
	if (this.leafValue == null)
		return '';
	var s = this.leafValue.toString();
	return s;
};
tersus.Text.prototype.setLeaf = function(value)
{
	if (value == null)
		this.leafValue == null;
	else this.leafValue = ''+value;
};
tersus.notEmpty = function (value)
{
	return value != null && value != undefined && value != ' ';
};
tersus.isNumber = function tersus_isNumber(value)
{
	if (value == null)
		return false;
	var str = value.toString();
	var re = /^\s*[-+]?(\d+(\.\d*)?|(\.\d+))([eE][-+]?\d+)?\s*$/;
	return str.match(re);
};
tersus.isNumberWithSeparators = function tersus_isNumber(value)
{
	if (value == null)
		return false;
	var str = value.toString();
	var reStr = '^[-]?((\\d{1,3}(['+tersus.THOUSANDS_SEPARATOR+']\\d{3})*)|\\d*)(['+tersus.DECIMAL_POINT+']\\d*)?$';
	var re = new RegExp(reStr);
	return str.match(re);
};

tersus.Number = function tersus_Number() {};
tersus.Number.prototype = new DataValue();
tersus.Number.prototype.constructor = tersus.Number;
tersus.Number.prototype.isLeaf = true;
tersus.Number.prototype.sqlType = 'NUMERIC';
tersus.Number.prototype.pluginFunc = tersus.Number;
tersus.Number.prototype.isNumber = true;
tersus.Number.prototype.isInstance = function(value)
{
	return value != null && value.isNumber;
};
tersus.Number.prototype.parseInput = function(s, props) 
{
	if (s != null)
	{
		s = s.replace(new RegExp('['+tersus.THOUSANDS_SEPARATOR+']','g'),'');
		s = s.replace(new RegExp('['+tersus.DECIMAL_POINT+']','g'),'.');
		if (props.currencySymbol)
			s = s.replace(props.currencySymbol, '');
	}
	if (s == null || s == '')
		return null;
	var x = parseFloat(s);
	if (isNaN(x))
		return null;
	var number = new (this.constructor)();
	number.leafValue = x;
	return number;
};

tersus.Number.prototype.toString = function()
{
	if (this.leafValue == null || this.leafValue == undefined)
		return null;
	else
		return this.leafValue.toString();
}
tersus.Number.prototype.setLeafStr = function (s)
{
	this.leafValue = parseFloat(s);
};

tersus.Number.prototype.validateInput = function (s, props)
{
	if ( s == null || s == '')
		return null;
	if (props.currencySymbol)
		s = s.replace(props.currencySymbol,'');
	
	
	if (tersus.isNumberWithSeparators(s))
		return null;
	else
		return tersus.Messages.INVALID_NUMBER;
};
tersus.Number.prototype.formatInput = function tersus_Number_formatInput(props)
{
	return this.formatString(props);
};
tersus.Number.prototype.formatString = function tersus_Number_formatString(props)
{
//	return ''+this.leafValue;
	var formatter = new NumberFormat();
	if (props)
	{
		if (tersus.isNumber(props.decimalPlaces))
			formatter.setPlaces(props.decimalPlaces);
		var useSeparators =  (true == props.useThousandsSeparator);
		formatter.setSeparators(useSeparators, tersus.THOUSANDS_SEPARATOR, tersus.DECIMAL_POINT);
		if (props.currencySymbol && props.currencySymbol != ' ')
		{
			formatter.setCurrencyValue(props.currencySymbol);
			formatter.setCurrency(true);
		}
		if (props.currencyPosition && NumberFormat.prototype[props.currencyPosition])
			formatter.setCurrencyPosition(NumberFormat.prototype[props.currencyPosition]);
	}
	formatter.setNumber(this.leafValue);
	if (props && props.showPercentage)
		return formatter.toPercentage();
	else
		return formatter.toFormatted();
	
	
};
tersus.Boolean = function tersus_Boolean() {};
tersus.Boolean.prototype = new DataValue();
tersus.Boolean.prototype.constructor = tersus.Boolean;
tersus.Boolean.prototype.isLeaf = true;
tersus.Boolean.prototype.pluginFunc = tersus.Boolean;
tersus.Boolean.prototype.YES_STR = 'Yes';
tersus.Boolean.prototype.TRUE_STR = 'true';
tersus.Boolean.prototype.NO_STR = 'No';
tersus.Boolean.prototype.leafValue = null;
tersus.Boolean.prototype.sqlType = 'CHAR(1)';
tersus.Boolean.prototype.setLeafStr = tersus.Boolean.prototype.setLeaf = function (v)
{
	if (v == null)
		this.leafValue = null;
	else if (v == true || v == this.YES_STR || v == this.TRUE_STR)
		this.leafValue = true;
	else
		this.leafValue = false;
};
tersus.Boolean.prototype.serialize = function ()
{
	if (this.leafValue == null)
		return 'null';
	else
		return this.leafValue? this.YES_STR: this.NO_STR;
		
};
tersus.Boolean.prototype.toString = tersus.Boolean.prototype.serialize;
tersus.Boolean.prototype.isBooleanValue = true;
tersus.Boolean.prototype.isInstance = function(value)
{
	return value != null && value.isBooleanValue;
};


tersus.DateValue = function tersus_DateValue(dateStr)
{
	if (dateStr)
	{
		var parts = dateStr.split('-');
		this.year = parseInt(parts[0],10);
		this.month = parseInt(parts[1],10);
		this.day = parseInt(parts[2],10);
	}
};
tersus.DateValue.prototype.formatString = function formatString()
{
	return formatDate(this.year, this.month, this.day, DATE_FORMAT);
}
tersus.DateValue.prototype.toString = function toString()
{
	var p2 = tersus.DateAndTime.pad2;
	return this.year+'-'+p2(this.month)+'-'+p2(this.day);
}
tersus.DateValue.prototype.isTersusDate = true;
tersus.DateValue.prototype.toLocalDate = function()
{
	var d= new Date(this.year, this.month-1,this.day);
	return d;
};

tersus.DateValue.prototype.equals = function (other)
{
	return other && other.isTersusDate && other.year == this.year && other.month == this.month && other.day == this.day;
};
function createDate(year, month, day)
{
	var date = new tersus.DateValue();
	date.year = year;
	date.month = month;
	date.day = day;
	return date;
};

tersus.Date = function tersus_Date() {};
tersus.Date.prototype = new DataValue();
tersus.Date.prototype.constructor = tersus.Date;
tersus.Date.prototype.isLeaf = true;
tersus.Date.prototype.sqlType = 'Date';
tersus.Date.prototype.pluginFunc = tersus.Date;
tersus.Date.prototype.isDate = true;
tersus.Date.prototype.isInstance = function(value)
{
	return value != null && value.isDate;
};
tersus.Date.prototype.setLeafStr = tersus.Date.prototype.setLeaf = function tersus_Date_setLeaf(value)
{
	if (value.isTersusDate)
		this.leafValue = value;
	else
		this.leafValue = new tersus.DateValue(value);
};

tersus.Date.prototype.getYear = function tersus_Date_getYear()
{
	if (this.leafValue)
		return this.leafValue.year;
	else
		return null;
};
tersus.Date.prototype.getMonth = function tersus_Date_getMonth()
{
	if (this.leafValue)
		return this.leafValue.month;
	else
		return null;
};
tersus.Date.prototype.getDay = function tersus_Date_getDay()
{
	if (this.leafValue)
		return this.leafValue.day;
	else
		return null;
};

tersus.Date.prototype.formatString = function(props)
{
	var dateFormat = null;
	if (props)
	{
		var dateFormat = props.dateFormat;
	}	
	if (! dateFormat)
		dateFormat = DATE_FORMAT;
	var date = this.leafValue;
	var s;
	if (date == null)
		s =  '';
	else if (date.isTersusDate)
		s=formatDate(date.year, date.month, date.day, dateFormat);
	else
		s = date.toString();
	return s;

};

Date.prototype.equals = function (other)
{
	return other.getTime && this.getTime() == other.getTime();
};

tersus.getDate = function(o)
{
	if (o && o.leafValue)
	{
		if (o.leafValue.isTersusDate)
			return o.leafValue.toLocalDate();
		else 
			return o.leafValue;
	}
		
};

tersus.Date.prototype.parseInput = function (str)
{
	if (str == null || str == '')
		return null;
	var d = parseDate(str, DATE_FORMAT);
	if (d == null)
		return null;
	var constructor = this.constructor;
	var node = new constructor();
	var date = new tersus.DateValue();
	date.year=d.y;
	date.month=d.m+1;
	date.day=d.d;
	node.leafValue=date;
	return node;
};

tersus.Date.prototype.validateInput = function (s, props)
{
	if ( s == null || s == '')
		return null;
	if (parseDate(s, DATE_FORMAT))
		return null;
	else
		return tersus.Messages.INVALID_DATE;
};

tersus.DateAndTime = function tersus_DateAndTime() {};
tersus.DateAndTime.prototype = new DataValue();
tersus.DateAndTime.prototype.constructor = tersus.DateAndTime;
tersus.DateAndTime.prototype.isLeaf = true;
tersus.DateAndTime.prototype.pluginFunc = tersus.DateAndTime;
tersus.DateAndTime.prototype.isDateAndTime = true;
tersus.DateAndTime.prototype.sqlType = 'Timestamp';
tersus.DateAndTime.prototype.isInstance = function(value)
{
	return value != null && value.isDateAndTime;
};
tersus.DateAndTime.prototype.formatString = function(props)
{
	var	dateFormat = DATE_FORMAT;
	var date = this.leafValue;
	var s;
	if (date == null)
		s =  '';
	else
	{
		s = formatDate(date.getFullYear(), date.getMonth()+1, date.getDate(), dateFormat);
		var p2 = tersus.DateAndTime.pad2;
		s += ' - '+p2(date.getHours())+':'+p2(date.getMinutes())+':'+p2(date.getSeconds());
	}
	return s;
};
tersus.DateAndTime.prototype.re = new RegExp("([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+)(:([0-9]+)(:([0-9]+))?)?");
tersus.DateAndTime.pad2 = function(value)
{
	if (value < 10)
		return '0'+value;
	else
		return value;
};
tersus.DateAndTime.pad3 = function(value)
{
	if (value < 10)
		return '00' + value;
	else if (value < 100)
		return '0' + value;
	else
		return value;
};
tersus.DateAndTime.prototype.setLeaf = tersus.DateAndTime.prototype.setLeafStr = function tersus_Date_setLeaf(value)
{
	if (value.constructor==Date)
		this.leafValue =value;
	else
	{
		var d = this.re.exec(value);
		if (d == null)
			internalError("Failed to parse date/time string '"+value+"'");
		var date =  this.leafValue = new Date(0);
		date.setUTCFullYear(d[1]);
		date.setUTCMonth(d[2]-1);
		date.setUTCDate(d[3]);
		date.setUTCHours(d[4]);
		date.setUTCMinutes(d[5]);
		if (d[7])
			date.setUTCSeconds(d[7]);
		if (d[9])
		date.setUTCMilliseconds(d[9]);
	};	
};
tersus.DateAndTime.prototype.serialize = function()
{
	var d = this.leafValue;
	var p2 = tersus.DateAndTime.pad2;
	var p3 = tersus.DateAndTime.pad3;
	return '"'+d.getUTCFullYear()+"-"+p2(d.getUTCMonth()+1)+"-"+p2(d.getUTCDate())+" "+p2(d.getUTCHours())+":"+p2(d.getUTCMinutes())+":"+p2(d.getUTCSeconds())+":"+p3(d.getUTCMilliseconds())+'"';
};

File = function File(ownerField)
{
	this.inputFieldDisplayNode = ownerField;
};
File.prototype = new DataValue();
File.prototype.constructor = File;
File.prototype.pluginFunc = File;

File.prototype.isFile = true;
File.prototype.getFileName = function getFileName()
{
	if (! this.inputFieldDisplayNode)
	{
		if (this.children && this.children['File Name'])
			return this.children['File Name'];
		else
			return null;
	}
	if ( this.inputFieldDisplayNode.currentWindow.closed)
	{
		alert('Tersus Application Error: Reference to a file input field in closed popup window.\n');
		return null;
	}
	if (! this.inputFieldDisplayNode.fileNode)
		return null;
	if (this.inputFieldDisplayNode.fileNode.value)
		return this.inputFieldDisplayNode.fileNode.value;
	else if (this.children)
		return this.children['File Name'];
	else
		return null;
	
};

File.prototype.addGetter('File Name',File.prototype.getFileName);
File.prototype.toString = function toString()
{
	return 'Input File '+ this.getFileName();
};// file: 050-serializer.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Serializer() {};
Serializer.prototype.DEBUG = false;
Serializer.prototype.Tokens = {};
Serializer.prototype.Tokens.START_OBJECT = '{';
Serializer.prototype.Tokens.END_OBJECT = '}';
Serializer.prototype.Tokens.START_ARRAY = '[';
Serializer.prototype.Tokens.END_ARRAY = ']';
Serializer.prototype.Tokens.OBJECT_SEPARATOR = ',';
Serializer.prototype.Tokens.ARRAY_SEPARATOR = ',';
Serializer.prototype.Tokens.ASSIGN = ':';
Serializer.prototype.Tokens.QUOTE = '"';

Serializer.prototype.serialize = function serialize(value)
{
	var output = [];
	var stack = [];
	if (value.constructor == Array)
		this._serializeList(value, output, stack);
	else
		this._serializeValue(value, output, stack);
	var serialization = output.join('');
	return serialization;
};
Serializer.prototype._serializeList = function _serializeList(values, output, stack)
{
	output.push(this.Tokens.START_ARRAY);
	for (var i=0; i<values.length; i++)
	{
		if (i>0)
			output.push(this.Tokens.ARRAY_SEPARATOR);
		this._serializeValue(values[i], output, stack);
	};
	output.push(this.Tokens.END_ARRAY);
};
/*
 Serializes a value hierarchy into an output buffer
 value - the value to be serialized
 output - an array of strings/primitive values serving as the output buffer
*/
Serializer.prototype._serializeValue  = function _serializeValue(value, output, stack)
{
	if (value.isDataNode)
	{
		this._serializeValue(value.value, output, stack);
		return;
	};
	if (value.isNode)
	{
		for (var i=0;i<stack.length;i++)
		{
			var n = stack[i];
			if (n == value)
				return;
		}
	}
	stack.push(value);
	if (value.serialize)
	{
		output.push(value.serialize());
	}
	else if (value.isNothing)
	{
		output.push(this.Tokens.START_OBJECT);
		output.push(this.Tokens.END_OBJECT);
	}
	else if (value.isLeaf)
	{
		if (value.leafValue || (value.leafValue == 0) || (value.leafValue == '') )
			this._quote(value.leafValue, output);
		else
			output.push('null');
	}
	else
	{
		output.push(this.Tokens.START_OBJECT);
		var childCount = 0;
		if (value.elements)
		{
			for (var role in value.elements)
			{
				var element = value.elements[role];
				if (element.isAncestorReference)
					continue;
				if (element.isSubFlow && ! element.isDisplayElement)
					continue;
				if (element.isRepetitive)
				{
					var childValues = element.getChildren(value);
					if (childValues.length == 0)
						continue;
					if (childCount >0)
						output.push(this.Tokens.OBJECT_SEPARATOR);
					this._quote(element.role, output);
					output.push(this.Tokens.ASSIGN);
					this._serializeList(childValues, output, stack);
				}
				else
				{
					var childValue = element.getChild(value);
					if (! childValue)
						continue;
					if (childValue.isPopup)
						continue; // A pop is realy an action here, and it may be closed.  We don't want to serialize it
					if (childCount >0)
						output.push(this.Tokens.OBJECT_SEPARATOR);
					this._quote(element.role, output);
					output.push(this.Tokens.ASSIGN);
					this._serializeValue(childValue, output, stack);
				}
				childCount++;
			}
		}
		output.push(this.Tokens.END_OBJECT);
	}
	stack.pop();
};

Serializer.prototype._quote= function _quote(value, output)
{
	output.push(this.Tokens.QUOTE);
	var s = value.toString(); 
	var l = s.length;
	var escaped = "";
    for (var i = 0; i < l; i++)
    {
    	c = s.charAt(i);
    	switch (c)
    	{
      		case '\\':
				escaped += '\\\\';
                break;
      		case '\t':
				escaped += '\\t';
                break;
			case '\r':
				escaped += '\\r';
				break;
			case '\n':
				escaped += '\\n';
				break;
			case this.Tokens.QUOTE:
				escaped += "\\"+this.Tokens.QUOTE;
				break;
			default:
				escaped += c;
          }
	}
	//TODO complete escaping (use JSON http://www.crockford.com/JSON)
	
	output.push(escaped);
	output.push(this.Tokens.QUOTE);
};// file: 051-trace.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function startTrace(silent)
{
	closeTrace();
	
	window.trace = new Trace();
	window.trace.open(silent);
};
function showTrace()
{
	var traceWindow = window.open("","traceWindow");
	traceWindow.document.write('<textarea cols="120" rows="80">' + trace.buffer.join('') + '</textarea>');
	window.trace.window = traceWindow;
	setTimeout(function(){traceWindow.focus();}, 100);
};
function stopTrace(silent)
{
	if (!silent)
	{
		if (! window.trace)
			alert('Tracing not started');
		else
			alert("Trace file '"+window.trace.filename+"' closed.");
	}
	closeTrace();
};
function closeTrace()
{
	if (window.trace)
	{
		window.trace.flush();
		if (window.trace.window) window.trace.window.close();
	}
	deleteCookie(Trace.COOKIE_NAME);
	window.trace = null;
};

function initTrace()
{
	var file = getCookie(Trace.COOKIE_NAME);
	if (file)
	{
		alert('Using trace file ' + file);
		window.trace = new Trace();
		window.trace.filename=file;
	}
};
function Trace() 
{

	this.buffer = [];
	this.elementStack = [];
	this.indentation = '';
};
Trace.COOKIE_NAME='tersus_trace_file';
Trace.prototype.open = function(silent)
{
	this.filename = this.openTraceFile();
	setCookie(Trace.COOKIE_NAME, this.filename);	
	if (!silent)
		alert("Tracing started. The trace file is '"+this.filename +"'");
	
};
Trace.prototype.openTraceFile = function()
{
	var req = createXMLHTTPRequest();
	var url = tersus.rootURL+'/Trace/NewFile';
	req.open('GET', url, false);
	req.send(null);
	if (req.status != 200)
	{
		alert('Failed to create trace file');
		return null;
	}
	else
	{
		var filename=''+req.responseText;
		return filename;
	}
};
Trace.prototype.flush=function()
{
	if (this.buffer.length == 0)
		return;
	var prefix = "// Client side trace\n";
	var content = prefix + this.buffer.join('');
	this.buffer.splice(0, this.buffer.length); // remove all
	var url = tersus.rootURL+'/Trace/'+encodeURIComponent(this.filename);
	var req = createXMLHTTPRequest();
/*	req.onreadystatechange= function()
	{
		if (req.readyState == 4 && req.status != 200)
		{
			alert('Failed to write to trace file');
		}
		
	};
	req.open('POST', url, true);
	*/
	req.open('POST', url, false);
	req.send(content);
	if (req.readyState == 4 && req.status != 200)
	{
		alert('Failed to write to trace file');
	}
	
};
Trace.prototype.close = function()
{
	this.traceWindow.close();
};
Trace.prototype.STARTED= 'Started';
Trace.prototype.FINISHED= 'Finished';
Trace.prototype.WAITING= 'Waiting';
Trace.prototype.RESUMED= 'Resumed';
Trace.prototype.PAUSED = 'Paused';
Trace.prototype.RESPONDED = 'Responded';
Trace.prototype.INVOKED = 'Invoked';
Trace.prototype.VALUE = 'Value';
Trace.prototype.ACTIVATED = 'Activated';
Trace.prototype.SET = 'Set';
Trace.prototype.ACCUMULATED = 'Accumulated';
Trace.prototype.REMOVED = 'Removed';
Trace.prototype.CREATED = 'Created';
Trace.prototype.CLICKED = 'Clicked';

Trace.prototype.location = function (node, element, suffix)
{
	return new tersus.RuntimeLocation(node,element, suffix);
};
Trace.prototype.started = function(node) 
{
	if (node.isDisplayNode && ! node.isButton)
		return; // We don't really care about 'start' of display nodes
	this.trace(node.type, this.STARTED, this.location(node), this.getTriggerValues(node));
};
Trace.prototype.getTriggerValues = function(node)
{
	var details=[];
	var count = 0;
	if (node.triggers)
	{
		for (var i=0; i<node.triggers.length; i++)
		{
			var trigger = node.triggers[i];
			var serialization = null;
			if (trigger.isRepetitive)
			{
				var values  = trigger.getChildren(node);
				if (values.length > 0)
					serialiation = Serializer.prototype.serialize(values);
			}
			else
			{
				var value = trigger.getChild(node);
				if (value != null)
					serialization = Serializer.prototype.serialize(value);
			}
			if (serialization != null)
			{
				
				if (count>0)
				{
					details.push(',');
				}
				++count;
				details.push(trigger.role);
				details.push('=');
				details.push(serialization);
			}
		}
	}
	return details.join('');
};
Trace.prototype.resumed = function(node) 
{
	//No tracing for 'resumed' - nothing interesting here (?)
};
Trace.prototype.finished = function(node)
{
	this.trace(node.type, this.FINISHED, this.location(node));
};
Trace.prototype.waiting = function(node)
{
	//No tracing for 'waiting' - nothing interesting here (?)
};
Trace.prototype.charged = function(node, exit, value)
{
	var details = null;
	if (value != null)
	{
		details = Serializer.prototype.serialize(value);
	}
	var event = this.SET;
	if (exit.isRepetitive)
		event = this.ACCUMULATED;
	this.trace(exit.type, event, this.location(node,exit),details,null);
	
};

Trace.prototype.paused = function(node)
{
	//No tracing for 'pause' - we want the trace to simulate the synchronous behavior
};
Trace.prototype.flow = function(flow,parent, details)
{
	this.trace(flow.type, this.ACTIVATED, this.location(parent,flow), details);
};

Trace.prototype.flowValue = function(flow, parent, value)
{
	var lastElement = flow.target.getElement(parent);
	if (!lastElement)
		return;//This can happen when elements are excluded from the client-side model because of permissions
	var eventType = '?';
	if (flow.operation == Operation.REPLACE)
		eventType = this.SET;
	else if (flow.operation == Operation.REMOVE)
		eventType = this.REMOVED;
	else if (flow.operation == Operation.ADD)
		eventType = this.ACCUMULATED;
	var pp = this.location(parent).path.str;
	var displayPath = pp ? pp + "/"+flow.target : flow.target;
	this.trace(lastElement.type, eventType, this.location(parent,flow,"Value"),Serializer.prototype.serialize(value),null,displayPath);
};
Trace.prototype.link = function(flow, filename, comment)
{
	this.trace(null,this.LINK, this.location(flow), "'"+filename+"' - "+ comment);
};

Trace.prototype.invoked = function(node)
{
	var details = null;
	this.trace(node.type, this.INVOKED, this.location(node), this.getTriggerValues(node));
};

Trace.prototype.activated = function(node)
{
	this.trace(node.type, this.ACTIVATED, this.location(node.parent, node.element), Serializer.prototype.serialize(node.value));
}

Trace.prototype.responded = function(node)
{
	this.trace(node.type, this.RESPONDED, this.location(node));
};

Trace.prototype.trace = function(objectType, event, location, details, comment, displayPath)
{
	if (location && (location.baseModelId != this.lastBaseModelId || this.buffer.length==0) )
	{
		// We need to write out the base model id either if this is the first record or if the base model id changed
		this.buffer.push('@');
		this.buffer.push(location.baseModelId);
		this.buffer.push('\n');
		this.lastBaseModelId = location.baseModelId;
	}
	if (!objectType)
		objectType = "-";
	if (!details)
		details = "-";
	if (! comment)
		comment = "-";
	var path = location.path?location.path.str:null;
	if (! path)
		path = "-";
	if (!displayPath)
		displayPath = "-";
	var now=new Date();
	var time = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds());
	
	this.buffer.push(objectType,"\t",event,"\t",path,"\t",details,"\t",comment,"\t",displayPath,"\t",time,"\n");
};

Trace.prototype.event = function(node, event)
{
	if (event == Events.ON_CLICK)
	{
		var location = this.location(node);
		var displayPath = location.path.str;
		location.path = null; // We send a location with an empty path to 'force' the event to appear as a top level event
		this.trace(node.type,this.CLICKED,location,null/*details*/,null/*comment*/,displayPath); 
	}
};

initTrace();// file: 052-loader.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.PERSPECTIVE = 'Perspective';
tersus.VIEW = 'View';
tersus.preloadAll = true;
tersus.onResize = function()
{
	tersus.async.exec(tersus._onResize, false /* don't wait */);
};
tersus._onResize = function onResize()
{
	if (window.currentRootDisplayNode)
		window.currentRootDisplayNode.onResize();
};
function getPerspective(name)
{
	for (var i=0; i<window.perspectives.length; i++)
	{
		if (window.perspectives[i].name == name)
		{
			return window.perspectives[i];
		}
	}
	return null;
};
function getView(name)
{
	for (var i=0; i< window.perspective.views.length; i++)
	{
		var v = perspective.views[i];
		if (v.name == name)
		{
			return  v;
		}
	}
	return null;
};
tersus.setPerspectiveAndView = function()
{
	var perspectiveName = tersus.searchParams[tersus.PERSPECTIVE];
	var viewName = tersus.searchParams[tersus.VIEW];
	window.perspective = getPerspective(perspectiveName);
	if (!window.perspective)
		window.perspective = window.perspectives[0];
	window.view = getView(viewName);
	if (!window.view)
		window.view = window.perspective.views[0];
};
tersus.load = function load()
{
	if (tlog) tlog('load()');
	tersus.init();
	if (tlog) tlog('init() finished');
	tersus.progress.set('Loading application ...');
	if (tlog) 
		tlog ('tersus.lastTimestamp:'+tersus.lastTimestamp)
	if (!tersus.lastTimestamp)
		tersus.reloadView();
	else if (window.localStorage && tersus.useLocalStorage && navigator.onLine == false)
	{
		tersus.reloadView();
	}
	else
		tersus.getTimestamp(tersus.handleLoadTimestampResponse);
	if (tlog) tlog('load() returns');
	
};
tersus.handleLoadTimestampResponse = function()
{
	var req = tersus.getTimestampReq;
	if (tlog) tlog('Ready state:'+req.readyState);
	if (req.readyState != 4)
		return;
	if (tlog) tlog('Status:'+req.status);
		
	if (req.status == 200 || req.responseText)
	{
		var currentTimestamp = parseInt(req.responseText);
		tersus.setLastTimestamp(currentTimestamp);
		tersus.reloadView();
	}
	else if(req.status == 0 && window.localStorage && tersus.useLocalStorage)
	{
		tersus.reloadView();
	}
};
tersus.reloadView = function()
{
	tersus.setPerspectiveAndView();
	tersus.loadView(document.getElementById('tersus.content'),view);
};
tersus.loader = {};
tersus.loadView = function loadView(targetElement, view)
{
	tersus.progress.set('Loading view - '+view.name);
	tersus.async.exec(function(){ tersus._loadView(targetElement, view);},false);
}
tersus._loadView = function loadView(targetElement, view)
{
	tersus.progress.set('Loading view - '+view.name);
	tersus.loader.currentView = view;
	tersus.loader.targetElement = targetElement;
	if (window.rootDisplayNode)
	{
		window.rootDisplayNode.destroyHierarchy();
		window.rootDisplayNode = null;
	}
	if (window.initPopupCalendar && ! tersus.popupCalendarInitialized)
	{
		tersus.popupCalendarInitialized = true;
		initPopupCalendar();
	}
	tersus.viewPath = view.path;
	if (tersus.repository.checkLoaded(view.id))
		tersus.loader.load();
	else
		if (tersus.preloadAll)
			tersus.repository.loadPackages([""],tersus.loader.load);
		else
			tersus.repository.loadPackages([tersus.getPackageId(view.id)],tersus.loader.load);
	tersus.alertMode = {interactive:true};
}
tersus.loader.load = function load()
{
	var view = tersus.loader.currentView;
	var targetElement = tersus.loader.targetElement;
	var root = window.rootDisplayNode;
	try
	{
		targetElement.innerHTML = '';
		if (!tersus.repository.isLoaded(view.id))
		{
			targetElement.innerHTML = 'View '+view.id+' not found';
			tersus.progress.clear();
			return;
		}
		if (! root)
		{
			var constructor = tersus.repository.get(view.id)
			window.currentRootDisplayNode = window.rootDisplayNode = root =  new constructor();
			root.mainWindow = window;
			root.currentWindow = window;
		}
		if (root.preload(tersus.loader.load))
		{
			root.create();
			root.doStart();
			if (window.trace)
				window.trace.flush();
			
			var topNode = root.wrapperNode ? root.wrapperNode : root.viewNode;	
			targetElement.appendChild(topNode);
			tersus.progress.clear();
			window.setTimeout(function(){window.rootDisplayNode.focusOnFirstField();},0);
		}
	}
	catch (e)
	{
			targetElement.innerHTML = escapeHTML(e.message);
	}
}
tersus.switchView = function(perspective,view,parameters)
{
	if (!perspective && window.perspectives.length > 1)
		perspective = window.perspective.name;
	if (perspective)
		var url = tersus.baseURL+'#Perspective='+encodeURIComponent(perspective)+'&View='+encodeURIComponent(view);
	else
		var url = tersus.baseURL+'#View='+encodeURIComponent(view);
	if (parameters)
		url+='&'+parameters;
	tersus.gotoURL(url, false, true);

};

function openTools()
{
	var w = 250;
	var h = 220;
	var leftPx = window.screenX+window.innerWidth;
	if (leftPx  > screen.availWidth -w -10)
		leftPx = screen.availWidth -w -10;
	if (leftPx<0) leftPx=0;
		
	var topPx = window.screenY;
	var popup = window.open("tools.html","Tools","top="+topPx+",left="+leftPx+"toolbar=no,location=no,status=no,menubar=no,width=" + w + ",height=" + h); 
	popup.focus();
};
function showContent()
{
	var w = window.open("","","");
	w.document.write('<textarea cols="80" rows="50">'+document.getElementById("main.content").innerHTML+"</textarea>");
	setTimeout(function(){w.focus();},0);
};


function removeSuffix(str, separator)
{
	var index = str.indexOf(separator);
	if (index >=0)
		return str.substring(0,index);
	else
		return str;
};
	
// Extract rootURL and baseURL
var fullURL = window.location.href;
var lastIndex = fullURL.lastIndexOf('/');
tersus.rootURL = fullURL.substring(0, lastIndex+1);
tersus.firstURL = fullURL;

tersus.baseURL = removeSuffix(removeSuffix(fullURL,'#'),'?');
// file: 060-sha256.js
/* A JavaScript implementation of the Secure Hash Algorithm, SHA-256
 * Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
 * Distributed under the BSD License
 * Some bits taken from Paul Johnston's SHA-1 implementation
 */
var chrsz = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode  */
function safe_add (x, y) {
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}
function S (X, n) {return ( X >>> n ) | (X << (32 - n));}
function R (X, n) {return ( X >>> n );}
function Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
function Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
function Sigma0256(x) {return (S(x, 2) ^ S(x, 13) ^ S(x, 22));}
function Sigma1256(x) {return (S(x, 6) ^ S(x, 11) ^ S(x, 25));}
function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));}
function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));}
function core_sha256 (m, l) {
    var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2);
    var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
    var W = new Array(64);
    var a, b, c, d, e, f, g, h, i, j;
    var T1, T2;
    /* append padding */
    m[l >> 5] |= 0x80 << (24 - l % 32);
    m[((l + 64 >> 9) << 4) + 15] = l;
    for ( var i = 0; i<m.length; i+=16 ) {
        a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
        for ( var j = 0; j<64; j++) {
            if (j < 16) W[j] = m[j + i];
            else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
            T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
            T2 = safe_add(Sigma0256(a), Maj(a, b, c));
            h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2);
        }
        HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]); HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
    }
    return HASH;
}
function str2binb (str) {
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
  return bin;
}
function binb2hex (binarray) {
  var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for (var i = 0; i < binarray.length * 4; i++) {
    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
  }
  return str;
}
function hex_sha256(s){return binb2hex(core_sha256(str2binb(s),s.length * chrsz));}
// file: 061-popcalendar.js
//	written	by Tan Ling	Wee	on 2 Dec 2001
//	last updated 28 Jul 2003
//	email : fuushikaden@yahoo.com
//	website : www.pengz.com
//	TabSize: 4
//
//	modified by ALQUANTO 30 July 2003 - german language included.
//									  - modified languageLogic with the ISO-2letter-strings
//									  - changes in in showCalendar: defaultLanguage is already set...
//									  - js and html corrected... more xhtml-compliant... simplier css
//	email: popcalendar@alquanto.de
//
//	modified by PinoToy 25 July 2003  - new logic for multiple languages (English, Spanish and ready for more).
//									  - changes in popUpMonth & popDownMonth methods for hidding	popup.
//									  - changes in popDownYear & popDownYear methods for hidding	popup.
//									  - new logic for disabling dates in	the past.
//									  - new method showCalendar, dynamic	configuration of language, enabling	past & position.
//									  - changes in the styles.
//	email  : pinotoy@yahoo.com
// No Copyright notice - assumed to be public domain
// Modified by Tersus, October 2004 - Image locations + Week starts on Monday
//                       January 2005 - Extract 'formatDate' function
//                                    - Changed 'popupCaledar' function to accept a callback in addition to the target node.
//                       May 2006     - changed 'popupCaledar' function to take into account scrolling and window size (added functions visible_size, screen_position at the end of the file)
//						 Aug 2006     - fixed formatDate(y,m,d, format) - used to add 1 to the month when outputing in numeric format
//						 Jan 2008     - added Hebrew translation
//                                    - added setCalendarStartOnSunday() to enable externalizing the setup.
//						 Jun 2008     - fixed arrows and drop-downs from right-to-left mode
//                       Sep 2008     - Using 'display:none' instead of 'visibility:hidden' to prevent scrolling problems
//						 Aug 2009	  - Refreshing current date and time when showing calendar	
//                                    - Extracted parseDate as a separate function
	var language = 'en';	// Default Language: en - english ; es - spanish; de - german
	var enablePast = 1;		// 0 - disabled ; 1 - enabled
	var fixedX = -1;		// x position (-1 if to appear below control)
	var fixedY = -1;		// y position (-1 if to appear below control)
	var showWeekNumber = 1;	// 0 - don't show; 1 - show
	var showToday = 1;		// 0 - don't show; 1 - show
	var imgDir = 'images/calendar/';		// directory for images ... e.g. var imgDir="/img/"
	var dayName = '';

	var gotoString = {
		en : 'Go To Current Month',
		es : 'Ir al Mes Actual',
		de : 'Gehe zu aktuellem Monat',
		he : 'עבור לחודש נוכחי'
	};
	var todayString = {
		en : 'Today is',
		es : 'Hoy es',
		de : 'Heute ist',
		he : 'היום - יום'
	};
	var weekString = {
		en : 'Wk',
		es : 'Sem',
		de : 'KW',
		he : 'שבוע'
	};
	var scrollLeftMessage = {
		en : 'Click to scroll to previous month. Hold mouse button to scroll automatically.',
		es : 'Presione para pasar al mes anterior. Deje presionado para pasar varios meses.',
		de : 'Klicken um zum vorigen Monat zu gelangen. Gedr?ckt halten, um automatisch weiter zu scrollen.',
		he : 'לחץ למעבק לחודש הקודם. לחץ והחזק לגלילה אוטומטית.'
	};
	var scrollRightMessage = {
		en : 'Click to scroll to next month. Hold mouse button to scroll automatically.',
		es : 'Presione para pasar al siguiente mes. Deje presionado para pasar varios meses.',
		de : 'Klicken um zum nächsten Monat zu gelangen. Gedr?ckt halten, um automatisch weiter zu scrollen.',
		he : 'לחץ למעבר לחודש הבא. לחץ והחזק לגלילה אוטומטית.'
	};
	var selectMonthMessage = {
		en : 'Click to select a month.',
		he : 'לחץ לבחירת חודש.', 
		es : 'Presione para seleccionar un mes',
		de : 'Klicken um Monat auszuwählen'
	};
	var selectYearMessage = {
		en : 'Click to select a year.',
		he : 'לחץ לבחירת שנה.',
		es : 'Presione para seleccionar un ano',
		de : 'Klicken um Jahr auszuwählen'
	};
	var selectDateMessage = {		// do not replace [date], it will be replaced by date.
		en : 'Select [date] as date.',
		he : 'בחבר ב [date] כתאריך.',
		es : 'Seleccione [date] como fecha',
		de : 'Wähle [date] als Datum.'
	};
	var	monthName = {
		en : new Array('January','February','March','April','May','June','July','August','September','October','November','December'),
		he : new Array('ינואר','פברואר','מרץ','אפריל','מאי','יוני','יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'),
		es : new Array('Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'),
		de : new Array('Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember')
	};
	var	monthName2 = {
		en : new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'),
		he : new Array('ינו','פבר','מרץ','אפר','מאי','יונ','יול','אוג','ספט','אוק','נוב','דצמ'),
		es : new Array('ENE','FEB','MAR','ABR','MAY','JUN','JUL','AGO','SEP','OCT','NOV','DIC'),
		de : new Array('JAN','FEB','MRZ','APR','MAI','JUN','JUL','AUG','SEP','OKT','NOV','DEZ')
	};
	function setCalendarStartOnSunday(startOnSunday)
	{
		if (startOnSunday) {
			startAt = 0;
			dayName = {
			en : new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat'),
			he : new Array('א','ב','ג','ד','ה','ו','ש'),
			es : new Array('Dom','Lun','Mar','Mie','Jue','Vie','Sab'),
			de : new Array('So','Mo','Di','Mi','Do','Fr','Sa')};
		}
		else {
		startAt = 1;
		dayName = {
			en : new Array('Mon','Tue','Wed','Thu','Fri','Sat','Sun'),
			he : new Array('ב','ג','ד','ה','ו','ש','א'),
			es : new Array('Lun','Mar','Mie','Jue','Vie','Sab','Dom'),
			de : new Array('Mo','Di','Mi','Do','Fr','Sa','So')
		};
		}
	};
	setCalendarStartOnSunday(false);

function getCalendarDirection()
{
	var node = document.getElementById('calendar');
	if (node.currentStyle)
		return node.currentStyle['direction'];
	else if (window.getComputedStyle)
		return getComputedStyle(node,null).getPropertyValue('direction');
};
	
function setToday()
{
 	today    = new Date();
 	dateNow  = today.getDate();
	monthNow = today.getMonth();
	yearNow  = today.getFullYear();
};
	var crossobj, crossMonthObj, crossYearObj, monthSelected, yearSelected, dateSelected, omonthSelected, oyearSelected, odateSelected, monthConstructed, yearConstructed, intervalID1, intervalID2, timeoutID1, timeoutID2, targetNode, valueHandler, ctlNow, dateFormat, nStartingYear, selDayAction, isPast;
	var visYear  = 0;
	var visMonth = 0;
	var bPageLoaded = false;
	var ie  = document.all;
	var dom = document.getElementById;
	var ns4 = document.layers;
	setToday();
	
	var imgsrc   = new Array('drop1.gif','drop2.gif','left1.gif','left2.gif','right1.gif','right2.gif');
	var img      = new Array();
	var bShow    = false;

	/* hides <select> and <applet> objects (for IE only) */
	function hideElement( elmID, overDiv ) {
		if(ie) {
			for(i = 0; i < document.all.tags( elmID ).length; i++) {
				obj = document.all.tags( elmID )[i];
				if(!obj || !obj.offsetParent) continue;

				// Find the element's offsetTop and offsetLeft relative to the BODY tag.
				objLeft   = obj.offsetLeft;
				objTop    = obj.offsetTop;
				objParent = obj.offsetParent;

				while(objParent.tagName.toUpperCase() != 'BODY') {
					objLeft  += objParent.offsetLeft;
					objTop   += objParent.offsetTop;
					objParent = objParent.offsetParent;
				}

				objHeight = obj.offsetHeight;
				objWidth  = obj.offsetWidth;

				if((overDiv.offsetLeft + overDiv.offsetWidth) <= objLeft);
				else if((overDiv.offsetTop + overDiv.offsetHeight) <= objTop);
				/* CHANGE by Charlie Roche for nested TDs*/
				else if(overDiv.offsetTop >= (objTop + objHeight + obj.height));
				/* END CHANGE */
				else if(overDiv.offsetLeft >= (objLeft + objWidth));
				else {
					obj.style.display = 'none';
				}
			}
		}
	}

	/*
	* unhides <select> and <applet> objects (for IE only)
	*/
	function showElement(elmID) {
		if(ie) {
			for(i = 0; i < document.all.tags( elmID ).length; i++) {
				obj = document.all.tags(elmID)[i];
				if(!obj || !obj.offsetParent) continue;
				obj.style.display = '';
			}
		}
	}

	function HolidayRec (d, m, y, desc) {
		this.d = d;
		this.m = m;
		this.y = y;
		this.desc = desc;
	}

	var HolidaysCounter = 0;
	var Holidays = new Array();

	function addHoliday (d, m, y, desc) {
		Holidays[HolidaysCounter++] = new HolidayRec (d, m, y, desc);
	}

	if (dom) {
		for	(i=0;i<imgsrc.length;i++) {
			img[i] = new Image;
			img[i].src = imgDir + imgsrc[i];
		}
		document.write ('<div onclick="bShow=true" id="calendar" style="z-index:+999;position:absolute;display:none;"><table width="'+((showWeekNumber==1)?250:220)+'" style="font-family:Arial;font-size:11px;border: 1px solid #A0A0A0;" bgcolor="#ffffff"><tr bgcolor="#000066"><td><table width="'+((showWeekNumber==1)?248:218)+'"><tr><td style="padding:2px;font-family:Arial;font-size:11px;"><font color="#ffffff' + '' /*C9D3E9*/ +'"><b><span id="caption"></span></b></font></td><td align="right"><a href="javascript:hideCalendar()"><img src="'+imgDir+'close.gif" width="15" height="13" border="0" /></a></td></tr></table></td></tr><tr><td style="padding:5px" bgcolor="#ffffff"><span id="content"></span></td></tr>');

		if (showToday == 1) {
			document.write ('<tr bgcolor="#f0f0f0"><td style="padding:5px" align="center"><span id="lblToday"></span></td></tr>');
		}
			
		document.write ('</table></div><div id="selectMonth" style="z-index:+999;position:absolute;display:none;"></div><div id="selectYear" style="z-index:+999;position:absolute;display:none;"></div>');
	}

	var	styleAnchor = 'text-decoration:none;color:black;';
	var	styleLightBorder = 'border:1px solid #a0a0a0;';

	function swapImage(srcImg, destImg) {
		if (ie) document.getElementById(srcImg).setAttribute('src',imgDir + destImg);
	}
	
	
	function initToday()
	{
		setToday();
		if (showToday == 1) {
			document.getElementById('lblToday').innerHTML =	'<font color="#000066">' + todayString[language] + ' <a onmousemove="window.status=\''+gotoString[language]+'\'" onmouseout="window.status=\'\'" title="'+gotoString[language]+'" style="'+styleAnchor+'" href="javascript:monthSelected=monthNow;yearSelected=yearNow;constructCalendar();">'+dayName[language][(today.getDay()-startAt==-1)?6:(today.getDay()-startAt)]+', ' + dateNow + ' ' + monthName[language][monthNow].substring(0,3) + ' ' + yearNow + '</a></font>';
		}
	
	}

	function initPopupCalendar() {
		if (!ns4)
		{

			crossobj=(dom)?document.getElementById('calendar').style : ie? document.all.calendar : document.calendar;
			hideCalendar();

			crossMonthObj = (dom) ? document.getElementById('selectMonth').style : ie ? document.all.selectMonth : document.selectMonth;

			crossYearObj = (dom) ? document.getElementById('selectYear').style : ie ? document.all.selectYear : document.selectYear;

			monthConstructed = false;
			yearConstructed = false;
			initToday();
			if (getCalendarDirection() == 'rtl')
			{
				var next1='left1.gif';var next2='left2.gif';var prev1='right1.gif';var prev2='right2.gif';
			}
			else
			{	
				var prev1='left1.gif';var prev2='left2.gif';var next1='right1.gif';var next2='right2.gif';
			}
			sHTML1 = '<span id="spanLeft" style="border:1px solid #36f;cursor:pointer" onmouseover="swapImage(\'changeLeft\',\''+prev2+'\');this.style.borderColor=\'#8af\';window.status=\''+scrollLeftMessage[language]+'\'" onclick="decMonth()" onmouseout="clearInterval(intervalID1);swapImage(\'changeLeft\',\''+prev1+'\');this.style.borderColor=\'#36f\';window.status=\'\'" onmousedown="clearTimeout(timeoutID1);timeoutID1=setTimeout(\'StartDecMonth()\',500)" onmouseup="clearTimeout(timeoutID1);clearInterval(intervalID1)">&nbsp<img id="changeLeft" src="'+imgDir+prev1+'" width="10" height="11" border="0">&nbsp</span>&nbsp;';
			sHTML1 += '<span id="spanRight" style="border:1px solid #36f;cursor:pointer" onmouseover="swapImage(\'changeRight\',\''+next2+'right2.gif\');this.style.borderColor=\'#8af\';window.status=\''+scrollRightMessage[language]+'\'" onmouseout="clearInterval(intervalID1);swapImage(\'changeRight\',\''+next1+'\');this.style.borderColor=\'#36f\';window.status=\'\'" onclick="incMonth()" onmousedown="clearTimeout(timeoutID1);timeoutID1=setTimeout(\'StartIncMonth()\',500)" onmouseup="clearTimeout(timeoutID1);clearInterval(intervalID1)">&nbsp<img id="changeRight" src="'+imgDir+next1+'" width="10" height="11" border="0">&nbsp</span>&nbsp;';
			sHTML1 += '<span id="spanMonth" style="border:1px solid #36f;cursor:pointer" onmouseover="swapImage(\'changeMonth\',\'drop2.gif\');this.style.borderColor=\'#8af\';window.status=\''+selectMonthMessage[language]+'\'" onmouseout="swapImage(\'changeMonth\',\'drop1.gif\');this.style.borderColor=\'#36f\';window.status=\'\'" onclick="popUpMonth()"></span>&nbsp;';
			sHTML1 += '<span id="spanYear" style="border:1px solid #36f;cursor:pointer" onmouseover="swapImage(\'changeYear\',\'drop2.gif\');this.style.borderColor=\'#8af\';window.status=\''+selectYearMessage[language]+'\'" onmouseout="swapImage(\'changeYear\',\'drop1.gif\');this.style.borderColor=\'#36f\';window.status=\'\'" onclick="popUpYear()"></span>&nbsp;';

			document.getElementById('caption').innerHTML = sHTML1;

			bPageLoaded=true;
		}
	}

	function hideCalendar() {
		crossobj.display = 'none';
		if (crossMonthObj != null) crossMonthObj.display = 'none';
		if (crossYearObj  != null) crossYearObj.display = 'none';
		showElement('SELECT');
		showElement('APPLET');
	}

	function padZero(num) {
		return (num	< 10) ? '0' + num : num;
	}

	function constructDate(d,m,y) {
		return formatDate(y,m+1,d, dateFormat);
	}
	/*
	Creates a date string according to a given format
	y: full year (e.g. 1999, 2004);
	m: month number (1..12)
	d: day in month (1..31)
	*/
	function formatDate(y,m,d, format) {
		sTmp = format;
		sTmp = sTmp.replace ('dd','<e>');
		sTmp = sTmp.replace ('d','<d>');
		sTmp = sTmp.replace ('<e>',padZero(d));
		sTmp = sTmp.replace ('<d>',d);
		sTmp = sTmp.replace ('mmmm','<p>');
		sTmp = sTmp.replace ('mmm','<o>');
		sTmp = sTmp.replace ('mm','<n>');
		sTmp = sTmp.replace ('m','<m>');
		sTmp = sTmp.replace ('<m>',m);
		sTmp = sTmp.replace ('<n>',padZero(m));
		sTmp = sTmp.replace ('<o>',monthName[language][m-1]);
		sTmp = sTmp.replace ('<p>',monthName2[language][m-1]);
		sTmp = sTmp.replace ('yyyy',y);
		return sTmp.replace ('yy',padZero(y%100));
	}

	function closeCalendar() {
		hideCalendar();
		targetNode.value = constructDate(dateSelected,monthSelected,yearSelected);
		if (valueHandler)
			valueHandler(yearSelected, monthSelected+1, dateSelected);
		valueHandler = null; // clean up
	}

	/*** Month Pulldown	***/
	function StartDecMonth() {
		intervalID1 = setInterval("decMonth()",80);
	}

	function StartIncMonth() {
		intervalID1 = setInterval("incMonth()",80);
	}

	function incMonth () {
		monthSelected++;
		if (monthSelected > 11) {
			monthSelected = 0;
			yearSelected++;
		}
		constructCalendar();
	}

	function decMonth () {
		monthSelected--;
		if (monthSelected < 0) {
			monthSelected = 11;
			yearSelected--;
		}
		constructCalendar();
	}

	function constructMonth() {
		popDownYear()
		if (!monthConstructed) {
			sHTML = "";
			for (i=0; i<12; i++) {
				sName = monthName[language][i];
				if (i == monthSelected){
					sName = '<b>' + sName + '</b>';
				}
				sHTML += '<tr><td id="m' + i + '" onmouseover="this.style.backgroundColor=\'#909090\'" onmouseout="this.style.backgroundColor=\'\'" style="cursor:pointer" onclick="monthConstructed=false;monthSelected=' + i + ';constructCalendar();popDownMonth();event.cancelBubble=true"><font color="#000066">&nbsp;' + sName + '&nbsp;</font></td></tr>';
			}

			document.getElementById('selectMonth').innerHTML = '<table width="70" style="font-family:Arial;font-size:11px;border:1px solid #a0a0a0;" bgcolor="#f0f0f0" cellspacing="0" onmouseover="clearTimeout(timeoutID1)" onmouseout="clearTimeout(timeoutID1);timeoutID1=setTimeout(\'popDownMonth()\',100);event.cancelBubble=true">' + sHTML + '</table>';

			monthConstructed = true;
		}
	}

	function popUpMonth() {
		if (visMonth == 1) {
			popDownMonth();
			visMonth--;
		} else {
			constructMonth();
			crossMonthObj.display='';
			if (getCalendarDirection() == 'rtl')
				crossMonthObj.left = parseInt(crossobj.left) + 132;
			else
				crossMonthObj.left = parseInt(crossobj.left) + 50;
			crossMonthObj.top =	parseInt(crossobj.top) + 26;
			hideElement('SELECT', document.getElementById('selectMonth'));
			hideElement('APPLET', document.getElementById('selectMonth'));
			visMonth++;
		}
	}

	function popDownMonth() {
		crossMonthObj.display = 'none';
		visMonth = 0;
	}

	/*** Year Pulldown ***/
	function incYear() {
		for	(i=0; i<7; i++) {
			newYear	= (i + nStartingYear) + 1;
			if (newYear == yearSelected)
				txtYear = '<span style="color:#006;font-weight:bold;">&nbsp;' + newYear + '&nbsp;</span>';
			else
				txtYear = '<span style="color:#006;">&nbsp;' + newYear + '&nbsp;</span>';
			document.getElementById('y'+i).innerHTML = txtYear;
		}
		nStartingYear++;
		bShow=true;
	}

	function decYear() {
		for	(i=0; i<7; i++) {
			newYear = (i + nStartingYear) - 1;
			if (newYear == yearSelected)
				txtYear = '<span style="color:#006;font-weight:bold">&nbsp;' + newYear + '&nbsp;</span>';
			else
				txtYear = '<span style="color:#006;">&nbsp;' + newYear + '&nbsp;</span>';
			document.getElementById('y'+i).innerHTML = txtYear;
		}
		nStartingYear--;
		bShow=true;
	}

	function selectYear(nYear) {
		yearSelected = parseInt(nYear + nStartingYear);
		yearConstructed = false;
		constructCalendar();
		popDownYear();
	}

	function constructYear() {
		popDownMonth();
		sHTML = '';
		if (!yearConstructed) {
			sHTML = '<tr><td align="center" onmouseover="this.style.backgroundColor=\'#909090\'" onmouseout="clearInterval(intervalID1);this.style.backgroundColor=\'\'" style="cursor:pointer" onmousedown="clearInterval(intervalID1);intervalID1=setInterval(\'decYear()\',30)" onmouseup="clearInterval(intervalID1)"><font color="#000066">-</font></td></tr>';

			j = 0;
			nStartingYear =	yearSelected - 3;
			for ( i = (yearSelected-3); i <= (yearSelected+3); i++ ) {
				sName = i;
				if (i == yearSelected) sName = '<b>' + sName + '</b>';
				sHTML += '<tr><td id="y' + j + '" onmouseover="this.style.backgroundColor=\'#909090\'" onmouseout="this.style.backgroundColor=\'\'" style="cursor:pointer" onclick="selectYear('+j+');event.cancelBubble=true"><font color="#000066">&nbsp;' + sName + '&nbsp;</font></td></tr>';
				j++;
			}

			sHTML += '<tr><td align="center" onmouseover="this.style.backgroundColor=\'#909090\'" onmouseout="clearInterval(intervalID2);this.style.backgroundColor=\'\'" style="cursor:pointer" onmousedown="clearInterval(intervalID2);intervalID2=setInterval(\'incYear()\',30)" onmouseup="clearInterval(intervalID2)"><font color="#000066">+</font></td></tr>';

			document.getElementById('selectYear').innerHTML = '<table width="44" cellspacing="0" bgcolor="#f0f0f0" style="font-family:Arial;font-size:11px;border:1px solid #a0a0a0;" onmouseover="clearTimeout(timeoutID2)" onmouseout="clearTimeout(timeoutID2);timeoutID2=setTimeout(\'popDownYear()\',100)">' + sHTML + '</table>';

			yearConstructed = true;
		}
	}

	function popDownYear() {
		clearInterval(intervalID1);
		clearTimeout(timeoutID1);
		clearInterval(intervalID2);
		clearTimeout(timeoutID2);
		crossYearObj.display= 'none';
		visYear = 0;
	}

	function popUpYear() {
		var leftOffset
		if (visYear==1) {
			popDownYear();
			visYear--;
		} else {
			constructYear();
			crossYearObj.display	= '';
			leftOffset = parseInt(crossobj.left) + document.getElementById('spanYear').offsetLeft;
			if (ie) leftOffset += 6;
			if (getCalendarDirection() == 'rtl')
				leftOffset += 32;
			crossYearObj.left = leftOffset;
			crossYearObj.top = parseInt(crossobj.top) + 26;
			visYear++;
		}
	}

	/*** calendar ***/
	function WeekNbr(n) {
		// Algorithm used:
		// From Klaus Tondering's Calendar document (The Authority/Guru)
		// http://www.tondering.dk/claus/calendar.html
		// a = (14-month) / 12
		// y = year + 4800 - a
		// m = month + 12a - 3
		// J = day + (153m + 2) / 5 + 365y + y / 4 - y / 100 + y / 400 - 32045
		// d4 = (J + 31741 - (J mod 7)) mod 146097 mod 36524 mod 1461
		// L = d4 / 1460
		// d1 = ((d4 - L) mod 365) + L
		// WeekNumber = d1 / 7 + 1

		year = n.getFullYear();
		month = n.getMonth() + 1;
		if (startAt == 0) {
			day = n.getDate() + 1;
		} else {
			day = n.getDate();
		}

		a = Math.floor((14-month) / 12);
		y = year + 4800 - a;
		m = month + 12 * a - 3;
		b = Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400);
		J = day + Math.floor((153 * m + 2) / 5) + 365 * y + b - 32045;
		d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461;
		L = Math.floor(d4 / 1460);
		d1 = ((d4 - L) % 365) + L;
		week = Math.floor(d1/7) + 1;

		return week;
	}
	function WeekYear(n) {
		// Algorithm used:
		// From Klaus Tondering's Calendar document (The Authority/Guru)
		// http://www.tondering.dk/claus/calendar.html
		// a = (14-month) / 12
		// y = year + 4800 - a
		// m = month + 12a - 3
		// J = day + (153m + 2) / 5 + 365y + y / 4 - y / 100 + y / 400 - 32045
		// d4 = (J + 31741 - (J mod 7)) mod 146097 mod 36524 mod 1461
		// L = d4 / 1460
		// d1 = ((d4 - L) mod 365) + L
		// WeekNumber = d1 / 7 + 1

		year = n.getFullYear();
		month = n.getMonth() + 1;
		if (startAt == 0) {
			day = n.getDate() + 1;
		} else {
			day = n.getDate();
		}

		a = Math.floor((14-month) / 12);
		y = year + 4800 - a;
		m = month + 12 * a - 3;
		b = Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400);
		J = day + Math.floor((153 * m + 2) / 5) + 365 * y + b - 32045;
		d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461;
		L = Math.floor(d4 / 1460);
		d1 = ((d4 - L) % 365) + L;
		week = Math.floor(d1/7) + 1;
		if (week == 1 && month == 12)
			return year+1;
		if (week >= 52 && month == 1)
			return year-1;
		return year;
	}
	function constructCalendar () {
		var aNumDays = Array (31,0,31,30,31,30,31,31,30,31,30,31);
		var dateMessage;
		var startDate = new Date (yearSelected,monthSelected,1);
		var endDate;

		if (monthSelected==1) {
			endDate = new Date (yearSelected,monthSelected+1,1);
			endDate = new Date (endDate - (24*60*60*1000));
			numDaysInMonth = endDate.getDate();
		} else {
			numDaysInMonth = aNumDays[monthSelected];
		}

		datePointer = 0;
		dayPointer = startDate.getDay() - startAt;
		
		if (dayPointer<0) dayPointer = 6;

		sHTML = '<table border="0" style="font-family:verdana;font-size:10px;"><tr>';

		if (showWeekNumber == 1) {
			sHTML += '<td width="27"><b>' + weekString[language] + '</b></td><td width="1" rowspan="7" bgcolor="#d0d0d0" style="padding:0px"><img src="'+imgDir+'divider.gif" width="1"></td>';
		}

		for (i = 0; i<7; i++) {
			sHTML += '<td width="27" align="right"><b><font color="#000066">' + dayName[language][i] + '</font></b></td>';
		}

		sHTML += '</tr><tr>';
		
		if (showWeekNumber == 1) {
			sHTML += '<td align="right">' + WeekNbr(startDate) + '&nbsp;</td>';
		}

		for	( var i=1; i<=dayPointer;i++ ) {
			sHTML += '<td>&nbsp;</td>';
		}
	
		for	( datePointer=1; datePointer <= numDaysInMonth; datePointer++ ) {
			dayPointer++;
			sHTML += '<td align="right">';
			sStyle=styleAnchor;
			if ((datePointer == odateSelected) && (monthSelected == omonthSelected) && (yearSelected == oyearSelected))
			{ sStyle+=styleLightBorder }

			sHint = '';
			for (k = 0;k < HolidaysCounter; k++) {
				if ((parseInt(Holidays[k].d) == datePointer)&&(parseInt(Holidays[k].m) == (monthSelected+1))) {
					if ((parseInt(Holidays[k].y)==0)||((parseInt(Holidays[k].y)==yearSelected)&&(parseInt(Holidays[k].y)!=0))) {
						sStyle+= 'background-color:#fdd;';
						sHint += sHint=="" ? Holidays[k].desc : "\n"+Holidays[k].desc;
					}
				}
			}

			sHint = sHint.replace('/\"/g', '&quot;');

			dateMessage = 'onmousemove="window.status=\''+selectDateMessage[language].replace('[date]',constructDate(datePointer,monthSelected,yearSelected))+'\'" onmouseout="window.status=\'\'" ';


			//////////////////////////////////////////////
			//////////  Modifications PinoToy  //////////
			//////////////////////////////////////////////
			if (enablePast == 0 && ((yearSelected < yearNow) || (monthSelected < monthNow) && (yearSelected == yearNow) || (datePointer < dateNow) && (monthSelected == monthNow) && (yearSelected == yearNow))) {
				selDayAction = '';
				isPast = 1;
			} else {
				selDayAction = 'href="javascript:dateSelected=' + datePointer + ';closeCalendar();"';
				isPast = 0;
			}

			if ((datePointer == dateNow) && (monthSelected == monthNow) && (yearSelected == yearNow)) {	///// today
				sHTML += "<b><a "+dateMessage+" title=\"" + sHint + "\" style=\"white-space:nowrap;"+sStyle+"\" "+selDayAction+"><font color=#ff0000>&nbsp;" + datePointer + "</font>&nbsp;</a></b>";
			} else if (dayPointer % 7 == (startAt * -1)+1) {									///// SI ES DOMINGO
				if (isPast==1)
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#909090>" + datePointer + "</font>&nbsp;</a>";
				else
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#54A6E2>" + datePointer + "</font>&nbsp;</a>";
			} else if ((dayPointer % 7 == (startAt * -1)+7 && startAt==1) || (dayPointer % 7 == startAt && startAt==0)) {	///// SI ES SABADO
				if (isPast==1)
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#909090>" + datePointer + "</font>&nbsp;</a>";
				else
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#54A6E2>" + datePointer + "</font>&nbsp;</a>";
			} else {																			///// CUALQUIER OTRO DIA
				if (isPast==1)
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#909090>" + datePointer + "</font>&nbsp;</a>";
				else
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' "+selDayAction+">&nbsp;<font color=#000066>" + datePointer + "</font>&nbsp;</a>";
			}

			sHTML += '';
			if ((dayPointer+startAt) % 7 == startAt) {
				sHTML += '</tr><tr>';
				if ((showWeekNumber == 1) && (datePointer < numDaysInMonth)) {
					sHTML += '<td align="right">' + (WeekNbr(new Date(yearSelected,monthSelected,datePointer+1))) + '&nbsp;</td>';
				}
			}
		}

		document.getElementById('content').innerHTML   = sHTML
		document.getElementById('spanMonth').innerHTML = '&nbsp;' +	monthName[language][monthSelected] + '&nbsp;<img id="changeMonth" src="'+imgDir+'drop1.gif" width="12" height="10" border="0">'
		document.getElementById('spanYear').innerHTML  = '&nbsp;' + yearSelected	+ '&nbsp;<img id="changeYear" src="'+imgDir+'drop1.gif" width="12" height="10" border="0">';
	}

	function showCalendar(ctl, ctl2, format, lang, past, fx, fy) {
		if (lang != null && lang != '') language = lang;
		if (past != null) enablePast = past;
		else enablePast = 0;
		if (fx != null) fixedX = fx;
		else fixedX = -1;
		if (fy != null) fixedY = fy;
		else fixedY = -1;

		if (showToday == 1) {
			document.getElementById('lblToday').innerHTML = '<font color="#000066">' + todayString[language] + ' <a onmousemove="window.status=\''+gotoString[language]+'\'" onmouseout="window.status=\'\'" title="'+gotoString[language]+'" style="'+styleAnchor+'" href="javascript:monthSelected=monthNow;yearSelected=yearNow;constructCalendar();">'+dayName[language][(today.getDay()-startAt==-1)?6:(today.getDay()-startAt)]+', ' + dateNow + ' ' + monthName[language][monthNow].substring(0,3) + ' ' + yearNow + '</a></font>';
		}
		popUpCalendar(ctl, ctl2, null, format);
	}

	/*
		Pops up the calendar.
		ctl: the document node used to position the popup calendar
		target: the document node in which the formatted value should be placed (and from which the initial value should be taken)
		handler: a function to be called when a date has been selected. 
		         the function accepts 3 arguments (y, m, d) where y is the full year (e.g. 2004)
		         m is the month (1..12) and d is the day (1..31)
	*/
	
	function parseDate(text, format)
	{
		var formatChar = ' ';
		var aFormat = format.split(formatChar);
		if (aFormat.length < 3) {
			formatChar = '/';
			aFormat = format.split(formatChar);
			if (aFormat.length < 3) {
				formatChar = '.';
				aFormat = format.split(formatChar);
				if (aFormat.length < 3) {
					formatChar = '-';
					aFormat = format.split(formatChar);
					if (aFormat.length < 3) {
						return null;					// invalid date format

					}
				}
			}
		}

		var tokensChanged = 0;
		var aData =	text.split(formatChar);			// use user's date

		var y, m, d;
		for (var i=0; i<3; i++) {
			if ((aFormat[i] == "d") || (aFormat[i] == "dd")) {
				d = parseInt(aData[i], 10);
				tokensChanged++;
			} else if ((aFormat[i] == "m") || (aFormat[i] == "mm")) {
				m = parseInt(aData[i], 10) - 1;
				tokensChanged++;
			} else if (aFormat[i] == "yyyy") {
				y = parseInt(aData[i], 10);
				tokensChanged++;
			} else if (aFormat[i] == "mmm") {
				for (j=0; j<12; j++) {
					if (aData[i] == monthName[language][j]) {
						m=j;
						tokensChanged++;
					}
				}
			} else if (aFormat[i] == "mmmm") {
				for (j=0; j<12; j++) {
					if (aData[i] == monthName2[language][j]) {
						m = j;
						tokensChanged++;
					}
				}
			}
		}

		if ((tokensChanged != 3)|| isNaN(d) || isNaN(m) || isNaN(y)) 
			return null; // Invalid format or invalid date string

		return {d:d, m:m, y:y};
	}
	function popUpCalendar(ctl, target, handler, format) {
		initToday();
		var leftpos = 0;
		var toppos  = 0;
		if (bPageLoaded) {
			if (crossobj.display == 'none') {
				valueHandler = handler;
				targetNode = target;
				dateFormat = format;
	
				var date = parseDate(target.value, format);
				if (date == null)
				{
					date = {d:dateNow, m:monthNow, y:yearNow};
				}
				dateSelected = date.d;
				monthSelected = date.m;
				yearSelected = date.y;

				odateSelected  = dateSelected;
				omonthSelected = monthSelected;
				oyearSelected  = yearSelected;

				var p = screen_position(ctl);
				var s = visible_size(ctl);
				var window_size = page_size(window);
				var scroll = page_scroll(window);
				crossobj.left = 0;
				crossobj.top = 0;
				constructCalendar (1, monthSelected, yearSelected);
				var calSize = visible_size(document.getElementById('calendar'));
				var left = (fixedX == -1) ? p.left  : fixedX;
				var top = (fixedY == -1) ? p.top + s.height + 2 : fixedY;
				if (left + calSize.width >window_size.width-10)
					left = window_size.width-calSize.width-10;
				if (left<0)
					left=0;
				if (top + calSize.height > window_size.height-10)
					top = window_size.height-10-calSize.height-10;
				if (top<0)
					top=0;
				crossobj.left = left+scroll.x;
				crossobj.top = top + scroll.y;
				crossobj.display = '';

				hideElement('SELECT', document.getElementById('calendar'));
				hideElement('APPLET', document.getElementById('calendar'));			

				bShow = true;
			} else {
				hideCalendar();
				if (ctlNow!=ctl) popUpCalendar(ctl, target, handler, format);
			}
			ctlNow = ctl;
		}
	}

	document.onkeypress = function hidecal1 (e) {
		if (window.event && window.event.keyCode == 27) // IE
			hideCalendar();
		else if (e && e.keyCode && e.keyCode == 27) // Mozilla
			hideCalendar();
		
		
	}
	document.onclick = function hidecal2 () {
		if (!bShow) hideCalendar();
		bShow = false;
	}
	function visible_size(node)
	{
		var width = node.offsetWidth;
		var height = node.offsetHeight;
		if (node == node.ownerDocument.body && node.clientHeight)
		{
			height = node.clientHeight;
		};
		//TODO handle width
		return {'height':height,'width':width};
	};
	function screen_position(node)
	{
		var x = 0;
		var y = 0;
		var currentNode = node;
		do
		{
			x+=currentNode.offsetLeft;
			y+=currentNode.offsetTop;
			currentNode = currentNode.offsetParent;
		}
		while (currentNode);
		currentNode = node;
		do
		{	
			if (currentNode.scrollLeft != undefined)
			{	
		  		x -= currentNode.scrollLeft;
  				y -= currentNode.scrollTop;
	  			currentNode = currentNode.parentNode;
	  		}
	  		else
		  		currentNode = null;
		}
		while (currentNode);
		return {'left':x, 'top':y};
	};
function page_size(w)
{
	var size = {};
	if (w.innerHeight) 
	{
		size.width = w.innerWidth;
		size.height = w.innerHeight;
	}
	else if (w.document.documentElement && w.document.documentElement.clientHeight)
	{
		size.width = w.document.documentElement.clientWidth;
		size.height = w.document.documentElement.clientHeight;
	}
	else if (w.document.body) 
	{
		size.width = w.document.body.clientWidth;
		size.height = w.document.body.clientHeight;
	}
	return size;
};

function page_scroll(w)
{
	var scroll = {};
	if (w.pageYOffset) 
	{
		scroll.x = w.pageXOffset;
		scroll.y = w.pageYOffset;
	}
	else if (w.document.documentElement && w.document.documentElement.scrollTop)
	{
		scroll.x = w.document.documentElement.scrollLeft;
		scroll.y = w.document.documentElement.scrollTop;
	}
	else if (w.document.body) // all other Explorers
	{
		scroll.x = w.document.body.scrollLeft;
		scroll.y = w.document.body.scrollTop;
	}
	return scroll;
};
	// file: 062-reload-styles.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.reloadStyles = function()
{
	var linkElement = document.getElementById('main_stylesheet');
	if (linkElement)
		linkElement.href='Styles?Timestamp='+(new Date()).getTime();
}
// file: 073-send-message.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function sendMessage(adapter, message, traceFileName)
{
	var url=tersus.rootURL+'File/'+encodeURIComponent(adapter);
	var req = createXMLHTTPRequest();
	var serviceNode = this;
	req.open('POST', url, true);
	var b = []
	Serializer.prototype._quote(message, b);
	req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	var requestBody='Message='+window.encodeURIComponent(b.join(''));
	if (traceFileName)
		requestBody+='&_traceFileName='+window.encodeURIComponent(traceFileName);
	req.send(requestBody);
	
}// file: 100-GenericField.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GenericField = function tersus_GenericField() {
};
tersus.GenericField.prototype = new DisplayNode();
tersus.GenericField.prototype.constructor = tersus.GenericField;
tersus.GenericField.prototype.currentReadOnly = null;
tersus.GenericField.prototype.value = null;
tersus.GenericField.prototype.isEditable = true;
tersus.GenericField.prototype.inputFieldTag = 'input';
tersus.GenericField.prototype.defaultTag = 'span';
tersus.GenericField.prototype.textTranslation = false;
tersus.GenericField.prototype.emptyOptionText = null;
tersus.GenericField.EMPTY_OPTION_TEXT = '<Empty Option Text>';
tersus.GenericField.prototype.init = function ()
{
	if (this.sharedProperties && tersus.isNumber(this.sharedProperties.maxLength))
    	this.maxLength = this.sharedProperties.maxLength;
};
tersus.GenericField.prototype.addGetter(tersus.GenericField.EMPTY_OPTION_TEXT, function()
{
	return this.emptyOptionText;
});
tersus.GenericField.prototype.updateOptions = function()
{
 	if (this.inputField && this.isChooser)
	{
		this.inputField.innerHTML = '';
		for (var i=0; i<this.options.length; i++)
		{
			var option = this.options[i];
			this.addOptionElement(option, i);
		}		
	}
 }
tersus.GenericField.prototype.addRemover(tersus.GenericField.EMPTY_OPTION_TEXT, function()
{
	if (this.emptyOptionText != null)
	{
		if (this.options)
			this.options.splice(0,1);//remove null from beginning of list
		this.emptyOptionText = null;
		this.updateOptions();
	}
});
tersus.GenericField.prototype.addSetter(tersus.GenericField.EMPTY_OPTION_TEXT,function(text)
{
	if (this.emptyOptionText == null)
	{
		if (this.options)
			this.options.splice(0,0,null); // add null to beginning of list
		else
			this.options = [null];
	}
	this.emptyOptionText = text;
	this.updateOptions();
});
tersus.GenericField.prototype.addGetter('<Max Length>', function()
{
	return this.maxLength;
});
tersus.GenericField.prototype.addSetter('<Max Length>', function(length)
{
	this.maxLength = length;
	if (this.inputField)
		this.inputField.maxLength = this.maxLength;
	// Reset value in order to truncate if needed
	this.setFieldValue(this.getFieldValue());
	
});
tersus.GenericField.prototype.reformat = function()
{
	this.setValueString();
};
tersus.GenericField.prototype.formatProperties = {
	currencySymbol:'<Currency Symbol>',
	currencyPosition:'<Currency Position>',
	useThousandsSeparator:'<Use Thousands Separator>',
	decimalPlaces:'<Decimal Places>'
};
tersus.GenericField.prototype.createFormatProps = function()
{
	this.formatProps = {};
	for (var p in this.formatProperties)
	{
		this.formatProps[p]=this.sprop(p);
	}	
};

tersus.GenericField.addFormatAccessor  = function (pt, prop, elementName)
{
	pt.addSetter(elementName, function(v)
	{
		if (! this.formatProps)
			this.createFormatProps();
		this.formatProps[prop] = v;	
		this.reformat();
	});
	pt.addGetter(elementName, function()
	{
		if (this.formatProps)
			return this.formatProps[prop];
		else
			return this.sprop(prop);
	});
};
for (var p in tersus.GenericField.prototype.formatProperties)
{
	tersus.GenericField.addFormatAccessor(tersus.GenericField.prototype, p,tersus.GenericField.prototype.formatProperties[p] );
};
tersus.clickNode = function (id)
{
	if (tersus.disabled)
		return;
	var node = tersus.findNode(id);
	if (node && node.onClick)
		node.onClick(node.viewNode);
};
tersus.GenericField.prototype.onClick  = function (domNode)
{
	if (domNode == this.browseButton)
		this.queueEvent(Events.ON_BROWSE);
	else
		DisplayNode.prototype.onClick.call(this,domNode);
};
tersus.GenericField.prototype['remove<Value>'] = function removeValue()
{
	this.value = null;
	if (this.viewNode)
	{
		if (this.inputField)
		{
			if (this.isChooser)
			{
				this.setSelectedIndex(0);
				if (this.options.length>0)
					this.value = this.options[0];
			}
			else
				this.inputField.value = '';
		}
		else if (this.hyperlink)
			this.hyperlink.innerHTML='';
		else
			this.viewNode.innerHTML = '';
		
	}
};

tersus.GenericField.prototype.updateSelfReadOnly = function tersus_GenericField_updateSelfReadOnly(readOnly)
{
	if (this.currentReadOnly == readOnly)
		return; // no change
	this.currentReadOnly = readOnly;
   	if (this.inputField)
       	this.value = this.getFieldValue();
	if (this.viewNode)
	{
		this.viewNode.innerHTML = '';
		if (readOnly)
		{
			if (this.hasEventHandler(Events.ON_CLICK))
				this.initLink()
			else
				this.initDisplay()
		}
		else
			this.initWritable();
	}
	this.setValueString();
};

tersus.GenericField.prototype.createViewNode = function tersus_GenericField_createViewNode()
{
	if (this.setDefaultProperties)
		this.setDefaultProperties();
	
    if (this.sharedProperties.inputFieldTag && this.sharedProperties.inputFieldTag != ' ')
    	this.inputFieldTag = this.sharedProperties.inputFieldTag;
    var optionsElement = this.getElement('<Options>');
    if (optionsElement)
    {
    	this.optionsElement = optionsElement;
    	this.isChooser = true;
    	this.options = [];
    	this.inputFieldTag = 'select';
    }
    DisplayNode.prototype.createViewNode.call(this);
};
tersus.GenericField.prototype.initViewNode = function tersus_GenericField_initViewNode()
{
    DisplayNode.prototype.initViewNode.call(this);
    this.updateSelfReadOnly(this.computedReadOnly());
};
tersus.GenericField.prototype.attachHTMLNode = function (e)
{
	this.viewNode = e;
	if (e.firstChild && e.firstChild.tagName == 'INPUT')
		this.inputField = e.firstChild;
   	this.registerEventHandler(Events.ON_CHANGE,this.inputField);
	this.registerEventHandler(Events.ON_FOCUS,this.inputField);
   	if (this.hasEventHandler(Events.ON_BLUR))
	   	this.registerEventHandler(Events.ON_BLUR,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYPRESS))
	   	this.registerEventHandler(Events.ON_KEYPRESS,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYDOWN))
	   	this.registerEventHandler(Events.ON_KEYDOWN,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYUP))
	   	this.registerEventHandler(Events.ON_KEYUP,this.inputField);
		
}

tersus.GenericField.prototype.setViewNode = function tersus_GenericField_setViewNode(viewNode)
{
	if (viewNode.tagName == 'INPUT')
	{	
		this.viewNode = this.createHTMLElement(this.getTag());
		viewNode.parentNode.replaceChild(this.viewNode, viewNode);
		this.viewNode.appendChild(viewNode);
		this.inputField = viewNode;
	}
	else
		this.viewNode = viewNode;
};
tersus.GenericField.nodesToAdjust = [];
tersus.GenericField.prototype.disabled = false;
tersus.GenericField.prototype.initWritable = function tersus_GenericField_initWritable()
{
	tersus.removeEventHandlers(this.viewNode);
    this.inputField = this.createHTMLElement(this.inputFieldTag);
    if (!this.isEditable)
    {
    	this.inputField.readOnly = true;
    }
    this.inputField.disabled = this.disabled;
    this.hyperlink = null;
    if (! this.isChooser && tersus.isNumber(this.sharedProperties.size))
    	this.inputField.size = this.sharedProperties.size;
    if (this.maxLength != null)
    	this.inputField.maxLength = this.maxLength;
    if (this.sharedProperties.width != undefined && this.sharedProperties.width != ' ')
    	this.inputField.style.width = this.sharedProperties.width;
    if (this.sharedProperties.styleClass && this.sharedProperties.styleClass != ' ')
	    this.inputField.className = this.sharedProperties.styleClass;
    if (this.sharedProperties.height && this.sharedProperties.height != ' ')
	    this.inputField.style.height = this.sharedProperties.height;
    var rows = this.sharedProperties.numberOfRows;
	if (rows && tersus.isNumber(rows))
		this.inputField.rows = parseInt(rows);
	var cols = this.sharedProperties.numberOfColumns;
	if (cols && tersus.isNumber(cols))
		this.inputField.cols = cols;
	if (this.isChooser)
	{	
		for (var i=0; i<this.options.length; i++)
		{
			var option = this.options[i];
			this.addOptionElement(option, i);
		}
		if (this.sharedProperties.size && this.sharedProperties.size != ' ')
			this.inputField.style.width = (2.5+0.57*this.sharedProperties.size) + "em"; // Trying to emulate the 'size' property of text input
		else if (this.sharedProperties.width && this.sharedProperties.width != ' ')
			this.inputField.style.width = this.sharedProperties.width;
			
	};
    	
    this.viewNode.innerHTML = '';
    this.viewNode.appendChild(this.inputField);
    if (this.hasEventHandler(Events.ON_BROWSE))
    {
	    this.viewNode.style.whiteSpace='nowrap';
		this.viewNode.style.position='relative';
    	this.inputField.className = 'pf_txt';

    	this.browseButton = this.createHTMLElement('button','pf_browse');
    	this.browseButton.innerHTML = '<img src="images/spacer.gif"/>';
	    //this.browseButton.type='text';
    	this.browseButton.id = this.getNodeId();
    	this.registerEventHandler(Events.ON_CLICK, this.browseButton);
	    this.viewNode.appendChild(this.browseButton);
	    var adjustList = tersus.GenericField.nodesToAdjust;
	    if (adjustList.length == 0)
		    setTimeout(tersus.GenericField.adjustPositions,10);
		adjustList.push(this);
	    //Adjust the position of the button based on the input field
    }
    this.inputField.setAttribute('node_id',this.getNodeId());
   	this.registerEventHandler(Events.ON_CHANGE,this.inputField);
	this.registerEventHandler(Events.ON_FOCUS,this.inputField);
   	if (this.hasEventHandler(Events.ON_BLUR))
	   	this.registerEventHandler(Events.ON_BLUR,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYPRESS))
	   	this.registerEventHandler(Events.ON_KEYPRESS,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYDOWN))
	   	this.registerEventHandler(Events.ON_KEYDOWN,this.inputField);
   	if (this.hasEventHandler(Events.ON_KEYUP))
	   	this.registerEventHandler(Events.ON_KEYUP,this.inputField);
};

tersus.GenericField.prototype.onChange = function(domNode)
{
	this.validateFieldValue();
	DisplayNode.prototype.onChange.call(this, domNode);
};
tersus.GenericField.prototype.onResize = function()
{
	if (this.browseButton)
	{
	    var adjustList = tersus.GenericField.nodesToAdjust;
	    this.browseButton.style.top='';
	    this.browseButton.style.left='';
	    if (adjustList.length == 0)
		    setTimeout(tersus.GenericField.adjustPositions,10);
		adjustList.push(this);
	}
};
tersus.GenericField.adjustPositions = function()
{
	var list = tersus.GenericField.nodesToAdjust;
	tersus.GenericField.nodesToAdjust = [];
	for (var i=0; i<list.length; i++)
	{
		var node = list[i];
		node.adjustPosition();
	}
};
/**
 * adjustPosition: align the browse button with the input field
 */
tersus.GenericField.prototype.adjustPosition = function()
{
	if (!this.inputField)
		return; // The field may have become read-only 
	var direction = getActualStyle(this.inputField,'direction');
	this.browseButton.style.height=getVisibleSize(this.inputField).height;
	var inputOffset = getOffsets(this.inputField);
	var inputTop=inputOffset.top;
	var buttonOffset = getOffsets(this.browseButton);
	var buttonTop = buttonOffset.top;
	var deltaTop = inputTop - buttonTop;
	this.browseButton.style.top = deltaTop+'px';
	if (direction == 'rtl')
	{
		var inputLeft = inputOffset.left;
		var buttonRight = buttonOffset.left + this.browseButton.offsetWidth-2; 	
		var deltaLeft = inputLeft - buttonRight;
		this.browseButton.style.borderRightWidth='0';
		this.browseButton.style.borderLeftWidth='2px';
		
	}
	else
	{
		var inputRight=inputOffset.left+this.inputField.offsetWidth -2; //Don't know why, but we need to substract 2
		var buttonLeft = buttonOffset.left;
		var deltaLeft = inputRight - buttonLeft;
		this.browseButton.style.borderRightWidth='2px';
		this.browseButton.style.borderLeftWidth='0px';
	}
	this.browseButton.style.left = deltaLeft+'px';
};
tersus.GenericField.prototype.getDefaultContent = function()
{
	return '';
};
tersus.GenericField.prototype.initLink = function tersus_GenericField_initLink()
{
	if (this.inputField)
		this.value = this.getFieldValue();
    this.inputField = null
    this.browseButton = null;
    this.hyperlink = this.createHTMLElement('a');
    var id = this.getNodeId();
    this.hyperlink.href='javascript:tersus.clickNode('+id+')';
   	this.hyperlink.innerHTML = this.getDefaultContent();
    this.viewNode.appendChild(this.hyperlink);
};
tersus.GenericField.prototype.initDisplay = function tersus_GenericField_initDisplay()
{
	this.hyperlink = null;
	this.inputField = null;
	this.browseButton = null;
	DisplayNode.prototype.setEventHandlers.call(this);
};
tersus.GenericField.prototype.getFieldValue = tersus.GenericField.prototype['get<Value>'] = function tersus_GenericField_getFieldValue()
{
	if (this.inputField)
	{	
		if (this.isChooser)
			this.value = this.getSelectedOption();
		else
		{
			var valueElement = this.getElement('<Value>');
			var valuePrototype = valueElement.getChildConstructor().prototype;
			this.value = valuePrototype.parseInput(this.inputField.value, this.formatProps ? this.formatProps : this.sharedProperties);
		}
	}
	return this.value;
};
tersus.GenericField.prototype.setFieldValue = tersus.GenericField.prototype['set<Value>'] = function tersus_GenericField_setFieldValue(value)
{
	this.value = value;
	// Truncate to maxLength if needed (only if this is a text field)
	if (this.maxLength && value && value.isText && value.leafValue && value.leafValue.length > this.maxLength)
	{
		this.value = new value.constructor();
		this.value.leafValue =  value.leafValue.substring(0,this.maxLength); 
	}

	if (this.isChooser && ! this.currentReadOnly)
		this.setSelectedIndex(this.findIndex(this.value));
	else
		this.setValueString();
};
tersus.GenericField.prototype.setValueString = function()
{
	this.valueStr = '';
	if (this.value != null)
	{
		if (this.isChooser)
			this.valueStr = this.getOptionText(this.value);
		else if (this.inputField)
			this.valueStr = this.value.formatInput(this.formatProps ? this.formatProps : this.sharedProperties);
		else
			this.valueStr = this.value.formatString(this.formatProps ? this.formatProps : this.sharedProperties);
	}
	if (this.inputField)
	{
		this.inputField.value = this.valueStr;
	}
	else if (this.hyperlink)
		this.hyperlink.innerHTML = this.escapeHTML(this.translate(this.valueStr));
	else if (this.viewNode)
		this.viewNode.innerHTML =  this.escapeHTML(this.translate(this.valueStr));
};
tersus.GenericField.prototype.setValueStringOpt = function()
{
	this.valueStr = '';
	if (this.value != null)
	{
		if (this.isChooser)
			this.valueStr = this.getOptionText(this.value);
		else if (this.optimizeFormatString)
			this.valueStr = this.value.leafValue;
		else if (this.inputField && this.valueFormatInput)
			this.valueStr = this.value.formatInput(this.sharedProperties);
		else if (this.value.formatString)
			this.valueStr = this.value.formatString(this.sharedProperties);
		else
			this.valueStr = this.value.toString();
	}
	if (this.inputField)
	{
		this.inputField.value = this.valueStr;
	}
	else if (this.hyperlink)
		this.hyperlink.innerHTML = this.escapeHTML(this.translate(this.valueStr));
	else if (this.viewNode)
		this.viewNode.innerHTML =  this.escapeHTML(this.translate(this.valueStr));
};
tersus.GenericField.prototype.setFieldValue.requiresNodes = true;
tersus.GenericField.prototype.validateFieldValue = function()
{
	var valueElement = this.getElement('<Value>');
	var valuePrototype = valueElement.getChildConstructor().prototype;
	if (valuePrototype.validateInput)
	{
		var errorMessage =  valuePrototype.validateInput(this.inputField.value, this.formatProps ? this.formatProps : this.sharedProperties);
		this.setValidationMessage(errorMessage);
	}
};
tersus.GenericField.prototype.setEventHandlers = function ()
{
};
tersus.GenericField.prototype.showValidationMessage = function (message)
{
	var targetNode = this.viewNode;
	if (this.inputField)
		targetNode = this.inputField;
	this.currentWindow.alert(message);
	if (targetNode.focus && !targetNode.disabled)
		targetNode.focus();
	if (targetNode.select)
		targetNode.select();
};

tersus.GenericField.prototype.tmpSelectedIndex = null;
tersus.GenericField.prototype.getSelectedOption  = function tersus_GenericField_getSelectedOption()
{
	var selectedIndex;
	if (this.tmpSelectedIndex != null) // In IE, the selected index is updated asynchronously, so we use tmpSelectedIndex if it is set
		selectedIndex = this.tmpSelectedIndex;
	else
		selectedIndex = this.inputField.selectedIndex;
	if (selectedIndex < 0)
		return null;
	return this.options[selectedIndex];
};

tersus.GenericField.prototype.setSelectedIndex = function tersus_GenericField_setSelectedIndex(selectedIndex)
{
	if (!this.inputField)
		return;
	if (window.browser == 'IE') // IE needs a delay in order to recognize any newly added option/s
	{
		var inputField = this.inputField;
		var node = this;
		this.tmpSelectedIndex = selectedIndex;
		setTimeout(function(){	
		inputField.selectedIndex = selectedIndex;
		node.tmpSelectedIndex = null;}
		, 10);
	}
	else
		this.inputField.selectedIndex = selectedIndex;
};

tersus.GenericField.prototype.getOptions = tersus.GenericField.prototype['get<Options>'] = function tersus_GenericField_getOptions()
{
	if ( !this.options)
		return [];
	if (this.emptyOptionText != null)
	{
		return this.options.slice(1); // Ignoring the first item in the array, which is the empty option (null)
	}
	return this.options;
};

tersus.GenericField.prototype.addOption = tersus.GenericField.prototype['add<Options>'] = function tersus_GenericField_addOption(value)
{
	if (! this.options)
		this.options = [];
	this.options.push(value);
	if (this.inputField)
	{
		this.addOptionElement(value, this.options.length -1 );
	}
};
tersus.GenericField.prototype.addOptionElement = function tersus_GenericField_addOptionElement(value, index)
{
	var optionNode = this.createHTMLElement('option');
	optionNode.innerHTML = this.translate(tersus.escapeHTML(this.getOptionText(value)));
	this.inputField.appendChild(optionNode);
	/* Check if the new option matches the value (which may have been set previously)
	 In case of a match, select the new option */
	if (this.value != null &&  compareValues(this.value, value))
		this.setSelectedIndex(index);
};
tersus.GenericField.prototype.deepCopy = function deepCopy(value)
{
	var selectedIndex = null;
	this.emptyOptionText = value.getLeafChild(tersus.GenericField.EMPTY_OPTION_TEXT);
	this.options = this.emptyOptionText == null ? [] : [null];

	for (var elementRole in value.elements)
	{
		if (elementRole == tersus.GenericField.EMPTY_OPTION_TEXT)
			continue;
		var element = this.getElement(elementRole);
		if (element)
		{
			if (element.isRepetitive)
			{
				var childValues = value.getChildren(elementRole);
				if (elementRole == '<Options>') // Special optimization - setting the options of a large chooser as one chunk of HTML
				{
					var html = [];
					if (this.emptyOptionText != null)
					{
						html.push('<OPTION>');
						html.push(tersus.escapeHTML(this.emptyOptionText));
						html.push('</OPTION>');
					}
					if (childValues.length > 0)
					{
						var optimize_get_text = false;
						var optionText;
						var v0 = childValues[0];
						this.getOptionText(v0);
						var textElement = v0.__textElement;
						if (textElement && textElement.modelId == BuiltinModels.TEXT_ID && ! this.textTranslation)
							optimize_get_text = true;
						for (var i=0; i<childValues.length;i++)
						{
							var v = childValues[i];
							this.options.push(v);
							if (this.inputField)
							{
								optionText = '';
								html.push('<OPTION>');
								if (optimize_get_text)
								{
									try
									{
										optionText = v.children[v.__textElementRole].leafValue;
									}
									catch (e)
									{
										optionText = '';
									}
									
									html.push(optionText);
								}
								else
									html.push(this.translate(tersus.escapeHTML(this.getOptionText(v))));
								html.push('</OPTION>');
								if (this.value != null &&  compareValues(this.value, v))
								{
									selectedIndex = i;
								}
							}
						}
						if (this.inputField)
						{
							var f=this.inputField;
							if (window.browser == 'IE')
							{
								// Don't remember why, but we need to re-recreate the input field in IE
								var oh = f.outerHTML;
								var p = f.parentNode;
								var ps = f.previousSibling;
								var endTag = '</SELECT>';
								f.outerHTML = oh.substring(0,oh.length-endTag.length) + html.join('') + endTag;
								if (ps)
									this.inputField = ps.nextSibling;
								else
									this.inputField = p.firstChild;
								this.attachHTMLNode(this.viewNode); // re-registers event handlers, which are lost when the input field is re-recreated.					

							}
							else
								f.innerHTML = html.join('');
						}
					}
					if (this.inputField && selectedIndex != null)
						this.setSelectedIndex(selectedIndex);
					
				}
				else
					element.setChildren(this, childValues, Operation.REPLACE);
			}
			else
			{
				var childValue = value.getChild(elementRole);
				if (childValue != null)
				{
					element.replaceChild(this, childValue);
				}
			}
		}
	}
	
};

tersus.GenericField.prototype.addOption.requiresNodes = true;
tersus.GenericField.prototype.removeOptions = tersus.GenericField.prototype['remove<Options>'] = function tersus_GenericField_removeOptions()
{
	this.options = [];
	if (this.inputField)
		this.inputField.innerHTML = '';
};

tersus.GenericField.prototype.findIndex = function tersus_GenericField_findIndex(value)
{
	if (this.options)
		for (var i=0; i<this.options.length; i++)
		{
			var option = this.options[i];
			if (compareValues(option, value))
				return i;
		}
	return -1;
};
tersus.GenericField.prototype.getOptionText = function tersus_GenericField_getOptionText(value)
{
	var outputValue = null;
	if (value && value.elementList)
	{
		var textElementRole = value.__textElementRole;
		if (textElementRole == null)
		{
			for (var i=0; i< value.elementList.length; i++)
			{
				var element = value.elementList[i];
				if (i==0)
				{
					textElementRole = element.role; // If no text element is found, the first element is used
					value.constructor.prototype.__textElement = element;
				}
				if (element.modelId == BuiltinModels.TEXT_ID)
				{
					textElementRole = element.role;
					value.constructor.prototype.__textElement = element;
					break;
				}
			}
		value.constructor.prototype.__textElementRole = textElementRole;
		}
		if (textElementRole && value.children)
			outputValue = value.children[textElementRole];
	}
	else
		outputValue = value;
	var text = '';
	if (outputValue != null)
		text =  outputValue.formatString(this.sharedProperties);
	else if (this.emptyOptionText != null)
		text = this.emptyOptionText;
	return text;
};
tersus.GenericField.prototype['get<Disabled>'] = function ()
{
	return this.disabled;
};

tersus.GenericField.prototype['set<Disabled>'] = function (disabled)
{
	this.disabled = disabled?true:false;
	if (this.inputField)
	{
		this.inputField.disabled=this.disabled;
	}
};
tersus.GenericField.prototype.getClickTarget = function()
{
	if (this.inputField)
		return this.inputField;
	else
		return this.viewNode;
};
tersus.GenericField.prototype.focus = function()
{
	if (this.inputField)
		this.inputField.focus();
	else if (this.viewNode.focus)
		this.viewNode.focus();
};
TextInputField = NumberInputField = tersus.GenericField; //backward compatability
// file: 101-DisplayField.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DisplayField = function tersus_DisplayField() {};
tersus.DisplayField.prototype = new tersus.GenericField();
tersus.DisplayField.prototype.constructor = tersus.DisplayField;
tersus.DisplayField.prototype.explicitReadOnly = true;
TextDisplay = NumberDisplay = DateDisplay = tersus.DisplayField; // backward compatability
// file: 110-Table.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 //Table - a simple table
Table = function Table() {this.columnNames={}; };
Table.prototype = new DisplayNode();
Table.prototype.constructor = Table;
Table.prototype.getTag = function()
{
	return 'table';
};
Table.prototype.reset = function reset()
{
	DisplayNode.prototype.reset.call(this);
	this.selectedRow = null;
	this.hiddenColumns = {};
	if (this.headerRow)
	{
		var headerCells=this.headerRow.childNodes;
		for (var i=0;i<headerCells.length;i++)
		{
			headerCells[i].style.display='';
		}
	}
}
Table.prototype.createViewNode = function createViewNode()
{
	this.hiddenColumns = {};
    DisplayNode.prototype.createViewNode.call(this);
    this.sort = (this.sharedProperties.sort == 'multiple');
    
	this.setProperties(); // In Mozilla, we have to set the styleclass before creating the body of the table
    this.createCaption();
    this.createHeader();
    this.bodyNode = this.currentWindow.document.createElement('tbody');
    var h = this.sharedProperties.contentHeight;
    if (h && h == ' ')
    	h = null;
    var w = this.sharedProperties.contentWidth;
    if (w && w == ' ')
    	w = null;
 	if (w || h)   
		setScrollableTable(this.bodyNode, w,h); // broswer dependant
    this.viewNode.appendChild(this.bodyNode);
    this.viewNode.id = this.getNodeId();
};
Table.prototype.createCaption = function createCaption()
{
	if ( this.sharedProperties.showCaption == false) // default = true
	{
		return;
	}
	else
		if ( ! this.getRowPrototype())
			return;
	this.captionDOMElement = this.createHTMLElement('caption');
	this.captionDOMElement.innerHTML = '<div>'+tersus.escapeHTML(this.getCaption())+'</div>';
	this.viewNode.appendChild(this.captionDOMElement);
};
Table.prototype.captionChanged = function()
{
	if (this.captionDOMElement)
		this.captionDOMElement.innerHTML = '<div>'+tersus.escapeHTML(this.getCaption())+'</div>';
};

Table.prototype.addHeaderCells = function addHeaderCells(headerRow,node)
/* Adds header cells based on the structure of the given node */
{
	for (var i=0; i< node.displayElements.length; i++)
	{	
		var columnElement = node.displayElements[i];
		var columnNodePrototype = columnElement.getChildConstructor().prototype;
		if (columnNodePrototype.isDisplayGroup)
		{
			this.addHeaderCells(headerRow, columnNodePrototype);
		}
		else
		{
			var labelHTML = columnElement.properties.caption;
			if (!labelHTML || labelHTML == ' ')
				labelHTML = tersus.escapeHTML(columnElement.role)
			labelHTML = this.translate(labelHTML);
			var headerCell = this.createHTMLElement('th');
			headerCell.setAttribute("element_name", columnElement.role);
			var columnName;
			if (columnElement.properties.sortColumnName)
				columnName = tersus.sqlize(columnElement.properties.sortColumnName);
			else
				columnName = tersus.sqlize(columnElement.role);
			this.columnNames[columnElement.role]=columnName.toLowerCase();
			headerCell.setAttribute("column_name", columnName);
			headerCell.innerHTML = labelHTML;
			var col = this.createHTMLChildElement(this.colgroup,'col');
			headerCell.col = col;
			if (this.sort && columnElement.properties.sortable != false)
			{
				headerCell.setAttribute('sort', 'none');
				headerCell.onclick = Table.headerClicked;
			}
			headerCell.onmousedown = Table.mouseDownOnHeader;
			headerCell.onmouseover = Table.updateHeaderCursor;
			headerCell.onmousemove = Table.updateHeaderCursor;
				

			if (headerRow.childNodes.length == 0)
				headerCell.className='first';
			headerRow.appendChild(headerCell);
		}
	}
};
Table.prototype.getRowPrototype = function()
{
	var output = null;
	if (this.subFlowList)
	{
		for (var i=0; i< this.subFlowList.length; i++)
		{
			var subFlow = this.subFlowList[i];
			if (subFlow.isDisplayElement && subFlow.role != '<Header>' && subFlow.role != '<Footer>')
			{
				if (output)
					return null;
				else
					output = subFlow;
			}
		}	
	}
	return output;
};
Table.prototype.createHeader = function createHeader()
{
	if ( this.sharedProperties.showHeadings == false) // default = true
		return;
	var rowElement = this.getRowPrototype();
	if (! rowElement) return;
	var rowPrototype = tersus.repository.get(rowElement.modelId).prototype;
	if (! rowPrototype.subFlowList) return;
	var headerRow = this.createHTMLElement('tr');
	this.colgroup = this.createHTMLChildElement(this.viewNode,'colgroup');
	this.addHeaderCells(headerRow, rowPrototype);
	var tableHeader = this.createHTMLElement('thead');
	tableHeader.appendChild(headerRow);
	this.header = tableHeader;
	this.headerRow = headerRow;
	this.viewNode.appendChild(tableHeader);
};

Table.prototype.removeChildViewNode = function removeChildViewNode(child)
{
	var c = child.viewNode;
	var row = null;
	if (c.tagName == 'TR' )
		row = c;
	else if (c.parentNode && c.parentNode.tagName == 'TR')
		row = c.parentNode;
	else if (c.parentNode && c.parentNode.parentNode && c.parentNode.parentNode.tagName== 'TR')
		row = c.parentNode.parentNode;
	if (row && row.parentNode)
		row.parentNode.removeChild(row);
};
Table.prototype.applyColOrder = function (row)
{
	if (this.colOrder)
	{
		var cells = [];
		for (var i=0;i<row.childNodes.length;i++)
		{
			cells.push(row.childNodes[i]);
		}
		if (cells.length != this.colOrder.length)
		{
			internalError("Failed to apply column order: mismatch between number of cells in row and number of columns in colOrder");
			return;
		}
		for (var i=0;i<cells.length;i++)
		{
			row.removeChild(cells[i]);
		}
		for (var i=0;i<cells.length;i++)
		{
			row.appendChild(cells[this.colOrder[i]]);
		}
	};
};
Table.prototype.getFooter = function()
{
	if (! this.footer)
		this.footer = 	this.header = this.createHTMLChildElement(this.viewNode, 'tfoot');
	return this.footer;
		
};
Table.prototype.appendChildViewNode = function appendChildViewNode(child, childElement)
{
	var element = childElement?childElement:child.element;
	var targetNode = this.bodyNode;
	if (element.role == '<Header>')
		targetNode = this.header;
	if (element.role == '<Footer>')
		targetNode = this.getFooter();
	var row = null;
	if (child.viewNode.tagName == 'TR')
	{
		row = child.viewNode;
	}
	else
	{
		var row = this.createHTMLElement('TR');
		if (child.viewNode.tagName == 'TH' || child.viewNode.tagName == 'TD')
			row.appendChild(child.viewNode);
		else
		{
			var cell = this.createHTMLChildElement(row,'TD');
			cell.appendChild(child.viewNode);
		}
		row.setAttribute('display_order', child.viewNode.getAttribute('display_order'));
	}
	if (this.headerRow && ! element.prop('suppressColumnHiding'))
	{
		var rowCells = row.childNodes;
		var headerCells = this.headerRow.childNodes;
		if (rowCells.length == headerCells.length)
		{
			for (var i=0;i<headerCells.length;i++)
			{
				if (headerCells[i].style.display=='none')
					rowCells[i].style.display= 'none';
			}
		}
	}
		
		 
	if (this.header) // If there is a header, we know we have a single row, so we can directly append the child row and skip display order handling
		targetNode.appendChild(row)
	else
		DisplayNode.appendChildNode(targetNode,row); 
};

Table.prototype['get<Selected Row>'] = function ()
{
	if (this.selectedRow)
		return this.selectedRow;
	else
		return null;
};
Table.prototype['set<Selected Row>'] = Table.prototype.select = function (row)
{
	//TODO(y) - check that row is a row in this table. Report an error if not.
	if (this.selectedRow)
		this.selectedRow.viewNode.className = this.selectedRow.baseClassName;
	this.selectedRow = row;
	if (row && row.viewNode)
	{
		row.viewNode.className = 'selected';
	}
};
Table.prototype.select.requiresNodes = true;
Table.prototype['get<Sort Order>'] = Table.prototype.getSortOrder = function()
{
	var sortOrder = null;
	var headerCells = this.headerRow.childNodes;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var columnName = headerCell.getAttribute('column_name');
		var sort = headerCell.getAttribute('sort');
		var sortKey = null;
		if (sort == 'up')
		 	sortKey=' ASC';
		else if (sort == 'down')
			sortKey=' DESC';
		if (sortKey)
		{
			if (sortOrder ==null)
				sortOrder = '';
			else
				sortOrder+=', ';
			sortOrder+=columnName;
			sortOrder+=sortKey;
		}
	}
	return sortOrder;
};
Table.prototype['set<Sort Order>'] = function (sort_order)
{
	//TODO: handle conflicts between column order and sort order
	var headerCells = this.headerRow.childNodes;
	var header_cell_map = {};
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var columnName = headerCell.getAttribute('column_name').toLowerCase();
		this.doSortNoFire(headerCell,'none');
		header_cell_map[columnName]=headerCell;
	}
	var result;
	var re = / *([^, ]+)( +([a-z]+))? *(,|$)/gi;
	var prevHeaderCell = null;
	while (result = re.exec(sort_order))
	{
		var columnName = result[1].toLowerCase();
		var dir = result[3];
		dir =  (dir && dir.toLowerCase().charAt(0)=='d') ? 'down' : 'up';
		var headerCell = header_cell_map[columnName];
		this.doSortNoFire(headerCell,dir);
		if (prevHeaderCell)
			this.ensureColumnOrder(prevHeaderCell, headerCell);
		prevHeaderCell = headerCell; 
	};
};
Table.prototype['set<Hidden Columns>'] = function(hidden_cols)
{
	var re = / *([^, ]+) *(,|$)/gi;
	var hidden = this.hiddenColumns;
	for (var columnName in hidden)
		hidden[columnName]=0;
	var result;
	while (result = re.exec(hidden_cols))
	{
		var columnName = result[1].toLowerCase();
		if (hidden[columnName] == null)
		{
			this.hideColumn(columnName);
		}
		else
			hidden[columnName]=1; // Just mark that this column is still hidden
	}
	for (var columnName in hidden)
	{
		if (hidden[columnName] == 0) // was hidden but no longer is
		{
			this.showColumn(columnName);
		}
	}
	this.rebuildColgroup();
};
Table.prototype['remove<Hidden Columns>'] = function()
{
	for (var columnName in this.hiddenColumns)
	{
		this.showColumn(columnName);
	}
	this.rebuildColgroup();

};

Table.prototype['get<Hidden Columns>'] =  function()
{
	var hidden = this.hiddenColumns;
	if (hidden == null)
		hidden = {}; 
	var hiddenCols = null;
	var headerCells = this.headerRow.childNodes;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var columnName = headerCell.getAttribute('column_name');
		if (hidden[columnName.toLowerCase()])
		{
			if (hiddenCols == null)
				hiddenCols = '';
			else
				hiddenCols+=', ';
			hiddenCols+=columnName;
		}
	}
	return hiddenCols;
};
Table.prototype['get<All Columns>'] =  function()
{
	var allCols = null;
	var headerCells = this.headerRow.childNodes;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var columnName = headerCell.getAttribute('column_name');
		if (allCols == null)
			allCols = '';
		else
			allCols+=',';
		allCols+=columnName;
	}
	return allCols;
};

Table.prototype.hideColumn = function(columnName)
{
	this.hiddenColumns[columnName] = 1;
	var headerCells = this.headerRow.childNodes;
	var rows = this.viewNode.rows;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		if ( columnName == headerCell.getAttribute('column_name').toLowerCase() )
		{
			var cw = getVisibleSize(headerCell).width;
			headerCell.col.style.width = cw + 'px';
			if (this.viewNode.style.width)
			{
				var originalWidth = parseInt(this.viewNode.style.width);
				this.viewNode.style.width = (originalWidth-cw) + 'px';
			}
			headerCell.style.display='none';
			if (this.colgroup == headerCell.col.parentNode)
				this.colgroup.removeChild(headerCell.col);
			for (var j=0;j<rows.length; j++)
			{
				var rowCells = 	rows[j].childNodes;
				rowCells[i].style.display = 'none';
			}
		}
	}
	
};
Table.prototype.showColumn = function(columnName)
{
	delete this.hiddenColumns[columnName];
	var headerCells = this.headerRow.childNodes;
	var rows = this.viewNode.rows;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		if ( columnName == headerCell.getAttribute('column_name').toLowerCase() )
		{
			if (this.viewNode.style.width)
			{
				var cw = parseInt(headerCell.col.style.width);
				if (cw)
				{
					var originalWidth = parseInt(this.viewNode.style.width);
					this.viewNode.style.width = (originalWidth+cw) + 'px';
				}
			}
			else
				headerCell.col.style.width='';
			headerCell.style.display='';
			for (var j=0;j<rows.length; j++)
			{
				var rowCells = 	rows[j].childNodes;
				rowCells[i].style.display = '';
			}
		}
	}
}
Table.prototype.setColWidths = function()
{
	var headerCells = this.headerRow.childNodes;
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var c = headerCell.col;
		if (headerCell.style.display!='none')
		{
			c.style.width=getActualStyle(headerCell,'width');
		}
	}

};
Table.prototype.rebuildColgroup = function()
{
	var headerCells = this.headerRow.childNodes;
	var cg = this.colgroup;
	var w= [];
	var cc = [];
	for (var i=0;i<headerCells.length;i++)
	{
		var headerCell = headerCells[i];
		var c = headerCell.col;
		if (cg == c.parentNode)
			cg.removeChild(c);
		if (headerCell.style.display!='none')
		{
			cg.appendChild(c);
		}
	}
//	this.currentWindow.setTimeout(function(){for (var i=0;i<w.length;i++) cc[i].style.width=w[i];},2000);
};	
Table.prototype.ensureColumnOrder = function (cell1, cell2) // ensures that cell2 is not before cell1
{
	var allSiblings = cell1.parentNode.childNodes;
	var i1=-1;
	var i2=-1;
	for (var i=0;i<allSiblings.length;i++)
	{
		if (allSiblings[i] == cell1)
			i1 = i;
		if (allSiblings[i] == cell2)
			i2 = i;
	}
	if (i2 < i1) // rearrage columns in the table so that cell2 appears right after cell1
	{
		this.moveCells(i2,i1+1);
	};
};
Table.isResizeLeft = function(e,headerCell)
{
	var offsets = getScreenPosition(headerCell);
	var win = getParentWindow(headerCell);
	var p = getEventPosition(win,e);
	return (p.x <= offsets.left +5);
};
Table.isResizeRight = function(e,headerCell)
{
	var offsets = getScreenPosition(headerCell);
	var size = getVisibleSize(headerCell);
	var win = getParentWindow(headerCell);
	var p = getEventPosition(win,e);
	return (p.x >= offsets.left + size.width -5);
};
Table.isResize = function(e, headerCell)
{
	return Table.isResizeRight(e,headerCell)
	 || headerCell.previousSibling && Table.isResizeLeft(e,headerCell);
};
Table.headerClicked = function(e)
{
	if (! Table.isResize(e,this))
	{
		var tableViewNode = this.parentNode.parentNode.parentNode;
		var tableNode = DisplayNode.findNodeForDocumentNode(tableViewNode);
		if (!tableNode)
			return;
		var win = tableNode.currentWindow;
		if (! getEventPosition(win,e).equals(tableNode.mouseDownPosition))
			return; // Ignore click if it's part of a drag operation
		var sort = this.getAttribute('sort');
		if (sort == 'up')
			tableNode.doSort(this,'down');
		else if (sort == 'down')
			tableNode.doSort(this,'none');
		else
			tableNode.doSort(this, 'up');
	}
};
Table.prototype.doSortNoFire = function(headerCell,dir)
{
	headerCell.setAttribute('sort',dir);
	headerCell.className = 'sort_'+dir;
};
Table.prototype.doSort = function(headerCell, dir)
{
	this.doSortNoFire(headerCell,dir);
	this.fireOnSort();
}
Table.prototype.fireOnSort = function()
{
	this.mainWindow.engine.handleEvent(this, Events.ON_SORT);
};
Table.mouseDownOnHeader = function(e)
{
	var tableViewNode = this.parentNode.parentNode.parentNode;
	var tableNode = DisplayNode.findNodeForDocumentNode(tableViewNode);
	if (!tableNode)
		return;
	var offsets = getScreenPosition(this);
	var size = getVisibleSize(this);
	var win = tableNode.currentWindow;
	clearSelection(win);
	tableNode.mouseDownPosition  = getEventPosition(win,e);
	if (Table.isResizeLeft(e,this))
	{
		var previousCell = this.previousSibling;
		if (previousCell)
			tableNode.beginResize(e,previousCell);
	}
	else if (Table.isResizeRight(e,this))
		tableNode.beginResize(e,this);
	else
		tableNode.beginReorder(e,this);
};
Table.finishDrag = function (e)
{
	var table=tersus.findNode(this.documentElement.getAttribute('tableId'));
	this.documentElement.setAttribute('tableId', null);
	this.onmouseup = null;
	this.onmousemove = null;
	table.viewNode.className=table.baseClassName;
};
Table.updateHeaderCursor = function (e)
{
	var tableId = this.ownerDocument.documentElement.getAttribute('tableId');
	var table = null;
	if (tableId)
		table=tersus.findNode(tableId);
	if (table && table.reorder)
		this.style.cursor='';
	else
	{
		if (Table.isResize(e,this))
		{
			this.style.cursor='e-resize';
		}
		else if (this.getAttribute('sort'))
			this.style.cursor='pointer';
		else
			this.style.cursor='';
	}
};
Table.performResize = function (e)
{
	var table=tersus.findNode(this.documentElement.getAttribute('tableId'));
	var win = table.currentWindow;
	clearSelection(win);
	var currentPosition = getEventPosition(win,e);
	var delta = {};
	delta.x = currentPosition.x - table.lastPosition.x;
	delta.y = currentPosition.y - table.lastPosition.y;
	table.lastPosition = currentPosition;		
	table.resize(delta);
};
Table.prototype.beginResize = function beginResize(e, headerCell)
{
	this.setColWidths();
	var table = this;
	var win = this.currentWindow;
	clearSelection(win);
	var doc = win.document;
	doc.documentElement.setAttribute('tableId', this.getNodeId());
	table.lastPosition = getEventPosition(win, e);
	table.viewNode.className+=' resizing';
	table.resizingHeaderCell = headerCell;
	table.currentColWidth = getVisibleSize(headerCell).width;
	table.currentTableWidth = getVisibleSize(table.viewNode).width;
	doc.onmousemove = Table.performResize;
	doc.onmouseup = Table.finishDrag;
};
Table.prototype.beginReorder = function beginReorder(e, headerCell)
{
	var table = this;
	var win = this.currentWindow;
	clearSelection(win);
	var doc = win.document;
	var feedback = doc.createElement('div');
	feedback.className='drag_feedback';
	doc.documentElement.setAttribute('tableId', this.getNodeId());
	table.reorder = {};
	table.reorder.feedback =feedback;
	table.reorder.headerCell = headerCell;
	table.reorder.startPosition = getEventPosition(win,e);;
	
	doc.onmousemove = Table.feedbackReorder;
	doc.onmouseup = Table.finishReorder;
};

Table.prototype.cancelReorder = function()
{
	if (! this.reorder)
		return;
	if (this.reorder.feedback.parentNode)
		this.reorder.feedback.parentNode.removeChild(this.reorder.feedback);
	this.reorder = null;
	var doc = this.currentWindow.document;
	doc.documentElement.setAttribute('tableId', null);
	doc.onmouseup = null;
	doc.onmousemove = null;
};
Table.finishReorder = function (e)
{
	var table=tersus.findNode(this.documentElement.getAttribute('tableId'));
	if (! table.reorder)
		return;
	var win = table.currentWindow;
	clearSelection(win);
	var headerCell = table.reorder.headerCell;
	var startX = table.reorder.startPosition.x;
	table.cancelReorder();
	var p = getEventPosition(win,e);
	var fromIndex=-1;
	var toIndex =-1;
	if (p.x != startX)
	{
		var headerCells =headerCell.parentNode.childNodes;
		for (var i=0;i<headerCells.length; i++)
		{
			var cell = headerCells[i];
			if (cell.style.display=='none')
				continue;
			if (cell == headerCell)
				fromIndex = i;
			else if (toIndex < 0)
			{
				var left = getScreenPosition(cell).left;
				var width = getVisibleSize(cell).width;
				if (p.x >= left && p.x <left+width)
				{ 
					if (p.x > left+width/2 )
					{
						toIndex = i+1;
					}
					else
						toIndex = i;
				}
			}
		}
		if (toIndex != -1 && toIndex != fromIndex && toIndex != fromIndex+1)
		{
			var originalSortOrder = table.getSortOrder();
			table.moveCells(fromIndex,toIndex);
			var newSortOrder = table.getSortOrder();
			if (originalSortOrder != newSortOrder)
			{
				table.fireOnSort();
			}
		}
	}
};
Table.move = function (parent, from, to)
{
	var children = parent.childNodes;
	var childFrom = children[from];
	var childTo = null;
	if (to < children.length)
	{
		childTo = children[to];
	}
	parent.insertBefore(childFrom,childTo);
};
Array.prototype.moveItem = function(fromIndex,toIndex)
{
	var item=this.splice(fromIndex,1)[0]; 
	var newIndex = (fromIndex<toIndex) ? toIndex-1: toIndex;
	this.splice(newIndex,0, item);
};
Table.prototype.moveCells = function (fromIndex,toIndex)
{
	this.reorderColGroup(fromIndex, toIndex);
	var rows = this.viewNode.rows;
	for (var i=0;i<rows.length; i++)
		Table.move(rows[i],fromIndex, toIndex);

	//Update the 'colOrder' permutation		
	if (!this.colOrder)
	{
		this.colOrder = [];
		for (var i=0;i<this.headerRow.childNodes.length;i++)
		{
			this.colOrder.push(i);
		}
	}
	this.colOrder.moveItem(fromIndex,toIndex);
};
Table.prototype.reorderColGroup = function(fromIndex, toIndex)
{
	// Since there are no 'col' elements for hidden columns, we need to correct the indices
	var headerCells  = this.headerRow.childNodes;
	var from = fromIndex;
	var to = toIndex;
	for (var i=0;i<headerCells.length;i++)
	{
		var c = headerCells[i];
		if (c.style.display == 'none')
		{
			if (i<=fromIndex)
				--from;
			if (i<=toIndex)
				--to;
		}
	}
	Table.move(this.colgroup, from, to);
};
Table.feedbackReorder = function (e)
{
	var table=tersus.findNode(this.documentElement.getAttribute('tableId'));
	var win = table.currentWindow;
	clearSelection(win);
	var headerCell = table.reorder.headerCell;
	var headerCellSize = getVisibleSize(headerCell);
	var p = getEventPosition(win,e);
	var o = getScreenPosition(table.viewNode);
	var w = getVisibleSize(table.viewNode).width;
	var h = getVisibleSize(table.viewNode).height;
	if( p.y<o.top || p.y > o.top+h || p.x<o.left || p.x > o.left + w)
	{
		table.cancelReorder();
		return;
	}
	
	var feedback = table.reorder.feedback;
	var body = win.document.body;
	if (!feedback.parentNode )
	{
		body.appendChild(feedback);
		feedback.innerHTML = headerCell.innerHTML;
		tersus.async.exec(function()
		{
			feedback.style.width=headerCellSize.width;
			feedback.style.height=headerCellSize.height;
			var d= (window.browser == 'Mozilla')?-2:0;
			feedback.style.top=(getScreenPosition(headerCell).top+d)+body.scrollTop;
			feedback.style.left=p.x+body.scrollLeft;
		}, false /* don't wait */)
	}
	else
	{
		table.reorder.feedback.style.left=p.x+body.scrollLeft;
	}
};
Table.prototype.resize = function(delta)
{
	this.currentColWidth += delta.x;
	this.currentTableWidth += delta.x;
	var table = this;
	setTimeout(function() {table.resizingHeaderCell.col.style.width = table.currentColWidth+'px';table.viewNode.style.width=table.currentTableWidth},10);
};
// file: 120-Row.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Row() {};
Row.prototype = new DisplayNode();
Row.prototype.constructor = Row;
Row.prototype.defaultTag = 'tr';
Row.prototype.attachViewNode = function Row_createViewNode()
{
	this.setDisplayOrder();
	if (this.parent.viewNode.tagName != 'TABLE')
	{
		this.tableNode  = this.createHTMLElement('table');
		this.tbodyNode = this.createHTMLElement('tbody');
		this.tableNode.setAttribute('display_order',this.viewNode.getAttribute('display_order'));
		this.tableNode.appendChild(this.tbodyNode);
		this.tbodyNode.appendChild(this.viewNode);
		if(this.sharedProperties.width != undefined && this.sharedProperties.width != ' ')
			this.tableNode.style.width = this.sharedProperties.width;
		if (this.sharedProperties.styleClass != undefined && this.sharedProperties.styleClass != ' ')
			this.tableNode.className = this.sharedProperties.styleClass;
		else if (this.defaultStyleClass)
			this.tableNode.className = this.defaultStyleClass;
			
		var rowNode = this.viewNode;
		
		// We temporarily set the view node to the table node, because this is the node
		// we want to append to the parent
		
		// This is not very clean, and it would have probably have been more elegant
		// if we distinguished between 'contentNode' and 'viewNode', but this refactoring is currently 
		// out of scope, especially because we'll have to decide what to do with
		// things like style class etc. (which currently apply to the content node)
		// We have to be careful with backward compatability.
		
		// We DON'T simply append our table to the parent view node, because the parent node
		// may have special logic in appendChildViewNode - specifically - we want to retain the behavior of DisplayGroup.

		this.viewNode = this.tableNode;
		this.parent.appendChildViewNode(this);
		this.viewNode = rowNode;		
	}
	else
	{
		this.parent.appendChildViewNode(this);
	}
	if (this.parent.sharedProperties.zebraTable == true)
	{
		var v = this.viewNode;
		var parity = v.parentNode.childNodes.length & 1;
		var cn = v.className;
		cn = cn ? cn : '';
		this.extraClassName =  (parity ? ' odd':' even');
		v.className = cn + this.extraClassName; 
	}
}
Row.prototype.setEventHandlers = function Row_setEventHandlers()
{
	DisplayNode.prototype.setEventHandlers.call(this);

	if (this.isSelectable())	
		this.registerEventHandler(Events.ON_CLICK);	
};
Row.prototype.isSelectable = function()
{
	return this.sharedProperties.selectable==true || this.parent.sharedProperties.selectable==true; 
}
Row.prototype.select = function()
{
	if (this.isSelectable())
	{
		var table = this.parent;
		table.select(this);
	}
};
Row.prototype.onClick = function (domNode)
{
	this.select();
	DisplayNode.prototype.onClick.call(this,domNode);
};
Row.prototype.onChildFocus = function (child)
{
	this.select();	
};
Row.prototype.onDelete = function ()
{
	DisplayNode.prototype.onDelete.call(this);
	if (this.parent.selectedRow == this)
		this.parent.selectedRow = null;
};
Row.prototype.removeChildViewNode = function removeChildViewNode(child)
{
	var c = child.viewNode;
	var p = this.viewNode;
	if (c.parentNode == p) // c is a cell (TD or TH)
		p.removeChild(c);
	else if (p == c.parentNode.parentNode) // c is wrapped in a cell
		p.removeChild(c.parentNode);
};

Row.prototype.appendChildViewNode = function appendChildViewNode(child, childElement)
{
	if (!childElement)
		childElement = child.element;
	var cellNode;
	if (child.viewNode.tagName == 'TD' || child.viewNode.tagName == 'TH')
		cellNode = child.viewNode;
	else
	{
		var cellNode = this.createHTMLElement('td');
		cellNode.setAttribute('display_order',child.viewNode.getAttribute('display_order'));
		cellNode.appendChild(child.viewNode);
	}
	if (child.element && child.element.properties)
	{
		var elementProperties = child.element.properties;
		if (tersus.isNumber(elementProperties.colSpan))
			cellNode.colSpan = elementProperties.colSpan;
		if (tersus.isNumber(elementProperties.rowSpan))
			cellNode.rowSpan = elementProperties.rowSpan;
		if (tersus.notEmpty(elementProperties.cellWidth))
			cellNode.style.width=elementProperties.cellWidth;
		if (elementProperties.cellStyleClass && elementProperties.cellStyleClass != ' ')
			cellNode.className=elementProperties.cellStyleClass;
	}
	if (child.colSpan)
		cellNode.colSpan = child.colSpan;
	DisplayNode.appendChildNode(this.viewNode,cellNode);
	if (cellNode.parentNode.childNodes.length == 1)
	{
		var c = cellNode.className;
		c = c + ' first';
		cellNode.className=c;
		if (cellNode == child.viewNode)
		{
			child.baseClassName = cellNode.className;
			child.extraClassName = ' first';
		}
	}
	var p = this.parent;
	if (p.applyColOrder && p.headerRow && this.viewNode.childNodes.length == p.headerRow.childNodes.length)
	{
		p.applyColOrder(this.viewNode);
	}
	if (p.hiddenColumns != null && p.hiddenColumns[p.columnNames[childElement.role]] != null)
		cellNode.style.display='none';
};

Row.prototype.deleteMe = function()
{
	DisplayNode.prototype.deleteMe.call(this);
	if (this.parent && this.parent.selectedRow == this)
		this.parent.selectedRow = null;
};// file: 130-Popup.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
//Popup - opens a pop-up window

function Popup() {};
Popup.prototype = new DisplayNode();
Popup.prototype.constructor = Popup;
Popup.prototype.create = function create()
{
	alert('Popup '+this.element.role+' created');
};
Popup.WAITING_TO_POP_UP = 'Waiting to pop-up';
Popup.POPPED_UP = 'Popped-up';
Popup.prototype.isPopup = true;
Popup.prototype.start = function()
{
	this.popupStatus = Popup.WAITING_TO_POP_UP;
	tersus.popupNodes[this.getNodeId()]=this;
	this.pause(); // Processing will start once the pop up loads
	this.currentWindow = this.createWindow();
	tersus.registerWindow(this.currentWindow);
	if (! this.currentWindow)
	{
		alert('Your browser blocks pop-up windows.\nTo use this application, please configure the browser to allow this site to open pop-up windows.');
		return;
	}
	this.currentWindow.focus();
}
Popup.prototype.findById = function popup_FindById(id, alreadyScanned)
{
	//Traverse the popup only if its window is open
	if (this.currentWindow && ! this.currentWindow.closed)
		return tersus.Node.prototype.findById.call(this,id, alreadyScanned);
	else
		return null;
};

// resume() is overriden to support the initial pause while waiting for the popup to pop)
Popup.prototype.resume = function resumePopup()
{
	if (this.popupStatus == Popup.WAITING_TO_POP_UP)
	{
		this.popupStatus = Popup.POPPED_UP;
		this.currentWindow.currentRootDisplayNode = this;
		this.currentWindow.focus();
		tersus.createEventDispatchers(this.currentWindow);
		this.setViewNode();
		this.createChildren();
		FlowNode.prototype.start.call(this);
		var node = this;
		this.currentWindow.setTimeout(function(){node.focusOnFirstField();}, 100);
	}
	else
	{
		this.runLoop();
	}
};
Popup.prototype.getPopupTitle = function getPopupTitle()
{
	return this.getCaption();
};

Popup.prototype.setTitle = function()
{
	try
	{
		if (this.currentWindow && ! this.currentWindow.closed)
		{
			this.currentWindow.document.title = this.getPopupTitle();
			if (this.header)
				this.header.innerHTML = tersus.escapeHTML(this.getPopupTitle());
		}	
	}
	catch (e)
	{
	}
};
Popup.prototype.captionChanged = Popup.prototype.setTitle;
Popup.prototype.setViewNode = function setViewNode()
{
	this.viewNode = this.currentWindow.document.getElementById('dialogBody');	
	if (this.viewNode)
	{
		this.header = this.currentWindow.document.getElementById('dialogHeader');
		this.footer = this.currentWindow.document.getElementById('dialogFooter');
	}
	else
	{
		this.viewNode = this.currentWindow.document.getElementById('root');	
		if (! this.viewNode)
			this.viewNode = this.currentWindow.document.body;
	}
	this.setTitle();
	var nodeId = this.getNodeId();
	this.isOpen = true;
	this.onResize();
};
Popup.prototype.templateURL = 'popup.html';
Popup.prototype.createWindow = function Popup_createWindow(){
	if (this.sprop('templateURL'))
		this.templateURL = this.sprop('templateURL');
	
	var options = this.sharedProperties.windowOptions;
	if (! options)
		options = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes';
	var w = this.sharedProperties.windowWidth;
	if ( ! w || w == ' ')
		w = 350;
	var h = this.sharedProperties.windowHeight;
	if (! h || h == ' ')
		h = 265;
	var leftPx = parseInt((screen.availWidth-w-10)/2);
	var topPx = parseInt((screen.availHeight-h-30)/2);
	if (leftPx<0) leftPx=0;
	if (topPx<0) topPx=0;
	var targetWindow = this.getTargetWindow();
	var skeletonURL = tersus.rootURL+this.templateURL+'?nodeId='+this.getNodeId();
	this.currentWindow.mainTersusWindow = this.mainWindow;
	var popup = this.currentWindow.open(skeletonURL,targetWindow,"top="+topPx+",left="+leftPx+",width=" + w + ",height=" + h+","+options); 
	return popup;
};

Popup.prototype.getTargetWindow = function getTargetWindow()
{
	//TODO support mutltipe popup windows
	if (this.sharedProperties.targetWindow && this.sharedProperties.targetWindow!=' ')
		return this.sharedProperties.targetWindow;
	else if (this.currentWindow == this.mainWindow)
		return "popup";
	else
		return this.currentWindow.name+"_popup";
};
Popup.prototype.destroy = function()
{
	if (! this.isDestroyed)
	{
		this.isDestroyed = true;
		DisplayNode.prototype.destroy.call(this);
		this.doClose();
	}
};
Popup.prototype.closeWindow = function() 
{
	this.destroyHierarchy();
};
Popup.prototype.doClose = function ()
{
	delete tersus.popupNodes[this.getNodeId()];
	tersus.unregisterWindow(this.currentWindow);
	if (this.currentWindow && ! this.currentWindow.closed)
		this.currentWindow.close();
	this.isOpen = false;
	this.viewNode = null;
	this.footer = null;
	this.header = null;
};

Popup.prototype.onResize = function()
{
	if (! (this.isOpen && this.currentWindow && ! this.currentWindow.closed))
		return;
	var d = this.viewNode.ownerDocument;
		
	var height = getVisibleSize(d.body).height;
	var margins = parseInt(getActualStyle(d.body,'margin-top'))+parseInt(getActualStyle(d.body,'margin-bottom'));
	height-=margins;

	var delta = getHeight(d.getElementById('root')) - getHeight(this.viewNode);
	if (window.browser != 'IE')
	{
		var paddingBottom = parseInt(getActualStyle(this.viewNode,'padding-bottom'));
		var paddingTop = parseInt(getActualStyle(this.viewNode,'padding-top'));
		delta += (paddingBottom + paddingTop);
	}
	else
	{
		delta+= 10; // Some extra padding needed on IE
	}
	delta +=10; // without this patch the scrollbar appears with no need - at least on Firefox
	if (tersus.isIPhoneSafari && height < 300) // for some reason we need to adjust the hieght further when working in Horizontal mode
		delta+=15
	if (height-delta > 0)
		this.viewNode.style.height = height-delta;
	this.onResizeChildren();
};
Popup.prototype.getValidationContext = function Popup_getValidationContext()
{
	return this;
};
Popup.prototype.computedReadOnly = function Popup_computedReadOnly()
{
	return this.explicitReadOnly;
};
Popup.prototype.parentReadOnlyChanged = function Popup_parentReadOnlyChanged(readOnly)
{
};
// file: 131-Popin.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.PopIn = function tersus_PopIn(){};
tersus.PopIn.prototype = new Popup();
tersus.PopIn.prototype.constructor = tersus.PopIn;
tersus.PopIn.prototype.isPopIn = true;
tersus.PopIn.prototype.templateURL='popin.html';
tersus.PopIn.prototype.onload = function()
{
	if (this.sprop('templateURL'))
		this.templateURL = this.sprop('templateURL');
	tersus.repository.loadHTMLTemplate(this.templateURL);
};

tersus.PopIn.prototype.create = function () {
	alert('Pop-in created');
}
tersus.PopIn.prototype.getCurrentRootViewNode = function()
{
	var root;
	var doc = this.currentWindow.document;
	root = doc.getElementById('root');
	if (! root)
		root = doc.getElementById('tersus.content');
	return root;
};
tersus.PopIn.prototype.createViewNode = function() 
{
	var w = this.currentWindow;
	var doc = w.document;
	clearSelection(w);
	this.originalTitle = doc.title;
	this.originalRoot = this.getCurrentRootViewNode();
	this.originalRootDisplayNode = w.currentRootDisplayNode;
	w.currentRootDisplayNode = this;
	var template = tersus.repository.getHTMLTemplate(this.templateURL);
	var newRoot = importNode(doc,template);
	newRoot.id = 'root';
	this.originalRoot.parentNode.replaceChild(newRoot, this.originalRoot);
	this.originalBodyStyle = doc.body.className;
	if (this.originalBodyStyle == '')
		doc.body.className = 'popin';
	else if (! this.originalBodyStyle.match(/popin/))
		doc.body.className='popin '+this.originalBodyStyle;
	this.setViewNode();
};
tersus.PopIn.prototype.disableNavigation = function()
{
	this.previousFixedURL  = tersus.history.fixedURL;
	if (this.sharedProperties.disableNavigation != false)
	{
		tersus.history.fixedURL = window.location.href;
	}
	else
		tersus.history.fixedURL = null;
	
	
};

tersus.PopIn.prototype.resumeNavigation = function()
{
	tersus.history.fixedURL = this.previousFixedURL;
};

tersus.PopIn.prototype.doClose = function()
{
	delete tersus.popupNodes[this.getNodeId()];
	
	if (this.isOpen)
	{
		this.resumeNavigation();
		var doc = this.currentWindow.document;
		var currentRoot = doc.getElementById('root');
		currentRoot.parentNode.replaceChild(this.originalRoot, currentRoot);
		doc.title = this.originalTitle;
		doc.body.className=this.originalBodyStyle;
		this.currentWindow.currentRootDisplayNode = this.originalRootDisplayNode;
		this.viewNode = null;
		this.footer = null;
		this.header = null;
		
	}
	this.isOpen = false;
};

tersus.PopIn.prototype.start = function()
{
	tersus.popupNodes[this.getNodeId()]=this;
	this.disableNavigation();
	this.createViewNode();
	this.initViewNode();
	this.createChildren();
	this.isOpen = true;
	FlowNode.prototype.start.call(this);
	var node = this;
	if (tersus.isIPhone)
		window.scrollTo(0,1);
	var activeElement = this.currentWindow.document.activeElement;

	// Remove focus to prevent selection from "smearing" into popin.  Do not blur BODY as in IE7 it causes the browser window to be pushed back
	if (activeElement && activeElement.blur && activeElement.tagName != 'BODY')
		activeElement.blur();
	this.currentWindow.setTimeout(function(){node.focusOnFirstField();}, 100);
	
};
tersus.PopIn.prototype.findById = function tersus_popIn_FindById(id, alreadyScanned)
{
	//Traverse the popup only if its window is open
	if (this.isOpen)
		return tersus.Node.prototype.findById.call(this,id, alreadyScanned);
	else
		return null;
};
// file: 140-Pane.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Pane() {};
Pane.prototype = new DisplayNode();
Pane.prototype.constructor = Pane;
Pane.prototype.defaultTag = 'div';
Pane.prototype.minHeight = 50;
Pane.prototype.setHeight = function(newHeight)
{
	this.viewNode.style.height = newHeight;
};
Pane.prototype.adjustBottom = function()
{
	var d = this.viewNode.ownerDocument;
	var body = this.viewNode.ownerDocument.body;
	var height = getVisibleSize(body).height;
	var margins = parseInt(getActualStyle(body,'margin-top'))+parseInt(getActualStyle(body,'margin-bottom'));
	height-=margins;

	var currentHeight = getVisibleSize(this.viewNode).height;
	var currentBottom = getOffsets(this.viewNode).top + currentHeight;
	if (window.browser != 'IE')
	{
		var paddingBottom = parseInt(getActualStyle(this.viewNode,'padding-bottom'));
		var paddingTop = parseInt(getActualStyle(this.viewNode,'padding-top'));
		currentBottom += paddingBottom + paddingTop;
	}
	
	var bottomMargin = tersus.isNumber(this.sharedProperties.adjustBottomMargin) ? parseInt(this.sharedProperties.adjustBottomMargin) :0;
	var delta = height-currentBottom - bottomMargin;
	
	if (delta+currentHeight >= this.minHeight)
		this.adjustHeight(delta);
};
Pane.prototype.adjustHeight = function(delta)
{
	tersus.adjustHeight(this.viewNode, delta);
};

Pane.prototype.setProperties = function()
{
	DisplayNode.prototype.setProperties.call(this);
	var pane = this;
	if (this.sharedProperties.adjustBottom == true)
		tersus.async.exec(function() {pane.onResize();}, false /* don't wait */);
};
Pane.prototype.onResize = function()
{
	if (this.sharedProperties.adjustBottom == true)
		this.adjustBottom();
	this.onResizeChildren();
};// file: 150-DisplayGroup.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DisplayGroup = function () {};
tersus.DisplayGroup.prototype = new DisplayNode();
tersus.DisplayGroup.prototype.constructor = tersus.DisplayGroup;
tersus.DisplayGroup.prototype.isDisplayGroup = true;
tersus.DisplayGroup.prototype.createViewNode = function ()
{
	
};
tersus.DisplayGroup.prototype.initViewNode = function ()
{
	
};
tersus.DisplayGroup.prototype.attachViewNode = function ()
{
	this.viewNode = this.parent.viewNode;
};
tersus.DisplayGroup.prototype.removeChildViewNode = function (child)
{
	if (this.parent)
		this.parent.removeChildViewNode(child);
};
tersus.DisplayGroup.prototype.addChildHTMLPrefix = function (htmlV, child)
{
	if (this.parent)
		this.parent.addChildHTMLPrefix(htmlV,child);
};
tersus.DisplayGroup.prototype.addChildHTMLSuffix = function (htmlV, child)
{
	if (this.parent)
		this.parent.addChildHTMLSuffix(htmlV,child);
}
tersus.DisplayGroup.prototype.appendChildViewNode = function (child)
{
	var displayOrder = this.element.displayOrder + child.viewNode.getAttribute('display_order')*0.01;
	child.viewNode.setAttribute('display_order',displayOrder);
	this.parent.appendChildViewNode(child,this.element);
	child.refreshVisibility();
};
tersus.DisplayGroup.prototype.refreshVisibility = function ()
{
	this.forDisplayChildren( function(child) {child.refreshVisibility();});
};

tersus.DisplayGroup.prototype.isGroup = true;
tersus.DisplayGroup.prototype.onDelete = function()
{
	this.forDisplayChildren( function(child) {child.onDelete();});
};
tersus.DisplayGroup.prototype.applyColOrder = function(row)
{
	if (this.parent.applyColOrder)
		this.parent.applyColOrder(row);
};
// file: 160-PushButton.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.PushButton = function (){};
tersus.PushButton.prototype = new DisplayNode();
tersus.PushButton.prototype.defaultTag = 'span';
tersus.PushButton.prototype.getButtonName = function ()
{
	return null;
};
tersus.PushButton.prototype.initViewNode = function tersus_PushButton_initViewNode()
{
    DisplayNode.prototype.initViewNode.call(this);
    this.updateSelfReadOnly(this.computedReadOnly());
};

tersus.PushButton.prototype.createViewNode = function ()
{
    var name = this.getButtonName();
    if (name != null)
    {
    	if (window.browser == 'IE')
	    	this.button = this.currentWindow.document.createElement('<input name="'+name+'">');
	    else
	    {
	    	this.button = this.createHTMLElement('input');
	    	this.button.name = name;
	    }
	}
    else
    	this.button = this.createHTMLElement('input');
    this.button.type = this.buttonType;
    this.button.className=this.buttonType;
    if (this.getElement('<Caption>'))
    {
    	DisplayNode.prototype.createViewNode.call(this);
    	this.viewNode.appendChild(this.button);
    	this.label = this.createHTMLElement('span',this.buttonType+'Label');
    	this.label.innerHTML = tersus.escapeHTML(this.getCaption());
    	this.viewNode.appendChild(this.label);
    }
    else
    	this.viewNode = this.button;
};
tersus.PushButton.prototype.getChecked = tersus.PushButton.prototype['get<Checked>'] = function ()
{
	if (this.viewNode)
		return this.button.checked;
};
tersus.PushButton.prototype.setChecked = tersus.PushButton.prototype['set<Checked>'] = function (value)
{
	if (this.viewNode)
		this.button.checked = value;
	if (window.browser=='IE')
	{
		// In IE 6.0, setting 'checked' before the button is rendered 
		// has no visual effect
		var button = this.button;
		tersus.async.exec(function(){ button.checked = value;}, false /* don't wait */);
	}
};
tersus.PushButton.prototype['remove<Checked>'] = function ()
{
	if (this.viewNode)
		this.button.checked = false;
};
tersus.PushButton.prototype.setEventHandlers = function()
{
	this.registerEventHandler(Events.ON_CLICK, this.button);
	if (this.label)
		this.registerEventHandler(Events.ON_CLICK, this.label);
};

tersus.PushButton.prototype.onClick = function(domNode)
{
	if (domNode == this.button)
	{
		DisplayNode.prototype.onClick.call(this);
		this.onChange();
	}
	else if (domNode == this.label)
		this.labelClicked();
};

tersus.PushButton.prototype.captionChanged = function()
{
	if (this.label)
		this.label.innerHTML = tersus.escapeHTML(this.getCaption());
};
tersus.PushButton.prototype.updateSelfReadOnly = function tersus_PushButton_updateSelfOnly(readOnly)
{
	if (this.currentReadOnly == readOnly)
		return; // no change
	this.currentReadOnly = readOnly;
	if (this.button)
	{
		if (readOnly)
		{
			this.button.disabled = true;
		}
		else
			this.button.disabled = false;
	}
};
// file: 170-SplitPane.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function SplitPane() {};
SplitPane.prototype = new DisplayNode();
SplitPane.prototype.constructor = SplitPane;
SplitPane.prototype.defaultTag = 'div';
SplitPane.prototype.defaultStyleClass = 'splitPane';
SplitPane.prototype.height=400;
SplitPane.prototype.minWidth=50;
SplitPane.prototype.leftWidth = 200;
SplitPane.prototype.borderWidth=1;
SplitPane.prototype.paddingWidth=5;
SplitPane.prototype.dividerThickness=5;
SplitPane.prototype.contentPaneStyle = "splitPaneContent";
SplitPane.prototype.dividerStyle = "splitPaneDivider";
SplitPane.prototype.setDimensions = function()
{
	if (this.sharedProperties.height)
		this.height =parseInt(this.sharedProperties.height);
	this.setHeight(this.height);
	this.divider.style.width = this.dividerThickness;
	if (this.sharedProperties.leftPaneWidth)
	{
		this.leftWidth=parseInt(this.sharedProperties.leftPaneWidth);
	}
	
};
SplitPane.prototype.setHeight = function(height)
{
	this.height = height;
	this.viewNode.style.height = '';
	this.pane1.style.height = '';
	this.pane2.style.height = '';
	this.viewNode.style.height = this.height;
	this.setPaneHeight(this.pane1,this.height);
	this.setPaneHeight(this.pane2,this.height);
	this.divider.style.height = this.height;
};
SplitPane.prototype.createViewNode = function createViewNode()
{
	DisplayNode.prototype.createViewNode.call(this);
	if (this.sharedProperties.paddingWidth)
		this.paddingWidth =parseInt(this.sharedProperties.paddingWidth);
	if (this.sharedProperties.borderWidth)
		this.borderWidth =parseInt(this.sharedProperties.borderWidth);
	this.viewNode.style.borderWidth = this.borderWidth;
	
	this.pane1 = this.createHTMLElement('div');
	this.pane2 = this.createHTMLElement('div');
	this.divider = this.createHTMLElement('div');
	this.direction = getActualStyle(this.currentWindow.document.body, 'direction');
	this.setPaneProperties(this.pane1);
	this.setPaneProperties(this.pane2);
	this.divider.className = this.dividerStyle;
	if (this.direction == 'rtl')
		this.divider.className+=' rtl';
	
	this.divider.setAttribute('SplitPaneId', this.getNodeId());
	this.setDimensions();
	this.attachContent();
	var splitPane = this;
	this.divider.onmousedown = SplitPane.beginDrag;
	tersus.async.exec( function() {splitPane.onResize();}, false /* don't wait */);
};

SplitPane.prototype.reset = function reset()
{
	DisplayNode.prototype.reset.call(this);
	this.pane1 = null;
	this.pane2 = null;
	this.viewNode.innerHTML='';
};
SplitPane.prototype.appendChildViewNode = function appendChildViewNode(child)
{
	if (! this.leftPaneContent)
	{
		this.leftPaneContent = child.viewNode;
		this.pane1.appendChild(this.leftPaneContent);
	}
	else if (! this.rightPaneConent)
	{
		this.rightPaneContent = child.viewNode;
		this.pane2.appendChild(this.rightPaneContent);
	}
	else
		modelError('More than 2 child nodes in '+this.modelId + ' (path = '+this.getPath()+')');
	
};
SplitPane.prototype.setPaneProperties = function setPaneProperties(pane, width)
{
		pane.className=this.contentPaneStyle;
		if (this.direction == 'rtl')
			pane.className+=' rtl';
		
		pane.style.padding = this.paddingWidth;

};
SplitPane.prototype.detachContent = function detachContent()
{
	if (this.contentAttached)
	{
		this.contentAttached = false;
		if (this.pane1.parentNode == this.viewNode)
			this.viewNode.removeChild(this.pane1);
		if (this.divider.parentNode == this.viewNode)
			this.viewNode.removeChild(this.divider);
		if (this.pane2.parentNode == this.viewNode)
			this.viewNode.removeChild(this.pane2);
	}
};
SplitPane.prototype.attachContent = function attachContent()
{
	if (! this.contentAttached)
	{
		this.contentAttached = true;
		this.viewNode.appendChild(this.pane1);
		this.viewNode.appendChild(this.divider);
		this.viewNode.appendChild(this.pane2);
	}
};

SplitPane.prototype.onResize = function onResize()
{
	if (this.contentAttached && ! this.resizing && this.viewNode.offsetWidth > 0)
	{
		this.resizing = true;
		var node = this.viewNode.parentNode;
		while (node && node.style)
		{
			var parentHeight = parseInt(node.style.height);
			if (parentHeight)
			{
				this.setHeight(parentHeight-2*this.borderWidth);
				break;
			}
			node = node.parentNode;
		}
		var parentWidth = 0;
		
		// Detach content so that the parent width is exactly the available width
		this.detachContent();
		// Clear explicit widths - to be recalculated
		this.viewNode.style.width=null;
		this.pane1.style.width=null;
		this.pane2.style.width = null;
		// Calculating the available width is browser specific
		if (window.browser == 'Mozilla')
		{
			//In mozilla, we need to set the width property of the parent div in order to make the initial rendering correct
			parentWidth=this.viewNode.offsetWidth;
			this.viewNode.style.width=parentWidth-2*this.borderWidth;
			this.availableWidth = parentWidth - 2*this.borderWidth-this.dividerThickness;
		}
		else if (window.browser == 'IE')	
		{
			parentWidth = this.viewNode.offsetWidth;
			this.availableWidth = parentWidth - 2*this.borderWidth-this.dividerThickness;
		}
		if (this.availableWidth <2*this.minWidth)
		{
			this.leftWidth = Math.round(this.availableWidth/2);
		}
		else if (this.leftWidth + this.minWidth > this.availableWidth)
		{
			this.leftWidth = this.availableWidth - this.minWidth;
		}
		//set explicit widths
		this.rightWidth= this.availableWidth - this.leftWidth;
		this.setPaneWidth(this.pane1, this.leftWidth);
		this.setPaneWidth(this.pane2, this.rightWidth);
		if (this.sharedProperties.adjustBottom == true)
		{
			this.adjustBottom();
		};
		//re-attach content
		this.attachContent();
		this.onResizeChildren();
		this.resizing = false;
	}
};

SplitPane.prototype.setPaneWidth = function setPaneWidth(pane,width)
{
		if (window.browser == 'IE')
		{
			// In IE, the width includes the padding
			pane.style.width=width;
		}
		else
		{
			pane.style.width=width-2*this.paddingWidth;
		}
};

SplitPane.prototype.setPaneHeight = function setPaneHeight(pane,height)
{
		if (window.browser == 'IE')
		{
			// In IE, the hight include padding
			pane.style.height=height;
		}
		else
		{
			pane.style.height=height -2*this.paddingWidth;
		}
};
SplitPane.beginDrag = function(e)
{
	var splitPane = tersus.findNode(this.getAttribute('SplitPaneId'));
	splitPane.beginDrag(e);
};
SplitPane.finishDrag = function (e)
{
	var splitPane=tersus.findNode(this.documentElement.getAttribute('SplitPaneId'));
	this.onmouseup = null;
	this.onmousemove = null;
	splitPane.viewNode.className=splitPane.baseClassName;
	
};
SplitPane.performDrag = function (e)
{
	var splitPane=tersus.findNode(this.documentElement.getAttribute('SplitPaneId'));
	var win = splitPane.currentWindow;
	var currentPosition = getEventPosition(win,e);
	var delta = {};
	delta.x = currentPosition.x - splitPane.lastPosition.x;
	delta.y = currentPosition.y - splitPane.lastPosition.y;
	splitPane.lastPosition = currentPosition;		
	splitPane.resize(delta);
};
SplitPane.prototype.beginDrag = function beginDrag(e)
{
	var splitPane = this;
	var win = this.currentWindow;
	var doc = win.document;
	doc.documentElement.setAttribute('SplitPaneId', this.getNodeId());
	splitPane.lastPosition = getEventPosition(win, e);
	splitPane.viewNode.className+=' resizing';
	doc.onmousemove =SplitPane.performDrag;
	doc.onmouseup=SplitPane.finishDrag;
};

SplitPane.prototype.resize = function resize(delta)
{
	if (this.leftWidth+delta.x >= this.minWidth && this.rightWidth-delta.x >= this.minWidth)
	{
		if (this.direction == 'ltr')
		{
			this.leftWidth += delta.x;
			this.rightWidth -= delta.x;
		}
		else
		{
			this.leftWidth -= delta.x;
			this.rightWidth += delta.x;
		}
			
		if (delta.x >0)
		{
			this.setPaneWidth(this.pane2, this.rightWidth);
			this.setPaneWidth(this.pane1, this.leftWidth);
		}
		else
		{
			this.setPaneWidth(this.pane1, this.leftWidth);
			this.setPaneWidth(this.pane2, this.rightWidth);
		}
		
		this.onResizeChildren();
		
	}
};
// file: 180-CallJavaApplet.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.CallJavaApplet = ActionNode.__subclass('CallJavaApplet');
tersus.CallJavaApplet.prototype.start = function()
{
	var appletName = this.getLeafChild('<Applet Class Name>');
	var archives = this.getLeafChild('<Archives>');
	var methodName = this.getLeafChild('<Method Name>');
	var args = this.prepareArguments();
	
	this.waitForApplet(appletName,methodName,args, archives);
};
tersus.CallJavaApplet.prototype.waitForApplet = function waitForApplet(appletName,methodName,args, archives)
{
	this.pause();
	if (document.applets[appletName])
	{
		this.callApplet(appletName,methodName, args);
	}
	else
	{
		var rootContext = (this.getExecutionContext() == window.rootDisplayNode);
		if (rootContext)
		{
			tersus.progress.set('Loading applet '+appletName);
		}
		var node = this;
		setTimeout(function()
		{
			node.createApplet(appletName,archives);
			node.startTime = new Date();
			node.timerId = setInterval(function ()
			{
				var active = false;
				
				try 
				{
					active = document.applets[appletName] && document.applets[appletName].isActive();
				}
				catch ( e)
				{
					active = false;
				}
					
				if (((new Date())-node.startTime) > 60000 || active)
				{
					clearInterval(node.timerId);
					node.callApplet(appletName,methodName, args);
				} 
			},1000);
		},100);
	}
};
tersus.CallJavaApplet.prototype.createApplet = function(appletName,archives)
{
	if (!archives)
		archives = '';
	var applet = document.createElement('applet');
	applet.codebase='.';
	applet.width=1;
	applet.height=1;
	applet.setAttribute('id',appletName);
	applet.setAttribute('name',appletName);
	applet.setAttribute('mayscript','true');
	applet.code=appletName;
	applet.archive=archives;
	var c = document.getElementById('applet_container');
	if (!c)
	{
		c = document.createElement('div');
		c.id='applet_container';
		document.body.appendChild(c);
	}
	c.appendChild(applet);
};

tersus.CallJavaApplet.prototype.prepareArguments = function()
{
	var st = this.triggers.concat([]);
	var args = [];
	st.sort(function(a,b){ if (a.role < b.role) return -1; else if (a.role == b.role) return 0; else return 1;});
	for (var i=0;i<st.length;i++)
	{
		var t = st[i];
		if (t.role.charAt(0) != '<' && t.modelId != BuiltinModels.NOTHING_ID  )
		{
			if (t.isRepetitive)
			{
				var a = [];
				var l =t.getChildren(this);
				if (l)
				{
					for (var j=0;j<l.length; j++)
					{
						var v = l[j];
						if (v!= null &&  v.leafValue != null)
							a.push(v.leafValue);
						 else
						  	a.push(v);
					}
				}
				args.push(a);
			}
			else
			{
				var v = t.getChild(this);
				if (v!= null && v.leafValue != null)
					args.push(v.leafValue);
				else
					args.push(v);
			}
		}
	}	
	return args;
};
tersus.CallJavaApplet.prototype.callApplet = function(appletName,methodName,args)
{
	var rootContext = (this.getExecutionContext() == window.rootDisplayNode);
	if (! document.applets[appletName])
	{
		if (rootContext)
			tersus.progress.clear();
		modelExecutionError('Applet '+appletName + ' not loaded',this);
		return;
	}
	var applet = document.applets[appletName];
	if (rootContext)
		tersus.progress.set("Calling "+methodName);
	window.tersus_CallJavaApplet_caller = this;
	if (window.browser == 'IE')
	{
		var invocation = 'applet.'+methodName+'(';
		for (i=0;i<args.length;i++)
		{
			if (i>0)
				invocation += ',';
			invocation+='args['+i+']';
		}
		invocation += ')';
		var output = eval(invocation);
	}
	else
		var output = applet[methodName].apply(applet,args);
	window.tersus_CallJavaApplet_caller = null;
	
	if (output != '__ASYNC')
		this.handleResponse(output);
	
};
tersus.CallJavaApplet.prototype.isJavaException = function (e)
{
	try
	{
		var m = e.getMessage();
		return true;
	}
	catch (e)
	{
		return false;
	}
};

tersus.CallJavaApplet.prototype.handleResponse = function(output,exitName)
{
	var executionContext = this.getExecutionContext();
	if (output)
	{
		if (this.isJavaException(output))
		{
			this.handleException(output);
			return;
		}
		if (!exitName)
			exitName = '<Output>';
		this.chargeLeafExit(exitName,output);
		if (executionContext == window.rootDisplayNode)
			tersus.progress.set('Processing response');
	}
	this.resumeAfterPause();
	executionContext.resume();
	if (executionContext == window.rootDisplayNode)
		tersus.progress.clear();
};
tersus.CallJavaApplet.prototype.handleException = function (e)
{
	var appletName = this.getLeafChild('<Applet Class Name>');
	var methodName = this.getLeafChild('<Method Name>');
	tersus.progress.set('Processing response');
	var message = '';
	if (this.isJavaException(e))
	{
		e.printStackTrace();
		message = e.getClass().getName() + ' : '+e.getMessage();
	}
	else if (e.message)
		message = e.message;
	if (this.getExit('<Error>'))
		this.chargeLeafExit('<Error>',message);
	else	
		modelExecutionError('Failed to invoke method '+methodName+' : ' + message,this);
	this.resumeAfterPause();
	var executionContext = this.getExecutionContext();
	executionContext.resume();
	if (executionContext == window.rootDisplayNode)
		tersus.progress.clear();
};

// file: 181-ShowFile.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.ShowFile = function ShowFile() {};
tersus.ShowFile.useIFrame=true;
tersus.ShowFile.prototype = new ServiceNode();
tersus.ShowFile.prototype.constructor = tersus.ShowFile;
tersus.ShowFile.prototype.start = function startService()
{	
	if (tersus.alertMode.interactive)
	this.callService();
};
tersus.ShowFile.prototype.getTraceFileName = function()
{
	return this.traceFileName;
};
tersus.ShowFile.iframe = null;
tersus.ShowFile.prototype.callService = function callService()
{
	if (window.trace)
	{
		this.traceFileName = window.trace.openTraceFile();
		window.trace.link(this,this.traceFileName, "contains the trace of the server side process");
	}
	var form = this.prepareForm();
	this.addTersusParameters(form);

	form.action = 'File';
	form.method = 'POST';
	if (tersus.ShowFile.useIFrame)
	{
		if (tersus.ShowFile.iframe == null)
			tersus.ShowFile.iframe = createAnIFrame(window,'_showFile');
		form.target='_showFile';
	}
	
	setEncType(form,'multipart/form-data'); 
	form.submit();
	for (var i=0; i< this.nodesToRemove.length; i++)
	{
		var node = this.nodesToRemove[i];
		node.parentNode.removeChild(node);
	};
};
// file: 200-FieldList.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Field = function Field(element, path)
{
	this.name = element.role;
	this.sqlName = element.columnName ? element.columnName : tersus.sqlize(element.role);
	this.path = path;
	this.element = element;
};
tersus.Field.prototype.constructor = tersus.Field;
tersus.Field.prototype.setValue = function (obj, value)
{
	obj.setValue(this.path, value, Operation.REPLACE);
};
tersus.Field.prototype.setLeafValue = function (obj, leafValue)
{
	var value = this.element.createChildInstance();
	value.setLeaf(leafValue);
	obj.setValue(this.path, value, Operation.REPLACE);
};
tersus.Field.prototype.getSQLDef = function()
{
	var childP = this.element.getChildConstructor().prototype;
	return this.sqlName+ ' ' + childP.sqlType;
};
tersus.Field.prototype.getSQLValue = function (obj)
{
	var values = obj.getValues(this.path);
	if (values && values.length == 1)
	{
		var v = values[0];
		if (v == null)
		  	return v;
		return v.isDateAndTime ? v.serialize() : v.leafValue; // SQLite doesn't support date and time - need to serialize
	}
	else 
		return null;
};


tersus.FieldList = function(model)
{
	this.initialize(model);
};
tersus.FieldList.prototype.constructor = tersus.FieldList;
tersus.FieldList.prototype.initialize = function(model)
{
	this.fields = [];
	this.primaryKeyFields=[];
	this.addFields(model);
	for (var i=0; i<this.fields.length;i++)
	{
		var f = this.fields[i];
		if (f.element.isPrimaryKey)
		{
			this.primaryKeyFields.push(f);
			f.isPrimaryKey = true;
		}
	}
	if (this.primaryKeyFields.length == 0 && this.fields.length >0)
	{
		this.primaryKeyFields.push(this.fields[0]); // Todo - remove this sometime in the future?
		this.primaryKeyFields[0].isPrimaryKey=true;
	}
};
tersus.FieldList.prototype.getField = function getField(name)
{
	var found = null;
	var sqlName = tersus.sqlize(name);
	for (var i=0;i<this.fields.length;i++)
	{
		var f = this.fields[i];
		if (f.element.role == name || f.sqlName == sqlName)
		{
			if (found)
			{
				modelError('Ambiguous column name '+name);
				return null;
			}
			found = f; 
		}
	}
	return found;
};
tersus.FieldList.prototype.addFields = function addFields(root,prefixPath)
{	
	if (prefixPath == null)
		prefixPath = new Path('');
	var elements = root.elementList;
	if (!elements)
		return;
	var n=elements.length;
	for (var i=0;i<n;i++)
	{
		var e = elements[i];
		var c = e.getChildConstructor().prototype;
		var p = prefixPath.clone();
		p.addSegment(e.role);
		if (c.isLeaf)
			this.fields.push(new tersus.Field(e, p));
		else
			this.addFields(c,p);
	} 
};
// file: 201-DatabaseAction.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.databases = {};
tersus.maxDatabaseSize=5000000;
tersus.DatabaseAction = ActionNode.__subclass('tersus.DatabaseAction');
tersus.DatabaseAction.prototype.getDB = function()
{
	var datasource = this.getLeafChild('<Data Source>');
	if (!datasource)
		datasource = 'default';
	if (datasource.charAt(0) != '/')
	{
		var m = tersus.rootURL.match(/^(?:https?:\/\/[^/]+\/|file:\/+)([^/]+)\/$/);
		if (m && m.length > 0)
			datasource=m[1]+'_'+datasource;
	}
	
	var db = tersus.databases[datasource];
	if (! db)
	{
		db = openDatabase(datasource, 1.0, datasource, tersus.maxDatabaseSize);
		tersus.databases[datasource]=db;
	}
	return db;
};

tersus.DatabaseAction.prototype.getSQLStatememt = function()
{
	var sql = this.getLeafChild('<SQL Statement>');
	if (!sql)
		modelError('Missing <SQL Statement>',this);
	return sql;
};

tersus.DatabaseAction.prototype.analyzeParameterizedSQL = function(str)
{
	var t = str;
	var i=0;
	var l = t.length;
	var out = [];
	var keys = [];
	while (i<l&& i>= 0)
	{
		var n = t.indexOf('${',i);
		if (n == -1)
		{
			out.push(t.substring(i));
			i = n;
		}
		else
		{
			out.push(t.substring(i,n));
			var b = n+ 2;
			var e=t.indexOf('}', b);
			if (e<0)
			{
				modelExecutionError("Invalid template: missing '}' for '${'.  Position="
							+ n
							+ " Text="
							+ t.substring(n, n + 20));
				return null;
			}
			var key=t.substring(b,e);
			out.push('?');
			keys.push(key);
			i = e+1;
		}

	}
	var result = {};
	result.sqlText = out.join('');
	result.parameters = keys;
	return result;
};

tersus.DatabaseAction.prototype.getFieldList = function(model)
{
	if (!model.fieldList)
	{
		model.fieldList = new tersus.FieldList(model);
	}	
	return model.fieldList;
};
tersus.DatabaseAction.prototype.getOutputColumnsExit = function getOutputColumnsExit()
{
	return this.getExit('<Output Columns>');
};
tersus.DatabaseAction.prototype.outputColumns = function outputColumns(colMap)
{
	var exit = this.getOutputColumnsExit();
	if (exit)
	{
		for (var name in colMap)
		{
			var col = exit.createChildInstance();
			col.setLeafChild('Name',name, Operation.REPLACE);
			col.setLeafChild('Type',colMap[name], Operation.REPLACE);
			this.accumulateExitValue(exit, col);		
		}
	}
};
tersus.DatabaseAction.prototype.outputResultAsMap = function outputResultAsMap(exit, row, columns)
{
	var out = exit.createChildInstance();
	var map = {};
	out.leafValue = map;
	for (var key in row)
	{
		var value = row[key];
		if (value == null)
		{
			if (columns[key] == null)
				columns[key] = '?';
			continue;
		}
		var type =	typeof(value);
		var c;
		if (type == 'string')
		{
			c = tersus.repository.get(BuiltinModels.TEXT_ID);
		}
		else if (type == 'number')
		{
			c = tersus.repository.get(BuiltinModels.NUMBER_ID);
		}
		else
			throw {message:'Unexpected database return type '+type};
		var node = new c();
		node.prototype = c.prototype;
		node.setLeaf(value);
		map[key]=node;
		if (columns)
		{
			if (columns[key] == null || columns[key]=='?')
				columns[key] = c.prototype.modelName;
			else if (columns[key] != c.prototype.modelName)
				columns[key] = 'Anything';
		}
				
	}
	if (exit.isRepetitive)		
		this.accumulateExitValue(exit, out);
	else
		this.chargeExit(exit,out);
	
};

tersus.DatabaseAction.prototype.getTableNameOfModel = function(record)
{
	return record.tableName  ? record.tableName : tersus.sqlize(record.modelName);
};
tersus.DatabaseAction.prototype.getTableName = function getTableName(record)
{
	var n = this.getLeafChild('<Table Name>');
	if (n == null)
		n = this.getTableNameOfModel(record);
	return n;
};

tersus.DatabaseAction.prototype.addPrimaryKeyWhereClause = function createPrimaryKeyFilter(record,fieldList,sqla, values)
{
	sqla.push("WHERE");
	var pk = fieldList.primaryKeyFields;
	var npk = pk.length;
	for (var i=0;i<npk;i++)
	{
		if (i>0)
			sqla.push('AND');
		var f = pk[i];
		var v = f.getSQLValue(record);
		sqla.push(f.sqlName);
		if (v == null)
			sqla.push('IS NULL');
		else
		{
			sqla.push('= ?');
			values.push(v);
		}
	}

};
tersus.DatabaseAction.prototype.addSelectFieldsSQL = function addSelectFieldsSQL(sqla, tableName, fieldList, explicitColumns)
{
	sqla.push('SELECT');
	if (fieldList)
	{
		var fields = fieldList.fields;
		var n = fields.length;
		for (var i=0;i<n; i++)
		{
			if (i>0)
				sqla.push(',');
			sqla.push(fields[i].sqlName);
		}
	}
	else 
		sqla.push(explicitColumns ? explicitColumns : '*');
	sqla.push('FROM');
	sqla.push(tableName);
};
tersus.DatabaseAction.prototype.outputResults = function(results, exit, maxRows, reverse)
{
	var nRows = 0;
	var rows = results.rows;
	if (rows)
		nRows =  rows.length;
	if (nRows == 0)
	{
		this.chargeEmptyExit('<None>');
		return;
	}
	if (maxRows && nRows > maxRows)
		nRows = maxRows;
	var outputColumnsExit = this.getOutputColumnsExit();
	var outputPrototype = exit.getChildConstructor().prototype;
	if (outputPrototype.isMap)
	{
		var colMap=null;
		if (outputColumnsExit)
			colMap = {};
		for (var i=0;i<nRows; i++)
		{
			this.outputResultAsMap(exit, rows.item(i), colMap);
		}
		if (outputColumnsExit)
		{
			this.outputColumns(colMap);
		}
	}
	else
	{
		var fields = this.getFieldList(outputPrototype).fields;
		var nFields = fields.length;
		if (reverse)
		{
			for (var i=nRows -1; i>=0; i--)
				this.outputResult(rows.item(i), fields, nFields, exit);
		}
		else
		{
			for (var i=0;i<nRows; i++)
				this.outputResult(rows.item(i), fields, nFields, exit);
		}
	}
	
};
tersus.DatabaseAction.prototype.outputResult = function(item, fields, nfields, exit)
{
	var out = exit.createChildInstance();
	if (out.isLeaf)
	{
		for (var k in item)
			out.setLeaf(item[k]);
	}
	else // composite
	{
		for (var j=0;j<nfields;j++)
		{
			var field = fields[j];
			var v = item[field.sqlName];
			if (v != null)
				field.setLeafValue(out,v);
		}
	} 
	if (exit.isRepetitive)		
		this.accumulateExitValue(exit, out);
	else
		this.chargeExit(exit,out);
};

tersus.DatabaseAction.prototype.start = function()
{
	this.pause();
	if (this.tableOK)
	{
		this.run();
		return;
	}
	this.tableOK = true;
	var p = this.getTablePrototype();
	if (!p || p.tableOK || p.isMap)
	{
		this.run();
	}
	else
	{
		p.tableOK = true;
		this.getTableDef(this.getTableNameOfModel(p), this.updateTableAndRun, this);
	}
};
tersus.DatabaseAction.prototype.updateTableAndRun = function (tableDef)
{
	var p = this.getTablePrototype();
	var fieldList = this.getFieldList(p);
	var fields = fieldList.fields;
	var nfields = fields.length;
	var batch = [];
	if (tableDef == null)
	{
		var sql = 'CREATE TABLE '+this.getTableNameOfModel(p) + ' (';
		for (var i=0;i<nfields; i++)
		{
			var field = fields[i];
			if (i>0)
				sql += ', ';
			sql+=field.getSQLDef();
		}
		var pk = fieldList.primaryKeyFields;
		if (pk.length > 0)
		{
			sql += ', PRIMARY KEY (';
			for (var i=0;i<pk.length;i++)
			{
				if (i>0)
					sql += ',';
				sql += pk[i].sqlName;
			}
			sql+=')';
		}
		sql+=')';
		batch.push(sql);
	}
	else
	{
		for (var i=0;i<nfields;i++)
		{
			var field = fields[i];
			if (tableDef.columns[field.sqlName] == null)
				batch.push('ALTER TABLE '+p.tableName+' ADD COLUMN '+field.getSQLDef());
		}
	}
	if (batch.length > 0)
		this.execSqlBatch(batch, function(){this.run();});
	else
		this.run();			
};

tersus.DatabaseAction.prototype.resumeContext = function()
{
	this.resumeAfterPause();
	var executionContext = this.getExecutionContext();
	executionContext.resume();
};
tersus.DatabaseAction.prototype.execSql = function (sql, values, callback)
{
	//alert(sql);
	var errorHandler = function(transaction,error)
	{
		alert('Error: '+error.message+' ['+error.code+']');
		return true;	
	};
	var node = this;
	var dataHandler = function(transaction, results)
	{
		callback.call(node,transaction, results);
	};
	this.getDB().transaction(function(transaction){ transaction.executeSql(sql, values, dataHandler, errorHandler);});	
};
tersus.DatabaseAction.prototype.execSqlBatch = function (commands, callback, index)
{
	if (index == null)
		index = 0;
	if (commands.length != null && index >= commands.length)
	{
		alert('Invalid index in execSqlBatch');
	}
	this.execSql(commands[index], [], function()
	{ 
		if (index+1==commands.length)
			callback.call(this);
		else
			this.execSqlBatch(commands, callback, index+1);
	});
};
tersus.DatabaseAction.prototype.getTableDef = function(tableName, callback, obj)
{
	var errorHandler = function(transaction,error)
	{
		alert('Error: '+error.message+' ['+error.code+']');
		return true;	
	};
	var dataHandler = function(transaction, results)
	{
		if (!results || !results.rows || results.rows.length == 0)
		{
			callback.call(obj,null);
			return;
		}
		
		var re0 = /create table [^(]*\((.*)\)$/i;
		var re1 = /\s*(?:(?:(\w+)(?:\s+(\w+))?(?:\s*\(\s*(\d+)\s*\)\s*)?)|(?:primary\s*key\s*\(\s*([^)]*)\s*\)))((?:\s|\w)*)(?:,|$)/ig;
		var row = results.rows.item(0);
		var tableName = row.name;
		var sql = row.sql;
		var tableSpec= re0.exec(sql)[1];
		var tableDef = {name:tableName,columns:{}};
		do
		{
			var m = re1.exec(tableSpec);
			if (m!= null)
			{
				if (m[1] != null) // Column definition
				{
					var col = {name:m[1], type:m[2], size:m[3]};
					if (m[5] && /primary\s+key/i.test(m[5]))
						col.isPrimaryKey=true;
					tableDef.columns[col.name]=col;
				}
				else if (m[4] != null) // Primary key definition
				{
					var pk = m[4].split(/\s*,\s*/);
					for (var j=0; j<pk.length;j++)
					{
						var c = pk[j];
						if (c && tableDef.columns[c])
							tableDef.columns[c].isPrimaryKey=true;
					}
				}
					
			}
		} while (m!= null);
		callback.call(obj, tableDef);
	};
	this.getDB().transaction(function(transaction) {
		transaction.executeSql("select name, sql from sqlite_master where type=? and name=?",['table', tableName],  dataHandler, errorHandler);
	});
};
tersus.DatabaseAction.prototype.getSQLValue = function getSQLValue(role)
{
	  var v = this.getChild(role);
	  if (v == null)
	  	return v;
	  return v.isDateAndTime ? v.serialize() : v.leafValue; // SQLite doesn't support date and time - need to serialize

};// file: ActionDialog.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.isIE6 = navigator.userAgent.indexOf('MSIE 6') >=0;

 //tersus.ActionDialog = function tersus_ActionDialog() {};
	tersus.ActionDialog = tersus.PopIn.__subclass('Dialog');
	tersus.ActionDialog.prototype.templateURL='actiondialog.html';
	tersus.ActionDialog.prototype.createViewNode = function()
	{
		// create mask (this gives modality by blocking UI access to existing content)
		clearSelection(this.currentWindow); // sometimes the original selection is extended to newly created elements
		var d = this.currentWindow.document;
		var r = this.getCurrentRootViewNode();
		//var ml = this.createHTMLChildElement(r,'div');
		
		// create dialog div
		var template = tersus.repository.getHTMLTemplate(this.templateURL);
		var actioDialogHtml = importNode(d,template);
		this.dialogLayer = actioDialogHtml;
		actioDialogHtml.className='confirm_screenopen';
		this.viewNode = tersus.findChildNodesByClassName(actioDialogHtml,'action_dialog_body')[0];
		this.viewNode = actioDialogHtml;
		this.isOpen = true;
		r.appendChild(actioDialogHtml);
		this.header = tersus.findChildNodesByClassName(actioDialogHtml,'action_dialog_title')[0];
		if (this.header)
		  this.header.innerHTML = tersus.escapeHTML(this.getPopupTitle());
		  
		this.onResize();
		
	};
	tersus.ActionDialog.prototype.onResize = function()
	{
		if (! (this.isOpen && this.currentWindow && ! this.currentWindow.closed && this.viewNode))
			return;
				this.onResizeChildren();
	}
	tersus.ActionDialog.prototype.doClose = function() 
	{
		delete tersus.popupNodes[this.getNodeId()];
	
		if (this.isOpen)
		{
			this.resumeNavigation();
			this.viewNode = null;
			this.header = null;
			var dl = this.dialogLayer;
			//var ml = this.maskLayer;
			this.dialogLayer=null;
			//this.maskLayer=null;
			dl.parentNode.removeChild(dl);
			//ml.parentNode.removeChild(ml);
		}
		this.isOpen = false;
	
	};
// file: AdvancedFind.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.AdvancedFind =  tersus.DatabaseAction.__subclass('tersus.AdvancedFind');
tersus.AdvancedFind.prototype.NO_N_MATCHES = 'No Number of Matches';
tersus.AdvancedFind.prototype.NO_POSITION = 'No Position';
tersus.AdvancedFind.prototype.getTablePrototype = function()
{
	var e = this.getExit('<Records>');
	if (e == null)
		e = this.getTrigger('<From>');
	if (e == null)
		e = this.getTrigger('<To>');
	if (e == null)
		e = this.getTrigger('<Start From>');
	if (e == null)
		e = this.getTrigger('<Match>');
	if (e == null)
		return null;
	return e.getChildConstructor().prototype;
};
tersus.AdvancedFind.prototype.run = function()
{
	var ctx =
	{
		condition:[],
		values:[],
		from:this.getChild('<From>'),
		to:this.getChild('<To>'),
		match: this.getChild('<Match>'),
		startFrom:this.getChild('<Start From>'),
		numberOfRecords:this.getChild('<Number of Records>'),
		offset:this.getLeafChild('<Offset>'),
		backward:(true == this.getLeafChild('<Backward>')),
		table:this.getLeafChild('<Table>'),
		columns:this.getLeafChild('<Columns>'),
		filter:this.getLeafChild('<Filter>'),
		givenOrderBy:this.getLeafChild('<Order By>'),
		recordsExit:this.getExit('<Records>'),
		columns:this.getLeafChild('<Columns>'),
		moreExit:this.getExit('<More>'),
		positionExit:this.getExit('<Position>'),
		tablePrototype:this.getTablePrototype(),
		numberOfMatchesExit:this.getExit('<Number of Matches>')
	};
	if (!ctx.offset)
		ctx.offset = 0;
	
	this.setOptimization(ctx);
	this.setFieldList(ctx);
	this.addTable(ctx);
	this.addDynamicFilterConditions(ctx);
	this.addRangeConditions(ctx);
    this.addMatchConditions(ctx);	
	this.setOrderBy(ctx, ctx.backward);
	ctx.needsMatches = ctx.numberOfMatchesExit	 && !ctx.noMatches;
	ctx.needsPosition = ctx.positionExit!=null && !ctx.noPosition;

	if (ctx.needsMatches 
	 || ctx.backward && ctx.needsPosition && ctx.startFrom == null)
    {
    	this.countMatches(ctx, function(ctx,count)
    	{
    		ctx.nMatches = count;
    		if (ctx.needsMatches)
    		{
    			this.chargeLeafExit(ctx.numberOfMatchesExit, count);
    		}
    		if (ctx.recordsExit)
    			this.executeQuery(ctx);
    		else
    			this.resumeContext();
    		
    	});
   	}
    else
  		if (ctx.recordsExit)
   			this.executeQuery(ctx);
   		else
   			this.resumeContext();
   		
};
tersus.AdvancedFind.prototype.setOptimization = function(ctx)
{
	ctx.noPosition = false;
	ctx.noMatches = false;
	var trigger = this.getTrigger('<Optimization>');
	if (!trigger)
		return;
	
	var list = trigger.getChildren(this);
    if (list)
    {
    	for (var i=0;i<list.length;i++)
    	{
    		var opt = list[i].leafValue;
    		if (opt == this.NO_POSITION)
    			ctx.noPosition=true;
    		else if (opt == this.NO_N_MATCHES)
    			ctx.noMatches = true;
    	}
    }
};
tersus.AdvancedFind.prototype.countMatches = function countMatches(ctx, callback)
{
	var sqla = ['SELECT COUNT(1) AS count FROM', ctx.tableSql];
	if (ctx.condition.length > 0)
	{
		sqla.push('WHERE');
		tersus.addAll(sqla, ctx.condition);
	}
	this.execSql(sqla.join(' '),ctx.values, function(transaction, results) 
	{
		var count = results.rows.item(0).count;
		callback.call(this, ctx, count);
	});
};
tersus.AdvancedFind.prototype.setFieldList = function setFieldList (ctx)
{
	if (ctx.tablePrototype != null && ! ctx.tablePrototype.isMap)
		ctx.fieldList = this.getFieldList(ctx.tablePrototype);
};
tersus.AdvancedFind.prototype.addTable = function addTable(ctx)
{
	var rawSql = ctx.table? ctx.table : this.getTableName(ctx.tablePrototype);
	var q = this.analyzeParameterizedSQL(rawSql);
	ctx.tableSql = q.sqlText;
	for (var i=0; i<q.parameters.length; i++)
	{
		ctx.values.push(this.getSQLValue(q.parameters[i]));
	}
};
tersus.AdvancedFind.prototype.addDynamicFilterConditions = function(ctx)
{
	if (! ctx.filter)
		return;
	ctx.condition.push('(');
	var q = this.analyzeParameterizedSQL(ctx.filter);
	ctx.condition.push(q.sqlText);
	ctx.condition.push(')');
	for (var i=0; i<q.parameters.length; i++)
	{
		ctx.values.push(this.getSQLValue(q.parameters[i]));
	}
};



tersus.AdvancedFind.prototype.addMatchConditions = function(ctx)
{
  if (ctx.match == null)
        return;
	if (ctx.tablePrototype == null || ctx.tablePrototype.isMap)
	{
		tersus.error("Map not supported in AdvancedFind range/match conditions");
		this.resumeContext();
		return; 
	}	
	var columns = ctx.fieldList.fields;
    for (var i = 0; i < columns.length; i++)
    {
		var column = columns[i];
        var matchValue =  column.getSQLValue(ctx.match);
		if (matchValue != null)
        {
			if (matchValue.indexOf && matchValue.indexOf('%') >= 0)
	            this.addCondition(ctx, column, ' like ', matchValue);
	        else
	            this.addCondition(ctx, column, ' = ', matchValue);
	    }
	}
};       
				

tersus.AdvancedFind.prototype.addRangeConditions = function(ctx)
{
  if (ctx.from == null && ctx.to == null)
        return;
	if (ctx.tablePrototype == null || ctx.tablePrototype.isMap)
	{
		tersus.error("Map not supported in AdvancedFind range/match conditions");
		this.resumeContext();
		return; 
	}	
	var columns = ctx.fieldList.fields;
    for (var i = 0; i < columns.length; i++)
    {
		var column = columns[i];
        var fromValue = null;
        var toValue = null;
        if (ctx.from != null)
			fromValue = column.getSQLValue(ctx.from);
		if (ctx.to != null)
			toValue = column.getSQLValue(ctx.to);
		if (fromValue == null && toValue != null)
        {
			if (ctx.condition.length > 0)
				ctx.condition.push("AND");
            ctx.condition.push("(");
            this.addCondition(ctx, column, '<=', toValue);
            this.appendOrIsNull(ctx.condition, column.sqlName);
        }
        else
        {
            if (fromValue != null)
                this.addCondition(ctx, column, '>=', fromValue);
            if (toValue != null)
                this.addCondition(ctx, column, '<=', toValue);
        }
    }	

};
tersus.AdvancedFind.prototype.addCondition = function addCondition(ctx, column, operator, value)
{
	var c = ctx.condition;
    if (c.length > 0 && c[c.length - 1] != '(' )
    {
        c.push(" AND ");
    }
    c.push(column.sqlName);
   	c.push(operator);
    c.push('?');
    //types.add(column.getValueHandler());
    ctx.values.push(value);

};

tersus.AdvancedFind.prototype.appendOrIsNull = function(sqla, columnName)
{
    sqla.push('OR');
    sqla.push(columnName);
    sqla.push(' IS NULL )');
};

tersus.AdvancedFind.prototype.setOrderBy = function setOrderBy(ctx, reverse)
{
    ctx.columnOrder = {};
    ctx.orderedColumns = [];
    if (ctx.recordsExit == null)
    	return;

    
    if (ctx.fieldList == null)
    {
        ctx.orderBy = [ctx.givenOrderBy];
    }
    else
    {
       	this.handleExplicitOrderBy(ctx,reverse);
        this.addPrimaryKeyToSortOrder(ctx,reverse);
    }
};

tersus.AdvancedFind.prototype.handleExplicitOrderBy = function handleExplicitOrderBy (ctx, reverse)
{
   	ctx.columnOrder = {};
   	ctx.orderedColumns=[];
   	ctx.orderBy = [];
    if (ctx.givenOrderBy)
    {
    	var p = ctx.givenOrderBy.split(/\s*,\s*/);
		for (var i=0;i<p.length;i++)
        {
        	var clause = p[i];
        	var pp = clause.split(/\s+/);
            if (pp.length == 0 || pp.length > 2)
            {
            	this.modelExecutionError("Invalid <Order By>: '" + ctx.givenOrderBy + "'", this);
            	return;
            }
            var columnName = pp[0];
            column = ctx.fieldList.getField(columnName);
            if (column == null)
            {
                modelExecutionError("Invalid <Order By> ('" + ctx.givenOrderBy
                        + "': unknown column '" + columnName + "'");
                return;
            }

	
			var desc = pp.length > 1 && pp[1].search(/^desc/i) >= 0;
			if (reverse)
				desc = !desc;
			this.addColumnToSortOrder(ctx, column, desc)
        }
    }
};
tersus.AdvancedFind.prototype.addColumnToSortOrder = function addColumnToSortOrder(ctx, column, desc)
{
    var dir = desc ? 'DESC' : 'ASC';
	ctx.columnOrder[column.sqlName]=desc;
    ctx.orderedColumns.push(column);
    if (ctx.orderBy.length > 0)
    	ctx.orderBy.push(',');
    ctx.orderBy.push(column.sqlName);
    if (desc)
		ctx.orderBy.push(dir);
};
tersus.AdvancedFind.prototype.addPrimaryKeyToSortOrder = function addPrimaryKeyToSortOrder(ctx, reverse)
{
    var pkColumns = ctx.fieldList.primaryKeyFields;
    for (var i = 0; i < pkColumns.length; i++)
    {
        var column = pkColumns[i];
        var columnName = column.sqlName;
    	if (ctx.columnOrder[columnName] == null)
        	this.addColumnToSortOrder(ctx, column, reverse);
    }
};
tersus.AdvancedFind.prototype.addStartFromConditions = function addStartFromConditions(ctx)
{
    if (ctx.startFrom == null)
        return;
    var startFromCondition = [];
    var previousTermsValues = [];
    var  previousTermsTypes = [];
    var nTerms = 0;
    var previousTermsClause = [];
    for (var i = 0; i < ctx.orderedColumns.length; i++)
    {
        var column =  ctx.orderedColumns[i];
        var columnName = column.sqlName;
        var desc = ctx.columnOrder[columnName];
        if (desc == null)
            continue;
        var value = column.getSQLValue(ctx.startFrom);
        var last = (i == ctx.orderedColumns.length - 1);
        if (value == null)
        {
            if (last)
            {
                if (desc) // If the value of the last column is null, we only care about it if it's sorted desc
                {
                    if (previousTermsClause.length > 0)
                    {
                        previousTermsClause.push("AND");
                        previousTermsClause.push(columnName);
                        previousTermsClause.push("IS NULL");
                    }

                }
                if (startFromCondition.length > 0 && previousTermsClause.length > 0)
                {
                    startFromCondition.push("OR (");
                    tersus.addAll(startFromCondition,previousTermsClause);
                    startFromCondition.push(")");
                }
                else if (previousTermsClause.length > 0)
                {
                	
                    tersus.addAll(startFromCondition,previousTermsClause);
                }
                tersus.addAll(values,previousTermsValues);
                tersus.addAll(types,previousTermsTypes);
                ++nTerms;
            }
            else
            {
                if (!desc)
                {
                    if (startFromCondition.length == 0)
                    {
                        startFromCondition.push("(");
                    }
                    else
                    {
                        startFromCondition.push('OR (');
                    }
                    if (previousTermsClause.length > 0)
                    {
                        tersus.addAll(startFromCondition,previousTermsClause);
		                tersus.addAll(values,previousTermsValues);
	//	                tersus.addAll(types,previousTermsTypes);
                        startFromCondition.push("AND");
                    }
                    startFromCondition.push(columnName);
                    startFromCondition.push("IS NOT NULL )");
                    ++nTerms;
                }
                if (previousTermsClause.length > 0)
                {
                    previousTermsClause.push("AND");
                }
                previousTermsClause.push(columnName);
                previousTermsClause.push(" IS NULL");

            }
        }
        else
        {
            if (startFromCondition.length > 0 && previousTermsClause.length > 0)
            {
                startFromCondition.push("OR (");
                tersus.addAll(startFromCondition,previousTermsClause);
                tersus.addAll(ctx.values,previousTermsValues);
//                tersus.addAll(types,previousTermsTypes);
                startFromCondition.push("AND");
            }
            else if (startFromCondition.length == 0)
                startFromCondition.push("(");
            else
                startFromCondition.push("OR (");
            startFromCondition.push(columnName);

            ctx.values.push(value);
            //types.push(column.getValueHandler());
            if (last)
            {
                if (!desc)
                    startFromCondition.push(">= ? )");
                else
                {
                    startFromCondition.push("<= ?");
                    // we need to explicitly include null values
                    this.appendOrIsNull(startFromCondition, columnName);
                }
            }
            else
            {
                if (!desc)
                    startFromCondition.push("> ? )");
                else
                {
                    startFromCondition.push("< ?");
                    // we need to explicitly include null values
                    this.appendOrIsNull(startFromCondition, columnName);
                }

                if (previousTermsClause.length > 0)
                    previousTermsClause.push("AND");
                previousTermsValues.push(value);
                previousTermsClause.push(columnName);
                previousTermsClause.push("= ?");
                //previousTermsTypes.push(column.getValueHandler());
            }
            ++nTerms;
        }
    }
    if (nTerms == 0)
        return;
    if (ctx.condition.length == 0)
        ctx.condition = startFromCondition;
    else
    {
        ctx.condition.push('AND (');
        tersus.addAll(ctx.condition, startFromCondition);
        ctx.condition.push(')');
    }

};
tersus.AdvancedFind.prototype.executeQuery = function(ctx)
{
	this.addStartFromConditions(ctx);
	var sqla = [];
	this.addSelectFieldsSQL(sqla, ctx.tableSql, ctx.fieldList, ctx.columns);
		
	if (ctx.condition.length > 0)
	{
		sqla.push('WHERE');
		tersus.addAll(sqla, ctx.condition);
	}
	 
	if (ctx.orderBy.length > 0)
	{
		sqla.push('ORDER BY');
		tersus.addAll(sqla,ctx.orderBy);
	}
	var extra = 0; 
	if (ctx.numberOfRecords > 0)
	{
		if (ctx.moreExit != null)
			extra = 1;
		sqla.push('LIMIT');
		sqla.push(extra + parseInt(ctx.numberOfRecords));
		sqla.push('OFFSET')
		sqla.push(ctx.offset);
	}
	var sql = sqla.join(' ');
	this.execSql(sql, ctx.values, function(transaction,results)
	{
		var nrows = results.rows.length;
		var nrecs = (ctx.numberOfRecords > 0 && nrows> ctx.numberOfRecords) ? ctx.numberOfRecords : nrows;
		if (ctx.moreExit && nrows > nrecs)
			this.chargeEmptyExit(ctx.moreExit);
		this.chargeLeafExit('<Number of Records Returned>', nrecs);
		if (ctx.recordsExit != null)
			this.outputResults(results, ctx.recordsExit, nrecs, ctx.backward);
		this.getPosition(ctx);
	});
};
tersus.AdvancedFind.prototype.getPosition = function(ctx)
{
	if (! ctx.needsPosition)
	{
		this.resumeContext();
		return;
	}
	if (ctx.startFrom == null)
	{
		var pos = ctx.backward ? ctx.nMatches - ctx.numberOfRecords-ctx.offset : ctx.offset;
		this.chargeLeafExit(ctx.positionExit,pos);
		this.resumeContext();
		return;
	}

    ctx.condition=[];
    ctx.values=[];
    this.addDynamicFilterConditions(ctx);
    this.addRangeConditions(ctx);
    this.addMatchConditions(ctx);
    this.setOrderBy(ctx, true); // Regardless of <Backward>, we count all records before our own record
    this.addStartFromConditions(ctx);
    this.countMatches(ctx, function(ctx, count)
    {
    	var startFromPosition = count - 1; // If <Start From> is the first record we have count=1 and startFromPosition = 0);
    	var pos = ctx.backward ? 
    						startFromPosition+1-ctx.numberOfRecords-ctx.offset :
    						startFromPosition + ctx.offset;
		this.chargeLeafExit(ctx.positionExit,pos);
		this.resumeContext();
		return;
    });
};


 // file: Alert.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 //Alert - displays something

Alert = function Alert() {};
Alert.prototype = new ActionNode();
Alert.prototype.constructor = Alert;

Alert.prototype.start = function startAlert()
{
	if (this.children && this.children['<Message>'] && tersus.alertMode.interactive)
	{
		var message =  tersus.unescapeString(''+this.getLeafChild('<Message>'));
		this.currentWindow.alert(this.translate(message));
	}
	this.finished();
	
};
// file: Appears.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Appears = function Appears(){};
tersus.Appears.prototype = new ActionNode();
tersus.Appears.prototype.constructor = tersus.Appears;
tersus.Appears.prototype.start = function()
{
	var list = this.getTriggerValues('<Item>');
	var item = this.getChild('<Item>');
	var found = false;
	for (var i=0; i<list.length; i++)
	{
		var v = list[i];
		if (compareValues(v, item))
		{
			found = true;
			break;
		}
	}
	if (found)
		this.chargeExit('<Yes>', item);
	else
		this.chargeExit('<No>', item); 
		
};
// file: Arrow.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
function DisclosureArrow() {};
DisclosureArrow.prototype = new DisplayNode();
DisclosureArrow.prototype.constructor = DisclosureArrow;
DisclosureArrow.prototype.defaultTag = 'span';
// file: Back.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Back = function tersus_GetElmentName() {};
tersus.Back.prototype = new ActionNode();
tersus.Back.prototype.constructor = tersus.Back;
tersus.Back.prototype.start = function ()
{
	setTimeout(function () {window.history.back();},0);
	this.finished();
};
// file: BackgroundAction.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.BackgroundAction = function tersus_BackgroundAction() {};
tersus.BackgroundAction.prototype = new ActionNode();
tersus.BackgroundAction.prototype.constructor = tersus.BackgroundAction;
tersus.BackgroundAction.prototype.start = function tersus_BackgroundAction_start()
{
	if (this.parent.isBackground)
	{
		// This is the "final" invocation (in the background)
		ActionNode.prototype.start.call(this);
	}
	else
	{
		// This is the "original" invocation that should start a background process
		var process = new BackgroundProcess(this.parent, this.element);
		if (this.triggers)
			for (var i = 0; i < this.triggers.length; i++)
			{
				var trigger = this.triggers[i];
			
				if (trigger.isRepetitive)
				{
					internalError("Repetitive triggers not supported in Background Action");
				}
				else
				{
					var value = this.getChild(trigger.role);
					if (value)
						process.setTriggerValue(trigger.role, value);
				}
			}
		tersus.async.exec(function (){process.start()}, false /* don't wait */);
		this.finished();
	}
};
// file: Branch.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Branch() {};
Branch.prototype = new ActionNode();
Branch.prototype.constructor = Branch;
Branch.prototype.start = function ()
{
	var dataTrigger = this.getElement('<Data>');
	var selectorTrigger = this.getElement('<Selector>');
	if (! selectorTrigger) // For backward compatability
		selectorTrigger = this.getElement('<Value>');
	var selectorValue = selectorTrigger.getChild(this);
	var dataValue;
	if (dataTrigger)
		dataValue = dataTrigger.getChild(this);
	else
		dataValue = selectorValue;
	var defaultExit = this.getElement('<Other>');
	for (var i=0; i<this.exits.length; i++)
	{
		var exit = this.exits[i];
		if (exit != defaultExit)
		{
			var valueStr = exit.valueStr;
			if (valueStr == undefined)
				valueStr = exit.role;
			if (this.pluginVersion && this.pluginVersion >=1)
				valueStr = eval("'"+valueStr+"'"); // unescape javascript notation
			if (selectorValue.toString() == valueStr)
			{
				this.chargeExit(exit, dataValue);
				return;
			}
			
		}
	}
	if (defaultExit)
		this.chargeExit(defaultExit, dataValue);
	this.finished();
};// file: BranchByType.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.BranchByType = function BranchByType(){};
tersus.BranchByType.prototype = new ActionNode();
tersus.BranchByType.prototype.constructor = tersus.BranchByType;
tersus.BranchByType.prototype.start = function()
{
	var input = this.getChild('<Input>');
	var otherExit = null;
	if (input)
	{
		for (var i=0; i<this.exits.length; i++)
		{
			var exit = this.exits[i];
			if (exit.role == '<Other>')
				otherExit = exit;
			else
			{
				var c = exit.getChildConstructor();
				if (c && c.prototype.isInstance(input))
				{
					this.chargeExit(exit, input);
					return;
				}
			}
		}
		if (otherExit)
			this.chargeExit(otherExit, input);
	}
	this.finished();
};// file: Button.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Button(){};
Button.prototype = new DisplayNode();
Button.prototype.constructor = Button;
Button.prototype.type = 'Button';
Button.prototype.defaultTag = 'button';
Button.prototype.isButton = true;
Button.prototype.destroy = function()
{
	this.isDestroyed = true;
	DisplayNode.prototype.destroy.call(this);
};
Button.prototype.createChildren = function Button_createChildren()
{
	// we don't create the sub-hierarchy for a button.
};
Button.prototype.createViewNode = function Button_createViewNode()
{
	DisplayNode.prototype.createViewNode.call(this);
	this.viewNode.innerHTML = tersus.escapeHTML(this.getCaption());
};
Button.prototype.captionChanged = function()
{
	if (this.viewNode)
		this.viewNode.innerHTML = tersus.escapeHTML(this.getCaption());
};
Button.prototype.setEventHandlers = function Button_setEventHandlers()
{
	DisplayNode.prototype.setEventHandlers.call(this);
	this.registerEventHandler(Events.ON_CLICK);
}
Button.prototype.doStart = function Button_start() 
{
	// We override doStart and not start because we don't want to trace 'Started' events for buttons
	this.waiting();
};
Button.prototype.onClick = function()
{
	queueEvent(this, this.handleClick, [], new Date(), "Button clicked ["+this.getPath().str+"]");
}; 
Button.prototype.handleClick = function tersus_Button_handleClick() 
{
	if (this.isDestroyed || !this.currentWindow || this.currentWindow.closed || this.status != FlowStatus.WAITING_FOR_INPUT)
	{
		return;
	}
	
	var validate = this.sharedProperties.validate != false; // null considered true
	var validationContext = this.getValidationContext();
	var valid = true;
	if (validate)
	{
		if (tlog) tlog('button.onclick:validating');
		valid = validationContext.validate();
	}
	if (valid)
	{
		if (tlog) tlog('button.onclick: starting handler');
		this.children = null;
		this.readyToResume();
		this.clicked = true;
		resumeRoot();
		if (tlog) tlog('button.onclick: handler done');
	}
	else
		if (tlog) tlog('button.onclick: not valid');
	
};

Button.prototype.validate = function validate()
{
	return true; // Do not traverse children
};
Button.prototype.resume = function resumeButton()
{
	if (this.clicked)
	{
		this.clicked = false;
		this.started();
		FlowNode.prototype.start.call(this);
	}
	else 
		FlowNode.prototype.resume.call(this);
};
Button.prototype['get<Disabled>'] = function ()
{
	return this.disabled;
};

Button.prototype['set<Disabled>'] = function (disabled)
{
	this.disabled = disabled?true:false;
	if (this.viewNode)
	{
		this.viewNode.disabled=this.disabled;
		if (window.browser == 'IE') // IE 6.0 doesn't support the :disable CSS pseudoclass, so we use an explicit style as a workaround
		{
			if (disabled && !this.viewNode.className)
				this.viewNode.className = 'disabled';
			if (!disabled && this.viewNode.className=='disabled')
				this.viewNode.className = '';
		}
	}
};
// file: CancelTimer.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.CancelTimer = function tersus_CancelTimer() {};
tersus.CancelTimer.prototype = new ActionNode();
tersus.CancelTimer.prototype.constructor = tersus.CancelTimer;
tersus.CancelTimer.prototype.start = function()
{
	var timerId = this.getLeafChild("<Timer Id>");
	if (! timerId)
	{
		modelError("Missing <Timer Id> in \"Cancel Timer\" "+this.modelId);
		return;
	}
	if (tlog) tlog("Cancelled timer "+timerId);
	clearInterval(timerId);
	this.finished();
};
// file: Checkbox.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Checkbox = function tersus_Checkbox () {};
tersus.Checkbox.prototype = new tersus.PushButton();
tersus.Checkbox.prototype.constructor = tersus.Checkbox;
tersus.Checkbox.prototype.buttonType='checkbox';
// <Value> property: for backwards compatability
tersus.Checkbox.prototype['get<Value>'] = tersus.PushButton.prototype['get<Checked>'];
tersus.Checkbox.prototype['set<Value>'] = tersus.PushButton.prototype['set<Checked>'];
tersus.Checkbox.prototype['remove<Value>'] = tersus.PushButton.prototype['remove<Checked>'];
tersus.Checkbox.prototype.labelClicked = function()
{
	if (this.button && ! this.button.disabled)
	{
		this.button.checked = ! this.button.checked;
		this.onChange();
	}
}
// file: Click.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Click = function Click() {};
tersus.Click.prototype = new ActionNode();
tersus.Click.prototype.constructor = tersus.Click;
tersus.Click.prototype.start = function ()
{
	var element = this.getChild('<Element>');
	var queue = this.getLeafChild('<Queue>');
	var action = this;
	var targetNode;
	if (element && element.getClickTarget)
		targetNode = element.getClickTarget();
	else if (element && element.viewNode)
	{
		targetNode = element.viewNode;
	}
	else 
	{
		targetNode = this.getLeafChild('<View Node>');
	}
	if (targetNode)
	{
		this.pause();
		var resume = function()
		{
		  	action.resumeAfterPause();
		  	action.getExecutionContext().resume();
 			tersus.progress.clear();
		}
		var click = function() {
			if (targetNode.click &&
			 ! (targetNode.tagName == 'INPUT' && targetNode.type=='text'))
			 	// click() on text input fields doesn't  work
				targetNode.click();
			else if (targetNode.onclick)
			{
				var e = {};
				e.type = 'mouseclick';
				targetNode.onclick(e);
			}
		 	tersus.async.exec(resume, false /* don't wait */);
		};
		tersus.async.exec(click, false /* don't wait  */); // not sure this behavior is correct
		/*
		 * Proposed improvement:
		 *  - If 'Click' runs in main thread it exits immediately and target is clicked later.
		    - If 'Click' runs in background, it pauses, and target is clicked when root contet is not busy ('wait=true') 
		  */
	}
}
tersus.Click.prototype.resume = function()
{
	this.finished();
};
// file: CloseWindow.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 

//CloseWindow - closes the currentWindow

function CloseWindow(){};
CloseWindow.prototype = new ActionNode();
CloseWindow.prototype.constructor = CloseWindow();
CloseWindow.prototype.start = function()
{
	// Find the containing node that has a closeWindow method
	var node = this;
	while (node && !node.closeWindow) 
		node = node.parent;
	if (node && node.closeWindow)
		node.closeWindow();
	this.finished();
};
// file: Collapse.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Collapse() {};
Collapse.prototype = new ActionNode();
Collapse.prototype.constructor = Collapse;
Collapse.prototype.start = function ()
{
	var item = this.getChild('<Item>');
	if (item.collapse)
		item.collapse();
	this.finished();
};
// file: Concatenate.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('Concatenate', function()
{
	var st = this.triggers.concat([]);
	var values = [];
	st.sort(function(a,b){ if (a.role < b.role) return -1; else if (a.role == b.role) return 0; else return 1;});
	var sep = this.getLeafChild('<Separator>');
	if (sep == null)
		sep = '';
	for (var i=0;i<st.length;i++)
	{
		var t = st[i];
		if (t.role != '<Separator>' && t.modelId != BuiltinModels.NOTHING_ID  )
		{
			if (t.isRepetitive)
			{
				var l =t.getChildren(this);
				if (l)
				{
					for (var j=0;j<l.length; j++)
					{
						var v = l[j];
						if (v!= null && v.leafValue != null)
							values.push(v.leafValue);
					}
				}
						
			}
			else
			{
				var v = t.getChild(this);
				if (v!= null && v.leafValue != null)
					values.push(v.leafValue);
			}
			
		}
	}
	var out = values.join(sep);
	this.chargeLeafExit('<Concatenation>',out);	
});

// file: Confirm.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
//Confirm - displays a confirmation message and retrieves user input
function Confirm() {};
Confirm.prototype = new ActionNode();
Confirm.prototype.constructor = Confirm;

Confirm.prototype.start = function startConfirm()
{
	var message =  tersus.unescapeString('' +this.getLeafChild('<Message>'));
	var response;
	if (tersus.alertMode.interactive)
		response = this.currentWindow.confirm(this.translate(message));
	else
		response = tersus.alertMode.confirm;
	if (response)
		this.chargeLeafExit('<OK>', message);
	else
		this.chargeLeafExit('<Cancel>', message);
	this.finished();
};// file: ConstructDate.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('ConstructDate', function()
{
	var d = new tersus.DateValue();
	d.year = this.getLeafChild('<Year>');
	d.month = this.getLeafChild('<Month>');
	d.day = this.getLeafChild('<Day>');
	this.chargeLeafExit('<Date>',d);	
});

// file: ConstructDateAndTime.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('ConstructDateAndTime', function()
{
	var y = this.getLeafChild('<Year>');
	var m = this.getLeafChild('<Month>');
	var d = this.getLeafChild('<Day>');
	var h = this.getLeafChild('<Hour>');
	var mi = this.getLeafChild('<Minute>');
	var s =  this.getLeafChild('<Second>');
	var ms =  this.getLeafChild('<Millisecond>');
	
	var dt = new Date(y,m-1, d, h, mi, s, ms);
	this.chargeLeafExit('<Date and Time>',dt);
});

// file: ConvertNumberToText.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.numberFormats = {};
tersus.newAction('ConvertNumberToText', function()
{
	var number = this.getLeafChild('<Number>');
	if (number == null)
		return;
	var formatStr = this.getLeafChild('<Format>');
	if (formatStr == null)
		this.chargeLeafExit ('<Text>',new String(number));
	else
		this.chargeLeafExit ('<Text>',gwtFormatNumber(number,formatStr));
});

// file: ConvertTextToNumber.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('ConvertTextToNumber', function()
{
	var text = this.getLeafChild('<Text>');
    if (text != null)
    {
    	if (tersus.isNumber(text))
    	{
    		var f = parseFloat(text);
    		if (! isNaN(f))
    		{
    			this.chargeLeafExit('<Number>',f);
    			return;
    		}
    	}
    	var nanExit = this.getExit('<Not a Number>');
    	if (nanExit != null)
    		this.chargeLeafExit(nanExit.role,text);
    	else
    		throw new tersus.Exception('Invalid number format '+text);
    }
});

// file: Count.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Count = function tersus_Count(){};
tersus.Count.prototype = new ActionNode();
tersus.Count.prototype.constructor = tersus.Count;
tersus.Count.prototype.start = function ()
{
	var values = this.getTriggerValues();
	this.chargeLeafExit('<Occurrences>',values.length);
};
// file: Create.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Create = function tersus_Create() {};
tersus.Create.prototype = new ActionNode();
tersus.Create.prototype.constructor = tersus.Create;
tersus.Create.prototype.start = function ()
{
	var modelId = this.getLeafChild('<Model Id>');
	var exit = this.getElement("<Object>");
	if (exit == null)
		return; // This can happen if user doesn't have permission for target type
	var modelNotFoundExit = this.getElement("<Model Not Found>");

	if (modelId != null)
	{
		var	constructor = tersus.repository.get(modelId);
		if (constructor!=null)
		{
			var value = new constructor();
			this.chargeExit(exit, value);
		}
		else
		{
			if (modelNotFoundExit!=null)
				this.chargeLeafExit(modelNotFoundExit.role,modelId);
			else
				modelExecutionError("Model not found:"+modelId,this);
				
		}
	}
	else
	{
		var value = exit.createChildInstance();
		this.chargeExit(exit, value);
	}
	this.finished();
};
// file: CreateFromTemplate.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.CreateFromTemplate = function() {};
tersus.CreateFromTemplate.prototype = new ActionNode();
tersus.CreateFromTemplate.prototype.constructor = tersus.CreateFromTemplate;
tersus.CreateFromTemplate.prototype.start = function()
{
	var t = this.getLeafChild('<Template>');
	var i=0;
	var l = t.length;
	var out = [];
	while (i<l&& i>= 0)
	{
		var n = t.indexOf('${',i);
		if (n == -1)
		{
			out.push(t.substring(i));
			i = n;
		}
		else
		{
			out.push(t.substring(i,n));
			var b = n+ 2;
			var e=t.indexOf('}', b);
			if (e<0)
			{
				modelExecutionError("Invalid template: missing '}' for '${'.  Position="
							+ n
							+ " Text="
							+ t.substring(n, n + 20));
				return null;
			}
			var key=t.substring(b,e);
			out.push(this.getLeafChild(key));
			i = e+1;
		}

	}
	this.chargeLeafExit('<Text>',out.join(''));
}

// file: CreateLocation.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.CreateLocation = function tersus_CreateLocation() {};
tersus.CreateLocation.prototype = new ActionNode();
tersus.CreateLocation.prototype.RELATIVE='<Relative>';
tersus.CreateLocation.prototype.BASE_URL='<Base URL>';
tersus.CreateLocation.prototype.constructor = tersus.CreateLocation;
tersus.CreateLocation.prototype.start = function ()
{
	var relative = this.getTriggerLeafValue(this.RELATIVE);
	var baseURL = this.getTriggerLeafValue(this.BASE_URL);
	if (relative && baseURL)
	{
		modelExecutionError(this.RELATIVE + ' and '+ this.BASE_URL+'should not be used together in Create Location',this);
		relative = false;
	}
	var params;
	if (relative)
		params = tersus.getInternalParameters();
	else
		params = {};
	if (this.triggers)
	{
		for (var i=0; i< this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			if (trigger.role != this.RELATIVE && trigger.modelId != BuiltinModels.NOTHING_ID)
			{
				var value = trigger.getChild(this);
				if (value != null)
				{
					if (value.serialize)
						value = value.serialize();
					else
						value = value.leafValue;
				}
				params[trigger.role]= value;
			}
		}
	}
	
	var URL;
	if (baseURL)
	{
		URL = baseURL;
		if (URL.indexOf('#') < 0 && URL.indexOf('?')<0)
			URL+='?';
	}
	else
	{
		URL = tersus.getCurrentViewURL();
		if (URL.indexOf('#') <0)
			URL += '#';
	}
	
	var lastChar = URL.charAt(URL.length-1);
	var first =  lastChar == '#' || lastChar == '?';
	for (var p in params)
	{
		var v = params[p];
		if (v!=undefined || v != null)
		{
			if (! first)
				URL +='&';
			URL += encodeURIComponent(p)+'='+encodeURIComponent(v);
			first = false;
		}
	}
	this.chargeLeafExit('<URL>',URL);
		
	this.finished();
};// file: DatabaseQuery.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DatabaseQuery = tersus.DatabaseAction.__subclass('tersus.DatabaseQuery');
tersus.DatabaseQuery.prototype.start = function()
{
	var sql = this.getSQLStatememt();
	var q = this.analyzeParameterizedSQL(sql);
	var values = [];
	for (var i=0; i<q.parameters.length; i++)
	{
		values.push(this.getSQLValue(q.parameters[i]));
	}
	this.pause();
	this.execSql(q.sqlText, values, function(transaction,results)
	{
		this.outputResults(results, this.getExit('<Results>'));
		this.resumeContext();
	});
};
// file: DatabaseUpdate.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DatabaseUpdate = tersus.DatabaseAction.__subclass('tersus.DatabaseUpdate');
tersus.DatabaseUpdate.prototype.start = function()
{
	var sql = this.getSQLStatememt();
	var q = this.analyzeParameterizedSQL(sql);
	var values = [];
	for (var i=0; i<q.parameters.length; i++)
	{
		values.push(this.getSQLValue(q.parameters[i]));
	}
	this.pause();
	this.execSql(q.sqlText, values, function(transaction,results)
	{
		this.handleResults(results);
		this.resumeContext();
	});
};
tersus.DatabaseUpdate.prototype.handleResults = function(results)
{
	if (results)
	{
		if (results.rowsAffected != null)
			this.chargeLeafExit('<Number of Records Affected>',results.rowsAffected);
//		if (results.insertId != null)
//			this.chargeLeafExit('<Insert Id>', results.insertId);
		}
};// file: DateField.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DateField = function tersus_DateField() {};
tersus.DateField.prototype = new tersus.GenericField();
tersus.DateField.prototype.constructor = tersus.DateField;
tersus.DateField.prototype.isEditable = true;
tersus.DateField.popCalendar = function()
{
	var documentNode = this;
	var node = DisplayNode.findNodeForDocumentNode(documentNode);
	if (!node)
		return;
	var valueHandler = function valueHandler(year, month, day)
	{
		node.onChange();
	};
	node.currentWindow.popUpCalendar(this, this, valueHandler, DATE_FORMAT);
};
tersus.DateField.prototype.initWritable = function ()
{
	tersus.GenericField.prototype.initWritable.call(this);
	this.inputField.id = this.getNodeId();
	this.inputField.onclick = tersus.DateField.popCalendar;
	if (!tersus.isNumber(this.sharedProperties.size))
		this.inputField.size = 10;
};

tersus.DateField.prototype.onChange = function()
{
	tersus.GenericField.prototype.onChange.call(this);
	hideCalendar();
};
tersus.DateInputField = DateInputField = tersus.DateField; // Backward compatability

// file: Delete.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Delete = tersus.DatabaseAction.__subclass('tersus.Delete');
tersus.Delete.prototype.getTablePrototype = function()
{
	return this.getTrigger('<Record>').getChildConstructor().prototype;
};
tersus.Delete.prototype.run = function()
{
	var record = this.getChild('<Record>');
	var tableName = this.getTableName(record);
	var fieldList = this.getFieldList(record.constructor.prototype);
	var sqla = []; // 'buffer' for creating the sql
	var values = []; // values
	sqla.push('DELETE FROM ');
	sqla.push(tableName);
	this.addPrimaryKeyWhereClause(record,fieldList,sqla, values);
	var sql = sqla.join(' ');
	this.execSql(sql, values, function(transaction,results)
	{
		this.handleResults(results,record,tableName);
		this.resumeContext();
	});
			
};
tersus.Delete.prototype.handleResults = function(results, record, tableName)
{
	var count = results.rowsAffected;
	if (count == 1)
		this.chargeExit('<Deleted>',record);
	else if (count == 0)
		this.chargeExit('<Not Found>',record);
	else
		modelExecutionError("Delete resulted in deleting multiple records in table "
                                    + tableName
                                    + ". Check primary key settings", this);
                                    
};// file: DeleteElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DeleteElement = function DeleteElement(){};
tersus.DeleteElement.prototype = new ActionNode();
tersus.DeleteElement.prototype.constructor = tersus.DeleteElement;
tersus.DeleteElement.prototype.start = function()
{
	var e = this.getChild('<Element>');
	if (e && e.deleteMe)
		e.deleteMe();
	else
		internalError("Failed to delete child in "+this.getPath());
	this.finished();
	
};
// file: Dialog.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.isIE6 = navigator.userAgent.indexOf('MSIE 6') >=0;
if ( tersus.isIPhone)
{
	tersus.Dialog = tersus.PopIn; // On iPhone (and iPhone simulation) we use a full pop-in for instead of a Dialog
}
else
{
	tersus.Dialog = tersus.PopIn.__subclass('Dialog');
	tersus.Dialog.prototype.createViewNode = function()
	{
		// create mask (this gives modality by blocking UI access to existing content)
		clearSelection(this.currentWindow); // sometimes the original selection is extended to newly created elements
		var d = this.currentWindow.document;
		var r = this.getCurrentRootViewNode();
		var ml = this.createHTMLChildElement(r,'div');
		ml.className='dialog_mask';
		ml.style.zindex = ++ tersus.topZindex;
		this.maskLayer = ml;
		// create dialog div
		var template = tersus.repository.getHTMLTemplate(this.templateURL);
		var dialog = importNode(d,template);
		this.dialogLayer = dialog;
		dialog.style.position='absolute';
		dialog.className='dialog';
		this.viewNode = tersus.findChildNodesByClassName(dialog,'dialogBody')[0];
		if (this.viewNode)
		{
			this.header = tersus.findChildNodesByClassName(dialog,'dialogHeader')[0];
			this.footer = tersus.findChildNodesByClassName(dialog,'dialogFooter')[0];
		}
		else
			this.viewNode = dialog;
		this.isOpen = true;
		r.appendChild(dialog);
		if (this.header)
		  this.header.innerHTML = tersus.escapeHTML(this.getPopupTitle());
		this.onResize();
		this.hideSelectNodes();
	};
	tersus.Dialog.prototype.onResize = function()
	{
		if (! (this.isOpen && this.currentWindow && ! this.currentWindow.closed && this.viewNode))
			return;
		var d = this.viewNode.ownerDocument;
	
		var s = getVisibleSize(d.body);
		var th = s.height - 30;
		var tw = s.width - 30;
	
		var w = this.sharedProperties.windowWidth;
		if ( ! w || w == ' ')
			w = 350;
		var h = this.sharedProperties.windowHeight;
		if (! h || h == ' ')
			h = 265;
		
		w = Math.min(w,tw);
		h = Math.min(h,th);
		var leftPx = parseInt((tw-w)/2);
		var topPx = parseInt((th-h)/2);
		var dl = this.dialogLayer;
		dl.style.top = topPx + d.body.scrollTop;
		dl.style.left = leftPx + d.body.scrollLeft;
		dl.style.width = w;
		var ml = this.maskLayer;
		ml.style.height = d.body.scrollHeight;
		ml.style.width = d.body.scrollWidth;
		ml.style.position = 'absolute';
		ml.style.top = 0;
		ml.style.left = 0;

		var delta = 0;
		if (this.header)
			delta += getHeight(this.header);
		if (this.footer)
			delta += getHeight(this.footer);
		this.viewNode.style.height = h-delta;
		this.onResizeChildren();
	}
	tersus.Dialog.prototype.doClose = function() 
	{
		delete tersus.popupNodes[this.getNodeId()];
	
		if (this.isOpen)
		{
			this.resumeNavigation();
			this.viewNode = null;
			this.header = null;
			var dl = this.dialogLayer;
			var ml = this.maskLayer;
			this.dialogLayer=null;
			this.maskLayer=null;
			dl.parentNode.removeChild(dl);
			ml.parentNode.removeChild(ml);
		}
		this.isOpen = false;
		this.restoreSelectNodes();
	};
	tersus.Dialog.prototype.hideSelectNodes = function()
	{
	   	if (!tersus.isIE6)
	   		return;
		var l = this.currentWindow.document.body.getElementsByTagName('select');
		this.selectNodes = [];
		for (var i=0;i<l.length;i++)
			this.selectNodes.push(l[i]);
		for (var i=0;i<this.selectNodes.length;i++)
		{
			var n = this.selectNodes[i];
			var placeHolder = this.createHTMLElement('span');
			n.placeHolder=placeHolder;
			n.parentNode.replaceChild(placeHolder,n);			
		}
	
	};
 	tersus.Dialog.prototype.restoreSelectNodes = function()
	{
		if (this.selectNodes)
		{
			for (var i =0; i<this.selectNodes.length; i++)
			{
				var n =	this.selectNodes[i];
				var placeHolder = n.placeHolder;
				placeHolder.parentNode.replaceChild(n, placeHolder);
				n.placeHolder = null;
			}
		};
	};
	tersus.Dialog.prototype.setEventHandlers = function()
	{
		DisplayNode.prototype.setEventHandlers.call(this);
		this.dragNode = this.header ? this.header : this.viewNode;
	
		this.registerEventHandler(Events.ON_MOUSEDOWN, this.dragNode);
	};
	tersus.Dialog.prototype.onMouseDown = function()
	{
		var atts = tersus.currentEventAttributes;
		if (!atts) return;
		if (this.checkTargetElement(atts.targetElement))
		{
			var p = getScreenPosition(this.dialogLayer);
			this.dialogLayer.style.position='absolute';
			this.dialogLayer.style.top  = p.top - getScroll(this.dialogLayer).top;
			this.dialogLayer.style.left = p.left  - getScroll(this.dialogLayer).left;
			this.baseP = p;
			this.baseMouseP = {x:atts.clientX,y:atts.clientY};
			var node = this;
			var b = this.viewNode.ownerDocument.body;
			b.style.cursor = 'pointer';
			b.onmouseup = function(e)
			{
				node.onDrag(e);
				node.endDrag();
				return false; // disable default action (image drag) 
			};
			b.onmousemove = function(e)
			{
				node.onDrag(e);
				return false; //disable default action (image drag)
			}
			return false; //disable default action (image drag)
		}
		return true;// Don't disable default action
	};

	// Checks whether an element is a "good" drag source (doesn't have its own event handling logic)
	tersus.Dialog.prototype.checkTargetElement = function (targetElement)
	{
		if (targetElement == this.dragNode)
			return true;
		var n = targetElement;
		while (n && n != this.dragNode)
		{
			if (n.onclick || n.onmousedown || n.onmouseup || n.onmousemove || n.ondoubleclick)
				return false;
			if (n.tagName == 'INPUT' || n.tagName == 'TEXTAREA' || n.tagName == 'SELECT' || n.tagName == 'OPTION')
				return false;
			n = n.parentNode;
		}
		return true;
	};
	tersus.Dialog.prototype.endDrag = function()
	{
		var b = this.viewNode.ownerDocument.body;
		b.onmousemove = null;
		b.onmouseup = null;
		b.style.cursor = 'default';
	
	
	};
	tersus.Dialog.prototype.onDrag = function(e)
	{
		var atts;
		if (e)
			atts = getEventAttributes(e);
		else
			atts = getEventAttributes(this.currentWindow.event);
		if (!atts) return;
		this.dialogLayer.style.top = this.baseP.top + atts.clientY - this.baseMouseP.y - getScroll(this.dialogLayer).top;
		this.dialogLayer.style.left = this.baseP.left + atts.clientX - this.baseMouseP.x - getScroll(this.dialogLayer).left;;
	
	};
}
// file: DialogFooter.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DialogFooter = function tersus_DialogFooter() {};
tersus.DialogFooter.prototype = new Row();
tersus.DialogFooter.prototype.constructor = tersus.DialogFooter;
tersus.DialogFooter.prototype.attachViewNode = function DialogFooter_attachViewNode()
{
	this.tableNode  = this.createHTMLElement('table');
	this.tbodyNode = this.createHTMLElement('tbody');
	this.tableNode.appendChild(this.tbodyNode);
	this.tbodyNode.appendChild(this.viewNode);
	if (this.parent&& this.parent.footer)
		this.parent.footer.appendChild(this.tableNode);

}
PopupFooter=tersus.DialogFooter; // For backward compatability// file: Divide.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Divide = function tersus_Divide() {};
tersus.Divide.prototype = new ActionNode();
tersus.Divide.prototype.constructor = tersus.Divide;
tersus.Divide.prototype.start = function ()
{
	var x = this.getLeafChild('<X>');
	var y = this.getLeafChild('<Y>');
	if (this.getElement('<Ratio>'))
		this.chargeLeafExit('<Ratio>', x/y);
	if (this.getElement('<Quotient>'))
		this.chargeLeafExit('<Quotient>',parseInt(x/y));
	if (this.getElement('<Remainder>'))
		this.chargeLeafExit('<Remainder>',x%y);
};
// file: DynamicDisplay.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DynamicDisplay = function tersus_DynamicDisplay() {};
tersus.DynamicDisplay.prototype = new DisplayNode();
tersus.DynamicDisplay.prototype.constructor = tersus.DynamicDisplay;
tersus.DynamicDisplay.prototype.defaultTag = 'span';
tersus.DynamicDisplay.prototype.content = null;
tersus.DynamicDisplay.prototype.initViewNode = function()
{
	this.viewNode.style.display='none';
};
// file: DynamicInvocation.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.DynamicInvocation = function tersus_DynamicInvocation() {};
tersus.DynamicInvocation.prototype = new FlowNode();
tersus.DynamicInvocation.prototype.constructor = tersus.DynamicInvocation;
tersus.DynamicInvocation.prototype.start = function ()
{
	var modelId = null;
	modelId = this.getLeafChild('<Model Id>');
	if (! modelId)
	{
		modelExecutionError('<Model Id> is missing',this);
		return;
	}
	/* We create a process of the given model, copy trigger values on to it, and then invoke it
	 * (including outgoing links).
	 *
	 */
	
	var	constructor = tersus.repository.get(modelId);
	var process = new constructor();
	process.element = this.element;
	process.parent = this.parent;
	process.mainWindow = this.mainWindow;
	process.currentWindow = this.currentWindow;
	if (process.triggers)
	{
		for (var i = 0; i < process.triggers.length; i++)
		{
			var trigger = process.triggers[i];
			var dTrigger = this.getElement(trigger.role);
			if (dTrigger)
			{
				if (trigger.isRepetitive)
				{
					var values = dTrigger.getChildren(this);
					dTrigger.removeChildren(this);
					for (var j=0; j< values.length; j++)
					{
						var value = values[j];
						trigger.addAChild(process,value)
					}
				}		
				else
				{
					var value = dTrigger.getChild(this);
					if (value)
						trigger.replaceChild(process,value);
				}
			}
		}
	}
	var node = this;
	process.whenDone = function()
	{
		node.finished();
	};
	process.setStatus(FlowStatus.READY_TO_START);
	process.invoke();
};
// file: Earlier.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Earlier = function tersus_Earlier() {};
tersus.Earlier.prototype = new ActionNode();
tersus.Earlier.prototype.constructor = tersus.Earlier;
tersus.Earlier.prototype.start = function ()
{
	var time1 = this.getChild('<Time 1>');
	var time2 = this.getChild('<Time 2>');
	if (tersus.getDate(time1) < tersus.getDate(time2))
		this.chargeExit('<Yes>', time1);
	else
		this.chargeExit('<No>', time1);
	
	this.finished();
};

// file: EarlierOrEqual.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.EarlierOrEqual = function tersus_EarlierOrEqual() {};
tersus.EarlierOrEqual.prototype = new ActionNode();
tersus.EarlierOrEqual.prototype.constructor = tersus.EarlierOrEqual;
tersus.EarlierOrEqual.prototype.start = function ()
{
	var time1 = this.getChild('<Time 1>');
	var time2 = this.getChild('<Time 2>');
	if (tersus.getDate(time1) <= tersus.getDate(time2))
		this.chargeExit('<Yes>', time1);
	else
		this.chargeExit('<No>', time1);
	
	this.finished();
};

// file: Earliest.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Earliest = function tersus_Earliest() {};
tersus.Earliest.prototype = new ActionNode();
tersus.Earliest.prototype.constructor = tersus.Earliest;
tersus.Earliest.prototype.start = function ()
{
	var trigger = this.getElement('<Times>');
	var list = trigger.getChildren(this);
	if (list&& list.length > 0)
	{
		var earliest = list[0];
		for (var i=1;i<list.length;i++)
		{
			var next = list[i];
			if (tersus.getDate(next) < tersus.getDate(earliest))
				earliest = next;
		}
		this.chargeExit('<Earliest>', earliest);
	}
	this.finished();
};

// file: EmbeddedHTML.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.EmbeddedHTML = function tersus_EmbeddedHTML(){};
tersus.EmbeddedHTML.prototype = new DisplayNode();
tersus.EmbeddedHTML.prototype.constructor = tersus.EmbeddedHTML;
tersus.EmbeddedHTML.prototype.defaultTag = 'div';
tersus.EmbeddedHTML.prototype.onload = function()
{
	tersus.repository.loadHTMLTemplate(tersus.translateResource(this.sharedProperties.templatePath));
};
tersus.EmbeddedHTML.prototype.createViewNode = function()
{
	var template = tersus.repository.getHTMLTemplate(tersus.translateResource(this.sharedProperties.templatePath));
	this.viewNode = importNode(this.currentWindow.document,template);
};
tersus.EmbeddedHTML.prototype.createChildren = function EmbeddedHTML_createChildren()
{
	if (this.displayElements)
	{
		/* Prepare a hash table with the nodes that correspond to different elements*/
		this.childNodeMap = {};
		tersus.EmbeddedHTML.addChildrenToMap(this.viewNode, this.childNodeMap);
		for (var i=0; i<this.displayElements.length; i++)
		{
			var e = this.displayElements[i];
			if ( !e.isRepetitive && ! e.isMethodElement)
			{
				var child = e.createChildWithoutVisuals(this);
				var childViewNode = this.childNodeMap[e.role];
				if (childViewNode)
				{
					child.setViewNode(childViewNode);
					childViewNode.setAttribute('element_name',null);
					child.setEventHandlers();
					child.createChildren();
				}
				else
					alert('Missing element '+e.role+ " in template (path="+this.getPath()+")");
				
			}
		}
	}
	
};
tersus.EmbeddedHTML.addChildrenToMap = function(scope, map)
{
	//Not reusing createNodeMap because in this case we don't traverse the whole hierarchy
	var children = scope.childNodes;
	for (var i=0; i< children.length; i++)
	{
		var childNode = children[i];
		if (childNode.nodeType == 1 /*Node.ELEMENT_NODE*/ )
		{
			var childName = childNode.getAttribute('element_name');
			if (childName != null)
				map[childName]=childNode;
			else					
				tersus.EmbeddedHTML.addChildrenToMap(childNode, map);
		}
	}
};tersus.EmbeddedElement = function EmbeddedElement(){};
tersus.EmbeddedElement.prototype = new tersus.EmbeddedHTML();
tersus.EmbeddedElement.prototype.constructor = tersus.EmbeddedElement;
tersus.EmbeddedElement.prototype.onload = function()
{
};

tersus.EmbeddedElement.prototype.createViewNode = function tersus_EmbeddedElement_createViewNode()
{
	var parentViewNode = this.parent.viewNode;
	this.templateNode = this.parent.childNodeMap[this.element.role];
	if (!this.templateNode)
		modelError("Failed to locate template node for "+this.getPath());
	this.viewNode = this.templateNode.cloneNode(this.templateNode,true);
	this.viewNode.setAttribute('element_name',null);
	this.viewNode.style.display='';
};
tersus.EmbeddedElement.prototype.attachViewNode = function tersus_EmbeddedElement_attachViewNode()
{
	this.templateNode.parentNode.insertBefore(this.viewNode,this.templateNode);
};
// file: Equals.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Equal() {};
Equal.prototype = new ActionNode();
Equal.prototype.constructor = Equal;
Equal.prototype.YES='<Yes>';
Equal.prototype.NO='<No>';
Equal.prototype.start = function ()
{
	var values = this.getTriggerValues();
	var lastValue = null;
	var allEqual = true;
	for (var j=0; j<values.length && allEqual; j++)
	{
		var value = values[j];
		if (lastValue == null)
			lastValue = value;
		else if (! compareValues(lastValue, value))
		{
			allEqual = false;
		}
	}
	if (allEqual)
	{
		if (this.getElement(this.YES))
			this.chargeExit(this.YES, lastValue);
	}
	else
	{
		if (this.getElement(this.NO) != null)
		{
			this.chargeEmptyExit(this.NO);
		}
	}
	this.finished();
	
};
// file: EqualsWithTolerance.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.EqualWithTolerance = function tersus_EqualWithTolerance() {};
tersus.EqualWithTolerance.prototype = new ActionNode();
tersus.EqualWithTolerance.prototype.constructor = tersus.EqualWithTolerance;
tersus.EqualWithTolerance.prototype.start = function ()
{
	var x = this.getLeafChild('<X>');
	var y = this.getLeafChild('<Y>');
	var tolerance = this.getLeafChild('<Tolerance>');
	if (x == null)
		modelExecutionError('Missng value for <X>', this);
	if (y == null)
		modelExecutionError('Missng value for <Y>', this);
	if (tolerance == null)
		modelExecutionError('Missng value for <Tolerance>', this);
	if (Math.abs(x-y) < tolerance)
		this.chargeLeafExit('<Yes>',x)
	else
		this.chargeLeafExit('<No>',x);
};
// file: Exists.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 //Exits - checks if a trigger value was received

Exists = function Exists() {};
Exists.prototype = new ActionNode();
Exists.prototype.constructor = Exists;
Exists.prototype.start = function startExists()
{
	var value = null;
	if (this.triggers)
	{
		for (var i=0; i< this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			if (trigger.isRepetitive)
			{
				var values = trigger.getChildren(this);
				if (values && values.length>0)
				{
					value = values[0];
					break;
				}
			}
			else
			{
				value = trigger.getChild(this);
				if (value != null)
					break;
			}
		}
	}
	if (value != null)
	{
		this.chargeExit('<Yes>', value);
		
	}
	else
	{
		this.chargeEmptyExit('<No>');
	}
	this.finished();

};// file: Expand.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Expand() {};
Expand.prototype = new ActionNode();
Expand.prototype.constructor = Expand;
Expand.prototype.start = function ()
{
	var item = this.getChild('<Item>');
	var node = this;
	item.onExpand = function()
	{
		node.continueAfterExpand();
		item.onExpand = null;
		node.finished();
	};
	node.pause();
	item.expand();
};
Expand.prototype.continueAfterExpand = function()
{
		this.resumeAfterPause();
		var executionContext = this.getExecutionContext();
		executionContext.resume();
};// file: Extract.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('Extract', function()
{
	var text = this.getLeafChild('<Text>');
    if (text != null)
    {
        var beginIndex = this.getLeafChild('<Position>');
        if (beginIndex <0)
        {
	        modelExecutionError('Negative <Position>',this);
    	    return;
    	}
        var length = this.getLeafChild('<Length>');
        var endIndex = text.length;
        if (length != null)
        {
            if (length < 0)
		        modelExecutionError('Negative <Length>',this);
            endIndex = beginIndex + length;
            if (endIndex > text.length)
            {
               modelExecutionError("<Text> ('" + text
                            + "') too short to extract a segment of length "
                            + length + " at position " + beginIndex + ".");
               return;
            }
        }
        var segment = text.substring(beginIndex, endIndex);
        this.chargeLeafExit('<Segment>', segment);
	}
});

// file: FileInputField.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
FileInputField = function FileInputField() {
};
FileInputField.prototype = new DisplayNode();
FileInputField.prototype.constructor = FileInputField;

FileInputField.prototype.isFileInputField = true;

FileInputField.prototype.createViewNode = function createViewNode()
{
    this.fileNode = this.currentWindow.document.createElement('input');
    this.fileNode.type = 'file';
    this.viewNode = this.currentWindow.document.createElement('form');
    this.viewNode.className='inline';
    this.viewNode.appendChild(this.fileNode);
    if (this.sharedProperties.size)
    	this.viewNode.size = this.sharedProperties.size;
};

FileInputField.prototype['get<Value>'] = function getFieldValue()
{
	if (this.children && this.children['<Value>'])
		return this.children['<Value>'];
	if (!this.fileNode || this.fileNode.value == "")
		return null;
	if (! this.inputFile)
	{
		var element = this.getElement('<Value>');
		if (element)
		{
			this.inputFile = element.createChild(this);
			this.inputFile.inputFieldDisplayNode = this;
		}
	}
	return this.inputFile;
};

FileInputField.prototype.registerEventHandler = function(event, domNode)
{
	if (!domNode)
		domNode = this.fileNode;
	DisplayNode.prototype.registerEventHandler.call(this,event,domNode);
};

// file: Find.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Find =  tersus.DatabaseAction.__subclass('tersus.Find');
tersus.Find.prototype.getTablePrototype = function()
{
	return this.getExit('<Records>').getChildConstructor().prototype;
};
tersus.Find.prototype.run = function()
{
	var exit = this.getExit('<Records>');
	if (!exit)
	{
		modelError('Missing exit <Records>',this);
		return;
	}
	var  p = exit.getChildConstructor().prototype;
	var fl = this.getFieldList(p);
	var triggers  = this.triggers;
	if (triggers == null)
		triggers = [];
	var tableName = this.getTableName(p);
	var sqla = [];
	this.addSelectFieldsSQL(sqla, tableName, fl);
	
	var first = true;
	var values = [];
	for (var i=0;i<triggers.length; i++)
	{
		var trigger = triggers[i];
		if (trigger.modelId == BuiltinModels.NOTHING_ID) // Control trigger
			continue;
		if (trigger.role.search(/<.*>$/)>=0) // Distinguished trigger (e.g. <Data Source>)
			continue;
		var field = fl.getField(trigger.role);
		if (first)
		{
			sqla.push('WHERE');
			first = false;
		}
		else
			sqla.push('AND');
		sqla.push(field.sqlName);
		var v = this.getSQLValue(trigger.role);
		if ( v == null)
			sqla.push ('IS NULL');
		else
		{
			sqla.push('= ?');
			values.push(v);
		}
	}
	var orderBy = this.getLeafChild('<Order By>');
	if (orderBy != null)
	{
		sqla.push('ORDER BY');
		sqla.push(orderBy);
	}
	var sql = sqla.join(' ');
	this.execSql(sql, values, function(transaction,results)
	{
		this.outputResults(results, exit);
		this.resumeContext();
	});
};
// file: FindElements.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function FindElements() {};
FindElements.prototype = new ActionNode();
FindElements.prototype.SCOPE_TRIGGER_ROLE='<Scope>';
FindElements.prototype.constructor = FindElements;

FindElements.prototype.start = function ()
{
	var filter = this.createFilter();
	var items = [];
	var scope = this.getChild(this.SCOPE_TRIGGER_ROLE);
	if (scope)	
		scope.scanChildren(filter, {}, items);
	else
	{
		// NO scope specified - scan everywhere
		window.rootDisplayNode.scanChildren(filter, {}, items);
		tersus.unregisterPopupNodes();
		for (var popupId in tersus.popupNodes)
		{
			node = tersus.popupNodes[popupId].scanChildren(filter, {}, items);
		}
	}
	if (items.length == 0)
	{
		var exit = this.getElement('<None>');
		if (exit)
			this.chargeEmptyExit(exit);
	}
	else
	{
		for (var i=0; i<items.length; i++)
		{
			var item = items[i];
			this.accumulateExitValue('<Elements>',item);
		}
	};
	this.finished();
};

FindElements.prototype.createFilter = function()
{
	var filter = {};
	filter.components = [];
	var exit = this.getElement('<Elements>');
	filter.modelId = exit.modelId;
	if (this.triggers)
		for (var i=0; i< this.triggers.length; i++)
		{
			var trigger = this.triggers[i];
			if (trigger.role != FindElements.prototype.SCOPE_TRIGGER_ROLE && trigger.modelId != BuiltinModels.NOTHING_ID)
			{
				var value = trigger.getChild(this);
				filter.components.push ({role:trigger.role,value:value});
			};
		};
	filter.match = function(item)
	{
		if (filter.modelId != tersus.ANYTHING && item.modelId != this.modelId)
			return false;
		for (var i =0; i<this.components.length;i++)
		{
			var component = this.components[i];
			if (component.role == '<Element Name>')
			{
				if (! (item.element && component.value && item.element.role == component.value.leafValue))
					return false;
			}
			else
			{
				var element = item.getElement(component.role)
				if (element)
				{
					var value = element.getChild(item);
					if (value && value.isDataNode)
						value = value.value;  // Get the underlying value (not the wrapper)
					if (!compareValues(value, component.value))
						return false;
						
				}
				else
				{ 
					return false;
				}
			}
		}
		return true;
	};
	return filter;
};
// file: FireEvent.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.FireEvent = function FireEvent() {};
tersus.FireEvent.prototype = new ActionNode();
tersus.FireEvent.prototype.constructor = tersus.FireEvent;
tersus.FireEvent.prototype.start = function ()
{
	var element = this.getChild('<Element>');
	var eventName = this.getLeafChild('<Event Name>');
	var eventSpec;
	for (var eventKey in Events)
	{
		if (Events[eventKey].elementName == eventName)
			eventSpec = Events[eventKey];
	}
	if (!eventSpec)
		eventSpec = new tersus.Event(eventName); // Ad-hoc event
		
	var parameters = {};
	for (var i = 0; i < this.triggers.length; i++)
	{
		var t = this.triggers[i];
		if (t.role.search('<') < 0)
		{
			var v;
			if ( t.isRepetitive)
				v =  t.getChildren(this);
			else
				v = t.getChild(this);
			if (v != null)
				parameters[t.role]=v;
		}
	}
	tersus.async.exec(function()
	{
		window.engine.handleEvent(element, eventSpec, parameters);
	}, true /* wait */);
	this.finished();
}// file: First.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.First = function tesrsus_First(){};
tersus.First.prototype = new ActionNode();
tersus.First.prototype.constructor = tersus.First;
tersus.First.prototype.start = function ()
{
	var trigger = this.getElement('<List>');
	var list = trigger.getChildren(this);
	if (list&& list.length > 0)
	{
		var first = list[0];
		this.chargeExit('<First>', first);
		
	}
	this.finished();
};
// file: FloatClose.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.FloatingClose = function tersus_DialogFooter() {};
tersus.FloatingClose.prototype = new Row();
tersus.FloatingClose.prototype.constructor = tersus.FloatingClose;
tersus.FloatingClose.prototype.attachViewNode = function DialogFooter_attachViewNode()
{
	
	//this.divNode = this.createHTMLElement('div');
	
	//this.divNode.appendChild(this.viewNode);
	if (this.parent&& this.parent.close)
	{
		this.parent.close.appendChild(this.viewNode);
	}

}
//PopupFooter=tersus.FloatingClose; // For backward compatability// file: FloatingToolbar.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.isIE6 = navigator.userAgent.indexOf('MSIE 6') >=0;


	tersus.FloatingToolbar = tersus.PopIn.__subclass('Dialog');
	tersus.FloatingToolbar.prototype.templateURL='floating.html';
	tersus.FloatingToolbar.prototype.createViewNode = function()
	{
		// create mask (this gives modality by blocking UI access to existing content)
		clearSelection(this.currentWindow); // sometimes the original selection is extended to newly created elements
		var d = this.currentWindow.document;
		var r = this.getCurrentRootViewNode();
		//var ml = this.createHTMLChildElement(r,'div');
		//ml.className='dialog_mask';
		//ml.style.zindex = ++ tersus.topZindex;
		//this.maskLayer = ml;
		// create dialog div
		var template = tersus.repository.getHTMLTemplate(this.templateURL);
		var dialog = importNode(d,template);
		this.dialogLayer = dialog;
		dialog.style.position='absolute';
		dialog.className='floating';
		this.viewNode = tersus.findChildNodesByClassName(dialog,'floatBody')[0];
		if (this.viewNode)
		{
			this.close = tersus.findChildNodesByClassName(dialog,'floatClose')[0];
			
		}
		else
			this.viewNode = dialog;
		this.isOpen = true;
		r.appendChild(dialog);
		if (this.header)
		  this.header.innerHTML = tersus.escapeHTML(this.getPopupTitle());
		this.onResize();
		this.hideSelectNodes();
	};
	tersus.FloatingToolbar.prototype.onResize = function()
	{
		if (! (this.isOpen && this.currentWindow && ! this.currentWindow.closed && this.viewNode))
			return;
				this.onResizeChildren();
	}
	tersus.FloatingToolbar.prototype.doClose = function() 
	{
		delete tersus.popupNodes[this.getNodeId()];
	
		if (this.isOpen)
		{
			this.resumeNavigation();
			this.viewNode = null;
			this.header = null;
			var dl = this.dialogLayer;
			//var ml = this.maskLayer;
			this.dialogLayer=null;
			//this.maskLayer=null;
			dl.parentNode.removeChild(dl);
			//ml.parentNode.removeChild(ml);
		}
		this.isOpen = false;
		this.restoreSelectNodes();
	};
	tersus.FloatingToolbar.prototype.hideSelectNodes = function()
	{
	   	if (!tersus.isIE6)
	   		return;
		var l = this.currentWindow.document.body.getElementsByTagName('select');
		this.selectNodes = [];
		for (var i=0;i<l.length;i++)
			this.selectNodes.push(l[i]);
		for (var i=0;i<this.selectNodes.length;i++)
		{
			var n = this.selectNodes[i];
			var placeHolder = this.createHTMLElement('span');
			n.placeHolder=placeHolder;
			n.parentNode.replaceChild(placeHolder,n);			
		}
	
	};
 	tersus.FloatingToolbar.prototype.restoreSelectNodes = function()
	{
		if (this.selectNodes)
		{
			for (var i =0; i<this.selectNodes.length; i++)
			{
				var n =	this.selectNodes[i];
				var placeHolder = n.placeHolder;
				placeHolder.parentNode.replaceChild(n, placeHolder);
				n.placeHolder = null;
			}
		};
	};
	tersus.FloatingToolbar.prototype.setEventHandlers = function()
	{
		DisplayNode.prototype.setEventHandlers.call(this);
		this.dragNode = this.header ? this.header : this.viewNode;
	
		this.registerEventHandler(Events.ON_MOUSEDOWN, this.dragNode);
	};
	tersus.FloatingToolbar.prototype.onMouseDown = function()
	{
		var atts = tersus.currentEventAttributes;
		if (!atts) return;
		if (this.checkTargetElement(atts.targetElement))
		{
			var p = getScreenPosition(this.dialogLayer);
			this.dialogLayer.style.position='absolute';
			this.dialogLayer.style.top  = p.top - getScroll(this.dialogLayer).top;
			this.dialogLayer.style.left = p.left  - getScroll(this.dialogLayer).left;
			this.baseP = p;
			this.baseMouseP = {x:atts.clientX,y:atts.clientY};
			var node = this;
			var b = this.viewNode.ownerDocument.body;
			b.style.cursor = 'pointer';
			b.onmouseup = function(e)
			{
				node.onDrag(e);
				node.endDrag();
				return false; // disable default action (image drag) 
			};
			b.onmousemove = function(e)
			{
				node.onDrag(e);
				return false; //disable default action (image drag)
			}
			return false; //disable default action (image drag)
		}
		return true;// Don't disable default action
	};

	// Checks whether an element is a "good" drag source (doesn't have its own event handling logic)
	tersus.FloatingToolbar.prototype.checkTargetElement = function (targetElement)
	{
		if (targetElement == this.dragNode)
			return true;
		var n = targetElement;
		while (n && n != this.dragNode)
		{
			if (n.onclick || n.onmousedown || n.onmouseup || n.onmousemove || n.ondoubleclick)
				return false;
			if (n.tagName == 'INPUT' || n.tagName == 'TEXTAREA' || n.tagName == 'SELECT' || n.tagName == 'OPTION')
				return false;
			n = n.parentNode;
		}
		return true;
	};
	tersus.FloatingToolbar.prototype.endDrag = function()
	{
		var b = this.viewNode.ownerDocument.body;
		b.onmousemove = null;
		b.onmouseup = null;
		b.style.cursor = 'default';
	
	
	};
	tersus.FloatingToolbar.prototype.onDrag = function(e)
	{
		var atts;
		if (e)
			atts = getEventAttributes(e);
		else
			atts = getEventAttributes(this.currentWindow.event);
		if (!atts) return;
		this.dialogLayer.style.top = this.baseP.top + atts.clientY - this.baseMouseP.y - getScroll(this.dialogLayer).top;
		this.dialogLayer.style.left = this.baseP.left + atts.clientX - this.baseMouseP.x - getScroll(this.dialogLayer).left;;
	
	};

// file: Focus.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('Focus', function()
{
	var e = this.getChild('<Element>');
	if (e.focus)
		e.focus();
	else if (e.viewNode.focus)
		e.viewNode.focus();
});

// file: Forward.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Forward = function tersus_GetElmentName() {};
tersus.Forward.prototype = new ActionNode();
tersus.Forward.prototype.constructor = tersus.Forward;
tersus.Forward.prototype.start = function ()
{
	setTimeout(function () {window.history.forward();},0);
	this.finished();
};
// file: GetCookie.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function GetCookie() {};
GetCookie.prototype = new ActionNode();
GetCookie.prototype.constructor = GetCookie;
GetCookie.prototype.start = function ()
{
	var name = this.getLeafChild('<Name>');
	if (name)
	{
		name=tersus.sqlize(name);
		var value = getCookie(name);
		if (value != null && value.length>0)
			this.chargeLeafExit('<Value>',value);
	}
		
	this.finished();
};
// file: GetElement.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetElement = function tersus_GetElement() {};
tersus.GetElement.prototype = new ActionNode();
tersus.GetElement.prototype.constructor = tersus.GetElement;
tersus.GetElement.prototype.start = function ()
{
	var elementName = this.getLeafChild('<Element Name>');
	var exit = this.getExit('<Element>');
	var parent = this.getChild('<Parent>');
	if (parent && parent.leafValue && parent.leafValue.tagName) // Special handling of html node attributes
	{
		var attributeValue = parent.leafValue.getAttribute(elementName);
		this.chargeLeafExit('<Element>',attributeValue);
	}
	else if (parent != null && parent.getChild)
	{
		
		var element = parent.getElement(elementName);
		var values = null;
		if (element)
		{
			if (element.isRepetitive)
			{
				values = element.getChildren(parent);
				if (values)
				{
					if (!exit.isRepetitive)
						for (var i=0;i<values.length;i++)
							this.chargeExit(exit, values[i]);
					else
						for (var i=0;i<values.length;i++)
							this.accumulateExitValue(exit, values[i]);
											 
				}
			}
			else
			{
				var value = element.getChild(parent);
				if (value != null)
				{
					if (!exit.isRepetitive)
						this.chargeExit(exit, value);
					else
						this.accumulateExitValue(exit, value);
				}
			}
		}
	}
		
	this.finished();
};
// file: GetElementName.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetElementName = function tersus_GetElementName() {};
tersus.GetElementName.prototype = new ActionNode();
tersus.GetElementName.prototype.constructor = tersus.GetElementName;
tersus.GetElementName.prototype.start = function ()
{
	var displayElement = this.getChild('<Element>');
	if (displayElement && displayElement.element)
	{
		var name = displayElement.element.role;
		this.chargeLeafExit('<Name>',name);
	}
		
	this.finished();
};
// file: GetEventAttributes.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetEventAttributes = function tersus_GetEventAttributes() {};
tersus.GetEventAttributes.prototype = new ActionNode();
tersus.GetEventAttributes.prototype.constructor = tersus.GetEventAttributes;
tersus.GetEventAttributes.prototype.start = function()
{
	var atts = tersus.currentEventAttributes;
	if (atts)
	{
		this.chargeLeafExit('<Event Type>', atts.type);
		this.chargeLeafExit('<Key Code>', atts.keyCode);
		this.chargeLeafExit('<Mouse Button>',atts.button);
		this.chargeLeafExit('<Mouse X>',atts.clientX);
		this.chargeLeafExit('<Mouse Y>',atts.clientY);
		var e = this.getExit('<Target Element>');
		if (e)
			this.chargeExit(e, DisplayNode.findNodeForDocumentNode(atts.targetElement));
	}
	
};
// file: GetIndex.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('GetIndex', function()
{
	var e = this.getChild('<Element>');
	if (e.element && e.element.isRepetitive)
	{
		var siblings = e.element.getChildren(e.parent);
		for (var i=0;i<siblings.length;i++)
		{
			if (siblings[i] == e)
				this.chargeLeafExit('<Index>',i);
		}
	}
	
});

// file: GetMapEntry.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('GetMapEntry', function()
{
	var map = this.getChild("<Map>");
	if (map && map.leafValue)
		map = map.leafValue;
	
	var key = this.getChild("<Key>");
	if (key && key.leafValue != null)
		key = key.leafValue;
		
	var value = map[key];
	if (value)
		this.chargeExit('<Value>',value);
	else
		this.chargeEmptyExit('<None>',value);	
});
// file: GetModel.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetModel = function tersus_GetModel() {};
tersus.GetModel.prototype = new ActionNode();
tersus.GetModel.prototype.constructor = tersus.GetModel;
tersus.GetModel.prototype.start = function ()
{
	var modelId = null;
	if (this.getElement('<Model Id>') && this.getElement('<Instance>'))
		modelError("'<Model Id>' and '<Instnace>' shouldn't both be specified");
	if (this.getElement('<Model Id>'))
	{
		modelId = this.getLeafChild('<Model Id>');
	}
	else
	{
		instance = this.getChild('<Instance>');
		if (instance)
			modelId = instance.modelId;
	}
	var model = null;
	if (modelId)
		model = tersus.repository.get(modelId).prototype;
	if (model)
	{
		if (! model.wrapper)
		{
			var exit =  this.getExit('<Model>');
			model.wrapper = exit.createChildInstance();
			model.wrapper.model = model;
		}
		this.chargeExit('<Model>',model.wrapper);
	}
	this.finished();
};
// file: GetNumberedItem.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetNumberedItem = function tersus_GetNumberedItem() {};
tersus.GetNumberedItem.prototype = new ActionNode();
tersus.GetNumberedItem.prototype.constructor = tersus.GetNumberedItem;
tersus.GetNumberedItem.prototype.start = function ()
{
	var listTrigger = this.getElement('<List>');
	if (!listTrigger)
	{
		modelError("Missing trigger <List>");
		return;
	}
	var list = listTrigger.getChildren(this);
	if (list)
	{
		var index = this.getLeafChild('<Index>');
		if (!index)
		{
			modelExecutionError('No <Index> specified',this);
			return;
		}
		if (index>=1 && index <= list.length)
			this.chargeExit('<Item>', list[index-1]);
			
		else if (this.getElement('<Invalid Index>'))
			this.chargeLeafExit('<Invalid Index>',index);
		else
		{
			modelExecutionError('Invalid trigger '+index+' (list size is '+list.length + ')', this)
			return;
		}
	}
	this.finished();
};
// file: GetPageParamters.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function GetPageParameters() {};
GetPageParameters.prototype = new FlowNode();
GetPageParameters.prototype.constructor = GetPageParameters();

GetPageParameters.prototype.start = function()
{
	for (var i=0; i< this.exits.length; i++)
	{
		var exit = this.exits[i];
		var paramValue = tersus.searchParams[exit.role];
		if (paramValue)
		{
			this.setLeafChild(exit.role, paramValue, Operation.REPLACE);
		}
	}
};// file: GetParent.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GetParent = function GetParent(){};
tersus.GetParent.prototype = new ActionNode();
tersus.GetParent.prototype.constructor = tersus.GetParent;
tersus.GetParent.prototype.start = function()
{
	var trigger = this.getTrigger('<Element>');
	var parent = null;
	if (trigger != null) // Get the parent of the specified element
	{
		var element = trigger.getChild(this);
		if (element)
		{
			parent = element.parent;
		}
	}
	else // Get the DisplayNode that contains this action
	{
		parent = this;
		while (parent && !parent.isDisplayNode)
			parent = parent.parent;
	}
	if (parent)
		this.chargeExit('<Parent>',parent);
	this.finished();
	
};
// file: GetPosition.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('GetPosition', function()
{
	var text = this.getLeafChild('<Text>');
	var segment = this.getLeafChild('<Segment>');
	if (text != null && segment != null)
	{
		var position = text.indexOf(segment);
			if (position >= 0)
				this.chargeLeafExit('<Position>',position);
			else
			{
				if (this.getExit('<Not Found>') != null)
					this.chargeLeafExit('<Not Found>', segment);
				else
					modelExecutionError("Segment '" + segment + "' is not contained in '" + 
						text + "' but " + NOT_FOUND + " exit is missing", this);
			}	
	}
});// file: GetStyleAttribute.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('GetStyleAttribute', function()
{
	var e = this.getChild('<Element>');
	var n = this.getLeafChild('<Attribute>');
	var a = tersus.getJsAttributeName(n);
	if (e && e.viewNode && a)
	var v = e.viewNode.style[a];
	this.chargeLeafExit('<Value>',v);
});

// file: GetTableSelection.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function GetTableSelection() {};
GetTableSelection.prototype = new FlowNode();
GetTableSelection.prototype.constructor = GetTableSelection;
GetTableSelection.prototype.start = function getTableSelection()
{
	var table = this.getChild('<Table>');
	var selection = table.selectedRow;
	if (selection)
		this.setChild('<Selected Row>', selection, Operation.REPLACE);
	else
		this.setLeafChild('<None Selected>', 'none', Operation.REPLACE);
};
// file: GetWeek.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function GetWeek() {};
GetWeek.prototype = new FlowNode();
GetWeek.prototype.constructor = GetWeek;
GetWeek.prototype.start = function getWeek()
{
	var date = this.getChild('<Date>');
	if (!date)
		return;
	var year = date.getYear();
	var month = date.getMonth();
	var day = date.getDay();
	// Algorithm from http://www.tondering.dk/claus/calendar.html

	var a = Math.floor((14-month) / 12);
	var y = year + 4800 - a;
	var m = month + 12 * a - 3;
	var b = Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400);
	var J = day + Math.floor((153 * m + 2) / 5) + 365 * y + b - 32045;
	var d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461;
	var L = Math.floor(d4 / 1460);
	var d1 = ((d4 - L) % 365) + L;
	var week = Math.floor(d1/7) + 1;
	var weekYear = year;
	if (week == 1 && month == 12)
		weekYear = year+1;
	if (week >= 52 && month == 1)
		weekYear = year-1;
		
	this.setLeafChild('<Year>', weekYear, Operation.REPLACE);
	this.setLeafChild('<Week Number>', week, Operation.REPLACE);		
};
// file: GotoURL.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
tersus.GotoURL = ServiceNode.__subclass('tersus.GotoURL');
tersus.GotoURL.prototype.excludedTriggers=new Set(['<URL>','<Method>', '<Replace>','<Relaod>', '<Target Window>']);
tersus.GotoURL.prototype.start = function ()
{
	var url = this.getLeafChild('<URL>');
	var replace = this.getLeafChild('<Replace>');
	var reload = this.getLeafChild('<Reload>');
	var targetWindow = this.getLeafChild('<Target Window>');
	if (reload != false)
		reload = true;
	var method = this.getLeafChild('<Method>');
	if (url == null)
		url = tersus.rootURL;
	
	if (method && method.search('^post$','i') >=0)
	{
		var form = this.prepareForm();
		if (targetWindow)
			form.target  = targetWindow;
		if (url.indexOf('?')>=0)
		{
			modelExecutionError('POST parameters are not part of the URL and should be provided using separate triggers');
			return;
		}
		form.action = url;
		form.method='POST';
		form.submit();
		for (var i=0; i< this.nodesToRemove.length; i++)
		{
			var node = this.nodesToRemove[i];
			node.parentNode.removeChild(node);
		}
	}
	else
	{
		var serializer;
		if (this.triggers)
		{
			var n = this.triggers.length;
			for (var i=0;i<n;i++)
			{
				var t = this.triggers[i];
				if (this.excludedTriggers.contains(t.role) || t.modelId == BuiltinModels.NOTHING_ID)
					continue;
				var value = t.getChild(this);
				if (value == null)
					continue;
				if (url.indexOf('#') < 0 && url.indexOf('?')<0)
					url+='?';
				else
					url += '&';
				url += encodeURIComponent(t.role)+'='+encodeURIComponent(value.leafValue);				
			}
		}
		if (targetWindow)
		{
			var w = window.open(url,targetWindow);
			if (w && w.focus)
				tersus.async.exec(function() {w.focus();}, false /* don't wait */); // Needed in Firefox
			else
				alert('Your browser blocks pop-up windows.\nTo use this application, please configure the browser to allow this site to open pop-up windows.');
		}				
		else
			tersus.async.exec(function () {tersus.gotoURL(url, replace, reload);}, false /* don't wait */);
	}
		
	this.finished();
};
// file: Greater.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Greater = function tersus_Greater() {};
tersus.Greater.prototype = new ActionNode();
tersus.Greater.prototype.constructor = tersus.Greater;
tersus.Greater.prototype.start = function ()
{
	var x = this.getLeafChild('<X>');
	var y = this.getLeafChild('<Y>');
	if (x > y)
		this.chargeLeafExit('<Yes>',x);
	else
		this.chargeLeafExit('<No>',x);
};
// file: GreaterOrEqual.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.GreaterOrEqual = function tersus_GreaterOrEqual() {};
tersus.GreaterOrEqual.prototype = new ActionNode();
tersus.GreaterOrEqual.prototype.constructor = tersus.GreaterOrEqual;
tersus.GreaterOrEqual.prototype.start = function ()
{
	var x = this.getLeafChild('<X>');
	var y = this.getLeafChild('<Y>');
	if (x >= y)
		this.chargeLeafExit('<Yes>',x);
	else
		this.chargeLeafExit('<No>',x);
};
// file: Grid.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Grid = function tersus_Grid() {};
tersus.Grid.prototype = new Table();
tersus.Grid.prototype.constructor = tersus.Grid;
tersus.Grid.prototype.createCaption = tersus.Grid.prototype.createHeader = function() {};
// file: HTMLDisplay.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.HTMLDisplay = function tersus_HTMLDisplay(){};
tersus.HTMLDisplay.prototype = new tersus.DisplayField();
tersus.HTMLDisplay.prototype.constructor = tersus.HTMLDisplay;
tersus.HTMLDisplay.prototype.defaultTag = 'div';
tersus.HTMLDisplay.prototype.allowHTMLTags = true;
// file: HTMLEditor.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.HTMLEditor = function tersus_HTMLEditor(){};
tersus.HTMLEditor.prototype = new DisplayNode();
tersus.HTMLEditor.prototype.constructor = tersus.HTMLEditor;
tersus.HTMLEditor.prototype.defaultTag = 'textarea';
tersus.HTMLEditor.prototype.createViewNode = function()
{
	DisplayNode.prototype.createViewNode.call(this);
	this.open();
};
tersus.HTMLEditor.commandMap = { 'mceImage':'<Insert Image>'}
tersus.HTMLEditor.execCommandHandler = function tersus_html_editor_command_handler(editor_id, elm, command, user_interface, value)
{
	if (!elm)
		return false;
	if ( ! tersus.HTMLEditor.commandMap[command])
		return false;
	var w = getParentWindow(elm).parent;
	var tMCE = tersus.HTMLEditor.getTinyMCE(w);
	if (tMCE)
	{
		var editorInstance = tMCE.getInstanceById(editor_id);
		var nodeId = editor_id.match(/mce_(\d+)/)[1];
		var node = tersus.findNode(nodeId);
		
		var element = node.getElement(tersus.HTMLEditor.commandMap[command]);
		if (element)
		{
			var child = element.createChild(node);
			resumeRoot(); // child will be executerd
			if (child.isButton) // we need to simulate pushing the button
				child.onClick();

			
			return true;
		}

	}

	return false;
	
};
tersus.HTMLEditor.defaultSettings = 
{
	mode : "none"
	,theme : "advanced" 
	,content_css : "Styles?timestamp="+tersus.lastStyleModification
	,execcommand_callback : tersus.HTMLEditor.execCommandHandler
};
tersus.HTMLEditor.prototype.createChildren = function()
{ // supressing child creation - child elements represent components of the externally defined editor 
  // in the future we may support adding elements to the display
};
tersus.HTMLEditor.loaded = false;
tersus.HTMLEditor.loading = false;
window.tinyMCE_onload =  function tinyMCE_onload()
{
	var w = window;
	if (tersus.HTMLEditor.customizeTinyMCE)
		tersus.HTMLEditor.customizeTinyMCE(w);	
	w.tinymce.dom.Event.domLoaded=true;
	var s = {}; // settings for tinyMCE
	var d = tersus.HTMLEditor.defaultSettings;
	for (p in d)
		s[p]= d[p];
	var u = tersus.HTMLEditor.settings; // user settings
	if (u)
	{
		for (p in u)
			s[p]=u[p];
	}
	w.tinyMCE.init(s);
	w.tinyMCE_loaded = true;
	w.tinyMCE_loading = false;
	tersus.foreach(w.tinyMCE_openQueue, function(node)
	{
		node.showEditor();
	});
}
tersus.HTMLEditor.prototype.open = function()
{
	var node = this;
	var w = this.currentWindow;
	if (!w.tinyMCE_loaded && !w.tinyMCE_loading)
	{
		w.tinyMCE_loading = true;
		w.tinyMCE_openQueue = [];
		tersus.loadScript('tiny_mce/tiny_mce_src.js',w);
	}
 	if (w.tinyMCE_loaded)
		tersus.async.exec( function () {node.showEditor();}, false /* don't wait */);
 	else
	 	w.tinyMCE_openQueue.push(node);
	this.open = true;
};
tersus.HTMLEditor.prototype.showEditor = function()
{
	var tMCE = this.getTinyMCE();
	if (tMCE)
	{
		var id = 'mce_'+this.getNodeId();
		this.editorId = this.viewNode.id = this.viewNode.name = id;
        tMCE.execCommand('mceAddControl', false, id);
//		tinyMCE.execCommand('mceFocus',false,this.getEditorId());
//		editorInstance.select();
	}
		
	else
		modelExecutionError("HTML Editor not available",this);
};
tersus.HTMLEditor.prototype.getEditor = function()
{
	var tMCE = this.getTinyMCE();
	if (tMCE && this.open)
		return tMCE.get(this.editorId);
	else
		return null;
};
tersus.HTMLEditor.prototype.invokeAction  = function(action, caller)
{
	//Todo - some actions (e.g. focus) may need to be invoked as global command
	//     - some actions may be implemented in the model 
	var editor = this.getEditor();
	if (editor)
	{
		var value = caller.getLeafChild('Value');
		editor.execCommand(action, false, value);
		editor.execCommand('mceRepaint');
	}
};
tersus.HTMLEditor.prototype.destroy = function()
{
	if (this.open)
	{
		var tMCE = this.getTinyMCE();
		var node = this;
		if (tMCE)
		{
			// Because of timing issues it is possible that tinyMCE still doesn't know about our editor.
			// In such cases we don't remove it (and there's a danger of memory leak - probably mainly on older browsers)
			if (this.editorId && tMCE.get(this.editorId))
				tMCE.execCommand('mceRemoveControl', false, node.editorId);
		}
		this.open = false;
	}
	
	DisplayNode.prototype.destroy.call(this);
};
tersus.HTMLEditor.getTinyMCE = function (w)
{
	var tMCE = null;
	try
	{
		if (w && ! w.closed)
			tMCE = w.tinyMCE;
	}
	catch (e)
	{
	}
	return tMCE;
};
tersus.HTMLEditor.prototype.getTinyMCE = function()
{
	return tersus.HTMLEditor.getTinyMCE(this.currentWindow);
};
tersus.HTMLEditor.prototype['get<HTML Text>'] = function()
{
	var editor = this.getEditor();
	if (editor)
		return editor.getContent();
};
tersus.HTMLEditor.prototype['get<Selected HTML Text>'] = function()
{
	var editor = this.getEditor();
	if (editor)
	{
		var sel = new TinyMCE_Selection(editor);
		return sel.getSelectedHTML();
	}
};
tersus.HTMLEditor.prototype['get<Selected HTML Element>'] = function()
{
	var editor = this.getEditor();
	if (editor)
	{
		var sel = editor.selection;
		if (sel)
			return sel.getNode();
	}
};
tersus.HTMLEditor.setHTML = tersus.HTMLEditor.prototype['set<HTML Text>'] = function(text)
{
	if (!this.open)
	{
		alert('Editor Not Open');
		return;
	}
	var node = this;
	var f = function()
	{
		var editor = node.getEditor();
		if (editor)
			setTimeout(function(){editor.setContent(text);},100);
		else
			setTimeout(f, 100);
	}
	setTimeout(f, 100);
};

// file: HTMLTag.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 var HTML_ATTRIBUTES = 'abbr,accept,accept-charset,accesskey,action,align,alink,alt,archive,axis,background,bgcolor,border,cellpadding,cellspacing,char,charoff,charset,checked,cite,class,classid,clear,code,codebase,codetype,color,cols,colspan,compact,content,coords,data,datetime,declare,defer,dir,disabled,enctype,face,for,frame,frameborder,headers,height,href,hreflang,hspace,http-equiv,id,ismap,label,lang,language,link,longdesc,marginheight,marginwidth,maxlength,media,method,multiple,name,nohref,noresize,noshade,nowrap,object,onblur,onchange,onclick,ondblclick,onfocus,onkeydown,onkeypress,onkeyup,onload,onmousedown,onmousemove,onmouseout,onmouseover,onmouseup,onreset,onselect,onsubmit,onunload,profile,prompt,readonly,rel,rev,rows,rowspan,rules,scheme,scope,scrolling,selected,shape,size,span,src,standby,start,style,summary,tabindex,target,text,title,type,usemap,valign,value,valuetype,version,vlink,vspace,width';
var STYLE_ATTRIBUTES = 'azimuth,background,background-attachment,background-color,background-image,background-position,background-repeat,border,border-collapse,border-color,border-spacing,border-style,border-top,border-right,border-bottom,border-left,border-top-color,border-right-color,border-bottom-color,border-left-color,border-top-style,border-right-style,border-bottom-style,border-left-style,border-top-width,border-right-width,border-bottom-width,border-left-width,border-width,bottom,caption-side,clear,clip,color,content,counter-increment,counter-reset,cue,cue-after,cue-before,cursor,direction,display,elevation,empty-cells,float,font,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,height,left,letter-spacing,line-height,list-style,list-style-image,list-style-position,list-style-type,margin,margin-top,margin-right,margin-bottom,margin-left,marker-offset,marks,max-height,max-width,min-height,min-width,orphans,outline,outline-color,outline-style,outline-width,overflow,padding,padding-top,padding-right,padding-bottom,padding-left,page,page-break-after,page-break-before,page-break-inside,pause,pause-after,pause-before,pitch,pitch-range,play-during,position,quotes,richness,right,size,speak,speak-header,speak-numeral,speak-punctuation,speech-rate,stress,table-layout,text-align,text-decoration,text-indent,text-shadow,text-transform,top,unicode-bidi,vertical-align,visibility,voice-family,volume,white-space,widows,width,word-spacing,z-index';
tersus.HTML_ATTRIBUTES = new Set(HTML_ATTRIBUTES.split(','));
var BOOLEAN_HTML_ATTRIBUTES = 'readonly,disabled'
tersus.BOOLEAN_HTML_ATTRIBUTES = new Set(BOOLEAN_HTML_ATTRIBUTES.split(','));
tersus.STYLE_ATTRIBUTES = new Set(STYLE_ATTRIBUTES.split(','));
tersus.HTMLTag = DisplayNode.__subclass('tersus.HTMLTag', function()
{
	this.dynamicAttributeElements = {};
	this.HTMLAttributeElements = [];
	this.styleAttributeElements = [];
});
tersus.HTMLTag.prototype.isHTMLTag = true;
tersus.propertyConversionMap = { 
	styleclass:'class',
	'style class':'class',
	wrappertag:'wrapper_tags',
	wrapperstyleclass:'wrapper_classes',
	path:'src'
};


tersus.HTMLTag.prototype.isHTMLTag = true;
tersus.convertProperty = function(p)
{
	var l = p.toLowerCase(); 
	var c = tersus.propertyConversionMap[l];
	return c ? c: l;
};
DisplayElement.prototype.isHTMLPrepared = false;
DisplayElement.prototype.prepareForHTML = function()
{
	if (this.isHTMLPrepared)
		return;
	this.isHTMLPrepared = true;
	var childPrototype = this.getChildConstructor().prototype;
	if (!childPrototype || !childPrototype.isHTMLTag)
		return;
	this.prepHTML = childPrototype.prepareForHTML(this);
	childPrototype.prepareChildrenForHTML();
};
tersus.HTMLTag.prototype.prepareChildrenForHTML = function()
{
	if (this.displayElements)
	{
		for (var i=0;i<this.displayElements.length;i++)
		{
			var e = this.displayElements[i];
			if (e.prepareForHTML)
				e.prepareForHTML();
		}
	}
};
tersus.HTMLTag.prototype.prepareForHTML = function(e)
{
	var props = {};
	var prep = {};
	for (var p in this.sharedProperties)
	{
		var v = this.sharedProperties[p];
		if (v != null && v != ' ')
			props[tersus.convertProperty(p)]=v;
	} 
	if (e)
	for (var p in e.properties)
	{
		var v = e.properties[p];
		if (v != null && v != ' ')
			props[tersus.convertProperty(p)]=v;
	}
	 
	prep.staticStyle = '';
	var html = '';
	for (var p in props)
	{
		var v = props[p];
		var dynamicElement =  this.dynamicAttributeElements[p];
		if (dynamicElement)
		{
			//Prepare default value
			if (prep.defaultValues == null)
				prep.defaultValues = {};
			prep.defaultValues[dynamicElement.role]=v;
		}
		else
		{
			//Parepare static value
			if (tersus.STYLE_ATTRIBUTES.contains(p))
				prep.staticStyle += p + ':' + v+';';
			else if (tersus.BOOLEAN_HTML_ATTRIBUTES.contains(p))
			{
				if (v)
					html+= " " + p;	
			}
			if (tersus.HTML_ATTRIBUTES.contains(p))
				html += " " + p +'="'+v+'"'; 	
		}
	}
	prep.tag = props.tag;
	prep.HTMLPrefix = '';
	prep.HTMLSuffix = '';
	prep.wrapper_tags = null;
	if (props.wrapper_tags)
	{
		var tags = prep.wrapper_tags = props.wrapper_tags.split(',');
		if (tags.length > 0)
			prep.wrapper_tag = tags[0];
		var classes = [];
		if (props.wrapper_classes)
		{
			classes = props.wrapper_classes.split(',');
		}
		
		for (var i=0;i<tags.length;i++)
		{
			var t = tags[i];
			var c = null;
			if (i< classes.length)
				c = classes[i];
			if (c)
				prep.HTMLPrefix += '<'+t+' class="'+c+'">';
			else
				prep.HTMLPrefix += '<'+t+'>';
			prep.HTMLSuffix = '</'+t+'>'+prep.HTMLSuffix;
		}
	}
	prep.HTMLPrefix += '<'+prep.tag + html;
	if (prep.staticStyle.length>0 && this.styleAttributeElements.length ==0)
		prep.HTMLPrefix += ' style="'+prep.staticStyle+'"';
	prep.HTMLPrefix += ' lid="';
	prep.HTMLSuffix = '</'+prep.tag+'>'+prep.HTMLSuffix;
	prep.simpleHTML = this.HTMLAttributeElements.length == 0 && this.styleAttributeElements.length ==0 && !this.getElement('<Visible>');
	return prep;
};
 
tersus.HTMLTag.prototype.reset = function()
{
	this.removeAll();
	this.create();
};
tersus.HTMLTag.prototype.create = tersus.HTMLTag.prototype.copyValue = function(value)
{
	if (this.element && !this.element.isHTMLPrepared)
		this.element.prepareForHTML();
	var nodeMap = {};
	var htmlV = [];
	var legacyNodes = []; // nodes that are not instances of HTMLTag and need to be copied the old way
	this.copyValueOpt(value, nodeMap, htmlV, legacyNodes);
	var html = htmlV.join('');
	var domNode = html2Node(html, this.currentWindow.document);
	var prev = this.wrapperNode ? this.wrapperNode: this.viewNode; // TODO (x) use placeHolderNode;
	this.viewNode = domNode;
	var wt = this.prep.wrapper_tags;
	if (wt)
	{
		this.wrapperNode = this.viewNode;
		for (var i=0;i<wt.length;i++)
			this.viewNode = this.viewNode.firstChild;
	}
	else
		this.wrapperNode = null;
	if (prev)
		prev.parentNode.replaceChild(domNode, prev);
	else
		this.attachViewNode();
	this.setEventHandlers();
	this.attachHierarchy(nodeMap);
	for (var i=0;i<legacyNodes.length;i++)
	{
		var n = legacyNodes[i];
		n.create(n.valueToCopy);
		n.valueToCopy = null;
	}
};
tersus.HTMLTag.prototype.onload = function()
{
	this.createEventHandlerList();
};
tersus.HTMLTag.prototype.copyValueOpt = function(value, nodeMap, htmlV, legacyNodes)
{
	if (this.element && this.element.prepHTML)
	{
		this.prep = this.element.prepHTML;
	}
	else
	{
		if (!this.prepHTML)
		{
			{
				var prototype = this.getPrototype();
				prototype.prepHTML = prototype.prepareForHTML(null);
				prototype.prepareChildrenForHTML();
			}
		}
		this.prep = this.prepHTML;
	}
	// Copy default values into instance
	var def = this.prep.defaultValues;
	if (def != null)
	{
		for (var role in def)
		{
			this.setLeafChild(role, def[role], Operation.REPLACE);
		}
	}
	if (value != null)
		this.leafValue = value.leafValue;
	else 
		this.leafValue = null;
	if (!this.isGroup)
	{
		htmlV.push(null); // placeHolder for tag opening; we can't create the tag before we copy values
		var openIndex = htmlV.length-1;
	}
	if (this.elements)
	{
		for (var elementRole in this.elements)
		{
			var element = this.getElement(elementRole);
			if (element)
			{
				if (element.isRepetitive)
				{
					if (value)
					{
						var childValues = value.getChildren(elementRole);
						for (var i=0;i<childValues.length;i++)
						{
							var oldChild = childValues[i];
							if (element.isDisplayElement)
							{
								var newChild =  element.createChildWithoutVisuals(this, oldChild.modelId);
								if (newChild.isHTMLTag)
									newChild.copyValueOpt(oldChild, nodeMap,htmlV, legacyNodes);
								else
								{
									newChild.valueToCopy = oldChild;
									legacyNodes.push(newChild);
								}
							}
							else
							{
								var newChild = oldChild; //No need to clone non-display elements
								element.addAChild(this, newChild);
							}
						}
					}
				}
				else
				{
					var oldChild = value ? value.getChild(elementRole) : null;
					if (element.isDisplayElement && (element.alwaysCreate || oldChild != null))
					{
						var newChild =  element.createChildWithoutVisuals(this, oldChild? oldChild.modelId:null);
						if (newChild.isHTMLTag)
							newChild.copyValueOpt(oldChild, nodeMap,htmlV,legacyNodes);
						else
						{
							newChild.valueToCopy = oldChild;
							legacyNodes.push(newChild);
						}
						Element.prototype.replaceChild.call(element,this, newChild);
					}
					else if (oldChild != null)
						element.replaceChild(this, oldChild);
					
				}
			}
		}	
	}
	if (! this.isGroup)
	{
		var nodeIdS = '' + this.getNodeId();
		nodeMap[nodeIdS] = this;
		var e = this.element;
		var prep = this.prep;
		if (prep.simpleHTML)
		{
			htmlV[openIndex] = prep.HTMLPrefix + nodeIdS+'">';
		}
		else
		{
			var hv = [];
			hv.push(prep.HTMLPrefix);
			hv.push(nodeIdS);
			hv.push('" ');
			for (var i=0;i<this.HTMLAttributeElements.length; i++)
			{
				var e = this.HTMLAttributeElements[i];
				var v = e.getChild(this);
				if ( v!=null)
				{
					if (tersus.BOOLEAN_HTML_ATTRIBUTES.contains(e.role))
					{
						if (v)
						{
							hv.push(e.attributeName);
							hv.push(' ');
						}
						
					}
					else
					{
						hv.push(e.attributeName);
						hv.push('="');
						hv.push(v.leafValue);
						hv.push('" ');
					}
				}
			}
			if (this.styleAttributeElements.length > 0 || e.staticStyle || this.visible == false)
			{
				hv.push(' style="');
				hv.push(prep.staticStyle);
				for (var i=0;i<this.styleAttributeElements.length; i++)
				{
					var e = this.styleAttributeElements[i];
					var v = e.getChild(this);
					if ( v!=null && v.leafValue != null)
					{
						hv.push(e.attributeName);
						hv.push(':');
						hv.push(v.leafValue);
						hv.push(';');
					}
				};
				if (!this.visible)
					hv.push('display:none;');
				hv.push('"');
			}
			hv.push('>');
			htmlV[openIndex] = hv.join('');
		}
			
		this.addHTMLTagContent(htmlV);
		htmlV.push(prep.HTMLSuffix);
	}
};
tersus.HTMLTag.prototype.addHTMLTagContent = function(htmlV)
{
	if (!this.displayElements)
		htmlV.push(this.escapeHTML(this.valueStr));
};

tersus.HTMLTag.prototype.attachHTMLNode = function(e)
{
	this.viewNode = e;
	var wt = this.prep.wrapper_tags;
	if (wt)
	{
		this.wrapperNode = this.viewNode;
		for (var i=0; i< wt.length;i++)
			this.wrapperNode = this.wrapperNode.parentNode;
	}
	if (this.hasEventHandlers)
		this.setEventHandlers();
};
tersus.HTMLTag.prototype.attachHierarchy = function (nodeMap) 
{
	var elements = this.viewNode.getElementsByTagName('*');
	for (var i=0;i<elements.length; i++)
	{
		var e = elements[i];
		var lid = e.getAttribute('lid');
		if (lid)
		{
			var n = nodeMap[lid];
			if (n)
				n.attachHTMLNode(e);
		}
	}
};
//Todo (?) - merge HTMLTag and DisplayNode so that optimization is the default
tersus.HTMLTag.prototype.createEventHandlerList = function createEventHandlerList()
{
	this.eventHandlerList = [];
	for (var key in Events)
	{
		var eventType = Events[key];
		if (this.hasEventHandler(eventType) && eventType.jsName)
			this.eventHandlerList.push(eventType);
	}
	this.isLocationChangeListener = this.hasEventHandler(Events.ON_LOCATION_CHANGE);
	
	this.hasEventHandlers = this.eventHandlerList.length > 0 || this.isLocationChangeListener;
};
tersus.HTMLTag.prototype.setEventHandlers = function DisplayNode_setEventHandlers()
{
	for (var i=0; i<this.eventHandlerList.length; i++)
	{
		var eventType = this.eventHandlerList[i];
		this.registerEventHandler(eventType);
	}
	if (this.isLocationChangeListener)
		tersus.locationChangeListeners.push(this.getNodeId());
};

tersus.HTMLTag.prototype.addIntermediateDataElement = function addIntermediateDataElement(role, modelId)
{
	var element = null;
	if (this.getGetter(role) && role != '<Style Class>' && role != '<Style>')
	{
		element = new MethodElement(this, role, modelId);
	}
	else if (role.search(/^<.*>$/)>=0) 
	{
		var p = tersus.convertProperty(role.substring(1,role.length-1));
		if (tersus.HTML_ATTRIBUTES.contains(p))
		{
			element = new tersus.HTMLAttributeElement(this,role,modelId);
			this.HTMLAttributeElements.push(element);
			this.dynamicAttributeElements[p]=element;
		}
		else if (tersus.STYLE_ATTRIBUTES.contains(p))
		{
			element = new tersus.StyleAttributeElement(this,role,modelId);
			this.styleAttributeElements.push(element);
			this.dynamicAttributeElements[p]=element;
		}
		else
		 	modelError("Unknown property \""+p+"\" for data element \""+role+"\"",this);
	}
	else
	{
		element = new FlowDataElement(role, modelId);
	}
	return this.addElement(element);
};

tersus.HTMLAttributeElement = DataElement.__subclass('HTMLAttributeElement', function(owner, role, modelId)
{
	this.owner = owner;
	this.role = role;
	this.modelId = modelId;
	this.attributeName = tersus.convertProperty(role.substring(1,role.length-1));
});
tersus.HTMLAttributeElement.prototype.replaceChild = function replaceChild(parent, value)
{
	DataElement.prototype.replaceChild.call(this, parent,value);
	var v = value != null ? value.leafValue : null;
	if (parent.viewNode)
	{
		if (this.attributeName == 'class')
		{
			if (v == null) v = '';
			parent.viewNode.className = v;
		}
		else if (tersus.BOOLEAN_HTML_ATTRIBUTES.contains(this.attributeName))
		{
			parent.viewNode[this.attributeName] = v;
		}
		else
			parent.viewNode.setAttribute(this.attributeName, v);
	}
};
tersus.HTMLAttributeElement.prototype.removeChild = function removeChild(parent)
{
	DataElement.prototype.removeChild.call(this, parent);
	if (parent.viewNode)
	{
		if (this.attributeName == 'class')
			parent.viewNode.className = '';
		else
			parent.viewNode.setAttribute(this.attributeName, null);
	}
};

tersus.HTMLAttributeElement.prototype.getChild = function getChild(parent)
{
	if (parent.viewNode)
	{
		var leafValue;
		if (this.attributeName == 'class')
		{
			leafValue = parent.viewNode.className;
			if (leafValue = '') 
				leafValue = null;
		}
		else if (tersus.BOOLEAN_HTML_ATTRIBUTES.contains(this.attributeName))
			leafValue = parent.viewNode[this.attributeName];
		else
			leafValue = parent.viewNode.getAttribute(this.attributeName);
		var dataValue = this.createChildInstance();
		dataValue.setLeaf(leafValue);
		return dataValue;

	}
	else
		return DataElement.prototype.getChild.call(this, parent);
};
tersus.StyleAttributeElement = DataElement.__subclass('StyleAttributeElement', function(owner, role, modelId)
{
	this.owner = owner;
	this.role = role;
	this.modelId = modelId;
	this.attributeName = tersus.convertProperty(role.substring(1,role.length-1));
	this.jsAttributeName = tersus.getJsAttributeName(this.attributeName);
});
tersus.StyleAttributeElement.prototype.replaceChild = function replaceChild(parent, value)
{
	DataElement.prototype.replaceChild.call(this, parent,value);
	if (parent.viewNode)
	{
		var v = value != null ? value.leafValue : null;
		if (v != null)
			parent.viewNode.style[this.jsAttributeName]= v;
	}
};
tersus.StyleAttributeElement.prototype.removeChild = function removeChild(parent)
{
	DataElement.prototype.removeChild.call(this, parent);
	if (parent.viewNode) // parent is a real display node
		parent.viewNode.style[this.jsAttributeName] = null;
};

tersus.StyleAttributeElement.prototype.getChild = function getChild(parent)
{
	if (parent.viewNode)
	{
		var leafValue = parent.viewNode.style[this.attributeName];
		var dataValue = this.createChildInstance();
		dataValue.setLeaf(leafValue);
		return dataValue;
	}
	else
		return DataElement.prototype.getChild.call(this, parent);
};
tersus.HTMLTag.prototype.formatProperties = tersus.GenericField.prototype.formatProperties;
tersus.HTMLTag.prototype.createFormatProps = tersus.GenericField.prototype.createFormatProps;
tersus.HTMLTag.prototype.reformat = tersus.GenericField.prototype.reformat;
for (var p in tersus.GenericField.prototype.formatProperties)
{
        tersus.GenericField.addFormatAccessor(tersus.HTMLTag.prototype, p,tersus.GenericField.prototype.formatProperties[p] );
};
tersus.HTMLTag.prototype.setValueString = function()
{
	this.valueStr = '';
	if (this.value != null)
	{
		if (this.optimizeFormatString)
			this.valueStr = this.value.leafValue;
		else if (this.value.formatString)
			this.valueStr = this.value.formatString(this.formatProps ? this.formatProps : this.sharedProperties);
		else
			this.valueStr = this.value.toString();
	}
	if (this.viewNode)
		this.viewNode.innerHTML = this.escapeHTML(this.valueStr);
};
// file: Hyperlink.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 
function Hyperlink() {};
Hyperlink.prototype = new DisplayNode();
Hyperlink.prototype.constructor = Hyperlink;
Hyperlink.prototype.defaultTag = 'span';
// file: Image.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Image = function TersusImage(){};
tersus.Image.prototype = new DisplayNode();
tersus.Image.prototype.constructor = tersus.Image;
tersus.Image.prototype.getTag = function()
{
	return "img";
};
tersus.Image.prototype['set<Path>'] = function( path)
{
	this.srcPath = path;
	this.viewNode.src = tersus.translateResource(path);
};
tersus.Image.prototype['get<Path>'] = function()
{
	if (this.srcPath)
		return this.srcPath;
	else
		return null;
};
// file: Insert.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.Insert = tersus.DatabaseAction.__subclass('tersus.Insert');
tersus.Insert.prototype.getTablePrototype = function()
{
	return this.getTrigger('<Record>').getChildConstructor().prototype;
};
tersus.Insert.prototype.run = function()
{
	var record = this.getChild('<Record>');
	var tableName = this.getTableName(record);
	var fieldList = this.getFieldList(record.constructor.prototype);
	var dupExit = this.getExit('<Duplicate>');
	if (dupExit)
		this.checkDup(record,tableName,fieldList);
	else
		this.insert(record,tableName,fieldList);
};
tersus.Insert.prototype.checkDup = function(record,tableName, fieldList)
{
	var sqla = [];
	var values = [];
	sqla.push("SELECT COUNT(1) as count FROM ");
	sqla.push(tableName);
	this.addPrimaryKeyWhereClause(record,fieldList,sqla, values);
	var sql = sqla.join(' ');
	this.execSql(sql, values, function(transaction,results)
	{
		var count = results.rows.item(0)['count'];
		if (count > 0)
		{
			this.chargeExit('<Duplicate>', record);
			this.resumeContext();			
		}
		else
			this.insert(record,tableName,fieldList);
	});
	
};
tersus.Insert.prototype.insert = function(record, tableName, fieldList)
{
	
	var sqla = []; // 'buffer' for creating the sql
	sqla.push('INSERT INTO');
	sqla.push(tableName);
	sqla.push('(');
	var values = []; // values
	var fields = fieldList.fields;
	var nfields = fields.length;
	var n = 0;
	for (var j=0;j<nfields;j++)
	{
		var field = fields[j];
		var v = field.getSQLValue(record);
		if (v != null)
		{
			if (n>0)
				sqla.push(',');
			sqla.push(field.sqlName);
			n++;
			values.push(v);
		}
	}
	sqla.push(')');
	sqla.push('VALUES (?');
	for (var i=1;i<n;i++)
		sqla.push(', ?');
	sqla.push(')');
	var sql = sqla.join(' ');
	this.execSql(sql, values, function(transaction,results)
	{
		this.chargeExit('<Inserted>',record);
		this.resumeContext();
	});
			
};// file: InsertNumberedItem.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.InsertNumberedItem = function InsertNumberedItem(){};
tersus.InsertNumberedItem.prototype = new ActionNode();
tersus.InsertNumberedItem.prototype.constructor = tersus.InsertNumberedItem;
tersus.InsertNumberedItem.prototype.start = function()
{
	var item = this.getChild('<Item>');
	var parent = this.getChild('<Parent>');
	if (!parent.elementList)
	{
		if (this.getElement('<Invalid Parent>'))
			this.chargeExit('<Invalid Parent>', parent);
		else
			modelExecutionError("Invalid parent "+parent.modelId,this);
		return;
	}
	var index = this.getLeafChild('<Index>');
	var e = this.getTargetElement(parent,item);
	if (!e)
	{
			if (this.getElement('<Invalid Item>'))
				this.chargeExit('<Invalid Item>', item);
			else
				modelExecutionError("Invalid item "+item.modelId,this);
			return;
	}
	if (index < 0 || index > e.getChildren(parent).length)
	{
		if (this.getElement('<Invalid Index>'))
			this.chargeLeafExit('<Invalid Index>', index);
		else
			modelExecutionError("Invalid index "+index,this);
		return;
	}
	e.addAChild(parent, item);
	var children = e.getChildren(parent);
	e.moveChild(parent,children.length-1, index);
	this.chargeExit('<Inserted>',item);
	
};
tersus.InsertNumberedItem.prototype.getTargetElement = function(parent,item)
{
	var triggerId = this.getElement('<Item>').modelId;
	if (parent && parent.elementList)
	{
		var elements = parent.elementList;
		for (var i=0;i<elements.length;i++)
		{
			if (elements[i].isRepetitive && (elements[i].modelId == item.modelId || elements[i].modelId == triggerId))
			{
				return elements[i];
			}
		}
	}
	return null;
};

// file: InvokeElementAction.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.InvokeElementAction = function() {};
tersus.InvokeElementAction.prototype = new ActionNode();
tersus.InvokeElementAction.prototype.constructor = tersus.InvokeElementAction;
tersus.InvokeElementAction.prototype.start = function()
{
	var targetElement = this.getChild('<Element>');
	var action = this.getLeafChild('<Action>');
	if (targetElement.invokeAction)
	{
		var output = targetElement.invokeAction(action, this);
		// Here we would need to pause the current process, run the target action, and when that action is completed, resume the current action
	}
};

// file: IsEmpty.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.newAction('IsEmpty', function()
{
	var text = this.getLeafChild('<Text>');
	
	if (text == null)
	{
		this.chargeEmptyExit('<Missing>');
		return;
	}
		
	var length = text.length;
	if (length > 0)
		this.chargeLeafExit('<No>',text);
	else
		this.chargeLeafExit('<Yes>',text);
});// file: IsZero.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 tersus.IsZero = function tersus_IsZero() {};
tersus.IsZero.prototype = new ActionNode();
tersus.IsZero.prototype.constructor = tersus.IsZero;
tersus.IsZero.prototype.start = function ()
{
	var x = this.getLeafChild('<X>');
	if (x==0)
		this.chargeLeafExit('<Yes>',x)
	else
		this.chargeLeafExit('<No>',x);
};
// file: Label.js
/*********************************************************************************************************
 * Copyright (c) 2003-2009 Tersus Software Ltd. , All rights reserved.
 *
 * This program is made available under the terms of the GNU Lesser General Public License, version 2.1,
 * which is part of this distribution and is available at hhttp://www.gnu.org/licenses/lgpl-2.1.txt
 **********************************************************************************************************/
 function Label() {};