<?php
/**
* @version	$Id: upgrades.php 14327 2011-05-20 08:14:24Z alex $
* @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!');

	$upgrade_class = 'CoreUpgrades';

	/**
	 * Class, that holds all upgrade scripts for "Core" module
	 *
	 */
	class CoreUpgrades extends kUpgradeHelper {

		/**
		 * Changes table structure, where multilingual fields of TEXT type are present
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_1_0($mode)
		{
			if ($mode == 'before') {
				// don't user after, because In-Portal calls this method too
				$this->_toolkit->SaveConfig();
			}

			if ($mode == 'after') {
				$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
				/* @var $ml_helper kMultiLanguageHelper */

				$lang_count = $ml_helper->getLanguageCount();
				$this->Application->UnitConfigReader->iterateConfigs(Array (&$this, 'updateTextFields'), $lang_count);
			}
		}

		/**
		 * Moves ReplacementTags functionality from EmailMessage to Events table
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_1_1($mode)
		{
			if ($mode == 'after') {
				$sql = 'SELECT ReplacementTags, EventId
						FROM '.TABLE_PREFIX.'EmailMessage
						WHERE (ReplacementTags IS NOT NULL) AND (ReplacementTags <> "") AND (LanguageId = 1)';
				$replacement_tags = $this->Conn->GetCol($sql, 'EventId');

				foreach ($replacement_tags as $event_id => $replacement_tag) {
					$sql = 'UPDATE '.TABLE_PREFIX.'Events
							SET ReplacementTags = '.$this->Conn->qstr($replacement_tag).'
							WHERE EventId = '.$event_id;
					$this->Conn->Query($sql);
				}

				// drop moved field from source table
				$sql = 'ALTER TABLE '.TABLE_PREFIX.'EmailMessage
						DROP `ReplacementTags`';
				$this->Conn->Query($sql);
			}
		}

		/**
		 * Callback function, that makes all ml fields of text type null with same default value
		 *
		 * @param string $prefix
		 * @param Array $config_data
		 * @param int $language_count
		 * @return bool
		 */
		function updateTextFields($prefix, &$config_data, $language_count)
		{
			if (!isset($config_data['TableName']) || !isset($config_data['Fields'])) {
				// invalid config found or prefix not found
				return false;
			}

			$table_name = $config_data['TableName'];
			$table_structure = $this->Conn->Query('DESCRIBE '.$table_name, 'Field');
			if (!$table_structure) {
				// table not found
				return false;
			}

			$sqls = Array ();
			foreach ($config_data['Fields'] as $field => $options) {
				if (isset($options['formatter']) && $options['formatter'] == 'kMultiLanguage' && !isset($options['master_field'])) {
					// update all l<lang_id>_<field_name> fields (new format)
					for ($i = 1; $i <= $language_count; $i++) {
						$ml_field = 'l'.$i.'_'.$field;
						if ($table_structure[$ml_field]['Type'] == 'text') {
							$sqls[] = 'CHANGE '.$ml_field.' '.$ml_field.' TEXT NULL DEFAULT NULL';
						}
					}

					// update <field_name> if found (old format)
					if (isset($table_structure[$field]) && $table_structure[$field]['Type'] == 'text') {
						$sqls[] = 'CHANGE '.$field.' '.$field.' TEXT NULL DEFAULT NULL';
					}
				}
			}

			if ($sqls) {
				$sql = 'ALTER TABLE '.$table_name.' '.implode(', ', $sqls);
				$this->Conn->Query($sql);
			}

			return true;
		}

		/**
		 * Replaces In-Portal tags in Forgot Password related email events to K4 ones
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_2_0($mode)
		{
			if ($mode == 'after') {
				// 1. get event ids based on their name and type combination
				$event_names = Array (
					'USER.PSWD_'.EVENT_TYPE_ADMIN,
					'USER.PSWD_'.EVENT_TYPE_FRONTEND,
					'USER.PSWDC_'.EVENT_TYPE_FRONTEND,
				);

				$event_sql = Array ();
				foreach ($event_names as $mixed_event) {
					list ($event_name, $event_type) = explode('_', $mixed_event, 2);
					$event_sql[] = 'Event = "'.$event_name.'" AND Type = '.$event_type;
				}

				$sql = 'SELECT EventId
						FROM '.TABLE_PREFIX.'Events
						WHERE ('.implode(') OR (', $event_sql).')';
				$event_ids = implode(',', $this->Conn->GetCol($sql));

				// 2. replace In-Portal tags to K4 tags
				$replacements = Array (
					'<inp:touser _Field="Password" />' => '<inp2:u_ForgottenPassword />',
					'<inp:m_confirm_password_link />' => '<inp2:u_ConfirmPasswordLink no_amp="1"/>',
				);

				foreach ($replacements as $old_tag => $new_tag) {
					$sql = 'UPDATE '.TABLE_PREFIX.'EmailMessage
							SET Template = REPLACE(Template, '.$this->Conn->qstr($old_tag).', '.$this->Conn->qstr($new_tag).')
							WHERE EventId IN ('.$event_ids.')';
					$this->Conn->Query($sql);
				}

			}
		}

		/**
		 * Makes admin primary language same as front-end - not needed, done in SQL
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_2_1($mode)
		{

		}

		function Upgrade_4_2_2($mode)
		{
			if ($mode == 'before') {
				if ($this->Conn->GetOne('SELECT LanguageId FROM '.TABLE_PREFIX.'Language WHERE PrimaryLang = 1')) return ;
				$this->Conn->Query('UPDATE '.TABLE_PREFIX.'Language SET PrimaryLang = 1 ORDER BY LanguageId LIMIT 1');
			}
		}

		/**
		 * Adds index to "dob" field in "PortalUser" table when it's missing
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_3_1($mode)
		{
			if ($mode == 'after') {
				$sql = 'DESCRIBE ' . TABLE_PREFIX . 'PortalUser';
				$structure = $this->Conn->Query($sql);

				foreach ($structure as $field_info) {
					if ($field_info['Field'] == 'dob') {
						if (!$field_info['Key']) {
							$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'PortalUser
									ADD INDEX (dob)';
							$this->Conn->Query($sql);
						}
						break;
					}
				}
			}
		}

		/**
		 * Removes duplicate phrases, update file paths in database
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_4_3_9($mode)
		{
			// 1. find In-Portal old <inp: tags
			$sql = 'SELECT EmailMessageId
					FROM '.TABLE_PREFIX.'EmailMessage
					WHERE Template LIKE \'%<inp:%\'';
			$event_ids = implode(',', $this->Conn->GetCol($sql));

			// 2. replace In-Portal old <inp: tags to K4 tags
			$replacements = Array (
				'<inp:m_category_field _Field="Name" _StripHTML="1"' => '<inp2:c_Field name="Name"',
				'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
				'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Login"',
				'<inp:touser _Field="' => '<inp2:u_Field name="',
				'<inp:m_page_title' => '<inp2:m_BaseUrl',
				'<inp:m_theme_url _page="current"' => '<inp2:m_BaseUrl',
				'<inp:topic _field="text"' => '<inp2:bb-post_Field name="PostingText"',
				'<inp:topic _field="link" _Template="inbulletin/post_list"' => '<inp2:bb_TopicLink template="__default__"',
			);

			if ($event_ids) {
				foreach ($replacements as $old_tag => $new_tag) {
					$sql = 'UPDATE '.TABLE_PREFIX.'EmailMessage
							SET Template = REPLACE(Template, '.$this->Conn->qstr($old_tag).', '.$this->Conn->qstr($new_tag).')
							WHERE EventId IN ('.$event_ids.')';
					$this->Conn->Query($sql);
				}
			}

			if ($mode == 'after') {
				$this->_insertInPortalData();
				$this->_moveDatabaseFolders();

				// in case, when In-Portal module is enabled -> turn AdvancedUserManagement on too
				if ($this->Application->findModule('Name', 'In-Portal')) {
					$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationValues
							SET VariableValue = 1
							WHERE VariableName = "AdvancedUserManagement"';
					$this->Conn->Query($sql);
				}
			}

			if ($mode == 'languagepack') {
				$this->_removeDuplicatePhrases();
			}
		}

		function _insertInPortalData()
		{
			$data = Array (
				'ConfigurationAdmin' => Array (
					'UniqueField' => 'VariableName',
					'Records' => Array (
						'AllowDeleteRootCats' => "('AllowDeleteRootCats', 'la_Text_General', 'la_AllowDeleteRootCats', 'checkbox', NULL , NULL , 10.09, 0, 0)",
						'Catalog_PreselectModuleTab' => "('Catalog_PreselectModuleTab', 'la_Text_General', 'la_config_CatalogPreselectModuleTab', 'checkbox', NULL, NULL, 10.10, 0, 1)",
						'RecycleBinFolder' => "('RecycleBinFolder', 'la_Text_General', 'la_config_RecycleBinFolder', 'text', NULL , NULL , 10.11, 0, 0)",
						'AdvancedUserManagement' => "('AdvancedUserManagement', 'la_Text_General', 'la_prompt_AdvancedUserManagement', 'checkbox', NULL, NULL, '10.011', 0, 1)",
					),
				),

				'ConfigurationValues' => Array (
					'UniqueField' => 'VariableName',
					'Records' => Array (
						'AdvancedUserManagement' => "(DEFAULT, 'AdvancedUserManagement', 0, 'In-Portal:Users', 'in-portal:configure_users')",
					),
				),

				'ItemTypes' => Array (
					'UniqueField' => 'ItemType',
					'Records' => Array (
						'1' => "(1, 'In-Portal', 'c', 'Category', 'Name', 'CreatedById', NULL, NULL, 'la_ItemTab_Categories', 1, 'admin/category/addcategory.php', 'clsCategory', 'Category')",
						'6' => "(6, 'In-Portal', 'u', 'PortalUser', 'Login', 'PortalUserId', NULL, NULL, '', 0, '', 'clsPortalUser', 'User')",
					),
				),

				'PermissionConfig' => Array (
					'UniqueField' => 'PermissionName',
					'Records' => Array (
						'CATEGORY.ADD' => "(DEFAULT, 'CATEGORY.ADD', 'lu_PermName_Category.Add_desc', 'lu_PermName_Category.Add_error', 'In-Portal')",
						'CATEGORY.DELETE' => "(DEFAULT, 'CATEGORY.DELETE', 'lu_PermName_Category.Delete_desc', 'lu_PermName_Category.Delete_error', 'In-Portal')",
						'CATEGORY.ADD.PENDING' => "(DEFAULT, 'CATEGORY.ADD.PENDING', 'lu_PermName_Category.AddPending_desc', 'lu_PermName_Category.AddPending_error', 'In-Portal')",
						'CATEGORY.MODIFY' => "(DEFAULT, 'CATEGORY.MODIFY', 'lu_PermName_Category.Modify_desc', 'lu_PermName_Category.Modify_error', 'In-Portal')",
						'ADMIN' => "(DEFAULT, 'ADMIN', 'lu_PermName_Admin_desc', 'lu_PermName_Admin_error', 'Admin')",
						'LOGIN' => "(DEFAULT, 'LOGIN', 'lu_PermName_Login_desc', 'lu_PermName_Admin_error', 'Front')",
						'DEBUG.ITEM' => "(DEFAULT, 'DEBUG.ITEM', 'lu_PermName_Debug.Item_desc', '', 'Admin')",
						'DEBUG.LIST' => "(DEFAULT, 'DEBUG.LIST', 'lu_PermName_Debug.List_desc', '', 'Admin')",
						'DEBUG.INFO' => "(DEFAULT, 'DEBUG.INFO', 'lu_PermName_Debug.Info_desc', '', 'Admin')",
						'PROFILE.MODIFY' => "(DEFAULT, 'PROFILE.MODIFY', 'lu_PermName_Profile.Modify_desc', '', 'Admin')",
						'SHOWLANG' => "(DEFAULT, 'SHOWLANG', 'lu_PermName_ShowLang_desc', '', 'Admin')",
						'FAVORITES' => "(DEFAULT, 'FAVORITES', 'lu_PermName_favorites_desc', 'lu_PermName_favorites_error', 'In-Portal')",
						'SYSTEM_ACCESS.READONLY' => "(DEFAULT, 'SYSTEM_ACCESS.READONLY', 'la_PermName_SystemAccess.ReadOnly_desc', 'la_PermName_SystemAccess.ReadOnly_error', 'Admin')",
					),
				),

				'Permissions' => Array (
					'UniqueField' => 'Permission;GroupId;Type;CatId',
					'Records' => Array (
						'LOGIN;12;1;0' => "(DEFAULT, 'LOGIN', 12, 1, 1, 0)",
						'in-portal:site.view;11;1;0' => "(DEFAULT, 'in-portal:site.view', 11, 1, 1, 0)",
						'in-portal:browse.view;11;1;0' => "(DEFAULT, 'in-portal:browse.view', 11, 1, 1, 0)",
						'in-portal:advanced_view.view;11;1;0' => "(DEFAULT, 'in-portal:advanced_view.view', 11, 1, 1, 0)",
						'in-portal:reviews.view;11;1;0' => "(DEFAULT, 'in-portal:reviews.view', 11, 1, 1, 0)",
						'in-portal:configure_categories.view;11;1;0' => "(DEFAULT, 'in-portal:configure_categories.view', 11, 1, 1, 0)",
						'in-portal:configure_categories.edit;11;1;0' => "(DEFAULT, 'in-portal:configure_categories.edit', 11, 1, 1, 0)",
						'in-portal:configuration_search.view;11;1;0' => "(DEFAULT, 'in-portal:configuration_search.view', 11, 1, 1, 0)",
						'in-portal:configuration_search.edit;11;1;0' => "(DEFAULT, 'in-portal:configuration_search.edit', 11, 1, 1, 0)",
						'in-portal:configuration_email.view;11;1;0' => "(DEFAULT, 'in-portal:configuration_email.view', 11, 1, 1, 0)",
						'in-portal:configuration_email.edit;11;1;0' => "(DEFAULT, 'in-portal:configuration_email.edit', 11, 1, 1, 0)",
						'in-portal:configuration_custom.view;11;1;0' => "(DEFAULT, 'in-portal:configuration_custom.view', 11, 1, 1, 0)",
						'in-portal:configuration_custom.add;11;1;0' => "(DEFAULT, 'in-portal:configuration_custom.add', 11, 1, 1, 0)",
						'in-portal:configuration_custom.edit;11;1;0' => "(DEFAULT, 'in-portal:configuration_custom.edit', 11, 1, 1, 0)",
						'in-portal:configuration_custom.delete;11;1;0' => "(DEFAULT, 'in-portal:configuration_custom.delete', 11, 1, 1, 0)",
						'in-portal:users.view;11;1;0' => "(DEFAULT, 'in-portal:users.view', 11, 1, 1, 0)",
						'in-portal:user_list.advanced:ban;11;1;0' => "(DEFAULT, 'in-portal:user_list.advanced:ban', 11, 1, 1, 0)",
						'in-portal:user_list.advanced:send_email;11;1;0' => "(DEFAULT, 'in-portal:user_list.advanced:send_email', 11, 1, 1, 0)",
						'in-portal:user_groups.view;11;1;0' => "(DEFAULT, 'in-portal:user_groups.view', 11, 1, 1, 0)",
						'in-portal:user_groups.add;11;1;0' => "(DEFAULT, 'in-portal:user_groups.add', 11, 1, 1, 0)",
						'in-portal:user_groups.edit;11;1;0' => "(DEFAULT, 'in-portal:user_groups.edit', 11, 1, 1, 0)",
						'in-portal:user_groups.delete;11;1;0' => "(DEFAULT, 'in-portal:user_groups.delete', 11, 1, 1, 0)",
						'in-portal:user_groups.advanced:send_email;11;1;0' => "(DEFAULT, 'in-portal:user_groups.advanced:send_email', 11, 1, 1, 0)",
						'in-portal:user_groups.advanced:manage_permissions;11;1;0' => "(DEFAULT, 'in-portal:user_groups.advanced:manage_permissions', 11, 1, 1, 0)",
						'in-portal:configure_users.view;11;1;0' => "(DEFAULT, 'in-portal:configure_users.view', 11, 1, 1, 0)",
						'in-portal:configure_users.edit;11;1;0' => "(DEFAULT, 'in-portal:configure_users.edit', 11, 1, 1, 0)",
						'in-portal:user_email.view;11;1;0' => "(DEFAULT, 'in-portal:user_email.view', 11, 1, 1, 0)",
						'in-portal:user_email.edit;11;1;0' => "(DEFAULT, 'in-portal:user_email.edit', 11, 1, 1, 0)",
						'in-portal:user_custom.view;11;1;0' => "(DEFAULT, 'in-portal:user_custom.view', 11, 1, 1, 0)",
						'in-portal:user_custom.add;11;1;0' => "(DEFAULT, 'in-portal:user_custom.add', 11, 1, 1, 0)",
						'in-portal:user_custom.edit;11;1;0' => "(DEFAULT, 'in-portal:user_custom.edit', 11, 1, 1, 0)",
						'in-portal:user_custom.delete;11;1;0' => "(DEFAULT, 'in-portal:user_custom.delete', 11, 1, 1, 0)",
						'in-portal:user_banlist.view;11;1;0' => "(DEFAULT, 'in-portal:user_banlist.view', 11, 1, 1, 0)",
						'in-portal:user_banlist.add;11;1;0' => "(DEFAULT, 'in-portal:user_banlist.add', 11, 1, 1, 0)",
						'in-portal:user_banlist.edit;11;1;0' => "(DEFAULT, 'in-portal:user_banlist.edit', 11, 1, 1, 0)",
						'in-portal:user_banlist.delete;11;1;0' => "(DEFAULT, 'in-portal:user_banlist.delete', 11, 1, 1, 0)",
						'in-portal:reports.view;11;1;0' => "(DEFAULT, 'in-portal:reports.view', 11, 1, 1, 0)",
						'in-portal:log_summary.view;11;1;0' => "(DEFAULT, 'in-portal:log_summary.view', 11, 1, 1, 0)",
						'in-portal:searchlog.view;11;1;0' => "(DEFAULT, 'in-portal:searchlog.view', 11, 1, 1, 0)",
						'in-portal:searchlog.delete;11;1;0' => "(DEFAULT, 'in-portal:searchlog.delete', 11, 1, 1, 0)",
						'in-portal:sessionlog.view;11;1;0' => "(DEFAULT, 'in-portal:sessionlog.view', 11, 1, 1, 0)",
						'in-portal:sessionlog.delete;11;1;0' => "(DEFAULT, 'in-portal:sessionlog.delete', 11, 1, 1, 0)",
						'in-portal:emaillog.view;11;1;0' => "(DEFAULT, 'in-portal:emaillog.view', 11, 1, 1, 0)",
						'in-portal:emaillog.delete;11;1;0' => "(DEFAULT, 'in-portal:emaillog.delete', 11, 1, 1, 0)",
						'in-portal:visits.view;11;1;0' => "(DEFAULT, 'in-portal:visits.view', 11, 1, 1, 0)",
						'in-portal:visits.delete;11;1;0' => "(DEFAULT, 'in-portal:visits.delete', 11, 1, 1, 0)",
						'in-portal:configure_general.view;11;1;0' => "(DEFAULT, 'in-portal:configure_general.view', 11, 1, 1, 0)",
						'in-portal:configure_general.edit;11;1;0' => "(DEFAULT, 'in-portal:configure_general.edit', 11, 1, 1, 0)",
						'in-portal:modules.view;11;1;0' => "(DEFAULT, 'in-portal:modules.view', 11, 1, 1, 0)",
						'in-portal:mod_status.view;11;1;0' => "(DEFAULT, 'in-portal:mod_status.view', 11, 1, 1, 0)",
						'in-portal:mod_status.edit;11;1;0' => "(DEFAULT, 'in-portal:mod_status.edit', 11, 1, 1, 0)",
						'in-portal:mod_status.advanced:approve;11;1;0' => "(DEFAULT, 'in-portal:mod_status.advanced:approve', 11, 1, 1, 0)",
						'in-portal:mod_status.advanced:decline;11;1;0' => "(DEFAULT, 'in-portal:mod_status.advanced:decline', 11, 1, 1, 0)",
						'in-portal:addmodule.view;11;1;0' => "(DEFAULT, 'in-portal:addmodule.view', 11, 1, 1, 0)",
						'in-portal:addmodule.add;11;1;0' => "(DEFAULT, 'in-portal:addmodule.add', 11, 1, 1, 0)",
						'in-portal:addmodule.edit;11;1;0' => "(DEFAULT, 'in-portal:addmodule.edit', 11, 1, 1, 0)",
						'in-portal:tag_library.view;11;1;0' => "(DEFAULT, 'in-portal:tag_library.view', 11, 1, 1, 0)",
						'in-portal:configure_themes.view;11;1;0' => "(DEFAULT, 'in-portal:configure_themes.view', 11, 1, 1, 0)",
						'in-portal:configure_themes.add;11;1;0' => "(DEFAULT, 'in-portal:configure_themes.add', 11, 1, 1, 0)",
						'in-portal:configure_themes.edit;11;1;0' => "(DEFAULT, 'in-portal:configure_themes.edit', 11, 1, 1, 0)",
						'in-portal:configure_themes.delete;11;1;0' => "(DEFAULT, 'in-portal:configure_themes.delete', 11, 1, 1, 0)",
						'in-portal:configure_styles.view;11;1;0' => "(DEFAULT, 'in-portal:configure_styles.view', 11, 1, 1, 0)",
						'in-portal:configure_styles.add;11;1;0' => "(DEFAULT, 'in-portal:configure_styles.add', 11, 1, 1, 0)",
						'in-portal:configure_styles.edit;11;1;0' => "(DEFAULT, 'in-portal:configure_styles.edit', 11, 1, 1, 0)",
						'in-portal:configure_styles.delete;11;1;0' => "(DEFAULT, 'in-portal:configure_styles.delete', 11, 1, 1, 0)",
						'in-portal:configure_lang.advanced:set_primary;11;1;0' => "(DEFAULT, 'in-portal:configure_lang.advanced:set_primary', 11, 1, 1, 0)",
						'in-portal:configure_lang.advanced:import;11;1;0' => "(DEFAULT, 'in-portal:configure_lang.advanced:import', 11, 1, 1, 0)",
						'in-portal:configure_lang.advanced:export;11;1;0' => "(DEFAULT, 'in-portal:configure_lang.advanced:export', 11, 1, 1, 0)",
						'in-portal:tools.view;11;1;0' => "(DEFAULT, 'in-portal:tools.view', 11, 1, 1, 0)",
						'in-portal:backup.view;11;1;0' => "(DEFAULT, 'in-portal:backup.view', 11, 1, 1, 0)",
						'in-portal:restore.view;11;1;0' => "(DEFAULT, 'in-portal:restore.view', 11, 1, 1, 0)",
						'in-portal:export.view;11;1;0' => "(DEFAULT, 'in-portal:export.view', 11, 1, 1, 0)",
						'in-portal:main_import.view;11;1;0' => "(DEFAULT, 'in-portal:main_import.view', 11, 1, 1, 0)",
						'in-portal:sql_query.view;11;1;0' => "(DEFAULT, 'in-portal:sql_query.view', 11, 1, 1, 0)",
						'in-portal:sql_query.edit;11;1;0' => "(DEFAULT, 'in-portal:sql_query.edit', 11, 1, 1, 0)",
						'in-portal:server_info.view;11;1;0' => "(DEFAULT, 'in-portal:server_info.view', 11, 1, 1, 0)",
						'in-portal:help.view;11;1;0' => "(DEFAULT, 'in-portal:help.view', 11, 1, 1, 0)",
					),
				),

				'SearchConfig' => Array (
					'UniqueField' => 'TableName;FieldName;ModuleName',
					'Records' => Array (
						'Category;NewItem;In-Portal' => "('Category', 'NewItem', 0, 1, 'lu_fielddesc_category_newitem', 'lu_field_newitem', 'In-Portal', 'la_text_category', 18, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;PopItem;In-Portal' => "('Category', 'PopItem', 0, 1, 'lu_fielddesc_category_popitem', 'lu_field_popitem', 'In-Portal', 'la_text_category', 19, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;HotItem;In-Portal' => "('Category', 'HotItem', 0, 1, 'lu_fielddesc_category_hotitem', 'lu_field_hotitem', 'In-Portal', 'la_text_category', 17, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;MetaDescription;In-Portal' => "('Category', 'MetaDescription', 0, 1, 'lu_fielddesc_category_metadescription', 'lu_field_metadescription', 'In-Portal', 'la_text_category', 16, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;ParentPath;In-Portal' => "('Category', 'ParentPath', 0, 1, 'lu_fielddesc_category_parentpath', 'lu_field_parentpath', 'In-Portal', 'la_text_category', 15, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;ResourceId;In-Portal' => "('Category', 'ResourceId', 0, 1, 'lu_fielddesc_category_resourceid', 'lu_field_resourceid', 'In-Portal', 'la_text_category', 14, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;CreatedById;In-Portal' => "('Category', 'CreatedById', 0, 1, 'lu_fielddesc_category_createdbyid', 'lu_field_createdbyid', 'In-Portal', 'la_text_category', 13, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;CachedNavbar;In-Portal' => "('Category', 'CachedNavbar', 0, 1, 'lu_fielddesc_category_cachednavbar', 'lu_field_cachednavbar', 'In-Portal', 'la_text_category', 12, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;CachedDescendantCatsQty;In-Portal' => "('Category', 'CachedDescendantCatsQty', 0, 1, 'lu_fielddesc_category_cacheddescendantcatsqty', 'lu_field_cacheddescendantcatsqty', 'In-Portal', 'la_text_category', 11, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;MetaKeywords;In-Portal' => "('Category', 'MetaKeywords', 0, 1, 'lu_fielddesc_category_metakeywords', 'lu_field_metakeywords', 'In-Portal', 'la_text_category', 10, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;Priority;In-Portal' => "('Category', 'Priority', 0, 1, 'lu_fielddesc_category_priority', 'lu_field_priority', 'In-Portal', 'la_text_category', 9, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;Status;In-Portal' => "('Category', 'Status', 0, 1, 'lu_fielddesc_category_status', 'lu_field_status', 'In-Portal', 'la_text_category', 7, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;EditorsPick;In-Portal' => "('Category', 'EditorsPick', 0, 1, 'lu_fielddesc_category_editorspick', 'lu_field_editorspick', 'In-Portal', 'la_text_category', 6, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;CreatedOn;In-Portal' => "('Category', 'CreatedOn', 0, 1, 'lu_fielddesc_category_createdon', 'lu_field_createdon', 'In-Portal', 'la_text_category', 5, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;Description;In-Portal' => "('Category', 'Description', 1, 1, 'lu_fielddesc_category_description', 'lu_field_description', 'In-Portal', 'la_text_category', 4, DEFAULT, 2, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;Name;In-Portal' => "('Category', 'Name', 1, 1, 'lu_fielddesc_category_name', 'lu_field_name', 'In-Portal', 'la_text_category', 3, DEFAULT, 2, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;ParentId;In-Portal' => "('Category', 'ParentId', 0, 1, 'lu_fielddesc_category_parentid', 'lu_field_parentid', 'In-Portal', 'la_text_category', 2, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;CategoryId;In-Portal' => "('Category', 'CategoryId', 0, 1, 'lu_fielddesc_category_categoryid', 'lu_field_categoryid', 'In-Portal', 'la_text_category', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;Modified;In-Portal' => "('Category', 'Modified', 0, 1, 'lu_fielddesc_category_modified', 'lu_field_modified', 'In-Portal', 'la_text_category', 20, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'Category;ModifiedById;In-Portal' => "('Category', 'ModifiedById', 0, 1, 'lu_fielddesc_category_modifiedbyid', 'lu_field_modifiedbyid', 'In-Portal', 'la_text_category', 21, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",

						'PortalUser;PortalUserId;In-Portal' => "('PortalUser', 'PortalUserId', -1, 0, 'lu_fielddesc_user_portaluserid', 'lu_field_portaluserid', 'In-Portal', 'la_text_user', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Login;In-Portal' => "('PortalUser', 'Login', -1, 0, 'lu_fielddesc_user_login', 'lu_field_login', 'In-Portal', 'la_text_user', 1, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Password;In-Portal' => "('PortalUser', 'Password', -1, 0, 'lu_fielddesc_user_password', 'lu_field_password', 'In-Portal', 'la_text_user', 2, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;tz;In-Portal' => "('PortalUser', 'tz', -1, 0, 'lu_fielddesc_user_tz', 'lu_field_tz', 'In-Portal', 'la_text_user', 17, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;dob;In-Portal' => "('PortalUser', 'dob', -1, 0, 'lu_fielddesc_user_dob', 'lu_field_dob', 'In-Portal', 'la_text_user', 16, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Modified;In-Portal' => "('PortalUser', 'Modified', -1, 0, 'lu_fielddesc_user_modified', 'lu_field_modified', 'In-Portal', 'la_text_user', 15, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Status;In-Portal' => "('PortalUser', 'Status', -1, 0, 'lu_fielddesc_user_status', 'lu_field_status', 'In-Portal', 'la_text_user', 14, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;ResourceId;In-Portal' => "('PortalUser', 'ResourceId', -1, 0, 'lu_fielddesc_user_resourceid', 'lu_field_resourceid', 'In-Portal', 'la_text_user', 13, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Country;In-Portal' => "('PortalUser', 'Country', -1, 0, 'lu_fielddesc_user_country', 'lu_field_country', 'In-Portal', 'la_text_user', 12, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Zip;In-Portal' => "('PortalUser', 'Zip', -1, 0, 'lu_fielddesc_user_zip', 'lu_field_zip', 'In-Portal', 'la_text_user', 11, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;State;In-Portal' => "('PortalUser', 'State', -1, 0, 'lu_fielddesc_user_state', 'lu_field_state', 'In-Portal', 'la_text_user', 10, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;City;In-Portal' => "('PortalUser', 'City', -1, 0, 'lu_fielddesc_user_city', 'lu_field_city', 'In-Portal', 'la_text_user', 9, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Street;In-Portal' => "('PortalUser', 'Street', -1, 0, 'lu_fielddesc_user_street', 'lu_field_street', 'In-Portal', 'la_text_user', 8, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Phone;In-Portal' => "('PortalUser', 'Phone', -1, 0, 'lu_fielddesc_user_phone', 'lu_field_phone', 'In-Portal', 'la_text_user', 7, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;CreatedOn;In-Portal' => "('PortalUser', 'CreatedOn', -1, 0, 'lu_fielddesc_user_createdon', 'lu_field_createdon', 'In-Portal', 'la_text_user', 6, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;Email;In-Portal' => "('PortalUser', 'Email', -1, 0, 'lu_fielddesc_user_email', 'lu_field_email', 'In-Portal', 'la_text_user', 5, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;LastName;In-Portal' => "('PortalUser', 'LastName', -1, 0, 'lu_fielddesc_user_lastname', 'lu_field_lastname', 'In-Portal', 'la_text_user', 4, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
						'PortalUser;FirstName;In-Portal' => "('PortalUser', 'FirstName', -1, 0, 'lu_fielddesc_user_firstname', 'lu_field_firstname', 'In-Portal', 'la_text_user', 3, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
					),
				),

				'StatItem' => Array (
					'UniqueField' => 'Module;ListLabel',
					'Records' => Array (
						'In-Portal;la_prompt_ActiveCategories' => "(DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>Category WHERE Status=1 ', NULL, 'la_prompt_ActiveCategories', '0', '1')",
						'In-Portal;la_prompt_ActiveUsers' => "(DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>PortalUser WHERE Status=1 ', NULL, 'la_prompt_ActiveUsers', '0', '1')",
						'In-Portal;la_prompt_CurrentSessions' => "(DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>UserSession', NULL, 'la_prompt_CurrentSessions', '0', '1')",
						'In-Portal;la_prompt_TotalCategories' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) as CategoryCount FROM <%prefix%>Category', NULL, 'la_prompt_TotalCategories', 0, 2)",
						'In-Portal;la_prompt_ActiveCategories' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ActiveCategories FROM <%prefix%>Category WHERE Status = 1', NULL, 'la_prompt_ActiveCategories', 0, 2)",
						'In-Portal;la_prompt_PendingCategories' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS PendingCategories FROM <%prefix%>Category WHERE Status = 2', NULL, 'la_prompt_PendingCategories', 0, 2)",
						'In-Portal;la_prompt_DisabledCategories' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS DisabledCategories FROM <%prefix%>Category WHERE Status = 0', NULL, 'la_prompt_DisabledCategories', 0, 2)",
						'In-Portal;la_prompt_NewCategories' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS NewCategories FROM <%prefix%>Category WHERE (NewItem = 1) OR ( (UNIX_TIMESTAMP() - CreatedOn) <= <%m:config name=\"Category_DaysNew\"%>*86400 AND (NewItem = 2) )', NULL, 'la_prompt_NewCategories', 0, 2)",
						'In-Portal;la_prompt_CategoryEditorsPick' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) FROM <%prefix%>Category WHERE EditorsPick = 1', NULL, 'la_prompt_CategoryEditorsPick', 0, 2)",
						'In-Portal;la_prompt_NewestCategoryDate' => "(DEFAULT, 'In-Portal', 'SELECT <%m:post_format field=\"MAX(CreatedOn)\" type=\"date\"%> FROM <%prefix%>Category', NULL, 'la_prompt_NewestCategoryDate', 0, 2)",
						'In-Portal;la_prompt_LastCategoryUpdate' => "(DEFAULT, 'In-Portal', 'SELECT <%m:post_format field=\"MAX(Modified)\" type=\"date\"%> FROM <%prefix%>Category', NULL, 'la_prompt_LastCategoryUpdate', 0, 2)",
						'In-Portal;la_prompt_TopicsUsers' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS TotalUsers FROM <%prefix%>PortalUser', NULL, 'la_prompt_TopicsUsers', 0, 2)",
						'In-Portal;la_prompt_UsersActive' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ActiveUsers FROM <%prefix%>PortalUser WHERE Status = 1', NULL, 'la_prompt_UsersActive', 0, 2)",
						'In-Portal;la_prompt_UsersPending' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS PendingUsers FROM <%prefix%>PortalUser WHERE Status = 2', NULL, 'la_prompt_UsersPending', 0, 2)",
						'In-Portal;la_prompt_UsersDisabled' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS DisabledUsers FROM <%prefix%>PortalUser WHERE Status = 0', NULL, 'la_prompt_UsersDisabled', 0, 2)",
						'In-Portal;la_prompt_NewestUserDate' => "(DEFAULT, 'In-Portal', 'SELECT <%m:post_format field=\"MAX(CreatedOn)\" type=\"date\"%> FROM <%prefix%>PortalUser', NULL, 'la_prompt_NewestUserDate', 0, 2)",
						'In-Portal;la_prompt_UsersUniqueCountries' => "(DEFAULT, 'In-Portal', 'SELECT COUNT( DISTINCT LOWER( Country ) ) FROM <%prefix%>PortalUser WHERE LENGTH(Country) > 0', NULL, 'la_prompt_UsersUniqueCountries', 0, 2)",
						'In-Portal;la_prompt_UsersUniqueStates' => "(DEFAULT, 'In-Portal', 'SELECT COUNT( DISTINCT LOWER( State ) ) FROM <%prefix%>PortalUser WHERE LENGTH(State) > 0', NULL, 'la_prompt_UsersUniqueStates', 0, 2)",
						'In-Portal;la_prompt_TotalUserGroups' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS TotalUserGroups FROM <%prefix%>PortalGroup', NULL, 'la_prompt_TotalUserGroups', 0, 2)",
						'In-Portal;la_prompt_BannedUsers' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS BannedUsers FROM <%prefix%>PortalUser WHERE IsBanned = 1', NULL, 'la_prompt_BannedUsers', 0, 2)",
						'In-Portal;la_prompt_NonExpiredSessions' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS NonExipedSessions FROM <%prefix%>UserSession WHERE Status = 1', NULL, 'la_prompt_NonExpiredSessions', 0, 2)",
						'In-Portal;la_prompt_ThemeCount' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ThemeCount FROM <%prefix%>Theme', NULL, 'la_prompt_ThemeCount', 0, 2)",
						'In-Portal;la_prompt_RegionsCount' => "(DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS RegionsCount FROM <%prefix%>Language', NULL, 'la_prompt_RegionsCount', 0, 2)",
						'In-Portal;la_prompt_TablesCount' => "(DEFAULT, 'In-Portal', '<%m:sql_action sql=\"SHOW+TABLES\" action=\"COUNT\" field=\"*\"%>', NULL, 'la_prompt_TablesCount', 0, 2)",
						'In-Portal;la_prompt_RecordsCount' => "(DEFAULT, 'In-Portal', '<%m:sql_action sql=\"SHOW+TABLE+STATUS\" action=\"SUM\" field=\"Rows\"%>', NULL, 'la_prompt_RecordsCount', 0, 2)",
						'In-Portal;la_prompt_SystemFileSize' => "(DEFAULT, 'In-Portal', '<%m:custom_action sql=\"empty\" action=\"SysFileSize\"%>', NULL, 'la_prompt_SystemFileSize', 0, 2)",
						'In-Portal;la_prompt_DataSize' => "(DEFAULT, 'In-Portal', '<%m:sql_action sql=\"SHOW+TABLE+STATUS\" action=\"SUM\" format_as=\"file\" field=\"Data_length\"%>', NULL, 'la_prompt_DataSize', 0, 2)",
					),
				),

				'StylesheetSelectors' => Array (
					'UniqueField' => 'SelectorId',
					'Records' => Array (
						'169' => "(169, 8, 'Calendar''s selected days', '.calendar tbody .selected', 'a:0:{}', '', 1, 'font-weight: bold;\\\r\\nbackground-color: #9ED7ED;\\r\\nborder: 1px solid #83B2C5;', 0)",
						'118' => "(118, 8, 'Data grid row', 'td.block-data-row', 'a:0:{}', '', 2, 'border-bottom: 1px solid #cccccc;', 48)",
						'81' => "(81, 8, '\"More\" link', 'a.link-more', 'a:0:{}', '', 2, 'text-decoration: underline;', 64)",
						'88' => "(88, 8, 'Block data, separated rows', 'td.block-data-grid', 'a:0:{}', '', 2, 'border: 1px solid #cccccc;', 48)",
						'42' => "(42, 8, 'Block Header', 'td.block-header', 'a:4:{s:5:\"color\";s:16:\"rgb(0, 159, 240)\";s:9:\"font-size\";s:4:\"20px\";s:11:\"font-weight\";s:6:\"normal\";s:7:\"padding\";s:3:\"5px\";}', 'Block Header', 1, 'font-family: Verdana, Helvetica, sans-serif;', 0)",
						'76' => "(76, 8, 'Navigation bar menu', 'tr.head-nav td', 'a:0:{}', '', 1, 'vertical-align: middle;', 0)",
						'48' => "(48, 8, 'Block data', 'td.block-data', 'a:2:{s:9:\"font-size\";s:5:\"12px;\";s:7:\"padding\";s:3:\"5px\";}', '', 1, '', 0)",
						'78' => "(78, 8, 'Body main style', 'body', 'a:0:{}', '', 1, 'padding: 0px; \\r\\nbackground-color: #ffffff; \\r\\nfont-family: arial, verdana, helvetica; \\r\\nfont-size: small;\\r\\nwidth: auto;\\r\\nmargin: 0px;', 0)",
						'58' => "(58, 8, 'Main table', 'table.main-table', 'a:0:{}', '', 1, 'width: 770px;\\r\\nmargin: 0px;\\r\\n/*table-layout: fixed;*/', 0)",
						'79' => "(79, 8, 'Block: header of data block', 'span.block-data-grid-header', 'a:0:{}', '', 1, 'font-family: Arial, Helvetica, sans-serif;\\r\\ncolor: #009DF6;\\r\\nfont-size: 12px;\\r\\nfont-weight: bold;\\r\\nbackground-color: #E6EEFF;\\r\\npadding: 6px;\\r\\nwhite-space: nowrap;', 0)",
						'64' => "(64, 8, 'Link', 'a', 'a:0:{}', '', 1, '', 0)",
						'46' => "(46, 8, 'Product title link', 'a.link-product1', 'a:0:{}', 'Product title link', 1, 'color: #62A1DE;\\r\\nfont-size: 14px;\\r\\nfont-weight: bold;\\r\\nline-height: 20px;\\r\\npadding-bottom: 10px;', 0)",
						'75' => "(75, 8, 'Copy of Main path link', 'table.main-path td a:hover', 'a:0:{}', '', 1, 'color: #ffffff;', 0)",
						'160' => "(160, 8, 'Current item in navigation bar', '.checkout-step-current', 'a:0:{}', '', 1, 'color: #A20303;\\r\\nfont-weight: bold;', 0)",
						'51' => "(51, 8, 'Right block data', 'td.right-block-data', 'a:1:{s:9:\"font-size\";s:4:\"11px\";}', '', 2, 'padding: 7px;\\r\\nbackground: #e3edf6 url(\"/in-commerce4/themes/default/img/bgr_login.jpg\") repeat-y	scroll left top;\\r\\nborder-bottom: 1px solid #64a1df;', 48)",
						'67' => "(67, 8, 'Pagination bar: text', 'table.block-pagination td', 'a:3:{s:5:\"color\";s:7:\"#8B898B\";s:9:\"font-size\";s:4:\"12px\";s:11:\"font-weight\";s:6:\"normal\";}', '', 1, '', 0)",
						'45' => "(45, 8, 'Category link', 'a.subcat', 'a:0:{}', 'Category link', 1, 'color: #2069A4', 0)",
						'68' => "(68, 8, 'Pagination bar: link', 'table.block-pagination td a', 'a:3:{s:5:\"color\";s:7:\"#8B898B\";s:9:\"font-size\";s:5:\"12px;\";s:11:\"font-weight\";s:6:\"normal\";}', '', 1, '', 0)",
						'69' => "(69, 8, 'Product description in product list', '.product-list-description', 'a:2:{s:5:\"color\";s:7:\"#8B898B\";s:9:\"font-size\";s:4:\"12px\";}', '', 1, '', 0)",
						'73' => "(73, 8, 'Main path link', 'table.main-path td a', 'a:0:{}', '', 1, 'color: #d5e231;', 0)",
						'83' => "(83, 8, 'Product title link in list (shopping cart)', 'a.link-product-cart', 'a:0:{}', 'Product title link', 1, 'color: #18559C;\\r\\nfont-size: 12px;\\r\\nfont-weight: bold;\\r\\ntext-decoration: none;\\r\\n\\r\\n', 0)",
						'72' => "(72, 8, 'Main path block text', 'table.main-path td', 'a:0:{}', '', 1, 'color: #ffffff;\\r\\nfont-size: 10px;\\r\\nfont-weight: normal;\\r\\npadding: 1px;\\r\\n', 0)",
						'61' => "(61, 8, 'Block: header of data table', 'td.block-data-grid-header', 'a:6:{s:4:\"font\";s:28:\"Arial, Helvetica, sans-serif\";s:5:\"color\";s:7:\"#009DF6\";s:9:\"font-size\";s:4:\"12px\";s:11:\"font-weight\";s:4:\"bold\";s:16:\"background-color\";s:7:\"#E6EEFF\";s:7:\"padding\";s:3:\"6px\";}', '', 1, 'white-space: nowrap;\\r\\npadding-left: 10px;\\r\\n/*\\r\\nbackground-image: url(/in-commerce4/themes/default/img/bullet1.gif);\\r\\nbackground-position: 10px 12px;\\r\\nbackground-repeat: no-repeat;\\r\\n*/', 0)",
						'65' => "(65, 8, 'Link in product list additional row', 'td.product-list-additional a', 'a:1:{s:5:\"color\";s:7:\"#8B898B\";}', '', 2, '', 64)",
						'55' => "(55, 8, 'Main table, left column', 'td.main-column-left', 'a:0:{}', '', 1, 'width:180px;\\r\\nborder: 1px solid #62A1DE;\\r\\nborder-top: 0px;', 0)",
						'70' => "(70, 8, 'Product title link in list (category)', 'a.link-product-category', 'a:0:{}', 'Product title link', 1, 'color: #18559C;\\r\\nfont-size: 12px;\\r\\nfont-weight: bold;\\r\\ntext-decoration: none;\\r\\n\\r\\n', 0)",
						'66' => "(66, 8, 'Pagination bar block', 'table.block-pagination', 'a:0:{}', '', 1, '', 0)",
						'49' => "(49, 8, 'Bulleted list inside block', 'td.block-data ul li', 'a:0:{}', '', 1, '    list-style-image: url(/in-commerce4/themes/default/img/bullet2.gif);\\r\\n    margin-bottom: 10px;\\r\\n    font-size: 11px;', 0)",
						'87' => "(87, 8, 'Cart item input form element', 'td.cart-item-atributes input', 'a:0:{}', '', 1, 'border: 1px solid #7BB2E6;', 0)",
						'119' => "(119, 8, 'Data grid row header', 'td.block-data-row-hdr', 'a:0:{}', 'Used in order preview', 2, 'background-color: #eeeeee;\\r\\nborder-bottom: 1px solid #dddddd;\\r\\nborder-top: 1px solid #cccccc;\\r\\nfont-weight: bold;', 48)",
						'82' => "(82, 8, '\"More\" link image', 'a.link-more img', 'a:0:{}', '', 2, 'text-decoration: none;\\r\\npadding-left: 5px;', 64)",
						'63' => "(63, 8, 'Additional info under product description in list', 'td.product-list-additional', 'a:5:{s:5:\"color\";s:7:\"#8B898B\";s:9:\"font-size\";s:4:\"11px\";s:11:\"font-weight\";s:6:\"normal\";s:10:\"border-top\";s:18:\"1px dashed #8B898B\";s:13:\"border-bottom\";s:18:\"1px dashed #8B898B\";}', '', 2, '', 48)",
						'43' => "(43, 8, 'Block', 'table.block', 'a:2:{s:16:\"background-color\";s:7:\"#E3EEF9\";s:6:\"border\";s:17:\"1px solid #64A1DF\";}', 'Block', 1, 'border: 0; \\r\\nmargin-bottom: 1px;\\r\\nwidth: 100%;', 0)",
						'84' => "(84, 8, 'Cart item cell', 'td.cart-item', 'a:0:{}', '', 1, 'background-color: #F6FAFF;\\r\\nborder-left: 1px solid #ffffff;\\r\\nborder-bottom: 1px solid #ffffff;\\r\\npadding: 4px;', 0)",
						'57' => "(57, 8, 'Main table, right column', 'td.main-column-right', 'a:0:{}', '', 1, 'width:220px;\\r\\nborder: 1px solid #62A1DE;\\r\\nborder-top: 0px;', 0)",
						'161' => "(161, 8, 'Block for sub categories', 'td.block-data-subcats', 'a:0:{}', '', 2, '  background: #FFFFFF\\r\\nurl(/in-commerce4/themes/default/in-commerce/img/bgr_categories.jpg);\\r\\n  background-repeat: no-repeat;\\r\\n  background-position: top right;\\r\\nborder-bottom: 5px solid #DEEAFF;\\r\\npadding-left: 10px;', 48)",
						'77' => "(77, 8, 'Left block header', 'td.left-block-header', 'a:0:{}', '', 2, 'font-family : verdana, helvetica, sans-serif;\\r\\ncolor : #ffffff;\\r\\nfont-size : 12px;\\r\\nfont-weight : bold;\\r\\ntext-decoration : none;\\r\\nbackground-color: #64a1df;\\r\\npadding: 5px;\\r\\npadding-left: 7px;', 42)",
						'80' => "(80, 8, 'Right block data - text', 'td.right-block-data td', 'a:1:{s:9:\"font-size\";s:5:\"11px;\";}', '', 2, '', 48)",
						'53' => "(53, 8, 'Right block header', 'td.right-block-header', 'a:0:{}', '', 2, 'font-family : verdana, helvetica, sans-serif;\\r\\ncolor : #ffffff;\\r\\nfont-size : 12px;\\r\\nfont-weight : bold;\\r\\ntext-decoration : none;\\r\\nbackground-color: #64a1df;\\r\\npadding: 5px;\\r\\npadding-left: 7px;', 42)",
						'85' => "(85, 8, 'Cart item cell with attributes', 'td.cart-item-attributes', 'a:0:{}', '', 1, 'background-color: #E6EEFF;\\r\\nborder-left: 1px solid #ffffff;\\r\\nborder-bottom: 1px solid #ffffff;\\r\\npadding: 4px;\\r\\ntext-align: center;\\r\\nvertical-align: middle;\\r\\nfont-size: 12px;\\r\\nfont-weight: normal;', 0)",
						'86' => "(86, 8, 'Cart item cell with name', 'td.cart-item-name', 'a:0:{}', '', 1, 'background-color: #F6FAFF;\\r\\nborder-left: 1px solid #ffffff;\\r\\nborder-bottom: 1px solid #ffffff;\\r\\npadding: 3px;', 0)",
						'47' => "(47, 8, 'Block content of featured product', 'td.featured-block-data', 'a:0:{}', '', 1, 'font-family: Arial,Helvetica,sans-serif;\\r\\nfont-size: 12px;', 0)",
						'56' => "(56, 8, 'Main table, middle column', 'td.main-column-center', 'a:0:{}', '', 1, '\\r\\n', 0)",
						'50' => "(50, 8, 'Product title link in list', 'a.link-product2', 'a:0:{}', 'Product title link', 1, 'color: #62A1DE;\\r\\nfont-size: 12px;\\r\\nfont-weight: bold;\\r\\ntext-decoration: none;\\r\\n\\r\\n', 0)",
						'71' => "(71, 8, 'Main path block', 'table.main-path', 'a:0:{}', '', 1, 'background: #61b0ec url(\"/in-commerce4/themes/default/img/bgr_path.jpg\") repeat-y scroll left top;\\r\\nwidth: 100%;\\r\\nmargin-bottom: 1px;\\r\\nmargin-right: 1px; \\r\\nmargin-left: 1px;', 0)",
						'62' => "(62, 8, 'Block: columns header for data table', 'table.block-no-border th', 'a:6:{s:4:\"font\";s:28:\"Arial, Helvetica, sans-serif\";s:5:\"color\";s:7:\"#18559C\";s:9:\"font-size\";s:4:\"11px\";s:11:\"font-weight\";s:4:\"bold\";s:16:\"background-color\";s:7:\"#B4D2EE\";s:7:\"padding\";s:3:\"6px\";}', '', 1, 'text-align: left;', 0)",
						'59' => "(59, 8, 'Block without border', 'table.block-no-border', 'a:0:{}', '', 1, 'border: 0px; \\r\\nmargin-bottom: 10px;\\r\\nwidth: 100%;', 0)",
						'74' => "(74, 8, 'Main path language selector cell', 'td.main-path-language', 'a:0:{}', '', 1, 'vertical-align: middle;\\r\\ntext-align: right;\\r\\npadding-right: 6px;', 0)",
						'171' => "(171, 8, 'Calendar''s highlighted day', '.calendar tbody .hilite', 'a:0:{}', '', 1, 'background-color: #f6f6f6;\\r\\nborder: 1px solid #83B2C5 !important;', 0)",
						'175' => "(175, 8, 'Calendar''s days', '.calendar tbody .day', 'a:0:{}', '', 1, 'text-align: right;\\r\\npadding: 2px 4px 2px 2px;\\r\\nwidth: 2em;\\r\\nborder: 1px solid #fefefe;', 0)",
						'170' => "(170, 8, 'Calendar''s weekends', '.calendar .weekend', 'a:0:{}', '', 1, 'color: #990000;', 0)",
						'173' => "(173, 8, 'Calendar''s control buttons', '.calendar .calendar_button', 'a:0:{}', '', 1, 'color: black;\\r\\nfont-size: 12px;\\r\\nbackground-color: #eeeeee;', 0)",
						'174' => "(174, 8, 'Calendar''s day names', '.calendar thead .name', 'a:0:{}', '', 1, 'background-color: #DEEEF6;\\r\\nborder-bottom: 1px solid #000000;', 0)",
						'172' => "(172, 8, 'Calendar''s top and bottom titles', '.calendar .title', 'a:0:{}', '', 1, 'color: #FFFFFF;\\r\\nbackground-color: #62A1DE;\\r\\nborder: 1px solid #107DC5;\\r\\nborder-top: 0px;\\r\\npadding: 1px;', 0)",
						'60' => "(60, 8, 'Block header for featured product', 'td.featured-block-header', 'a:0:{}', '', 2, '\\r\\n', 42)",
						'54' => "(54, 8, 'Right block', 'table.right-block', 'a:0:{}', '', 2, 'background-color: #E3EEF9;\\r\\nborder: 0px;\\r\\nwidth: 100%;', 43)",
						'44' => "(44, 8, 'Block content', 'td.block-data-big', 'a:0:{}', 'Block content', 1, '  background: #DEEEF6\\r\\nurl(/in-commerce4/themes/default/img/menu_bg.gif);\\r\\n  background-repeat: no-repeat;\\r\\n  background-position: top right;\\r\\n', 0)",
					),
				),

				'Stylesheets' => Array (
					'UniqueField' => 'StylesheetId',
					'Records' => Array (
						'8' => "(8, 'Default', 'In-Portal Default Theme', '', 1124952555, 1)",
					),
				),

				'Counters' => Array (
					'UniqueField' => 'Name',
					'Records' => Array (
						'members_count' => "(DEFAULT, 'members_count', 'SELECT COUNT(*) FROM <%PREFIX%>PortalUser WHERE Status = 1', NULL , NULL , '3600', '0', '|PortalUser|')",
						'members_online' => "(DEFAULT, 'members_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSession WHERE PortalUserId > 0', NULL , NULL , '3600', '0', '|UserSession|')",
						'guests_online' => "(DEFAULT, 'guests_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSession WHERE PortalUserId <= 0', NULL , NULL , '3600', '0', '|UserSession|')",
						'users_online' => "(DEFAULT, 'users_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSession', NULL , NULL , '3600', '0', '|UserSession|')",
					),
				),
			);

			// check & insert if not found defined before data
			foreach ($data as $table_name => $table_info) {
				$unique_fields = explode(';', $table_info['UniqueField']);
				foreach ($table_info['Records'] as $unique_value => $insert_sql) {
					$unique_values = explode(';', $unique_value);

					$where_clause = Array ();
					foreach ($unique_fields as $field_index => $unique_field) {
						$where_clause[] = $unique_field . ' = ' . $this->Conn->qstr($unique_values[$field_index]);
					}

					$sql = 'SELECT ' . implode(', ', $unique_fields) . '
							FROM ' . TABLE_PREFIX . $table_name . '
							WHERE (' . implode(') AND (', $where_clause) . ')';
					$found = $this->Conn->GetRow($sql);
					if ($found) {
						$found = implode(';', $found);
					}

					if ($found != $unique_value) {
						$this->Conn->Query('INSERT INTO ' . TABLE_PREFIX . $table_name . ' VALUES ' . $insert_sql);
					}
				}
			}
		}

		/**
		 * Removes duplicate phrases per language basis (created during proj-base and in-portal shared installation)
		 *
		 */
		function _removeDuplicatePhrases()
		{
			$id_field = $this->Application->getUnitOption('phrases', 'IDField');
			$table_name = $this->Application->getUnitOption('phrases', 'TableName');

			$sql = 'SELECT LanguageId, Phrase, MIN(LastChanged) AS LastChanged, COUNT(*) AS DupeCount
					FROM ' . $table_name . '
					GROUP BY LanguageId, Phrase
					HAVING COUNT(*) > 1';
			$duplicate_phrases = $this->Conn->Query($sql);

			foreach ($duplicate_phrases as $phrase_record) {
				// 1. keep phrase, that was added first, because it is selected in PhrasesCache::LoadPhraseByLabel
				$where_clause = Array (
					'LanguageId = ' . $phrase_record['LanguageId'],
					'Phrase = ' . $this->Conn->qstr($phrase_record['Phrase']),
					'LastChanged' . ' = ' . $phrase_record['LastChanged'],
				);

				$sql = 'SELECT ' . $id_field . '
						FROM ' . $table_name . '
						WHERE (' . implode(') AND (', $where_clause) . ')';
				$phrase_id = $this->Conn->GetOne($sql);

				// 2. delete all other duplicates
				$where_clause = Array (
					'LanguageId = ' . $phrase_record['LanguageId'],
					'Phrase = ' . $this->Conn->qstr($phrase_record['Phrase']),
					$id_field . ' <> ' . $phrase_id,
				);

				$sql = 'DELETE FROM ' . $table_name . '
						WHERE (' . implode(') AND (', $where_clause) . ')';
				$this->Conn->Query($sql);
			}
		}

		function _moveDatabaseFolders()
		{
			// Tables: PageContent, Images
			if ($this->Conn->TableFound('PageContent')) {
				// 1. replaces "/kernel/user_files/" references in content blocks
				$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
				/* @var $ml_helper kMultiLanguageHelper */

				$language_count = $ml_helper->getLanguageCount();
				$replace_sql = '%1$s = REPLACE(%1$s, "/kernel/user_files/", "/system/user_files/")';

				$update_sqls = Array ();
				for ($i = 1; $i <= $language_count; $i++) {
					if (!$ml_helper->LanguageFound($i)) {
						continue;
					}

					$field = 'l' . $i . '_Content';
					$update_sqls[] = sprintf($replace_sql, $field);
				}

				if ($update_sqls) {
					$sql = 'UPDATE ' . TABLE_PREFIX . 'PageContent
							SET ' . implode(', ', $update_sqls);
					$this->Conn->Query($sql);
				}
			}

			// 2. replace path of images uploaded via "Images" tab of category items
			$this->_replaceImageFolder('/kernel/images/', '/system/images/');

			// 3. replace path of images uploaded via "Images" tab of category items (when badly formatted)
			$this->_replaceImageFolder('kernel/images/', 'system/images/');

			// 4. replace images uploaded via "In-Bulletin -> Emoticons" section
			$this->_replaceImageFolder('in-bulletin/images/emoticons/', 'system/images/emoticons/');

			// 5. update backup path in config
			$this->_toolkit->saveConfigValues(
				Array (
					'Backup_Path' => FULL_PATH . '/system/backupdata'
				)
			);
		}

		/**
		 * Replaces mentions of "/kernel/images" folder in Images table
		 *
		 * @param string $from
		 * @param string $to
		 */
		function _replaceImageFolder($from, $to)
		{
			$replace_sql = '%1$s = REPLACE(%1$s, "' . $from . '", "' . $to . '")';
			$sql = 'UPDATE ' . TABLE_PREFIX . 'Images
					SET ' . sprintf($replace_sql, 'ThumbPath') . ', ' . sprintf($replace_sql, 'LocalPath');
			$this->Conn->Query($sql);
		}


		/**
		 * Update colors in skin (only if they were not changed manually)
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_0_0($mode)
		{
			if ($mode == 'before') {
				$this->_removeDuplicatePhrases(); // because In-Commerce & In-Link share some phrases with Proj-CMS
				$this->_createProjCMSTables();
				$this->_addMissingConfigurationVariables();
			}

			if ($mode == 'after') {
				$this->_fixSkinColors();
				$this->_restructureCatalog();
				$this->_sortImages();

//				$this->_sortConfigurationVariables('In-Portal', 'in-portal:configure_general');
//				$this->_sortConfigurationVariables('In-Portal', 'in-portal:configure_advanced');
			}
		}

		function _sortConfigurationVariables($module, $section)
		{
			$sql = 'SELECT ca.heading, cv.VariableName
					FROM ' . TABLE_PREFIX . 'ConfigurationAdmin ca
					LEFT JOIN ' . TABLE_PREFIX . 'ConfigurationValues cv USING(VariableName)
					WHERE (cv.ModuleOwner = ' . $this->Conn->qstr($module) . ') AND (cv.Section = ' . $this->Conn->qstr($section) . ')
					ORDER BY ca.DisplayOrder asc, ca.GroupDisplayOrder asc';
			$variables = $this->Conn->GetCol($sql, 'VariableName');

			if (!$variables) {
				return ;
			}

			$variables = $this->_groupRecords($variables);

			$group_number = 0;
			$variable_order = 1;

			$prev_heading = '';

			foreach ($variables as $variable_name => $variable_heading) {
				if ($prev_heading != $variable_heading) {
					$group_number++;
					$variable_order = 1;
				}

				$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationAdmin
						SET DisplayOrder = ' . $this->Conn->qstr($group_number * 10 + $variable_order / 100) . '
						WHERE VariableName = ' . $this->Conn->qstr($variable_name);
				$this->Conn->Query($sql);

				$variable_order++;
				$prev_heading = $variable_heading;
			}
		}

		/**
		 * Group list records by header, saves internal order in group
		 *
		 * @param Array $records
		 * @param string $heading_field
		 */
		function _groupRecords($variables)
		{
			$sorted = Array();

			foreach ($variables as $variable_name => $variable_heading) {
				$sorted[$variable_heading][] = $variable_name;
			}

			$variables = Array();
			foreach ($sorted as $heading => $heading_records) {
				foreach ($heading_records as $variable_name) {
					$variables[$variable_name] = $heading;
				}
			}

			return $variables;
		}

		/**
		 * Returns module root category
		 *
		 * @param string $module_name
		 * @return int
		 */
		function _getRootCategory($module_name, $module_prefix)
		{
			// don't cache anything here (like in static variables), because database value is changed on the fly !!!
			$sql = 'SELECT RootCat
					FROM ' . TABLE_PREFIX . 'Modules
					WHERE LOWER(Name) = ' . $this->Conn->qstr( strtolower($module_name) );
			$root_category = $this->Conn->GetOne($sql);

			// put to cache too, because CategoriesEventHandler::_prepareAutoPage uses kApplication::findModule
			$this->Application->ModuleInfo[$module_name]['Name'] = $module_name;
			$this->Application->ModuleInfo[$module_name]['RootCat'] = $root_category;
			$this->Application->ModuleInfo[$module_name]['Var'] = $module_prefix;

			return $root_category;
		}

		/**
		 * Move all categories (except "Content") from "Home" to "Content" category and hide them from menu
		 *
		 */
		function _restructureCatalog()
		{
			$root_category = $this->_getRootCategory('Core', 'adm');

			$sql = 'SELECT CategoryId
					FROM ' . TABLE_PREFIX . 'Category
					WHERE ParentId = 0 AND CategoryId <> ' . $root_category;
			$top_categories = $this->Conn->GetCol($sql);

			if ($top_categories) {
				// hide all categories located outside "Content" category from menu
				$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
						SET IsMenu = 0
						WHERE (ParentPath LIKE "|' . implode('|%") OR (ParentPath LIKE "|', $top_categories) . '|%")';
				$this->Conn->Query($sql);

				// move all top level categories under "Content" category and make them visible in menu
				$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
						SET IsMenu = 1, ParentId = ' . $root_category . '
						WHERE ParentId = 0 AND CategoryId <> ' . $root_category;
				$this->Conn->Query($sql);
			}

			// make sure, that all categories have valid value for Priority field

			$priority_helper =& $this->Application->recallObject('PriorityHelper');
			/* @var $priority_helper kPriorityHelper */

			$event = new kEvent('c:OnListBuild');

			// update all categories, because they are all under "Content" category now
			$sql = 'SELECT CategoryId
					FROM ' . TABLE_PREFIX . 'Category';
			$categories = $this->Conn->GetCol($sql);

			foreach ($categories as $category_id) {
				$priority_helper->recalculatePriorities($event, 'ParentId = ' . $category_id);
			}

			// create initial theme structure in Category table
			$this->_toolkit->rebuildThemes();

			// make sure, that all system templates have ThemeId set (only possible during platform project upgrade)
			$sql = 'SELECT ThemeId
					FROM ' . TABLE_PREFIX . 'Theme
					WHERE PrimaryTheme = 1';
			$primary_theme_id = $this->Conn->GetOne($sql);

			if ($primary_theme_id) {
				$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
						SET ThemeId = ' . $primary_theme_id . '
						WHERE IsSystem = 1 AND ThemeId = 0';
				$this->Conn->Query($sql);
			}
		}

		/**
		 * Changes skin colors to match new ones (only in case, when they match default values)
		 *
		 */
		function _fixSkinColors()
		{
			$skin =& $this->Application->recallObject('skin', null, Array ('skip_autoload' => 1));
			/* @var $skin kDBItem */

			$skin->Load(1, 'IsPrimary');
			if ($skin->isLoaded()) {
				$skin_options = unserialize( $skin->GetDBField('Options') );

				$changes = Array (
					// option: from -> to
					'HeadBgColor' => Array ('#1961B8', '#007BF4'),
					'HeadBarColor' => Array ('#FFFFFF', '#000000'),

					'HeadColor' => Array ('#CCFF00', '#FFFFFF'),
					'TreeColor' => Array ('#006F99', '#000000'),
					'TreeHoverColor' => Array ('', '#009FF0'),
					'TreeHighHoverColor' => Array ('', '#FFFFFF'),
					'TreeHighBgColor' => Array ('#4A92CE', '#4A92CE'),
					'TreeBgColor' => Array ('#FFFFFF', '#DCECF6'),
				);

				$can_change = true;
				foreach ($changes as $option_name => $change) {
					list ($change_from, $change_to) = $change;

					$can_change = $can_change && ($change_from == $skin_options[$option_name]['Value']);
					if ($can_change) {
						$skin_options[$option_name]['Value'] = $change_to;
					}
				}

				if ($can_change) {
					$skin->SetDBField('Options', serialize($skin_options));
					$skin->Update();

					$skin_helper =& $this->Application->recallObject('SkinHelper');
					/* @var $skin_helper SkinHelper */

					$skin_file = $skin_helper->getSkinPath();
					if (file_exists($skin_file)) {
						unlink($skin_file);
					}
				}
			}
		}

		/**
		 * 1. Set root category not to generate filename automatically and hide it from catalog
		 * 2. Hide root category of In-Edit and set it's fields
		 *
		 * @param int $category_id
		 */
		function _resetRootCategory($category_id)
		{
			$fields_hash = Array (
				'l1_Name' => 'Content', 'Filename' => 'Content', 'AutomaticFilename' => 0,
				'l1_Description' => 'Content', 'Status' => 4,
			);

			$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Category', 'CategoryId = ' . $category_id);
		}

		function _createProjCMSTables()
		{
			// 0. make sure, that Content category exists
			$root_category = $this->_getRootCategory('Proj-CMS', 'st');
			if ($root_category) {
				// proj-cms module found -> remove it
				$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Modules
						WHERE Name = "Proj-CMS"';
				$this->Conn->Query($sql);
				unset($this->Application->ModuleInfo['Proj-CMS']);

				$this->_resetRootCategory($root_category);

				// unhide all structure categories
				$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
						SET Status = 1
						WHERE (Status = 4) AND (CategoryId <> ' . $root_category . ')';
				$this->Conn->Query($sql);
			} else {
				$root_category = $this->_getRootCategory('In-Edit', 'cms');
				if ($root_category) {
					// in-edit module found -> remove it
					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Modules
							WHERE Name = "In-Edit"';
					$this->Conn->Query($sql);
					unset($this->Application->ModuleInfo['In-Edit']);

					$this->_resetRootCategory($root_category);
				}
			}

			if (!$root_category) {
				// create "Content" category when Proj-CMS/In-Edit module was not installed before
				// use direct sql here, because category table structure doesn't yet match table structure in object

				$fields_hash = Array (
					'l1_Name' => 'Content', 'Filename' => 'Content', 'AutomaticFilename' => 0,
					'l1_Description' => 'Content', 'Status' => 4,
				);

				$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Category');

				$root_category = $this->Conn->getInsertID();
			}

			$this->_toolkit->deleteCache();
			$this->_toolkit->SetModuleRootCategory('Core', $root_category);

			// 1. process "Category" table
			$structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'Category', 'Field');
			if (!array_key_exists('Template', $structure)) {
				// fields from "Pages" table were not added to "Category" table (like before "Proj-CMS" module install)
				$sql = "ALTER TABLE " . TABLE_PREFIX . "Category
							ADD COLUMN Template varchar(255) default NULL,
							ADD COLUMN l1_Title varchar(255) default '',
							ADD COLUMN l2_Title varchar(255) default '',
							ADD COLUMN l3_Title varchar(255) default '',
							ADD COLUMN l4_Title varchar(255) default '',
							ADD COLUMN l5_Title varchar(255) default '',
							ADD COLUMN l1_MenuTitle varchar(255) NOT NULL default '',
							ADD COLUMN l2_MenuTitle varchar(255) NOT NULL default '',
							ADD COLUMN l3_MenuTitle varchar(255) NOT NULL default '',
							ADD COLUMN l4_MenuTitle varchar(255) NOT NULL default '',
							ADD COLUMN l5_MenuTitle varchar(255) NOT NULL default '',
							ADD COLUMN MetaTitle text,
							ADD COLUMN IndexTools text,
							ADD COLUMN IsIndex tinyint(1) NOT NULL default '0',
							ADD COLUMN IsMenu TINYINT(4) NOT NULL DEFAULT '1',
							ADD COLUMN IsSystem tinyint(4) NOT NULL default '0',
							ADD COLUMN FormId int(11) default NULL,
							ADD COLUMN FormSubmittedTemplate varchar(255) default NULL,
							ADD COLUMN l1_Translated tinyint(4) NOT NULL default '0',
							ADD COLUMN l2_Translated tinyint(4) NOT NULL default '0',
							ADD COLUMN l3_Translated tinyint(4) NOT NULL default '0',
							ADD COLUMN l4_Translated tinyint(4) NOT NULL default '0',
							ADD COLUMN l5_Translated tinyint(4) NOT NULL default '0',
							ADD COLUMN FriendlyURL varchar(255) NOT NULL default '',
							ADD INDEX IsIndex (IsIndex),
							ADD INDEX l1_Translated (l1_Translated),
							ADD INDEX l2_Translated (l2_Translated),
							ADD INDEX l3_Translated (l3_Translated),
							ADD INDEX l4_Translated (l4_Translated),
							ADD INDEX l5_Translated (l5_Translated)";
				$this->Conn->Query($sql);
			}

			if (array_key_exists('Path', $structure)) {
				$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'Category
						DROP Path';
				$this->Conn->Query($sql);
			}

			// 2. process "PageContent" table
			if ($this->Conn->TableFound(TABLE_PREFIX . 'PageContent')) {
				$structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'PageContent', 'Field');
				if (!array_key_exists('l1_Translated', $structure)) {
					$sql = "ALTER TABLE " . TABLE_PREFIX . "PageContent
								ADD COLUMN l1_Translated tinyint(4) NOT NULL default '0',
								ADD COLUMN l2_Translated tinyint(4) NOT NULL default '0',
								ADD COLUMN l3_Translated tinyint(4) NOT NULL default '0',
								ADD COLUMN l4_Translated tinyint(4) NOT NULL default '0',
								ADD COLUMN l5_Translated tinyint(4) NOT NULL default '0'";
					$this->Conn->Query($sql);
				}
			}

			// 3. process "FormFields" table
			if ($this->Conn->TableFound(TABLE_PREFIX . 'FormFields')) {
				$structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'FormFields', 'Field');
				if (!$structure['FormId']['Key']) {
					$sql = "ALTER TABLE " . TABLE_PREFIX . "FormFields
								CHANGE Validation Validation TINYINT NOT NULL DEFAULT '0',
								ADD INDEX FormId (FormId),
								ADD INDEX Priority (Priority),
								ADD INDEX IsSystem (IsSystem),
								ADD INDEX DisplayInGrid (DisplayInGrid)";
					$this->Conn->Query($sql);
				}
			}
			else {
				$this->Conn->Query("INSERT INTO " . TABLE_PREFIX . "Permissions VALUES (DEFAULT, 'in-portal:forms.view', 11, 1, 1, 0)");
				$this->Conn->Query("INSERT INTO " . TABLE_PREFIX . "Permissions VALUES (DEFAULT, 'in-portal:forms.add', 11, 1, 1, 0)");
				$this->Conn->Query("INSERT INTO " . TABLE_PREFIX . "Permissions VALUES (DEFAULT, 'in-portal:forms.edit', 11, 1, 1, 0)");
				$this->Conn->Query("INSERT INTO " . TABLE_PREFIX . "Permissions VALUES (DEFAULT, 'in-portal:forms.delete', 11, 1, 1, 0)");
			}

			// 4. process "FormSubmissions" table
			if ($this->Conn->TableFound(TABLE_PREFIX . 'FormSubmissions')) {
				$structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'FormSubmissions', 'Field');
				if (!$structure['SubmissionTime']['Key']) {
					$sql = "ALTER TABLE " . TABLE_PREFIX . "FormSubmissions
								ADD INDEX SubmissionTime (SubmissionTime)";
					$this->Conn->Query($sql);
				}
			}
			else {
				$this->Conn->Query("INSERT INTO " . TABLE_PREFIX . "Permissions VALUES (DEFAULT, 'in-portal:submissions.view', 11, 1, 1, 0)");
			}

			// 5. add missing event
			$sql = 'SELECT EventId
					FROM ' . TABLE_PREFIX . 'Events
					WHERE (Event = "FORM.SUBMITTED") AND (Type = 1)';
			$event_id = $this->Conn->GetOne($sql);

			if (!$event_id) {
				$sql = "INSERT INTO " . TABLE_PREFIX . "Events VALUES (DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, 'Core:Category', 'la_event_FormSubmitted', 1)";
				$this->Conn->Query($sql);
			}

			$sql = 'SELECT EventId
					FROM ' . TABLE_PREFIX . 'Events
					WHERE (Event = "FORM.SUBMITTED") AND (Type = 0)';
			$event_id = $this->Conn->GetOne($sql);

			if (!$event_id) {
				$sql = "INSERT INTO " . TABLE_PREFIX . "Events VALUES (DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, 'Core:Category', 'la_event_FormSubmitted', 0)";
				$this->Conn->Query($sql);
			}
		}

		function _addMissingConfigurationVariables()
		{
			$variables = Array (
				'cms_DefaultDesign' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('cms_DefaultDesign', 'la_Text_General', 'la_prompt_DefaultDesignTemplate', 'text', NULL, NULL, 10.15, 0, 0)",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'cms_DefaultDesign', '/platform/designs/general', 'In-Portal', 'in-portal:configure_categories')",
				),

				'Require_AdminSSL' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('Require_AdminSSL', 'la_Text_Website', 'la_config_RequireSSLAdmin', 'checkbox', '', '', 10.105, 0, 1)",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'Require_AdminSSL', '', 'In-Portal', 'in-portal:configure_advanced')",
				),

				'UsePopups' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('UsePopups', 'la_Text_Website', 'la_config_UsePopups', 'radio', '', '1=la_Yes,0=la_No', 10.221, 0, 0)",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'UsePopups', '1', 'In-Portal', 'in-portal:configure_advanced')",
				),

				'UseDoubleSorting' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('UseDoubleSorting', 'la_Text_Website', 'la_config_UseDoubleSorting', 'radio', '', '1=la_Yes,0=la_No', 10.222, 0, 0)",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'UseDoubleSorting', '0', 'In-Portal', 'in-portal:configure_advanced')",
				),

				'MenuFrameWidth' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('MenuFrameWidth', 'la_title_General', 'la_prompt_MenuFrameWidth', 'text', NULL, NULL, 10.31, 0, 0)",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'MenuFrameWidth', 200, 'In-Portal', 'in-portal:configure_advanced')",
				),

				'DefaultSettingsUserId' => Array (
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationAdmin VALUES ('DefaultSettingsUserId', 'la_title_General', 'la_prompt_DefaultUserId', 'text', NULL, NULL, '10.06', '0', '0')",
					"INSERT INTO " . TABLE_PREFIX . "ConfigurationValues VALUES (DEFAULT, 'DefaultSettingsUserId', -1, 'In-Portal:Users', 'in-portal:configure_users')",
				),
			);

			foreach ($variables as $variable_name => $variable_sqls) {
				$sql = 'SELECT VariableId
						FROM ' . TABLE_PREFIX . 'ConfigurationValues
						WHERE VariableName = ' . $this->Conn->qstr($variable_name);
				$variable_id = $this->Conn->GetOne($sql);

				if ($variable_id) {
					continue;
				}

				foreach ($variable_sqls as $variable_sql) {
					$this->Conn->Query($variable_sql);
				}
			}
		}

		/**
		 * Sort images in database (update Priority field)
		 *
		 */
		function _sortImages()
		{
			$sql = 'SELECT *
					FROM ' . TABLE_PREFIX . 'Images
					ORDER BY ResourceId ASC , DefaultImg DESC , ImageId ASC';
			$images = $this->Conn->Query($sql);

			$priority = 0;
			$last_resource_id = false;

			foreach ($images as $image) {
				if ($image['ResourceId'] != $last_resource_id) {
					// each item have own priorities among it's images
					$priority = 0;
					$last_resource_id = $image['ResourceId'];
				}

				if (!$image['DefaultImg']) {
					$priority--;
				}

				$sql = 'UPDATE ' . TABLE_PREFIX . 'Images
						SET Priority = ' . $priority . '
						WHERE ImageId = ' . $image['ImageId'];
				$this->Conn->Query($sql);
			}
		}

		/**
		 * Update to 5.0.1
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_0_1($mode)
		{
			if ($mode == 'after') {
				// delete old events
				$events_to_delete = Array ('CATEGORY.MODIFY', 'CATEGORY.DELETE');

				$sql = 'SELECT EventId
						FROM ' . TABLE_PREFIX . 'Events
						WHERE Event IN ("' . implode('","', $events_to_delete) . '")';
				$event_ids = $this->Conn->GetCol($sql);

				if ($event_ids) {
					$this->_deleteEvents($event_ids);

					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Phrase
							WHERE Phrase IN ("la_event_category.modify", "la_event_category.delete")';
					$this->Conn->Query($sql);
				}

				// partially delete events
				$sql = 'SELECT EventId
						FROM ' . TABLE_PREFIX . 'Events
						WHERE (Event IN ("CATEGORY.APPROVE", "CATEGORY.DENY")) AND (Type = ' . EVENT_TYPE_ADMIN . ')';
				$event_ids = $this->Conn->GetCol($sql);

				if ($event_ids) {
					$this->_deleteEvents($event_ids);
				}
			}
		}

		function _deleteEvents($ids)
		{
			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'EmailMessage
					WHERE EventId IN (' . implode(',', $ids) . ')';
			$this->Conn->Query($sql);

			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Events
					WHERE EventId IN (' . implode(',', $ids) . ')';
			$this->Conn->Query($sql);
		}

		/**
		 * Update to 5.0.2-B2; Transforms IsIndex field values to SymLinkCategoryId field
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_0_2_B2($mode)
		{
			// 0 - Regular, 1 - Category Index, 2 - Container

			if ($mode == 'before') {
				// fix "Content" category
				$fields_hash = Array (
					'CreatedById' => USER_ROOT,
					'CreatedOn' => time(),
					'ResourceId' => $this->Application->NextResourceId(),
				);

				$category_id = $this->Application->findModule('Name', 'Core', 'RootCat');
				$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Category', 'CategoryId = ' . $category_id);

				// get all categories, marked as category index
				$sql = 'SELECT ParentPath, CategoryId
						FROM ' . TABLE_PREFIX . 'Category
						WHERE IsIndex = 1';
				$category_indexes = $this->Conn->GetCol($sql, 'CategoryId');

				foreach ($category_indexes as $category_id => $parent_path) {
					$parent_path = explode('|', substr($parent_path, 1, -1));

					// set symlink to $category_id for each category, marked as container in given category path
					$sql = 'SELECT CategoryId
							FROM ' . TABLE_PREFIX . 'Category
							WHERE CategoryId IN (' . implode(',', $parent_path) . ') AND (IsIndex = 2)';
					$category_containers = $this->Conn->GetCol($sql);

					if ($category_containers) {
						$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
								SET SymLinkCategoryId = ' . $category_id . '
								WHERE CategoryId IN (' . implode(',', $category_containers) . ')';
						$this->Conn->Query($sql);
					}

				}
			}

			if ($mode == 'after') {
				// scan theme to fill Theme.TemplateAliases and ThemeFiles.TemplateAlias fields
				$this->_toolkit->rebuildThemes();

				$sql = 'SELECT TemplateAliases, ThemeId
						FROM ' . TABLE_PREFIX . 'Theme
						WHERE (Enabled = 1) AND (TemplateAliases <> "")';
				$template_aliases = $this->Conn->GetCol($sql, 'ThemeId');

				$all_template_aliases = Array (); // reversed alias (from real template to alias)

				foreach ($template_aliases as $theme_id => $theme_template_aliases) {
					$theme_template_aliases = unserialize($theme_template_aliases);

					if (!$theme_template_aliases) {
						continue;
					}

					$all_template_aliases = array_merge($all_template_aliases, array_flip($theme_template_aliases));
				}

				$default_design_replaced = false;
				$default_design = trim($this->Application->ConfigValue('cms_DefaultDesign'), '/');

				foreach ($all_template_aliases as $from_template => $to_alias) {
					// replace default design in configuration variable (when matches alias)
					if ($from_template == $default_design) {
						// specific alias matched
						$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationValues
								SET VariableValue = ' . $this->Conn->qstr($to_alias) . '
								WHERE VariableName = "cms_DefaultDesign"';
						$this->Conn->Query($sql);

						$default_design_replaced = true;
					}

					// replace Category.Template and Category.CachedTemplate fields (when matches alias)
					$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
							SET Template = ' . $this->Conn->qstr($to_alias) . '
							WHERE Template IN (' . $this->Conn->qstr('/' . $from_template) . ',' . $this->Conn->qstr($from_template) . ')';
					$this->Conn->Query($sql);

					$sql = 'UPDATE ' . TABLE_PREFIX . 'Category
							SET CachedTemplate = ' . $this->Conn->qstr($to_alias) . '
							WHERE CachedTemplate IN (' . $this->Conn->qstr('/' . $from_template) . ',' . $this->Conn->qstr($from_template) . ')';
					$this->Conn->Query($sql);
				}

				if (!$default_design_replaced) {
					// in case if current default design template doesn't
					// match any of aliases, then set it to #default_design#
					$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationValues
							SET VariableValue = "#default_design#"
							WHERE VariableName = "cms_DefaultDesign"';
					$this->Conn->Query($sql);
				}

				// replace data in category custom fields used for category item template storage
				$mod_rewrite_helper =& $this->Application->recallObject('ModRewriteHelper');
				/* @var $mod_rewrite_helper kModRewriteHelper */

				foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
					$custom_field_id = $mod_rewrite_helper->getItemTemplateCustomField($module_info['Var']);

					if (!$custom_field_id) {
						continue;
					}

					foreach ($all_template_aliases as $from_template => $to_alias) {
						$sql = 'UPDATE ' . TABLE_PREFIX . 'CategoryCustomData
								SET l1_cust_' . $custom_field_id . ' = ' . $this->Conn->qstr($to_alias) . '
								WHERE l1_cust_' . $custom_field_id . ' = ' . $this->Conn->qstr($from_template);
						$this->Conn->Query($sql);
					}
				}
			}
		}

		/**
		 * Update to 5.0.3-B2; Moves CATEGORY.* permission from module root categories to Content category
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_0_3_B2($mode)
		{
			if ($mode == 'before') {
				// get permissions
				$sql = 'SELECT PermissionName
						FROM ' . TABLE_PREFIX . 'PermissionConfig
						WHERE PermissionName LIKE "CATEGORY.%"';
				$permission_names = $this->Conn->GetCol($sql);

				// get groups
				$sql = 'SELECT GroupId
						FROM ' . TABLE_PREFIX . 'PortalGroup';
				$user_groups = $this->Conn->GetCol($sql);
				$user_group_count = count($user_groups);

				// get module root categories
				$sql = 'SELECT RootCat
						FROM ' . TABLE_PREFIX . 'Modules';
				$module_categories = $this->Conn->GetCol($sql);

				$module_categories[] = 0;
				$module_categories = implode(',', array_unique($module_categories));

				$permissions = $delete_permission_ids = Array ();

				foreach ($permission_names as $permission_name) {
					foreach ($user_groups as $group_id) {
						$sql = 'SELECT PermissionId
								FROM ' . TABLE_PREFIX . 'Permissions
								WHERE (Permission = ' . $this->Conn->qstr($permission_name) . ') AND (PermissionValue = 1) AND (GroupId = ' . $group_id . ') AND (`Type` = 0) AND (CatId IN (' . $module_categories . '))';
						$permission_ids = $this->Conn->GetCol($sql);

						if ($permission_ids) {
							if (!array_key_exists($permission_name, $permissions)) {
								$permissions[$permission_name] = Array ();
							}

							$permissions[$permission_name][] = $group_id;
							$delete_permission_ids = array_merge($delete_permission_ids, $permission_ids);
						}
					}
				}

				if ($delete_permission_ids) {
					// here we can delete some of permissions that will be added later
					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Permissions
							WHERE PermissionId IN (' . implode(',', $delete_permission_ids) . ')';
					$this->Conn->Query($sql);
				}

				$home_category = $this->Application->findModule('Name', 'Core', 'RootCat');

				foreach ($permissions as $permission_name => $permission_groups) {
					// optimize a bit
					$has_everyone = in_array(15, $permission_groups);

					if ($has_everyone || (!$has_everyone && count($permission_groups) == $user_group_count - 1)) {
						// has permission for "Everyone" group OR allowed in all groups except "Everyone" group
						// so remove all other explicitly allowed permissions
						$permission_groups = Array (15);
					}

					foreach ($permission_groups as $group_id) {
						$fields_hash = Array (
							'Permission' => $permission_name,
							'GroupId' => $group_id,
							'PermissionValue' => 1,
							'Type' => 0, // category-based permission,
							'CatId' => $home_category,
						);

						$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Permissions');
					}
				}

				$updater =& $this->Application->recallObject('kPermCacheUpdater');
				/* @var $updater kPermCacheUpdater */

				$updater->OneStepRun();
			}
		}

		/**
		 * Update to 5.1.0-B1; Makes email message fields multilingual
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_1_0_B1($mode)
		{
			if ($mode == 'before') {
				// migrate email events
				$table_structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'Events', 'Field');

				if (!array_key_exists('Headers', $table_structure)) {
					$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'Events
							ADD `Headers` TEXT NULL AFTER `ReplacementTags`,
							ADD `MessageType` VARCHAR(4) NOT NULL default "text" AFTER `Headers`';
					$this->Conn->Query($sql);
				}

				// alter here, because kMultiLanguageHelper::createFields
				// method, called after will expect that to be in database
				$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'Events
							ADD AllowChangingSender TINYINT NOT NULL DEFAULT "0" AFTER MessageType ,
							ADD CustomSender TINYINT NOT NULL DEFAULT "0" AFTER AllowChangingSender ,
							ADD SenderName VARCHAR(255) NOT NULL DEFAULT "" AFTER CustomSender ,
							ADD SenderAddressType TINYINT NOT NULL DEFAULT "0" AFTER SenderName ,
							ADD SenderAddress VARCHAR(255) NOT NULL DEFAULT "" AFTER SenderAddressType ,
							ADD AllowChangingRecipient TINYINT NOT NULL DEFAULT "0" AFTER SenderAddress ,
							ADD CustomRecipient TINYINT NOT NULL DEFAULT "0" AFTER AllowChangingRecipient ,
							ADD Recipients TEXT AFTER CustomRecipient,
							ADD INDEX (AllowChangingSender),
							ADD INDEX (CustomSender),
							ADD INDEX (SenderAddressType),
							ADD INDEX (AllowChangingRecipient),
							ADD INDEX (CustomRecipient)';
				$this->Conn->Query($sql);

				// create multilingual fields for phrases and email events
				$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
				/* @var $ml_helper kMultiLanguageHelper */

				$ml_helper->createFields('phrases');
				$ml_helper->createFields('emailevents');

				if ($this->Conn->TableFound(TABLE_PREFIX . 'EmailMessage')) {
					$email_message_helper =& $this->Application->recallObject('EmailMessageHelper');
					/* @var $email_message_helper EmailMessageHelper */

					for ($language_id = 1; $language_id <= $ml_helper->languageCount; $language_id++) {
						if (!$ml_helper->LanguageFound($language_id)) {
							continue;
						}

						$sql = 'SELECT EmailMessageId, Template, EventId
								FROM ' . TABLE_PREFIX . 'EmailMessage
								WHERE LanguageId = ' . $language_id;
						$translations = $this->Conn->Query($sql, 'EventId');

						foreach ($translations as $event_id => $translation_data) {
							$parsed = $email_message_helper->parseTemplate($translation_data['Template']);

							$fields_hash = Array (
								'l' . $language_id . '_Subject' => $parsed['Subject'],
								'l' . $language_id . '_Body' => $parsed['Body'],
							);

							if ($parsed['Headers']) {
								$fields_hash['Headers'] = $parsed['Headers'];
							}

							$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Events', 'EventId = ' . $event_id);

							$sql = 'DELETE FROM ' . TABLE_PREFIX . 'EmailMessage
									WHERE EmailMessageId = ' . $translation_data['EmailMessageId'];
							$this->Conn->Query($sql);
						}
					}
				}

				// migrate phrases
				$temp_table = $this->Application->GetTempName(TABLE_PREFIX . 'Phrase');

				$sqls = Array (
					'DROP TABLE IF EXISTS ' . $temp_table,
					'CREATE TABLE ' . $temp_table . ' LIKE ' . TABLE_PREFIX . 'Phrase',
					'ALTER TABLE ' . $temp_table . ' DROP LanguageId, DROP Translation',
					'ALTER IGNORE TABLE ' . $temp_table . ' DROP INDEX LanguageId_2',
					'ALTER TABLE ' . $temp_table . ' DROP PhraseId',
					'ALTER TABLE ' . $temp_table . ' ADD PhraseId INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST',
				);

				foreach ($sqls as $sql) {
					$this->Conn->Query($sql);
				}

				$already_added = Array ();
				$primary_language_id = $this->Application->GetDefaultLanguageId();

				for ($language_id = 1; $language_id <= $ml_helper->languageCount; $language_id++) {
					if (!$ml_helper->LanguageFound($language_id)) {
						continue;
					}

					$sql = 'SELECT Phrase, PhraseKey, Translation AS l' . $language_id . '_Translation, PhraseType, LastChanged, LastChangeIP, Module
							FROM ' . TABLE_PREFIX . 'Phrase
							WHERE LanguageId = ' . $language_id;
					$phrases = $this->Conn->Query($sql, 'Phrase');

					foreach ($phrases as $phrase => $fields_hash) {
						if (array_key_exists($phrase, $already_added)) {
							$this->Conn->doUpdate($fields_hash, $temp_table, 'PhraseId = ' . $already_added[$phrase]);
						}
						else {
							$this->Conn->doInsert($fields_hash, $temp_table);
							$already_added[$phrase] = $this->Conn->getInsertID();
						}
					}

					// in case some phrases were found in this language, but not in primary language -> copy them
					if ($language_id != $primary_language_id) {
						$sql = 'UPDATE ' . $temp_table . '
								SET l' . $primary_language_id . '_Translation = l' . $language_id . '_Translation
								WHERE l' . $primary_language_id . '_Translation IS NULL';
						$this->Conn->Query($sql);
					}
				}

				$this->Conn->Query('DROP TABLE IF EXISTS ' . TABLE_PREFIX . 'Phrase');
				$this->Conn->Query('RENAME TABLE ' . $temp_table . ' TO ' . TABLE_PREFIX . 'Phrase');

				$this->_updateCountryStatesTable();
				$this->_replaceConfigurationValueSeparator();

				// save "config.php" in php format, not ini format as before
				$this->_toolkit->SaveConfig();
			}

			if ($mode == 'after') {
				$this->_transformEmailRecipients();
				$this->_fixSkinColors();
			}
		}

		/**
		 * Move country/state translations from Phrase to CountryStates table
		 *
		 */
		function _updateCountryStatesTable()
		{
			// refactor StdDestinations table
			$sql = 'RENAME TABLE ' . TABLE_PREFIX . 'StdDestinations TO ' . TABLE_PREFIX . 'CountryStates';
			$this->Conn->Query($sql);

			$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'CountryStates
						CHANGE DestId CountryStateId INT(11) NOT NULL AUTO_INCREMENT,
						CHANGE DestType Type INT(11) NOT NULL DEFAULT \'1\',
						CHANGE DestParentId StateCountryId INT(11) NULL DEFAULT NULL,
						CHANGE DestAbbr IsoCode CHAR(3) NOT NULL DEFAULT \'\',
						CHANGE DestAbbr2 ShortIsoCode CHAR(2) NULL DEFAULT NULL,
						DROP INDEX DestType,
						DROP INDEX DestParentId,
						ADD INDEX (`Type`),
						ADD INDEX (StateCountryId)';
			$this->Conn->Query($sql);

			$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
			/* @var $ml_helper kMultiLanguageHelper */

			$ml_helper->createFields('country-state');

			for ($language_id = 1; $language_id <= $ml_helper->languageCount; $language_id++) {
				if (!$ml_helper->LanguageFound($language_id)) {
					continue;
				}

				$sub_select = '	SELECT l' . $language_id . '_Translation
								FROM ' . TABLE_PREFIX . 'Phrase
								WHERE Phrase = DestName';

				$sql = 'UPDATE ' . TABLE_PREFIX . 'CountryStates
						SET l' . $language_id . '_Name = (' . $sub_select . ')';
				$this->Conn->Query($sql);
			}

			$sql = 'ALTER TABLE ' . TABLE_PREFIX . 'CountryStates
					DROP DestName';
			$this->Conn->Query($sql);

			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Phrase
					WHERE Phrase LIKE ' . $this->Conn->qstr('la_country_%') . ' OR Phrase LIKE ' . $this->Conn->qstr('la_state_%');
			$this->Conn->Query($sql);
		}

		/**
		 * Makes configuration values dropdowns use "||" as separator
		 *
		 */
		function _replaceConfigurationValueSeparator()
		{
			$custom_field_helper =& $this->Application->recallObject('InpCustomFieldsHelper');
			/* @var $custom_field_helper InpCustomFieldsHelper */

			$sql = 'SELECT ValueList, VariableName
					FROM ' . TABLE_PREFIX . 'ConfigurationAdmin
					WHERE ValueList LIKE "%,%"';
			$variables = $this->Conn->GetCol($sql, 'VariableName');

			foreach ($variables as $variable_name => $value_list) {
				$ret = Array ();
				$options = $custom_field_helper->GetValuesHash($value_list, ',', false);

				foreach ($options as $option_key => $option_title) {
					if (substr($option_key, 0, 3) == 'SQL') {
						$ret[] = $option_title;
					}
					else {
						$ret[] = $option_key . '=' . $option_title;
					}
				}

				$fields_hash = Array (
					'ValueList' => implode(VALUE_LIST_SEPARATOR, $ret),
				);

				$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ConfigurationAdmin', 'VariableName = ' . $this->Conn->qstr($variable_name));
			}
		}

		/**
		 * Transforms "FromUserId" into Sender* and Recipients columns
		 *
		 */
		function _transformEmailRecipients()
		{
			$sql = 'SELECT FromUserId, Type, EventId
					FROM ' . TABLE_PREFIX . 'Events
					WHERE FromUserId IS NOT NULL AND (FromUserId <> ' . USER_ROOT . ')';
			$events = $this->Conn->Query($sql, 'EventId');

			$minput_helper =& $this->Application->recallObject('MInputHelper');
			/* @var $minput_helper MInputHelper */

			foreach ($events as $event_id => $event_data) {
				$sql = 'SELECT Login
						FROM ' . TABLE_PREFIX . 'PortalUser
						WHERE PortalUserId = ' . $event_data['FromUserId'];
				$username = $this->Conn->GetOne($sql);

				if (!$username) {
					continue;
				}

				if ($event_data['Type'] == EVENT_TYPE_FRONTEND) {
					// from user
					$fields_hash = Array (
						'CustomSender' => 1,
						'SenderAddressType' => ADDRESS_TYPE_USER,
						'SenderAddress' => $username
					);
				}

				if ($event_data['Type'] == EVENT_TYPE_ADMIN) {
					// to user
					$records = Array (
						Array (
							'RecipientType' => RECIPIENT_TYPE_TO,
							'RecipientName' => '',
							'RecipientAddressType' => ADDRESS_TYPE_USER,
							'RecipientAddress' => $username
						)
					);

					$fields_hash = Array (
						'CustomRecipient' => 1,
						'Recipients' => $minput_helper->prepareMInputXML($records, array_keys( reset($records) ))
					);
				}

				$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Events', 'EventId = ' . $event_id);
			}

			$this->Conn->Query('ALTER TABLE ' . TABLE_PREFIX . 'Events DROP FromUserId');
		}

		/**
		 * Update to 5.1.0; Fixes refferer of form submissions
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_1_0($mode)
		{
			if ($mode == 'after') {
				$base_url = $this->Application->BaseURL();

				$sql = 'UPDATE ' . TABLE_PREFIX . 'FormSubmissions
						SET ReferrerURL = REPLACE(ReferrerURL, ' . $this->Conn->qstr($base_url) . ', "/")';
				$this->Conn->Query($sql);
			}
		}

		/**
		 * Update to 5.1.1-B1; Transforms DisplayToPublic logic
		 *
		 * @param string $mode when called mode {before, after)
		 */
		function Upgrade_5_1_1_B1($mode)
		{
			if ($mode == 'after') {
				$this->processDisplayToPublic();
			}
		}

		function processDisplayToPublic()
		{
			$profile_mapping = Array (
				'pp_firstname' => 'FirstName',
				'pp_lastname' => 'LastName',
				'pp_dob' => 'dob',
				'pp_email' => 'Email',
				'pp_phone' => 'Phone',
				'pp_street' => 'Street',
				'pp_city' => 'City',
				'pp_state' => 'State',
				'pp_zip' => 'Zip',
				'pp_country' => 'Country',
			);

			$fields = array_keys($profile_mapping);
			$fields = array_map(Array (&$this->Conn, 'qstr'), $fields);
			$where_clause = 'VariableName IN (' . implode(',', $fields) . ')';

			// 1. get user, that have saved their profile at least once
			$sql = 'SELECT DISTINCT PortalUserId
					FROM ' . TABLE_PREFIX . 'PersistantSessionData
					WHERE ' . $where_clause;
			$users = $this->Conn->GetCol($sql);

			foreach ($users as $user_id) {
				// 2. convert to new format
				$sql = 'SELECT VariableValue, VariableName
						FROM ' . TABLE_PREFIX . 'PersistantSessionData
						WHERE (PortalUserId = ' . $user_id . ') AND ' . $where_clause;
				$user_variables = $this->Conn->GetCol($sql, 'VariableName');

				// go through mapping to preserve variable order
				$value = Array ();

				foreach ($profile_mapping as $from_name => $to_name) {
					if (array_key_exists($from_name, $user_variables) && $user_variables[$from_name]) {
						$value[] = $to_name;
					}
				}

				if ($value) {
					$fields_hash = Array (
						'DisplayToPublic' => '|' . implode('|', $value) . '|',
					);

					$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'PortalUser', 'PortalUserId = ' . $user_id);
				}

				// 3. delete old style variables
				$sql = 'DELETE FROM ' . TABLE_PREFIX . 'PersistantSessionData
						WHERE (PortalUserId = ' . $user_id . ') AND ' . $where_clause;
				$this->Conn->Query($sql);
			}
		}
	}