Index: trunk/kernel/include/debugger.php
===================================================================
--- trunk/kernel/include/debugger.php	(revision 2677)
+++ trunk/kernel/include/debugger.php	(revision 2678)
@@ -1,984 +1,1007 @@
 <?php
 
 	if( !class_exists('Debugger') )
 	{
 		function dbg_ConstOn($const_name)
 		{
 			return defined($const_name) && constant($const_name);
 		}
 		
 		function dbg_safeDefine($const_name,$const_value)
 		{
 			if(!defined($const_name)) define($const_name,$const_value);
 		}
 		
 		unset($_REQUEST['debug_host']);	// this var messed up whole detection stuff :(
 		
 		// Detect fact, that this session beeing debugged by Zend Studio
 		foreach($_REQUEST as $rq_name=>$rq_value)
 		{
 			if( substr($rq_name,0,6)=='debug_' )
 			{
 				dbg_safeDefine('DBG_ZEND_PRESENT', 1);
 				break;
 			} 
 		}
 		
 		dbg_safeDefine('DBG_ZEND_PRESENT',0);
 		
 		// set default values for debugger constants
 		$dbg_constMap=Array('DBG_OPTIONS'=>0,
 							'DBG_USE_HIGHLIGHT'=>1,
 							'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1,
 							'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1,
 							'DBG_IGNORE_STRICT_ERRORS'=>1,
 							'DBG_DOMVIEWER'=>'/temp/domviewer.html',
 							'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack 
 							'DBG_LOCAL_BASE_PATH'=>'w:');
 		
 		foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
 		{
 			dbg_safeDefine($dbg_constName,$dbg_constValue);
 		}
 		
 		// only for IE, in case if no windows php script editor defined
 		/*if(!defined('WINDOWS_EDITOR'))
 		{
 			$dbg_editor = 0;
 			$dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
 			$dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
 			define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
 			unset($dbg_editors,$dbg_editor);
 		}*/
 	
 		class Debugger 
 		{
 			/**
 			 * Debugger data for building report
 			 *
 			 * @var Array
 			 */
 			var $Data = Array();
 			var $ProfilerData = Array();
 			var $ProfilerTotals = Array();
 			var $RecursionStack = Array();	// prevent recursion when processing debug_backtrace() function results
 			
 			var $TraceNextError=false;
 			
 			var $Options = 0;
 			var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
 									'output_buffer' => 4, 'highlight_output' => 8);
 			
 			
 			var $longErrors=Array();
 			
 			/**
 			 * Amount of memory used by debugger itself
 			 *
 			 * @var Array
 			 * @access private
 			 */
 			var $memoryUsage=Array();
 			
 			var $IncludesData=Array();
 			var $IncludeLevel=0;
 			
 			function Debugger()
 			{
 				$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
 				$this->profileStart('script_runtime', 'Script runtime');
 				ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1);
 				$this->memoryUsage['error_handling']=0; // memory amount used by error handler
 				$this->appendRequest();
 			}
 			
 			function initOptions()
 			{
 				
 			}
 			
 			function mapLongError($msg)
 			{
 				$key=$this->generateID();
 				$this->longErrors[$key]=$msg;
 				return $key;
 			}
 			
 			function setOption($name,$value)
 			{
 				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
 				if($value)
 				{
 					$this->Options|=$this->OptionsMap[$name];
 				}
 				else
 				{
 					$this->Options=$this->Options&~$this->OptionsMap[$name];
 				}
 			}
 			
 			function getOption($name)
 			{
 				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
 	    		return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
 			}
 			
 			/**
 			 * Set's flag, that next error that occurs will
 			 * be prepended by backtrace results
 			 *
 			 */
 			function traceNext()
 			{
 				$this->TraceNextError=true;
 			}
 			
 			function dumpVars()
 			{
 				$dumpVars = func_get_args();
 				foreach($dumpVars as $varValue)
 				{
 					$this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
 				}
 			}
 			
 			function prepareHTML($dataIndex)
 			{
 				$Data =& $this->Data[$dataIndex];
 				if($Data['debug_type'] == 'html') return $Data['html'];
 				
 				switch($Data['debug_type'])
 				{
 					case 'error':
 						$fileLink = $this->getFileLink($Data['file'],$Data['line']);
 						$ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
 						$ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
 						return $ret;
 						break;
 					
 					case 'var_dump':
 						return $this->highlightString( print_r($Data['value'], true) );
 						break;
 						
 					case 'trace':
 						ini_set('memory_limit','500M');
 						$trace =& $Data['trace'];
 						
 						//return 'sorry';
 						//return $this->highlightString(print_r($trace,true));
 						
 						
 						$i = 0; $traceCount = count($trace);
 						$ret = '';
 						while($i < $traceCount)
 						{
 							$traceRec =& $trace[$i];
 							$argsID = 'trace_args_'.$dataIndex.'_'.$i;
+							
+							$has_args = isset($traceRec['args']);
+							
 							if(isset($traceRec['file']))
 							{
 								$func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
-								$ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
+								$args_link = $has_args ? '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>' : '<b>Function</b>';
+								
+								$ret .= $args_link.': '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
 								$ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
 							}
 							else 
 							{
 								$ret .= 'no file information available';
 							}
 							
 							// ensure parameter value is not longer then 200 symbols
+							if($has_args)
+							{
 							$this->processTraceArguments($traceRec['args']);
 							$args = $this->highlightString(print_r($traceRec['args'], true));
 							$ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
+							}
 							$i++;
 						}
 						return $ret;
 						break;
 					
 					case 'profiler':
 						$profileKey = $Data['profile_key'];
 						$Data =& $this->ProfilerData[$profileKey];
 						$runtime = ($Data['ends'] - $Data['begins']); // in seconds
 						return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
 						break;
 							
 					default:
 						return 'incorrect debug data';
 						break;
 				}
 			}
 			
