Index: branches/5.1.x/core/kernel/utility/debugger.php
===================================================================
--- branches/5.1.x/core/kernel/utility/debugger.php	(revision 13988)
+++ branches/5.1.x/core/kernel/utility/debugger.php	(revision 13989)
@@ -1,1526 +1,1526 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	if( !class_exists('Debugger') ) {
 
 		class Debugger {
 
 			/**
 			* Holds reference to global KernelApplication instance
 			*
 			* @access public
 			* @var kApplication
 			*/
 			var $Application = null;
 
 			/**
 			 * Set to true if fatal error occured
 			 *
 			 * @var bool
 			 */
 			var $IsFatalError = false;
 
 			/**
 			 * Counts warnings on the page
 			 *
 			 * @var int
 			 */
 			var $WarningCount = 0;
 
 			/**
 			 * Allows to track compile errors, like "stack-overflow"
 			 *
 			 * @var bool
 			 */
 			var $_compileError = false;
 
 			/**
 			 * Debugger data for building report
 			 *
 			 * @var Array
 			 */
 			var $Data = Array();
 
 			var $ProfilerData = Array();
 			var $ProfilerTotals = Array();
 			var $ProfilerTotalCount = Array();
 
 			var $ProfilePoints = Array();
 
 			/**
 			 * Prevent recursion when processing debug_backtrace() function results
 			 *
 			 * @var Array
 			 */
 			var $RecursionStack = Array();
 
 			var $scrollbarWidth = 0;
 
 			/**
 			 * Long errors are saved here, because trigger_error doesn't support error messages over 1KB in size
 			 *
 			 * @var Array
 			 */
 			var $longErrors = Array();
 
 			var $IncludesData = Array();
 			var $IncludeLevel = 0;
 
 			var $reportDone = false;
 
 			/**
 			 * Transparent spacer image used in case of none spacer image defined via SPACER_URL contant.
 			 * Used while drawing progress bars (memory usage, time usage, etc.)
 			 *
 			 * @var string
 			 */
 			var $dummyImage = '';
 
 			/**
 			 * Temporary files created by debugger will be stored here
 			 *
 			 * @var string
 			 */
 			var $tempFolder = '';
 
 			/**
 			 * Debug rows will be separated using this string before writing to debug file
 			 *
 			 * @var string
 			 */
 			var $rowSeparator = '@@';
 
 			/**
 			 * Base URL for debugger includes
 			 *
 			 * @var string
 			 */
 			var $baseURL = '';
 
 			/**
 			 * Holds last recorded timestamp (for appendTimestamp)
 			 *
 			 * @var int
 			 */
 			var $LastMoment;
 
 			/**
 			 * Determines, that current request is AJAX request
 			 *
 			 * @var bool
 			 */
 			var $_isAjax = false;
 
 			function Debugger()
 			{
 				global $start, $dbg_options;
 				// check if user haven't defined DEBUG_MODE contant directly
 				if (defined('DEBUG_MODE') && DEBUG_MODE) {
 					die('error: contant DEBUG_MODE defined directly, please use <strong>$dbg_options</strong> array instead');
 				}
 
 				// check IP before enabling debug mode
 				$ip_match =  $this->ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : '');
 
 				if (!$ip_match) {
 					define('DEBUG_MODE', 0);
 					return ;
 				}
 
 				// debug is allowed for user, continue initialization
 				$this->InitDebugger();
 				$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start);
 				$this->profileStart('script_runtime', 'Script runtime', $start);
 				$this->LastMoment = $start;
 
 				error_reporting(E_ALL);
 				ini_set('display_errors', $this->constOn('DBG_ZEND_PRESENT') ? 0 : 1);	// show errors on screen in case if not in Zend Studio debugging
 
 				$this->scrollbarWidth = $this->isGecko() ? 22 : 25;					// vertical scrollbar width differs in Firefox and other browsers
 				$this->appendRequest();
 			}
 
 			/**
 			 * Checks, that user IP address is within allowed range
 			 *
 			 * @param string $ip_list semi-column (by default) separated ip address list
 			 * @param string $separator ip address separator (default ";")
 			 *
 			 * @return bool
 			 */
 			function ipMatch($ip_list, $separator = ';')
 			{
 				$ip_match = false;
 				$ip_addresses = $ip_list ? explode($separator, $ip_list) : Array ();
 				foreach ($ip_addresses as $ip_address) {
 					if ($this->netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) {
 						$ip_match = true;
 						break;
 					}
 				}
 
 				return $ip_match;
 			}
 
 			/**
 			 * Set's default values to constants debugger uses
 			 *
 			 */
 			function InitDebugger()
 			{
 				global $dbg_options;
 
 				unset($dbg_options['DBG_IP']);
 
 				// Detect fact, that this session beeing debugged by Zend Studio
 				foreach ($_COOKIE as $cookie_name => $cookie_value) {
 					if (substr($cookie_name, 0, 6) == 'debug_') {
 						$this->safeDefine('DBG_ZEND_PRESENT', 1);
 						break;
 					}
 				}
 
 				$this->safeDefine('DBG_ZEND_PRESENT', 0); // set this constant value to 0 (zero) to debug debugger using Zend Studio
 
 				// set default values for debugger constants
 				$dbg_constMap = Array (
 					'DBG_USE_HIGHLIGHT'			=>	1,							// highlight output same as php code using "highlight_string" function
 					'DBG_WINDOW_WIDTH'			=>	700,						// set width of debugger window (in pixels) for better viewing large amount of debug data
 					'DBG_USE_SHUTDOWN_FUNC'		=>	DBG_ZEND_PRESENT ? 0 : 1,	// use shutdown function to include debugger code into output
 					'DBG_HANDLE_ERRORS'			=>	DBG_ZEND_PRESENT ? 0 : 1,	// handle all allowed by php (see php manual) errors instead of default handler
 					'DBG_IGNORE_STRICT_ERRORS'	=>	1,							// ignore PHP5 errors about private/public view modified missing in class declarations
 					'DBG_DOMVIEWER'				=>	'/temp/domviewer.html',		// path to DOMViewer on website
 					'DOC_ROOT'					=>	str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
 					'DBG_LOCAL_BASE_PATH'		=>	'w:',						// replace DOC_ROOT in filenames (in errors) using this path
 				);
 
 				// only for IE, in case if no windows php script editor defined
 				if (!defined('DBG_EDITOR')) {
 //					$dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\UltraEdit\uedit32.exe %F/%L';
 					$dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe %F';
 				}
 
 				// debugger is initialized before kHTTPQuery, so do jQuery headers check here too
 				if (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 					$this->_isAjax = true;
 				}
 				elseif (array_key_exists('ajax', $_GET) && $_GET['ajax'] == 'yes') {
 					$this->_isAjax = true;
 				}
 
 				// user defined options override debugger defaults
 				$dbg_constMap = $this->array_merge_recursive2($dbg_constMap, $dbg_options);
 
 				if ($this->_isAjax && array_key_exists('DBG_SKIP_AJAX', $dbg_constMap) && $dbg_constMap['DBG_SKIP_AJAX']) {
 					$dbg_constMap['DBG_SKIP_REPORTING'] = 1;
 				}
 
 				// allows to validate unit configs via request variable
 				if ( !array_key_exists('DBG_VALIDATE_CONFIGS', $dbg_constMap) ) {
 					$dbg_constMap['DBG_VALIDATE_CONFIGS'] = array_key_exists('validate_configs', $_GET) ? (int)$_GET['validate_configs'] : 0;
 				}
 
 				// when validation configs, don't show sqls for better validation error displaying
 				if ($dbg_constMap['DBG_VALIDATE_CONFIGS']) {
 					$dbg_constMap['DBG_SQL_PROFILE'] = 0;
 				}
 
 				// when showing explain make shure, that debugger window is large enough
 				if (array_key_exists('DBG_SQL_EXPLAIN', $dbg_constMap) && $dbg_constMap['DBG_SQL_EXPLAIN']) {
 					$dbg_constMap['DBG_WINDOW_WIDTH'] = 1000;
 				}
 
 				foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) {
 					$this->safeDefine($dbg_constName, $dbg_constValue);
 				}
 			}
 
 			function constOn($const_name)
 			{
 				return defined($const_name) && constant($const_name);
 			}
 
 			function safeDefine($const_name, $const_value) {
 				if (!defined($const_name)) {
 					define($const_name, $const_value);
 				}
 			}
 
 			function array_merge_recursive2($paArray1, $paArray2)
 			{
 				if (!is_array($paArray1) or !is_array($paArray2)) {
 					return $paArray2;
 				}
 
 				foreach ($paArray2 AS $sKey2 => $sValue2) {
 					$paArray1[$sKey2] = isset($paArray1[$sKey2]) ? array_merge_recursive2($paArray1[$sKey2], $sValue2) : $sValue2;
 				}
 
 				return $paArray1;
 			}
 
 			function netMatch($network, $ip) {
 
 				$network = trim($network);
 				$ip = trim($ip);
 
 				if ($network == $ip) {
 					// comparing two ip addresses directly
 					return true;
 				}
 
 				$d = strpos($network, '-');
 				if ($d !== false) {
 					// ip address range specified
 					$from = ip2long(trim(substr($network, 0, $d)));
 					$to = ip2long(trim(substr($network, $d + 1)));
 
 					$ip = ip2long($ip);
 					return ($ip >= $from && $ip <= $to);
 				}
 				elseif (strpos($network, '/') !== false) {
 					// sigle subnet specified
 					$ip_arr = explode('/', $network);
 
 					if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) {
 						$ip_arr[0] .= '.0';    // Alternate form 194.1.4/24
 					}
 
 					$network_long = ip2long($ip_arr[0]);
 					$x = ip2long($ip_arr[1]);
 
 					$mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1]));
 					$ip_long = ip2long($ip);
 
 					return ($ip_long & $mask) == ($network_long & $mask);
 				}
 
 				return false;
 			}
 
 			function InitReport()
 			{
 				if (!class_exists('kApplication')) return false;
 
 				$application =& kApplication::Instance();
 
 				// string used to separate debugger records while in file (used in debugger dump filename too)
 				$this->rowSeparator = '@'.(is_object($application->Factory) ? $application->GetSID() : 0).'@';
 //				$this->rowSeparator = '@'.rand(0,100000).'@';
 
 				// include debugger files from this url
 				$reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/';
 				$kernel_path = preg_replace($reg_exp, '', KERNEL_PATH, 1);
 				$this->baseURL = PROTOCOL.SERVER_NAME.rtrim(BASE_PATH, '/').$kernel_path.'/utility/debugger';
 
 				// save debug output in this folder
 				$this->tempFolder = WRITEABLE . '/cache';
 			}
 
 			function mapLongError($msg)
 			{
 				$key = $this->generateID();
 				$this->longErrors[$key] = $msg;
 				return $key;
 			}
 
 			/**
 			 * Appends all passed variable values (wihout variable names) to debug output
 			 *
 			 */
 			function dumpVars()
 			{
 				$dump_mode = 'var_dump';
 				$dumpVars = func_get_args();
 
 				if ($dumpVars[count($dumpVars) - 1] === 'STRICT') {
 					$dump_mode = 'strict_var_dump';
 					array_pop($dumpVars);
 				}
 
 				foreach ($dumpVars as $varValue) {
 					$this->Data[] = Array('value' => $varValue, 'debug_type' => $dump_mode);
 				}
 
 			}
 
 			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( $this->print_r($Data['value'], true) );
 						break;
 
 					case 'strict_var_dump':
 						return $this->highlightString( var_export($Data['value'], true) );
 						break;
 
 					case 'trace':
 						ini_set('memory_limit', '500M');
 						$trace =& $Data['trace'];
 
 						$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'];
 								$args_link = $has_args ? '<a href="javascript:$Debugger.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';
 							}
 
 							if ($has_args) {
 								// if parameter value is longer then 200 symbols, then leave only first 50
 								$args = $this->highlightString($this->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
 
 						$totals_key = getArrayValue($Data, 'totalsKey');
 						if ($totals_key) {
 							$total_before = $Data['totalsBefore'];
 							$total = $this->ProfilerTotals[$totals_key];
 
 							$div_width = Array();
 							$total_width = ($this->getWindowWidth() - 10);
 							$div_width['before'] = round(($total_before / $total) * $total_width);
 							$div_width['current'] = round(($runtime / $total) * $total_width);
 							$div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width);
 
 							$subtitle = array_key_exists('subtitle', $Data) ? ' (' . $Data['subtitle'] . ')' : '';
 							$ret = '<b>Name' . $subtitle . '</b>: '.$Data['description'].'<br />';
 
 							$additional = isset($Data['additional']) ? $Data['additional'] : Array ();
 							if (isset($Data['file'])) {
 								array_unshift($additional, Array('name' => 'File', 'value' => $this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line'])));
 							}
 							array_unshift($additional, Array('name' => 'Runtime', 'value' => $runtime.'s'));
 
 							$ret .= '<div>'; //FF 3.5 needs this!
 							foreach ($additional as $mixed_param) {
 								$ret .= '[<strong>'.$mixed_param['name'].'</strong>: '.$mixed_param['value'].'] ';
 							}
 
 							/*if (isset($Data['file'])) {
 								$ret .= '[<b>Runtime</b>: '.$runtime.'s] [<b>File</b>: '.$this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line']).']<br />';
 							}
 							else {
 								$ret .= '<b>Runtime</b>: '.$runtime.'s<br />';
 							}*/
 
 							$ret .= '</div>';
 
 							$ret .= '<div class="dbg_profiler" style="width: '.$div_width['before'].'px; border-right: 0px; background-color: #298DDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
 							$ret .= '<div class="dbg_profiler" style="width: '.$div_width['current'].'px; border-left: 0px; border-right: 0px; background-color: #EF4A4A;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
 							$ret .= '<div class="dbg_profiler" style="width: '.$div_width['left'].'px; border-left: 0px; background-color: #DFDFDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
 
 							return $ret;
 						}
 						else {
 							return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
 						}
 						break;
 
 					default:
 						return 'incorrect debug data';
 						break;
 				}
 			}
 
 			function getWindowWidth()
 			{
 				return DBG_WINDOW_WIDTH - $this->scrollbarWidth - 8;
 			}
 
 			/**
 			 * Tells debugger to skip objects that are heavy in plan of memory usage while printing debug_backtrace results
 			 *
 			 * @param Object $object
 			 * @return bool
 			 */
 			function IsBigObject(&$object)
 			{
 				$skip_classes = Array(
 										defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication',
 										'kFactory',
 										'kUnitConfigReader',
 										'NParser',
 								);
 
 				foreach ($skip_classes as $class_name) {
 					if (strtolower(get_class($object)) == strtolower($class_name)) {
 						return true;
 					}
 				}
 
 				return false;
 			}
 
 			/**
 			 * Advanced version of print_r (for debugger only). Don't print objects recursively
 			 *
 			 * @param Array $array
 			 * @param bool $return_output return output or print it out
 			 * @param int $tab_count offset in tabs
 			 * @return string
 			 */
 			function print_r(&$array, $return_output = false, $tab_count = -1)
 			{
 				static $first_line = true;
 
 				// not an array at all
 				if (!is_array($array)) {
 					switch (gettype($array)) {
 						case 'NULL':
 							return 'NULL'."\n";
 							break;
 
 						case 'object':
 							return $this->processObject($array, $tab_count);
 							break;
 
 						default:
 							// number or string
 							if (strlen($array) > 200) {
 								$array = substr($array, 0, 50).' ...';
 							}
 							return $array."\n";
 							break;
 					}
 				}
 
 				$output = '';
 
 				$tab_count++;
 				$output .= "Array\n".str_repeat('    ', $tab_count)."(\n";
 
 				$tab_count++;
 				$tabsign = $tab_count ? str_repeat('    ', $tab_count) : '';
 
 				$array_keys = array_keys($array);
 
 				foreach ($array_keys as $key) {
 					switch (gettype($array[$key])) {
 						case 'array':
 							$output .= $tabsign.'['.$key.'] = '.$this->print_r($array[$key], true, $tab_count);
 							break;
 
 						case 'boolean':
 							$output .= $tabsign.'['.$key.'] = '.($array[$key] ? 'true' : 'false')."\n";
 							break;
 
 						case 'integer':
 						case 'double':
 						case 'string':
 							if (strlen($array[$key]) > 200) {
 								$array[$key] = substr($array[$key], 0, 50).' ...';
 							}
 							$output .= $tabsign.'['.$key.'] = '.$array[$key]."\n";
 							break;
 
 						case 'NULL':
 							$output .= $tabsign.'['.$key."] = NULL\n";
 							break;
 
 						case 'object':
 							$output .= $tabsign.'['.$key."] = ";
 							$output .= "Object (".get_class($array[$key]).") = \n".str_repeat('    ', $tab_count + 1)."(\n";
 							$output .= $this->processObject($array[$key], $tab_count + 2);
 							$output .= str_repeat('    ', $tab_count + 1).")\n";
 							break;
 
 						default:
 							$output .= $tabsign.'['.$key.'] unknown = '.gettype($array[$key])."\n";
 							break;
 					}
 				}
 
 				$tab_count--;
 				$output .= str_repeat('    ', $tab_count).")\n";
 
 				if ($first_line) {
 					$first_line = false;
 					$output .= "\n";
 				}
 
 				$tab_count--;
 
 				if ($return_output) {
 					return $output;
 				}
 				else {
 					echo $output;
 				}
 
 				return true;
 			}
 
 			function processObject(&$object, $tab_count)
 			{
 				$object_class = get_class($object);
 				if (!in_array($object_class, $this->RecursionStack)) {
 					if ($this->IsBigObject($object)) {
 						return 'SKIPPED (class: '.$object_class.")\n";
 					}
 
 					$attribute_names = get_class_vars($object_class);
 					if (!$attribute_names) {
 						return "NO_ATTRIBUTES\n";
 					}
 					else {
 						$output = '';
 						array_push($this->RecursionStack, $object_class);
 
 						$tabsign = $tab_count ? str_repeat('    ', $tab_count) : '';
 						foreach ($attribute_names as $attribute_name => $attribute_value) {
 							if (is_object($object->$attribute_name)) {
 								// it is object
 								$output .= $tabsign.'['.$attribute_name.'] = '.$this->processObject($object->$attribute_name, $tab_count + 1);
 							}
 							else {
 								$output .= $tabsign.'['.$attribute_name.'] = '.$this->print_r($object->$attribute_name, true, $tab_count);
 							}
 						}
 						array_pop($this->RecursionStack);
 						return $output;
 					}
 				}
 				else {
 					// object [in recursion stack]
 					return '*** RECURSION *** (class: '.$object_class.")\n";
 				}
 			}
 
 			/**
 			 * Format SQL Query using predefined formatting
 			 * and highlighting techniques
 			 *
 			 * @param string $sql
 			 * @return string
 			 */
 			function formatSQL($sql)
 			{
 				$sql = trim( preg_replace('/(\n|\t| )+/is', ' ', $sql) );
 
 				// whitespace in the beginning of the regex is to avoid splitting inside words, for exmaple "FROM int_ConfigurationValues" into "FROM intConfiguration\n\tValues"
 				$formatted_sql = preg_replace('/\s(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY)\s/is', "\n\t$1 ", ' ' . $sql);
 				$formatted_sql = $this->highlightString($formatted_sql);
 
 				if (defined('DBG_SQL_EXPLAIN') && DBG_SQL_EXPLAIN) {
 					if (substr($sql, 0, 6) == 'SELECT') {
 						$formatted_sql .= '<br/>' . '<strong>Explain</strong>:<br /><br />';
 						$explain_result = $this->Application->Conn->Query('EXPLAIN ' . $sql, null, true);
 
 						$explain_table = '';
 						foreach ($explain_result as $explain_row) {
 							if (!$explain_table) {
 								// first row -> draw header
 								$explain_table .= '<tr class="explain_header"><td>' . implode('</td><td>', array_keys($explain_row)) . '</td></tr>';
 							}
 							$explain_table .= '<tr><td>' . implode('</td><td>', $explain_row) . '</td></tr>';
 						}
 
 						$formatted_sql .= '<table class="dbg_explain_table">' . $explain_table . '</table>';
 					}
 				}
 
 				return $formatted_sql;
 			}
 
 			function highlightString($string)
 			{
 				if (!(defined('DBG_USE_HIGHLIGHT') && DBG_USE_HIGHLIGHT) || $this->_compileError) {
 					return nl2br($string);
 				}
 
 				$string = str_replace( Array('\\', '/') , Array('_no_match_string_', '_n_m_s_'), $string);
 				$this->_compileError = true; // next line is possible cause of compile error
 				$string = highlight_string('<?php '.$string.' ?>', true);
 				$this->_compileError = false;
 
 				$string = str_replace( Array('_no_match_string_', '_n_m_s_'), Array('\\', '/'), $string);
 
 				if (strlen($string) >= 65536) {
 					// preg_replace will fail, when string is longer, then 65KB
 					return str_replace(Array ('&lt;?php&nbsp;', '?&gt;'), '', $string);
 				}
 
 				return preg_replace('/&lt;\?(.*)php&nbsp;(.*)\?&gt;/Us', '\\2', $string);
 			}
 
 			/**
 			 * Determine by php type of browser used to show debugger
 			 *
 			 * @return bool
 			 */
 			function isGecko()
 			{
 				// we need isset because we may run scripts from shell with no user_agent at all
 				return isset($_SERVER['HTTP_USER_AGENT']) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false;
 			}
 
 			/**
 			 * Returns link for editing php file (from error) in external editor
 			 *
 			 * @param string $file filename with path from root folder
 			 * @param int $lineno line number in file where error is found
 			 * @param string $title text to show on file edit link
 			 * @return string
 			 */
 			function getFileLink($file, $lineno = 1, $title = '')
 			{
 				if (!$title) {
 					$title = str_replace('/', '\\', $this->getLocalFile($file));
 				}
 
 				if ($this->isGecko()) {
 					return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
 				}
 				else {
 					return '<a href="javascript:$Debugger.editFile(\''.$this->getLocalFile($file).'\', '.$lineno.');" title="'.$file.'">'.$title.'</a>';
 				}
 
 			}
 
 			/**
 			 * Converts filepath on server to filepath in mapped DocumentRoot on developer pc
 			 *
 			 * @param string $remoteFile
 			 * @return string
 			 */
 			function getLocalFile($remoteFile)
 			{
 				return preg_replace('/^'.preg_quote(DOC_ROOT, '/').'/', DBG_LOCAL_BASE_PATH, $remoteFile, 1);
 			}
 
 			/**
 			 * Appends call trace till this method call
 			 *
 			 */
 			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');
 			}
 
 			/**
 			 * Appends HTML code whithout transformations
 			 *
 			 * @param string $html
 			 */
 			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()
 			{
 				if (isset($_SERVER['SCRIPT_FILENAME'])) {
 					$script = $_SERVER['SCRIPT_FILENAME'];
 				}
 				else {
 					$script = $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'];
 				}
 
 				$this->appendHTML('ScriptName: <b>'.$this->getFileLink($script, 1, basename($script)).'</b> (<b>'.dirname($script).'</b>)');
 				if ($this->_isAjax) {
 					$this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI'].' (QS Length:'.strlen($_SERVER['QUERY_STRING']).')');
 				}
 
 				$tools_html = '	<table style="width: ' . $this->getWindowWidth() . 'px;">
 									<tr>
 										<td>' . $this->_getDomViewerHTML() . '</td>
 										<td>' . $this->_getToolsHTML() . '</td>
 									</tr>
 								</table>';
 				$this->appendHTML($tools_html);
 
 				ob_start();
 				?>
 				<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: <?php echo $this->getWindowWidth(); ?>px;">
 					<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($this->print_r($value, true));
 						}
 
 						$in_cookie = isset($_COOKIE[$key]);
 						$src = isset($_GET[$key]) && !$in_cookie ? 'GE' : (isset($_POST[$key]) && !$in_cookie ? 'PO' : ($in_cookie ? 'CO' : '?') );
 						echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
 					}
 				?>
 				</table>
 				<?php
 				$this->appendHTML(ob_get_contents());
 				ob_end_clean();
 			}
 
 			/**
 			 * Appends php session content to debugger output
 			 *
 			 */
 			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 = null, $timeStamp = null)
 			{
 				if (!isset($timeStamp)) {
 					$timeStamp = $this->getMoment();
 				}
 				$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data));
 				if (isset($description)) {
 					$this->ProfilerData[$key]['description'] = $description;
 				}
 
 				if (substr($key, 0, 4) == 'sql_') {
 					// append place from what was called
 					$trace_results = debug_backtrace();
 					$trace_count = count($trace_results);
 					$i = 0;
 					while ($i < $trace_count) {
 						$trace_file = basename($trace_results[$i]['file']);
 						if ($trace_file != 'db_connection.php' && $trace_file != 'adodb.inc.php') {
 							break;
 						}
 						$i++;
 					}
 
 					$this->ProfilerData[$key]['file'] = $trace_results[$i]['file'];
 					$this->ProfilerData[$key]['line'] = $trace_results[$i]['line'];
 
 					if (array_key_exists('object', $trace_results[$i + 1]) && isset($trace_results[$i + 1]['object']->Prefix)) {
 						$object =& $trace_results[$i + 1]['object'];
 						$prefix_special = rtrim($object->Prefix . '.' . $object->Special, '.');
 						$this->ProfilerData[$key]['prefix_special'] = $prefix_special;
 					}
 
 					unset($trace_results);
 				}
 
 				$this->Data[] = Array('profile_key' => $key, 'debug_type' => 'profiler');
 			}
 
 			function profileFinish($key, $description = null, $timeStamp = null)
 			{
 				if (!isset($timeStamp)) {
 					$timeStamp = $this->getMoment();
 				}
 				$this->ProfilerData[$key]['ends'] = $timeStamp;
 
 				if (isset($description)) {
 					$this->ProfilerData[$key]['description'] = $description;
 				}
 
 				if (substr($key, 0, 4) == 'sql_') {
 					$func_arguments = func_get_args();
 					$rows_affected = $func_arguments[3];
 
 					$additional = Array ();
 
 					if ($rows_affected > 0) {
 						$additional[] = Array ('name' => 'Affected Rows', 'value' => $rows_affected);
 
 						if (isset($func_arguments[4])) {
 							if (strlen($func_arguments[4]) > 200) {
 								$func_arguments[4] = substr($func_arguments[4], 0, 50) . ' ...';
 							}
 
 							$additional[] = Array ('name' => 'Result', 'value' => $func_arguments[4]);
 						}
 					}
 
 					$additional[] =	Array ('name' => 'Query Number', 'value' => $func_arguments[5]);
 
 					if ($func_arguments[6]) {
 						$this->profilerAddTotal('cachable_queries', $key);
 						$this->ProfilerData[$key]['subtitle'] = 'cachable';
 					}
 
 					if (array_key_exists('prefix_special', $this->ProfilerData[$key])) {
 						$additional[] =	Array ('name' => 'PrefixSpecial', 'value' => $this->ProfilerData[$key]['prefix_special']);
 					}
 
 					$this->ProfilerData[$key]['additional'] =& $additional;
 				}
 			}
 
 			function profilerAddTotal($total_key, $key = null, $value = null)
 			{
 				if (!isset($this->ProfilerTotals[$total_key])) {
 					$this->ProfilerTotals[$total_key] = 0;
 					$this->ProfilerTotalCount[$total_key] = 0;
 				}
 
 				if (!isset($value)) {
 					$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
 				}
 
 				if (isset($key)) {
 					$this->ProfilerData[$key]['totalsKey'] = $total_key;
 					$this->ProfilerData[$key]['totalsBefore'] = $this->ProfilerTotals[$total_key];
 				}
 
 				$this->ProfilerTotals[$total_key] += $value;
 				$this->ProfilerTotalCount[$total_key]++;
 			}
 
 			function getMoment()
 			{
 				list($usec, $sec) = explode(' ', microtime());
 	   			return ((float)$usec + (float)$sec);
 			}
 
 			function appendTimestamp($message)
 			{
 				global $start;
 				$time = $this->getMoment();
 				$from_last = $time - $this->LastMoment;
 				$from_start = $time - $start;
 				$this->appendHTML(sprintf("<b>%s</b> %.5f from last %.5f from start", $message, $from_last, $from_start));
 				$this->LastMoment = $time;
 			}
 
 			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 = preg_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($error_code)
 			{
 				$error_map = Array(
 									'Fatal Error' 	=>	Array(E_USER_ERROR),
 									'Warning'		=>	Array(E_WARNING, E_USER_WARNING),
 									'Notice'		=>	Array(E_NOTICE, E_USER_NOTICE),
 							);
 
 				if (defined('E_STRICT')) {
 					// since PHP 5
 					$error_map['PHP5 Strict'] = Array(E_STRICT);
 				}
 
 				if (defined('E_RECOVERABLE_ERROR')) {
 					// since PHP 5.2
 					$error_map['Fatal Error (recoverable)'] = Array(E_RECOVERABLE_ERROR);
 				}
 
 				if (defined('E_DEPRECATED')) {
 					// since PHP 5.3
 					$error_map['PHP5 Depricated'] = Array(E_DEPRECATED, E_USER_DEPRECATED);
 				}
 
 				foreach ($error_map as $error_name => $error_codes) {
 					if (in_array($error_code, $error_codes)) {
 						return $error_name;
 					}
 				}
 
 				return '';
 			}
 
 			/**
 			 * Returns profile total key (check against unexisting key too)
 			 *
 			 * @param string $key
 			 * @return int
 			 */
 			function getProfilerTotal($key)
 			{
 				if (isset($this->ProfilerTotalCount[$key])) {
 					return (int)$this->ProfilerTotalCount[$key];
 				}
 				return 0;
 			}
 
 			function ProfilePoint($title, $level=1)
 			{
 				$trace_results = debug_backtrace();
 				$level = min($level,count($trace_results)-1);
 
 				do {
 					$point = $trace_results[$level];
 					$location = $point['file'].':'.$point['line'];
 					$level++;
 					$has_more = isset($trace_results[$level]);
 				} while ($has_more && $point['function'] == $trace_results[$level]['function'] );
 
 				if (!isset($this->ProfilePoints[$title])) {
 					$this->ProfilePoints[$title] = array();
 				}
 				if (!isset($this->ProfilePoints[$title][$location])) {
 					$this->ProfilePoints[$title][$location] = 0;
 				}
 				$this->ProfilePoints[$title][$location]++;
 			}
 
 			/**
 			 * Generates report
 			 *
 			 */
 			function printReport($returnResult = false, $clean_output_buffer = true)
 			{
 				if ($this->reportDone) {
 					// don't print same report twice (in case if shutdown function used + compression + fatal error)
 					return '';
 				}
 
 				$this->profileFinish('script_runtime');
 				$this->breakOutofBuffering(!$returnResult);
 
 				$debugger_start = memory_get_usage();
 
 				if (defined('SPACER_URL')) {
 					$this->dummyImage = SPACER_URL;
 				}
 
 				$this->InitReport(); // set parameters required by AJAX
 
 				// defined here, because user can define this contant while script is running, not event before debugger is started
 				$this->safeDefine('DBG_RAISE_ON_WARNINGS', 	0);
 				$this->safeDefine('DBG_TOOLBAR_BUTTONS', 	1);
 
 				$this->appendSession(); // show php session if any
 
 				// ensure, that 1st line of debug output always is this one:
 				$top_line = '<table cellspacing="0" cellpadding="0" style="width: '.$this->getWindowWidth().'px; margin: 0px;"><tr><td align="left" width="50%">[<a href="javascript:window.location.reload();">Reload Frame</a>] [<a href="javascript:$Debugger.Toggle(27);">Hide Debugger</a>] [<a href="javascript:$Debugger.Clear();">Clear Debugger</a>]</td><td align="right" width="50%">[Current Time: <b>'.date('H:i:s').'</b>] [File Size: <b>#DBG_FILESIZE#</b>]</td></tr></table>';
 
 				$this->appendHTML($top_line);
 				$this->moveToBegin(1);
 
 				if (count($this->ProfilePoints)>0) {
 					foreach($this->ProfilePoints as $point => $locations) {
 						arsort($this->ProfilePoints[$point]);
 					}
 
 					$this->appendHTML($this->highlightString($this->print_r($this->ProfilePoints, true)));
 					/*foreach ($this->ProfilePoints as $point => $locations) {
 						foreach ($locations as $location => $occurences) {
 
 
 						}
 					}*/
 				}
 
 				if ($this->constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) {
 					// sql query profiling was enabled -> show totals
 					if (array_key_exists('cachable_queries', $this->ProfilerTotalCount)) {
 						$append = ' <strong>Cachable queries</strong>: ' . $this->ProfilerTotalCount['cachable_queries'];
 					}
 					else {
 						$append = '';
 					}
 
 					$this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql'].' <b>Number of queries</b>: '.$this->ProfilerTotalCount['sql'] . $append);
 				}
 
 				if ($this->constOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes'])) {
 					// included file profiling was enabled -> show totals
 					$this->appendHTML('<b>Included Files Total time:</b> '.$this->ProfilerTotals['includes'].' Number of includes: '.$this->ProfilerTotalCount['includes']);
 				}
 
 				if ($this->constOn('DBG_PROFILE_MEMORY')) {
 					// detailed memory usage reporting by objects was enabled -> show totals
 					$this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects'] / 1024, 2).'Kb');
 				}
 
 				if ($this->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 ($this->constOn('DBG_PROFILE_INCLUDES')) {
 					$this->appendHTML('<b>Included files statistics:</b>'.( $this->constOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
 					$totals = Array( 'mem' => 0, 'time' => 0);
 					$totals_configs = Array( 'mem' => 0, 'time' => 0);
 					if (is_array($this->IncludesData['mem'])) {
 						if ( $this->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']));
 					}
 				}
 
 				$skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT');
 
 				if (($this->_isAjax && !$this->constOn('DBG_SKIP_AJAX')) || !$skip_reporting) {
 					$debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt';
 					if (file_exists($debug_file)) unlink($debug_file);
 
 					$i = 0;
 					$fp = fopen($debug_file, 'a');
 					$lineCount = count($this->Data);
 					while ($i < $lineCount) {
 						fwrite($fp, $this->prepareHTML($i).$this->rowSeparator);
 						$i++;
 					}
 					fclose($fp);
 				}
 
 				if ($skip_reporting) {
 					// let debugger write report and then don't output anything
 					$this->reportDone = true;
 					return '';
 				}
 
 				$application =& kApplication::Instance();
 				$dbg_path = str_replace(FULL_PATH, '', $this->tempFolder);
 
 				ob_start();
 				// the <script .. /script> and hidden div helps browser to break out of script tag or attribute esacped
 				// with " or ' in case fatal error (or user-error) occurs inside it in compiled template,
 				// otherwise it has no effect
 			?>
 					<div style="display: none" x='nothing'><script></script></div><html><body></body></html>
 					<script type="text/javascript" src="<?php echo $this->baseURL; ?>/debugger.js"></script>
 					<link rel="stylesheet" rev="stylesheet" href="<?php echo $this->baseURL; ?>/debugger.css" type="text/css" media="screen" />
 
 					<script type="text/javascript">
 						var $Debugger = new Debugger(<?php echo "'".$this->rowSeparator."', ".$this->getProfilerTotal('error_handling').', '.($this->IsFatalError ? 'true' : 'false').', '.$this->getProfilerTotal('sql'); ?>);
 						$Debugger.createEnvironment(<?php echo DBG_WINDOW_WIDTH; ?>, <?php echo $this->getWindowWidth(); ?>);
 
 						$Debugger.DOMViewerURL = '<?php echo constant('DBG_DOMVIEWER'); ?>';
 						$Debugger.EditorPath = '<?php echo defined('DBG_EDITOR') ? addslashes(DBG_EDITOR) : '' ?>';
 						$Debugger.DebugURL = '<?php echo $this->baseURL.'/debugger_responce.php?sid='.$this->rowSeparator.'&path='.urlencode($dbg_path); ?>';
-						$Debugger.EventURL = '<?php echo is_object($application->Factory) ? $application->HREF('dummy', '', Array ('pass' => 'm')) : ''; ?>';
+						$Debugger.EventURL = '<?php echo is_object($application->Factory) ? $application->HREF('dummy', '', Array ('pass' => 'm', '__NO_REWRITE__' => 1)) : ''; ?>';
 						<?php
 							if ($this->IsFatalError || (DBG_RAISE_ON_WARNINGS && $this->WarningCount)) {
 								echo '$Debugger.Toggle();';
 							}
 							if (DBG_TOOLBAR_BUTTONS) {
 								echo '$Debugger.AddToolbar("$Debugger");';
 							}
 						?>
 						window.focus();
 					</script>
 				<?php
 					if (!isset($this->ProfilerTotals['error_handling'])) {
 						$memory_used = $debugger_start;
 						$this->ProfilerTotalCount['error_handling'] = 0;
 					}
 					else {
 						$memory_used = $debugger_start - $this->ProfilerTotals['error_handling'];
 					}
 
 					if ($returnResult) {
 						$ret = ob_get_contents();
 						if ($clean_output_buffer) {
 							ob_end_clean();
 						}
 						$ret .= $this->getShortReport($memory_used);
 
 						$this->reportDone = true;
 						return $ret;
 					}
 					else {
 						if (!$this->constOn('DBG_HIDE_FULL_REPORT')) {
 							$this->breakOutofBuffering();
 						}
 						elseif ($clean_output_buffer) {
 							ob_clean();
 						}
 						echo $this->getShortReport($memory_used);
 
 						$this->reportDone = true;
 					}
 			}
 
 			/**
 			 * Format's memory usage report by debugger
 			 *
 			 * @return string
 			 * @access private
 			 */
 			function getShortReport($memory_used)
 			{
 				if ($this->constOn('DBG_TOOLBAR_BUTTONS')) {
 					// we have sql & error count in toolbar, don't duplicate here
 					$info = Array(
 						'Script Runtime'	=>	'PROFILE:script_runtime',
 						'SQL\'s Runtime'	=>	'PROFILE_T:sql',
 					);
 				}
 				else {
 					// toolbar not visible, then show sql & error count too
 					$info = Array (
 						'Script Runtime'	=>	'PROFILE:script_runtime',
 						'SQL\'s Runtime'	=>	'PROFILE_T:sql',
 						'-'					=>	'SEP:-',
 						'Notice / Warning'	=>	'PROFILE_TC:error_handling',
 						'SQLs Count'		=>	'PROFILE_TC:sql',
 					);
 				}
 
 				$ret = '<tr><td>Application:</td><td><b>'.$this->formatSize($memory_used).'</b> ('.$memory_used.')</td></tr>';
 				foreach ($info as $title => $value_key) {
 					list ($record_type, $record_data) = explode(':', $value_key, 2);
 					switch ($record_type) {
 						case 'PROFILE': // profiler totals value
 							$Data =& $this->ProfilerData[$record_data];
 							$profile_time = ($Data['ends'] - $Data['begins']); // in seconds
 							$ret .= '<tr><td>'.$title.':</td><td><b>'.sprintf('%.5f', $profile_time).' s</b></td></tr>';
 							break;
 
 						case 'PROFILE_TC': // profile totals record count
 							$record_cell = '<td>';
 							if ($record_data == 'error_handling' && $this->ProfilerTotalCount[$record_data] > 0) {
 								$record_cell = '<td class="debug_error">';
 							}
 							$ret .= '<tr>'.$record_cell.$title.':</td>'.$record_cell.'<b>'.$this->ProfilerTotalCount[$record_data].'</b></td></tr>';
 							break;
 
 						case 'PROFILE_T': // profile total
 							$record_cell = '<td>';
 							$total = array_key_exists($record_data, $this->ProfilerTotals) ? $this->ProfilerTotals[$record_data] : 0;
 							$ret .= '<tr>'.$record_cell.$title.':</td>'.$record_cell.'<b>'.sprintf('%.5f', $total).' s</b></td></tr>';
 							break;
 
 						case 'SEP':
 							$ret .= '<tr><td colspan="2" style="height: 1px; background-color: #000000; padding: 0px;"><img src="'.$this->dummyImage.'" height="1" alt=""/></td></tr>';
 							break;
 					}
 				}
 
 				return '<br /><table class="dbg_stats_table"><tr><td style="border-color: #FFFFFF;"><table class="dbg_stats_table" align="left">'.$ret.'</table></td></tr></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 = '')
 			{
 				$this->ProfilerData['error_handling']['begins'] = memory_get_usage();
 
 				$errorType = $this->getErrorNameByCode($errno);
 				if (!$errorType) {
 					trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
 					return false;
 				}
 
 				if ($this->constOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT)) return;
 
 				if (preg_match('/(.*)#([\d]+)$/', $errstr, $rets) ) {
 					// replace short message with long one (due triger_error limitations on message size)
 					$long_id = $rets[2];
 					$errstr = $this->longErrors[$long_id];
 					unset($this->longErrors[$long_id]);
 				}
 
 				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);
 				}
 
 				$this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
 				$this->ProfilerData['error_handling']['ends'] = memory_get_usage();
 				$this->profilerAddTotal('error_handling', 'error_handling');
 
 				if ($errorType == 'Warning') {
 					$this->WarningCount++;
 				}
 
 				if (substr($errorType, 0, 5) == 'Fatal') {
 					$this->IsFatalError = true;
 					// append debugger report to data in buffer & clean buffer afterwards
 					die( $this->breakOutofBuffering(false) . $this->printReport(true) );
 				}
 			}
 
 			function breakOutofBuffering($flush = true)
 			{
 				$buffer_content = Array();
 				while (ob_get_level()) {
 					$buffer_content[] = ob_get_clean();
 				}
 				$ret = implode('', array_reverse($buffer_content));
 				if ($flush) {
 					echo $ret;
 					flush();
 				}
 				return $ret;
 			}
 
 			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;
 			}
 
 			function printConstants($constants)
 			{
 				if (!is_array($constants)) {
 					$constants = explode(',', $constants);
 				}
 				$contant_tpl = '<tr><td>%s</td><td><b>%s</b></td></tr>';
 				$ret = '<table class="dbg_flat_table" style="width: '.$this->getWindowWidth().'px;">';
 				foreach ($constants as $constant_name) {
 					$ret .= sprintf($contant_tpl, $constant_name, constant($constant_name));
 				}
 				$ret .= '</table>';
 				$this->appendHTML($ret);
 			}
 
 			function AttachToApplication() {
 				if (!$this->constOn('DBG_HANDLE_ERRORS')) {
 					return true;
 				}
 
 				if (class_exists('kApplication')) {
 					restore_error_handler(); // replace application error handler with own
 					$this->Application =& kApplication::Instance();
 					$this->Application->Debugger =& $this;
 					$this->Application->errorHandlers[] = Array (&$this, 'saveError');
 				}
 				else {
 					set_error_handler(Array(&$this, 'saveError'));
 				}
 			}
 
 			/**
 			 * Returns HTML for tools section
 			 *
 			 * @return string
 			 */
 			function _getToolsHTML()
 			{
 				$html = '<table>
 							<tr>
 								<td>System Tools:</td>
 								<td>
 									<select id="reset_cache" style="border: 1px solid #000000;">
 										<option value=""></option>
 										<option value="events[adm][OnResetModRwCache]">Reset mod_rewrite Cache</option>
 										<option value="events[adm][OnResetCMSMenuCache]">Reset SMS Menu Cache</option>
 										<option value="events[adm][OnResetSections]">Reset Sections Cache</option>
 										<option value="events[adm][OnResetConfigsCache]">Reset Configs Cache</option>
 										<option value="events[adm][OnRebuildThemes]">Re-build Themes Files</option>
 										<option value="events[lang][OnReflectMultiLingualFields]">Re-build Multilanguage Fields</option>
 										<option value="events[adm][OnDeleteCompiledTemplates]">Delete Compiled Templates</option>
 									</select>
 								</td>
 								<td>
 									<input type="button" class="button" onclick="$Debugger.resetCache(\'reset_cache\');" value="Go"/>
 								</td>
 							</tr>
 						</table>';
 
 				return $html;
 			}
 
 			/**
 			 * Returns HTML for dom viewer section
 			 *
 			 * @return string
 			 */
 			function _getDomViewerHTML()
 			{
 				$html = '<table>
 							<tr>
 								<td>
 									<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>:
 								</td>
 								<td>
 									 <input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>
 								</td>
 								<td>
 									<button class="button" onclick="return $Debugger.OpenDOMViewer();">Show</button>
 								</td>
 							</tr>
 						</table>';
 
 				return $html;
 			}
 		}
 
 		if (!function_exists('memory_get_usage')) {
 			function memory_get_usage(){ return -1;	}
 		}
 
 		if (!Debugger::constOn('DBG_ZEND_PRESENT')) {
 			$debugger = new Debugger();
 		}
 
 		if (Debugger::constOn('DBG_USE_SHUTDOWN_FUNC')) {
 			register_shutdown_function( Array(&$debugger, 'printReport') );
 		}
 	}
