Вход Регистрация
Файл: admin/applications/core/modules_admin/applications/hooks.php
Строк: 2591
<?php
/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * Hooks Management
 * Last Updated: $Date: 2012-05-31 11:34:45 -0400 (Thu, 31 May 2012) $
 * </pre>
 *
 * @author         $Author: ips_terabyte $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @subpackage    Core
 * @link        http://www.invisionpower.com
 * @since        3.0.0
 * @version        $Revision: 10844 $
 */

if ( ! defined( 'IN_ACP' ) )
{
    print 
"<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded 'admin.php'.";
    exit();
}

class 
admin_core_applications_hooks extends ipsCommand
{
    
/**
     * Skin object
     *
     * @var        object            Skin templates
     */
    
protected $html;
    
    
/**
     * Hooks library
     *
     * @var        object            Hooks library
     */
    
protected $hooksFunctions;
    
    
/**
     * Existing hooks
     *
     * @var        array             Existing hooks
     */
    
protected $hooks;    
    
    
/**
     * Array of all the cache versions
     * for the required applications
     * 
     * @var    $cachedVersions
     */
    
protected $cachedVersions = array();
    
    
/**
     * Main class entry point
     *
     * @param    object        ipsRegistry reference
     * @return    @e void        [Outputs to screen]
     */
    
public function doExecute( ipsRegistry $registry ) 
    {
        
//-----------------------------------------
        // Load skin
        //-----------------------------------------
        
        
$this->html = $this->registry->output->loadTemplate('cp_skin_applications');
        
        
//-----------------------------------------
        // Load hooks library
        //-----------------------------------------
        
        
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir('core') . '/sources/classes/hooksFunctions.php', 'hooksFunctions' );
        
$this->hooksFunctions = new $classToLoad( $registry );
        
        
// lang already loaded by hookFunctions
        //$this->registry->class_localization->loadLanguageFile( array( 'admin_applications' ), 'core' );

        //-----------------------------------------
        // Set up stuff
        //-----------------------------------------
        
        
$this->form_code    = $this->html->form_code    = 'module=applications&amp;section=hooks&amp;';
        
$this->form_code_js    = $this->html->form_code_js    = 'module=applications&section=hooks&';
        
        
//-----------------------------------------
        // What to do...
        //-----------------------------------------
        
        
switch( $this->request['do'] )
        {
            case 
'reenable_all_hooks':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_reenableAllHooks();
            break;
            case 
'disable_all_hooks':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_disableAllHooks();
            break;
                
            break;
            case 
'disable_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_disableHook();
            break;
            case 
'enable_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_enableHook();
            break;
            
            case 
'uninstall_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_delete' );
                
$this->_uninstallHook();
            break;
            case 
'install_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_installHook();
            break;
            
            case 
'reorder':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_reorder();
            break;
            
            case 
'view_details':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_viewDetails();
            break;
            
            case 
'check_requirements':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_checkRequirements();
            break;
            
            case 
'export_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_exportHook();
            break;
            
            case 
'do_export_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_doExportHook();
            break;
            
            case 
'create_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_hookForm( 'add' );
            break;
            
            case 
'edit_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_hookForm( 'edit' );
            break;
            
            case 
'do_create_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_hookSave( 'add' );
            break;
            
            case 
'do_edit_hook':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->_hookSave( 'edit' );
            break;
            
            case 
'removeDeadCaches':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->removeDeadCaches();
            break;

            case 
'reimport_apps':
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->reimportAppHooks();
            break;

            case 
'hooks_overview':
            default:
                
$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'hooks_manage' );
                
$this->request['do'] = 'hooks_overview';
                
$this->_hooksOverview();
            break;
        }
        
        
//-----------------------------------------
        // Pass to CP output hander
        //-----------------------------------------
        
        
$this->registry->getClass('output')->html_main .= $this->registry->getClass('output')->global_template->global_frame_wrapper();
        
$this->registry->getClass('output')->sendOutput();
    }
    
    
/**
     * Reimport all hooks for all installed applications
     *
     * @return    @e void
     */
    
protected function reimportAppHooks()
    {
        
$stats    = array( 'inserted' => 0, 'updated' => 0, 'skipped' => 0 );
        
        foreach( 
ipsRegistry::$applications as $app )
        {
            
$_stats    = $this->installAppHooks( $app['app_directory'] );
            
            
$stats['inserted']    = $stats['inserted'] + $_stats['inserted'];
            
$stats['updated']    = $stats['updated'] + $_stats['updated'];
            
$stats['skipped']    = $stats['skipped'] + $_stats['skipped'];
        }
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->global_message = sprintf( $this->lang->words['app_hooks_rebuilt'], $stats['inserted'], $stats['updated'], $stats['skipped'] );
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * Rebuild skins following hook import that included a template
     *
     * @return    @e void
     */
    
protected function removeDeadCaches()
    {
        
$messages = array();
        
$keep      = array();
        
$unlink      = array();
        
        
/* Grab all current hooks caches */
        
$this->DB->build( array( 'select' => '*',
                                 
'from'   => 'core_hooks_files' ) );
                                
        
$this->DB->execute();
        
        while( 
$row = $this->DB->fetch() )
        {
            
$keep[] = $row['hook_file_stored'];
        }
        
        try
        {
            foreach( new 
DirectoryIterator( IPS_HOOKS_PATH ) as $file )
            {
                if ( ! 
$file->isDot() )
                {
                    
$_name = $file->getFileName();
                    
                    if ( 
preg_match( "#_[a-z0-9]{32}.php$#", $_name ) )
                    {
                        if ( ! 
in_array( $_name, $keep ) )
                        {
                            
$unlink[] = $_name;
                        }
                    }
                }
            }
        } catch ( 
Exception $e ) { print $e->getMessage(); }
        
        
/* Anything to unlink? */
        
if ( count( $unlink ) )
        {
            foreach( 
$unlink as $file )
            {
                @
unlink( IPS_HOOKS_PATH . $file );
            }
        }
        
        
/* Print message */
        
$this->registry->output->global_message = sprintf( $this->lang->words['hook_removed_files'], count( $unlink ) ) . '<br />' . implode( '<br />', $unlink );
        
$this->_hooksOverview();
    }

    
/**
     * Reorder hooks
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _reorder()
    {
        
//-----------------------------------------
        // INIT
        //-----------------------------------------

        
$classToLoad = IPSLib::loadLibrary( IPS_KERNEL_PATH . 'classAjax.php', 'classAjax' );
        
$ajax         = new $classToLoad();
        
        
//-----------------------------------------
        // Checks...
        //-----------------------------------------

        
if( $this->registry->adminFunctions->checkSecurityKey( $this->request['md5check'], true ) === false )
        {
            
$ajax->returnString( $this->lang->words['postform_badmd5'] );
        }
         
         
//-----------------------------------------
         // Save new position
         //-----------------------------------------

         
$position    = 1;
         
         if( 
is_array($this->request['hooks']) AND count($this->request['hooks']) )
         {
             
/* Reset all hooks to 0 temporarily */
             
$this->DB->update( 'core_hooks', array( 'hook_position' => 0 ) );
             
             foreach( 
$this->request['hooks'] as $this_id )
             {
                 
$this->DB->update( 'core_hooks', array( 'hook_position' => $position ), 'hook_id=' . $this_id );
                 
                 
$position++;
             }
         }
         
        
$this->rebuildHooksCache();

         
$ajax->returnString('OK');
    }
    
    
/**
     * Install a new hook
     *
     * @return   void
     */
    
protected function _installHook()
    {
        
//-----------------------------------------
        // Get uploaded schtuff
        //-----------------------------------------

        
$tmp_name = $_FILES['FILE_UPLOAD']['name'];
        
$tmp_name = preg_replace( "#.gz$#", "", $tmp_name );
        
        
$content  = ipsRegistry::getClass('adminFunctions')->importXml( $tmp_name );
        
        if( ! 
$content )
        {
            
$this->registry->output->showError( $this->lang->words['h_noxml'], 1110 );
        }

        
$this->installHook( $content, TRUE, FALSE );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * Function mostly used in installer/upgrader
     * Inserts new hooks
     *
     * @param    string        Application to install hooks for
     */
    
public function installAppHooks( $app )
    {
        static 
$hooks    = array();

        
$msgs    = array( 'inserted' => 0, 'updated' => 0, 'skipped' => 0 );
        
$xmlData = array();
        
$path    = IPSLib::getAppDir( $app ) . '/xml';
        
        if ( 
is_file( $path . '/hooks.xml' ) AND is_dir( $path . '/hooks' ) )
        {
            if( !
count($hooks) )
            {
                
/* Fetch current hooks */
                
$this->DB->build( array( 'select' => '*',
                                         
'from'   => 'core_hooks' ) );
                
$this->DB->execute();
                
                while( 
$row = $this->DB->fetch() )
                {
                    if ( 
$row['hook_key'] )
                    {
                        
$hooks[ $row['hook_key'] ] = $row;
                    }
                }
            }
            
            
/* Alright. We're in. Read the XML file */
            
require_once( IPS_KERNEL_PATH . 'classXML.php' );/*noLibHook*/
            
$xml    = new classXML( IPS_DOC_CHAR_SET );

            
/* Grab wrapper file */
            
$xml->load(  $path . '/hooks.xml' );

            foreach( 
$xml->fetchElements('hook') as $data )
            {
                
$xmlData[] = $xml->fetchElementsFromRecord( $data );
            }

            
/* Examine XML */
            
if ( is_array( $xmlData ) AND count( $xmlData ) )
            {
                foreach( 
$xmlData as $x )
                {
                    if ( 
is_file( $path . '/hooks/' . $x['file'] ) )
                    {
                        
$xml->load(  $path . '/hooks/' . $x['file'] );
                        
                        foreach( 
$xml->fetchElements('config') as $data )
                        {
                            
$config    = $xml->fetchElementsFromRecord( $data );
                        }
                        
                        if ( ! isset( 
$hooks[ $config['hook_key'] ] ) )
                        {
                            
/* Add it */
                            
$msgs['inserted']++;
                            
$this->installHook( file_get_contents( $path . '/hooks/' . $x['file'] ), FALSE, FALSE, $x['enabled'] );
                        } 
                        else
                        {
                            
$this->installHook( file_get_contents( $path . '/hooks/' . $x['file'] ), FALSE, FALSE, $x['enabled'] );
                            
$msgs['updated']++;
                        }
                    }
                }
            }
        }
        
        return 
$msgs;
    }
    
    
/**
     * Public install hook so we can use it in the installer and elsewhere
     *
     * @param    string        XML data
     * @param    boolean        Add message to output->global_message
     * @param    boolean        Allow skins to recache
     * @param    int            Install enabled
     * @return    @e void
     */
    
public function installHook( $content, $addMessage=FALSE, $allowSkinRecache=TRUE, $enabled=1 )
    {
        
//-----------------------------------------
        // Hooks directory writable?
        //-----------------------------------------
        
        
if( !is_writable( IPS_HOOKS_PATH ) )
        {
            if( !
$addMessage )
            {
                return 
false;
            }

            
$this->registry->output->showError( $this->lang->words['h_dir_notwritable'], 111159 );
        }
        
        
//-----------------------------------------
        // Got our hooks?
        //-----------------------------------------
        
        
if( !is_array($this->hooks) OR !count($this->hooks) )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$this->hooks[ $r['hook_key'] ]    = $r;
            }
        }

        
//-----------------------------------------
        // Get xml mah-do-dah
        //-----------------------------------------
        
        
require_once( IPS_KERNEL_PATH . 'classXML.php' );/*noLibHook*/
        
$xml    = new classXML( IPS_DOC_CHAR_SET );
        
        
//-----------------------------------------
        // Unpack the datafile
        //-----------------------------------------
        
        
$xml->loadXML( $content );

        foreach( 
$xml->fetchElements('config') as $data )
        {
            
$config    = $xml->fetchElementsFromRecord( $data );

            if( !
count($config) )
            {
                
$this->registry->output->showError( $this->lang->words['h_xmlwrong'], 1111 );
            }
        }
        
        
//-----------------------------------------
        // Temp
        //-----------------------------------------
        
        
$tempExtraData = unserialize( $config['hook_extra_data'] );

        
//-----------------------------------------
        // Set config
        //-----------------------------------------
        
        
$config = array('hook_name'                => $config['hook_name'],
                        
'hook_desc'                => $config['hook_desc'],
                        
'hook_author'            => $config['hook_author'],
                        
'hook_email'            => $config['hook_email'],
                        
'hook_website'            => $config['hook_website'],
                        
'hook_update_check'        => $config['hook_update_check'],
                        
'hook_requirements'        => $config['hook_requirements'],
                        
'hook_version_human'    => $config['hook_version_human'],
                        
'hook_version_long'        => $config['hook_version_long'],
                        
'hook_key'                => $config['hook_key'],
                        
'hook_global_caches'    => $config['hook_global_caches'],
                        
'hook_enabled'            => $enabled,
                        
'hook_updated'            => IPS_UNIX_TIME_NOW,
                        );

        
$extra_data    = array();

        
//-----------------------------------------
        // Set files
        //-----------------------------------------
        
        
$files        = array();

        foreach( 
$xml->fetchElements('hookfiles') as $node )
        {
            foreach( 
$xml->fetchElements('file', $node) as $_file )
            {
                
$file    = $xml->fetchElementsFromRecord( $_file );
    
                if( 
$file['hook_type'] )
                {
                    
$files[]     = array(
                                        
'hook_file_real'    => $file['hook_file_real'],
                                        
'hook_type'            => $file['hook_type'],
                                        
'hook_classname'    => $file['hook_classname'],
                                        
'hook_data'            => $file['hook_data'],
                                        
'hooks_source'        => $file['hooks_source'],
                                        );
                }
            }
        }

        
//-----------------------------------------
        // Set the custom script
        //-----------------------------------------

        
$custom         = array();
        