+			function isApplication(&$object)
+			{
+				$app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication';
+				return get_class($object) == $app_class;
+			}
+			
 			function processTraceArguments(&$traceArgs)
 			{
 				if(!$traceArgs) return '';
-				foreach ($traceArgs as $argID => $argValue)
+				
+				$array_keys = array_keys($traceArgs);
+				foreach($array_keys as $argID)
 				{
+					$argValue =& $traceArgs[$argID];
+					
 					if( is_array($argValue) || is_object($argValue) )
 					{
 						if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
 						{	
-							if( get_class($argValue) == 'kfactory' || get_class($argValue) == 'debugger' ) continue;
+							array_push($this->RecursionStack, get_class($argValue));
+							
+							if( get_class($argValue) == 'kfactory' || $this->isApplication($argValue) || get_class($argValue) == 'templateparser' )
+							{
+								$argValue = null;
+								continue;
+							}
 							
 							// object & not in stack - ok
-							array_push($this->RecursionStack, get_class($argValue));
 							settype($argValue,'array');
 							$this->processTraceArguments($argValue);
 							array_pop($this->RecursionStack);
 						}
 						elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
 						{
 							// object & in stack - recursion
 							$traceArgs[$argID] = '**** RECURSION ***';
 						}
 						else
 						{
 							// normal array here
 							$this->processTraceArguments($argValue);
 						}
 					}
 					else
 					{
 						$traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
 					}
 				}
 			}
 			
 			function cutStringForHTML($string)
 			{
 				if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
 				return $string;
 			}
 			
 			/**
 			 * Format SQL Query using predefined formatting
 			 * and highlighting techniques
 			 *
 			 * @param string $sql
 			 * @return string
 			 */
 			function formatSQL($sql)
 			{
 				$sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
 				$sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
 				return $this->highlightString($sql);
 			}
 			
 			function highlightString($string)
 			{
 				if( dbg_ConstOn('DBG_USE_HIGHLIGHT') )
 				{
 					$string = str_replace('\\','_no_match_string_',$string);
 					$string = highlight_string('<?php '.$string.'?>', true);
 					$string = str_replace('_no_match_string_','\\',$string);
 					return preg_replace('/&lt;\?(.*)php (.*)\?&gt;/s','$2',$string);
 				}
 				else
 				{
 					return $string;
 				}
 			}
 			
 			function getFileLink($file, $lineno = 1, $title = '')
 			{
 				if(!$title) $title = $file;
 				$is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
 				if($is_mozilla)
 				{
 					return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
 				}
 				else 
 				{
 					return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>';		
 				}
 				
 			}
 			
 			function getLocalFile($remoteFile)
 			{
 				return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);	
 			}
 			
 			function appendTrace()
 			{
 				$trace = debug_backtrace();
 				array_shift($trace);
 				$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
 			}
 			
 			function appendMemoryUsage($msg, $used=null)
 			{
 				if (!isset($used)) $used = round(memory_get_usage()/1024);
 				$this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
 			}
 			
 			function appendHTML($html)
 			{
 				$this->Data[] = Array('html' => $html,'debug_type' => 'html');	
 			}
 			
 			/**
 			 * Change debugger info that was already generated before.
 			 * Returns true if html was set.
 			 *
 			 * @param int $index
 			 * @param string $html
 			 * @param string $type = {'append','prepend','replace'}
 			 * @return bool
 			 */
 			function setHTMLByIndex($index,$html,$type='append')
 			{
 				if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' )
 				{
 					return false;	
 				}
 				
 				switch ($type)
 				{
 					case 'append':
 						$this->Data[$index]['html'] .= '<br>'.$html;
 						break;
 					case 'prepend':
 						$this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
 						break;
 					case 'replace':
 						$this->Data[$index]['html'] = $html;
 						break;
 				}
 				return true;
 			}
 			
 			/**
 			 * Move $debugLineCount lines of input from debug output
 			 * end to beginning.
 			 *
 			 * @param int $debugLineCount
 			 */
 			function moveToBegin($debugLineCount)
 			{
 				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
 				$this->Data = array_merge($lines,$this->Data);
 			}
 			
 			function moveAfterRow($new_row, $debugLineCount)
 			{
 				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
 				$rows_before = array_splice($this->Data,0,$new_row,$lines);
 				$this->Data = array_merge($rows_before,$this->Data);
 			}
 			
 			function appendRequest()
 			{
 				$script = $_SERVER['SCRIPT_FILENAME'];
 				$this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)');
 				
 				$this->appendHTML('<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>: <input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>&nbsp;<button class="button" onclick="return dbg_OpenDOMViewer();">Show</button>');
 
 				ob_start();
 				?>
 				<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: 100%;">
 					<thead style="font-weight: bold;">
 						<td width="20">Src</td><td>Name</td><td>Value</td>
 					</thead>
 				<?php
 					foreach($_REQUEST as $key => $value)
 					{
 						if( !is_array($value) && trim($value) == '' )
 						{
 							$value = '<b class="debug_error">no value</b>';
 						}
 						else
 						{
 							$value = htmlspecialchars(print_r($value, true));
 						}
 						$src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
 						echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
 					}
 				?> 
 				</table>
 				<?php
 				$this->appendHTML( ob_get_contents() );
 				ob_end_clean();
 			}
 			
 			function appendSession()
 			{
 				if( isset($_SESSION)&&$_SESSION )
 				{
 					$this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
 					$this->dumpVars($_SESSION);
 					$this->moveToBegin(2);
 				}	
 			}
 			
 			function profileStart($key, $description)
 			{
 				$timeStamp = $this->getMoment();
 				$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
 				$this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
 			}
 			
 			function profileFinish($key)
 			{
 				$this->ProfilerData[$key]['ends'] = $this->getMoment();
 			}
 			
 			function profilerAddTotal($total_key, $key=null, $value=null)
 			{
 				if (!isset($this->ProfilerTotals[$total_key])) {
 					$this->ProfilerTotals[$total_key] = 0;
 				}
 				if (!isset($value)) {
 					$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
 				}
 				$this->ProfilerTotals[$total_key] += $value;
 			}
 			
 			function getMoment()
 			{
 				list($usec, $sec) = explode(' ', microtime()); 
 	   			return ((float)$usec + (float)$sec); 
 			}
 			
 			function generateID()
 			{
 				list($usec, $sec) = explode(" ",microtime());
 	
 				$id_part_1 = substr($usec, 4, 4);
 				$id_part_2 = mt_rand(1,9);
 				$id_part_3 = substr($sec, 6, 4);
 				$digit_one = substr($id_part_1, 0, 1);
 				if ($digit_one == 0) {
 					$digit_one = mt_rand(1,9);
 					$id_part_1 = ereg_replace("^0","",$id_part_1);
 					$id_part_1=$digit_one.$id_part_1;
 				}
 				return $id_part_1.$id_part_2.$id_part_3;
 			}
 	
 			
 			function getErrorNameByCode($errorCode)
 			{
 				switch($errorCode)
 				{
 					case E_USER_ERROR:
 						return 'Fatal Error';
 						break;
 						
 					case E_WARNING:
 					case E_USER_WARNING:
 						return 'Warning';
 						break;
 						
 					case E_NOTICE:
 					case E_USER_NOTICE:
 						return 'Notice';
 						break;
 					
 					case E_STRICT:
 					return 'PHP5 Strict';
 					break;
 					
 					default:
 						return '';
 						break;
 				}
 			}
 			
 			/**
 			 * Generates report
 			 *
 			 */
 			function printReport($returnResult = false)
 			{
 				if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return;
 				
 				$this->profileFinish('script_runtime');
 				if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return;
 				
 				dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0);
 				dbg_safeDefine('DBG_WINDOW_WIDTH', 700);
 				
 				$this->memoryUsage['debugger_start']=memory_get_usage();
 				
 				// show php session if any
 				$this->appendSession();
 				
 				// ensure, that 1st line of debug output always is this one:
 				$this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>');
 				$this->moveToBegin(1);
 				
 				if( dbg_ConstOn('DBG_SQL_PROFILE') && getArrayValue($this->ProfilerTotals, 'sql') )
 				{
 					$this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']);
 				}
 				
 				if( dbg_ConstOn('DBG_PROFILE_MEMORY') )
 				{
 					$this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb');
 				}
 				
 				if( dbg_ConstOn('DBG_INCLUDED_FILES') )
 				{
 					$files = get_included_files();
 					$this->appendHTML('<b>Included files:</b>');
 					foreach ($files as $file)
 					{
 						$this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)');
 					}
 				}
 				
 				if( dbg_ConstOn('DBG_PROFILE_INCLUDES') )
 				{
 					$this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
 					$totals = Array( 'mem' => 0, 'time' => 0);
 					$totals_configs = Array( 'mem' => 0, 'time' => 0);
 					if ( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ) {
 						array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
 					}
 					foreach ($this->IncludesData['file'] as $key => $file_name) {
 						$this->appendHTML(  str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
 						if ($this->IncludesData['level'][$key] == 0) {
 							$totals['mem'] += $this->IncludesData['mem'][$key];
 							$totals['time'] += $this->IncludesData['time'][$key];
 						}
 						else if ($this->IncludesData['level'][$key] == -1) {
 							$totals_configs['mem'] += $this->IncludesData['mem'][$key];
 							$totals_configs['time'] += $this->IncludesData['time'][$key];
 						}
 					}
 					$this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
 					$this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
 					$this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
 				}
 				
 				
 				$i = 0; $lineCount = count($this->Data);
 				ob_start();
 				?>
 					<style type="text/css">
 				
 						.dbg_flat_table {
 							border-collapse: collapse;
 							width: auto;
 						}
 						
 						.dbg_flat_table TD {
 							border: 1px solid buttonface;
 							padding: 4px;
 						}
 						
 						.debug_layer_table {
 							border-collapse: collapse;
 							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
 						}
 						
 						.debug_text, .debug_row_even TD, .debug_row_odd TD {
 							color: #000000;
 							font-family: Verdana;
 							font-size: 11px;
 							word-wrap: break-word;
 						}
 						
 						.debug_cell {
 							border: 1px solid #FF0000;
 							padding: 4px;
 							word-wrap: break-word;
 						}
 						
 						.debug_row_even {
 							background-color: #CCCCFF;
 						}
 						
 						.debug_row_odd {
 							background-color: #FFFFCC;
 						}
 						
 						.debug_layer_container {
 							left: 2px;
 							top: 1px;
 							width: <?php echo DBG_WINDOW_WIDTH; ?>px;
 							z-index: +1000;
 							position: absolute;
 							overflow: auto;
 							border: 2px solid;
 							padding: 3px;
 							border-top-color: threedlightshadow;
 							border-left-color: threedlightshadow;
 							border-right-color: threeddarkshadow;
 							border-bottom-color: threeddarkshadow;
 							background-color: buttonface;
 						}
 						
 						.debug_layer {
 							padding: 0px;
 							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
 						}
 						
 						.debug_error {
 							color: #FF0000;
 						}
 					</style>
 					<div id="debug_layer" class="debug_layer_container" style="display: none;">
 						<div class="debug_layer">
 							<table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table">
 				<?php
 				while ($i < $lineCount)
 				{
 					echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>';
 					$i++;
 				}
 				?>
 							</table>
 						</div>
 					</div>
 					<script language="javascript">
 					
 						function dbg_OpenDOMViewer()
 						{
 							var $value = document.getElementById('dbg_domviewer').value;
 							DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value);
 							window.open('<?php echo constant('DBG_DOMVIEWER'); ?>');
 							return false;
 						}
 						
 						function getEventKeyCode($e)
 						{
 							var $KeyCode = 0;
 							if($e.keyCode) $KeyCode = $e.keyCode;
 							else if($e.which) $KeyCode = $e.which;
 							return $KeyCode;
 						}
 					
 						function keyProcessor($e)
 						{
 							if(!$e) $e = window.event;
 							var $KeyCode = getEventKeyCode($e);
 							if($KeyCode==123||$KeyCode==27) // F12 or ESC
 							{
 								toggleDebugLayer($KeyCode);
 								$e.cancelBubble = true;
 								if($e.stopPropagation) $e.stopPropagation();
 							}
 						}
 						
 						function toggleDebugLayer($KeyCode)
 						{
 							var $isVisible=false;
 							var $DebugLayer = document.getElementById('debug_layer');
 							if( typeof($DebugLayer) != 'undefined' )
 							{
 								$isVisible = ($DebugLayer.style.display == 'none')?false:true;
 								if(!$isVisible&&$KeyCode==27) return false;
 								
 								resizeDebugLayer(null);
 								$DebugLayer.style.display = $isVisible?'none':'block';
 							}
 						}
 						
 						function prepareSizes($Prefix)
 						{
 							var $ret = '';
 							$ret = eval('document.body.'+$Prefix+'Top')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Left')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Height')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Width')+'; ';	
 							return $ret;
 						}
 						
 						function resizeDebugLayer($e)
 						{
 							if(!$e) $e = window.event;
 							var $DebugLayer = document.getElementById('debug_layer');
 							var $TopMargin = 1;
 							
 							var $pageWidth = document.all ? document.body.offsetWidth - 4 : window.innerWidth;
 							var $pageHeight = document.all ? document.body.clientHeight : window.innerHeight; // document.body.offsetHeight - 2
 							
 							var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY;
 							
 							if( typeof($DebugLayer) != 'undefined' )
 							{
 								if(document.all)
 								{
 									$DebugLayer.style.top = ($pageTop + 2) + 'px';
 									$DebugLayer.style.height = ($pageHeight - 2 - 4) + 'px';
 								}
 								else
 								{
 									$DebugLayer.style.top = ($pageTop + 2) + 'px';
 									$DebugLayer.style.height = ($pageHeight - 2 - 15) + 'px';
 								}
 							}
 //							window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client');
 //							window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight;
 							return true;
 						}
 						
 						function SetClipboard(copyText)
 						{
 							if(window.clipboardData)
 							{ 	
 								// IE send-to-clipboard method.
 								window.clipboardData.setData('Text', copyText);
 							}
 							else if (window.netscape)
 							{
 								// You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
 								netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 	
 								// Store support string in an object.
 								var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
 								if (!str) return false;
 								str.data=copyText;
 	
 								// Make transferable.
 								var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
 								if (!trans) return false;
 	
 								// Specify what datatypes we want to obtain, which is text in this case.
 								trans.addDataFlavor("text/unicode");
 								trans.setTransferData("text/unicode",str,copyText.length*2);
 	
 								var clipid=Components.interfaces.nsIClipboard;
 								var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
 								if (!clip) return false;
 	
 								clip.setData(trans,null,clipid.kGlobalClipboard);
 							}
 	
 						}
 						
 						function showProps($Obj, $Name)
 						{
 							var $ret = '';
 							for($Prop in $Obj)
 							{
 								$ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n";
 							}
 							return $ret;
 						}
 						
 						function editFile($fileName,$lineNo)
 						{
 							if(!document.all)
 							{
 								alert('Only works in IE');
 								return;
 							}
 							
 							var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>';
 							if($editorPath)
 							{
 								var $obj = new ActiveXObject("LaunchinIE.Launch");
 								$editorPath = $editorPath.replace('%F',$fileName);
 								$editorPath = $editorPath.replace('%L',$lineNo);
 								$obj.LaunchApplication($editorPath);
 							}
 							else
 							{
 								alert('Editor path not defined!');	
 							}
 						}
 						
 						function toggleTraceArgs($ArgsLayerID)
 						{
 							var $ArgsLayer = document.getElementById($ArgsLayerID);
 							$ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none';
 						}
 						
 						
 						document.onkeydown = keyProcessor;
 						window.onresize = resizeDebugLayer;
 						window.onscroll = resizeDebugLayer;
 						window.focus();
 						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> )
 						{
 							toggleDebugLayer();
 						}
 						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
 						{
 							document.getElementById('debug_layer').scrollTop = 10000000;
 						}
 					</script>
 				<?php
 				
 					dbg_safeDefine('DBG_SHOW_MEMORY_USAGE', 1);
 					if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') )
 					{
 						$this->memoryUsage['debugger_finish']=memory_get_usage();
 						$this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
 						$this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
 						$this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
 					}
 					
 					if($returnResult)
 					{
 						$ret = ob_get_contents();
 						ob_clean();
 						if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret .= $this->getMemoryUsageReport();
 						return $ret;
 					}
 					else
 					{
 						if( !dbg_ConstOn('DBG_HIDE_FULL_REPORT') )
 						{
 						ob_end_flush();
 						}
 						else
 						{
 							ob_clean();
 						}
 						if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
 					}
 			}
 			
 			/**
 			 * Format's memory usage report by debugger
 			 *
 			 * @return string
 			 * @access private
 			 */
 			function getMemoryUsageReport()
 			{
 				if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return '';
 				
 				$info = Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report',
 							'saveError'=>'error_handling',
 							'Total'=>'total',
 							'Application'=>'application');
 				$ret=Array();
 				foreach($info as $title => $value_key)
 				{
 					$ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>';
 				}
 				return '<table class="dbg_flat_table">'.implode('',$ret).'</table>';
 			}
 			
 			
 			/**
 			 * User-defined error handler
 			 *
 			 * @param int $errno
 			 * @param string $errstr
 			 * @param string $errfile
 			 * @param int $errline
 			 * @param array $errcontext
 			 */
 			function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
 			{
 				$memory_used=Array();
 				$memory_used['begin']=memory_get_usage();
 				
 				$errorType = $this->getErrorNameByCode($errno);
 				if(!$errorType)
 				{
 					trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
 					return false;
 				}
 				
 				if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return;	
 				
 				$long_id_pos=strrpos($errstr,'#');
 				if($long_id_pos!==false)
 				{
 					// replace short message with long one (due triger_error limitations on message size)
 					$long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
 					$errstr=$this->longErrors[$long_id];	
 					unset($this->longErrors[$long_id]);
 				}
 				
 				
 				/*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line 
 				
 				[PRE-PARSED block, $line 13]: Undefined variable: IdField*/
 				/*
 				if( strpos($errfile,'runtime-created') !== false ) {
 					$errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> ';
 				}*/
 				
 				if( strpos($errfile,'eval()\'d code') !== false )
 				{
 					$errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
 					$tmpStr = $errfile;
 					$pos = strpos($tmpStr,'(');
 					$errfile = substr($tmpStr,0,$pos);
 					$pos++;
 					$errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
 				}
 				// if($this->TraceNextError || $errno == E_USER_ERROR)
 				if($this->TraceNextError)
 				{
 					$this->appendTrace();	
 					$this->TraceNextError=false;
 				}
 				$this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
 				$memory_used['end']=memory_get_usage();
 				$this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
 				if( substr($errorType,0,5) == 'Fatal')
 				{
 					echo '<script language="javascript">var $isFatalError = 1;</script>';
 					exit;
 				}
 			}
 			
 			function saveToFile($msg)
 			{
 				$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
 				fwrite($fp,$msg."\n");
 				fclose($fp);
 			}
 			
 			/**
 			 * Formats file/memory size in nice way
 			 *
 			 * @param int $bytes
 			 * @return string
 			 * @access public
 			 */
 			function formatSize($bytes)
 			{
 				if ($bytes >= 1099511627776) {
 					$return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
 					$suffix = "TB";
 				} elseif ($bytes >= 1073741824) {
 					$return = round($bytes / 1024 / 1024 / 1024, 2);
 					$suffix = "GB";
 				} elseif ($bytes >= 1048576) {
 					$return = round($bytes / 1024 / 1024, 2);
 					$suffix = "MB";
 				} elseif ($bytes >= 1024) {
 					$return = round($bytes / 1024, 2);
 					$suffix = "KB";
 				} else {
 					$return = $bytes;
 					$suffix = "Byte";
 				}
 				$return .= ' '.$suffix;
 				return $return;
 			}
 			
 		}
 	
 		if( !function_exists('memory_get_usage') )
 		{
 			function memory_get_usage(){ return -1;	}
 		}
 		
 		$debugger = new Debugger();
 		
 		if( dbg_ConstOn('DBG_HANDLE_ERRORS') )
 		{
 			if( class_exists('kApplication') )
 			{
 				$application =& kApplication::Instance();
 				$application->Debugger =& $debugger;
 				$application->errorHandlers[] = Array(&$debugger, 'saveError');
 			}
 			else
 			{
 				set_error_handler( Array(&$debugger, 'saveError')  );
 			}
 		}
 
 		if( dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) register_shutdown_function( Array(&$debugger, 'printReport') );
 	}
 ?>
\ No newline at end of file

