<commit_before>/* Class: Myna
	Top Level library package (server-only).
	
	Detail:
		Contains generally useful functions that don't fit into the other 
		categories. The Myna namespace is also contains several other objects and 
		libraries  
		
		See:
		
		<Myna.Database>, <Myna.DataManager>, <Myna.File>, <Myna.HttpConnection>,
		<Myna.JavaUtils>, <Myna.Ldap>, <Myna.Mail>, <Myna.Permissions>, 
		<Myna.Profiler>, <Myna.Query>, <Myna.Table>, <Myna.Template>,
		<Myna.Thread>, <Myna.ValidationResult>, <Myna.WebService>,
 */
 
if (!Myna) var Myna={}
/* Function: abort 
	Halts JavaScript execution, optionally showing a message or dumping an object   
	 
	Parameters: 
		label	- 	*Optional* If supplied by itself, this is simply out put to the browser. 
					If value is supplied as well, this because the title for the dump.  
		value   - 	*Optional* Value to dump  
 
	Returns: 
		void
		
	See: 
		<Myna.dump>
	*/
	Myna.abort=function Myna_abort(label,value){
		if (value != undefined){
			this.print(Myna.dump(value,label));
		} else if (label != undefined){
			this.print("<hr>" +label);
		}
		if ($req) $req.handled=true;
		throw new Error("___MYNA_ABORT___");
	}
	
/* Function: beanToObject 
	Attempts to convert a JavaBean in to JavaScript object 
	 
	Parameters: 
		bean - Java object to convert  
 
	Returns: 
		JavaScript Object 
		
	Detail: 
		This function examines _bean_ and looks for functions that start with "get" 
		followed by at least one other character. These functions are executed and 
		their values are returned as a Javascript object where the property names 
		are the get functions minus the "get" and the following character lower cased. 
		Functions that start with "is" are treated similarly, except the "is" is kept 
		in the proerty name
		
		(code)
		*EXAMPLE*
		
		this class...
		
		public class PersonBean implements java.io.Serializable {
			private name="bob";
			private deceased=true;
			...
			public String getName() {
				return this.name;
			}
			
			public boolean isDeceased() {
				return this.deceased;
			}
		}
		
		would become...
		
		{
			name:"bob",
			isDeceased:true
		}
		(end)
	 
	*/
	Myna.beanToObject=function Myna_beanToObject(bean){
		var 
			result={}, // object with get properties
			property,	// 
			x;		// loop counter
			
		for (x in bean){
			if (/^get./.test(x)){
				try{ 
					property=x.replace(/^get/,"");
					property=property.substr(0,1).toLowerCase() + property.substr(1);
					result[property] = bean[x]();
					if (result[property] instanceof java.lang.String){
						result[property] = result[property];
					}
					
				}catch(e){} 
			}
			if (/^is./.test(x)){
				try{ 
					property=x.replace(/^is/,"");
					property=property.substr(0,1).toLowerCase() + property.substr(1);
					result[property] = bean[x]();
					if (result[property] instanceof java.lang.String){
						result[property] = Boolean(result[property]);
					}
					
				}catch(e){} 
			}
		}
		return result;
	}
/* Function: createSyncFunction 
	returns a thread-safe version of a javascript function  
	 
	Parameters: 
		functionObject - JavaScript Function object to synchronize 
 
	Returns: 
		a thread-safe version _functionObject_, similar to synchronized 
		keyword for Java functions
	 
	 
	*/
	Myna.createSyncFunction=function Myna_createSyncFunction(functionObject){	
		return new Packages.org.mozilla.javascript.Synchronizer(functionObject)
	}
/* Function: createUuid 
	Creates a Universally Unique Identifier 
	 
	Returns: 
		String UUID
		
	Detail: 
		A UUID is a 128 bit number represented as a HEX string that is 
		expected to unique even when compared to numbers generated by 
		other generators. Here is an example: 
		
		> f005889f-2b8d-409c-a126-f01eb50846d4
		
		Good uses for UUIDs are anything that needs to be uniquely 
		identified such as :
		
		* Primary key for a table (especially when you don't have 
			access to the database at time of generation)
		* Session id
		* Cryptographic salt (this is slow)
		* Temporary File names in a cluster (Two JVM's may create the same temp 
			file in the save directory using <$lib.file.createTempFile>)
		
		Myna UUID's are based on a cryptographically secure random number 
		generator, and are therefore NOT sortable by time. 
		
		See:
			http://jug.safehaus.org/
	 
	 
	*/
	Myna.createUuid=function Myna_createUuid(){
		var gen = Packages.org.safehaus.uuid.UUIDGenerator.getInstance();
		return String(gen.generateRandomBasedUUID());
	}
/* Function: createByteArray 
	returns a java Byte array of the supplied size 
	 
	
		
	Detail: 
		When working with binary data or streams it is often necessary to pass 
		a Byte array to java functions as a buffer. This function will create 
		this buffer for you 
	*/
	Myna.createByteArray=function Myna_createByteArray(size){
		return new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE,size);	
	}
/* Function: createCharArray 
	returns a java Character array of the supplied size 
	 
	
		
	Detail: 
		When working with striong data or streams it is often necessary to pass 
		a Character array to java functions as a buffer. This function will 
		create this buffer for you 
	*/
	Myna.createCharArray=function Myna_createCharArray(size){
		return new java.lang.reflect.Array.newInstance(java.lang.Character.TYPE,size);	
	}
