Location: PHPKode > projects > OpenNitro > trunk/Nitro/Debug.inc.php
<?php
//
// +---------------------------------------------------------------------------+
// | Nitro :: Debug                                                            |
// +---------------------------------------------------------------------------+
// | Copyright (c) 2003 June Systems BV                                        |
// +---------------------------------------------------------------------------+
// | This library is free software; you can redistribute it and/or modify it   |
// | under the terms of the GNU Lesser General Public License as published by  |
// | the Free Software Foundation; either version 2.1 of the License, or (at   |
// | your option) any later version.                                           |
// |                                                                           |
// | This library is distributed in the hope that it will be useful, but       |
// | WITHOUT ANY WARRANTY; without even the implied warranty of                |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   |
// | General Public License for more details.                                  |
// |                                                                           |
// | You should have received a copy of the GNU Lesser General Public License  |
// | along with this library; if not, write to the Free Software Foundation,   |
// | Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA            |
// +---------------------------------------------------------------------------+
// | Authors: Siggi Oskarsson <hide@address.com>                          |
// +---------------------------------------------------------------------------+
//
// $Id: Debug.inc.php 229 2008-04-17 09:20:31Z oli $
//
// Nitro debug class
//

/**
 * This file contains the Nitro debug functions and classes
 *
 * @package	Nitro
 * @subpackage	Debug
 * @author 		Siggi Oskarsson
 * @version 	$Revision: 1.25 $
 * @copyright	2004 June Systems BV
 */

/**
 * Create a new debug group
 *
 * This function creates a new debug group in the default debug object
 * $_DEBUG and sets a message. This is used to create a hierarchy in the
 * debug messages.
 *
 * @param	string	$Class	Class in which debug message originated
 * @param	string	$Function	Function in which debug message originated
 * @param	string	$Message	Debug message
 * @param	string	$File	File in which debug message originated
 * @param	string	$Line	Line in which debug message originated
 * @param	mixed	$Values	Extra values to pass to the debug class
 * @access	public
 */
function DebugGroup($Class, $Function = "", $Message, $File = FALSE, $Line = FALSE, $Level = DEBUG_ALL, $Values = FALSE)
{
	global $_DEBUG;

	if (is_object($_DEBUG)) return $_DEBUG->AddGroup($Class, $Function, $Message, $File, $Line, $Level, $Values);
}
/**
 * Create a debug message
 *
 * This function creates a new debug message in the default debug object
 * $_DEBUG.
 *
 * @param	string	$Class	Class in which debug message originated
 * @param	string	$Function	Function in which debug message originated
 * @param	string	$Message	Debug message
 * @param	string	$File	File in which debug message originated
 * @param	string	$Line	Line in which debug message originated
 * @param	mixed	$Values	Extra values to pass to the debug class
 * @access	public
 */
function Debug($Class, $Function = "", $Message = "", $File = FALSE, $Line = FALSE, $Level = DEBUG_ALL, $Values = FALSE)
{
	global $_DEBUG;

	if (is_object($_DEBUG)) {
		$Message = preg_replace("/(\n)|(\r)|(\t)/", ' ', $Message);
		$Message = preg_replace("/[ ]+/", ' ', $Message);
		return $_DEBUG->Add($Class, $Function, $Message, $File, $Line, $Level, $Values);
	} else {
		return FALSE;
	}
}
/**
 * Close last open Debug group
 * @see DebugGroup()
 */
function DebugCloseGroup($Level = DEBUG_ALL)
{
	global $_DEBUG;

	if (is_object($_DEBUG)) $_DEBUG->CloseGroup($Level);
}

/**
 * Nitro debug class
 *
 * This is the Nitro debug class which is used to create a debug
 * trace of the page requested. It also contains all POST and GET 
 * variables, aswell as the SESSION variables prior to page request
 * and after the page request finishes.
 *
 * @package	Nitro
 * @subpackage	Debug
 */
class NitroDebug {
	var $StartTime;
	var $EndTime;
	var $GroupTime;

	var $Objects = Array();
	var $MessageStack = Array();
	