Property changes on: trunk/kernel/include/debugger.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.40
\ No newline at end of property
+1.41
\ No newline at end of property
Index: trunk/core/kernel/utility/debugger.php
===================================================================
--- trunk/core/kernel/utility/debugger.php	(revision 2677)
+++ trunk/core/kernel/utility/debugger.php	(revision 2678)
@@ -1,984 +1,1007 @@
 <?php
 
 	if( !class_exists('Debugger') )
 	{
 		function dbg_ConstOn($const_name)
 		{
 			return defined($const_name) && constant($const_name);
 		}
 
 		function dbg_safeDefine($const_name,$const_value)
 		{
 			if(!defined($const_name)) define($const_name,$const_value);
 		}
 
 		unset($_REQUEST['debug_host']);	// this var messed up whole detection stuff :(
 
 		// Detect fact, that this session beeing debugged by Zend Studio
 		foreach($_REQUEST as $rq_name=>$rq_value)
 		{
 			if( substr($rq_name,0,6)=='debug_' )
 			{
 				dbg_safeDefine('DBG_ZEND_PRESENT', 1);
 				break;
 			}
 		}
 
 		dbg_safeDefine('DBG_ZEND_PRESENT',0);
 
 		// set default values for debugger constants
 		$dbg_constMap=Array('DBG_OPTIONS'=>0,
 							'DBG_USE_HIGHLIGHT'=>1,
 							'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1,
 							'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1,
 							'DBG_IGNORE_STRICT_ERRORS'=>1,
 							'DBG_DOMVIEWER'=>'/temp/domviewer.html',
 							'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
 							'DBG_LOCAL_BASE_PATH'=>'w:');
 
 		foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
 		{
 			dbg_safeDefine($dbg_constName,$dbg_constValue);
 		}
 
 		// only for IE, in case if no windows php script editor defined
 		/*if(!defined('WINDOWS_EDITOR'))
 		{
 			$dbg_editor = 0;
 			$dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
 			$dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
 			define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
 			unset($dbg_editors,$dbg_editor);
 		}*/
 
 		class Debugger
 		{
 			/**
 			 * Debugger data for building report
 			 *
 			 * @var Array
 			 */
 			var $Data = Array();
 			var $ProfilerData = Array();
 			var $ProfilerTotals = Array();
 			var $RecursionStack = Array();	// prevent recursion when processing debug_backtrace() function results
 
 			var $TraceNextError=false;
 
 			var $Options = 0;
 			var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
 									'output_buffer' => 4, 'highlight_output' => 8);
 
 
 			var $longErrors=Array();
 
 			/**
 			 * Amount of memory used by debugger itself
 			 *
 			 * @var Array
 			 * @access private
 			 */
 			var $memoryUsage=Array();
 
 			var $IncludesData=Array();
 			var $IncludeLevel=0;
 
 			function Debugger()
 			{
 				$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
 				$this->profileStart('script_runtime', 'Script runtime');
 				ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1);
 				$this->memoryUsage['error_handling']=0; // memory amount used by error handler
 				$this->appendRequest();
 			}
 
 			function initOptions()
 			{
 
 			}
 
 			function mapLongError($msg)
 			{
 				$key=$this->generateID();
 				$this->longErrors[$key]=$msg;
 				return $key;
 			}
 
 			function setOption($name,$value)
 			{
 				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
 				if($value)
 				{
 					$this->Options|=$this->OptionsMap[$name];
 				}
 				else
 				{
 					$this->Options=$this->Options&~$this->OptionsMap[$name];
 				}
 			}
 
 			function getOption($name)
 			{
 				if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
 	    		return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
 			}
 
 			/**
 			 * Set's flag, that next error that occurs will
 			 * be prepended by backtrace results
 			 *
 			 */
 			function traceNext()
 			{
 				$this->TraceNextError=true;
 			}
 
 			function dumpVars()
 			{
 				$dumpVars = func_get_args();
 				foreach($dumpVars as $varValue)
 				{
 					$this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
 				}
 			}
 
 			function prepareHTML($dataIndex)
 			{
 				$Data =& $this->Data[$dataIndex];
 				if($Data['debug_type'] == 'html') return $Data['html'];
 
 				switch($Data['debug_type'])
 				{
 					case 'error':
 						$fileLink = $this->getFileLink($Data['file'],$Data['line']);
 						$ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
 						$ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
 						return $ret;
 						break;
 
 					case 'var_dump':
 						return $this->highlightString( print_r($Data['value'], true) );
 						break;
 
 					case 'trace':
 						ini_set('memory_limit','500M');
 						$trace =& $Data['trace'];
 
 						//return 'sorry';
 						//return $this->highlightString(print_r($trace,true));
 
 
 						$i = 0; $traceCount = count($trace);
 						$ret = '';
 						while($i < $traceCount)
 						{
 							$traceRec =& $trace[$i];
 							$argsID = 'trace_args_'.$dataIndex.'_'.$i;
+							
+							$has_args = isset($traceRec['args']);
+							
 							if(isset($traceRec['file']))
 							{
 								$func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
-								$ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
+								$args_link = $has_args ? '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>' : '<b>Function</b>';
+								
+								$ret .= $args_link.': '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
 								$ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
 							}
 							else
 							{
 								$ret .= 'no file information available';
 							}
 
 							// ensure parameter value is not longer then 200 symbols
-							$this->processTraceArguments($traceRec['args']);
-							$args = $this->highlightString(print_r($traceRec['args'], true));
-							$ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
+							if($has_args)
+							{
+								$this->processTraceArguments($traceRec['args']);
+								$args = $this->highlightString(print_r($traceRec['args'], true));
+								$ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
+							}
 							$i++;
 						}
 						return $ret;
 						break;
 
 					case 'profiler':
 						$profileKey = $Data['profile_key'];
 						$Data =& $this->ProfilerData[$profileKey];
 						$runtime = ($Data['ends'] - $Data['begins']); // in seconds
 						return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
 						break;
 
 					default:
 						return 'incorrect debug data';
 						break;
 				}
 			}
 
+			function isApplication(&$object)
+			{
+				$app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication';
+				return get_class($object) == $app_class;
+			}
+			
 			function processTraceArguments(&$traceArgs)
 			{
 				if(!$traceArgs) return '';
-				foreach ($traceArgs as $argID => $argValue)
+				
+				$array_keys = array_keys($traceArgs);
+				foreach($array_keys as $argID)
 				{
+					$argValue =& $traceArgs[$argID];
+					
 					if( is_array($argValue) || is_object($argValue) )
 					{
 						if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
 						{
-							if( get_class($argValue) == 'kfactory' || get_class($argValue) == 'debugger' ) continue;
+							array_push($this->RecursionStack, get_class($argValue));
+							
+							if( get_class($argValue) == 'kfactory' || $this->isApplication($argValue) || get_class($argValue) == 'templateparser' )
+							{
+								$argValue = null;
+								continue;
+							}
 							
 							// object & not in stack - ok
-							array_push($this->RecursionStack, get_class($argValue));
 							settype($argValue,'array');
 							$this->processTraceArguments($argValue);
 							array_pop($this->RecursionStack);
 						}
 						elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
 						{
 							// object & in stack - recursion
 							$traceArgs[$argID] = '**** RECURSION ***';
 						}
 						else
 						{
 							// normal array here
 							$this->processTraceArguments($argValue);
 						}
 					}
 					else
 					{
 						$traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
 					}
 				}
 			}
 
 			function cutStringForHTML($string)
 			{
 				if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
 				return $string;
 			}
 
 			/**
 			 * Format SQL Query using predefined formatting
 			 * and highlighting techniques
 			 *
 			 * @param string $sql
 			 * @return string
 			 */
 			function formatSQL($sql)
 			{
 				$sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
 				$sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
 				return $this->highlightString($sql);
 			}
 
 			function highlightString($string)
 			{
 				if( dbg_ConstOn('DBG_USE_HIGHLIGHT') )
 				{
 					$string = str_replace('\\','_no_match_string_',$string);
 					$string = highlight_string('<?php '.$string.'?>', true);
 					$string = str_replace('_no_match_string_','\\',$string);
 					return preg_replace('/&lt;\?(.*)php (.*)\?&gt;/s','$2',$string);
 				}
 				else
 				{
 					return $string;
 				}
 			}
 
 			function getFileLink($file, $lineno = 1, $title = '')
 			{
 				if(!$title) $title = $file;
 				$is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
 				if($is_mozilla)
 				{
 					return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
 				}
 				else
 				{
 					return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>';
 				}
 
 			}
 
 			function getLocalFile($remoteFile)
 			{
 				return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);
 			}
 
 			function appendTrace()
 			{
 				$trace = debug_backtrace();
 				array_shift($trace);
 				$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
 			}
 
 			function appendMemoryUsage($msg, $used=null)
 			{
 				if (!isset($used)) $used = round(memory_get_usage()/1024);
 				$this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
 			}
 
 			function appendHTML($html)
 			{
 				$this->Data[] = Array('html' => $html,'debug_type' => 'html');
 			}
 
 			/**
 			 * Change debugger info that was already generated before.
 			 * Returns true if html was set.
 			 *
 			 * @param int $index
 			 * @param string $html
 			 * @param string $type = {'append','prepend','replace'}
 			 * @return bool
 			 */
 			function setHTMLByIndex($index,$html,$type='append')
 			{
 				if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' )
 				{
 					return false;
 				}
 
 				switch ($type)
 				{
 					case 'append':
 						$this->Data[$index]['html'] .= '<br>'.$html;
 						break;
 					case 'prepend':
 						$this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
 						break;
 					case 'replace':
 						$this->Data[$index]['html'] = $html;
 						break;
 				}
 				return true;
 			}
 
 			/**
 			 * Move $debugLineCount lines of input from debug output
 			 * end to beginning.
 			 *
 			 * @param int $debugLineCount
 			 */
 			function moveToBegin($debugLineCount)
 			{
 				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
 				$this->Data = array_merge($lines,$this->Data);
 			}
 
 			function moveAfterRow($new_row, $debugLineCount)
 			{
 				$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
 				$rows_before = array_splice($this->Data,0,$new_row,$lines);
 				$this->Data = array_merge($rows_before,$this->Data);
 			}
 
 			function appendRequest()
 			{
 				$script = $_SERVER['SCRIPT_FILENAME'];
 				$this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)');
 
 				$this->appendHTML('<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>: <input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>&nbsp;<button class="button" onclick="return dbg_OpenDOMViewer();">Show</button>');
 
 				ob_start();
 				?>
 				<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: 100%;">
 					<thead style="font-weight: bold;">
 						<td width="20">Src</td><td>Name</td><td>Value</td>
 					</thead>
 				<?php
 					foreach($_REQUEST as $key => $value)
 					{
 						if( !is_array($value) && trim($value) == '' )
 						{
 							$value = '<b class="debug_error">no value</b>';
 						}
 						else
 						{
 							$value = htmlspecialchars(print_r($value, true));
 						}
 						$src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
 						echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
 					}
 				?>
 				</table>
 				<?php
 				$this->appendHTML( ob_get_contents() );
 				ob_end_clean();
 			}
 
 			function appendSession()
 			{
 				if( isset($_SESSION)&&$_SESSION )
 				{
 					$this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
 					$this->dumpVars($_SESSION);
 					$this->moveToBegin(2);
 				}
 			}
 
 			function profileStart($key, $description)
 			{
 				$timeStamp = $this->getMoment();
 				$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
 				$this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
 			}
 
 			function profileFinish($key)
 			{
 				$this->ProfilerData[$key]['ends'] = $this->getMoment();
 			}
 
 			function profilerAddTotal($total_key, $key=null, $value=null)
 			{
 				if (!isset($this->ProfilerTotals[$total_key])) {
 					$this->ProfilerTotals[$total_key] = 0;
 				}
 				if (!isset($value)) {
 					$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
 				}
 				$this->ProfilerTotals[$total_key] += $value;
 			}
 
 			function getMoment()
 			{
 				list($usec, $sec) = explode(' ', microtime());
 	   			return ((float)$usec + (float)$sec);
 			}
 
 			function generateID()
 			{
 				list($usec, $sec) = explode(" ",microtime());
 
 				$id_part_1 = substr($usec, 4, 4);
 				$id_part_2 = mt_rand(1,9);
 				$id_part_3 = substr($sec, 6, 4);
 				$digit_one = substr($id_part_1, 0, 1);
 				if ($digit_one == 0) {
 					$digit_one = mt_rand(1,9);
 					$id_part_1 = ereg_replace("^0","",$id_part_1);
 					$id_part_1=$digit_one.$id_part_1;
 				}
 				return $id_part_1.$id_part_2.$id_part_3;
 			}
 
 
 			function getErrorNameByCode($errorCode)
 			{
 				switch($errorCode)
 				{
 					case E_USER_ERROR:
 						return 'Fatal Error';
 						break;
 
 					case E_WARNING:
 					case E_USER_WARNING:
 						return 'Warning';
 						break;
 
 					case E_NOTICE:
 					case E_USER_NOTICE:
 						return 'Notice';
 						break;
 
 					case E_STRICT:
 					return 'PHP5 Strict';
 					break;
 
 					default:
 						return '';
 						break;
 				}
 			}
 
 			/**
 			 * Generates report
 			 *
 			 */
 			function printReport($returnResult = false)
 			{
 				if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return;
 
 				$this->profileFinish('script_runtime');
 				if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return;
 
 				dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0);
 				dbg_safeDefine('DBG_WINDOW_WIDTH', 700);