/* Function: dump 
	returns nested HTML table representing the supplied object
	 
	Parameters: 
		obj			-	Object to dump
		label		-	*Optional* 
						Caption for the dump table
		maxDepth	-	*Optional, default=4* 
						Maximum depth of recursion. This is	to protect against 
						circular references and to speed performance. 
 
	Returns: 
		Nested HTML and (client-side) JavaScript table representing the supplied object
	
	*/
	Myna.dump=function Myna_dump(obj,label,maxDepth){
		var result,	// string result that will be returned
			d;		// recursive dump function
		if (maxDepth == undefined) maxDepth=4;
		if (label) {
			label = label;
		}
		result=[
			'<style>',
				'.dump_toggle_table_left{',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:linen;',
					'border:1px solid black;',
				'}',
				
				'.dump_toggle_table_right{',
					'cursor:normal;',
					'background-color:white;',
					'border:1px solid black;',
				'}',
				'.dump_toggle_table caption{',
					'background-color:silver;',
					'font-weight:bold;',
					'border:1px solid black;',
				'}',
				
				
				
				'.query td{',
					'border:1px solid purple;',
					'background-color:#e2b2f4;	',
				'}',
				'.query .dump_toggle_table_right {',
					'background-color:white;',
				'}',
				'.query .dump_toggle_table_left, .query_head th {',
					'font-size:9pt;',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#a481b1;',
					'border:1px solid purple;',
					'color:black;',
					'padding:2px;',
				'}',
				'.query caption{',
					'background-color:#a481b1;',
					'border:1px solid purple;',
					'color:black;',
				'}',
				'.array td{',
					'border:1px solid green;',
					'background-color:#c6ffc7;	',
				'}',
				'.array .dump_toggle_table_left  {',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#94ff96;',
					'border:1px solid green;',
					'color:black;',
					'padding:2px;',
				'}',
				'.array caption{',
					'background-color:#94ff96;',
					'border:1px solid green;',
					'color:black;',
				'}',
				
				'.object td{',
					'border:1px solid blue;',
					'background-color:#c6cdff;	',
				'}',
				'.object .dump_toggle_table_left  {',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#788aff;',
					'border:1px solid blue;',
					'color:black;',
					'padding:2px;',
				'}',
				'.object caption{',
					'background-color:#788aff;',
					'border:1px solid blue;',
					'color:black;',
				'}',
				
				
				
				'.dump_toggle_table{',
					
					'border:1px solid black;',
				'}',
				'.dump_toggle_table table{',
					'width:100%;',
				'}',
				'.dump_toggle_table td, .dump_toggle_table caption{',
					'font-family:sans-serif;',
					'font-size:9pt;',
				'}',
			'</style>',
			'<script>',
				'function _dump_toggle(left_side){',
					'var ns = left_side.nextSibling; ',
					'if (ns.style.display == \'none\'){',
						'ns.style.display=\'\';',
					'} else {',
						'ns.style.display=\'none\';',
					'}',
					
				'}',
			'</script>',
		].join('\n')
		

		d=function(obj,maxDepth){
			var my = arguments.callee,		//referenence to this function for the purpose of accessing static variables
				result,						// function local result object to hold the result of this call
				keys,						// stores result of Myna.getKeys()
				type,						// stores classname of object
				x,							// loop counter
				row,
				col
				
			
			
			if (!maxDepth) return "[ max recursion ]";
			 
			if (!my["max_r"]) my.max_r=1;
			
			result="";
			try{
			switch (ObjectLib.typeOf(obj)){
				case "array":
					if (obj instanceof Myna.DataSet){
						keys = ObjectLib.getKeys(obj,true).filter(function(prop){
								return prop != parseFloat(prop);
						});
						result+='<table class="query" border="0" cellspacing="0"><caption>DataSet</caption>';
						for (x=0; x < keys.length; ++x) {
						result+=	'<tr>'+
							'<td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
							'>' + keys[x] + '</td>'+
							'<td '+'class="dump_toggle_table_right" valign="top">';
				
							if (keys[x] != parseFloat(keys[x])){
								result+=d(obj[keys[x]],maxDepth-1)
							}
							
							result+=
								'</td>'+
							'</tr>';
						}
						result+=
							'<tr><td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
								'></td><td class="dump_toggle_table_right" valign="top">'+
							'<table height="1"  border="1" ><caption>Data:</caption>'+
								'<tr class="query_head">';
								for ( col=0; col < obj.columns.length; ++col) {
									result+=
									'<th class="">'+
										 obj.columns[col] +
									'</th>';
								}
								
								result+=
								'</tr>';
								for (row=0; row < obj.length; ++row) {
									result+=
									'<tr>';
										for (col=0; col < obj.columns.length; ++col) {
											var value=obj[row][obj.columns[col]];
											if (value === null || value ===undefined) value="";
											
											result+=
											'<td class="" ' +(value.length < 50?"nowrap":"")+'>'+
												value + 
											'</td>';
											
										}
									result+=
									'</tr>';
								}
								result+=
							'</table></td></tr>'
						result+=
						'</table>';
					} else {
						result +='<table class="array dump_toggle_table" border="0" cellspacing="0"><caption>Array</caption>'
						for ( x=0; x < obj.length; ++x){
							//if (typeof obj[x] == "function") continue;
							result +=[
								'<tr>',
									'<td class="dump_toggle_table_left"',
										'valign="top" ',
										'onclick="_dump_toggle(this)"',
									'>' + x +'</td><td class=" dump_toggle_table_right" valign="top">' + d(obj[x],maxDepth-1) + '</td>',
								'</tr>',
							].join('\n');
						}
						result +='</table>'
					}
				break;
				case "null":
					result +='NULL'
				break;
				case "date":
					result += obj.toString();
				break;
				case "object":
					keys = ObjectLib.getKeys(obj,true);
					
					if (obj instanceof Myna.Query ){
						result+='<table class="query" border="0" cellspacing="0"><caption>QueryResult</caption>';
						for (x=0; x < keys.length; ++x) {
						result+=	'<tr>'+
							'<td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
							'>' + keys[x] + '</td>'+
							'<td '+'class="dump_toggle_table_right" valign="top">';
							
							if (keys[x] == "data") {
								result+=
								'<table height="1"  border="1" >'+
									'<tr class="query_head">';
									for ( col=0; col < obj.columns.length; ++col) {
										result+=
										'<th class="">'+
											 obj.columns[col].name +
										'</th>';
									} 
									result+=
									'</tr>';
									for ( row=0; row < obj.data.length; ++row) {
										result+=
										'<tr>';
											for (col=0; col < obj.columns.length; ++col) {
												result+=
												'<td class="">'+
													obj.data[row][obj.columns[col].name] + 
												'</td>';
											}
										result+=
										'</tr>';
									}
								result+=
								'</table>'
							} else if (keys[x] == "sql") {
								result+=
								'<pre>' + obj.formatSql().escapeHtml() + '</pre>';
							} else if (keys[x] == "result") {
								result+=d(obj[keys[x]].toJson().parseJson(),maxDepth-1)
							} else  {
								result+=d(obj[keys[x]],maxDepth-1)
							} 
							result+=
								'</td>'+
							'</tr>';
						}
						result+=
						'</table>';
					} else {
						keys = ObjectLib.getKeys(obj,true);
						if (keys.length){
							if (obj["getClass"]){
								type =obj.getClass.toString(); 
							} else {
								 type ="Object"
							}
							result +='<table class="object" border="0" cellspacing="0"><caption>' + type + '</caption>'
							for (x=0; x < keys.length; ++x){
								result +=[
									'<tr>',
										'<td class="dump_toggle_table_left"',
											'valign="top" ',
											'onclick="_dump_toggle(this)"',
										'>' + keys[x] + '</td><td class="dump_toggle_table_right" valign="top">' + d(obj[keys[x]],maxDepth-1) + '</td>',
									'</tr>',
								].join('\n')
							}
							result +='</table>';	
						} else if (String(obj) == "[object Object]"){
							result += "[No Data Properties]";
						} else {
							result +=String(obj);	
						}
					}
					//result += obj instanceof Date;
				break;
				
				case "class":
					result +=[
						'<table border="0">',
							'<caption>' + obj.getClass() + '</caption>',
							'<tr><td>' + obj.toString()  + '</td></tr>',
						'</table>',
					].join('\n')
				break;
				
				
				case "xml":
					result +=[
						'<table border="0">',
							'<caption>XML Object</caption>',
							'<tr><td>' + d(Myna.xmlToObject(obj),maxDepth)  + '</td></tr>',
						'</table>',
					].join('\n')
				break;
				
				case "number":
				case "string":
				case "boolean":
					result += String(obj);
				break;
				case "function":
					result += "[object Function]";
				break;
				default:
					result += typeof obj 
				break;
				
			}
			} catch(e){ return e.toJson()}
				
			return result;
		}
		
		//result += d(obj,maxDepth);
		result += [
			'<table class="dump_toggle_table">',
			label?'<caption style="cursor:pointer" onclick="_dump_toggle(this)">' + label  + '</caption><tr>':'',
					'<td>' + d(obj,maxDepth) + '</td>',
				'</tr>',
			'</table>',
		].join('\n')
		return result;
	}
/* Function: dumpText 
	returns ASCII tree representing the supplied object
	 
	Parameters: 
		obj			-	Object to dump
		label		-	*Optional* 
						Caption for the dump table
		maxDepth	-	*Optional, default=4* 
						Maximum depth of recursion. This is	to protect against 
						circular references and to speed performance. 
	
	*/	
	Myna.dumpText=function Myna_dump(obj,label,maxDepth){
		var result=[];
		if (maxDepth == undefined) maxDepth=4;
		var itemToken = "+-";
		var lastItemToken = "\\-";
		var levelToken = "| ";
		var firstLevelToken = "  ";

		var d=function(obj,maxDepth,padding){
			var my = arguments.callee,		//referenence to this function for the purpose of accessing static variables
				result,						// function local result object to hold the result of this call
				keys,						// stores result of Myna.getKeys()
				type,						// stores classname of object
				x,							// loop counter
				row,
				col
				
			
			
			if (!maxDepth) return "[ max recursion ]";
			 
			if (!my["max_r"]) my.max_r=1;
			
			result=[];
			try{
				switch (ObjectLib.typeOf(obj)){
					case "array":
						result.push("[ Array ]")
						obj.forEach(function(value,index){
							
							if (index +1 == obj.length){
								result.push(padding + lastItemToken +"["+(index) +"] " + d(value,maxDepth-1,padding+firstLevelToken))	
							} else {
								result.push(padding + itemToken +"[" + (index) + "] " + d(value,maxDepth-1,padding+levelToken))
							}
							
						})
					break;
					case "null":
						result.push('NULL')
					break;
					case "date":
						result.push( obj.toString());
					break;
					case "object":
						keys = ObjectLib.getKeys(obj,true);
						if (keys.length){
							if (obj["getClass"]){
								type =obj.getClass.toString(); 
							} else {
								 type ="Object"
							}
							result.push("[ " +type+" ]")
							keys.forEach(function(key,index){
								if (index +1 == keys.length){
									result.push(padding + lastItemToken +"["+(key) +"] " + d(obj[key],maxDepth-1,padding+firstLevelToken))	
								} else {
									result.push(padding + itemToken +"[" + (key) + "] " + d(obj[key],maxDepth-1,padding+levelToken))
								}
							})
						} else if (String(obj) == "[object Object]"){
							result.push("[No Data Properties]");
						} else {
							result.push(String(obj));	
						}
					break;
					
					case "class":
						result.push( obj.getClass() + ' = ' + obj.toString());
							
					break;
					
					
					case "xml":
						result .push("[XML Object] " + d(Myna.xmlToObject(obj),maxDepth,padding));
					break;
					
					case "number":
					case "string":
					case "boolean":
						result.push(String(obj));
					break;
					case "function":
						result.push("[object Function]");
					break;
					default:
						result.push( "[ " + typeof obj+" ]") 
					break;
					
				}
			} catch(e){ result.push(e.toJson())}
				
			return result.join("\n");
		}
		
		if (label) result.push(label);
		result.push(d(obj,maxDepth,"  "));		
		return result.join("\n");
	}
/* Function: executeShell 
	Executes a shell command/script
	 
	Parameters: 
		shellCommand	-	Command shell to execute such as "cmd", "csh", "bash". 
							Can include a platform specific path and arguments 
							to the shell like "/bin/perl -I/usr/local/perl_includes" 
		script			-	String of commands to execute in the shell
		waitForOutput	-	*Optional, default=true* If true, this function will 
							wait for the script to complete and return a result object 
							with stderr, stdout, and the exit code. If False returns  
							empty result object immediately
							
	Returns: 
		A JavaScript object that looks like this:
		
		(code)
		{
			output:"here is the stdout",
			errors:"here is the stderr",
			exitCode:-1
		}
		(end)
		
	Detail: 
		This function attempts to execute the supplied script in the supplied shell. 
		This is obviously platform dependent, so you may want to consult <$server.osName>. 
		It saves _script_ to a tempfile and then executes _shellCommand_ with the temp file 
		name as the last parameter
		
	Example:
	(code)
	var result =Myna.executeShell("bash",<ejs>
			echo "began script at `date`"
			du -sh "<%=new Myna.File("/").javaFile.getAbsolutePath()%>"
			echo "finished script at `date`"
	</ejs>)
	if (result.exitCode == 0){
			Myna.print("<pre>" +result.output + "</pre>");
	} else {
			Myna.print("<pre>" +result.errors + "</pre>");
	}	
	(end)
	
	*/
	Myna.executeShell=function Myna_executeShell(shellCommand,script,waitForOutput){
		var
			runtime = java.lang.Runtime.getRuntime(),
			process, 		//holds java.lang.Process object returned by exec
			curLine,		// current line of process output
			reader,			//buffered reader for process output
			systemPath, 	//filesystem path to script file
			scriptFile,		// java.io.File of script file
			result={output:"",errors:"",exitCode:-1},		//output object to store output, errors, and exitCode
			scriptPath = Myna.File.createTempFile("shl");	//URI of script file
			
		if (waitForOutput === undefined) waitForOutput=true;
		
		scriptFile = new Myna.File(scriptPath);
		systemPath = scriptFile.javaFile.getAbsolutePath();
		
		//write the script to the temp file
		scriptFile.writeString(script);
		result.file=scriptFile.toString();
		result.script=script;
		result.shellCommand=shellCommand;
		process = runtime.exec(shellCommand + " " + systemPath,null,scriptFile.javaFile.getParentFile());
		
		if (waitForOutput){
			result.output = Myna.JavaUtils.streamToString(process.getInputStream());
			result.errors = Myna.JavaUtils.streamToString(process.getErrorStream());
			
			process.waitFor();
			result.exitCode = process.exitValue();
		}
		if (result.exitCode ==0 && String(result.errors).length ==0){
			scriptFile.forceDelete();
		} else {
			Myna.log("Error","Error in Myna.executeShell",<ejs>
				<b>Shell Command:</b><br>
				<pre><%=shellCommand%></pre><p>
				
				<b>Script:</b><br>
				<pre><%=script%></pre><p>
				
				<b>Errors:</b><br>
				<pre><%=result.errors%></pre><p>
				
				<b>Output:</b><br>
				<pre><%=result.output%></pre><p>
				
				<b>ScriptPath:</b><br>
				<pre><%=result.file%></pre><p>
			</ejs>);	
		}
		return result;
		
	}