	/**
	 * Nitro debug class constructor
	 *
	 * This function initializes the debug class and sets the GET, POST
	 * and pre-page SESSION variables. It also notes the time of creation
	 * of the debug option using GetMicroTime.
	 * @see NitroGetMicroTime()
	 */
	function NitroDebug()
	{
		$this->StartTime = NitroGetMicroTime();
		$this->Objects["POST"] = $_POST;
		$this->Objects["GET"] = $_GET;
		$this->Objects["SESSION"]["Pre"] = $_SESSION;

		// Add first debug statement by hand...
		$this->Objects["Messages"][0]["Time"] = NitroGetMicroTime();
		$this->Objects["Messages"][0]["Class"] = 'Debug';
		$this->Objects["Messages"][0]["Function"] = '__constructor';
		$this->Objects["Messages"][0]["Message"] = ' -- Debug started at '.date('Y-m-d H:i:s').' -- ';
		$this->Objects["Messages"][0]["Parent"] = 0;
		$this->Objects["Messages"][0]["File"] = __FILE__;
		$this->Objects["Messages"][0]["Line"] = __LINE__;
		$this->Objects["Messages"][0]["Values"] = NULL;
		$this->Objects["Messages"][0]["Error"] = 0;
	}
	
	/**
	 * Create a new debug group
	 *
	 * This function creates a new debug group.
	 *
	 * @param	string	$Class	Class in which debug message originated
	 * @param	string	$Function	Function in which debug message originated
	 * @param	string	$Message	Debug message
	 * @param	string	$File	File in which debug message originated
	 * @param	string	$Line	Line in which debug message originated
	 * @param	mixed	$Values	Extra values to pass to the debug class
	 * @access	public
	 */
	function AddGroup($Class, $Function, $Message, $File = FALSE, $Line = FALSE, $Level = DEBUG_ALL, $Values = FALSE)
	{
		global $__NitroConf;
		$RV = FALSE;
		$_debug_level = ($_COOKIE["SetDebugLevel"] ? $_COOKIE["SetDebugLevel"] : eval("return ".$__NitroConf->CONF["Debug"]["debug_level"].";"));

		if (($Level & $_debug_level)!=0) {
			$RV = $this->Add($Class, $Function, $Message, $File, $Line, $Level);
			array_push($this->MessageStack, $RV);
		}
		
		if ($RV) $this->GroupTime[$RV]['Start'] = NitroGetMicroTime();
		
		return $RV;
	}
	
	/**
	 * Close last open Debug group
	 * @see AddGroup()
	 */
	function CloseGroup($Level = DEBUG_ALL)
	{
		global $__NitroConf;
		$_debug_level = ($_COOKIE["SetDebugLevel"] ? $_COOKIE["SetDebugLevel"] : eval("return ".$__NitroConf->CONF["Debug"]["debug_level"].";"));

		if (($Level & $_debug_level)!=0) {
			$temp = array_pop($this->MessageStack);
			
			$this->GroupTime[$temp]['Stop'] = NitroGetMicroTime();
			$this->GroupTime[$temp]['Duration'] = ($this->GroupTime[$temp]['Stop'] - $this->GroupTime[$temp]['Start']);
			
			if (function_exists("RuntimeDebug")) {
				RuntimeDebug(
					$this->Objects['Messages'][$temp]['Class']."::".$this->Objects['Messages'][$temp]['Function'],
					$Level,
					count($this->MessageStack),
					"[\033[".($this->GroupTime[$temp]['Duration'] > 1 ? '41' : '40').";33;1m".sprintf('% 8.3f', ($this->GroupTime[$temp]['Duration'] * 1000))."ms\033[0m]",
					"\033[32m".chr(192).chr(196)."\033[31m".chr(180)."\033[0m"
					);
			}
		}

		return TRUE;
	}
	