-
+				
 				$this->memoryUsage['debugger_start']=memory_get_usage();
 
 				// show php session if any
 				$this->appendSession();
 
 				// ensure, that 1st line of debug output always is this one:
 				$this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>');
 				$this->moveToBegin(1);
 				
 				if( dbg_ConstOn('DBG_SQL_PROFILE') && getArrayValue($this->ProfilerTotals, 'sql') )
 				{
 					$this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']);
 				}
 				
 				if( dbg_ConstOn('DBG_PROFILE_MEMORY') )
 				{
 					$this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb');
 				}
 				
 				if( dbg_ConstOn('DBG_INCLUDED_FILES') )
 				{
 					$files = get_included_files();
 					$this->appendHTML('<b>Included files:</b>');
 					foreach ($files as $file)
 					{
 						$this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)');
 					}
 				}
 				
 				if( dbg_ConstOn('DBG_PROFILE_INCLUDES') )
 				{
 					$this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
 					$totals = Array( 'mem' => 0, 'time' => 0);
 					$totals_configs = Array( 'mem' => 0, 'time' => 0);
 					if ( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ) {
 						array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
 					}
 					foreach ($this->IncludesData['file'] as $key => $file_name) {
 						$this->appendHTML(  str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
 						if ($this->IncludesData['level'][$key] == 0) {
 							$totals['mem'] += $this->IncludesData['mem'][$key];
 							$totals['time'] += $this->IncludesData['time'][$key];
 						}
 						else if ($this->IncludesData['level'][$key] == -1) {
 							$totals_configs['mem'] += $this->IncludesData['mem'][$key];
 							$totals_configs['time'] += $this->IncludesData['time'][$key];
 						}
 					}
 					$this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
 					$this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
 					$this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
 				}
 
 
 				$i = 0; $lineCount = count($this->Data);
 				ob_start();
 				?>
 					<style type="text/css">
 
 						.dbg_flat_table {
 							border-collapse: collapse;
 							width: auto;
 						}
 
 						.dbg_flat_table TD {
 							border: 1px solid buttonface;
 							padding: 4px;
 						}
 
 						.debug_layer_table {
 							border-collapse: collapse;
 							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
 						}
 
 						.debug_text, .debug_row_even TD, .debug_row_odd TD {
 							color: #000000;
 							font-family: Verdana;
 							font-size: 11px;
 							word-wrap: break-word;
 						}
 
 						.debug_cell {
 							border: 1px solid #FF0000;
 							padding: 4px;
 							word-wrap: break-word;
 						}
 
 						.debug_row_even {
 							background-color: #CCCCFF;
 						}
 
 						.debug_row_odd {
 							background-color: #FFFFCC;
 						}
 
 						.debug_layer_container {
 							left: 2px;
 							top: 1px;
 							width: <?php echo DBG_WINDOW_WIDTH; ?>px;
 							z-index: +1000;
 							position: absolute;
 							overflow: auto;
 							border: 2px solid;
 							padding: 3px;
 							border-top-color: threedlightshadow;
 							border-left-color: threedlightshadow;
 							border-right-color: threeddarkshadow;
 							border-bottom-color: threeddarkshadow;
 							background-color: buttonface;
 						}
 
 						.debug_layer {
 							padding: 0px;
 							width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
 						}
 
 						.debug_error {
 							color: #FF0000;
 						}
 					</style>
 					<div id="debug_layer" class="debug_layer_container" style="display: none;">
 						<div class="debug_layer">
 							<table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table">
 				<?php
 				while ($i < $lineCount)
 				{
 					echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>';
 					$i++;
 				}
 				?>
 							</table>
 						</div>
 					</div>
 					<script language="javascript">
 
 						function dbg_OpenDOMViewer()
 						{
 							var $value = document.getElementById('dbg_domviewer').value;
 							DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value);
 							window.open('<?php echo constant('DBG_DOMVIEWER'); ?>');
 							return false;
 						}
 
 						function getEventKeyCode($e)
 						{
 							var $KeyCode = 0;
 							if($e.keyCode) $KeyCode = $e.keyCode;
 							else if($e.which) $KeyCode = $e.which;
 							return $KeyCode;
 						}
 
 						function keyProcessor($e)
 						{
 							if(!$e) $e = window.event;
 							var $KeyCode = getEventKeyCode($e);
 							if($KeyCode==123||$KeyCode==27) // F12 or ESC
 							{
 								toggleDebugLayer($KeyCode);
 								$e.cancelBubble = true;
 								if($e.stopPropagation) $e.stopPropagation();
 							}
 						}
 
 						function toggleDebugLayer($KeyCode)
 						{
 							var $isVisible=false;
 							var $DebugLayer = document.getElementById('debug_layer');
 							if( typeof($DebugLayer) != 'undefined' )
 							{
 								$isVisible = ($DebugLayer.style.display == 'none')?false:true;
 								if(!$isVisible&&$KeyCode==27) return false;
 
 								resizeDebugLayer(null);
 								$DebugLayer.style.display = $isVisible?'none':'block';
 							}
 						}
 
 						function prepareSizes($Prefix)
 						{
 							var $ret = '';
 							$ret = eval('document.body.'+$Prefix+'Top')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Left')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Height')+'; ';
 							$ret += eval('document.body.'+$Prefix+'Width')+'; ';
 							return $ret;
 						}
 
 						function resizeDebugLayer($e)
 						{
 							if(!$e) $e = window.event;
 							var $DebugLayer = document.getElementById('debug_layer');
 							var $TopMargin = 1;
 
 							var $pageWidth = document.all ? document.body.offsetWidth - 4 : window.innerWidth;
 							var $pageHeight = document.all ? document.body.clientHeight : window.innerHeight; // document.body.offsetHeight - 2
 
 							var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY;
 
 							if( typeof($DebugLayer) != 'undefined' )
 							{
 								if(document.all)
 								{
 									$DebugLayer.style.top = ($pageTop + 2) + 'px';
 									$DebugLayer.style.height = ($pageHeight - 2 - 4) + 'px';
 								}
 								else
 								{
 									$DebugLayer.style.top = ($pageTop + 2) + 'px';
 									$DebugLayer.style.height = ($pageHeight - 2 - 15) + 'px';
 								}
 							}
 //							window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client');
 //							window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight;
 							return true;
 						}
 
 						function SetClipboard(copyText)
 						{
 							if(window.clipboardData)
 							{
 								// IE send-to-clipboard method.
 								window.clipboardData.setData('Text', copyText);
 							}
 							else if (window.netscape)
 							{
 								// You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
 								netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
 								// Store support string in an object.
 								var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
 								if (!str) return false;
 								str.data=copyText;
 
 								// Make transferable.
 								var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
 								if (!trans) return false;
 
 								// Specify what datatypes we want to obtain, which is text in this case.
 								trans.addDataFlavor("text/unicode");
 								trans.setTransferData("text/unicode",str,copyText.length*2);
 
 								var clipid=Components.interfaces.nsIClipboard;
 								var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
 								if (!clip) return false;
 
 								clip.setData(trans,null,clipid.kGlobalClipboard);
 							}
 
 						}
 
 						function showProps($Obj, $Name)
 						{
 							var $ret = '';
 							for($Prop in $Obj)
 							{
 								$ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n";
 							}
 							return $ret;
 						}
 
 						function editFile($fileName,$lineNo)
 						{
 							if(!document.all)
 							{
 								alert('Only works in IE');
 								return;
 							}
 
 							var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>';
 							if($editorPath)
 							{
 								var $obj = new ActiveXObject("LaunchinIE.Launch");
 								$editorPath = $editorPath.replace('%F',$fileName);
 								$editorPath = $editorPath.replace('%L',$lineNo);
 								$obj.LaunchApplication($editorPath);
 							}
 							else
 							{
 								alert('Editor path not defined!');
 							}
 						}
 
 						function toggleTraceArgs($ArgsLayerID)
 						{
 							var $ArgsLayer = document.getElementById($ArgsLayerID);
 							$ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none';
 						}
 
 
 						document.onkeydown = keyProcessor;
 						window.onresize = resizeDebugLayer;
 						window.onscroll = resizeDebugLayer;
 						window.focus();
 						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> )
 						{
 							toggleDebugLayer();
 						}
 						if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
 						{
 							document.getElementById('debug_layer').scrollTop = 10000000;
 						}
 					</script>
 				<?php
 				
 					dbg_safeDefine('DBG_SHOW_MEMORY_USAGE', 1);
 					if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') )
 					{
 						$this->memoryUsage['debugger_finish']=memory_get_usage();
 						$this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
 						$this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
 						$this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
 					}
 					
 					if($returnResult)
 					{
 						$ret = ob_get_contents();
 						ob_clean();
 						if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret .= $this->getMemoryUsageReport();
 						return $ret;
 					}
 					else
 					{
 						if( !dbg_ConstOn('DBG_HIDE_FULL_REPORT') )
 						{
 							ob_end_flush();
 						}
 						else
 						{
 							ob_clean();
 						}
 						if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
 					}
 			}
 
 			/**
 			 * Format's memory usage report by debugger
 			 *
 			 * @return string
 			 * @access private
 			 */
 			function getMemoryUsageReport()
 			{
 				if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return '';
 				
 				$info = Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report',
 							'saveError'=>'error_handling',
 							'Total'=>'total',
 							'Application'=>'application');
 				$ret=Array();
 				foreach($info as $title => $value_key)
 				{
 					$ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>';
 				}
 				return '<table class="dbg_flat_table">'.implode('',$ret).'</table>';
 			}
 
 
 			/**
 			 * User-defined error handler
 			 *
 			 * @param int $errno
 			 * @param string $errstr
 			 * @param string $errfile
 			 * @param int $errline
 			 * @param array $errcontext
 			 */
 			function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
 			{
 				$memory_used=Array();
 				$memory_used['begin']=memory_get_usage();
 
 				$errorType = $this->getErrorNameByCode($errno);
 				if(!$errorType)
 				{
 					trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
 					return false;
 				}
 
 				if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return;
 
 				$long_id_pos=strrpos($errstr,'#');
 				if($long_id_pos!==false)
 				{
 					// replace short message with long one (due triger_error limitations on message size)
 					$long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
 					$errstr=$this->longErrors[$long_id];
 					unset($this->longErrors[$long_id]);
 				}
 
 
 				/*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line
 
 				[PRE-PARSED block, $line 13]: Undefined variable: IdField*/
 				/*
 				if( strpos($errfile,'runtime-created') !== false ) {
 					$errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> ';
 				}*/
 				
 				if( strpos($errfile,'eval()\'d code') !== false )
 				{
 					$errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
 					$tmpStr = $errfile;
 					$pos = strpos($tmpStr,'(');
 					$errfile = substr($tmpStr,0,$pos);
 					$pos++;
 					$errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
 				}
 				// if($this->TraceNextError || $errno == E_USER_ERROR)
 				if($this->TraceNextError)
 				{
 					$this->appendTrace();
 					$this->TraceNextError=false;
 				}
 				$this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
 				$memory_used['end']=memory_get_usage();
 				$this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
 				if( substr($errorType,0,5) == 'Fatal')
 				{
 					echo '<script language="javascript">var $isFatalError = 1;</script>';
 					exit;
 				}
 			}
 
 			function saveToFile($msg)
 			{
 				$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
 				fwrite($fp,$msg."\n");
 				fclose($fp);
 			}
 
 			/**
 			 * Formats file/memory size in nice way
 			 *
 			 * @param int $bytes
 			 * @return string
 			 * @access public
 			 */
 			function formatSize($bytes)
 			{
 				if ($bytes >= 1099511627776) {
 					$return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
 					$suffix = "TB";
 				} elseif ($bytes >= 1073741824) {
 					$return = round($bytes / 1024 / 1024 / 1024, 2);
 					$suffix = "GB";
 				} elseif ($bytes >= 1048576) {
 					$return = round($bytes / 1024 / 1024, 2);
 					$suffix = "MB";
 				} elseif ($bytes >= 1024) {
 					$return = round($bytes / 1024, 2);
 					$suffix = "KB";
 				} else {
 					$return = $bytes;
 					$suffix = "Byte";
 				}
 				$return .= ' '.$suffix;
 				return $return;
 			}
 
 		}
 
 		if( !function_exists('memory_get_usage') )
 		{
 			function memory_get_usage(){ return -1;	}
 		}
 
 		$debugger = new Debugger();
 		
 		if( dbg_ConstOn('DBG_HANDLE_ERRORS') )
 		{
 			if( class_exists('kApplication') )
 			{
 				$application =& kApplication::Instance();
 				$application->Debugger =& $debugger;
 				$application->errorHandlers[] = Array(&$debugger, 'saveError');
 			}
 			else
 			{
 				set_error_handler( Array(&$debugger, 'saveError')  );
 			}
 		}
 
 		if( dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) register_shutdown_function( Array(&$debugger, 'printReport') );
 	}
 ?>
\ No newline at end of file