/* Function: executeWinBatch 
	Executes a Windows batch file
	 
	Parameters: 
		script			-	String of commands to execute in the shell
		waitForOutput	-	*Optional, default=true* If true, this function will 
							wait for the script to complete and return a result object 
							with stderr, stdout, and the exit code. If False returns  
							empty result object immediately
							
	Returns: 
		A JavaScript object that looks like this:
		
		(code)
		{
			output:"here is the stdout",
			errors:"here is the stderr",
			exitCode:-1
		}
		(end)
		
	Detail: 
		This function attempts to execute the supplied script as a Windows batch file. 
		This is obviously platform dependent, so you may want to consult <$server.osName>. 
		It saves _script_ to a tempfile and then executes that file at a windows batch file
		
	See Also: <executeShell>
	
	Examples:
	(code)
		Myna.executeWinBatch("notepad.exe i:\\custom\\mpages\\applist.js")
	(end)
	*/
	Myna.executeWinBatch=function Myna_executeWinBatch(script,waitForOutput){
		var
			runtime = java.lang.Runtime.getRuntime(),
			process, 		//holds java.lang.Process object returned by exec
			curLine,		// current line of process output
			reader,			//buffered reader for process output
			systemPath, 	//filesystem path to script file
			scriptFile,		// java.io.File of script file
			result={output:"",errors:"",exitCode:-1},		//output object to store output, errors, and exitCode
			scriptPath = Myna.File.createTempFile("shl");	//URI of script file
			
		if (waitForOutput === undefined) waitForOutput=true;
		
		
		
		//write the script to the temp file
		scriptFile = new Myna.File(scriptPath);
		scriptFile.renameTo(scriptPath.listLast("/") + ".cmd")
		systemPath = scriptFile.javaFile.getAbsolutePath();
		scriptFile.writeString(script);
		result.file=scriptFile.toString();
		result.script=script;
		process = runtime.exec(systemPath,null,scriptFile.javaFile.getParentFile());
		
		
		
		if (waitForOutput){
			result.output = Myna.JavaUtils.streamToString(process.getInputStream());
			result.errors = Myna.JavaUtils.streamToString(process.getErrorStream());
			
			process.waitFor();
			result.exitCode = process.exitValue();
		}
		if (result.exitCode ==0 && String(result.errors).length ==0){
			scriptFile.forceDelete();
		} else {
			Myna.log("Error","Error in Myna.executeWinBatch",<ejs>
				<b>Shell Command:</b><br>
				
				<b>Script:</b><br>
				<pre><%=script%></pre><p>
				
				<b>Errors:</b><br>
				<pre><%=result.errors%></pre><p>
				
				<b>Output:</b><br>
				<pre><%=result.output%></pre><p>
				
				<b>ScriptPath:</b><br>
				<pre><%=result.file%></pre><p>
			</ejs>);	
		}
		return result;
		
	}