\ No newline at end of file
Index: branches/5.1.x/core/kernel/utility/unit_config_reader.php
===================================================================
--- branches/5.1.x/core/kernel/utility/unit_config_reader.php	(revision 13988)
+++ branches/5.1.x/core/kernel/utility/unit_config_reader.php	(revision 13989)
@@ -1,1104 +1,1106 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class kUnitConfigReader extends kBase {
 
 	/**
 	 * Configs readed
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $configData = Array();
 	var $configFiles = Array();
 
 	var $CacheExpired = false;
 
 	var $prefixFiles = array();
 
 	var $ProcessAllConfigs = false;
 	var $FinalStage = false;
 	var $StoreCache = false;
 	var $AfterConfigProcessed = array();
 
 	/**
 	 * Escaped directory separator for using in regular expressions
 	 *
 	 * @var string
 	 */
 	var $_directorySeparator = '';
 
 	/**
 	 * Regular expression for detecting module folder
 	 *
 	 * @var string
 	 */
 	var $_moduleFolderRegExp = '';
 
 	/**
 	 * Folders to skip during unit config search
 	 *
 	 * @var Array
 	 */
 	var $_skipFolders = Array ('CVS', '.svn', 'admin_templates', 'libchart');
 
 	/**
 	 * Scan kernel and user classes
 	 * for available configs
 	 *
 	 * @access protected
 	 */
 	function Init($prefix,$special)
 	{
 		parent::Init($prefix,$special);
 
 		$this->_directorySeparator = preg_quote(DIRECTORY_SEPARATOR);
 
 		$editor_path = explode('/', trim(EDITOR_PATH, '/'));
 		$this->_skipFolders[] = array_pop($editor_path); // last of cmseditor folders
 
 		$this->_moduleFolderRegExp = '#' . $this->_directorySeparator . '(core|modules' . $this->_directorySeparator . '.*?)' . $this->_directorySeparator . '#';
 	}
 
 	function CacheParsedData()
 	{
 		$event_manager =& $this->Application->recallObject('EventManager');
 		$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
 
 		$config_vars = Array (
 			// session related
 			'SessionTimeout',
 			'SessionCookieName',
 			'SessionCookieDomains',
 			'SessionBrowserSignatureCheck',
 			'SessionIPAddressCheck',
 			'CookieSessions',
 			'KeepSessionOnBrowserClose',
 			'User_GuestGroup',
 			'User_LoggedInGroup',
 
 			// output related
 			'UseModRewrite',
 			'UseContentLanguageNegotiation',
 			'UseOutputCompression',
 			'OutputCompressionLevel',
 			'Config_Site_Time',
 			'SystemTagCache',
 
 			// tracking related
 			'UseChangeLog',
 			'UseVisitorTracking',
 			'ModRewriteUrlEnding',
 			'ForceModRewriteUrlEnding',
 			'UseCronForRegularEvent',
 		);
 
 		foreach ($config_vars as $var) {
 			$this->Application->ConfigValue($var);
 		}
 
 		$cache = Array(
 			'Factory.Files' => $this->Application->Factory->Files,
 			'Factory.realClasses' => $this->Application->Factory->realClasses,
 			'Factory.Dependencies' => $this->Application->Factory->Dependencies,
 			'ConfigReader.prefixFiles' => $this->prefixFiles,
 			'EventManager.buildEvents' => $event_manager->buildEvents,
 			'EventManager.beforeRegularEvents' => $event_manager->beforeRegularEvents,
 			'EventManager.afterRegularEvents' => $event_manager->afterRegularEvents,
 			'EventManager.beforeHooks' => $event_manager->beforeHooks,
 			'EventManager.afterHooks' => $event_manager->afterHooks,
 			'TagsAggregator.data' => $aggregator->_Array,
 
 			// the following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
 			'Application.Caches.ConfigVariables' => $this->Application->Caches['ConfigVariables'],
 			'Application.ConfigCacheIds' => $this->Application->ConfigCacheIds,
 			'Application.ConfigHash' => $this->Application->ConfigHash,
 			'Application.ReplacementTemplates' => $this->Application->ReplacementTemplates,
 			'Application.RewriteListeners' => $this->Application->RewriteListeners,
 			'Application.ModuleInfo' => $this->Application->ModuleInfo,
 		);
 
 		if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 			$this->Application->setCache('master:configs_parsed', serialize($cache));
 			$this->Application->setCache('master:config_files', serialize($this->configFiles));
 		}
 		else {
 			$this->Application->setDBCache('configs_parsed', serialize($cache));
 			$this->Application->setDBCache('config_files', serialize($this->configFiles));
 		}
 
 		$cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s');
 		$this->Application->setDBCache('last_cache_rebuild', $cache_rebuild_by);
 
 		unset($this->configFiles);
 	}
 
 	function RestoreParsedData()
 	{
 		$conn =& $this->Application->GetADODBConnection();
 
 		if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 			$data = $this->Application->getCache('master:configs_parsed', false);
 		}
 		else {
 			$data = $this->Application->getDBCache('configs_parsed');
 		}
 
 		if ($data) {
 			$cache = unserialize($data);
 			$this->Application->Factory->Files = $cache['Factory.Files'];
 			$this->Application->Factory->realClasses = $cache['Factory.realClasses'];
 			$this->Application->Factory->Dependencies = $cache['Factory.Dependencies'];
 			$this->prefixFiles = $cache['ConfigReader.prefixFiles'];
 
 			$event_manager =& $this->Application->recallObject('EventManager');
 			$event_manager->buildEvents = $cache['EventManager.buildEvents'];
 			$event_manager->beforeRegularEvents = $cache['EventManager.beforeRegularEvents'];
 			$event_manager->afterRegularEvents = $cache['EventManager.afterRegularEvents'];
 			$event_manager->beforeHooks = $cache['EventManager.beforeHooks'];
 			$event_manager->afterHooks = $cache['EventManager.afterHooks'];
 
 			$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
 			$aggregator->_Array = $cache['TagsAggregator.data'];
 
 			$this->Application->ConfigHash = $cache['Application.ConfigHash'];
 
 			$this->Application->Caches['ConfigVariables'] = $cache['Application.ConfigCacheIds'];
 			$this->Application->ConfigCacheIds = $cache['Application.ConfigCacheIds'];
 
 			$this->Application->ReplacementTemplates = $cache['Application.ReplacementTemplates'];
 			$this->Application->RewriteListeners = $cache['Application.RewriteListeners'];
 
 			$this->Application->ModuleInfo = $cache['Application.ModuleInfo'];
 
 			return true;
 
 		}
 		else return false;
 	}
 
 	function ResetParsedData($include_sections = false)
 	{
 		$conn =& $this->Application->GetADODBConnection();
 
 		if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 			$this->Application->deleteCache('master:configs_parsed');
 		}
 		else {
 			$this->Application->deleteDBCache('configs_parsed');
 		}
 
 		if ($include_sections) {
 			if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 				$this->Application->deleteCache('master:sections_parsed');
 			}
 			else {
 				$this->Application->deleteDBCache('sections_parsed');
 			}
 		}
 	}
 
 	function scanModules($folderPath, $cache = true)
 	{
 		if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) {
 			// disable config caching during installation
 			$cache = false;
 		}
 
 		if ($cache) {
 			$restored = $this->RestoreParsedData();
 			if ($restored) return;
 		}
 
 		$this->ProcessAllConfigs = true;
 
 		$this->includeConfigFiles($folderPath, $cache);
 		$this->ParseConfigs();
 
 		// tell AfterConfigRead to store cache if neede
 		// can't store it here beacuse AfterConfigRead needs ability to change config data
 		$this->StoreCache = $cache;
 	}
 
 	function findConfigFiles($folderPath, $level = 0)
 	{
 		/*if ($level == 0) {
 			if ($this->Application->isDebugMode()) {
 				$start_time = getmicrotime();
 				$this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . $folderPath . '")');
 				$this->Application->Debugger->appendTrace();
 			}
 		}*/
 
 		// if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted
 		$reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/';
 		$folderPath = preg_replace($reg_exp, '', $folderPath, 1); // this make sense, since $folderPath may NOT contain FULL_PATH
 
 		$base_folder = FULL_PATH . $folderPath . DIRECTORY_SEPARATOR;
 		$sub_folders = glob($base_folder . '*', GLOB_ONLYDIR);
 		if (!$sub_folders) {
 			return ;
 		}
 
 		if ($level == 0) {
 			// don't scan Front-End themes because of extensive directory structure
 			$sub_folders = array_diff($sub_folders, Array ($base_folder . 'themes', $base_folder . 'tools'));
 		}
 
 		foreach ($sub_folders as $full_path) {
 			$sub_folder = substr($full_path, strlen($base_folder));
 
 			if (in_array($sub_folder, $this->_skipFolders)) {
 				continue;
 			}
 
 			if (preg_match('/^\./', $sub_folder)) {
 				// don't scan ".folders"
 				continue;
 			}
 
 			$config_name = $this->getConfigName($folderPath . DIRECTORY_SEPARATOR . $sub_folder);
 
 			if (file_exists(FULL_PATH . $config_name)) {
 				$this->configFiles[] = $config_name;
 			}
 
 			$this->findConfigFiles($full_path, $level + 1);
 		}
 
 		/*if ($level == 0) {
 			if ($this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . FULL_PATH . $folderPath . '"): ' . (getmicrotime() - $start_time));
 			}
 		}*/
 	}
 
 	function includeConfigFiles($folderPath, $cache = true)
 	{
 		$this->Application->refreshModuleInfo();
 
 		if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 			$data = $this->Application->getCache('master:config_files', false);
 		}
 		else {
 			$data = $this->Application->getDBCache('config_files');
 		}
 
 		if ($cache && $data) {
 			$this->configFiles = unserialize($data);
 
 			if ( !defined('DBG_VALIDATE_CONFIGS') && !DBG_VALIDATE_CONFIGS ) {
 				shuffle($this->configFiles);
 			}
 		}
 		else {
 			$this->findConfigFiles(FULL_PATH . DIRECTORY_SEPARATOR . 'core'); // search from core directory
 			$this->findConfigFiles($folderPath); // search from modules directory
 		}
 
 		foreach ($this->configFiles as $filename)
 		{
 			$prefix = $this->PreloadConfigFile($filename);
 			if (!$prefix) {
 				trigger_error('Prefix not defined in config file ' . $filename, E_USER_ERROR);
 			}
 		}
 	}
 
 	/**
 	 * Process all read config files - called ONLY when there is no cache!
 	 *
 	 */
 	function ParseConfigs()
 	{
 		// 1. process normal configs and their dependencies
 		$prioritized_configs = array();
 		foreach ($this->configData as $prefix => $config) {
 			if (isset($config['ConfigPriority'])) {
 				$prioritized_configs[$prefix] = $config['ConfigPriority'];
 				continue;
 			}
 			$this->parseConfig($prefix);
 		}
 
 		foreach ($this->configData as $prefix => $config) {
 			$this->ProcessDependencies($prefix);
 			$this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
 			$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
 		}
 
 		// 2. process prioritized configs and their dependencies
 		asort($prioritized_configs);
 		foreach ($prioritized_configs as $prefix => $priority) {
 			$this->parseConfig($prefix);
 		}
 
 		foreach ($prioritized_configs as $prefix => $priority) {
 			$this->ProcessDependencies($prefix);
 		}
 	}
 
 	function AfterConfigRead($store_cache = null)
 	{
 //		if (!$this->ProcessAllConfigs) return ;
 		$this->FinalStage = true;
 		foreach ($this->configData as $prefix => $config) {
 			$this->runAfterConfigRead($prefix);
 		}
 
 		if (!isset($store_cache)) {
 			// store cache not overrided -> use global setting
 			$store_cache = $this->StoreCache;
 		}
 
 		if ($store_cache || (defined('IS_INSTALL') && IS_INSTALL)) {
 			// cache is not stored during install, but dynamic clones should be processed in any case
 			$this->processDynamicClones();
 			$this->retrieveCollections();
 		}
 
 		if ($store_cache) {
 			$this->_sortRewriteListeners();
 			$this->CacheParsedData();
 
 			if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) {
 				// validate configs here to have changes from OnAfterConfigRead hooks to prefixes
 				foreach ($this->configData as $prefix => $config) {
 					if (!isset($config['TableName'])) continue;
 					$this->ValidateConfig($prefix);
 				}
 			}
 
 			$after_event = new kEvent('adm:OnAfterCacheRebuild');
 			$this->Application->HandleEvent($after_event);
 		}
 	}
 
 	/**
 	 * Sort rewrite listeners according to RewritePriority (non-prioritized listeners goes first)
 	 *
 	 */
 	function _sortRewriteListeners()
 	{
 		$listeners = Array ();
 		$prioritized_listeners = Array ();
 
 		// process non-prioritized listeners
 		foreach ($this->Application->RewriteListeners as $prefix => $listener_data) {
 			if ($listener_data['priority'] === false) {
 				$listeners[$prefix] = $listener_data;
 			}
 			else {
 				$prioritized_listeners[$prefix] = $listener_data['priority'];
 			}
 		}
 
 		// process prioritized listeners
 		asort($prioritized_listeners, SORT_NUMERIC);
 		foreach ($prioritized_listeners as $prefix => $priority) {
 			$listeners[$prefix] = $this->Application->RewriteListeners[$prefix];
 		}
 
 		$this->Application->RewriteListeners = $listeners;
 	}
 
 	/**
 	 * Re-reads all configs
 	 *
 	 */
 	function ReReadConfigs()
 	{
 		// clear restored cache (not in db)
 		$this->Application->Factory->Files = Array ();
 		$this->Application->Factory->realClasses = Array ();
 		$this->Application->Factory->Dependencies = Array ();
 
 		$this->Application->EventManager->beforeRegularEvents = Array ();
 		$this->Application->EventManager->afterRegularEvents = Array ();
 		$this->Application->EventManager->beforeHooks = Array ();
 		$this->Application->EventManager->afterHooks = Array ();
 
 		// otherwise ModulesHelper indirectly used from includeConfigFiles won't work
 		$this->Application->RegisterDefaultClasses();
 
 		// parse all configs
 		$this->ProcessAllConfigs = true;
 		$this->AfterConfigProcessed = Array ();
 		$this->includeConfigFiles(MODULES_PATH, false);
 		$this->ParseConfigs();
 		$this->AfterConfigRead(false);
 		$this->processDynamicClones();
-		$this->retrieveCollections();
+
+		// don't call kUnitConfigReader::retrieveCollections since it
+		// will overwrite what we already have in kApplication class instance
 	}
 
 	/**
 	 * Process clones, that were defined via OnAfterConfigRead event
 	 *
 	 */
 	function processDynamicClones()
 	{
 		$new_clones = Array();
 		foreach ($this->configData as $prefix => $config) {
 			$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
 			if ($clones) {
 				$new_clones = array_merge($new_clones, $clones);
 			}
 		}
 
 		// call OnAfterConfigRead for cloned configs
 		$new_clones = array_unique($new_clones);
 		foreach ($new_clones as $prefix) {
 			$this->runAfterConfigRead($prefix);
 		}
 	}
 
 	/**
 	 * Process all collectable unit config options here to also catch ones, defined from OnAfterConfigRead events
 	 *
 	 */
 	function retrieveCollections()
 	{
 		foreach ($this->configData as $prefix => $config) {
 			// collect replacement templates
 			if (array_key_exists('ReplacementTemplates', $config) && $config['ReplacementTemplates']) {
 				$this->Application->ReplacementTemplates = array_merge($this->Application->ReplacementTemplates, $config['ReplacementTemplates']);
 			}
 
 			// collect rewrite listeners
 			if (array_key_exists('RewriteListener', $config) && $config['RewriteListener']) {
 				$rewrite_listeners = $config['RewriteListener'];
 
 				if (!is_array($rewrite_listeners)) {
 					// when one method is used to build and parse url
 					$rewrite_listeners = Array ($rewrite_listeners, $rewrite_listeners);
 				}
 
 				foreach ($rewrite_listeners as $index => $rewrite_listener) {
 					if (strpos($rewrite_listener, ':') === false) {
 						$rewrite_listeners[$index] = $prefix . '_EventHandler:' . $rewrite_listener;
 					}
 				}
 
 				$rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false;
 
 				$this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listeners, 'priority' => $rewrite_priority);
 			}
 		}
 	}
 
 	/**
 	 * Register nessasary classes
 	 * This method should only process the data which is cached!
 	 *
 	 * @param string $prefix
 	 * @access private
 	 */
 	function parseConfig($prefix)
 	{
 		$config =& $this->configData[$prefix];
 		$event_manager =& $this->Application->recallObject('EventManager');
 		/* @var $event_manager kEventManager */
 
 		$register_classes = getArrayValue($config,'RegisterClasses');
 		if (!$register_classes) $register_classes = Array();
 		$class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass');
 		foreach($class_params as $param_name)
 		{
 			if ( !(isset($config[$param_name]) ) ) continue;
 			$config[$param_name]['pseudo'] = $this->getPrefixByParamName($param_name,$prefix);
 			$register_classes[] = $config[$param_name];
 		}
 
 		foreach($register_classes as $class_info)
 		{
 			$require_classes = getArrayValue($class_info, 'require_classes');
 			if ($require_classes) {
 				if (!is_array($require_classes)) {
 					$require_classes = array($require_classes);
 				}
 				if (!isset($config['_Dependencies'][$class_info['class']])) {
 					$config['_Dependencies'][$class_info['class']] = array();
 				}
 				$config['_Dependencies'][$class_info['class']] = array_merge($config['_Dependencies'][$class_info['class']], $require_classes);
 			}
 
 			$this->Application->registerClass(
 				$class_info['class'],
 				$config['BasePath'] . DIRECTORY_SEPARATOR . $class_info['file'],
 				$class_info['pseudo']/*,
 				getArrayValue($class_info, 'require_classes')*/
 			);
 			if (getArrayValue($class_info, 'build_event')) {
 				$event_manager->registerBuildEvent($class_info['pseudo'],$class_info['build_event']);
 			}
 		}
 
 		$regular_events = getArrayValue($config, 'RegularEvents');
 		if ($regular_events) {
 			foreach ($regular_events as $short_name => $regular_event_info) {
 				$event_status = array_key_exists('Status', $regular_event_info) ? $regular_event_info['Status'] : STATUS_ACTIVE;
 				$event_manager->registerRegularEvent( $short_name, $config['Prefix'].':'.$regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'], $event_status);
 			}
 		}
 
 		$hooks = getArrayValue($config, 'Hooks');
 		if (is_array($hooks) && count($hooks) > 0) {
 			foreach ($hooks as $hook) {
 				if (isset($config['ParentPrefix']) && $hook['HookToPrefix'] == $config['ParentPrefix']) {
 					trigger_error('Depricated Hook Usage [prefix: <b>'.$config['Prefix'].'</b>; do_prefix: <b>'.$hook['DoPrefix'].'</b>] use <b>#PARENT#</b> as <b>HookToPrefix</b> value, where HookToPrefix is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE);
 				}
 
 				if ($hook['HookToPrefix'] == '') {
 					$hook['HookToPrefix'] = $config['Prefix']; // new: set hooktoprefix to current prefix if not set
 				}
 
 				if (isset($config['ParentPrefix'])) {
 					// new: allow to set hook to parent prefix what ever it is
 					if ($hook['HookToPrefix'] == '#PARENT#') {
 						$hook['HookToPrefix'] = $config['ParentPrefix'];
 					}
 
 					if ($hook['DoPrefix'] == '#PARENT#') {
 						$hook['DoPrefix'] = $config['ParentPrefix'];
 					}
 				}
 				elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') {
 					continue; // we need parent prefix but it's not set !
 				}
 
 				$do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
 
 				if ( !is_array($hook['HookToEvent']) ) {
 					$hook_events = Array( $hook['HookToEvent'] );
 				}
 				else {
 					$hook_events = $hook['HookToEvent'];
 				}
 				foreach ($hook_events as $hook_event) {
 					$this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']);
 				}
 			}
 		}
 
 		if ( is_array(getArrayValue($config, 'AggregateTags')) ) {
 			foreach ($config['AggregateTags'] as $aggregate_tag) {
 				if (isset($config['ParentPrefix'])) {
 					if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) {
 						trigger_error('Depricated Aggregate Tag Usage [prefix: <b>'.$config['Prefix'].'</b>; AggregateTo: <b>'.$aggregate_tag['AggregateTo'].'</b>] use <b>#PARENT#</b> as <b>AggregateTo</b> value, where AggregateTo is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE);
 					}
 
 					if ($aggregate_tag['AggregateTo'] == '#PARENT#') {
 						$aggregate_tag['AggregateTo'] = $config['ParentPrefix'];
 					}
 				}
 				$aggregate_tag['LocalPrefix'] = $config['Prefix'];
 				$this->Application->registerAggregateTag($aggregate_tag);
 			}
 		}
 	}
 
 	function ValidateConfig($prefix)
 	{
 		global $debugger;
 
 		$config =& $this->configData[$prefix];
 
 		$tablename = $config['TableName'];
 		$float_types = Array ('float', 'double', 'numeric');
 		$conn =& $this->Application->GetADODBConnection();
 
 		$table_found = $conn->Query('SHOW TABLES LIKE "'.$tablename.'"');
 		if (!$table_found) {
 			// config present, but table missing, strange
 			safeDefine('DBG_RAISE_ON_WARNINGS', 1);
 			$debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Table <strong>$tablename</strong> missing, but prefix <b>".$config['Prefix']."</b> requires it!");
 			$debugger->WarningCount++;
 
 			return ;
 		}
 
 		$res = $conn->Query('DESCRIBE '.$tablename);
 		$config_link = $debugger->getFileLink(FULL_PATH.$this->prefixFiles[$config['Prefix']], 1, $config['Prefix']);
 
 		$error_messages = Array (
 			'field_not_found' => 'Field <strong>%s</strong> exists in the database, but <strong>is not defined</strong> in config',
 			'default_missing' => 'Default value for field <strong>%s</strong> not set in config',
 			'not_null_error1' => 'Field <strong>%s</strong> is NOT NULL in the database, but is not configured as not_null', // or required',
 			'not_null_error2' => 'Field <strong>%s</strong> is described as NOT NULL in config, but <strong>does not have DEFAULT value</strong>',
 			'not_null_error3' => 'Field <strong>%s</strong> is described as <strong>NOT NULL in config</strong>, but is <strong>NULL in db</strong>',
 			'invalid_default' => '<strong>Default value</strong> for field %s<strong>%s</strong> not sync. to db (in config = %s, in db = %s)',
 			'date_column_not_null_error' => 'Field <strong>%s</strong> must be NULL in config and database, since it contains date',
 			'user_column_default_error' => 'Field <strong>%s</strong> must be have NULL as default value, since it holds user id',
 			'type_missing' => '<strong>Type definition</strong> for field <strong>%s</strong> missing in config',
 			'virtual_type_missing' => '<strong>Type definition</strong> for virtual field <strong>%s</strong> missing in config',
 			'virtual_default_missing' => 'Default value for virtual field <strong>%s</strong> not set in config',
 			'virtual_not_null_error' => 'Virtual field <strong>%s</strong> cannot be not null, since it doesn\'t exist in database',
 			'invalid_calculated_field' => 'Calculated field <strong>%s</strong> is missing corresponding virtual field',
 		);
 
 		$config_errors = Array ();
 		$tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix
 
 		// validate unit config field declaration in relation to database table structure
 		foreach ($res as $field) {
 			$f_name = $field['Field'];
 
 			if (getArrayValue($config, 'Fields')) {
 				if (preg_match('/l[\d]+_[\w]/', $f_name)) {
 					// skip multilingual fields
 					continue;
 				}
 
 				if (!array_key_exists ($f_name, $config['Fields'])) {
 					$config_errors[] = sprintf($error_messages['field_not_found'], $f_name);
 				}
 				else {
 					$db_default = $field['Default'];
 
 					if (is_numeric($db_default)) {
 						$db_default = preg_match('/[\.,]/', $db_default) ? (float)$db_default : (int)$db_default;
 					}
 
 					$default_missing = false;
 					$options = $config['Fields'][$f_name];
 					$not_null = isset($options['not_null']) && $options['not_null'];
 					$formatter = array_key_exists('formatter', $options) ? $options['formatter'] : false;
 
 					if (!array_key_exists('default', $options)) {
 						$config_errors[] = sprintf($error_messages['default_missing'], $f_name);
 						$default_missing = true;
 					}
 
 					if ($field['Null'] != 'YES') {
 						// field is NOT NULL in database (MySQL5 for null returns "NO", but MySQL4 returns "")
 						if ( $f_name != $config['IDField'] && !isset($options['not_null']) /*&& !isset($options['required'])*/ ) {
 							$config_errors[] = sprintf($error_messages['not_null_error1'], $f_name);
 						}
 						if ($not_null && !isset($options['default']) ) {
 							$config_errors[] = sprintf($error_messages['not_null_error2'], $f_name);
 						}
 					}
 					elseif ($not_null) {
 						$config_errors[] = sprintf($error_messages['not_null_error3'], $f_name);
 					}
 
 					if (($formatter == 'kDateFormatter') && $not_null) {
 						$config_errors[] = sprintf($error_messages['date_column_not_null_error'], $f_name);
 					}
 
 					// columns, holding userid should have NULL as default value
 					if (array_key_exists('type', $options) && !$default_missing) {
 						// both type and default value set
 
 						if (preg_match('/ById$/', $f_name) && $options['default'] !== null) {
 							$config_errors[] = sprintf($error_messages['user_column_default_error'], $f_name);
 						}
 					}
 
 					if (!array_key_exists('type', $options)) {
 						$config_errors[] = sprintf($error_messages['type_missing'], $f_name);
 					}
 
 					if (!$default_missing && ($field['Type'] != 'text')) {
 						if ( is_null($db_default) && $not_null ) {
 							$db_default = $options['type'] == 'string' ? '' : 0;
 						}
 
 						if ($f_name == $config['IDField'] && $options['type'] != 'string' && $options['default'] !== 0) {
 							$config_errors[] = sprintf($error_messages['invalid_default'], '<span class="debug_error">IDField</span> ', $f_name, $this->varDump($options['default']), $this->varDump($field['Default']));
 						}
 						else if (((string)$options['default'] != '#NOW#') && ($db_default !== $options['default']) && !in_array($options['type'], $float_types)) {
 							$config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($db_default));
 						}
 					}
 				}
 			}
 		}
 
 		// validate virtual fields
 		if ( array_key_exists('VirtualFields', $config) ) {
 			foreach ($config['VirtualFields'] as $f_name => $options) {
 				if (!array_key_exists('type', $options)) {
 					$config_errors[] = sprintf($error_messages['virtual_type_missing'], $f_name);
 				}
 
 				if (array_key_exists('not_null', $options)) {
 					$config_errors[] = sprintf($error_messages['virtual_not_null_error'], $f_name);
 				}
 
 				if (!array_key_exists('default', $options)) {
 					$config_errors[] = sprintf($error_messages['virtual_default_missing'], $f_name);
 				}
 			}
 		}
 
 		// validate calculated fields
 		if ( array_key_exists('CalculatedFields', $config) ) {
 			foreach ($config['CalculatedFields'] as $special => $calculated_fields) {
 				foreach ($calculated_fields as $calculated_field => $calculated_field_expr) {
 					if ( !isset($config['VirtualFields'][$calculated_field]) ) {
 						$config_errors[] = sprintf($error_messages['invalid_calculated_field'], $calculated_field);
 					}
 				}
 			}
 
 			$config_errors = array_unique($config_errors);
 		}
 
 		if ($config_errors) {
 			$error_prefix = '<strong class="debug_error">Config Error'.(count($config_errors) > 1 ? 's' : '').': </strong> for prefix <strong>'.$config_link.'</strong> ('.$tablename.') in unit config:<br />';
 			$config_errors = $error_prefix.'&nbsp;&nbsp;&nbsp;'.implode('<br />&nbsp;&nbsp;&nbsp;', $config_errors);
 
 			safeDefine('DBG_RAISE_ON_WARNINGS', 1);
 			$debugger->appendHTML($config_errors);
 			$debugger->WarningCount++;
 		}
 	}
 
 	function varDump($value)
 	{
 		return '<strong>'.var_export($value, true).'</strong> of '.gettype($value);
 	}
 
 	function ProcessDependencies($prefix)
 	{
 		$config =& $this->configData[$prefix];
 		$deps = getArrayValue($config, '_Dependencies');
 		if (!$deps) return ;
 
 		foreach ($deps as $real_class => $requires) {
 			foreach ($requires as $class) {
 				$this->Application->registerDependency($real_class, $class);
 			}
 		}
 		unset($config['_Dependencies']);
 	}
 
 	function postProcessConfig($prefix, $config_key, $dst_prefix_var)
 	{
 		$main_config =& $this->configData[$prefix];
 		$sub_configs = isset($main_config[$config_key]) && $main_config[$config_key] ? $main_config[$config_key] : false; // getArrayValue($main_config, $config_key);
 		if (!$sub_configs) {
 			return array();
 		}
 		unset($main_config[$config_key]);
 
 		$processed = array();
 		foreach ($sub_configs as $sub_prefix => $sub_config) {
 			if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) {
 				$this->loadConfig($sub_prefix);
 			}
 			$sub_config['Prefix'] = $sub_prefix;
 			$this->configData[$sub_prefix] = array_merge_recursive2($this->configData[$$dst_prefix_var], $sub_config);
 
 			// when merging empty array to non-empty results non-empty array, but empty is required
 			foreach ($sub_config as $sub_key => $sub_value) {
 				if (!$sub_value) {
 					unset($this->configData[$sub_prefix][$sub_key]);
 				}
 			}
 			if ($config_key == 'Clones') {
 				$this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix];
 			}
 
 			$this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var);
 			if ($config_key == 'AggregateConfigs') {
 				$processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed);
 			}
 			elseif ($this->ProcessAllConfigs) {
 				$this->parseConfig($sub_prefix);
 			}
 			array_push($processed, $sub_prefix);
 		}
 
 		if (!$prefix) {
 			// configs, that used only for cloning & not used ifself
 			unset($this->configData[$prefix]);
 		}
 		return array_unique($processed);
 	}
 
 	function PreloadConfigFile($filename)
 	{
 		$config_found = file_exists(FULL_PATH . $filename) && $this->configAllowed($filename);
 
 		if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES) {
 			if ( in_array($filename, get_required_files()) ) {
 				return;
 			}
 
 			global $debugger;
 
 			if ($config_found) {
 				$file = FULL_PATH . $filename;
 				$file_crc = crc32($file);
 
 				$debugger->ProfileStart('inc_' . $file_crc, $file);
 				include_once($file);
 				$debugger->ProfileFinish('inc_' . $file_crc);
 				$debugger->profilerAddTotal('includes', 'inc_' . $file_crc);
 			}
 		}
 		elseif ($config_found) {
 			include_once(FULL_PATH . $filename);
 		}
 
 		if ($config_found) {
 			if (isset($config) && $config) {
 				// config file is included for 1st time -> save it's content for future processing
 				$prefix = array_key_exists('Prefix', $config) ? $config['Prefix'] : '';
 
 				preg_match($this->_moduleFolderRegExp, $filename, $rets);
 				$config['ModuleFolder'] = str_replace(DIRECTORY_SEPARATOR, '/', $rets[1]);
 				$config['BasePath'] = dirname(FULL_PATH . $filename);
 
 				if (array_key_exists('AdminTemplatePath', $config)) {
 					// append template base folder for admin templates path of this prefix
 					$module_templates = $rets[1] == 'core' ? '' : substr($rets[1], 8) . '/';
 					$config['AdminTemplatePath'] = $module_templates . $config['AdminTemplatePath'];
 				}
 
 				if (array_key_exists($prefix, $this->prefixFiles) && ($this->prefixFiles[$prefix] != $filename)) {
 					trigger_error(
 						'Single unit config prefix "<strong>' . $prefix . '</strong>" ' .
 						'is used in multiple unit config files: ' .
 						'"<strong>' . $this->prefixFiles[$prefix] . '</strong>", "<strong>' . $filename . '</strong>"',
 						E_USER_WARNING
 					);
 				}
 
 				$this->configData[$prefix] = $config;
 				$this->prefixFiles[$prefix] = $filename;
 
 				return $prefix;
 			}
 			elseif ($prefix = array_search($filename, $this->prefixFiles)) {
 				// attempt is made to include config file twice or more, but include_once prevents that,
 				// but file exists on hdd, then it is already saved to all required arrays, just return it's prefix
 				return $prefix;
 			}
 		}
 
 		return 'dummy';
 	}
 
 	function loadConfig($prefix)
 	{
 		if (!isset($this->prefixFiles[$prefix])) {
 			if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
 			trigger_error('Configuration file for prefix <b>'.$prefix.'</b> is unknown', E_USER_ERROR);
 			return ;
 		}
 		$file = $this->prefixFiles[$prefix];
 		$prefix = $this->PreloadConfigFile($file);
 
 		if ($this->FinalStage) {
 			// run prefix OnAfterConfigRead so all
 			// hooks to it can define their clonses
 			$this->runAfterConfigRead($prefix);
 		}
 
 		$clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
 		$clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones);
 
 		if ($this->FinalStage) {
 			$clones = array_unique($clones);
 			foreach ($clones as $a_prefix) {
 				$this->runAfterConfigRead($a_prefix);
 			}
 		}
 	}
 
 	function runAfterConfigRead($prefix)
 	{
 		if (in_array($prefix, $this->AfterConfigProcessed)) {
 			return ;
 		}
 
 		$this->Application->HandleEvent( new kEvent($prefix . ':OnAfterConfigRead') );
 
 		if (!(defined('IS_INSTALL') && IS_INSTALL)) {
 			// allow to call OnAfterConfigRead multiple times during install
 			array_push($this->AfterConfigProcessed, $prefix);
 		}
 	}
 
 	/**
 	 * Reads unit (specified by $prefix)
 	 * option specified by $option
 	 *
 	 * @param string $prefix
 	 * @param string $name
 	 * @param mixed $default
 	 * @return string
 	 * @access public
 	 */
 	function getUnitOption($prefix, $name, $default = false)
 	{
 		if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
 			if (!isset($this->configData[$rets[1]])) {
 				$this->loadConfig($rets[1]);
 			}
 			$ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false;
 //			$ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]);
 		}
 		else {
 			if (!isset($this->configData[$prefix])) {
 				$this->loadConfig($prefix);
 			}
 			$ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false;
 //			$ret = getArrayValue($this->configData, $prefix, $name);
 		}
 		return $ret === false ? $default : $ret;
 	}
 
 	/**
 	 * Read all unit with $prefix options
 	 *
 	 * @param string $prefix
 	 * @return Array
 	 * @access public
 	 */
 	function getUnitOptions($prefix)
 	{
 		if (!isset($this->configData[$prefix])) {
 			$this->loadConfig($prefix);
 		}
 
 		return $this->configData[$prefix];
 	}
 
 	/**
 	 * Set's new unit option value
 	 *
 	 * @param string $prefix
 	 * @param string $name
 	 * @param string $value
 	 * @access public
 	 */
 	function setUnitOption($prefix, $name, $value)
 	{
 		if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
 			if (!isset($this->configData[$rets[1]])) {
 				$this->loadConfig($rets[1]);
 			}
 			$this->configData[$rets[1]][$name][$rets[2]] = $value;
 		}
 		else {
 			if (!isset($this->configData[$prefix])) {
 				$this->loadConfig($prefix);
 			}
 			$this->configData[$prefix][$name] = $value;
 		}
 
 	}
 
 	function getPrefixByParamName($paramName,$prefix)
 	{
 		$pseudo_class_map=Array(
 		'ItemClass'=>'%s',
 		'ListClass'=>'%s_List',
 		'EventHandlerClass'=>'%s_EventHandler',
 		'TagProcessorClass'=>'%s_TagProcessor'
 		);
 		return sprintf($pseudo_class_map[$paramName],$prefix);
 	}
 
 	/**
 	 * Get's config file name based
 	 * on folder name supplied
 	 *
 	 * @param string $folderPath
 	 * @return string
 	 * @access private
 	 */
 	function getConfigName($folderPath)
 	{
 		return $folderPath . DIRECTORY_SEPARATOR . basename($folderPath) . '_config.php';
 	}
 
 	/**
 	 * Checks if config file is allowed for includion (if module of config is installed)
 	 *
 	 * @param string $config_path relative path from in-portal directory
 	 */
 	function configAllowed($config_path)
 	{
 		static $module_paths = null;
 
 		if (defined('IS_INSTALL') && IS_INSTALL) {
 			// at installation start no modules in db and kernel configs could not be read
 			return true;
 		}
 
 		if (preg_match('#^' . $this->_directorySeparator . 'core#', $config_path)) {
 			// always allow to include configs from "core" module's folder
 			return true;
 		}
 
 		if (!$this->Application->ModuleInfo) {
 			return false;
 		}
 
 		if (!isset($module_paths)) {
 			$module_paths = Array ();
 
 			foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
 				$module_paths[] = str_replace('/', DIRECTORY_SEPARATOR, rtrim($module_info['Path'], '/'));
 			}
 
 			$module_paths = array_unique($module_paths);
 		}
 
 		preg_match($this->_moduleFolderRegExp, $config_path, $rets);
 
 		// config file path starts with module folder path
 		return in_array($rets[1], $module_paths);
 	}
 
 	/**
 	 * Returns true if config exists and is allowed for reading
 	 *
 	 * @param string $prefix
 	 * @return bool
 	 */
 	function prefixRegistred($prefix)
 	{
 		return isset($this->prefixFiles[$prefix]) ? true : false;
 	}
 
 	/**
 	 * Returns config file for given prefix
 	 *
 	 * @param string $prefix
 	 * @return string
 	 */
 	function getPrefixFile($prefix)
 	{
 		return array_key_exists($prefix, $this->prefixFiles) ? $this->prefixFiles[$prefix] : false;
 	}
 
 	function iterateConfigs($callback_function, $params)
 	{
 		$this->includeConfigFiles(MODULES_PATH); //make sure to re-read all configs
 		$this->AfterConfigRead();
 
 		foreach ($this->configData as $prefix => $config_data) {
 			$callback_function[0]->$callback_function[1]($prefix, $config_data, $params);
 		}
 	}
 
 }