Property changes on: trunk/core/kernel/utility/debugger.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.20
\ No newline at end of property
+1.21
\ No newline at end of property
Index: trunk/core/kernel/application.php
===================================================================
--- trunk/core/kernel/application.php	(revision 2677)
+++ trunk/core/kernel/application.php	(revision 2678)
@@ -1,1340 +1,1340 @@
 <?php
 
 /**
 * Basic class for Kernel3-based Application
 *
 * This class is a Facade for any other class which needs to deal with Kernel3 framework.<br>
 * The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br>
 * <br>
 * The class is a singleton, which means that there could be only one instance of KernelApplication in the script.<br>
 * This could be guranteed by NOT calling the class constuctor directly, but rather calling KernelApplication::Instance() method,
 * which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br>
 * See singleton pattern by GOF.
 * @package kernel4
 */
 
 class kApplication {
 
 	/**
 	 * Is true, when Init method was called already, prevents double initialization
 	 *
 	 * @var bool
 	 */
 	var $InitDone = false;
 
 	/**
 	* Holds internal TemplateParser object
 	* @access private
 	* @var TemplateParser
 	*/
 	var $Parser;
 
 	/**
 	* Holds parser output buffer
 	* @access private
 	* @var string
 	*/
 	var $HTML;
 
 	/**
 	 * Prevents request from beeing proceeded twice in case if application init is called mere then one time
 	 *
 	 * @var bool
 	 * @todo This is not good anyway (by Alex)
 	 */
 	var $RequestProcessed = false;
 
 	/**
 	* The main Factory used to create
 	* almost any class of kernel and
 	* modules
 	*
 	* @access private
 	* @var kFactory
 	*/
 	var $Factory;
 
 	/**
 	 * Reference to debugger
 	 *
 	 * @var Debugger
 	 */
 	var $Debugger = null;
 
 	/**
 	 * Holds all phrases used
 	 * in code and template
 	 *
 	 * @var PhrasesCache
 	 */
 	var $Phrases;
 
 	/**
 	 * Holds DBConnection
 	 *
 	 * @var kDBConnection
 	 */
 	var $DB;
 
 	/**
 	 * Maintains list of user-defined error handlers
 	 *
 	 * @var Array
 	 */
 	var $errorHandlers = Array();
 
 	/**
 	* Returns kApplication instance anywhere in the script.
  	*
  	* This method should be used to get single kApplication object instance anywhere in the
  	* Kernel-based application. The method is guranteed to return the SAME instance of kApplication.
  	* Anywhere in the script you could write:
  	* <code>
  	*		$application =& kApplication::Instance();
  	* </code>
  	* or in an object:
  	* <code>
  	*		$this->Application =& kApplication::Instance();
  	* </code>
  	* to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class.
  	* To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant
  	* BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would
  	* create and return default KernelApplication instance.
  	* @static
  	* @access public
 	* @return kApplication
 	*/
 	function &Instance()
 	{
 		static $instance = false;
 
 		if(!$instance)
 		{
 			if (!defined('APPLICATION_CLASS')) define('APPLICATION_CLASS', 'kApplication');
 			$class = APPLICATION_CLASS;
 			$instance = new $class();
 		}
 		return $instance;
 	}
 
 	/**
 	* Initializes the Application
  	*
  	* @access public
 	* @see HTTPQuery
 	* @see Session
 	* @see TemplatesCache
 	* @return bool Was Init actually made now or before
 	*/
 	function Init()
 	{
 		if($this->InitDone) return false;
 
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') )
 		{
 			$GLOBALS['debugger']->appendMemoryUsage('Application before Init:');
 		}
 
 		if( !$this->isDebugMode() )
 		{
 			error_reporting(0);
 			ini_set('display_errors', 0);
 		}
 
 		$error_handler = set_error_handler( Array(&$this,'handleError') );
 		if($error_handler) $this->errorHandlers[] = $error_handler;
 
 
 		$this->DB = new kDBConnection(SQL_TYPE, Array(&$this,'handleSQLError') );
 		$this->DB->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
 		$this->DB->debugMode = $this->isDebugMode();
 
 		$this->Factory = new kFactory();
 
 		$this->registerDefaultClasses();
 		$this->SetDefaultConstants();
 
 		// 1. to read configs before doing any recallObject (called from "SetDefaultConstants" anyway)
 		//$config_reader =& $this->recallObject('kUnitConfigReader');
 
 		if( !$this->GetVar('m_lang') ) $this->SetVar('m_lang', $this->GetDefaultLanguageId() );
 		if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId() );
 		if( $this->GetVar('m_cat_id') === false ) $this->SetVar('m_cat_id', 0);
 
 		$this->Phrases = new PhrasesCache( $this->GetVar('m_lang') );
 
 		$this->SetVar('lang.current_id', $this->GetVar('m_lang') );
 		$language =& $this->recallObject('lang.current', null, Array('live_table'=>true) );
 
 		if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId() );
 		$this->SetVar('theme.current_id', $this->GetVar('m_theme') );
 
 		if( !$this->RecallVar('UserGroups') )
 		{
 			$ses =& $this->recallObject('Session');
 			$user_groups = trim($ses->GetField('GroupList'), ',');
 			if (!$user_groups) $user_groups = $this->ConfigValue('User_GuestGroup');
 			$this->StoreVar('UserGroups', $user_groups);
 		}
 
 		if( !$this->RecallVar('curr_iso') ) $this->StoreVar('curr_iso', $this->GetPrimaryCurrency() );
 
 		$this->SetVar('visits_id', $this->RecallVar('visit_id') );
 
 		$this->ValidateLogin(); // TODO: write that method
 
 		if( $this->isDebugMode() )
 		{
 			$GLOBALS['debugger']->profileFinish('kernel4_startup');
 		}
 
 		if( defined('CMS') && CMS == 1 && !$this->GetVar('admin') && !$this->IsAdmin() )
 		{
 			define('MOD_REWRITE', 1);
 		}
 
 		$this->InitDone = true;
 		return true;
 	}
 
 	function GetDefaultLanguageId()
 	{
 		$table = $this->getUnitOption('lang','TableName');
 		$id_field = $this->getUnitOption('lang','IDField');
 		return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryLang = 1');
 	}
 
 	function GetDefaultThemeId()
 	{
 		if (defined('DBG_FORCE_THEME') && DBG_FORCE_THEME){
 			return DBG_FORCE_THEME;
 		}
 		$table = $this->getUnitOption('theme','TableName');
 		$id_field = $this->getUnitOption('theme','IDField');
 		return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryTheme = 1');
 	}
 
 	function GetPrimaryCurrency()
 	{
 		$this->setUnitOption('mod','AutoLoad',false);
 		$module =& $this->recallObject('mod');
 		$this->setUnitOption('mod','AutoLoad',true);
 
 		if( $module->Load('In-Commerce') && $module->GetDBField('Loaded') == 1 )
 		{
 			$table = $this->getUnitOption('curr','TableName');
 			return $this->DB->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 1');
 		}
 		else
 		{
 			return 'USD';
 		}
 	}
 
 	/**
 	* Registers default classes such as ItemController, GridController and LoginController
 	*
 	* Called automatically while initializing Application
 	* @access private
 	* @return void
 	*/
 	function RegisterDefaultClasses()
 	{
 		$this->registerClass('kArray',KERNEL_PATH.'/utility/params.php');
 		$this->registerClass('Params',KERNEL_PATH.'/utility/params.php');
 
 		$this->registerClass('HTTPQuery', KERNEL_PATH.'/utility/http_query.php', 'HTTPQuery', Array('Params') );
 
 		$this->registerClass('Session', KERNEL_PATH.'/session/session.php');
 		$this->registerClass('SessionStorage', KERNEL_PATH.'/session/session.php');
 
 		$this->registerClass('kEventManager', KERNEL_PATH.'/event_manager.php', 'EventManager');
 		$this->registerClass('kUnitConfigReader', KERNEL_PATH.'/utility/unit_config_reader.php');
 
 		$this->registerClass('Params', KERNEL_PATH.'/utility/params.php', 'kActions');
 
 		$this->registerClass('kFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kOptionsFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kUploadFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kPictureFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kDateFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kLEFTFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kMultiLanguage', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kPasswordFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kCCDateFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kUnitFormatter', KERNEL_PATH.'/utility/formatters.php');
 		$this->registerClass('kFilesizeFormatter', KERNEL_PATH.'/utility/formatters.php');
 
 		$this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php');
 
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild');
 
 		$this->registerClass('TemplatesCache',KERNEL_PATH.'/parser/template.php');
 		$this->registerClass('Template',KERNEL_PATH.'/parser/template.php');
 		$this->registerClass('TemplateParser',KERNEL_PATH.'/parser/template_parser.php');
 
 		$this->registerClass('MainProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor');
 
 		$this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php');
 		$this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php');
 		$this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php');
 		$this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php');
 		$this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php');
 
 		$this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php');
 		$this->registerClass('kEmailMessage',KERNEL_PATH.'/utility/email.php');
 		$this->registerClass('kSmtpClient',KERNEL_PATH.'/utility/smtp_client.php');
 
 		if (file_exists(MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php')) {
 			$this->registerClass('kCurrencyRates',MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php');
 		}
 
 		$this->registerClass('FCKeditor', FULL_PATH.'/admin/editor/cmseditor/fckeditor.php'); // need this?
 	}
 
 	/**
 	* Defines default constants if it's not defined before - in config.php
 	*
 	* @access private
 	*/
 	function SetDefaultConstants()
 	{
 		if (!defined('SERVER_NAME')) define('SERVER_NAME', $_SERVER['HTTP_HOST']);
 
 		$admin_dir = $this->ConfigValue('AdminDirectory');
 		if(!$admin_dir) $admin_dir = 'admin';
 		safeDefine('ADMIN_DIR', $admin_dir);
 
 		$this->registerModuleConstants();
 	}
 
 	/**
 	 * Registers each module specific constants if any found
 	 *
 	 */
 	function registerModuleConstants()
 	{
 		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		foreach($unit_config_reader->modules_installed as $module_path)
 		{
 			$contants_file = FULL_PATH.$module_path.'constants.php';
 			if( file_exists($contants_file) ) k4_include_once($contants_file);
 		}
 	}
 
 	function ProcessRequest()
 	{
 		$event_manager =& $this->recallObject('EventManager');
 
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_SHOW_HTTPQUERY') )
 		{
 			global $debugger;
 			$http_query =& $this->recallObject('HTTPQuery');
 			$debugger->appendHTML('HTTPQuery:');
 			$debugger->dumpVars($http_query->_Params);
 		}
 
 		$event_manager->ProcessRequest();
 		$event_manager->RunRegularEvents(reBEFORE);
 		$this->RequestProcessed =  true;
 	}
 
 	/**
 	* Actually runs the parser against current template and stores parsing result
 	*
 	* This method gets t variable passed to the script, loads the template given in t variable and
 	* parses it. The result is store in {@link $this->HTML} property.
 	* @access public
 	* @return void
 	*/
 	function Run()
 	{
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') )
 		{
 			$GLOBALS['debugger']->appendMemoryUsage('Application before Run:');
 		}
 
 		if (!$this->RequestProcessed) $this->ProcessRequest();
 
 		$this->InitParser();
 		$template_cache =& $this->recallObject('TemplatesCache');
 		$t = $this->GetVar('t');
 
 		if(defined('CMS') && CMS)
 		{
 			$cms_handler =& $this->recallObject('cms_EventHandler');
 			if( !$template_cache->TemplateExists($t) )
 			{
 				$t = $cms_handler->GetDesignTemplate();
 			}
 			else
 			{
 				$cms_handler->SetCatByTemplate();
 			}
 		}
 
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') )
 		{
 			$GLOBALS['debugger']->appendMemoryUsage('Application before Parsing:');
 		}
 
 		$this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t), $t );
 
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') )
 		{
 			$GLOBALS['debugger']->appendMemoryUsage('Application after Parsing:');
 		}
 	}
 
 	function InitParser()
 	{
 		if( !is_object($this->Parser) ) $this->Parser =& $this->recallObject('TemplateParser');
 	}
 
 	/**
 	* Send the parser results to browser
 	*
 	* Actually send everything stored in {@link $this->HTML}, to the browser by echoing it.
 	* @access public
 	* @return void
 	*/
 	function Done()
 	{
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') )
 		{
 			$GLOBALS['debugger']->appendMemoryUsage('Application before Done:');
 		}
 
 		if( $this->GetVar('admin') )
 		{
 			$reg = '/('.preg_quote(BASE_PATH, '/').'.*\.html)(#.*){0,1}(")/sU';
 			$this->HTML = preg_replace($reg, "$1?admin=1$2$3", $this->HTML);
 		}
 
 		//eval("?".">".$this->HTML);
 
 		echo $this->HTML;
 		$this->Phrases->UpdateCache();
 
 		flush();
 
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->RunRegularEvents(reAFTER);
 
 		$session =& $this->recallObject('Session');
 		$session->SaveData();
 		//$this->SaveBlocksCache();
 	}
 
 	function SaveBlocksCache()
 	{
 		/*if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			$data = serialize($this->PreParsedCache);
 
 			$this->DB->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("blocks_cache", '.$this->DB->qstr($data).', '.time().')');
 		}*/
 	}
 
 	//	Facade
 
 	/**
 	* Returns current session id (SID)
 	* @access public
 	* @return longint
 	*/
 	function GetSID()
 	{
 		$session =& $this->recallObject('Session');
 		return $session->GetID();
 	}
 
 	function DestroySession()
 	{
 		$session =& $this->recallObject('Session');
 		$session->Destroy();
 	}
 
 	/**
 	* Returns variable passed to the script as GET/POST/COOKIE
 	*
 	* @access public
 	* @param string $var Variable name
 	* @return mixed
 	*/
 	function GetVar($var,$mode=FALSE_ON_NULL)
 	{
 		$http_query =& $this->recallObject('HTTPQuery');
 		return $http_query->Get($var,$mode);
 	}
 
 	/**
 	* Returns ALL variables passed to the script as GET/POST/COOKIE
 	*
 	* @access public
 	* @return array
 	*/
 	function GetVars()
 	{
 		$http_query =& $this->recallObject('HTTPQuery');
 		return $http_query->GetParams();
 	}
 
 	/**
 	* Set the variable 'as it was passed to the script through GET/POST/COOKIE'
 	*
 	* This could be useful to set the variable when you know that
 	* other objects would relay on variable passed from GET/POST/COOKIE
 	* or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br>
 	*
 	* This method is formerly known as $this->Session->SetProperty.
 	* @param string $var Variable name to set
 	* @param mixed $val Variable value
 	* @access public
 	* @return void
 	*/
 	function SetVar($var,$val)
 	{
 		$http_query =& $this->recallObject('HTTPQuery');
 		$http_query->Set($var,$val);
 	}
 
 	/**
 	 * Deletes Session variable
 	 *
 	 * @param string $var
 	 */
 	function RemoveVar($var)
 	{
 		$session =& $this->recallObject('Session');
 		return $session->RemoveVar($var);
 	}
 
 	/**
 	 * Deletes HTTPQuery variable
 	 *
 	 * @param string $var
 	 * @todo think about method name
 	 */
 	function DeleteVar($var)
 	{
 		$http_query =& $this->recallObject('HTTPQuery');
 		return $http_query->Remove($var);
 	}
 
 	/**
 	* Returns session variable value
 	*
 	* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
 	*
 	* @see SimpleSession
 	* @access public
 	* @param string $var Variable name
 	* @param mixed $default Default value to return if no $var variable found in session
 	* @return mixed
 	*/
 	function RecallVar($var,$default=false)
 	{
 		$session =& $this->recallObject('Session');
 		return $session->RecallVar($var,$default);
 	}
 
 	/**
 	* Stores variable $val in session under name $var
 	*
 	* Use this method to store variable in session. Later this variable could be recalled.
 	* @see RecallVar
 	* @access public
 	* @param string $var Variable name
 	* @param mixed $val Variable value
 	*/
 	function StoreVar($var, $val)
 	{
 		$session =& $this->recallObject('Session');
 		$session->StoreVar($var, $val);
 	}
 
 	function StoreVarDefault($var, $val)
 	{
 		$session =& $this->recallObject('Session');
 		$session->StoreVarDefault($var, $val);
 	}
 
 	/**
 	* Links HTTP Query variable with session variable
 	*
 	* If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session.
 	* This method could be used for making sure that GetVar will return query or session value for given
 	* variable, when query variable should overwrite session (and be stored there for later use).<br>
 	* This could be used for passing item's ID into popup with multiple tab -
 	* in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id').
 	* After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session
 	* @access public
 	* @param string $var HTTP Query (GPC) variable name
 	* @param mixed $ses_var Session variable name
 	* @param mixed $default Default variable value
 	*/
 	function LinkVar($var, $ses_var=null, $default='')
 	{
 		if (!isset($ses_var)) $ses_var = $var;
 		if ($this->GetVar($var) !== false)
 		{
 			$this->StoreVar($ses_var, $this->GetVar($var));
 		}
 		else
 		{
 			$this->SetVar($var, $this->RecallVar($ses_var, $default));
 		}
 	}
 
 	/**
 	* Returns variable from HTTP Query, or from session if not passed in HTTP Query
 	*
 	* The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed.
 	* Returns the default value if variable does not exist in session and was not passed in HTTP Query
 	*
 	* @see LinkVar
 	* @access public
 	* @param string $var HTTP Query (GPC) variable name
 	* @param mixed $ses_var Session variable name
 	* @param mixed $default Default variable value
 	* @return mixed
 	*/
 	function GetLinkedVar($var, $ses_var=null, $default='')
 	{
 		if (!isset($ses_var)) $ses_var = $var;
 		$this->LinkVar($var, $ses_var, $default);
 		return $this->GetVar($var);
 	}
 
 	function AddBlock($name, $tpl)
 	{
 		$this->cache[$name] = $tpl;
 	}
 
 	function SetTemplateBody($title,$body)
 	{
 		$templates_cache =& $this->recallObject('TemplatesCache');
 		$templates_cache->SetTemplateBody($title,$body);
 	}
 
 	function ProcessTag($tag_data)
 	{
 		$a_tag = new Tag($tag_data,$this->Parser);
 		return $a_tag->DoProcessTag();
 	}
 
 	function ProcessParsedTag($prefix, $tag, $params)
 	{
 		$a_tag = new Tag('',$this->Parser);
 		$a_tag->Tag = $tag;
 		$a_tag->Processor = $prefix;
 		$a_tag->NamedParams = $params;
 		return $a_tag->DoProcessTag();
 	}
 
 	/**
 	* Return ADODB Connection object
 	*
 	* Returns ADODB Connection object already connected to the project database, configurable in config.php
 	* @access public
 	* @return kDBConnection
 	*/
 	function &GetADODBConnection()
 	{
 		return $this->DB;
 	}
 
 	function ParseBlock($params,$pass_params=0,$as_template=false)
 	{
 		if (substr($params['name'], 0, 5) == 'html:') return substr($params['name'], 6);
 		return $this->Parser->ParseBlock($params, $pass_params, $as_template);
 	}
 
 	/**
 	* Return href for template
 	*
 	* @access public
 	* @param string $t Template path
 	* @var string $prefix index.php prefix - could be blank, 'admin'
 	*/
 	function HREF($t, $prefix='', $params=null, $index_file=null)
 	{
 		global $HTTP_SERVER_VARS;
 		if (defined('ADMIN') && $prefix == '') $prefix='/admin';
 		if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = '';
 		$index_file = isset($index_file) ? $index_file : (defined('INDEX_FILE') ? INDEX_FILE : basename($_SERVER['SCRIPT_NAME']));
 
 		if( isset($params['index_file']) ) $index_file = $params['index_file'];
 
 		$ssl = isset($params['__SSL__']) ? $params['__SSL__'] : null;
 		if ($ssl && PROTOCOL == 'http://') {
 			$session =& $this->recallObject('Session');
 			$cookie_url = $session->CookieDomain.$session->CookiePath;
 			$ssl_url = $this->ConfigValue('SSL_URL');
 
 			if (!preg_match('#'.preg_quote($cookie_url).'#', $ssl_url)) {
 				$session->SetMode(smGET_ONLY);
 			}
 		}
 		unset($params['__SSL__']);
 
 		if (getArrayValue($params, 'opener') == 'u') {
 			$opener_stack=$this->RecallVar('opener_stack');
 			if($opener_stack) {
 				$opener_stack=unserialize($opener_stack);
 				if (count($opener_stack) > 0) {
 					list($index_file, $env) = explode('|', $opener_stack[count($opener_stack)-1]);
 					$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.ENV_VAR_NAME.'='.$env;
 					if( getArrayValue($params,'escape') ) $ret = addslashes($ret);
 					return $ret;
 				}
 				else {
 					//define('DBG_REDIRECT', 1);
 					$t = $this->GetVar('t');
 				}
 			}
 			else {
 				//define('DBG_REDIRECT', 1);
 				$t = $this->GetVar('t');
 			}
 		}
 
 		$pass = isset($params['pass']) ? $params['pass'] : '';
 		$pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
 
 		if (defined('MOD_REWRITE') && MOD_REWRITE) {
 			$env = $this->BuildEnv('', $params, $pass, $pass_events, false);
 			$env = ltrim($env, ':-');
 
 			$session =& $this->recallObject('Session');
 			$sid = $session->NeedQueryString() ? '?sid='.$this->GetSID() : '';
 //			$env = str_replace(':', '/', $env);
 			$ret = rtrim($this->BaseURL($prefix, $ssl).$t.'.html/'.$env.'/'.$sid, '/');
 
 		}
 		else {
 			$env = $this->BuildEnv($t, $params, $pass, $pass_events);
 			$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env;
 		}
 
 		return $ret;
 	}
 
 	function BuildEnv($t, $params, $pass='all', $pass_events=false, $env_var=true)
 	{
 		$session =& $this->recallObject('Session');
 		$sid = $session->NeedQueryString() && !(defined('MOD_REWRITE') && MOD_REWRITE) ? $this->GetSID() : '';
 		if( getArrayValue($params,'admin') == 1 ) $sid = $this->GetSID();
 
 		$ret = '';
 		if ($env_var) {
 			$ret = ENV_VAR_NAME.'=';
 		}
 		$ret .=	defined('INPORTAL_ENV') ? $sid.'-'.$t : $sid.':'.$t;
 
 		$pass = str_replace('all', trim($this->GetVar('passed'), ','), $pass);
 
 		if(strlen($pass) > 0)
 		{
 			$pass_info = array_unique( explode(',',$pass) ); // array( prefix[.special], prefix[.special] ...
 			foreach($pass_info as $pass_element)
 			{
 				$ret.=':';
 				list($prefix)=explode('.',$pass_element);
 				$query_vars = $this->getUnitOption($prefix,'QueryString');
 
 				//if pass events is off and event is not implicity passed
 				if(!$pass_events && !isset($params[$pass_element.'_event'])) {
 					$params[$pass_element.'_event'] = ''; // remove event from url if requested
 					//otherwise it will use value from get_var
 				}
 
 				if($query_vars)
 				{
 					$tmp_string=Array(0=>$pass_element);
 					foreach($query_vars as $index => $var_name)
 					{
 						//if value passed in params use it, otherwise use current from application
 						$tmp_string[$index] =  isset( $params[$pass_element.'_'.$var_name] ) ? $params[$pass_element.'_'.$var_name] : $this->GetVar($pass_element.'_'.$var_name);
 						if ( isset($params[$pass_element.'_'.$var_name]) ) {
 							unset( $params[$pass_element.'_'.$var_name] );
 						}
 					}
 
 					$escaped = array();
 					foreach ($tmp_string as $tmp_val) {
 						$escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val);
 					}
 
 					if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) {
 						$ret.= array_shift($escaped).array_shift($escaped).'-'.implode('-',$escaped);
 					}
 					else {
 						$ret.=implode('-',$escaped);
 					}
 				}
 			}
 		}
 		unset($params['pass']);
 		unset($params['opener']);
 		unset($params['m_event']);
 
 		if ($this->GetVar('admin') && !isset($params['admin'])) {
 			$params['admin'] = 1;
 		}
 
 		if( getArrayValue($params,'escape') )
 		{
 			$ret = addslashes($ret);
 			unset($params['escape']);
 		}
 
 		foreach ($params as $param => $value)
 		{
 			$ret .= '&'.$param.'='.$value;
 		}
 
 		return $ret;
 	}
 
 	function BaseURL($prefix='', $ssl=null)
 	{
 		if ($ssl === null) {
 			return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').BASE_PATH.$prefix.'/';
 		}
 		else {
 			if ($ssl) {
 				if (PROTOCOL == 'http://') {
 					$this->StoreVar('HTTP_SERVER_NAME', SERVER_NAME);
 					$this->StoreVar('HTTP_BASE_PATH', BASE_PATH);
 				}
 				return $this->ConfigValue('SSL_URL').$prefix.'/';
 			}
 			else {
 				return 'http://'.$this->RecallVar('HTTP_SERVER_NAME').(defined('PORT')?':'.PORT : '').$this->RecallVar('HTTP_BASE_PATH').$prefix.'/';
 			}
 		}
 	}
 
 	function Redirect($t='', $params=null, $prefix='', $index_file=null)
 	{
 		if ($t == '' || $t === true) $t = $this->GetVar('t');
 
 		// pass prefixes and special from previous url
 		if (!isset($params['pass'])) $params['pass'] = 'all';
 
 		$location = $this->HREF($t, $prefix, $params, $index_file);
 		$a_location = $location;
 		$location = "Location: $location";
 		//echo " location : $location <br>";
 
 
 		if( $this->isDebugMode() && dbg_ConstOn('DBG_REDIRECT') )
 		{
 			$GLOBALS['debugger']->appendTrace();
 			echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>";
 		}
 		else
 		{
 			if(headers_sent() != '')
 			{
 				echo '<script language="javascript" type="text/javascript">window.location.href = \''.$a_location.'\';</script>';
 			}
 			else
 			{
 				header("$location");
 			}
 		}
 
 		$session =& $this->recallObject('Session');
 		$session->SaveData();
 		$this->SaveBlocksCache();
 		exit;
 	}
 
 	function Phrase($label)
 	{
 		return $this->Phrases->GetPhrase($label);
 	}
 
 	/**
 	 * Replace language tags in exclamation marks found in text
 	 *
 	 * @param string $text
 	 * @param bool $force_escape force escaping, not escaping of resulting string
 	 * @return string
 	 * @access public
 	 */
 	function ReplaceLanguageTags($text, $force_escape=null)
 	{
 		return $this->Phrases->ReplaceLanguageTags($text,$force_escape);
 	}
 
 	/**
 	 * Validtates user in session if required
 	 *
 	 */
 	function ValidateLogin()
 	{
 		if (defined('LOGIN_REQUIRED'))
 		{
 			// Original Kostja call
 			//$login_controller =& $this->Factory->MakeClass(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login'));
 
 			// Call proposed by Alex
 			//$login_controller =& $this->RecallObject(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login'));
 
 			//$login_controller->CheckLogin();
 		}
 	}
 
 	/**
 	 * Returns configuration option value by name
 	 *
 	 * @param string $name
 	 * @return string
 	 */
 	function ConfigValue($name)
 	{
 		return $this->DB->GetOne('SELECT VariableValue FROM '.TABLE_PREFIX.'ConfigurationValues WHERE VariableName = '.$this->DB->qstr($name) );
 	}
 
 	/**
 	 * Allows to process any type of event
 	 *
 	 * @param kEvent $event
 	 * @access public
 	 * @author Alex
 	 */
 	function HandleEvent(&$event, $params=null, $specificParams=null)
 	{
 		if ( isset($params) ) {
 			$event = new kEvent( $params, $specificParams );
 		}
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->HandleEvent($event);
 	}
 
 	/**
 	 * Registers new class in the factory
 	 *
 	 * @param string $real_class Real name of class as in class declaration
 	 * @param string $file Filename in what $real_class is declared
 	 * @param string $pseudo_class Name under this class object will be accessed using getObject method
 	 * @param Array $dependecies List of classes required for this class functioning
 	 * @access public
 	 * @author Alex
 	 */
 	function registerClass($real_class, $file, $pseudo_class = null, $dependecies = Array() )
 	{
 		$this->Factory->registerClass($real_class, $file, $pseudo_class, $dependecies);
 	}
 
 	/**
 	 * Add $class_name to required classes list for $depended_class class.
 	 * All required class files are included before $depended_class file is included
 	 *
 	 * @param string $depended_class
 	 * @param string $class_name
 	 * @author Alex
 	 */
 	function registerDependency($depended_class, $class_name)
 	{
 		$this->Factory->registerDependency($depended_class, $class_name);
 	}
 
 	/**
 	 * Registers Hook from subprefix event to master prefix event
 	 *
 	 * @param string $hookto_prefix
 	 * @param string $hookto_special
 	 * @param string $hookto_event
 	 * @param string $mode
 	 * @param string $do_prefix
 	 * @param string $do_special
 	 * @param string $do_event
 	 * @param string $conditional
 	 * @access public
 	 * @todo take care of a lot parameters passed
 	 * @author Kostja
 	 */
 	function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional);
 	}
 
 	/**
 	 * Allows one TagProcessor tag act as other TagProcessor tag
 	 *
 	 * @param Array $tag_info
 	 * @author Kostja
 	 */
 	function registerAggregateTag($tag_info)
 	{
 		$aggregator =& $this->recallObject('TagsAggregator', 'kArray');
 		$aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial')));
 	}
 
 	/**
 	 * Returns object using params specified,
 	 * creates it if is required
 	 *
 	 * @param string $name
 	 * @param string $pseudo_class
 	 * @param Array $event_params
 	 * @return Object
 	 * @author Alex
 	 */
 	function &recallObject($name,$pseudo_class=null,$event_params=Array())
 	{
 		$func_args = func_get_args();
 		$result =& ref_call_user_func_array( Array(&$this->Factory, 'getObject'), $func_args );
 		return $result;
 	}
 
 	/**
 	 * Checks if object with prefix passes was already created in factory
 	 *
 	 * @param string $name object presudo_class, prefix
 	 * @return bool
 	 * @author Kostja
 	 */
 	function hasObject($name)
 	{
 		return isset($this->Factory->Storage[$name]);
 	}
 
 	/**
 	 * Removes object from storage by given name
 	 *
 	 * @param string $name Object's name in the Storage
 	 * @author Kostja
 	 */
 	function removeObject($name)
 	{
 		$this->Factory->DestroyObject($name);
 	}
 
 	/**
 	 * Get's real class name for pseudo class,
 	 * includes class file and creates class
 	 * instance
 	 *
 	 * @param string $pseudo_class
 	 * @return Object
 	 * @access public
 	 * @author Alex
 	 */
 	function &makeClass($pseudo_class)
 	{
 		$func_args = func_get_args();
 		$result =& ref_call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args);
 
 		return $result;
 	}
 
 	/**
 	 * Checks if application is in debug mode
 	 *
 	 * @return bool
 	 * @access public
 	 * @author Alex
 	 */
 	function isDebugMode()
 	{
-		return defined('DEBUG_MODE') && DEBUG_MODE;
+		return defined('DEBUG_MODE') && DEBUG_MODE && is_object($this->Debugger);
 	}
 
 	/**
 	 * Checks if it is admin
 	 *
 	 * @return bool
 	 * @author Alex
 	 */
 	function IsAdmin()
 	{
 		return defined('ADMIN') && ADMIN;
 	}
 
 	/**
 	 * Reads unit (specified by $prefix)
 	 * option specified by $option
 	 *
 	 * @param string $prefix
 	 * @param string $option
 	 * @return string
 	 * @access public
 	 * @author Alex
 	 */
 	function getUnitOption($prefix,$option)
 	{
 		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $unit_config_reader->getUnitOption($prefix,$option);
 	}
 
 	/**
 	 * Set's new unit option value
 	 *
 	 * @param string $prefix
 	 * @param string $name
 	 * @param string $value
 	 * @author Alex
 	 * @access public
 	 */
 	function setUnitOption($prefix,$option,$value)
 	{
 		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $unit_config_reader->setUnitOption($prefix,$option,$value);
 	}
 
 	/**
 	 * Read all unit with $prefix options
 	 *
 	 * @param string $prefix
 	 * @return Array
 	 * @access public
 	 * @author Alex
 	 */
 	function getUnitOptions($prefix)
 	{
 		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $unit_config_reader->getUnitOptions($prefix);
 	}
 
 	/**
 	 * Returns true if config exists and is allowed for reading
 	 *
 	 * @param string $prefix
 	 * @return bool
 	 */
 	function prefixRegistred($prefix)
 	{
 		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $unit_config_reader->prefixRegistred($prefix);
 	}
 
 	/**
 	 * Splits any mixing of prefix and
 	 * special into correct ones
 	 *
 	 * @param string $prefix_special
 	 * @return Array
 	 * @access public
 	 * @author Alex
 	 */
 	function processPrefix($prefix_special)
 	{
 		return $this->Factory->processPrefix($prefix_special);
 	}
 
 	/**
 	 * Set's new event for $prefix_special
 	 * passed
 	 *
 	 * @param string $prefix_special
 	 * @param string $event_name
 	 * @access public
 	 */
 	function setEvent($prefix_special,$event_name)
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->setEvent($prefix_special,$event_name);
 	}
 
 
 	/**
 	 * SQL Error Handler
 	 *
 	 * @param int $code
 	 * @param string $msg
 	 * @param string $sql
 	 * @return bool
 	 * @access private
 	 * @author Alex
 	 */
 	function handleSQLError($code,$msg,$sql)
 	{
 		global $debugger;
 		if($debugger)
 		{
 			$errorLevel=defined('DBG_SQL_FAILURE') && DBG_SQL_FAILURE ? E_USER_ERROR : E_USER_WARNING;
 			$debugger->dumpVars($_REQUEST);
 			$debugger->appendTrace();
 
 			$error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$debugger->formatSQL($sql);
 			$long_id=$debugger->mapLongError($error_msg);
 			trigger_error( substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel);
 			return true;
 		}
 		else
 		{
 			//$errorLevel = defined('IS_INSTALL') && IS_INSTALL ? E_USER_WARNING : E_USER_ERROR;
 			$errorLevel = E_USER_WARNING;
 			trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel);
 			/*echo '<b>xProcessing SQL</b>: '.$sql.'<br>';
 			echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/
 			return $errorLevel == E_USER_ERROR ? false : true;
 		}
 	}
 
 	/**
 	 * Default error handler
 	 *
 	 * @param int $errno
 	 * @param string $errstr
 	 * @param string $errfile
 	 * @param int $errline
 	 * @param Array $errcontext
 	 */
 	function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
 	{
 		if( defined('SILENT_LOG') && SILENT_LOG )
 		{
 			$fp = fopen(FULL_PATH.'/silent_log.txt','a');
 			$time = date('d/m/Y H:i:s');
 			fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n");
 			fclose($fp);
 		}
 
 		if( !$this->errorHandlers ) return true;
 
 		$i = 0; // while (not foreach) because it is array of references in some cases
 		$eh_count = count($this->errorHandlers);
 		while($i < $eh_count)
 		{
 			if( is_array($this->errorHandlers[$i]) )
 			{
 				$object =& $this->errorHandlers[$i][0];
 				$method = $this->errorHandlers[$i][1];
 				$object->$method($errno, $errstr, $errfile, $errline, $errcontext);
 			}
 			else
 			{
 				$function = $this->errorHandlers[$i];
 				$function($errno, $errstr, $errfile, $errline, $errcontext);
 			}
 			$i++;
 		}
 	}
 
 	/**
 	 * Returns & blocks next ResourceId available in system
 	 *
 	 * @return int
 	 * @access public
 	 * @author Eduard
 	 */
 	function NextResourceId()
 	{
 		$this->DB->Query('LOCK TABLES '.TABLE_PREFIX.'IdGenerator WRITE');
 		$this->DB->Query('UPDATE '.TABLE_PREFIX.'IdGenerator SET lastid = lastid+1');
 		$id = $this->DB->GetOne("SELECT lastid FROM ".TABLE_PREFIX."IdGenerator");
 		$this->DB->Query('UNLOCK TABLES');
 		return $id;
 	}
 
 	/**
 	 * Returns main prefix for subtable prefix passes
 	 *
 	 * @param string $current_prefix
 	 * @return string
 	 * @access public
 	 * @author Kostja
 	 */
 	function GetTopmostPrefix($current_prefix)
 	{
 		while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') )
 		{
 			$current_prefix = $parent_prefix;
 		}
 		return $current_prefix;
 	}
 
 	function EmailEventAdmin($email_event_name, $to_user_id = -1, $send_params = false)
 	{
 		return $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params);
 	}
 
 	function EmailEventUser($email_event_name, $to_user_id = -1, $send_params = false)
 	{
 		return $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params);
 	}
 
 	function EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false)
 	{
 		$event = new kEvent('emailevents:OnEmailEvent');
 		$event->setEventParam('EmailEventName', $email_event_name);
 		$event->setEventParam('EmailEventToUserId', $to_user_id);
 		$event->setEventParam('EmailEventType', $email_event_type);
 		if ($send_params){
 			$event->setEventParam('DirectSendParams', $send_params);
 		}
 		$this->HandleEvent($event);
 
 		return $event;
 	}
 
 
 	function LoggedIn()
 	{
 		$user =& $this->recallObject('u');
 		return ($user->GetDBField('PortalUserId') > 0);
 	}
 
 	function CheckPermission($name, $cat_id = null)
 	{
 		if( !isset($cat_id) )
 		{
 			$cat_id = $this->GetVar('m_cat_id');
 		}
 		if( $cat_id == 0 )
 		{
 			$cat_hierarchy = Array(0);
 		}
 		else
 		{
 			$sql = 'SELECT ParentPath FROM '.$this->getUnitOption('c', 'TableName').' WHERE CategoryId = '.$cat_id;
 			$cat_hierarchy = $this->DB->GetOne($sql);
 			$cat_hierarchy = explode('|', $cat_hierarchy);
 			array_shift($cat_hierarchy);
 			array_pop($cat_hierarchy);
 			$cat_hierarchy = array_reverse($cat_hierarchy);
 			array_push($cat_hierarchy, 0);
 		}
 
 		$groups = $this->RecallVar('UserGroups');
 
 		foreach($cat_hierarchy as $category_id)
 		{
 			$sql = 'SELECT PermissionValue FROM '.TABLE_PREFIX.'Permissions
 					WHERE Permission = "'.$name.'"
 					AND CatId = '.$category_id.'
 					AND GroupId IN ('.$groups.')';
 			$res = $this->DB->GetOne($sql);
 			if($res !== false)
 			{
 				return $res;
 			}
 		}
 
 		return 0;
 	}
 
 	/**
 	 * Set's any field of current visit
 	 *
 	 * @param string $field
 	 * @param mixed $value
 	 */
 	function setVisitField($field, $value)
 	{
 		$visit =& $this->recallObject('visits');
 		$visit->SetDBField($field, $value);
 		$visit->Update();
 	}
 
 }
 
 ?>