$customClass = null;

        foreach( 
$xml->fetchElements('hookextras_custom') as $node )
        {
            foreach( 
$xml->fetchElements('file', $node) as $_file )
            {
                
$file    = $xml->fetchElementsFromRecord( $_file );
                
                if( 
count($file) )
                {
                    
$custom    = array( 'filename'    => $file['filename'],
                                     
'source'    => $file['source'],
                                    );
                }
            }
        }
        
        
/* Got any custom file to initialize? */
        
if ( $custom['filename'] && $custom['source'] )
        {
            
# Our dirty trick to avoid saving the file on disk just yet...
            
$_custom = preg_replace( '#^(s*)<?(php)+#i', '', $custom['source'] );
            eval(
$_custom);
            
            
$classname = str_replace( '.php', '', $custom['filename'] );
            
            if( 
class_exists( $classname ) )
            {
                
$customClass = new $classname( $this->registry );
                
                if( 
method_exists( $customClass, 'pre_install' ) )
                {
                    
$customClass->pre_install();
                }
            }
        }
        
        
//-----------------------------------------
        // Set the settings
        //-----------------------------------------
        
        
$settings        = array();
        
$settingGroups    = array();

        foreach( 
$xml->fetchElements('hookextras_settings') as $node )
        {
            foreach( 
$xml->fetchElements('setting', $node) as $_setting )
            {
                
$setting    = $xml->fetchElementsFromRecord( $_setting );
    
                if( 
$setting['conf_is_title'] == 1)
                {
                    
$settingGroups[]    = array(
                                                
'conf_title_title'        => $setting['conf_title_title'],
                                                
'conf_title_desc'        => $setting['conf_title_desc'],
                                                
'conf_title_noshow'        => $setting['conf_title_noshow'],
                                                
'conf_title_keyword'    => $setting['conf_title_keyword'],
                                                
'conf_title_app'        => $setting['conf_title_app'],
                                                
'conf_title_tab'        => $setting['conf_title_tab'],
                                                );
                }
                else
                {
                    
$settings[]            = array(
                                                
'conf_title'            => $setting['conf_title'],
                                                
'conf_description'        => $setting['conf_description'],
                                                
'conf_group'            => $setting['conf_group'],
                                                
'conf_type'                => $setting['conf_type'],
                                                
'conf_key'                => $setting['conf_key'],
                                                
'conf_default'            => $setting['conf_default'],
                                                
'conf_extra'            => $setting['conf_extra'],
                                                
'conf_evalphp'            => $setting['conf_evalphp'],
                                                
'conf_protected'        => $setting['conf_protected'],
                                                
'conf_position'            => $setting['conf_position'],
                                                
'conf_start_group'        => $setting['conf_start_group'],
                                                
'conf_add_cache'        => $setting['conf_add_cache'],
                                                
'conf_title_keyword'    => $setting['conf_title_keyword'],
                                                );
                }
            }
        }

        
//-----------------------------------------
        // Set the lang bits
        //-----------------------------------------
        
        