\ No newline at end of file
Index: branches/5.1.x/core/units/site_domains/site_domain_eh.php
===================================================================
--- branches/5.1.x/core/units/site_domains/site_domain_eh.php	(revision 13988)
+++ branches/5.1.x/core/units/site_domains/site_domain_eh.php	(revision 13989)
@@ -1,258 +1,259 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2010 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class SiteDomainEventHandler extends kDBEventHandler {
 
 		/**
-		 * Allows to override standart permission mapping
+		 * Permission check override
 		 *
+		 * @param kEvent $event
 		 */
-		function mapPermissions()
+		function CheckPermission(&$event)
 		{
-			parent::mapPermissions();
-
-			$permissions = Array (
-				'OnItemBuild' => Array ('self' => true),
-			);
+			if ($event->Name == 'OnItemBuild') {
+				// check permission without using $event->getSection(),
+				// so first cache rebuild won't lead to "ldefault_Name" field being used
+				return true;
+			}
 
-			$this->permMapping = array_merge($this->permMapping, $permissions);
+			return parent::CheckPermission($event);
 		}
 
 		/**
 		 * Returns ID of site domain, that matches current url
 		 *
 		 * @param kEvent $event
 		 */
 		function getPassedID(&$event)
 		{
 			if ($event->Special == 'current') {
 				if ($this->Application->isAdmin) {
 					$event->setEventParam('raise_warnings', 0);
 				}
 				else {
 					if (PROTOCOL == 'https://') {
 						return $this->querySiteDomain('SSLUrl', rtrim($this->Application->BaseURL(), '/'));
 					}
 
 					return $this->querySiteDomain('DomainName', $_SERVER['HTTP_HOST']);
 				}
 			}
 
 			return parent::getPassedID($event);
 		}
 
 		function querySiteDomain($field, $value)
 		{
 			$site_helper =& $this->Application->recallObject('SiteHelper');
 			/* @var $site_helper SiteHelper */
 
 			$site_domains = $site_helper->getSiteDomains();
 			$domain_by_name = $site_helper->getDomainByName($field, $value);
 			$domain_by_ip = $site_helper->getDomainByIP();
 
 			if ($domain_by_ip) {
 				$site_domain = $site_domains[$domain_by_ip];
 				$redirect_mode = $site_domain['RedirectOnIPMatch'];
 
 				if (($redirect_mode == SITE_DOMAIN_REDIRECT_EXTERNAL) && ($domain_by_ip == $domain_by_name)) {
 					// redirect to external url (when visiting protected domain)
 					$external_url = $site_domain['ExternalUrl'];
 
 					if (preg_match('/^http[s]{0,1}:\/\//', $external_url)) {
 						$this->Application->Redirect('external:' . $external_url);
 					}
 					else {
 						$this->Application->Redirect('external:' . PROTOCOL . $external_url . $_SERVER['REQUEST_URI']);
 					}
 				}
 				elseif (($redirect_mode == SITE_DOMAIN_REDIRECT_CURRENT) && ($domain_by_ip != $domain_by_name)) {
 					// redirect to a domain detected by IP (when not already on it)
 					if ((PROTOCOL == 'https://') && !$site_domain['SSLUrlUsesRegExp'] && $site_domain['SSLUrl']) {
 						// need to remove sub folder from ssl url
 						$ssl_url = preg_replace('/^(https:\/\/[^\/]*)(\/.*){0,1}$/', '\\1', $site_domain['SSLUrl']);
 						$this->Application->Redirect('external:' . $ssl_url . $_SERVER['REQUEST_URI']);
 					}
 					elseif ((PROTOCOL == 'http://') && !$site_domain['DomainNameUsesRegExp']) {
 						$this->Application->Redirect('external:http://' . $site_domain['DomainName'] . $_SERVER['REQUEST_URI']);
 					}
 				}
 
 				return $domain_by_ip;
 			}
 
 			return $domain_by_name;
 		}
 
 		/**
 		 * Load item if id is available
 		 *
 		 * @param kEvent $event
 		 */
 		function LoadItem(&$event)
 		{
 			if ($this->Application->isAdmin) {
 				// don't load domain data from cache
 				parent::LoadItem($event);
 
 				return ;
 			}
 
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$id = (int)$this->getPassedID($event);
 
 			if ($object->isLoaded() && ($object->GetID() == $id)) {
 				// object is already loaded by same id
 				return ;
 			}
 
 			$site_helper =& $this->Application->recallObject('SiteHelper');
 			/* @var $site_helper SiteHelper */
 
 			$site_domains = $site_helper->getSiteDomains();
 			$domain_data = array_key_exists($id, $site_domains) ? $site_domains[$id] : false;
 
 			if ($object->LoadFromHash($domain_data)) {
 				$actions =& $this->Application->recallObject('kActions');
 				$actions->Set($event->Prefix_Special.'_id', $object->GetID() );
 			}
 			else {
 				$object->setID($id);
 			}
 		}
 
 		/**
 		 * Removes In-Commerce related fields, when it's not installed
 		 *
 		 * @param kEvent $event
 		 */
 		function OnAfterConfigRead(&$event)
 		{
 			parent::OnAfterConfigRead($event);
 
 			if (!$this->Application->isModuleEnabled('In-Commerce')) {
 				$remove_fields = Array (
 					'BillingCountry', 'ShippingCountry',
 					'PrimaryCurrencyId', 'Currencies',
 					'PrimaryPaymentTypeId', 'PaymentTypes'
 				);
 
 				// remove field definitions
 				$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
 
 				foreach ($remove_fields as $remove_field) {
 					unset($fields[$remove_field]);
 				}
 
 				$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
 
 				// remove grid columns
 				$grids = $this->Application->getUnitOption($event->Prefix, 'Grids');
 
 				foreach ($grids as $grid_name => $grid_info) {
 					foreach ($remove_fields as $remove_field) {
 						if (array_key_exists($remove_field, $grid_info['Fields'])) {
 							unset($grids[$grid_name]['Fields'][$remove_field]);
 						}
 					}
 				}
 
 				$this->Application->setUnitOption($event->Prefix, 'Grids', $grids);
 			}
 		}
 
 		/**
 		 * Delete cached information about site domains
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSave(&$event)
 		{
 			parent::OnSave($event);
 
 			if ($event->status == erSUCCESS) {
 				$this->_deleteCache();
 			}
 		}
 
 		/**
 		 * Deletes cached information about site domains
 		 */
 		function _deleteCache()
 		{
 			if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
 				$this->Application->deleteCache('master:domains_parsed');
 			}
 			else {
 				$this->Application->deleteDBCache('domains_parsed');
 			}
 
 			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls';
 			$this->Conn->Query($sql);
 		}
 
 		/**
 		 * Set's required fields based on redirect mode
 		 *
 		 * @param kEvent $event
 		 */
 		function OnAfterItemLoad(&$event)
 		{
 			parent::OnAfterItemLoad($event);
 
 			$this->_setRequired($event);
 		}
 
 		/**
 		 * Set's required fields based on redirect mode
 		 *
 		 * @param kEvent $event
 		 */
 		function OnBeforeItemCreate(&$event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$this->_setRequired($event);
 		}
 
 		/**
 		 * Set's required fields based on redirect mode
 		 *
 		 * @param kEvent $event
 		 */
 		function OnBeforeItemUpdate(&$event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$this->_setRequired($event);
 		}
 
 		/**
 		 * Set's required fields
 		 *
 		 * @param kEvent $event
 		 */
 		function _setRequired(&$event)
 		{
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$redirect_mode = $object->GetDBField('RedirectOnIPMatch');
 			$object->setRequired('ExternalUrl', $redirect_mode == SITE_DOMAIN_REDIRECT_EXTERNAL);
 			$object->setRequired('DomainIPRange', $redirect_mode > 0);
 		}
 	}