\ No newline at end of file

Property changes on: trunk/core/kernel/application.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.56
\ No newline at end of property
+1.57
\ No newline at end of property
Index: trunk/core/kernel/parser/template_parser.php
===================================================================
--- trunk/core/kernel/parser/template_parser.php	(revision 2677)
+++ trunk/core/kernel/parser/template_parser.php	(revision 2678)
@@ -1,535 +1,537 @@
 <?php
 
 k4_include_once(KERNEL_PATH.'/parser/tags.php');
 k4_include_once(KERNEL_PATH.'/parser/construct_tags.php');
 
 class TemplateParser extends kBase {
 	var $Template;
 	var $Output = '';
 	var $Position = 0;
 	var $LastPosition = 0;
 
 	var $Ses;
 	var $Recursion = Array();
 	var $RecursionIndex = 0;
 	var $SkipMode = 0;
 	var $Params = Array();
 	var $Pattern = Array();
 	var $ForSort = Array();
 	var $Values = Array();
 	var $Buffers = Array();
 	var $Args;
 
 	var $ParamsRecursionIndex = 0;
 	var $ParamsStack = Array();
 
 	var $CompiledBuffer;
 
 	var $DataExists = false;
 
 	function TemplateParser()
 	{
 		parent::kBase();
 		$this->Ses =& $this->Application->recallObject('Session');
 	}
 
 	function AddParam($pattern, $value, $dont_sort=0)
 	{
 		$this->ForSort[] = Array($pattern, $value);
 		if (!$dont_sort) //used when mass-adding params, to escape sorting after every new param
 			$this->SortParams(); //but do sort by default!
 	}
 
 	//We need to sort params by its name length desc, so that params starting with same word get parsed correctly
 	function SortParams()
 	{
 		uasort($this->ForSort, array ("TemplateParser", "CmpParams"));
 		$this->Pattern = Array();
 		$this->Values = Array();
 		foreach($this->ForSort as $pair)
 		{
 			$this->Pattern[] = $pair[0];
 			$this->Values[] = $pair[1];
 		}
 	}
 
 	function CmpParams($a, $b)
 	{
 		$a_len = strlen($a[0]);
 		$b_len = strlen($b[0]);
 		if ($a_len == $b_len) return 0;
 		return $a_len > $b_len ? -1 : 1;
 	}
 
 	function SetParams($params)
 	{
 		if (!is_array($params)) $params = Array();
 		$this->Params = $params;
 		foreach ($params as $key => $val) {
 			$this->AddParam('/[{]{0,1}\$'.$key.'[}]{0,1}/i', $val, 1); //Do not sort every time
 		}
 		$this->SortParams(); //Sort once after adding is done
 	}
 
 	function GetParam($name)
 	{
 		//return isset($this->Params[strtolower($name)]) ? $this->Params[strtolower($name)] : false;
 		return isset($this->Params[$name]) ? $this->Params[$name] : false;
 	}
 
 	function SetParam($name, $value)
 	{
 		$this->Params[strtolower($name)] = $value;
 	}
 
 	function SetBuffer($body)
 	{
 		$this->Buffers[$this->RecursionIndex] = $body;
 	}
 
 	function GetBuffer()
 	{
 		return $this->Buffers[$this->RecursionIndex];
 	}
 
 	function GetCode()
 	{
 		return $this->Code[$this->RecursionIndex];
 	}
 
 	function AppendBuffer($append)
 	{
 		$this->Buffers[$this->RecursionIndex] .= $append;
 		$this->AppendCode( $this->ConvertToCode($append) );
 	}
 
 	function AppendOutput($append, $append_code=false)
 	{
 		if ($this->SkipMode == parse) {
 			$this->Output .= $append; //append to Ouput only if we are parsing
 			if ($append_code) $this->AppendCompiledHTML($append);
 		}
 		elseif ($this->SkipMode == skip) {
 			if ($append_code) $this->AppendCompiledHTML($append);
 		}
 		elseif ($this->SkipMode == skip_tags) {
 			$this->AppendBuffer($append); //append to buffer if we are skipping tags
 		}
 	}
 
 	function ConvertToCode($data)
 	{
 		$code = '$o .= \''. str_replace("'", "\'", $data) .'\';';
 		$code = explode("\n", $code);
 		return $code;
 	}
 
 	function AppendCode($code)
 	{
 		if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			if (!isset($this->Code[$this->RecursionIndex])) {
 				$this->Code[$this->RecursionIndex] = Array();
 			}
 			if (is_array($code)) {
 				foreach ($code as $line) {
 					$this->Code[$this->RecursionIndex][] = rtrim($line, "\n")."\n";
 				}
 			}
 			else {
 				$this->Code[$this->RecursionIndex][] .= rtrim($code, "\n")."\n";
 			}
 		}
 	}
 
 	function AppendCompiledFunction($f_name, $f_body)
 	{
 		$real_name = 'f_'.abs(crc32($this->TemplateName)).'_'.$f_name;
 		if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			// if such function already compiled
 			if ( isset($this->Application->CompiledFunctions[$f_name]) ||
 						function_exists($real_name)
 					)
 			{
 				if (!isset($this->Application->CompiledFunctions[$f_name])) {
 					$real_name = $real_name.'_';
 				}
 				else {
 					$real_name = $this->Application->CompiledFunctions[$f_name].'_';
 				}
 			}
 
 			$this->CompiledBuffer .= 'if (!function_exists(\''.$real_name.'\')) {'."\n";
 
 
 			$this->CompiledBuffer .= "\t".'$application->PreParsedBlocks[\''.$f_name.'\'] = \''.$real_name.'\';';
 			$this->CompiledBuffer .= "\n\t".'function '.$real_name.'($params)'."\n\t{\n";
 			$this->CompiledBuffer .= $f_body;
 			$this->CompiledBuffer .= "\t}\n\n";
 
 			$this->CompiledBuffer .= '}'."\n";
 
 			$this->Application->CompiledFunctions[$f_name] = $real_name;
 
 		}
 	}
 
 	function AppendCompiledCode($code)
 	{
 		if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			if (is_array($code)) {
 				foreach ($code as $line) {
 					$this->CompiledBuffer .= "\t".rtrim($line, "\n")."\n";
 				}
 			}
 			else {
 				$this->CompiledBuffer .= $code;
 			}
 			$this->CompiledBuffer .= "\t".'echo $o;'."\n\t".'$o = \'\';'."\n";
 		}
 	}
 
 	function AppendCompiledHTML($append)
 	{
 		if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			$this->CompiledBuffer .= '?'.'>'."\n";
 			$this->CompiledBuffer .= rtrim($append, "\t");
 			$this->CompiledBuffer .= '<'.'?php'."\n";
 		}
 	}
 
 	function ResetCode()
 	{
 		$this->Code[$this->RecursionIndex] = Array();
 	}
 
 	function FindTag2()
 	{
 		$openings = Array('<%' => '%>', '<inp2:' => Array('>', '/>'), '</inp2:' => '>', '</inp2>' => '');
 
 		$tag_open_pos = false;
 		foreach ($openings as $an_opening => $closings) {
 			$pos = strpos($this->Template, $an_opening, $this->Position);
 			if ($pos !== false && ($tag_open_pos === false || (int) $pos <= (int) $tag_open_pos)) {
 				$tag_open_pos = $pos;
 				$open_len = strlen($an_opening);
 				$opening_tag = $an_opening;
 				$tag_closings = $closings;
 			}
 		}
 
 		if ($tag_open_pos === false) { //If no tags left - adding all other data
 			$this->AppendOutput(substr($this->Template, $this->Position), true);
 			return false;
 		}
 
 		//Adding all data before tag open
 		$this->AppendOutput(substr($this->Template, $this->Position, $tag_open_pos - $this->Position), true);
 
 
 		if (is_array($tag_closings)) {
 			$tag_close_pos = false;
 			foreach ($tag_closings as $a_closing) {
 				$pos = strpos($this->Template, $a_closing, $tag_open_pos);
 				if ($pos !== false && ($tag_close_pos === false || (int) $pos <= (int) $tag_close_pos)) {
 					$tag_close_pos = $pos;
 					$closing_tag = $a_closing;
 				}
 			}
 		}
 		elseif ($opening_tag == '</inp2>') {
 			$closing_tag = '';
 			$tag_close_pos = $tag_open_pos + $open_len;
 		}
 		else {
 			$closing_tag = $tag_closings;
 			$tag_close_pos = strpos($this->Template, $closing_tag, $tag_open_pos);
 		}
 		$close_len = strlen($closing_tag);
 
 		//Cutting out the tag itself
 		$tag = substr($this->Template, $tag_open_pos + $open_len, $tag_close_pos - $tag_open_pos - $open_len);
 
 
 		if ($opening_tag == '<inp2:') {
 			//getting prefix_tag upto first space, tab or line break into regs[1]
 			preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs);
 			$tag_part = $regs[1];
 			if (strpos($tag_part, '_') !== false) {
 				list($prefix, $the_tag) = explode('_', $tag, 2);
 				$tag = $prefix.':'.$the_tag;
 			}
 			else {
 				$the_tag = $tag;
 				$tag = ':'.$tag;
 			}
 		}
 
 		if ($opening_tag == '</inp2>') { //empty closing means old style in-portal if <inp2:tag>....</inp2>
 			$tag = 'm:endif';
 		}
 
 		if ($opening_tag == '</inp2:') {
 			preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs);
 			$tag_part = $regs[1];
 			if (strpos($tag_part, '_') !== false) {
 				list($prefix, $the_tag) = explode('_', $tag, 2);
 				$tag = $prefix.':'.$the_tag;
 			}
 			$tag .= ' _closing_tag_="1"';
 		}
 
 		// if there is no prefix for the tag
 		if (strpos($tag, ':') === 0) {
 			$prefix = getArrayValue($this->Params, 'PrefixSpecial');
 			$tag = $prefix.$tag;
 		}
 
 		// temporary - for backward compatability with in-portal style if
 		if ($opening_tag == '<inp2:' && $closing_tag == '>' && $tag_part != 'm_if' && $tag_part != 'm_DefineElement') {
 			if (strpos($the_tag, ' ') !== false) {
 				list($function, $params) = explode(' ', $the_tag, 2);
 			}
 			else {
 				$function = $the_tag;
 				$params = '';
 			}
 			$tag = 'm:if prefix="'.$prefix.'" function="'.$function.'" '.$params;
 		}
 
 		$this->Position = $tag_close_pos + $close_len;
 		return $tag;
 	}
 
 	function CurrentLineNumber()
 	{
 		return substr_count(substr($this->Template, 0, $this->Position), "\n")+1;
 	}
 
 	function SkipModeName()
 	{
 		switch ($this->SkipMode) {
 			case skip: return 'skip';
 			case skip_tags: return 'skip_tags';
 			case parse: return 'parse';
 		}
 	}
 
 	function CheckDir($dir)
 	{
 		if (file_exists($dir)) {
 			return;
 		}
 		else {
 			$segments = explode('/', $dir);
 			$cur_path = '';
 			foreach ($segments as $segment) {
 				$cur_path .= '/'.$segment;
 				if (!file_exists($cur_path)) {
 					mkdir($cur_path);
 				}
 			}
 		}
 	}
 
 	function Parse($template, $name='unknown', $pre_parse = 1)
 	{
 		$this->Template = $template;
 		$this->TemplateName = $name;
 		$this->Position = 0;
 		$this->Output = '';
 		$this->TagHolder = new MyTagHolder();
 
 		$has_inp_tags = false;
 
 		if ($this->GetParam('from_inportal')) $pre_parse = 0;
 
 		if (defined('EXPERIMENTAL_PRE_PARSE') && $pre_parse) {
 			$template_cache =& $this->Application->recallObject('TemplatesCache');
 			$fname = $template_cache->GetRealFilename($this->TemplateName).'.php';
 
 			$fname = str_replace(FULL_PATH, FULL_PATH.'/kernel/cache', $fname);
 
 			if (!defined('SAFE_MODE') || !SAFE_MODE) {
 				$this->CheckDir(dirname($fname));
 			}
 
 			$tname = $template_cache->GetRealFilename($this->TemplateName).'.tpl';
 			$output = '';
 			$is_cached = false;
 			ob_start();
 			if (defined('SAFE_MODE') && SAFE_MODE) {
 				$conn =& $this->Application->GetADODBConnection();
 				$cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$fname.'"');
 				if ($cached !== false && $cached['Cached'] > filemtime($tname)) {
 					eval('?'.'>'.$cached['Data'].'<'.'?');
 					$is_cached = true;
 				}
 			}
 			else {
 				if (file_exists($fname) && filemtime($fname) > filemtime($tname)) {
 					include($fname);
 					$is_cached = true;
 				}
 			}
 			$output = ob_get_contents();
 			ob_end_clean();
 
 			if ( $is_cached && !$this->GetParam('from_inportal') ) {
 				if ( strpos($output, '<inp:') !== false) {
 					$inp1_parser =& $this->Application->recallObject('Inp1Parser');
 					$output = $inp1_parser->Parse($name, $output);
 				}
 				return $output;
 			}
 
 			$this->CompiledBuffer .= '<'.'?php'."\n";
 			$this->CompiledBuffer .= 'global $application;'."\n";
 			$this->CompiledBuffer .= '$o = \'\';'."\n";
 		}
 
 		if (!getArrayValue($this->Params, 'PrefixSpecial')) {
 			$this->Params['PrefixSpecial'] = '$PrefixSpecial';
 		}
 
 		//While we have more tags
 		while ($tag_data = $this->FindTag2())
 		{
 			//Create tag object from passed tag data
 			if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
 			{
 				global $debugger;
 				$debugger->appendHTML('mode: '.$this->SkipModeName().' tag '.$debugger->highlightString($tag_data).' in '.$debugger->getFileLink($debugger->getLocalFile(FULL_PATH.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
 			}
 //				$tag =& new MyTag($tag_data, $this);
 			$tag =& $this->TagHolder->GetTag($tag_data, $this);
 
 			if (!$this->CheckRecursion($tag)) //we do NOT process closing tags
 			{
 				$tag->Process();
 			}
 		}
 
 		if ( !$this->GetParam('from_inportal') ) {
 			if ( strpos($this->Output, '<inp:') !== false) {
 				$inp1_parser =& $this->Application->recallObject('Inp1Parser');
 				$this->Output = $inp1_parser->Parse($name, $this->Output);
 				$has_inp_tags = true;
 			}
 		}
 
 
 		if (defined('EXPERIMENTAL_PRE_PARSE') && $pre_parse && !$has_inp_tags) {
 //			$this->CompiledBuffer .= 'echo $o;'."\n";
 			$this->CompiledBuffer .= '?'.'>'."\n";
 
 			if (defined('SAFE_MODE') && SAFE_MODE) {
 				if (!isset($conn)) $conn =& $this->Application->GetADODBConnection();
 				$conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ('.$conn->qstr($fname).','.$conn->qstr(str_replace('<'.'?php','<'.'?',$this->CompiledBuffer)).','.mktime().')');
 			}
 			else {
 				$compiled = fopen($fname, 'w');
 				fwrite($compiled, $this->CompiledBuffer);
 				fclose($compiled);
 			}
 		}
 
 		return $this->Output;
 	}
 
 	function ParseBlock($params, $force_pass_params=0, $as_template=false)
 	{
 		if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
 		{
 			global $debugger;
 			$debugger->appendHTML('ParseBlock '.$params['name'].' pass_params is '.$params['pass_params'].' force is '.$force_pass_params.' in '.$debugger->getFileLink($debugger->getLocalFile(FULL_PATH.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
 
 		}
 		/*if ( $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRE_PARSE') ) {
 			global $debugger;
 			$debugger->CurrentPreParsedBlock = $params['name'];
 		}*/
 		if (defined('EXPERIMENTAL_PRE_PARSE')) {
 			$this->MainParser = false;
 			if (isset($this->Application->PreParsedBlocks[$params['name']]) ) {
 
 				if ($this->ParamsRecursionIndex == 0) {
 					$this->ParamsStack[$this->ParamsRecursionIndex] = $this->Params;
 				}
 
 				if (isset($params['pass_params']) || $force_pass_params) {
 					$pass_params = array_merge($this->ParamsStack[$this->ParamsRecursionIndex], $params);
 				}
 				else {
 					$pass_params = $params;
 				}
 
 				$this->ParamsStack[++$this->ParamsRecursionIndex] = $pass_params;
 				$this->Params = $pass_params;
 
 				$f = $this->Application->PreParsedBlocks[$params['name']];
 
 //					$this->ParamsRecursionIndex--;
 
 				//$this->SetParams($params);
+				if( !isset($pass_params['PrefixSpecial']) ) $pass_params['PrefixSpecial'] = $pass_params['prefix'];
+				
 				$ret = $f($pass_params);
 
 				unset($this->ParamsStack[$this->ParamsRecursionIndex--]);
 				$this->Params = $this->ParamsStack[$this->ParamsRecursionIndex];
 				$this->MainParser = true;
 				return $ret;
 			}
 		}
 
 		$BlockParser =& $this->Application->makeClass('TemplateParser');
 		if (isset($params['pass_params']) || $force_pass_params) {
 			$BlockParser->SetParams(array_merge($this->Params, $params));
 		}
 		else
 			$BlockParser->SetParams($params);
 		$this->Application->Parser =& $BlockParser;
 		if (!isset($params['name'])) trigger_error('<b>***Error: Block name not passed to ParseBlock</b>', E_USER_ERROR);
 		$templates_cache =& $this->Application->recallObject('TemplatesCache');
 
 		$template_name = $as_template ? $params['name'] : $templates_cache->GetTemplateFileName($params['name']) . '-block:'.$params['name'];
 
 		$silent = getArrayValue($params, 'from_inportal') && !defined('DBG_TEMPLATE_FAILURE');
 
 		$o = $BlockParser->Parse(
 				$templates_cache->GetTemplateBody($params['name'], $silent),
 				$template_name
 			);
 		if (getArrayValue($params, 'BlockNoData') && !$BlockParser->DataExists) {
 			$template_name = $as_template ? $params['BlockNoData'] : $templates_cache->GetTemplateFileName($params['BlockNoData']) . '-block:'.$params['BlockNoData'];
 			$o = $BlockParser->Parse(
 				$templates_cache->GetTemplateBody($params['BlockNoData'], $silent),
 				$template_name
 			);
 		}
 		$this->Application->Parser =& $this;
 		$this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists;
 		return $o;
 	}
 
 	function Recurve(&$tag)
 	{
 		$this->Recursion[++$this->RecursionIndex] =& $tag;
 	}
 
 	function CheckRecursion(&$tag)
 	{
 		if ($this->RecursionIndex > 0) { //If we are inside the recursion
 			if ($this->Recursion[$this->RecursionIndex]->CheckRecursion($tag)) { //If we can close this recursion
 				unset($this->Recursion[$this->RecursionIndex--]); //unsetting current recursion level and decreasing it at the same time
 				return true; //we should inform not to process closing tag
 			}
 		}
 		return false;
 	}
 
 	function SetSkipMode($mode)
 	{
 		$this->SkipMode = $mode;
 	}
 }
 
 ?>
\ No newline at end of file

Property changes on: trunk/core/kernel/parser/template_parser.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.12
\ No newline at end of property
+1.13
\ No newline at end of property