$language        = array();

        foreach( 
$xml->fetchElements('hookextras_language') as $node )
        {
            foreach( 
$xml->fetchElements('language', $node) as $_langbit )
            {
                
$langbit    = $xml->fetchElementsFromRecord( $_langbit );
                
                
$language[]    = array(
                                    
'word_app'        => $langbit['word_app'],
                                    
'word_pack'        => $langbit['word_pack'],
                                    
'word_key'        => $langbit['word_key'],
                                    
'word_default'    => $langbit['word_default'],
                                    
'word_custom'    => $langbit['word_custom'],
                                    
'word_js'        => intval($langbit['word_js']),
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the modules
        //-----------------------------------------
        
        
$modules        = array();

        foreach( 
$xml->fetchElements('hookextras_modules') as $node )
        {
            foreach( 
$xml->fetchElements('module', $node) as $_module )
            {
                
$module        = $xml->fetchElementsFromRecord( $_module );
                
$modules[]    = array(
                                    
'sys_module_title'            => $module['sys_module_title'],
                                    
'sys_module_application'    => $module['sys_module_application'],
                                    
'sys_module_key'            => $module['sys_module_key'],
                                    
'sys_module_description'    => $module['sys_module_description'],
                                    
'sys_module_version'        => $module['sys_module_version'],
                                    
'sys_module_protected'        => $module['sys_module_protected'],
                                    
'sys_module_visible'        => $module['sys_module_visible'],
                                    
'sys_module_position'        => $module['sys_module_position'],
                                    
'sys_module_admin'            => $module['sys_module_admin'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the help files
        //-----------------------------------------
        
        
$help            = array();

        foreach( 
$xml->fetchElements('hookextras_help') as $node )
        {
            foreach( 
$xml->fetchElements('help', $node) as $_helpfile )
            {
                
$helpfile    = $xml->fetchElementsFromRecord( $_helpfile );
                
$help[]        = array(
                                    
'title'            => $helpfile['title'],
                                    
'text'            => $helpfile['text'],
                                    
'description'    => $helpfile['description'],
                                    
'position'        => $helpfile['position'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the templates
        //-----------------------------------------
        
        
$templates        = array();

        foreach( 
$xml->fetchElements('hookextras_templates') as $node )
        {
            foreach( 
$xml->fetchElements('templates', $node) as $_template )
            {
                
$template        = $xml->fetchElementsFromRecord( $_template );
                
$templates[]    = array(
                                        
'template_set_id'        => 0,
                                        
'template_group'        => $template['template_group'],
                                        
'template_content'        => $template['template_content'],
                                        
'template_name'            => $template['template_name'],
                                        
'template_data'            => $template['template_data'],
                                        
'template_updated'        => $template['template_updated'],
                                        
'template_removable'    => $template['template_removable'],
                                        
'template_added_to'        => intval($template['template_added_to']),
                                        
'template_user_added'    => 1,
                                        
'template_user_edited'  => 0,
                                        
'template_master_key'   => $template['template_master_key'] ? $template['template_master_key'] : 'root',
                                        );
            }
        }
        
        
//-----------------------------------------
        // Set the CSS
        //-----------------------------------------
        
        
$css            = array();

        foreach( 
$xml->fetchElements('hookextras_css') as $node )
        {
            foreach( 
$xml->fetchElements('css', $node) as $_css )
            {
                
$_css    = $xml->fetchElementsFromRecord( $_css );
                
$css[]    = array(
                                    
'css_set_id'        => 0,
                                    
'css_group'            => $_css['css_group'],
                                    
'css_content'        => $_css['css_content'],
                                    
'css_position'        => $_css['css_position'],
                                    
'css_added_to'        => 1,
                                    
'css_app'            => $_css['css_app'],
                                    
'css_app_hide'        => $_css['css_app_hide'],
                                    
'css_attributes'    => $_css['css_attributes'],
                                    
'css_removed'        => $_css['css_removed'],
                                    
'css_modules'        => $_css['css_modules'],
                                    
'css_master_key'    => $_css['css_master_key'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the Replacements
        //-----------------------------------------
        
        
$replacements    = array();
        
        foreach( 
$xml->fetchElements('hookextras_replacements') as $node )
        {
            foreach( 
$xml->fetchElements('replacements', $node) as $_r )
            {
                
$_r    = $xml->fetchElementsFromRecord( $_r );
                
$replacements[]    = array(
                                    
'replacement_key'        => $_r['replacement_key'],
                                    
'replacement_content'    => $_r['replacement_content'],
                                    );
            }
        }
        
        
//-----------------------------------------
        // Set the tasks
        //-----------------------------------------
        
        
$tasks            = array();

        foreach( 
$xml->fetchElements('hookextras_tasks') as $node )
        {
            foreach( 
$xml->fetchElements('tasks', $node) as $_task )
            {
                
$task        = $xml->fetchElementsFromRecord( $_task );
                
$tasks[]    = array(
                                    
'task_title'        => $task['task_title'],
                                    
'task_file'            => $task['task_file'],
                                    
'task_week_day'        => $task['task_week_day'],
                                    
'task_month_day'    => $task['task_month_day'],
                                    
'task_hour'            => $task['task_hour'],
                                    
'task_minute'        => $task['task_minute'],
                                    
'task_cronkey'        => $task['task_cronkey'],
                                    
'task_log'            => $task['task_log'],
                                    
'task_description'    => $task['task_description'],
                                    
'task_enabled'        => $task['task_enabled'],
                                    
'task_key'            => $task['task_key'],
                                    
'task_safemode'        => $task['task_safemode'],
                                    
'task_locked'        => $task['task_locked'],
                                    
'task_application'    => $task['task_application'],
                                    );
            }
        }

        
//-----------------------------------------
        // Set the database changes
        //-----------------------------------------
        
        
$database        = array(
                                
'create'    => array(),
                                
'alter'        => array(),
                                
'update'    => array(),
                                
'insert'    => array(),
                                );

        foreach( 
$xml->fetchElements('hookextras_database_create') as $node )
        {
            foreach( 
$xml->fetchElements('create', $node) as $_table )
            {
                
$table        = $xml->fetchElementsFromRecord( $_table );
                
$database['create'][]    = array(
                                            
'name'        => $table['name'],
                                            
'fields'    => $table['fields'],
                                            
'tabletype'    => $table['tabletype'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_alter') as $node )
        {
            foreach( 
$xml->fetchElements('alter', $node) as $_table )
            {
                
$table        = $xml->fetchElementsFromRecord( $_table );
                
$database['alter'][]    = array(
                                            
'altertype'    => $table['altertype'],
                                            
'table'        => $table['table'],
                                            
'field'        => $table['field'],
                                            
'newfield'    => $table['newfield'],
                                            
'fieldtype'    => $table['fieldtype'],
                                            
'default'    => $table['default'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_update') as $node )
        {
            foreach( 
$xml->fetchElements('update', $node) as $_table )
            {
                
$table        = $xml->fetchElementsFromRecord( $_table );
                
$database['update'][]    = array(
                                            
'table'        => $table['table'],
                                            
'field'        => $table['field'],
                                            
'newvalue'    => $table['newvalue'],
                                            
'oldvalue'    => $table['oldvalue'],
                                            
'where'        => $table['where'],
                                            );
            }
        }

        foreach( 
$xml->fetchElements('hookextras_database_insert') as $node )
        {
            foreach( 
$xml->fetchElements('insert', $node) as $_table )
            {
                
$table        = $xml->fetchElementsFromRecord( $_table );
                
$database['insert'][]    = array(
                                            
'table'        => $table['table'],
                                            
'updates'    => $table['updates'],
                                            
'fordelete'    => $table['fordelete'],
                                            );
            }
        }

        
//-----------------------------------------
        // Set some vars for display tallies
        //-----------------------------------------

        
$filesInserted            = 0;
        
$settingGroupsInserted    = 0;
        
$settingsInserted        = 0;
        
$settingsUpdated        = 0;
        
$languageInserted        = 0;
        
$languageUpdated        = 0;
        
$modulesInserted        = 0;
        
$modulesUpdated            = 0;
        
$helpInserted            = 0;
        
$helpUpdated            = 0;
        
$templatesInserted        = 0;
        
$templatesUpdated        = 0;
        
$templateHooks            = false;
        
$tasksInserted            = 0;
        
$tasksUpdated            = 0;
        
$createQueries            = 0;
        
$alterQueries            = 0;
        
$updateQueries            = 0;
        
$insertQueries            = 0;
        
$cssInserted            = 0;
        
$cssUpdated                = 0;
        
$replacementsInserted    = 0;
        
$replacementsUpdated    = 0;
        
        
//-----------------------------------------
        // Insert/update DB records
        //-----------------------------------------
        
        
if( $this->hooks[ $config['hook_key'] ]['hook_id'] )
        {
            
//-----------------------------------------
            // Don't change enabled/disabled status
            //-----------------------------------------
            
            
unset( $config['hook_enabled'] );
            
            
$this->DB->update( 'core_hooks', $config, 'hook_id=' . $this->hooks[ $config['hook_key'] ]['hook_id'] );
            
            
$hook_id    = $this->hooks[ $config['hook_key'] ]['hook_id'];
            
            
$extra_data    = unserialize( $this->hooks[ $config['hook_key'] ]['hook_extra_data'] );
            
            
/* Reset DB */
            
$extra_data['database'] = array();
        }
        else
        {
            
$config['hook_installed']            = IPS_UNIX_TIME_NOW;
            
$this->hook[ $config['hook_key'] ]    = $config;
            
            
$this->DB->insert( 'core_hooks', $config );
            
            
$hook_id    = $this->DB->getInsertId();
            
            
$this->hook[ $config['hook_key'] ]['hook_id'] = $hook_id;
            
            
$extra_data['display']    = $tempExtraData['display'];
        }

        if( 
count($files) )
        {
            
//-----------------------------------------
            // If we are updating, remove old files
            //-----------------------------------------
            
            
if( $this->hooks[ $config['hook_key'] ]['hook_id'] )
            {
                
$this->DB->build( array( 'select' => 'hook_file_id, hook_file_stored', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . $this->hooks[ $config['hook_key'] ]['hook_id'] ) );
                
$outer = $this->DB->execute();
                
                while( 
$r = $this->DB->fetch($outer) )
                {
                    @
unlink( IPS_HOOKS_PATH . $r['hook_file_stored'] );
                    
$this->DB->delete( 'core_hooks_files', 'hook_file_id=' . $r['hook_file_id'] );
                }
            }
                
            foreach( 
$files as $file )
            {
                
//-----------------------------------------
                // Store new files
                //-----------------------------------------
                
                
$filename    = $file['hook_classname'] . '_' . md5( uniqid( microtime(), true ) ) . '.php';
                
                
file_put_contents( IPS_HOOKS_PATH . $filename, $file['hooks_source'] );
                
chmod( IPS_HOOKS_PATH . $filename, IPS_FILE_PERMISSION );
                
                
$file['hook_file_stored']    = $filename;
                
$file['hook_hook_id']        = $hook_id;
                
                
$this->DB->insert( 'core_hooks_files', $file );
                
$filesInserted++;
                
                
/* Need to recache skins? */
                
if ( $file['hook_type'] == 'templateHooks' )
                {
                    
$templateHooks = true;
                }
            }
        }
        
        
//-----------------------------------------
        // Put custom install/uninstall file
        //-----------------------------------------
        
        
if( is_object($customClass) )
        {
            
$extra_data['display']['custom'] = $custom['filename'];
            
            
file_put_contents( IPS_HOOKS_PATH . 'install_' . $custom['filename'], $custom['source'] );
            
chmod( IPS_HOOKS_PATH . 'install_' . $custom['filename'], IPS_FILE_PERMISSION );
        }
                
        
//-----------------------------------------
        // (1) Settings
        //-----------------------------------------
        
        
if( count($settingGroups) OR count($settings) )
        {
            
$setting_groups = array();
            
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_settings_titles' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$setting_groups[ $r['conf_title_id'] ] = $r;
                
$setting_groups_by_key[ $r['conf_title_keyword'] ] = $r;
            }
            
            
//-----------------------------------------
            // Get current settings.
            //-----------------------------------------
            
            
$this->DB->build( array( 'select' => 'conf_id, conf_key', 'from' => 'core_sys_conf_settings' ) );
            
$this->DB->execute();
            
            while ( 
$r = $this->DB->fetch() )
            {
                
$cur_settings[ $r['conf_key'] ] = $r['conf_id'];
            }
        }
            
        if( 
count($settingGroups) )
        {
            
$need_to_update = array();
            
            foreach( 
$settingGroups as $data )
            {
                if ( 
$data['conf_title_title'] AND $data['conf_title_keyword'] )
                {
                    
//-----------------------------------------
                    // Get ID based on key
                    //-----------------------------------------
                    
                    
$conf_id = $setting_groups_by_key[ $data['conf_title_keyword'] ]['conf_title_id'];
                    
                    
$save = array( 'conf_title_title'   => $data['conf_title_title'],
                                   
'conf_title_desc'    => $data['conf_title_desc'],
                                   
'conf_title_keyword' => $data['conf_title_keyword'],
                                   
'conf_title_app'     => $data['conf_title_app'],
                                   
'conf_title_tab'        => $data['conf_title_tab'],
                                   
'conf_title_noshow'  => $data['conf_title_noshow']  );
                    
                    
//-----------------------------------------
                    // Not got a row, insert first!
                    //-----------------------------------------
                    
                    
if ( ! $conf_id )
                    {
                        
$this->DB->insert( 'core_sys_settings_titles', $save );
                        
$conf_id = $this->DB->getInsertId();
                        
$settingGroupsInserted++;
                        
$extra_data['settingGroups'][] = $save['conf_title_keyword'];
                    }
                    else
                    {
                        
//-----------------------------------------
                        // Update...
                        //-----------------------------------------
                        
                        
$this->DB->update( 'core_sys_settings_titles', $save, 'conf_title_id='.$conf_id );
                    }
                    
                    
//-----------------------------------------
                    // Update settings cache
                    //-----------------------------------------
                    
                    
$save['conf_title_id']                                    = $conf_id;
                    
$setting_groups_by_key[ $save['conf_title_keyword'] ]    = $save;
                    
$setting_groups[ $save['conf_title_id'] ]                = $save;
                        
                    
//-----------------------------------------
                    // Set need update...
                    //-----------------------------------------
                    
                    
$need_update[] = $conf_id;
                }
            }
        }
        
        if( 
count($settings) )
        {
            foreach( 
$settings as $idx => $data )
            {
                
$data['conf_group'] = $setting_groups_by_key[ $data['conf_title_keyword'] ]['conf_title_id'];
                
                
//-----------------------------------------
                // Remove from array
                //-----------------------------------------
                
                
unset( $data['conf_title_keyword'] );
                
                if ( 
$cur_settings[ $data['conf_key'] ] )
                {
                    
$this->DB->update( 'core_sys_conf_settings', $data, 'conf_id='.$cur_settings[ $data['conf_key'] ] );
                    
$settingsUpdated++;
                }
                else
                {
                    
$this->DB->insert( 'core_sys_conf_settings', $data );
                    
$settingsInserted++;
                    
$extra_data['settings'][] = $data['conf_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // Update group counts...
        //-----------------------------------------
        
        
if ( count( $need_update ) )
        {
            foreach( 
$need_update as $i => $idx )
            {
                
$conf = $this->DB->buildAndFetch( array( 'select' => 'count(*) as count', 'from' => 'core_sys_conf_settings', 'where' => 'conf_group=' . $idx ) );
            
                
$count = intval($conf['count']);
                
                
$this->DB->update( 'core_sys_settings_titles', array( 'conf_title_count' => $count ), 'conf_title_id='.$idx );
            }
        }
        
        if( 
count($settingGroups) OR count($settings) )
        {
            
$this->cache->rebuildCache( 'settings', 'global' );
        }

        
//-----------------------------------------
        // (2) Languages
        //-----------------------------------------

        
if( count($language) )
        {
            
$langPacks    = array();
            
            
$this->DB->build( array( 'select' => 'lang_id', 'from' => 'core_sys_lang' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$langPacks[] = $r['lang_id'];
            }

            foreach( 
$language as $langbit )
            {
                foreach( 
$langPacks as $lang_id )
                {
                    
$langbit['lang_id'] = $lang_id;
                    
                    
// See if it exists
                    
$cnt = $this->DB->buildAndFetch( array( 'select' => 'word_id', 'from' => 'core_sys_lang_words', 'where' => "lang_id={$lang_id} AND word_app='{$langbit['word_app']}' AND word_key='{$langbit['word_key']}' AND word_pack='{$langbit['word_pack']}'" ) );
                    
                    if( 
$cnt['word_id'] )
                    {
                        
$this->DB->update( 'core_sys_lang_words', $langbit, 'word_id=' . $cnt['word_id'] );
                        
$languageUpdated++;
                    }
                    else
                    {
                        
$this->DB->insert( 'core_sys_lang_words', $langbit );
                        
$languageInserted++;
                        
$word_id = $this->DB->getInsertId();
                        
$extra_data['language'][ $langbit['word_pack'] ][]    = $langbit['word_key'];
                    }
                }
            }
            
            
$classToLoad = IPSLib::loadActionOverloader( IPSLib::getAppDir('core') . '/modules_admin/languages/manage_languages.php', 'admin_core_languages_manage_languages' );
            
$langLib     = new $classToLoad();
            
$langLib->makeRegistryShortcuts( $this->registry );
            
            foreach( 
$langPacks as $langId )
            {
                
$langLib->cacheToDisk( $langId );
            }
        }
        
        
//-----------------------------------------
        // (3) Modules
        //-----------------------------------------
        
        
if( count($modules) )
        {
            
//-----------------------------------------
            // Get current modules
            //-----------------------------------------
            
$cur_modules = array();
            
$this->DB->build( array( 'select'    => '*',
                                        
'from'    => 'core_sys_module',
                                        
'order'    => 'sys_module_id' ) );
            
            
$this->DB->execute();
            
            while ( 
$r = $this->DB->fetch() )
            {
                
$cur_modules[ $r['sys_module_application'] ][ $r['sys_module_key'] ] = $r['sys_module_id'];
            }
            
            foreach( 
$modules as $module )
            {
                
//-----------------------------------------
                // Insert or update?
                //-----------------------------------------
            
                
if ( $cur_modules[ $module['sys_module_application'] ][ $module['sys_module_key'] ] )
                {
                    
$this->DB->update( 'core_sys_module', $module, "sys_module_id=" . $cur_modules[ $module['sys_module_application'] ][ $module['sys_module_key'] ] );
                    
$modulesUpdated++;
                }
                else
                {
                    
$this->DB->insert( 'core_sys_module', $module );
                    
$modulesInserted++;
                    
                    
$extra_data['modules'][] = ( $module['sys_module_admin'] ? 'admin' : 'public' ) . '-' . $module['sys_module_application'] . '-' . $module['sys_module_key'];
                }
            }
            
            
$classToLoad = IPSLib::loadActionOverloader( IPSLib::getAppDir('core') . '/modules_admin/applications/applications.php', 'admin_core_applications_applications' );
            
$moduleLib   = new $classToLoad();
            
$moduleLib->makeRegistryShortcuts( $this->registry );
            
$moduleLib->moduleRecache();
            
$moduleLib->applicationsMenuDataRecache();
        }
        
        
//-----------------------------------------
        // (4) Help Files
        //-----------------------------------------
        
        
if( count($help) )
        {
            
$keys        = array();
            
            
$this->DB->build( array( 'select' => 'title', 'from' => 'faq' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$keys[] = $r['title'];
            }

            foreach( 
$help as $entry )
            {
                if( 
in_array( $entry['title'], $keys ) )
                {
                    
$this->DB->update( 'faq', $entry, "title='{$entry['title']}'" );
                    
$helpUpdated++;
                }
                else
                {    
                    
$this->DB->insert( 'faq', $entry );
                    
$helpInserted++;
                    
$help_id = $this->DB->getInsertId();
                    
$extra_data['help'][] = $entry['title'];
                }
            }
        }

        
//-----------------------------------------
        // (6) Templates
        //-----------------------------------------
        
        
if( count($templates) )
        {
            
$bits        = array();
            
            
/* Root will always be updated */
            
$this->DB->build( array( 'select' => 'template_name,template_group,template_master_key', 'from' => 'skin_templates' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$bits[ $r['template_master_key'] ][ $r['template_group'] ][] = $r['template_name'];
            }

            foreach( 
$templates as $template )
            {
                
//-----------------------------------------
                // If template is not in root set, add it to
                // prevent fatal error selecting other skins
                //-----------------------------------------
                
                
if ( $template['template_master_key'] != 'root' && ( !isset($bits['root'][ $template['template_group'] ]) OR !in_array( $template['template_name'], $bits['root'][ $template['template_group'] ] ) ) )
                {
                    
$this->DB->insert( 'skin_templates', array_merge( $template, array( 'template_set_id' => 0, 'template_master_key' => 'root', 'template_content' => '' ) ) );
                    
                    
$extra_data['templates'][ $template['template_group'] ][ $template['template_name'] ]    = $template['template_name'];
                    
$bits['root'][ $template['template_group'] ][]                                            = $template['template_name'];
                }
                
                
//-----------------------------------------
                // Ignore unknown skin sets
                //-----------------------------------------
                
                
if ( !isset($bits[ $template['template_master_key'] ]) )
                {
                    continue;
                }
                
                if( isset(
$bits[ $template['template_master_key'] ][ $template['template_group'] ]) AND in_array( $template['template_name'], $bits[ $template['template_master_key'] ][ $template['template_group'] ] ) )
                {
                    
$template['template_updated'] = IPS_UNIX_TIME_NOW;

                    
$this->DB->update( 'skin_templates', $template, "template_master_key='{$template['template_master_key']}' AND template_group='{$template['template_group']}' AND template_name='{$template['template_name']}'" );
                    
$templatesUpdated++;
                }
                else
                {    
                    
$this->DB->insert( 'skin_templates', $template );
                    
$templatesInserted++;

                    
$extra_data['templates'][ $template['template_group'] ][ $template['template_name'] ]    = $template['template_name'];
                    
$bits[ $template['template_master_key'] ][ $template['template_group'] ][]                = $template['template_name'];
                }
            }
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------
        
        
if( count( $css ) )
        {
            
$bits        = array();
            
            
$this->DB->build( array( 'select' => 'css_master_key, css_group', 'from' => 'skin_css' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$bits[ $r['css_master_key'] ][ $r['css_group'] ] = $r['css_group'];
            }

            foreach( 
$css as $entry )
            {
                
//-----------------------------------------
                // Ignore unknown skin sets
                //-----------------------------------------
                
                
if ( !isset( $bits[ $entry['css_master_key'] ] ) )
                {
                    continue;
                }
                
                if( 
in_array( $entry['css_group'], $bits[ $entry['css_master_key'] ] ) )
                {
                    
$entry['css_updated']    = IPS_UNIX_TIME_NOW;

                    
$this->DB->update( 'skin_css', $entry, "css_master_key='{$entry['css_master_key']}' AND css_group='{$entry['css_group']}'" );
                    
$cssUpdated++;
                }
                else
                {    
                    
$this->DB->insert( 'skin_css', $entry );
                    
$cssInserted++;

                    
$extra_data['css'][ $entry['css_group'] ]                    = $entry['css_group'];
                    
$bits[ $entry['css_master_key'] ][ $entry['css_group'] ]    = $entry['css_group'];
                }
            }
        }
        
        
//-----------------------------------------
        // Skin Replacements
        //-----------------------------------------
                
        
if( count( $replacements ) )
        {
            
$bits        = array();
            
            
$this->DB->build( array( 'select' => 'replacement_master_key, replacement_key', 'from' => 'skin_replacements' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$bits[ $r['replacement_master_key'] ][ $r['replacement_key'] ] = $r['replacement_key'];
            }
            
            foreach( 
$replacements as $entry )
            {
                if ( !isset( 
$bits[ $entry['replacement_master_key'] ] ) )
                {
                    
$entry['replacement_master_key'] = 'root';
                }
            
                if( 
in_array( $entry['replacement_key'], $bits[ $entry['replacement_master_key'] ] ) )
                {
                    
$this->DB->update( 'skin_replacements', $entry, "replacement_master_key='{$entry['replacement_master_key']}' AND replacement_key='{$entry['replacement_key']}'" );
                    
$replacementsUpdated++;
                }
                else
                {    
                    
$this->DB->insert( 'skin_replacements', $entry );
                    
$replacementsInserted++;

                    
$extra_data['replacements'][ $entry['replacement_key'] ]        = $entry['replacement_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // (7) Tasks
        //-----------------------------------------
        
        
if( count($tasks) )
        {
            
$keys        = array();
            
            
$this->DB->build( array( 'select' => 'task_key', 'from' => 'task_manager' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$keys[] = $r['task_key'];
            }

            foreach( 
$tasks as $entry )
            {
                if( 
in_array( $entry['task_key'], $keys ) )
                {
                    
$this->DB->update( 'task_manager', $entry, "task_key='{$entry['task_key']}'" );
                    
$tasksUpdated++;
                }
                else
                {    
                    
$this->DB->insert( 'task_manager', $entry );
                    
$tasksInserted++;
                    
$task_id = $this->DB->getInsertId();
                    
$extra_data['tasks'][] = $entry['task_key'];
                }
            }
        }
        
        
//-----------------------------------------
        // (8) Create new tables
        //-----------------------------------------
        
        
if( count($database['create']) )
        {
            foreach(
$database['create'] as $create )
            {
                
$query    = "CREATE TABLE {$this->settings['sql_tbl_prefix']}{$create['name']} (
                            
{$create['fields']}
                            )"
;
                
                if( 
$create['tabletype'] )
                {
                    
$query .= " ENGINE=" . $create['tabletype'];
                }
                else if( 
$this->settings['sql_driver'] == 'mysql' AND $this->settings['mysql_tbl_type'] )
                {
                    
$query .= " ENGINE=" . $this->settings['mysql_tbl_type'];
                }
                
                
//-----------------------------------------
                // Fix prefix
                //-----------------------------------------

                
$this->DB->return_die = true;
                
$this->DB->query( $query );
                
$this->DB->return_die = false;
                
$createQueries++;
                
                
$extra_data['database']['create'][] = $create;
            }
        }

        
//-----------------------------------------
        // (9) Alter tables
        //-----------------------------------------
        
        
if( count($database['alter']) )
        {
            foreach( 
$database['alter'] as $alter )
            {
                
$this->DB->return_die = true;
                
                switch( 
$alter['altertype'] )
                {
                    case 
'remove':
                        
$this->DB->dropField( $alter['table'], $alter['field'] );
                    break;
                    
                    case 
'add':
                        
$this->DB->addField( $alter['table'], $alter['field'], $alter['fieldtype'], $alter['default'] );
                    break;
                    
                    case 
'change':
                        
$this->DB->changeField( $alter['table'], $alter['field'], $alter['newfield'], $alter['fieldtype'], $alter['default'] );
                    break;
                }
                
                
$this->DB->return_die = false;
                
$alterQueries++;
                
$extra_data['database']['alter'][] = $alter;
            }
        }
        
        
//-----------------------------------------
        // (10) Run update queries
        //-----------------------------------------
        
        
if( count($database['update']) )
        {
            foreach( 
$database['update'] as $update )
            {
                
$this->DB->return_die = true;
                
$this->DB->update( $update['table'], array( $update['field'] => $update['newvalue'] ), html_entity_decode( $update['where'], ENT_QUOTES ) );
                
$this->DB->return_die = false;
                
$updateQueries++;
                
$extra_data['database']['update'][] = $update;
            }
        }
        
        
//-----------------------------------------
        // (11) Run insert queries
        //-----------------------------------------
        
    //    if( !$this->hooks[ $config['hook_key'] ]['hook_id'] )
    //    {
            
if( count($database['insert']) )
            {
                foreach( 
$database['insert'] as $insert )
                {
                    
$fields        = array();
                    
$content    = explode( ',', $insert['updates'] );
                    
                    foreach( 
$content as $value )
                    {
                        list( 
$field, $toInsert ) = explode( '=', $value );
                        
                        
$fields[ trim($field) ] = str_replace( '~C~', ',', $toInsert );
                    }

                    
$this->DB->return_die = true;
                    
$this->DB->insert( $insert['table'], $fields );
                    
$this->DB->return_die = false;
                    
$insertQueries++;
                    
$extra_data['database']['insert'][] = $insert;
                }
            }
    
//    }
        
        /* Got an install function to run too? */
        
if( is_object($customClass) )
        {
            if( 
method_exists( $customClass, 'install' ) )
            {
                
$customClass->install();
            }
        }
        
        if( 
count($extra_data) )
        {
            
$this->DB->update( 'core_hooks', array( 'hook_extra_data' => serialize( $extra_data ) ), 'hook_id=' . $hook_id );
        }
                    
        
//print_r($config);
        //print_r($files);
        //print_r($custom);
        //print_r($settingGroups);
        //print_r($settings);
        //print_r($language);
        //print_r($modules);
        //print_r($templates);
        //print_r($tasks);
        //print_r($help);
        //print_r($database);

        
if ( $addMessage )
        {
            
$_tempMsg = <<<EOF
        <strong>{$this->lang->words['h_newhookin']}</strong>
        <ul>
            <li>
{$filesInserted} {$this->lang->words['h_filesin']}</li>
            <li>
{$settingGroupsInserted} {$this->lang->words['h_settinggin']}</li>
            <li>
{$settingsInserted} {$this->lang->words['h_settingin']}</li>
            <li>
{$settingsUpdated} {$this->lang->words['h_settingup']}</li>
            <li>
{$languageInserted} {$this->lang->words['h_langbitin']}</li>
            <li>
{$languageUpdated} {$this->lang->words['h_langbitup']}</li>
            <li>
{$modulesInserted} {$this->lang->words['h_modin']}</li>
            <li>
{$modulesUpdated} {$this->lang->words['h_modup']}</li>
            <li>
{$helpInserted} {$this->lang->words['h_helpin']}</li>
            <li>
{$helpUpdated} {$this->lang->words['h_helpup']}</li>
            <li>
{$templatesInserted} {$this->lang->words['h_tempin']}</li>
            <li>
{$templatesUpdated} {$this->lang->words['h_tempup']}</li>
            <li>
{$cssInserted} {$this->lang->words['h_cssin']}</li>
            <li>
{$cssUpdated} {$this->lang->words['h_cssup']}</li>
            <li>
{$replacementsInserted} {$this->lang->words['h_replacementsin']}</li>
            <li>
{$replacementsUpdated} {$this->lang->words['h_replacementsup']}</li>
            <li>
{$tasksInserted} {$this->lang->words['h_taskin']}</li>
            <li>
{$tasksUpdated} {$this->lang->words['h_taskup']}</li>
            <li>
{$createQueries} {$this->lang->words['h_dbcreated']}</li>
            <li>
{$alterQueries} {$this->lang->words['h_dbaltered']}</li>
            <li>
{$updateQueries} {$this->lang->words['h_updateran']}</li>
            <li>
{$insertQueries} {$this->lang->words['h_insertran']}</li>
        </ul>
EOF;

            
$this->registry->output->setMessage( $_tempMsg, 1 );
        }
        
        
//-----------------------------------------
        // Got some skin recaching to do...
        //-----------------------------------------
        
        
if( $allowSkinRecache === TRUE AND ( $templatesInserted OR $templatesUpdated OR $templateHooks OR $cssUpdated OR $cssInserted ) )
        {
            
/* Rebuild cache */
            
$this->rebuildHooksCache();
            
            
/* Flag skins for recache */
            
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
            
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
            
$skinCaching = new skinCaching( $this->registry );
            
$skinCaching->flagSetForRecache();
        }
    }

    
/**
     * Show the form to export a hook
     *
     * @return   void
     */
    
protected function _exportHook()
    {
        
/* Get the hook */
        
$id    = intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError( $this->lang->words['h_noexport'], 1112 );
        }
        
        
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_noexport'], 1113 );
        }
        
        
/* Set defaults */
        
$hookData['hook_extra_data'] = unserialize( $hookData['hook_extra_data'] );

        
/* Output */
        
$this->registry->output->html .= $this->html->hooksExport( $hookData );
    }
    
    
/**
     * Actually export the damn hook already
     * Sorry, it has been a long day...
     *
     * @return    @e void
     */
    
protected function _doExportHook()
    {
        
//-----------------------------------------
        // Get hook
        //-----------------------------------------
        
        
$id    = intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError( $this->lang->words['h_noexport'], 1114 );
        }
        
        
$hookData    = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_noexport'], 1115 );
        }
        
        
$extra_data    = unserialize( $hookData['hook_extra_data'] );
        
        
//-----------------------------------------
        // Get hook files
        //-----------------------------------------
        
        
$files = array();
        
$index = 1;
        
        
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . $id, 'order' => 'hook_file_id ASC' ) );
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            
$files[ $index ]    = $r;
            
$index++;
        }

        
//-----------------------------------------
        // Get XML class
        //-----------------------------------------
        
        
require_once( IPS_KERNEL_PATH.'classXML.php' );/*noLibHook*/

        
$xml = new classXML( IPS_DOC_CHAR_SET );
        
        
$xml->newXMLDocument();
        
$xml->addElement( 'hookexport' );

        
//-----------------------------------------
        // Put hook data in export
        //-----------------------------------------
        
        
$xml->addElement( 'hookdata', 'hookexport' );
        
$content    = array();
        
        foreach( 
$hookData as $k => $v )
        {
            if( 
in_array( $k, array( 'hook_id', 'hook_enabled', 'hook_installed', 'hook_updated', 'hook_position' ) ) )
            {
                continue;
            }
            
            
$content[ $k ] = $v;
        }
        
        
$xml->addElementAsRecord( 'hookdata', 'config', $content );
        
        
//-----------------------------------------
        // Put hook files in export
        //-----------------------------------------
        
        
$xml->addElement( 'hookfiles', 'hookexport' );

        foreach( 
$files as $index => $r )
        {
            
$content    = array();
            
            foreach( 
$r as $k => $v )
            {
                if( 
in_array( $k, array( 'hook_file_id', 'hook_hook_id', 'hook_file_stored', 'hooks_source' ) ) )
                {
                    continue;
                }
                
                
$content[ $k ] = $v;
            }
            
            
$source    = is_file( IPS_HOOKS_PATH . $r['hook_file_stored'] ) ? file_get_contents( IPS_HOOKS_PATH . $r['hook_file_stored'] ) : '';
            
            if ( !empty(
$source) && in_array( $r['hook_type'], array( 'skinHooks', 'commandHooks', 'libraryHooks' ) ) )
            {
                
$source    = $this->_cleanSource( $source );
            }

            
$content['hooks_source'] = $source;

            
$xml->addElementAsRecord( 'hookfiles', 'file', $content );
        }

        
//-----------------------------------------
        // Custom install/uninstall script?
        //-----------------------------------------
        
        
if( $extra_data['custom'] )
        {
            
$content    = array();
            
$xml->addElement( 'hookextras_custom', 'hookexport' );
        
            
$content['filename']    = $extra_data['custom'];
            
$content['source']        = is_file( IPS_HOOKS_PATH . 'install_' . $extra_data['custom'] ) ? file_get_contents( IPS_HOOKS_PATH . 'install_' . $extra_data['custom'] ) : '';
            
            
$xml->addElementAsRecord( 'hookextras_custom', 'file', $content );
        }
        
        
//-----------------------------------------
        // Settings or setting groups?
        //-----------------------------------------
        
        
$entry        = array();
        
$_groups    = array();
        
$_settings    = array();
        
$titles        = array();
        
$content    = array();
        
        
$xml->addElement( 'hookextras_settings', 'hookexport' );
        
        
# Store group ids and setting ids for entire setting groups
        
if( is_array($extra_data['settingGroups']) AND count($extra_data['settingGroups']) )
        {
            
$_groups    = $extra_data['settingGroups'];
            
$_groupIds    = array();
            
            
$this->DB->build( array( 'select' => 'conf_title_id', 'from' => 'core_sys_settings_titles', 'where' => "conf_title_keyword IN('" . implode( "','", $_groups ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$rr = $this->DB->fetch() )
            {
                
$_groupIds[] = $rr['conf_title_id'];
            }
            
            if( 
count($_groupIds) )
            {
                
$this->DB->build( array( 'select' => 'conf_key', 'from' => 'core_sys_conf_settings', 'where' => 'conf_group IN(' . implode( ',', $_groupIds ) . ')' ) );
                
$this->DB->execute();
                
                while( 
$setting = $this->DB->fetch() )
                {
                    
$_settings[] = $setting['conf_key'];
                }
            }
        }
        
        
# Store group ids and setting ids for indvidual settings
        
if( is_array($extra_data['settings']) AND count($extra_data['settings']) )
        {
            foreach( 
$extra_data['settings'] as $_aSetting )
            {
                
$_settings[] = $_aSetting;
            }
            
            
$this->DB->build( array( 'select'    => 't.conf_title_keyword', 
                                     
'from'        => array( 'core_sys_settings_titles' => 't' ), 
                                     
'where'    => "c.conf_key IN('" . implode( "','", $extra_data['settings'] ) . "')",
                                     
'add_join'    => array(
                                                         array(
                                                             
'from'    => array( 'core_sys_conf_settings' => 'c' ),
                                                             
'where'    => 'c.conf_group=t.conf_title_id',
                                                             
'type'    => 'left',
                                                             )
                                                         )
                            )        );
            
$this->DB->execute();
            
            while( 
$group = $this->DB->fetch() )
            {
                
$_groups[] = $group['conf_title_keyword'];
            }
        }
        
        if( 
count($_groups) )
        {
            
# Now get the group data for the XML file
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_settings_titles', 'where' => "conf_title_keyword IN('" . implode( "','", $_groups ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$content    = array();
                
                
$titles[ $r['conf_title_id'] ] = $r['conf_title_keyword'];
                
                
$content['conf_is_title']    = 1;
                
                foreach( 
$r as $k => $v )
                {
                    if( 
in_array( $k, array( 'conf_title_tab', 'conf_title_keyword', 'conf_title_title', 'conf_title_desc', 'conf_title_app', 'conf_title_noshow' ) ) )
                    {
                        
$content[ $k ] = $v;
                    }
                }

                
$xml->addElementAsRecord( 'hookextras_settings', 'setting', $content );
            }
        }
        
        if( 
count($_settings) )
        {
            
# Now get the group data for the XML file
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_conf_settings', 'where' => "conf_key IN('" . implode( "','", $_settings ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$r['conf_value']            = '';
                
$r['conf_title_keyword']    = $titles[ $r['conf_group'] ];
                
$r['conf_is_title']            = 0;

                
$xml->addElementAsRecord( 'hookextras_settings', 'setting', $r );
            }
        }

        
//-----------------------------------------
        // Language strings/files
        //-----------------------------------------
        
        
$entry        = array();
        
        
$xml->addElement( 'hookextras_language', 'hookexport' );
        
        if( 
is_array($extra_data['language']) AND count($extra_data['language']) )
        {
            foreach( 
$extra_data['language'] as $file => $strings )
            {
                
$bits = explode( '_', $file );
                
$app  = $bits[0];
                
$pack = str_replace( $app.'_', '', $file );
                
                
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_lang_words', 'where' => "word_app='{$app}' AND word_pack='{$pack}' AND word_key IN('" . implode( "','", $strings ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$r = $this->DB->fetch() )
                {
                    
$content    = array();
                    
                    foreach( 
$r as $k => $v )
                    {
                        if( !
in_array( $k, array( 'word_app', 'word_pack', 'word_key', 'word_default' ) ) )
                        {
                            continue;
                        }
                        
                        
$content[ $k ] = $v;
                    }
    
                    
$xml->addElementAsRecord( 'hookextras_language', 'language', $content );
                }
            }
        }

        
//-----------------------------------------
        // Modules
        //-----------------------------------------

        
$xml->addElement( 'hookextras_modules', 'hookexport' );
        
        if( 
is_array($extra_data['modules']) AND count($extra_data['modules']) )
        {
            foreach ( 
$extra_data['modules'] as $module )
            {
                list( 
$_side, $_app, $_module ) = explode( '-', $module );
                
$_is_admin = ( $_side == 'admin' ) ? 1 : 0;
                
                
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_module', 'where' => "sys_module_application='{$_app}' AND sys_module_key='{$_module}' AND sys_module_admin={$_is_admin}" ) );
                
$this->DB->execute();
                
                while( 
$r = $this->DB->fetch() )
                {
                    unset(
$r['sys_module_id']);
                    
                    
$xml->addElementAsRecord( 'hookextras_modules', 'module', $r );
                }
            }
        }
        
        
//-----------------------------------------
        // Help files
        //-----------------------------------------

        
$xml->addElement( 'hookextras_help', 'hookexport' );
        
        if( 
is_array($extra_data['help']) AND count($extra_data['help']) )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'faq', 'where' => "title IN('" . implode( "','", $extra_data['help'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                unset(
$r['id']);

                
$xml->addElementAsRecord( 'hookextras_help', 'help', $r );
            }
        }
        
        
//-----------------------------------------
        // Skin templates
        //-----------------------------------------

        
$remapData    = $this->registry->output->buildRemapData( true );

        
$xml->addElement( 'hookextras_templates', 'hookexport' );
                
        if( 
is_array($extra_data['templates']) AND count($extra_data['templates']) )
        {
            foreach( 
$extra_data['templates'] as $file => $templates )
            {
                
$this->DB->build( array( 'select' => '*', 'from' => 'skin_templates', 'where' => "template_set_id IN ('" . implode( "','", $remapData['export'] ) . "') AND template_master_key != '' AND template_group='{$file}' AND template_name IN('" . implode( "','", $templates ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$r = $this->DB->fetch() )
                {
                    unset(
$r['template_id']);
                    unset(
$r['template_set_id']);
    
                    
$xml->addElementAsRecord( 'hookextras_templates', 'templates', $r );
                }
            }
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------

        
$xml->addElement( 'hookextras_css', 'hookexport' );
                
        if( 
is_array( $extra_data['css'] ) AND count ( $extra_data['css'] ) )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'skin_css', 'where' => "css_set_id IN ('" . implode( "','", $remapData['export'] ) . "') AND css_master_key != '' AND css_group IN('" . implode( "','", $extra_data['css'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                unset(
$r['css_id']);
                unset(
$r['css_set_id']);

                
$xml->addElementAsRecord( 'hookextras_css', 'css', $r );
            }
        }
        
        
//-----------------------------------------
        // Replacements
        //-----------------------------------------

        
$xml->addElement( 'hookextras_replacements', 'hookexport' );
                
        if( 
is_array( $extra_data['replacements'] ) AND count ( $extra_data['replacements'] ) )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'skin_replacements', 'where' => "replacement_key IN('" . implode( "','", $extra_data['replacements'] ) . "')", 'group' => 'replacement_key' ) );
            
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                unset(
$r['replacement_id']);
                unset(
$r['replacement_set_id']);

                
$xml->addElementAsRecord( 'hookextras_replacements', 'replacements', $r );
            }
        }

        
//-----------------------------------------
        // Tasks
        //-----------------------------------------

        
$xml->addElement( 'hookextras_tasks', 'hookexport' );
                
        if( 
is_array($extra_data['tasks']) AND count($extra_data['tasks']) )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'task_manager', 'where' => "task_key IN('" . implode( "','", $extra_data['tasks'] ) . "')" ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                unset(
$r['task_id']);
                unset(
$r['task_next_run']);

                
$xml->addElementAsRecord( 'hookextras_tasks', 'tasks', $r );
            }
        }

        
//-----------------------------------------
        // Database changes
        //-----------------------------------------

        
$xml->addElement( 'hookextras_database_create', 'hookexport' );
        
        if( 
is_array($extra_data['database']['create']) AND count($extra_data['database']['create']) )
        {
            foreach( 
$extra_data['database']['create'] as $create_query )
            {
                
$xml->addElementAsRecord( 'hookextras_database_create', 'create', $create_query );
            }
        }

        
$xml->addElement( 'hookextras_database_alter', 'hookexport' );
        
        if( 
is_array($extra_data['database']['alter']) AND count($extra_data['database']['alter']) )
        {
            foreach( 
$extra_data['database']['alter'] as $alter_query )
            {
                
$xml->addElementAsRecord( 'hookextras_database_alter', 'alter', $alter_query );
            }
        }

        
$xml->addElement( 'hookextras_database_update', 'hookexport' );
        
        if( 
is_array($extra_data['database']['update']) AND count($extra_data['database']['update']) )
        {
            foreach( 
$extra_data['database']['update'] as $update_query )
            {
                
$xml->addElementAsRecord( 'hookextras_database_update', 'update', $update_query );
            }
        }

        
$xml->addElement( 'hookextras_database_insert', 'hookexport' );
        
        if( 
is_array($extra_data['database']['insert']) AND count($extra_data['database']['insert']) )
        {
            foreach( 
$extra_data['database']['insert'] as $insert_query )
            {
                
$xml->addElementAsRecord( 'hookextras_database_insert', 'insert', $insert_query );
            }
        }

        
//-----------------------------------------
        // Print to browser
        //-----------------------------------------

        
$this->registry->output->showDownload( $xml->fetchDocument(), $hookData['hook_key'] . '.xml', '', 0 );
    }
    
    
/**
     * Clean source code for export..
     *
     * @param    string            Hook source code
     * @return    string            "Cleaned" source code
     */
    
protected function _cleanSource( $source )
    {
        
$source = preg_replace( "/classs+(S+)s+extendss+(S+)/i", "class \1 extends (~extends~)", $source );
        
        return 
$source;
    }
    
    
/**
     * Fix hook positions
     *
     * @return   @e void
     */
    
protected function _fixPositions()
    {
        
/* Init vars */
        
$new_order   = 0;
        
$usedActions = array();

        
$this->DB->build( array( 'select' => 'hook_id, hook_position', 'from' => 'core_hooks', 'where' => 'hook_enabled=1', 'order' => 'hook_position ASC' ) );
        
$qid = $this->DB->execute();

        while ( 
$hook = $this->DB->fetch( $qid ) )
        {
            
$new_order++;
            
$this->DB->update( 'core_hooks', array ( 'hook_position' => $new_order ), "hook_id={$hook['hook_id']}" );
            
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks_files', 'where' => "hook_type IN ('commandHooks', 'skinHooks', 'libraryHooks' ) AND hook_hook_id=" . $hook['hook_id'] ) );
            
$this->DB->execute();
        
            while( 
$file = $this->DB->fetch() )
            {
                if( 
$file['hooks_source'] )
                {
                    
$source = $this->_cleanSource( $file['hooks_source'] );
                }
                else
                {
                    
$source = is_file( IPS_HOOKS_PATH . $file['hook_file_stored'] ) ? file_get_contents( IPS_HOOKS_PATH . $file['hook_file_stored'] ) : '';
                    
                    if( 
$source )
                    {
                         
$source = $this->_cleanSource( $source );
                    }
                }
                
                if( 
$source )
                {
                    
$hook_data    = unserialize( $file['hook_data'] );
                    
$overload    = $hook_data['classToOverload'];
                    
$newClass    = $overload;
                    
                    
$app = ( $file['hook_type'] == 'libraryHooks' ) ? trim($hook_data['libApplication']) : '~_NO_APP_~';
                    
                    if( isset( 
$usedActions[ $app ][ $overload ] ) )
                    {
                        
$newClass = $usedActions[ $app ][ $overload ];
                    }
                    else if( 
$file['hook_type'] == 'skinHooks' )
                    {
                        
$newClass .= "(~id~)";
                    }
                    
                    
$source = str_replace( "(~extends~)", $newClass, $source );
                    
                    
file_put_contents( IPS_HOOKS_PATH . $file['hook_file_stored'], $source );
                    
                    
$usedActions[ $app ][ $hook_data['classToOverload'] ] = $file['hook_classname'];
                }
            }
        }
    }
    
    
/**
     * Check if there is an update for a hook
     *
     * @param    string         URL to check
     * @param    string        Long version number
     * @return    bool
     */
    
public function _updateAvailable( $url, $version )
    {
        if( empty(
$url) || $version === '' )
        {
            return 
false;
        }
        
        
$classToLoad = IPSLib::loadLibrary( IPS_KERNEL_PATH . '/classFileManagement.php', 'classFileManagement' );
        
$checker = new $classToLoad();
        
        
/* Timeout to prevent page from taking too long */
        
$checker->timeout = 5;
        
        
/* Setup url and check */
        
$url  = str_replace( 'php&', 'php?', $url );
        
$url .= '&boardVersion=' . IPB_LONG_VERSION . '&version=' . $version;
        
        
$return = $checker->getFileContents( $url );
        
        
/* Return the content (if valid) or return 'no update' */
        
return ( strpos( $return, '0' ) === 0 || strpos( $return, '1' ) === 0 ) ? explode( '|', $return ) : array( 0 );
    }
    
    
/**
     * Sorts hooks by their position
     * (this is used to avoid a mysql filesort)
     * 
     * @param    array        $a        First hook data
     * @param    array        $b        Second hook data
     * @return    @e integer
     */
    
protected function sortHooksByPosition( $a, $b )
    {
        if ( 
$a['hook_position'] == $b['hook_position'] )
        {
            return 
0;
        }
        
        return ( 
$a['hook_position'] < $b['hook_position'] ) ? -1 : 1;
    }
    
    
/**
     * Hooks overview
     *
     * @return    @e void        [Outputs to screen]
     */
    
public function _hooksOverview()
    {
        
/* INI */
        
$hooksFound            = array( 'installed' => array(), 'uninstalled' => array() );
        
$hookwarnings        = 0;
        
$hookUpdates        = 0;
        
$checkUpdates        = !empty( $this->request['checkUpdates'] ) ? true : false;
        
$message            = '';
        
$confGroupIdsToLoad    = array();
        
$confGroupKeysToLoad= array();
        
        
/* Get current hooks */
        
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks' ) );
        
$outer    = $this->DB->execute();
        
        while( 
$r = $this->DB->fetch($outer) )
        {
            
/* Format some dates */
            
$r['_updated']   = $this->registry->getClass('class_localization')->formatTime( $r['hook_updated'] );
            
$r['_installed'] = $this->registry->getClass('class_localization')->formatTime( $r['hook_installed'] );
            
            
/* Got updates? */
            
if ( $r['hook_update_check'] && $checkUpdates === true )
            {
                
$r['hook_update_available'] = $this->_updateAvailable( $r['hook_update_check'], $r['hook_version_long'] );
                
                if ( 
$r['hook_update_available'][0] )
                {
                    
$hookUpdates++;
                }
            }
            else
            {
                
$r['hook_update_available']    = array( 0 );
            }
            
            
/* Got some setting groups to take care of? */
            
$r['_has_setting_links'] = null;
            
$r['_hook_extra_data']   = IPSLib::isSerialized($r['hook_extra_data']) ? unserialize($r['hook_extra_data']) : array();
            
            if ( 
is_array($r['_hook_extra_data']['settingGroups']) && count($r['_hook_extra_data']['settingGroups']) )
            {
                
$r['_has_setting_links'] = array();
                
                foreach( 
$r['_hook_extra_data']['settingGroups'] as $_group )
                {
                    
$confGroupKeysToLoad[ $_group ] = $_group;
                }
            }
            
            if ( 
is_array($r['_hook_extra_data']['settings']) && count($r['_hook_extra_data']['settings']) )
            {
                
$r['_has_setting_links'] = array();
                
                
$this->DB->build( array( 'select' => 'conf_group, conf_key', 'from' => 'core_sys_conf_settings', 'where' => "conf_key IN ('" . implode( "','", $r['_hook_extra_data']['settings'] ) . "')" ) );
                
$this->DB->execute();
                
                while( 
$hsg = $this->DB->fetch() )
                {
                    
$confGroupIdsToLoad[ $hsg['conf_key'] ] = $hsg['conf_group'];
                }
            }
            
            
/* Check requirements */
            
$r['_require_errors'] = $this->checkHookRequirements( $r );
            
            
/* Store */
            
if( $r['hook_enabled'] )
            {
                if ( 
count($r['_require_errors']) )
                {
                    
$hookwarnings++;
                }
                
                
$hooksFound['installed'][ $r['hook_id'] ]    = $r;
            }
            else
            {
                
$hooksFound['uninstalled'][ $r['hook_id'] ]    = $r;
            }
        }
        
        
/* Got groups to load? */
        
$where = array();
        
        if ( 
count($confGroupKeysToLoad) )
        {
            
$where[] = "conf_title_keyword IN ('" . implode( "','", $confGroupKeysToLoad ) . "')";
        }
        
        if ( 
count($confGroupIdsToLoad) )
        {
            
$where[] = "conf_title_id IN (" . implode( ",", $confGroupIdsToLoad ) . ")";
        }
        
        if ( 
count($where) )
        {
            
$confGroupsLoaded = array();
            
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_settings_titles', 'where' => implode( ' OR ', $where ) ) );
            
$this->DB->execute();
            
            while( 
$gr = $this->DB->fetch() )
            {
                if ( empty(
$gr['conf_title_noshow']) )
                {
                    
$confGroupsLoaded['ids'][ $gr['conf_title_id'] ]        = $gr;
                    
$confGroupsLoaded['keys'][ $gr['conf_title_keyword'] ]    = & $confGroupsLoaded['ids'][ $gr['conf_title_id'] ];
                }
            }
            
            
/* Merge back the data */
            
foreach( $hooksFound as $rk => $rt )
            {
                foreach( 
$rt as $sk => $st )
                {
                    if ( 
is_array($st['_has_setting_links']) )
                    {
                        if ( 
is_array($st['_hook_extra_data']['settingGroups']) && count($st['_hook_extra_data']['settingGroups']) )
                        {
                            foreach( 
$st['_hook_extra_data']['settingGroups'] as $_group )
                            {
                                if ( isset(
$confGroupsLoaded['keys'][ $_group ]) )
                                {
                                    
$hooksFound[ $rk ][ $sk ]['_has_setting_links'][ $confGroupsLoaded['keys'][ $_group ]['conf_title_id'] ] = $confGroupsLoaded['keys'][ $_group ]['conf_title_title'];
                                }
                            }
                        }
                        
                        if ( 
is_array($st['_hook_extra_data']['settings']) && count($st['_hook_extra_data']['settings']) )
                        {
                            foreach( 
$st['_hook_extra_data']['settings'] as $_id )
                            {
                                if ( isset(
$confGroupsLoaded['ids'][ $confGroupIdsToLoad[ $_id ] ]) )
                                {
                                    
$hooksFound[ $rk ][ $sk ]['_has_setting_links'][ $confGroupIdsToLoad[ $_id ] ] = $confGroupsLoaded['ids'][ $confGroupIdsToLoad[ $_id ] ]['conf_title_title'];
                                }
                            }
                        }
                    }
                }
            }
        }
        
        
/* Got updates to show? */
        
if ( $checkUpdates === true )
        {
            
$message = ( $hookUpdates == 1 ) ? $this->lang->words['updates_string_single'] : sprintf( $this->lang->words['updates_string_more'], $hookUpdates );
        }
        
        if ( 
count($hooksFound['installed']) )
        {
            
uasort( $hooksFound['installed'], array( $this, 'sortHooksByPosition' ) );
        }
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hooksOverview( $hooksFound, $hookwarnings, $message );
    }
    
    
/**
     * Disables all hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _disableAllHooks()
    {
        
/* INIT */
        
$activeHookIds = array();
        
        
/* Query Enabled Hooks */
        
$this->DB->build( array( 'select' => 'hook_id', 'from' => 'core_hooks', 'where' => "hook_enabled=1" ) );
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            
$activeHookIds[] = $r['hook_id'];
        }
        
        
/* Make sure there were active hooks */
        
if( ! count( $activeHookIds ) )
        {
            
$this->registry->output->global_message = $this->lang->words['hook_disable_all_none'];
            
$this->_hooksOverview();
            return;
        }
        
        
/* Disable hooks */
        
$this->DB->update( 'core_hooks', array( 'hook_enabled' => 0 ), 'hook_id IN( ' . implode( ',', $activeHookIds ) . ' ) ' );
        
        
/* Save to cache */
        
$this->cache->setCache( 'disabledHooksCache', $activeHookIds, array( 'array' => 1 ) );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* All Done */
        
$this->registry->output->global_message = $this->lang->words['hook_disabled_all'];
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * Re-enable all hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _reenableAllHooks()
    {
        
/* INIT */
        
$activeHookIds = $this->cache->getCache( 'disabledHooksCache' );
        
        
/* Make sure there were active hooks */
        
if( ! count( $activeHookIds ) )
        {
            
$this->registry->output->global_message = $this->lang->words['hook_enable_all_none'];
            
$this->_hooksOverview();
            return;
        }
        
        
/* Disable hooks */
        
$this->DB->update( 'core_hooks', array( 'hook_enabled' => 1 ), 'hook_id IN( ' . implode( ',', $activeHookIds ) . ' ) ' );
        
        
/* Save to cache */
        
$this->cache->setCache( 'disabledHooksCache', array(), array( 'array' => 1 ) );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
        
/* Flag all for recache */
        
$skinCaching->flagSetForRecache();
        
        
/* All Done */
        
$this->registry->output->global_message = $this->lang->words['hook_reenable_all'];
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * Disables a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _disableHook()
    {
        
/* INI */
        
$hook_id = intval( $this->request['id'] );
        
        if( !
$hook_id )
        {
            
$this->registry->output->showError( $this->lang->words['h_noedit'], '1118.D' );
        }
        
        
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $hook_id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_noedit'], '1119.D' );
        }
        
        
/* Do update */
        
$this->DB->update( 'core_hooks', array( 'hook_enabled' => 0, 'hook_position' => 0 ), "hook_id={$hookData['hook_id']}" );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->setMessage( $this->lang->words['h_hasbeendisabled'] );
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }    
    
    
/**
     * Enables a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _enableHook()
    {
        
/* INI */
        
$hook_id = intval($this->request['id']);
        
        if( !
$hook_id )
        {
            
$this->registry->output->showError( $this->lang->words['h_noedit'], '1118.E' );
        }
        
        
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $hook_id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_noedit'], '1119.E' );
        }
        
        
/* Check for requirements */
        
if ( empty($this->request['skipRequirements']) )
        {
            
$errors = $this->checkHookRequirements( $hookData );
            
            if ( 
count($errors) )
            {
                
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=check_requirements&amp;fromInstall=1&amp;id='.$hook_id );
            }
        }
        
        
/* Do update */
        
$this->DB->update( 'core_hooks', array( 'hook_enabled' => 1 ), "hook_id={$hookData['hook_id']}" );
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->global_message = $this->lang->words['h_hasbeenenabled'];
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * Uninstall a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _uninstallHook()
    {
        
/* Init vars */
        
$hook_id    = intval( $this->request['id'] );
        
        
$hook        = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $hook_id ) );
        
$extra_data    = unserialize( $hook['hook_extra_data'] );
        
        if ( ! 
$hook['hook_id'] )
        {
            
$this->registry->output->global_message = $this->lang->words['h_hasbeenun'];
            
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
        }
        
        
/* Got any custom file to initialize? */
        
$_customFile = '';
        
$customClass = null;
        
        if ( 
$extra_data['display']['custom'] )
        {
            
$_customFile = IPS_HOOKS_PATH . 'install_' . $extra_data['display']['custom'];
            
            if( 
is_file( $_customFile ) )
            {
                require_once( 
$_customFile );/*noLibHook*/
                
                
$classname = str_replace( '.php', '', $extra_data['display']['custom'] );
                
                if( 
class_exists( $classname ) )
                {
                    
$customClass = new $classname( $this->registry );
                    
                    if( 
method_exists( $customClass, 'pre_uninstall' ) )
                    {
                        
$customClass->pre_uninstall();
                    }
                }
            }
        }
        
        
/* Get associated files */
        
$this->DB->build( array( 'select' => 'hook_file_stored', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . $hook_id ) );
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            @
unlink( IPS_HOOKS_PATH . $r['hook_file_stored'] );
        }
        
        
/* Delete hook file entries */
        
$this->DB->delete( 'core_hooks_files', "hook_hook_id={$hook_id}" );
        
        
//-----------------------------------------
        // Settings or setting groups?
        //-----------------------------------------
        
        
if( count($extra_data['settingGroups']) )
        {
            
$this->DB->delete( 'core_sys_settings_titles', "conf_title_keyword IN('" . implode( "','", $extra_data['settingGroups'] ) . "')" );
        }
        
        if( 
count($extra_data['settings']) )
        {
            
$this->DB->delete( 'core_sys_conf_settings', "conf_key IN('" . implode( "','", $extra_data['settings'] ) . "')" );
        }
        
        
$this->cache->rebuildCache( 'settings', 'global' );
        
        
//-----------------------------------------
        // Language strings/files
        //-----------------------------------------
        
        
if( count($extra_data['language']) )
        {
            foreach( 
$extra_data['language'] as $file => $bit )
            {
                
$this->DB->delete( 'core_sys_lang_words', "word_pack='{$file}' AND word_key IN('" . implode( "','", $bit ) . "')" );
            }
            
            
$langPacks    = array();
            
            
$this->DB->build( array( 'select' => 'lang_id', 'from' => 'core_sys_lang' ) );
            
$this->DB->execute();
            
            while( 
$r = $this->DB->fetch() )
            {
                
$langPacks[] = $r['lang_id'];
            }
            
            
$classToLoad = IPSLib::loadActionOverloader( IPSLib::getAppDir('core') . '/modules_admin/languages/manage_languages.php', 'admin_core_languages_manage_languages' );
            
$langLib     = new $classToLoad();
            
$langLib->makeRegistryShortcuts( $this->registry );
            
            foreach( 
$langPacks as $langId )
            {
                
$langLib->cacheToDisk( $langId );
            }
        }
        
        
//-----------------------------------------
        // Modules
        //-----------------------------------------
        
        
if( count($extra_data['modules']) )
        {
            foreach( 
$extra_data['modules'] as $module )
            {
                list( 
$_side, $_app, $_module ) = explode( '-', $module );
                
$_is_admin = ( $_side == 'admin' ) ? 1 : 0;
                
                
$this->DB->delete( 'core_sys_module', "sys_module_application='{$_app}' AND sys_module_key='{$_module}' AND sys_module_admin={$_is_admin}" );
            }
            
            
$this->cache->rebuildCache( 'module_cache', 'global' );
            
$this->cache->rebuildCache( 'app_menu_cache', 'global' );
        }
        
        
//-----------------------------------------
        // Help files
        //-----------------------------------------
        
        
if( count($extra_data['help']) )
        {
            
$this->DB->delete( 'faq', "title IN('" . implode( "','", $extra_data['help'] ) . "')" );
        }
        
        
//-----------------------------------------
        // Skin templates
        //-----------------------------------------
        
        
if( count($extra_data['templates']) )
        {
            foreach( 
$extra_data['templates'] as $group => $bits )
            {
                
$this->DB->delete( 'skin_templates', "template_group='{$group}' AND template_name IN('" . implode( "','", $bits ) . "')" );
            }

            require_once( 
IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
            
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
            
$skinCaching = new skinCaching( $this->registry );
            
$skinCaching->rebuildPHPTemplates( 0 );
        }
        
        
//-----------------------------------------
        // CSS
        //-----------------------------------------
        
        
if( count( $extra_data['css'] ) )
        {
            
$this->DB->delete( 'skin_css', "css_group IN('" . implode( "','", $extra_data['css'] ) . "')" );
            
            if( ! 
$skinCaching )
            {
                require_once( 
IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
                
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
                
$skinCaching = new skinCaching( $this->registry );
            }
            
            
$skinCaching->rebuildCSSCache( 0 );
        }
        
        
//-----------------------------------------
        // Tasks
        //-----------------------------------------
        
        
if( count($extra_data['tasks']) )
        {
            
$this->DB->delete( 'task_manager', "task_key IN('" . implode( "','", $extra_data['tasks'] ) . "')" );
        }
        
        
//-----------------------------------------
        // Database changes
        //-----------------------------------------
        
        
if( is_array($extra_data['database']['create']) AND count($extra_data['database']['create']) )
        {
            foreach( 
$extra_data['database']['create'] as $create_query )
            {
                
$this->DB->return_die    = true;
                
$this->DB->dropTable( $create_query['name'] );
                
$this->DB->return_die    = false;
            }
        }
        
        if( 
is_array($extra_data['database']['alter']) AND count($extra_data['database']['alter']) )
        {
            foreach( 
$extra_data['database']['alter'] as $alter_query )
            {
                
$this->DB->return_die    = true;
                
                if( 
$alter_query['altertype'] == 'add' )
                {
                    if( 
$this->DB->checkForField( $alter_query['field'], $alter_query['table'] ) )
                    {
                        
$this->DB->dropField( $alter_query['table'], $alter_query['field'] );
                    }
                }
                else if( 
$alter_query['altertype'] == 'change' )
                {
                    if( 
$this->DB->checkForField( $alter_query['newfield'], $alter_query['table'] ) )
                    {
                        
$this->DB->changeField( $alter_query['table'] , $alter_query['newfield'], $alter_query['field'], $alter_query['fieldtype'], $alter_query['default'] );
                    }
                }
                
                
$this->DB->return_die    = false;
            }
        }
        
        if( 
is_array($extra_data['database']['update']) AND count($extra_data['database']['update']) )
        {
            foreach( 
$extra_data['database']['update'] as $update_query )
            {
                
$this->DB->return_die    = true;
                
$this->DB->update( $update_query['table'], array( $update_query['field'] => $update_query['oldvalue'] ), $update_query['where'] );
                
$this->DB->return_die    = false;
            }
        }
        
        if( 
is_array($extra_data['database']['insert']) AND count($extra_data['database']['insert']) )
        {
            foreach( 
$extra_data['database']['insert'] as $insert_query )
            {
                if( 
$insert_query['fordelete'] )
                {
                    
$this->DB->return_die    = true;
                    
$this->DB->delete( $insert_query['table'], $insert_query['fordelete'] );
                    
$this->DB->return_die    = false;
                }
            }
        }
        
        
//-----------------------------------------
        // Custom install/uninstall script?
        //-----------------------------------------
        
        
if ( $_customFile )
        {
            if( 
is_object($customClass) && method_exists( $customClass, 'uninstall' ) )
            {
                
$customClass->uninstall();
            }
            
            @
unlink( $_customFile );
        }
        
        
/* Delete main hook entry */
        
$this->DB->delete( 'core_hooks', "hook_id={$hook_id}" );
        
        
$this->rebuildHooksCache();
        
        
/* Done */
        
$this->registry->output->global_message = $this->lang->words['h_hasbeenun'];
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }    
    
    
/**
     * Hook add/edit form
     * This dynamic form allows users to associate multiple files with a single hook.
     *
     * @param    string        [add|edit]
     * @return    @e void        [Outputs to screen]
     */
    
protected function _hookForm( $type='add' )
    {
        
/* Init vars */
        
$form            = array();
        
$files            = array();
        
$hookData        = array();
        
$requirements    = array();
        
$entryPoints    = array( 'foreach' => array( array( 'outer.pre', $this->lang->words['h_outerpre'] ),
                                                     array( 
'inner.pre', $this->lang->words['h_innerpre'] ),
                                                     array( 
'inner.post', $this->lang->words['h_innerpost'] ),
                                                     array( 
'outer.post', $this->lang->words['h_outerpost'] )
                                                    ),
                                 
'if' => array( array( 'pre.startif', $this->lang->words['h_prestartif'] ),
                                                array( 
'post.startif', $this->lang->words['h_poststartif'] ),
                                                array( 
'pre.else', $this->lang->words['h_preelse']),
                                                array( 
'post.else', $this->lang->words['h_postelse'] ),
                                                array( 
'pre.endif', $this->lang->words['h_preendif'] ),
                                                array( 
'post.endif', $this->lang->words['h_postendif'] )
                                                )
                                );
        
        
/* Edit time? */
        
if( $type == 'edit' )
        {
            
$id    = intval($this->request['id']);
            
            if( !
$id )
            {
                
$this->registry->output->showError( $this->lang->words['h_noedit'], 1116 );
            }
            
            
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
            
            if( !
$hookData['hook_id'] )
            {
                
$this->registry->output->showError( $this->lang->words['h_noedit'], 1117 );
            }
            
            
/* Sort out extra stuff and requirements */
            
$hookData['hook_extra_data']    = unserialize( $hookData['hook_extra_data'] );
            
$hookData['hook_requirements']    = unserialize( $hookData['hook_requirements'] );
            
            
/* Old data? - @todo: we should remove that around 3.3(4?) */
            
if ( ! isset($hookData['hook_requirements']['required_applications']['core']) && isset($hookData['hook_requirements']['hook_ipb_version_min']) && ( $hookData['hook_requirements']['hook_ipb_version_min'] > 0 || $hookData['hook_requirements']['hook_ipb_version_max'] > 0 ) )
            {
                
$requirements['core'] = array( 'min_version' => intval($hookData['hook_requirements']['hook_ipb_version_min']), 'max_version' => intval($hookData['hook_requirements']['hook_ipb_version_max']) );
            }
            
            if ( 
is_array($hookData['hook_requirements']['required_applications']) && count($hookData['hook_requirements']['required_applications']) )
            {
                
/* Get the setup class */
                
require_once( IPS_ROOT_PATH . 'setup/sources/base/setup.php' );/*noLibHook*/
                
                
foreach( $hookData['hook_requirements']['required_applications'] as $appKey => $versionData )
                {
                    
/* Fetch and check versions */
                    
if ( !isset($this->cachedVersions[ $appKey ]) )
                    {
                        
$this->cachedVersions[ $appKey ] = IPSSetUp::fetchXmlAppVersions( $appKey );
                    }
                    
                    
$_versions = $this->cachedVersions[ $appKey ];
                    
                    
krsort($_versions);
                    
                    
/* Setup our default 'no version' value */
                    
$versions = array( array( 0, $this->lang->words['h_any_version'] ) );
                    
                    foreach( 
$_versions as $long => $human )
                    {
                        if ( 
$long < 30000 && in_array( $appKey, array( 'core', 'forums', 'members' ) ) )
                        {
                            continue;
                        }
                        
                        
$versions[] = array( $long, $human );
                    }
                    
                    
$versionData['_versions'] = $versions;
                    
$requirements[ $appKey ]  = $versionData;
                }
            }
            
            
/* Sort out hook files */
            
$index        = 1;
            
$skinGroups = $this->hooksFunctions->getSkinGroups();
            
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . $id ) );
            
$outer = $this->DB->execute();
            
            
/* Get them outside the while cycle to prevent warnings */
            
$_dataHooks = IPSLib::getDataHookLocations();
            
            while( 
$r = $this->DB->fetch($outer) )
            {
                
$r['hook_data']        = unserialize( $r['hook_data'] );

                if( 
$r['hook_type'] == 'templateHooks' )
                {
                    
$templates    = $this->hooksFunctions->getSkinMethods( $r['hook_data']['skinGroup'] );
                    
$hookIds    = $this->hooksFunctions->getHookIds( $r['hook_data']['skinFunction'], $r['hook_data']['type'] );
                    
                    
$r['_skinDropdown']        = $this->registry->output->formDropdown( "skinGroup[{$index}]", $skinGroups, $r['hook_data']['skinGroup'], "skinGroup[{$index}]", "onchange='getTemplatesForAdd({$index});'" );
                    
$r['_templateDropdown']    = $this->registry->output->formDropdown( "skinFunction[{$index}]", $templates, $r['hook_data']['skinFunction'], "skinFunction[{$index}]", "onchange='getTypeOfHook({$index});'" );
                    
$r['_hookTypeDropdown']    = $this->registry->output->formDropdown( "type[{$index}]", array( array( 0, $this->lang->words['a_selectone'] ), array( 'foreach', $this->lang->words['hook_foreach_loop'] ), array( 'if', $this->lang->words['hook_if_statement'] ) ), $r['hook_data']['type'], "type[{$index}]", "onchange='getHookIds({$index});'" );
                    
$r['_hookIdsDropdown']    = $this->registry->output->formDropdown( "id[{$index}]", $hookIds, $r['hook_data']['id'], "id[{$index}]", "onchange='getHookEntryPoints({$index});'" );
                    
$r['_hookEPDropdown']    = $this->registry->output->formDropdown( "position[{$index}]", $r['hook_data']['type'] == 'foreach' ? $entryPoints['foreach'] : $entryPoints['if'], $r['hook_data']['position'] );
                }
                
                if( 
$r['hook_type'] == 'dataHooks' )
                {
                    
$r['_dataLocationDropdown']    = $this->registry->output->formDropdown( "dataLocation[{$index}]", $_dataHooks, $r['hook_data']['dataLocation'] );
                }
                
                
$files[ $index ] = $r;
                
$index++;
            }
            
            
$action = 'do_edit_hook';
        }
        else
        {
            
$action = 'do_create_hook';
        }
        
        
/* Info */
        
foreach( array( 'hook_name', 'hook_desc', 'hook_key', 'hook_version_human', 'hook_version_long', 'hook_author', 'hook_email', 'hook_website', 'hook_update_check' ) as $_hook_key )
        {
            
$form[ $_hook_key ] = $this->registry->output->formSimpleInput( $_hook_key , isset($this->request[ $_hook_key ]) ? $this->request[ $_hook_key ] : $hookData[ $_hook_key ], 60 );
        }
        
        
/* Requirements */
        
foreach( array( 'hook_php_version_min', 'hook_php_version_max' ) as $_version_key )
        {
            
$form[ $_version_key ] = $this->registry->output->formSimpleInput( $_version_key , isset($this->request[ $_version_key ]) ? $this->request[ $_version_key ] : $hookData['hook_requirements'][ $_version_key ], 20 );
        }
        
        
/* Setup the global caches DD */
        
$_caches = array();
        
        
$this->DB->build( array( 'select' => 'cs_key',
                                 
'from'   => 'cache_store',
                                 
'order'  => 'cs_key ASC'
                         
)        );
        
$this->DB->execute();
        
        while( 
$gc = $this->DB->fetch() )
        {
            
$_caches[] = array( $gc['cs_key'], $gc['cs_key'] );
        }
        
        
sort( $_caches );
        
        
$form['hook_global_caches'] = $this->registry->output->formMultiDropdown( 'hook_global_caches[]', $_caches, isset($_POST['hook_global_caches']) ? $_POST['hook_global_caches'] : explode(',',$hookData['hook_global_caches']), 15 );
        
        
/* Get some data for the javascript */
        
$form['jsDataTypes']  = IPSText::br2nl( $this->registry->output->formDropdown( "type[#{index}]", array( array( 0, $this->lang->words['a_selectone'] ), array( 'foreach', $this->lang->words['hook_foreach_loop'] ), array( 'if', $this->lang->words['hook_if_statement'] ) ), '', "type[#{index}]", "onchange='getHookIds(#{index});'" ) );
        
$form['jsDataPoints'] = IPSText::br2nl( $this->registry->output->formDropdown( "position[#{index}]", $r['hook_data']['type'] == 'foreach' ? $entryPoints['foreach'] : $entryPoints['if'] ) );
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hookForm( $form, $action, $hookData, $files, $requirements );
    }

    
/**
     * Hook add/edit save
     * Save the new (or updated) hook record
     *
     * @param    string        [add|edit]
     * @return    @e void        [Outputs to screen]
     */
    
protected function _hookSave( $type='add' )
    {
        
/* Init vars */
        
$hookData   = array();
        
$newFiles    = array();
        
$requireApp    = array();
        
$_hookFiles    = array();
        
$extraKey   = '';
        
        
/* Get data if we are editing */
        
if( $type == 'edit' )
        {
            
$id    = intval($this->request['hook_id']);
            
            if( !
$id )
            {
                
$this->registry->output->showError( $this->lang->words['h_noedit'], 1118 );
            }
            
            
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
            
            if( !
$hookData['hook_id'] )
            {
                
$this->registry->output->showError( $this->lang->words['h_noedit'], 1119 );
            }
            
            
$extraKey = ' AND hook_id != ' . $hookData['hook_id'];
        }
        
        
/* Error Checking */
        
if( ! $this->request['hook_name'] )
        {
            
$errors[] = $this->lang->words['hook_form_no_title'];
        }
        
        if( empty( 
$this->request['hook_key'] ) )
        {
            
$errors[] = $this->lang->words['hook_form_no_key'];
        }
        else
        {
            
$keyCheck = $this->DB->buildAndFetch( array( 'select' => 'count(*) as found', 'from' => 'core_hooks', 'where' => "hook_key='" . $this->DB->addSlashes( $this->request['hook_key'] ) . "'" . $extraKey ) );
            
            if ( 
$keyCheck['found'] > 0 )
            {
                
$errors[] = $this->lang->words['hook_form_dupe_key'];
            }
        }
        
        
/* Got any errors? */
        
if ( is_array( $errors ) && count( $errors ) )
        {
            
$this->registry->output->global_error = implode( '<br />', $errors );
            
$this->_hookForm();
            return;
        }
        
        
/* Not IN_DEV? */
        
if ( ! IN_DEV )
        {
            
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . intval($this->request['hook_id']) ) );
            
$this->DB->execute();
            
            while( 
$_r = $this->DB->fetch() )
            {
                
$_hookFiles[ $_r['hook_classname'] ] = $_r['hook_file_stored'];
            }
        }
        
        
/* Check for requirements */
        
if ( is_array( $this->request['requireApp'] ) AND count( $this->request['requireApp'] ) )
        {
            foreach( 
$this->request['requireApp'] as $_index => $app_key )
            {
                if ( 
$app_key )
                {
                    
$minVersion = intval($this->request['minVersion'][ $_index ]);
                    
$maxVersion = intval($this->request['maxVersion'][ $_index ]);
                    
                    
$requireApp[ $app_key ] = array( 'app_name'        => ipsRegistry::$applications[ $app_key ]['app_title'],
                                                     
'min_version'    => $minVersion,
                                                     
'max_version'    => $maxVersion
                                                    
);
                }
            }
        }
        
        
/* Check for files */
        
if ( is_array( $this->request['file'] ) AND count( $this->request['file'] ) )
        {
            foreach( 
$this->request['file'] as $index => $file )
            {
                if ( 
$file )
                {
                    
$newFiles[ $index ]    = array('hook_file_real'    => $file,
                                                
'hook_type'            => $this->request['hook_type'][ $index ],
                                                
'hook_classname'    => $this->request['hook_classname'][ $index ],
                                                
'hook_data'            => serialize( array('dataLocation'        => trim( $this->request['dataLocation'][ $index ] ),
                                                                                        
'libApplication'    => trim( $this->request['libApplication'][ $index ] ),
                                                                                        
'classToOverload'    => trim($this->request['classToOverload'][ $index ]),
                                                                                        
'skinGroup'            => $this->request['skinGroup'][ $index ],
                                                                                        
'skinFunction'        => $this->request['skinFunction'][ $index ],
                                                                                        
'type'                => $this->request['type'][ $index ],
                                                                                        
'id'                => $this->request['id'][ $index ],
                                                                                        
'position'            => $this->request['position'][ $index ],
                                                                                        )
                                                                                 )
                                                );

                    
/**
                     * @link    http://community.invisionpower.com/tracker/issue-22084-hook-edit-does-not-preserve-correct-name/
                     * We don't want to reset the stored name if you are not in developer mode
                     */
                    
if ( IN_DEV )
                    {
                        
$newFiles[ $index ]['hook_file_stored']    = $file; // During import this is a random name, but for devs it's actual file
                    
}
                    else
                    {
                        
$newFiles[ $index ]['hook_file_stored']    = $_hookFiles[ $this->request['hook_classname'][ $index ] ] ? $_hookFiles[ $this->request['hook_classname'][ $index ] ] : $file;
                    }
                }
            }
        }
        
        
/* Get position */
        
if ( $type == 'add' )
        {
            
$position = $this->DB->buildAndFetch( array( 'select' => 'MAX(hook_position) as newPos', 'from' => 'core_hooks' ) );
            
            
$position['newPos'] = intval($position['newPos']) + 1;
        }
        else
        {
            
$position['newPos'] = $hookData['hook_position'];
        }

        
$mainHookRecord    = array('hook_name'                => trim($this->request['hook_name']),
                                
'hook_key'                => substr( trim($this->request['hook_key']), 0, 32 ),
                                
'hook_global_caches'    => ( is_array($this->request['hook_global_caches']) && count($this->request['hook_global_caches']) ) ? implode(',', $this->request['hook_global_caches']) : '',
                                
'hook_desc'                => trim($this->request['hook_desc']),
                                
'hook_version_human'    => trim($this->request['hook_version_human']),
                                
'hook_version_long'        => trim($this->request['hook_version_long']),
                                
'hook_author'            => trim($this->request['hook_author']),
                                
'hook_email'            => trim($this->request['hook_email']),
                                
'hook_website'            => trim($this->request['hook_website']),
                                
'hook_update_check'        => trim($this->request['hook_update_check']),
                                
'hook_enabled'            => $type == 'add' ? 1 : $hookData['hook_enabled'],
                                
'hook_installed'        => $type == 'add' ? IPS_UNIX_TIME_NOW : $hookData['hook_installed'],
                                
'hook_updated'            => $type == 'add' ? 0 : IPS_UNIX_TIME_NOW,
                                
'hook_position'            => $position['newPos'],
                                
'hook_requirements'        => serialize( array('required_applications'    => $requireApp,
                                                                            
'hook_php_version_min'    => trim($this->request['hook_php_version_min']),
                                                                            
'hook_php_version_max'    => trim($this->request['hook_php_version_max'])
                                                                            )
                                                                     )
                                );
        
        if( 
$type == 'edit' )
        {
            
$this->DB->update( 'core_hooks', $mainHookRecord, 'hook_id=' . $hookData['hook_id'] );
            
            
$this->DB->delete( 'core_hooks_files', 'hook_hook_id=' . $hookData['hook_id'] );
        }
        else
        {
            
$this->DB->insert( 'core_hooks', $mainHookRecord );
            
            
$hookData['hook_id'] = $this->DB->getInsertId();
        }
        
        foreach( 
$newFiles as $index => $toInsert )
        {
            
$toInsert['hook_hook_id'] = $hookData['hook_id'];
            
            
$this->DB->insert( 'core_hooks_files', $toInsert );
        }
        
        
/* Rebuild cache */
        
$this->rebuildHooksCache();
        
        
/* Rebuild global caches */
        
try
        {
            
IPSLib::cacheGlobalCaches();
        }
        catch( 
Exception $e ){}
        
        
/* Flag skins for recache */
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinFunctions.php' );/*noLibHook*/
        
require_once( IPS_ROOT_PATH . 'sources/classes/skins/skinCaching.php' );/*noLibHook*/
        
$skinCaching = new skinCaching( $this->registry );
        
$skinCaching->flagSetForRecache();
        
        
/* Redirect */
        
$this->registry->output->setMessage( $this->lang->words['h_saved'] );
        
$this->registry->output->silentRedirectWithMessage( $this->settings['base_url'] . $this->form_code . '&amp;do=hooks_overview' );
    }
    
    
/**
     * View details about a hook
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _viewDetails()
    {
        
$id    = intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError( $this->lang->words['h_nodetails'], 11110 );
        }
        
        
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_nodetails'], 11111 );
        }
        
        
/* Extra data */
        
$hookData['_updated']         = $this->registry->getClass('class_localization')->formatTime( $hookData['hook_updated'] );
        
$hookData['hook_extra_data'] = unserialize( $hookData['hook_extra_data'] );
        
        
/* Meets requirements? */
        
$hookData['_require_errors'] = $this->checkHookRequirements( $hookData );
        
        
/* Got updates? */
        
if ( $hookData['hook_update_check'] )
        {
            
$hookData['hook_update_available']    = $this->_updateAvailable( $hookData['hook_update_check'], $hookData['hook_version_long'] );
        }
        else
        {
            
$hookData['hook_update_available']    = array( 0 );
        }
        
        
/* Get files */
        
$files = array();
        
$index = 1;
        
        
$this->DB->build( array( 'select' => '*', 'from' => 'core_hooks_files', 'where' => 'hook_hook_id=' . $id ) );
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            
$r['hook_data']  = unserialize( $r['hook_data'] );
            
$files[ $index ] = $r;
            
$index++;
        }

        
/* Output */
        
$this->registry->output->html .= $this->html->hookDetails( $hookData, $files );
    }
    
    
/**
     * Check if the hook meets all the requirements
     * 
     * @param    mixed    $hook    Can be an hook ID or an array of the hook data
     * @return    @e array Errors found
     */
    
public function checkHookRequirements( $hook )
    {
        
/* Init vars */
        
$hookData = array();
        
$reqsData = array();
        
$errors   = array();
        
        
/* We already have some data? */
        
if ( is_array($hook) && count($hook) )
        {
            
$hookData = $hook;
        }
        elseif ( 
is_int($hook) )
        {
            
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $hook ) );
        }
            
        
/* Requirements are still serialized? */
        
if ( IPSLib::isSerialized($hookData['hook_requirements']) )
        {
            
$hookData['hook_requirements'] = unserialize($hookData['hook_requirements']);
        }
        
        
/* Make our var shorter... */
        
$reqsData = &$hookData['hook_requirements'];
        
        
/* Old data? - @todo: remove this check around 3.3(4?) */
        
if ( ! isset($reqsData['required_applications']['core']) && isset($reqsData['hook_ipb_version_min']) && ( $reqsData['hook_ipb_version_min'] > 0 || $reqsData['hook_ipb_version_max'] > 0 ) )
        {
            
$reqsData['hook_ipb_version_min'] = ( $reqsData['hook_ipb_version_min'] < 30000 ) ? 30000 : $reqsData['hook_ipb_version_min'];
            
            
$reqsData['required_applications']['core'] = array( 'min_version' => intval($reqsData['hook_ipb_version_min']), 'max_version' => intval($reqsData['hook_ipb_version_max']) );
        }
        
        
//-----------------------------------------
        // Let's start checking requirements
        //-----------------------------------------
        
        /* PHP */
        
if( $reqsData['hook_php_version_min'] OR $reqsData['hook_php_version_max'] )
        {
            if( 
$reqsData['hook_php_version_min'] AND version_compare( PHP_VERSION, $reqsData['hook_php_version_min'], '<' ) == true )
            {
                
$errors['php_min'] = sprintf( $this->lang->words['h_phpold'],$reqsData['hook_php_version_min'] );
            }
            
            if( 
$reqsData['hook_php_version_max'] AND version_compare( PHP_VERSION, $reqsData['hook_php_version_max'], '>' ) == true )
            {
                
$errors['php_max'] = sprintf( $this->lang->words['h_phpnew'], $reqsData['hook_php_version_max'] );
            }
        }
        
        
/* Additional applications */
        
if ( is_array($reqsData['required_applications']) && count($reqsData['required_applications']) )
        {
            
/* Get the setup class */
            
require_once( IPS_ROOT_PATH . 'setup/sources/base/setup.php' );/*noLibHook*/
            
            /* Loop through all apps */
            
foreach( $reqsData['required_applications'] as $appKey => $appData )
            {
                
/* Versions file doesn't exist? */
                
if ( !is_file( IPSLib::getAppDir( $appKey ) . '/xml/versions.xml' ) )
                {
                    
$errors[ $appKey.'_app' ] = sprintf( $this->lang->words['hook_require_appnotfound'], $appData['app_name'] );
                }
                
/* App not installed/enabled? */
                
elseif ( !IPSLib::appIsInstalled( $appKey ) )
                {
                    
$errors[ $appKey.'_app' ] = sprintf( $this->lang->words['hook_require_appdisabled'], ipsRegistry::$applications[ $appKey ]['app_title'] );
                }
                elseif ( 
$appData['min_version'] OR $appData['max_version'] )
                {
                    
/* Fetch and check versions */
                    
if ( !isset($this->cachedVersions[ $appKey ]) )
                    {
                        
$this->cachedVersions[ $appKey ] = IPSSetUp::fetchXmlAppVersions( $appKey );
                    }
                    
                    
$versions = $this->cachedVersions[ $appKey ];
                    
                    if ( 
is_array($versions) && count($versions) )
                    {
                        if ( !isset(
$this->cachedUpgradeInfo[ $appKey ]) )
                        {
                            
$_key    = in_array( $appKey, array( 'forums', 'members' ) ) ? 'core' : $appKey;
                            
$this->cachedUpgradeInfo[ $_key ]    = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'upgrade_history', 'where' => "upgrade_app='{$_key}'", 'order' => 'upgrade_version_id DESC', 'limit' => array( 1 ) ) );
                            
                            
/* Extra caching for the three core apps */
                            
if( in_array( $appKey, array( 'core', 'forums', 'members' ) ) )
                            {
                                
$this->cachedUpgradeInfo['core']    = $this->cachedUpgradeInfo[ $_key ];
                                
$this->cachedUpgradeInfo['forums']    = $this->cachedUpgradeInfo[ $_key ];
                                
$this->cachedUpgradeInfo['members']    = $this->cachedUpgradeInfo[ $_key ];
                            }
                        }
                        
                        
/* Do we meet tha requirements? */
                        
if ( $appData['min_version'] AND $this->cachedUpgradeInfo[ $appKey ]['upgrade_version_id'] < $appData['min_version'] )
                        {
                            
$errors[ $appKey.'_min' ] = sprintf( $this->lang->words['hook_require_tooold'], isset($versions[ $appData['min_version'] ]) ? $versions[ $appData['min_version'] ] : $appData['min_version'] );
                        }
                        
                        if ( 
$appData['max_version'] AND $this->cachedUpgradeInfo[ $appKey ]['upgrade_version_id'] > $appData['max_version'] )
                        {
                            
$errors[ $appKey.'_max' ] = sprintf( $this->lang->words['hook_require_toonew'], isset($versions[ $appData['max_version'] ]) ? $versions[ $appData['max_version'] ] : $appData['max_version'] );
                        }
                    }
                }
            }
        }
        
        return 
$errors;
    }
    
    
/**
     * Check if you meet hook requirements
     *
     * @return    @e void        [Outputs to screen]
     */
    
protected function _checkRequirements()
    {
        
$id    = intval($this->request['id']);
        
        if( !
$id )
        {
            
$this->registry->output->showError( $this->lang->words['h_norequirements'], 11112 );
        }
        
        
$hookData = $this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'core_hooks', 'where' => 'hook_id=' . $id ) );
        
        if( !
$hookData['hook_id'] )
        {
            
$this->registry->output->showError( $this->lang->words['h_norequirements'], 11113 );
        }
        
        
/* Get requirements */
        
$hookData['hook_requirements'] = unserialize($hookData['hook_requirements']);
        
        
/* Check requirements */
        
$errors = $this->checkHookRequirements( $hookData );
        
        
/* Output */
        
$this->registry->output->html .= $this->html->hookRequirements( $hookData, $errors, $this->cachedVersions );
    }
    
    
/**
     * Rebuild hooks cache
     *
     * @return    @e void
     */
    
public function rebuildHooksCache()
    {
        
/* INI */
        
$cache = array( 'commandHooks' => array(), 'skinHooks' => array(), 'templateHooks' => array(), 'dataHooks' => array(), 'libraryHooks' => array() );

        
/* First fix positions */
        
$this->_fixPositions();

        
/* Get current hooks */
        
$this->DB->build( array( 'select'    => 'f.*', 
                                 
'from'        => array( 'core_hooks_files' => 'f' ), 
                                 
'where'    => 'c.hook_enabled=1',
                                 
'order'    => 'c.hook_position ASC',
                                 
'add_join'    => array( array( 'select' => 'c.hook_id',
                                                             
'from'   => array( 'core_hooks' => 'c' ),
                                                             
'where'  => 'c.hook_id=f.hook_hook_id',
                                                             
'type'   => 'left' ) )
                            )        );
        
$this->DB->execute();
        
        while( 
$r = $this->DB->fetch() )
        {
            
/* Got no main hook id? Weird but skip.. */
            
if ( empty($r['hook_id']) )
            {
                continue;
            }
            
            
/* INIT */
            
$_cache    = array();
            
$data    = unserialize( $r['hook_data'] );
            
            
/* General Stuff */
            
$_cache    = array( 'filename'  => $r['hook_file_stored'],
                             
'className' => $r['hook_classname']
                            );
            
            
/* Hook type specific stuff */
            
if( $r['hook_type'] == 'templateHooks' )
            {
                
$_cache['type']                = $data['type'];
                
$_cache['skinFunction']        = $data['skinFunction'];
                
$_cache['id']                = $data['id'];
                
$_cache['position']            = $data['position'];
            }
            else if( 
/*$r['hook_type'] == 'dataHooks' OR*/ $r['hook_type'] == 'libraryHooks' )
            {
                
$_cache['classToOverload']    = $data['classToOverload'];
            }
            
            
/* Add to array */
            
if( $r['hook_type'] == 'templateHooks' )
            {
                
$cache[ $r['hook_type'] ][ $data['skinGroup'] ][] = $_cache;
            }
            else if( 
$r['hook_type'] == 'dataHooks' )
            {
                
$cache[ $r['hook_type'] ][ $data['dataLocation'] ][] = $_cache;
            }
            else if( 
$r['hook_type'] == 'libraryHooks' )
            {
                
$cache[ $r['hook_type'] ][ $data['libApplication'] ][ $data['classToOverload'] ][] = $_cache;
            }
            else
            {
                
$cache[ $r['hook_type'] ][ $data['classToOverload'] ][] = $_cache;
            }
        }
        
        
/* Update the cache */
        
$this->cache->setCache( 'hooks', $cache, array( 'array' => 1 ) );
    }
}
Онлайн: 2
Реклама