/* Function: formatError 
	returns an html formatted string representing the supplied exception. 
	 
	Parameters: 
		e - a caught exception  
 
	*/
	Myna.formatError=function Myna_formatError(e){
		try{
			/* if (e instanceof Packages.org.mozilla.javascript.RhinoException){ */
			if (e.sourceName){
				e = {rhinoException:e}	
			}
			
			
			if (e.rhinoException){
				e.lineNumber = e.rhinoException.lineNumber();
				e.fileName = e.rhinoException.sourceName();
				e.message = e.rhinoException.details();
			}
			
			e.rootIndex=0;
			if ((e.rhinoException || e.stack) && !$server.isThread){
				var stack =Myna.parseJsStack(e);
				for (var x=0;x < stack.length;++x){
					/* $server_gateway.currentDir + $server_gateway.scriptName */
					if (String(stack[x]).indexOf("/shared/js/") ==-1 ){
						var parts = stack[x].match(/at (.*?):(\d+)/);
						e.fileName = parts[1];
						e.lineNumber = parts[2]; 
						e.rootIndex=x+1;
						break;
					} 
				}	
			} 
			
			var errorTpl = new Myna.XTemplate(
				'<div class="myna_error_div">',
					'<h1>An Error has Occurred:</h1>',
					'{content}',
				'</div>',
				'<style>',
					'h1{',
						'font-size:14pt;',
					'}',
					'.myna_error_div{',
						'background-color:silver;',
						'border:2px solid brown;',
						'padding:10px;',
						'margin:10px;',
						'width:"99%";',
					'}',
					'.myna_error_div .error_line{',
						'background-color:pink;	',
						'border:1px solid red;	',
					'}',
					'.myna_error_div, .myna_error_div td,.myna_error_div th{',
						'font-family:sans-serif;',
						'font-size:10pt',
					'}',
					'.myna_error_div th{',
						'text-align:right;	',
						'width:80;',
						'vertical-align:top;',
						'color:white;',
						'background-color:darkblue;',
					'}',
					'.myna_error_div td{',
						'background-color:white;',
						'border:1px solid darkblue;',
					'}',
					'.myna_root_line{',
						'font-weight:bold;',
					'}',
				'</style>'
				
				
			)
			var standardTpl = new Myna.XTemplate(
				'\n\n\n\n<!-- ',
					'\n\tERROR: {message}',
					'\n\tFILE: {fileName}',
					'\n\tLINE:{lineNumber}',
					'\n\tSTACK:\n',
					'<tpl for="jsStack">\n',
						'{[ xindex == parent.rootIndex? "***":"" ]}{.}\n',
					'</tpl>\n',
				'\n-->\n\n\n\n',
				
				'<table width="100%" height="1" cellpadding="5" cellspacing="0" border="0" >',
					'<tr><th >Message:</th><td>{message}</td></tr>',
					'<tr><th >File:</th><td>{fileName}</td></tr>',
					'<tr><th >Line:</th><td>{lineNumber}</td></tr>',
					'<tr><th >Stacktrace:</th><td>',
						'<tpl for="jsStack">',
						'<div class="{[ xindex == parent.rootIndex? "myna_root_line":"" ]}" style="padding-left:{#}0">{.}</div>',
						'</tpl>',
					'</td></tr>',
					'<tr><th >Query:</th><td>{query}</td></tr>',
					'<tr><th >File Context:</th><td>',
						'<pre>',
						'<tpl for="lines">',
							'<div class="{[ parent.lineNumber == values.lineNumber? "error_line":"" ]}">{lineNumber}: {lineText}</div>',
						'</tpl>',
						'</pre>',
					'</td></tr>',
					'<tr><th >Memory Context:</th><td>',
						'<pre>',
						'<tpl for="scriptLines">',
							'<div class="{[ parent.lineNumber == values.originalIndex? "error_line":"" ]}">{lineNumber}: {lineText}</div>',
						'</tpl>',
						'</pre>',
					'</td></tr>',
					'<tr><th >Java Stacktrace:</th><td>',
						'<tpl for="javaStack">',
							'<div >{.}</div>',
						'</tpl>',
					
					'<tr><th >$server:</th><td>',
						'<b>Server URL</b>: {serverUrl}<br>',
						'<b>Hostname</b>: {hostname}<br>',
						'<b>Instance ID</b>: {instance_id}<br>',
						'<b>Purpose</b>: {purpose}<br>',
						'<b>Request Path</b>: {requestPath}<br>',
						'<b>Client IP</b>: {remoteAddr}<br>',
					'</td></tr>',
					'<tr><th >$req:</th><td>{req}</td></tr>',
				'</table>'
			)
			
			if (e.fileName !== undefined && e.lineNumber !== undefined && e.message !== undefined){
				e.fileName = String(e.fileName).split(/#/)[0];
				var lines ;
				try{
					lines =new Myna.File(e.fileName).readLines().map(function(element,index){
						return {
							lineNumber:index+1,
							lineText:element.escapeHtml()+"\n"
						}
					})
					.filter(function(element,index){
						return e.lineNumber -10 < element.lineNumber && element.lineNumber < e.lineNumber +10; 
					})
					
				}catch(e){lines="unavailable"}
					
					
				var data ={
					message:e.message,
					fileName:e.fileName,
					lineNumber:e.lineNumber,
					jsStack:["unavailable"],
					javaStack:["unavailable"],
					rootIndex:e.rootIndex,
					req: Myna.dump($req.data,"Request Data",10),
					lines:lines,
					serverUrl:$server.serverUrl,
					instance_id:$server.instance_id,
					requestPath:$server.requestUrl+$server.requestScriptName,
					hostname:$server.hostName,
					remoteAddr:$server.remoteAddr,
					purpose:$server.purpose,
					scriptLines:String($server_gateway.currentScript).split(/\n/)
						.map(function(element,index){
							return {
								lineNumber:index+1,
								lineText:element.escapeHtml()+"\n"
							}
						})
						.filter(function(element,index){
							return e.lineNumber -10 < element.lineNumber && element.lineNumber < e.lineNumber +10; 
						})
				}
					data.jsStack=e.rhinoException?Myna.parseJsStack(e):Myna.dump(e);
					data.javaStack=e.rhinoException?Myna.parseJavaStack(e):"unavailable";	
				if (e.query){
					data.query = Myna.dump(e.query)	
				}	
				return errorTpl.apply({
					content:standardTpl.apply(data)
				})
			} else {
				return errorTpl.apply({content:Myna.dump(e)})
			}
		} catch (ne){
			var result =String(e) +Myna.dump(Myna.JavaUtils.beanToObject(e)); 
			Myna.log("Error",
					"Error formating error",
					"Original error:<br>" + result +"<br>Formatting error:<br>" 
					+String(ne)+Myna.dump(Myna.JavaUtils.beanToObject(ne) + Myna.formatError(ne))
			)
			return result	;
		}
		
	}

/* Function: freeMemory 
	attempts to free the specified amount of memory within the timeout, returning 
	true if successful.
	 
	Parameters: 
		size		-	number of bytes to free
		timeout 	-	*Optional, default 0*
						timeout in miliseconds to wait for memory to become available; 
 
	Returns: 
		true if memory is available
		
	Detail: 
		if _timeout_ is 0, or memory is currently avaialble, this function will 
		return immediately. Otherwise this function will repeatedly 
		call System.gc() to attempt to free memory until enough is 
		available or the _timeout_ is exceeded
		
	See:
		<$server.memMax>, 
		<$server.memCurrent>, 
		<$server.memAvailable>, 
		<$server.memFree>,
		<$server.memUsed>
	*/
	Myna.freeMemory=function Myna_freeMemory(size,timeout){
		if (!timeout) timeout=0;
		
		if ($server.memAvailable > size ) return true;
		var start = new Date().getTime();
		while(new Date().getTime()-start < timeout){
			java.lang.System.gc();
			if ($server.memAvailable > size ) return true;
			Myna.sleep(parseInt(Math.max(10,timeout/10)));
		}
		return false;
	}	
	
/* Function: enumToArray 
	Converts a Java enumeration into a JavaScript Array.
		
	Parameters: 
		enumeration - Java enumeration to iterate over
 
	Returns: 
		JS Array object
		
	*/
	Myna.enumToArray=function Myna_enumToArray(enumeration){
		var element,
			result=[];
		while (enumeration.hasMoreElements()) {
			element = enumeration.nextElement()
			result.push(element);
			
		}
		return result;
	}
	
/* Function: getGeneralProperties 
	Returns the Java Properties object loaded from /WEB-INF/classes/general.properties
	 
	*/
	Myna.getGeneralProperties=function Myna_getGeneralProperties(){
		return Myna.mapToObject($server_gateway.generalProperties)
	}

	
/* Function: include 
	executes a .js, .sjs, or .ejs file in the current thread
	 
	Parameters: 
		path	-	<MynaPath> or <Myna.File> representing location of file 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object to 
					the script. any "global" variables created in the script will be
					created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	Detail:
		If the file extension is one of js, sjs, or ejs:
		
		This function executes the the script at _path_ against the supplied _scope_.
		This behavior is similar to the JavaScript "apply" function. The code in the file will be 
		treated like the body of a function on _scope_.
						
	See:
		* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:apply
		* <Myna.includeOnce>
		
	*/
	Myna.include=function Myna_include(path,scope){
		var file =new Myna.File(path); 
		var isCommandline = $server_gateway.environment.get("isCommandline")
		if (typeof $profiler !== "undefined") $profiler.begin("Include " + path);
		var content =file.readString();
		if (isCommandline) {
			content = content.replace(/^#/,"//#");	
		}
		
		if (/\.ejs$/.test(path)){
			content = "<"+"%try{%" +">" + content 
				+"<" +"%\n} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__;if($application && $application._onError) {$application._onError(e)} else{throw(e)}}%" +">";
		} else if (/\.s?js$/.test(path) || scope || isCommandline){
			content = "try{" + content 
				+"\n} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__; if($application && $application._onError) {$application._onError(e)} else{throw(e)}}";
		} else {
			throw new Error("Cannot include '"+path+"'. include() can only be called with .js .sjs or .ejs files")	
		}
		content +="\n";
		
		var originalDir = $server_gateway.currentDir;
		var originalScriptName = $server_gateway.scriptName;
		
		var realPath = file.toString()
		//Myna.printConsole("path = " + realPath +" currentDir = " + realPath.listBefore("/"))
		$server_gateway.currentDir = realPath.listBefore("/") +"/";
		$server_gateway.scriptName = realPath.listAfter("/")
		
		if (scope){
			$server_gateway.executeJsString(scope,content,path);
		} else {
			scope=$server_gateway.threadScope
			$server_gateway.executeJsString(scope,content,path);
		} 
		
		$server_gateway.currentDir = originalDir ;
		$server_gateway.scriptName = originalScriptName;
		
		if (typeof $profiler !== "undefined") $profiler.end("Include " + path);
		return scope;
	}
/* Function: includeDirectory 
	executes all .sjs files in the supplied directory, in the current thread
	 
	Parameters: 
		path	-	<MynaPath> representing a directory 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object 
					to the each script in _path_. Any "global" variables created 
					in the script will be created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	See:
		* <Myna.include>
		* <Myna.includeDirectoryOnce>
		
	*/
	Myna.includeDirectory=function Myna_includeDirectory(path,scope){
		scope = scope||$server_gateway.threadScope;
		var dir = new Myna.File(path);
		if (!dir.isDirectory()) throw new Error("'" + dir + "' is not a directory");
		dir.listFiles("sjs").forEach(function(file){
			Myna.include(file,scope);
		})
		return scope;
	}
/* Function: includeDirectoryOnce
	executes all .sjs files in the supplied directory, in the current thread, if 
	they have not been executed before in this request
	 
	Parameters: 
		path	-	<MynaPath> representing a directory 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object 
					to the each script in _path_. Any "global" variables created 
					in the script will be created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	See:
		* <Myna.include>
		* <Myna.includeDirectory>
		
	*/
	Myna.includeDirectoryOnce=function Myna_includeDirectory(path,scope){
		scope = scope||$server_gateway.threadScope;
		var dir = new Myna.File(path);
		if (!dir.isDirectory()) throw new Error("'" + dir + "' is not a directory");
		dir.listFiles("sjs").forEach(function(file){
			Myna.includeOnce(file,scope);
		})
		return scope;
	}
/* Function: includeText 
	Includes a text file in the current thread
	 
	Parameters: 
		path	-	<MynaPath> repesenting location of file 
		 
	Returns: 
		void
		
	See:
		* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:apply
		* <Myna.includeOnce>
		
	*/
	Myna.includeText=function Myna_includeText(path){
		var file =new Myna.File(path); 
		this.print(file.readString())
	}
	/* Experimental code */
	/* Myna.evalIinclude=function Myna_evalIinclude(path,scope){
		if (/thread2.sjs/.test(path)){
			Myna.log("debug","starting "+path);	
		}
		var file =new Myna.File(path); 
		if (typeof $profiler !== "undefined") $profiler.begin("Include " + path);
		//var code =file.readString();
		var code =String($server_gateway.translateString(file.readString(),file.toString()));
		code = "try{" + code  +"} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__; if($application && $application._onError) {$application._onError(e)} else{throw(e)}}";
		code +="\n";
		var f =function(){
			eval(code);
		}
		if (scope){
			f.apply(scope);	
		} else {
			f.apply();	
		}
		if (typeof $profiler !== "undefined") $profiler.end("Include " + path);
	} */
/* Function: includeOnce   
	Includes a text file or executes a .js, .sjs, or .ejs file in the current thread, if that path has not already been loaded. 

	Parameters: 
		path	-	<MynaPath> repesenting location of file 
		scope 	-	*Optional, default <$server.globalScope>* This is the 
					object that will be passed as the "this" object to the 
					script
 
	Returns: 
		_scope_ after execution
		
	Detail:
		This function will call <include> for this path only once in this request.
		
	See:
		* <Myna.include>
		
	*/
	Myna.includeOnce=function Myna_includeOnce(path,scope){
		var file =new Myna.File(path); 
		if ($server_gateway.uniqueIncludes_.add(file.toString())){
			return Myna.include(path,scope);
		} else return scope;
	}
/* Function: includeContent   
	Includes a text file or executes a .js, .sjs, or .ejs file in the current thread, and returns the output instead of printing 

	Parameters: 
		path	-	<MynaPath> repesenting location of file 
		scope 	-	*Optional, default <$server.globalScope>* This is the 
					object that will be passed as the "this" object to the 
					script
 
	Returns: 
		content generated by the included file
		
	See:
		* <Myna.include>
		
	*/	
	Myna.includeContent=function Myna_includeContent(path,scope){
        var oldContent = $res.clear();
        Myna.include(path,scope);
        var newContent = $res.clear();
        this.print(oldContent);
        return newContent;
	}<commit_msg>* added Myna.captureContent() and added caching optinos to include content <commit_after>/* Class: Myna
	Top Level library package (server-only).
	
	Detail:
		Contains generally useful functions that don't fit into the other 
		categories. The Myna namespace is also contains several other objects and 
		libraries  
		
		See:
		
		<Myna.Database>, <Myna.DataManager>, <Myna.File>, <Myna.HttpConnection>,
		<Myna.JavaUtils>, <Myna.Ldap>, <Myna.Mail>, <Myna.Permissions>, 
		<Myna.Profiler>, <Myna.Query>, <Myna.Table>, <Myna.Template>,
		<Myna.Thread>, <Myna.ValidationResult>, <Myna.WebService>,
 */
 
if (!Myna) var Myna={}
/* Function: abort 
	Halts JavaScript execution, optionally showing a message or dumping an object   
	 
	Parameters: 
		label	- 	*Optional* If supplied by itself, this is simply out put to the browser. 
					If value is supplied as well, this because the title for the dump.  
		value   - 	*Optional* Value to dump  
 
	Returns: 
		void
		
	See: 
		<Myna.dump>
	*/
	Myna.abort=function Myna_abort(label,value){
		if (value != undefined){
			this.print(Myna.dump(value,label));
		} else if (label != undefined){
			this.print("<hr>" +label);
		}
		if ($req) $req.handled=true;
		throw new Error("___MYNA_ABORT___");
	}
	
/* Function: beanToObject 
	Attempts to convert a JavaBean in to JavaScript object 
	 
	Parameters: 
		bean - Java object to convert  
 
	Returns: 
		JavaScript Object 
		
	Detail: 
		This function examines _bean_ and looks for functions that start with "get" 
		followed by at least one other character. These functions are executed and 
		their values are returned as a Javascript object where the property names 
		are the get functions minus the "get" and the following character lower cased. 
		Functions that start with "is" are treated similarly, except the "is" is kept 
		in the proerty name
		
		(code)
		*EXAMPLE*
		
		this class...
		
		public class PersonBean implements java.io.Serializable {
			private name="bob";
			private deceased=true;
			...
			public String getName() {
				return this.name;
			}
			
			public boolean isDeceased() {
				return this.deceased;
			}
		}
		
		would become...
		
		{
			name:"bob",
			isDeceased:true
		}
		(end)
	 
	*/
	Myna.beanToObject=function Myna_beanToObject(bean){
		var 
			result={}, // object with get properties
			property,	// 
			x;		// loop counter
			
		for (x in bean){
			if (/^get./.test(x)){
				try{ 
					property=x.replace(/^get/,"");
					property=property.substr(0,1).toLowerCase() + property.substr(1);
					result[property] = bean[x]();
					if (result[property] instanceof java.lang.String){
						result[property] = result[property];
					}
					
				}catch(e){} 
			}
			if (/^is./.test(x)){
				try{ 
					property=x.replace(/^is/,"");
					property=property.substr(0,1).toLowerCase() + property.substr(1);
					result[property] = bean[x]();
					if (result[property] instanceof java.lang.String){
						result[property] = Boolean(result[property]);
					}
					
				}catch(e){} 
			}
		}
		return result;
	}
/* Function: captureContent   
	executes a function and returns any content generated by that function

	Parameters: 
		func		-	function to execute 
		scope		-	*Optional, default true*
						The scope in which to execute _func_
								
	Returns: 
		content generated by _func_
		
	See Also:
		* <Myna.includeContent>
		
	*/	
	Myna.captureContent=function Myna_captureContent(func,scope){
		if (!scope) scope = this;
		var original = $res.clear();
		func.call(scope)
		var content = $res.clear();
		$res.print(original)
		return content;
	}
/* Function: createSyncFunction 
	returns a thread-safe version of a javascript function  
	 
	Parameters: 
		functionObject - JavaScript Function object to synchronize 
 
	Returns: 
		a thread-safe version _functionObject_, similar to synchronized 
		keyword for Java functions
	 
	 
	*/
	Myna.createSyncFunction=function Myna_createSyncFunction(functionObject){	
		return new Packages.org.mozilla.javascript.Synchronizer(functionObject)
	}
/* Function: createUuid 
	Creates a Universally Unique Identifier 
	 
	Returns: 
		String UUID
		
	Detail: 
		A UUID is a 128 bit number represented as a HEX string that is 
		expected to unique even when compared to numbers generated by 
		other generators. Here is an example: 
		
		> f005889f-2b8d-409c-a126-f01eb50846d4
		
		Good uses for UUIDs are anything that needs to be uniquely 
		identified such as :
		
		* Primary key for a table (especially when you don't have 
			access to the database at time of generation)
		* Session id
		* Cryptographic salt (this is slow)
		* Temporary File names in a cluster (Two JVM's may create the same temp 
			file in the save directory using <$lib.file.createTempFile>)
		
		Myna UUID's are based on a cryptographically secure random number 
		generator, and are therefore NOT sortable by time. 
		
		See:
			http://jug.safehaus.org/
	 
	 
	*/
	Myna.createUuid=function Myna_createUuid(){
		var gen = Packages.org.safehaus.uuid.UUIDGenerator.getInstance();
		return String(gen.generateRandomBasedUUID());
	}
/* Function: createByteArray 
	returns a java Byte array of the supplied size 
	 
	
		
	Detail: 
		When working with binary data or streams it is often necessary to pass 
		a Byte array to java functions as a buffer. This function will create 
		this buffer for you 
	*/
	Myna.createByteArray=function Myna_createByteArray(size){
		return new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE,size);	
	}
/* Function: createCharArray 
	returns a java Character array of the supplied size 
	 
	
		
	Detail: 
		When working with striong data or streams it is often necessary to pass 
		a Character array to java functions as a buffer. This function will 
		create this buffer for you 
	*/
	Myna.createCharArray=function Myna_createCharArray(size){
		return new java.lang.reflect.Array.newInstance(java.lang.Character.TYPE,size);	
	}
/* Function: dump 
	returns nested HTML table representing the supplied object
	 
	Parameters: 
		obj			-	Object to dump
		label		-	*Optional* 
						Caption for the dump table
		maxDepth	-	*Optional, default=4* 
						Maximum depth of recursion. This is	to protect against 
						circular references and to speed performance. 
 
	Returns: 
		Nested HTML and (client-side) JavaScript table representing the supplied object
	
	*/
	Myna.dump=function Myna_dump(obj,label,maxDepth){
		var result,	// string result that will be returned
			d;		// recursive dump function
		if (maxDepth == undefined) maxDepth=4;
		if (label) {
			label = label;
		}
		result=[
			'<style>',
				'.dump_toggle_table_left{',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:linen;',
					'border:1px solid black;',
				'}',
				
				'.dump_toggle_table_right{',
					'cursor:normal;',
					'background-color:white;',
					'border:1px solid black;',
				'}',
				'.dump_toggle_table caption{',
					'background-color:silver;',
					'font-weight:bold;',
					'border:1px solid black;',
				'}',
				
				
				
				'.query td{',
					'border:1px solid purple;',
					'background-color:#e2b2f4;	',
				'}',
				'.query .dump_toggle_table_right {',
					'background-color:white;',
				'}',
				'.query .dump_toggle_table_left, .query_head th {',
					'font-size:9pt;',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#a481b1;',
					'border:1px solid purple;',
					'color:black;',
					'padding:2px;',
				'}',
				'.query caption{',
					'background-color:#a481b1;',
					'border:1px solid purple;',
					'color:black;',
				'}',
				'.array td{',
					'border:1px solid green;',
					'background-color:#c6ffc7;	',
				'}',
				'.array .dump_toggle_table_left  {',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#94ff96;',
					'border:1px solid green;',
					'color:black;',
					'padding:2px;',
				'}',
				'.array caption{',
					'background-color:#94ff96;',
					'border:1px solid green;',
					'color:black;',
				'}',
				
				'.object td{',
					'border:1px solid blue;',
					'background-color:#c6cdff;	',
				'}',
				'.object .dump_toggle_table_left  {',
					'width:1px;',
					'font-weight:bold;',
					'cursor:pointer;',
					'background-color:#788aff;',
					'border:1px solid blue;',
					'color:black;',
					'padding:2px;',
				'}',
				'.object caption{',
					'background-color:#788aff;',
					'border:1px solid blue;',
					'color:black;',
				'}',
				
				
				
				'.dump_toggle_table{',
					
					'border:1px solid black;',
				'}',
				'.dump_toggle_table table{',
					'width:100%;',
				'}',
				'.dump_toggle_table td, .dump_toggle_table caption{',
					'font-family:sans-serif;',
					'font-size:9pt;',
				'}',
			'</style>',
			'<script>',
				'function _dump_toggle(left_side){',
					'var ns = left_side.nextSibling; ',
					'if (ns.style.display == \'none\'){',
						'ns.style.display=\'\';',
					'} else {',
						'ns.style.display=\'none\';',
					'}',
					
				'}',
			'</script>',
		].join('\n')
		

		d=function(obj,maxDepth){
			var my = arguments.callee,		//referenence to this function for the purpose of accessing static variables
				result,						// function local result object to hold the result of this call
				keys,						// stores result of Myna.getKeys()
				type,						// stores classname of object
				x,							// loop counter
				row,
				col
				
			
			
			if (!maxDepth) return "[ max recursion ]";
			 
			if (!my["max_r"]) my.max_r=1;
			
			result="";
			try{
			switch (ObjectLib.typeOf(obj)){
				case "array":
					if (obj instanceof Myna.DataSet){
						keys = ObjectLib.getKeys(obj,true).filter(function(prop){
								return prop != parseFloat(prop);
						});
						result+='<table class="query" border="0" cellspacing="0"><caption>DataSet</caption>';
						for (x=0; x < keys.length; ++x) {
						result+=	'<tr>'+
							'<td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
							'>' + keys[x] + '</td>'+
							'<td '+'class="dump_toggle_table_right" valign="top">';
				
							if (keys[x] != parseFloat(keys[x])){
								result+=d(obj[keys[x]],maxDepth-1)
							}
							
							result+=
								'</td>'+
							'</tr>';
						}
						result+=
							'<tr><td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
								'></td><td class="dump_toggle_table_right" valign="top">'+
							'<table height="1"  border="1" ><caption>Data:</caption>'+
								'<tr class="query_head">';
								for ( col=0; col < obj.columns.length; ++col) {
									result+=
									'<th class="">'+
										 obj.columns[col] +
									'</th>';
								}
								
								result+=
								'</tr>';
								for (row=0; row < obj.length; ++row) {
									result+=
									'<tr>';
										for (col=0; col < obj.columns.length; ++col) {
											var value=obj[row][obj.columns[col]];
											if (value === null || value ===undefined) value="";
											
											result+=
											'<td class="" ' +(value.length < 50?"nowrap":"")+'>'+
												value + 
											'</td>';
											
										}
									result+=
									'</tr>';
								}
								result+=
							'</table></td></tr>'
						result+=
						'</table>';
					} else {
						result +='<table class="array dump_toggle_table" border="0" cellspacing="0"><caption>Array</caption>'
						for ( x=0; x < obj.length; ++x){
							//if (typeof obj[x] == "function") continue;
							result +=[
								'<tr>',
									'<td class="dump_toggle_table_left"',
										'valign="top" ',
										'onclick="_dump_toggle(this)"',
									'>' + x +'</td><td class=" dump_toggle_table_right" valign="top">' + d(obj[x],maxDepth-1) + '</td>',
								'</tr>',
							].join('\n');
						}
						result +='</table>'
					}
				break;
				case "null":
					result +='NULL'
				break;
				case "date":
					result += obj.toString();
				break;
				case "object":
					keys = ObjectLib.getKeys(obj,true);
					
					if (obj instanceof Myna.Query ){
						result+='<table class="query" border="0" cellspacing="0"><caption>QueryResult</caption>';
						for (x=0; x < keys.length; ++x) {
						result+=	'<tr>'+
							'<td class="dump_toggle_table_left"'+
								'valign="top" '+
								'onclick="_dump_toggle(this)"'+
							'>' + keys[x] + '</td>'+
							'<td '+'class="dump_toggle_table_right" valign="top">';
							
							if (keys[x] == "data") {
								result+=
								'<table height="1"  border="1" >'+
									'<tr class="query_head">';
									for ( col=0; col < obj.columns.length; ++col) {
										result+=
										'<th class="">'+
											 obj.columns[col].name +
										'</th>';
									} 
									result+=
									'</tr>';
									for ( row=0; row < obj.data.length; ++row) {
										result+=
										'<tr>';
											for (col=0; col < obj.columns.length; ++col) {
												result+=
												'<td class="">'+
													obj.data[row][obj.columns[col].name] + 
												'</td>';
											}
										result+=
										'</tr>';
									}
								result+=
								'</table>'
							} else if (keys[x] == "sql") {
								result+=
								'<pre>' + obj.formatSql().escapeHtml() + '</pre>';
							} else if (keys[x] == "result") {
								result+=d(obj[keys[x]].toJson().parseJson(),maxDepth-1)
							} else  {
								result+=d(obj[keys[x]],maxDepth-1)
							} 
							result+=
								'</td>'+
							'</tr>';
						}
						result+=
						'</table>';
					} else {
						keys = ObjectLib.getKeys(obj,true);
						if (keys.length){
							if (obj["getClass"]){
								type =obj.getClass.toString(); 
							} else {
								 type ="Object"
							}
							result +='<table class="object" border="0" cellspacing="0"><caption>' + type + '</caption>'
							for (x=0; x < keys.length; ++x){
								result +=[
									'<tr>',
										'<td class="dump_toggle_table_left"',
											'valign="top" ',
											'onclick="_dump_toggle(this)"',
										'>' + keys[x] + '</td><td class="dump_toggle_table_right" valign="top">' + d(obj[keys[x]],maxDepth-1) + '</td>',
									'</tr>',
								].join('\n')
							}
							result +='</table>';	
						} else if (String(obj) == "[object Object]"){
							result += "[No Data Properties]";
						} else {
							result +=String(obj);	
						}
					}
					//result += obj instanceof Date;
				break;
				
				case "class":
					result +=[
						'<table border="0">',
							'<caption>' + obj.getClass() + '</caption>',
							'<tr><td>' + obj.toString()  + '</td></tr>',
						'</table>',
					].join('\n')
				break;
				
				
				case "xml":
					result +=[
						'<table border="0">',
							'<caption>XML Object</caption>',
							'<tr><td>' + d(Myna.xmlToObject(obj),maxDepth)  + '</td></tr>',
						'</table>',
					].join('\n')
				break;
				
				case "number":
				case "string":
				case "boolean":
					result += String(obj);
				break;
				case "function":
					result += "[object Function]";
				break;
				default:
					result += typeof obj 
				break;
				
			}
			} catch(e){ return e.toJson()}
				
			return result;
		}
		
		//result += d(obj,maxDepth);
		result += [
			'<table class="dump_toggle_table">',
			label?'<caption style="cursor:pointer" onclick="_dump_toggle(this)">' + label  + '</caption><tr>':'',
					'<td>' + d(obj,maxDepth) + '</td>',
				'</tr>',
			'</table>',
		].join('\n')
		return result;
	}
/* Function: dumpText 
	returns ASCII tree representing the supplied object
	 
	Parameters: 
		obj			-	Object to dump
		label		-	*Optional* 
						Caption for the dump table
		maxDepth	-	*Optional, default=4* 
						Maximum depth of recursion. This is	to protect against 
						circular references and to speed performance. 
	
	*/	
	Myna.dumpText=function Myna_dump(obj,label,maxDepth){
		var result=[];
		if (maxDepth == undefined) maxDepth=4;
		var itemToken = "+-";
		var lastItemToken = "\\-";
		var levelToken = "| ";
		var firstLevelToken = "  ";

		var d=function(obj,maxDepth,padding){
			var my = arguments.callee,		//referenence to this function for the purpose of accessing static variables
				result,						// function local result object to hold the result of this call
				keys,						// stores result of Myna.getKeys()
				type,						// stores classname of object
				x,							// loop counter
				row,
				col
				
			
			
			if (!maxDepth) return "[ max recursion ]";
			 
			if (!my["max_r"]) my.max_r=1;
			
			result=[];
			try{
				switch (ObjectLib.typeOf(obj)){
					case "array":
						result.push("[ Array ]")
						obj.forEach(function(value,index){
							
							if (index +1 == obj.length){
								result.push(padding + lastItemToken +"["+(index) +"] " + d(value,maxDepth-1,padding+firstLevelToken))	
							} else {
								result.push(padding + itemToken +"[" + (index) + "] " + d(value,maxDepth-1,padding+levelToken))
							}
							
						})
					break;
					case "null":
						result.push('NULL')
					break;
					case "date":
						result.push( obj.toString());
					break;
					case "object":
						keys = ObjectLib.getKeys(obj,true);
						if (keys.length){
							if (obj["getClass"]){
								type =obj.getClass.toString(); 
							} else {
								 type ="Object"
							}
							result.push("[ " +type+" ]")
							keys.forEach(function(key,index){
								if (index +1 == keys.length){
									result.push(padding + lastItemToken +"["+(key) +"] " + d(obj[key],maxDepth-1,padding+firstLevelToken))	
								} else {
									result.push(padding + itemToken +"[" + (key) + "] " + d(obj[key],maxDepth-1,padding+levelToken))
								}
							})
						} else if (String(obj) == "[object Object]"){
							result.push("[No Data Properties]");
						} else {
							result.push(String(obj));	
						}
					break;
					
					case "class":
						result.push( obj.getClass() + ' = ' + obj.toString());
							
					break;
					
					
					case "xml":
						result .push("[XML Object] " + d(Myna.xmlToObject(obj),maxDepth,padding));
					break;
					
					case "number":
					case "string":
					case "boolean":
						result.push(String(obj));
					break;
					case "function":
						result.push("[object Function]");
					break;
					default:
						result.push( "[ " + typeof obj+" ]") 
					break;
					
				}
			} catch(e){ result.push(e.toJson())}
				
			return result.join("\n");
		}
		
		if (label) result.push(label);
		result.push(d(obj,maxDepth,"  "));		
		return result.join("\n");
	}
/* Function: executeShell 
	Executes a shell command/script
	 
	Parameters: 
		shellCommand	-	Command shell to execute such as "cmd", "csh", "bash". 
							Can include a platform specific path and arguments 
							to the shell like "/bin/perl -I/usr/local/perl_includes" 
		script			-	String of commands to execute in the shell
		waitForOutput	-	*Optional, default=true* If true, this function will 
							wait for the script to complete and return a result object 
							with stderr, stdout, and the exit code. If False returns  
							empty result object immediately
							
	Returns: 
		A JavaScript object that looks like this:
		
		(code)
		{
			output:"here is the stdout",
			errors:"here is the stderr",
			exitCode:-1
		}
		(end)
		
	Detail: 
		This function attempts to execute the supplied script in the supplied shell. 
		This is obviously platform dependent, so you may want to consult <$server.osName>. 
		It saves _script_ to a tempfile and then executes _shellCommand_ with the temp file 
		name as the last parameter
		
	Example:
	(code)
	var result =Myna.executeShell("bash",<ejs>
			echo "began script at `date`"
			du -sh "<%=new Myna.File("/").javaFile.getAbsolutePath()%>"
			echo "finished script at `date`"
	</ejs>)
	if (result.exitCode == 0){
			Myna.print("<pre>" +result.output + "</pre>");
	} else {
			Myna.print("<pre>" +result.errors + "</pre>");
	}	
	(end)
	
	*/
	Myna.executeShell=function Myna_executeShell(shellCommand,script,waitForOutput){
		var
			runtime = java.lang.Runtime.getRuntime(),
			process, 		//holds java.lang.Process object returned by exec
			curLine,		// current line of process output
			reader,			//buffered reader for process output
			systemPath, 	//filesystem path to script file
			scriptFile,		// java.io.File of script file
			result={output:"",errors:"",exitCode:-1},		//output object to store output, errors, and exitCode
			scriptPath = Myna.File.createTempFile("shl");	//URI of script file
			
		if (waitForOutput === undefined) waitForOutput=true;
		
		scriptFile = new Myna.File(scriptPath);
		systemPath = scriptFile.javaFile.getAbsolutePath();
		
		//write the script to the temp file
		scriptFile.writeString(script);
		result.file=scriptFile.toString();
		result.script=script;
		result.shellCommand=shellCommand;
		process = runtime.exec(shellCommand + " " + systemPath,null,scriptFile.javaFile.getParentFile());
		
		if (waitForOutput){
			result.output = Myna.JavaUtils.streamToString(process.getInputStream());
			result.errors = Myna.JavaUtils.streamToString(process.getErrorStream());
			
			process.waitFor();
			result.exitCode = process.exitValue();
		}
		if (result.exitCode ==0 && String(result.errors).length ==0){
			scriptFile.forceDelete();
		} else {
			Myna.log("Error","Error in Myna.executeShell",<ejs>
				<b>Shell Command:</b><br>
				<pre><%=shellCommand%></pre><p>
				
				<b>Script:</b><br>
				<pre><%=script%></pre><p>
				
				<b>Errors:</b><br>
				<pre><%=result.errors%></pre><p>
				
				<b>Output:</b><br>
				<pre><%=result.output%></pre><p>
				
				<b>ScriptPath:</b><br>
				<pre><%=result.file%></pre><p>
			</ejs>);	
		}
		return result;
		
	}
/* Function: executeWinBatch 
	Executes a Windows batch file
	 
	Parameters: 
		script			-	String of commands to execute in the shell
		waitForOutput	-	*Optional, default=true* If true, this function will 
							wait for the script to complete and return a result object 
							with stderr, stdout, and the exit code. If False returns  
							empty result object immediately
							
	Returns: 
		A JavaScript object that looks like this:
		
		(code)
		{
			output:"here is the stdout",
			errors:"here is the stderr",
			exitCode:-1
		}
		(end)
		
	Detail: 
		This function attempts to execute the supplied script as a Windows batch file. 
		This is obviously platform dependent, so you may want to consult <$server.osName>. 
		It saves _script_ to a tempfile and then executes that file at a windows batch file
		
	See Also: <executeShell>
	
	Examples:
	(code)
		Myna.executeWinBatch("notepad.exe i:\\custom\\mpages\\applist.js")
	(end)
	*/
	Myna.executeWinBatch=function Myna_executeWinBatch(script,waitForOutput){
		var
			runtime = java.lang.Runtime.getRuntime(),
			process, 		//holds java.lang.Process object returned by exec
			curLine,		// current line of process output
			reader,			//buffered reader for process output
			systemPath, 	//filesystem path to script file
			scriptFile,		// java.io.File of script file
			result={output:"",errors:"",exitCode:-1},		//output object to store output, errors, and exitCode
			scriptPath = Myna.File.createTempFile("shl");	//URI of script file
			
		if (waitForOutput === undefined) waitForOutput=true;
		
		
		
		//write the script to the temp file
		scriptFile = new Myna.File(scriptPath);
		scriptFile.renameTo(scriptPath.listLast("/") + ".cmd")
		systemPath = scriptFile.javaFile.getAbsolutePath();
		scriptFile.writeString(script);
		result.file=scriptFile.toString();
		result.script=script;
		process = runtime.exec(systemPath,null,scriptFile.javaFile.getParentFile());
		
		
		
		if (waitForOutput){
			result.output = Myna.JavaUtils.streamToString(process.getInputStream());
			result.errors = Myna.JavaUtils.streamToString(process.getErrorStream());
			
			process.waitFor();
			result.exitCode = process.exitValue();
		}
		if (result.exitCode ==0 && String(result.errors).length ==0){
			scriptFile.forceDelete();
		} else {
			Myna.log("Error","Error in Myna.executeWinBatch",<ejs>
				<b>Shell Command:</b><br>
				
				<b>Script:</b><br>
				<pre><%=script%></pre><p>
				
				<b>Errors:</b><br>
				<pre><%=result.errors%></pre><p>
				
				<b>Output:</b><br>
				<pre><%=result.output%></pre><p>
				
				<b>ScriptPath:</b><br>
				<pre><%=result.file%></pre><p>
			</ejs>);	
		}
		return result;
		
	}

/* Function: formatError 
	returns an html formatted string representing the supplied exception. 
	 
	Parameters: 
		e - a caught exception  
 
	*/
	Myna.formatError=function Myna_formatError(e){
		try{
			/* if (e instanceof Packages.org.mozilla.javascript.RhinoException){ */
			if (e.sourceName){
				e = {rhinoException:e}	
			}
			
			
			if (e.rhinoException){
				e.lineNumber = e.rhinoException.lineNumber();
				e.fileName = e.rhinoException.sourceName();
				e.message = e.rhinoException.details();
			}
			
			e.rootIndex=0;
			if ((e.rhinoException || e.stack) && !$server.isThread){
				var stack =Myna.parseJsStack(e);
				for (var x=0;x < stack.length;++x){
					/* $server_gateway.currentDir + $server_gateway.scriptName */
					if (String(stack[x]).indexOf("/shared/js/") ==-1 ){
						var parts = stack[x].match(/at (.*?):(\d+)/);
						e.fileName = parts[1];
						e.lineNumber = parts[2]; 
						e.rootIndex=x+1;
						break;
					} 
				}	
			} 
			
			var errorTpl = new Myna.XTemplate(
				'<div class="myna_error_div">',
					'<h1>An Error has Occurred:</h1>',
					'{content}',
				'</div>',
				'<style>',
					'h1{',
						'font-size:14pt;',
					'}',
					'.myna_error_div{',
						'background-color:silver;',
						'border:2px solid brown;',
						'padding:10px;',
						'margin:10px;',
						'width:"99%";',
					'}',
					'.myna_error_div .error_line{',
						'background-color:pink;	',
						'border:1px solid red;	',
					'}',
					'.myna_error_div, .myna_error_div td,.myna_error_div th{',
						'font-family:sans-serif;',
						'font-size:10pt',
					'}',
					'.myna_error_div th{',
						'text-align:right;	',
						'width:80;',
						'vertical-align:top;',
						'color:white;',
						'background-color:darkblue;',
					'}',
					'.myna_error_div td{',
						'background-color:white;',
						'border:1px solid darkblue;',
					'}',
					'.myna_root_line{',
						'font-weight:bold;',
					'}',
				'</style>'
				
				
			)
			var standardTpl = new Myna.XTemplate(
				'\n\n\n\n<!-- ',
					'\n\tERROR: {message}',
					'\n\tFILE: {fileName}',
					'\n\tLINE:{lineNumber}',
					'\n\tSTACK:\n',
					'<tpl for="jsStack">\n',
						'{[ xindex == parent.rootIndex? "***":"" ]}{.}\n',
					'</tpl>\n',
				'\n-->\n\n\n\n',
				
				'<table width="100%" height="1" cellpadding="5" cellspacing="0" border="0" >',
					'<tr><th >Message:</th><td>{message}</td></tr>',
					'<tr><th >File:</th><td>{fileName}</td></tr>',
					'<tr><th >Line:</th><td>{lineNumber}</td></tr>',
					'<tr><th >Stacktrace:</th><td>',
						'<tpl for="jsStack">',
						'<div class="{[ xindex == parent.rootIndex? "myna_root_line":"" ]}" style="padding-left:{#}0">{.}</div>',
						'</tpl>',
					'</td></tr>',
					'<tr><th >Query:</th><td>{query}</td></tr>',
					'<tr><th >File Context:</th><td>',
						'<pre>',
						'<tpl for="lines">',
							'<div class="{[ parent.lineNumber == values.lineNumber? "error_line":"" ]}">{lineNumber}: {lineText}</div>',
						'</tpl>',
						'</pre>',
					'</td></tr>',
					'<tr><th >Memory Context:</th><td>',
						'<pre>',
						'<tpl for="scriptLines">',
							'<div class="{[ parent.lineNumber == values.originalIndex? "error_line":"" ]}">{lineNumber}: {lineText}</div>',
						'</tpl>',
						'</pre>',
					'</td></tr>',
					'<tr><th >Java Stacktrace:</th><td>',
						'<tpl for="javaStack">',
							'<div >{.}</div>',
						'</tpl>',
					
					'<tr><th >$server:</th><td>',
						'<b>Server URL</b>: {serverUrl}<br>',
						'<b>Hostname</b>: {hostname}<br>',
						'<b>Instance ID</b>: {instance_id}<br>',
						'<b>Purpose</b>: {purpose}<br>',
						'<b>Request Path</b>: {requestPath}<br>',
						'<b>Client IP</b>: {remoteAddr}<br>',
					'</td></tr>',
					'<tr><th >$req:</th><td>{req}</td></tr>',
				'</table>'
			)
			
			if (e.fileName !== undefined && e.lineNumber !== undefined && e.message !== undefined){
				e.fileName = String(e.fileName).split(/#/)[0];
				var lines ;
				try{
					lines =new Myna.File(e.fileName).readLines().map(function(element,index){
						return {
							lineNumber:index+1,
							lineText:element.escapeHtml()+"\n"
						}
					})
					.filter(function(element,index){
						return e.lineNumber -10 < element.lineNumber && element.lineNumber < e.lineNumber +10; 
					})
					
				}catch(e){lines="unavailable"}
					
					
				var data ={
					message:e.message,
					fileName:e.fileName,
					lineNumber:e.lineNumber,
					jsStack:["unavailable"],
					javaStack:["unavailable"],
					rootIndex:e.rootIndex,
					req: Myna.dump($req.data,"Request Data",10),
					lines:lines,
					serverUrl:$server.serverUrl,
					instance_id:$server.instance_id,
					requestPath:$server.requestUrl+$server.requestScriptName,
					hostname:$server.hostName,
					remoteAddr:$server.remoteAddr,
					purpose:$server.purpose,
					scriptLines:String($server_gateway.currentScript).split(/\n/)
						.map(function(element,index){
							return {
								lineNumber:index+1,
								lineText:element.escapeHtml()+"\n"
							}
						})
						.filter(function(element,index){
							return e.lineNumber -10 < element.lineNumber && element.lineNumber < e.lineNumber +10; 
						})
				}
					data.jsStack=e.rhinoException?Myna.parseJsStack(e):Myna.dump(e);
					data.javaStack=e.rhinoException?Myna.parseJavaStack(e):"unavailable";	
				if (e.query){
					data.query = Myna.dump(e.query)	
				}	
				return errorTpl.apply({
					content:standardTpl.apply(data)
				})
			} else {
				return errorTpl.apply({content:Myna.dump(e)})
			}
		} catch (ne){
			var result =String(e) +Myna.dump(Myna.JavaUtils.beanToObject(e)); 
			Myna.log("Error",
					"Error formating error",
					"Original error:<br>" + result +"<br>Formatting error:<br>" 
					+String(ne)+Myna.dump(Myna.JavaUtils.beanToObject(ne) + Myna.formatError(ne))
			)
			return result	;
		}
		
	}

/* Function: freeMemory 
	attempts to free the specified amount of memory within the timeout, returning 
	true if successful.
	 
	Parameters: 
		size		-	number of bytes to free
		timeout 	-	*Optional, default 0*
						timeout in miliseconds to wait for memory to become available; 
 
	Returns: 
		true if memory is available
		
	Detail: 
		if _timeout_ is 0, or memory is currently avaialble, this function will 
		return immediately. Otherwise this function will repeatedly 
		call System.gc() to attempt to free memory until enough is 
		available or the _timeout_ is exceeded
		
	See:
		<$server.memMax>, 
		<$server.memCurrent>, 
		<$server.memAvailable>, 
		<$server.memFree>,
		<$server.memUsed>
	*/
	Myna.freeMemory=function Myna_freeMemory(size,timeout){
		if (!timeout) timeout=0;
		
		if ($server.memAvailable > size ) return true;
		var start = new Date().getTime();
		while(new Date().getTime()-start < timeout){
			java.lang.System.gc();
			if ($server.memAvailable > size ) return true;
			Myna.sleep(parseInt(Math.max(10,timeout/10)));
		}
		return false;
	}	
	
/* Function: enumToArray 
	Converts a Java enumeration into a JavaScript Array.
		
	Parameters: 
		enumeration - Java enumeration to iterate over
 
	Returns: 
		JS Array object
		
	*/
	Myna.enumToArray=function Myna_enumToArray(enumeration){
		var element,
			result=[];
		while (enumeration.hasMoreElements()) {
			element = enumeration.nextElement()
			result.push(element);
			
		}
		return result;
	}
	
/* Function: getGeneralProperties 
	Returns the Java Properties object loaded from /WEB-INF/classes/general.properties
	 
	*/
	Myna.getGeneralProperties=function Myna_getGeneralProperties(){
		return Myna.mapToObject($server_gateway.generalProperties)
	}

	
/* Function: include 
	executes a .js, .sjs, or .ejs file in the current thread
	 
	Parameters: 
		path	-	<MynaPath> or <Myna.File> representing location of file 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object to 
					the script. any "global" variables created in the script will be
					created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	Detail:
		If the file extension is one of js, sjs, or ejs:
		
		This function executes the the script at _path_ against the supplied _scope_.
		This behavior is similar to the JavaScript "apply" function. The code in the file will be 
		treated like the body of a function on _scope_.
						
	See:
		* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:apply
		* <Myna.includeOnce>
		
	*/
	Myna.include=function Myna_include(path,scope){
		var file =new Myna.File(path); 
		var isCommandline = $server_gateway.environment.get("isCommandline")
		if (typeof $profiler !== "undefined") $profiler.begin("Include " + path);
		var content =file.readString();
		if (isCommandline) {
			content = content.replace(/^#/,"//#");	
		}
		
		if (/\.ejs$/.test(path)){
			content = "<"+"%try{%" +">" + content 
				+"<" +"%\n} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__;if($application && $application._onError) {$application._onError(e)} else{throw(e)}}%" +">";
		} else if (/\.s?js$/.test(path) || scope || isCommandline){
			content = "try{" + content 
				+"\n} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__; if($application && $application._onError) {$application._onError(e)} else{throw(e)}}";
		} else {
			throw new Error("Cannot include '"+path+"'. include() can only be called with .js .sjs or .ejs files")	
		}
		content +="\n";
		
		var originalDir = $server_gateway.currentDir;
		var originalScriptName = $server_gateway.scriptName;
		
		var realPath = file.toString()
		//Myna.printConsole("path = " + realPath +" currentDir = " + realPath.listBefore("/"))
		$server_gateway.currentDir = realPath.listBefore("/") +"/";
		$server_gateway.scriptName = realPath.listAfter("/")
		
		if (scope){
			$server_gateway.executeJsString(scope,content,path);
		} else {
			scope=$server_gateway.threadScope
			$server_gateway.executeJsString(scope,content,path);
		} 
		
		$server_gateway.currentDir = originalDir ;
		$server_gateway.scriptName = originalScriptName;
		
		if (typeof $profiler !== "undefined") $profiler.end("Include " + path);
		return scope;
	}
/* Function: includeDirectory 
	executes all .sjs files in the supplied directory, in the current thread
	 
	Parameters: 
		path	-	<MynaPath> representing a directory 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object 
					to the each script in _path_. Any "global" variables created 
					in the script will be created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	See:
		* <Myna.include>
		* <Myna.includeDirectoryOnce>
		
	*/
	Myna.includeDirectory=function Myna_includeDirectory(path,scope){
		scope = scope||$server_gateway.threadScope;
		var dir = new Myna.File(path);
		if (!dir.isDirectory()) throw new Error("'" + dir + "' is not a directory");
		dir.listFiles("sjs").forEach(function(file){
			Myna.include(file,scope);
		})
		return scope;
	}
/* Function: includeDirectoryOnce
	executes all .sjs files in the supplied directory, in the current thread, if 
	they have not been executed before in this request
	 
	Parameters: 
		path	-	<MynaPath> representing a directory 
		scope 	-	*Optional, default <$server.globalScope>* 
					This is the object that will be passed as the "this" object 
					to the each script in _path_. Any "global" variables created 
					in the script will be created on _scope_ object instead.
 
	Returns: 
		_scope_ after execution
		
	See:
		* <Myna.include>
		* <Myna.includeDirectory>
		
	*/
	Myna.includeDirectoryOnce=function Myna_includeDirectory(path,scope){
		scope = scope||$server_gateway.threadScope;
		var dir = new Myna.File(path);
		if (!dir.isDirectory()) throw new Error("'" + dir + "' is not a directory");
		dir.listFiles("sjs").forEach(function(file){
			Myna.includeOnce(file,scope);
		})
		return scope;
	}
/* Function: includeText 
	Includes a text file in the current thread
	 
	Parameters: 
		path	-	<MynaPath> repesenting location of file 
		 
	Returns: 
		void
		
	See:
		* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:apply
		* <Myna.includeOnce>
		
	*/
	Myna.includeText=function Myna_includeText(path){
		var file =new Myna.File(path); 
		this.print(file.readString())
	}
	/* Experimental code */
	/* Myna.evalIinclude=function Myna_evalIinclude(path,scope){
		if (/thread2.sjs/.test(path)){
			Myna.log("debug","starting "+path);	
		}
		var file =new Myna.File(path); 
		if (typeof $profiler !== "undefined") $profiler.begin("Include " + path);
		//var code =file.readString();
		var code =String($server_gateway.translateString(file.readString(),file.toString()));
		code = "try{" + code  +"} catch(e) {if (__exception__ && !e.rhinoException) e.rhinoException=__exception__; if($application && $application._onError) {$application._onError(e)} else{throw(e)}}";
		code +="\n";
		var f =function(){
			eval(code);
		}
		if (scope){
			f.apply(scope);	
		} else {
			f.apply();	
		}
		if (typeof $profiler !== "undefined") $profiler.end("Include " + path);
	} */
/* Function: includeOnce   
	Includes a text file or executes a .js, .sjs, or .ejs file in the current thread, if that path has not already been loaded. 

	Parameters: 
		path	-	<MynaPath> repesenting location of file 
		scope 	-	*Optional, default <$server.globalScope>* This is the 
					object that will be passed as the "this" object to the 
					script
 
	Returns: 
		_scope_ after execution
		
	Detail:
		This function will call <include> for this path only once in this request.
		
	See:
		* <Myna.include>
		
	*/
	Myna.includeOnce=function Myna_includeOnce(path,scope){
		var file =new Myna.File(path); 
		if ($server_gateway.uniqueIncludes_.add(file.toString())){
			return Myna.include(path,scope);
		} else return scope;
	}
/* Function: includeContent   
	Includes a text file or executes a .js, .sjs, or .ejs file in the current thread, and returns the output instead of printing 

	Parameters: 
		path				-	<MynaPath> repesenting location of file 
		scope 			-	*Optional, default <$server.globalScope>* This is the 
								object that will be passed as the "this" object to the 
								script
		cacheOptions	-	*Optional, default null*
								If this is defined, then these options will be passed to 
								a <Myna.Cache> instance for the results of this include 
								
	Returns: 
		content generated by the included file
		
	See:
		* <Myna.include>
		
	*/	
	Myna.includeContent=function Myna_includeContent(path,scope,cacheOptions){
		
		var oldContent = $res.clear();
		if (cacheOptions){
      	cacheOptions.code = function(path,scope){
      		Myna.include(path,scope);
      	};
      	new Myna.Cache(cacheOptions).call(path,scope)
      } else {
			Myna.include(path,scope);	
      }
		
		var newContent = $res.clear();
		this.print(oldContent);
		return newContent;
			
      
	}

{'fraction_non_alphanumeric': 0.1557196427881084, 'fraction_numerical': 0.004974162704088865, 'mean_word_length': 2.814678267708794, 'pattern_counts': {'":': 50, '<': 707, '<?xml version=': 0, '>': 679, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1187773', 'n_tokens_mistral': 33565, 'n_tokens_neox': 25363, 'n_words': 6043}