	/**
	 * Add a debug message
	 *
	 * This function adds new debug message to the class.
	 *
	 * @param	string	$Class	Class in which debug message originated
	 * @param	string	$Function	Function in which debug message originated
	 * @param	string	$Message	Debug message
	 * @param	string	$File	File in which debug message originated
	 * @param	string	$Line	Line in which debug message originated
	 * @param	mixed	$Values	Extra values to pass to the debug class
	 * @access	public
	 */
	function Add($Class, $Function, $Message, $File = FALSE, $Line = FALSE, $Level = DEBUG_ALL, $Values = FALSE)
	{
		global $__NitroConf;
		$_debug_level = ($_COOKIE["SetDebugLevel"] ? $_COOKIE["SetDebugLevel"] : eval("return ".$__NitroConf->CONF["Debug"]["debug_level"].";"));

		if (($Level & $_debug_level)!=0) {
			if (function_exists("RuntimeDebug")) RuntimeDebug($Class."::".$Function." => ".$Message, $Level, count($this->MessageStack));
			$n = count($this->Objects["Messages"]);
			$this->Objects["Messages"][$n]["Time"] = NitroGetMicroTime();
			$this->Objects["Messages"][$n]["Class"] = $Class;
			$this->Objects["Messages"][$n]["Function"] = $Function;
			$this->Objects["Messages"][$n]["Message"] = $Message;
			$this->Objects["Messages"][$n]["Parent"] = end($this->MessageStack);
			$this->Objects["Messages"][$n]["File"] = $File;
			$this->Objects["Messages"][$n]["Line"] = $Line;
			$this->Objects["Messages"][$n]["Values"] = $Values;
			$this->Objects["Messages"][$n]["Error"] = (($Level & DEBUG_ALL_ERR) && !(($Level & DEBUG_ALL_OK) OR ($Level & DEBUG_ALL_WARN)) ? 1 : 0);
			return $n;
		} else {
			return FALSE;
		}
	}

	/**
	 * Stop debugging
	 *
	 * This function halts the debugging, sets the post-page SESSION variable
	 * and set the end timer.
	 *
	 * @access	public
	 */
	function StopDebug()
	{
		$this->Objects["SESSION"]["Post"] = $_SESSION;
		$this->EndTime = NitroGetMicroTime();
	}

	/**
	 * Draw javascript output of the debug session to the browser
	 *
	 * This function draws a simple javascript representation of the 
	 * debug session. This will be open in a new debug window.
	 */
	function DrawJScript()
	{
		if(count($this->Objects["Messages"])) {
			// This is borrowed from Smarty
			$RV = "<SCRIPT LANGUAGE='Javascript'>\n";
			$RV.= <<<EOS
			if( self.name == '' ) {
				var title = 'NitroConsole';
			} else {
				var title = 'NitroConsole_' + self.name;
			}
			nitro_console = window.open("",title,"width=680,height=600,resizable,scrollbars=yes");
			nitro_console.document.write("<HTML><TITLE>Nitro Debug Console_"+self.name+"</TITLE><BODY bgcolor=#ffffff>");

EOS;
			$Parent = Array();
			foreach($this->Objects["Messages"] AS $ID => $Row) {
				$diff = sprintf("%0.5f", (float)((float)$Row["Time"] - (float)$this->StartTime));
				if (end($Parent) !== $Row["Parent"]) {
					if (in_array($Row["Parent"], $Parent)) {
						while(end($Parent) !== $Row["Parent"]) {
							array_pop($Parent);
						}
					}else array_push($Parent, $Row["Parent"]);
				}
				//$RV.= "nitro_console.document.write(\"".$diff.": ".str_repeat(" - ", count($Parent)).$Row["Class"]."->".$Row["Function"].": ".substr(str_replace("\r\n", " ", $Row["Message"]),0,82)."<BR>\");\n";
				$RV.= "nitro_console.document.write(\"".$diff.": ".str_repeat(" - ", count($Parent)).$Row["Class"]."->".$Row["Function"].": ".ereg_replace("	+", " ", str_replace("\n", " ", str_replace("\r", "", $Row["Message"])))."<BR>\");\n";
			}
	
			ob_start();
			print_r($_GET);
			$GET = ob_get_contents();
			ob_end_clean();
			//$RV.= "nitro_console.document.write(\"GET: <PRE>".str_replace("\n", "<BR>", $GET)."</PRE>\");\n";
			ob_start();
			print_r($_POST);
			$POST = ob_get_contents();
			ob_end_clean();
			//$RV.= "nitro_console.document.write(\"POST: <PRE>".str_replace("\n", "<BR>", $POST)."</PRE>\");\n";
			ob_start();
			print_r($_SESSION);
			$SESSION = ob_get_contents();
			ob_end_clean();
			//$RV.= "nitro_console.document.write(\"SESSION: ".session_id()."<PRE>".str_replace("\n", "<BR>", $SESSION)."</PRE>\");\n";
			
			$RV.= <<<EOS
			nitro_console.document.write("</BODY></HTML>");
			nitro_console.document.close();
			nitro_console.document.focus();

EOS;
			$RV.= "</SCRIPT>";
		} else {
			$RV = FALSE;
		}
		return $RV;
	}
	
	/**
	 * Draw debug window output
	 *
	 * This function draws a javascript representation of the 
	 * debug session.
	 */
	function DrawDebugWindow_OLD($JSDir = "")
	{
		$RV.= "<SCRIPT SRC='".$JSDir."/NitroDebug.js' TYPE='text/javascript' LANGUAGE='JavaScript'></SCRIPT>\n";
		$RV.= "<SCRIPT LANGUAGE='Javascript'>\n";
		$RV.= <<<EOS
		if( self.name == '' ) {
			var title = 'NitroConsole';
		} else {
			var title = 'NitroConsole_' + self.name;
		}
		nitro_console = window.open("",title,"width=680,height=600,resizable,scrollbars=yes");
		nitro_console.document.write("<HTML><HEAD><TITLE>Nitro Debug Console_"+self.name+"</TITLE>");

EOS;
		$RV.= "nitro_console.document.write(unescape(\"".rawurlencode("<SCRIPT SRC='".$JSDir."/NitroDebug.js' TYPE='text/javascript' LANGUAGE='JavaScript'></SCRIPT>")."\"));\n";
		$RV.= <<<EOS
		nitro_console.document.write("<LINK REL='stylesheet' type='text/css' href='$JSDir/NitroDebug.css' />");
		nitro_console.document.write("</HEAD><BODY bgcolor=#ffffff>");
		nitro_console.document.write("<A HREF='Javascript: ToggleAll(\"Open\")'>Open all</A> | <A HREF='Javascript: ToggleAll(\"Close\")'>Close all</A>");

EOS;

		$RV.= "var d = new Array();\n";
		$RV.= "StartTime = ".sprintf("%0.10f", $this->StartTime)."\n";
		$PrevTime = $this->StartTime;
		$PrevID = NULL;
		foreach ($this->Objects["Messages"] AS $ID => $Row) {
			if (isset($PrevID)) $this->Objects["Messages"][$PrevID]["Duration"] = $Row["Time"] - $PrevTime;
			$PrevTime = $Row["Time"];
			$PrevID = $ID;
		}
		$ParentIDs = Array();
		foreach ($this->Objects["Messages"] AS $ID => $Row) {
			$Parent = ($Row["Parent"] ? $Row["Parent"] : 0);
			if (!in_array($Parent, $ParentIDs)) {
				$ParentIDs[] = $Parent;
				$RV.= 'd['.$Parent.'] = new Array();'."\n";
			}
			$RV.= 'd['.$Parent.']['.$ID.'] = new Array();'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Time"] = '.sprintf("%0.10f", $Row['Time']).';'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Duration"] = '.sprintf("%0.10f", $Row['Duration']).';'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Class"] = "'.$Row['Class'].'";'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Function"] = "'.$Row['Function'].'";'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Message"] = "'.rawurlencode($Row['Message']).'";'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["File"] = "'.$Row['File'].'";'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Line"] = "'.$Row['Line'].'";'."\n";
			$RV.= 'd['.$Parent.']['.$ID.']["Error"] = '.$Row['Error'].';'."\n";
		}
		$RV.= '
		var out = DrawDebugOutput(d, 0,0);
		nitro_console.document.write("<TABLE CELLSPACING=0 CELLPADDING=1><TR><TD><DIV STYLE=\'width: 250px; overflow: hidden\'><B>Class::Method</TD><TD><DIV STYLE=\'width: 50px; overflow: hidden\'><B>Start</DIV></TD><TD><DIV STYLE=\'width: 50px; overflow: hidden\'><B>Duration</DIV></TD><TD><B>Message</TD></TR></TABLE>");
		nitro_console.document.write(out);
		nitro_console.document.write("</BODY></HTML>");
		</SCRIPT>
		';
		
		return $RV;
	}
	
	function DrawModelessDialog($JSDir = "") {
		$Debug = Array();
		foreach ($this->Objects["Messages"] AS $ID => $Row) {
			$Parent = ($Row["Parent"] ? $Row["Parent"] : 0);
			$Debug[$Parent][$ID]["Time"] = sprintf("%0.10f", $Row['Time']);
			$Debug[$Parent][$ID]["Duration"] = sprintf("%0.10f", $Row['Duration']);
			$Debug[$Parent][$ID]["Class"] = $Row['Class'];
			$Debug[$Parent][$ID]["Function"] = $Row['Function'];
			$Debug[$Parent][$ID]["Message"] = $Row['Message'];
			$Debug[$Parent][$ID]["File"] = $Row['File'];
			$Debug[$Parent][$ID]["Line"] = $Row['Line'];
			$Debug[$Parent][$ID]["Error"] = $Row['Error'];
		}

		$dout = current($this->DrawDebugOutput($Debug, 0, 0));
		$out = "
		<HTML><HEAD><TITLE>Nitro Debug Console_</TITLE>
		<SCRIPT SRC='$JSDir/NitroDebug.js' TYPE='text/javascript' LANGUAGE='JavaScript'></SCRIPT>
		<LINK REL='stylesheet' type='text/css' href='$JSDir/NitroDebug.css' />
		</HEAD><BODY bgcolor=#ffffff>
		<A HREF='#' onClick=\"ToggleAll('Open')\">Open all</A> | <A HREF='#' onClick='ToggleAll(\"Close\")'>Close all</A>
		<TABLE CELLSPACING=0 CELLPADDING=1><TR><TD><DIV STYLE='width: 250px; overflow: hidden'><B>Class::Method</TD><TD><DIV STYLE='width: 50px; overflow: hidden'><B>Start</DIV></TD><TD><DIV STYLE='width: 50px; overflow: hidden'><B>Duration</DIV></TD><TD><B>Message</TD></TR></TABLE>
		$dout
		</BODY></HTML>
		";

		$SID = session_id();
		$OutFile = '/tmp/NitroDebug_'.$SID;
		$fp = fopen($OutFile, 'w');
		fputs($fp, $out);
		fclose($fp);
		
		$RV = "
		<SCRIPT LANGUAGE='Javascript'>
		showModelessDialog(\"".$this->Conf["Settings"]["PageURL"]."&ShowDebugOutput=$SID\", document, \"resizable: yes; help: no; status: no; scroll: yes; dialogWidth: 1024px; dialogHeight: 768px;\");
		</SCRIPT>
		";

		return $RV;
	}
	
	function DrawDebugWindow($JSDir = "") {
		$Debug = Array();
		foreach ($this->Objects["Messages"] AS $ID => $Row) {
			$Parent = ($Row["Parent"] ? $Row["Parent"] : 0);
			$Debug[$Parent][$ID]["Time"] = sprintf("%0.10f", $Row['Time']);
			$Debug[$Parent][$ID]["Duration"] = sprintf("%0.10f", $Row['Duration']);
			$Debug[$Parent][$ID]["Class"] = $Row['Class'];
			$Debug[$Parent][$ID]["Function"] = $Row['Function'];
			$Debug[$Parent][$ID]["Message"] = $Row['Message'];
			$Debug[$Parent][$ID]["File"] = $Row['File'];
			$Debug[$Parent][$ID]["Line"] = $Row['Line'];
			$Debug[$Parent][$ID]["Error"] = $Row['Error'];
		}

		$dout = current($this->DrawDebugOutput($Debug, 0, 0));
		$out = "
		<HTML><HEAD><TITLE>Nitro Debug Console_</TITLE>
		<SCRIPT SRC='$JSDir/NitroDebug.js' TYPE='text/javascript' LANGUAGE='JavaScript'></SCRIPT>
		<LINK REL='stylesheet' type='text/css' href='$JSDir/NitroDebug.css' />
		</HEAD><BODY bgcolor=#ffffff>
		<A HREF='#' onClick=\"ToggleAll('Open')\">Open all</A> | <A HREF='#' onClick='ToggleAll(\"Close\")'>Close all</A>
		<TABLE CELLSPACING=0 CELLPADDING=1><TR><TD><DIV STYLE='width: 250px; overflow: hidden'><B>Class::Method</TD><TD><DIV STYLE='width: 50px; overflow: hidden'><B>Start</DIV></TD><TD><DIV STYLE='width: 50px; overflow: hidden'><B>Duration</DIV></TD><TD><B>Message</TD></TR></TABLE>
		$dout
		</BODY></HTML>
		";

		$SID = session_id();
		$OutFile = '/tmp/NitroDebug_'.$SID;
		$fp = fopen($OutFile, 'w');
		fputs($fp, $out);
		fclose($fp);
		
		$RV = "
		<SCRIPT LANGUAGE='Javascript'>
		if( self.name == '' ) {
			var title = 'NitroConsole';
		} else {
			var title = 'NitroConsole_' + self.name;
		}
		window.open(\"".$this->Conf["Settings"]["PageURL"]."&ShowDebugOutput=$SID\", title, \"width=680,height=600,resizable,scrollbars=yes\");
		</SCRIPT>
		";

		return $RV;
	}
	
	function DrawDebugOutput(&$Debug, $ParentID, $Level)
	{
		$RV = "";
	
		$TimesEnd = Array();
		$Prevj = -1;
		foreach($Debug[$ParentID] AS $j => $D) {
			if ($Prevj > -1) $TimesEnd[$Prevj] = $j;
			$Prevj = $j;
		}
		$Err = 0;
		foreach($Debug[$ParentID] AS $j => $D) {
			$Err += $D['Error'];
			// eerst kinderen ophalen
			if ($Debug[$j] && $j > 0) {
				$tmp = $this->DrawDebugOutput($Debug, $j, $Level + 1);
			} else {
				$tmp = Array(FALSE, FALSE);
			}

			$RV.= "<TABLE CELLSPACING=0 CELLPADDING=1>";
			$RV.= "<TR".($D['Error'] == 1 ? " BGCOLOR='#FF0000'" : "").">";
			$RV.= "<TD VALIGN=TOP>";
			$RV.= "<DIV STYLE='width: 250px; overflow: hidden'>";
			for($i = 0; $i < $Level; $i++) {
				$RV.= "<IMG SRC='/images/fake.gif' WIDTH=12 HEIGHT=12 ALT=''>";
			}
			$RV.= "<A HREF='#' onClick='ToggleVisible(" . $j . ")'><IMG SRC='/images/".($tmp[1] ? "min" : "plus").".gif' BORDER=0 HEIGHT=12 WIDTH=12 ALT='' ID='IMG_" . $j . "'></A>";
			$RV.= " ".$D['Class'] . "::";
			$RV.= $D['Function'];
			$RV.= "</DIV></TD><TD VALIGN=TOP>";
			$RV.= "<DIV STYLE='width: 50px; overflow: hidden'>";
			$time = $D['Time'] - $this->StartTime;
			$RV.= round($time, 6);
			$RV.= "</DIV></TD><TD VALIGN=TOP>";
			$RV.= "<DIV STYLE='width: 50px; overflow: hidden'>";
			$NextTime = $TimesEnd[$j];
			if ($NextTime && $Debug[$ParentID][$NextTime]) {
				$time = $Debug[$ParentID][$NextTime]['Time'] - $D['Time'];
				$RV.= round($time, 6);
			} else {
				$RV.= "-"; 
			}
			$RV.= "</DIV></TD><TD VALIGN=TOP>";
			$RV.= $D['Message'];
			$RV.= "</TD></TR>";
			$RV.= "</TABLE>\r\n";

			$RV.= "<DIV ID='DIV_" . $j . "' STYLE='display: ".($tmp[1] ? "block" : "none")."'>";
			$RV.= "<TABLE CELLSPACING=0 CELLPADDING=1>";
			$RV.= "<TR>";
			$RV.= "<TD VALIGN=TOP>";
			for($i = 0; $i < $Level + 1; $i++) {
				$RV.= "<IMG SRC='/images/fake.gif' WIDTH=12 HEIGHT=12 ALT=''>";
			}
			$RV.= "</TD><TD VALIGN=TOP>";
			$RV.= " <I>File: " . $D['File'] . ":" . $D['Line'];
			$RV.= "</TD></TR></TABLE>";
			if ($tmp[0]) {
				$RV.= $tmp[0];
				$Err+= $tmp[1];
			}
			$RV.= "</DIV>\r\n";
		}
	
		return Array($RV, ($Err ? 1: 0));
	}
}
?>
Return current item: OpenNitro