<repo_name>MartinAronsen/storm<file_sep>/hooks/Db.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Db extends _HOOK_CLASS_
{
    protected $start = null;

    protected $final = null;

    protected $currentQ = 1;


    public function query( $query, $log = true, $read = false )
    {
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB' ) and CJ_STORM_PROFILER_DISABLE_DB ) {
            return parent::query( $query, $log, $read );
        }

        $dbMem = true;
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB_MEM' ) and CJ_STORM_PROFILER_DISABLE_DB_MEM ) {
            $dbMem = false;
        }

        if ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) {
            $this->start = microtime( true );
            if ( $dbMem ) {
                \IPS\storm\Profiler::i()->memoryStart();
            }
            $return = parent::query( $query, true );
            $this->final = microtime( true ) - $this->start;
            $this->log( $query );
            $this->sendToProfiler();

            return $return;
        }

        return parent::query( $query, $log, $read );
    }


    public function log( $query, $server = null )
    {
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB' ) and CJ_STORM_PROFILER_DISABLE_DB ) {
            parent::log( $query, $server );
        }

        $dbMem = true;
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB_MEM' ) and CJ_STORM_PROFILER_DISABLE_DB_MEM ) {
            $dbMem = false;
        }

        if ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) {
            if ( $dbMem ) {
                \IPS\storm\Profiler::i()->memoryEnd( 'DB Query', $query );
            }
            $bt = var_export( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), true );
            $this->log[ $this->currentQ ] = [
                'query'     => $query,
                'backtrace' => $bt,
            ];
        }
        else {
            parent::log( $query, $server );
        }

    }

    public function sendToProfiler()
    {
        if ( isset( $this->log[ $this->currentQ ] ) ) {
            $data = $this->log[ $this->currentQ ];
            \IPS\storm\Profiler::i()->dbQuery( $data, round( $this->final, 4 ) );
            $this->currentQ++;
        }
    }


    public function preparedQuery( $query, array $_binds, $read = false )
    {
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB' ) and CJ_STORM_PROFILER_DISABLE_DB ) {
            return parent::preparedQuery( $query, $_binds );
        }
        $dbMem = true;
        if ( defined( 'CJ_STORM_PROFILER_DISABLE_DB_MEM' ) and CJ_STORM_PROFILER_DISABLE_DB_MEM ) {
            $dbMem = false;
        }

        if ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) {
            $this->start = microtime( true );
            if ( $dbMem ) {
                \IPS\storm\Profiler::i()->memoryStart();
            }

            $bindsS = [];
            $queryS = $query;
            $i = 0;
            for ( $j = 0; $j < \strlen( $queryS ); $j++ ) {
                if ( $queryS[ $j ] == '?' ) {
                    if ( array_key_exists( $i, $_binds ) ) {
                        if ( $_binds[ $i ] instanceof \IPS\Db\Select ) {
                            $queryS = \substr( $queryS, 0, $j ) . $_binds[ $i ]->query . \substr( $queryS, $j + 1 );
                            $j += \strlen( $_binds[ $i ]->query );

                            foreach ( $_binds[ $i ]->binds as $_bind ) {
                                $bindsS[] = $_bind;
                            }
                        }
                        else {
                            $bindsS[] = $_binds[ $i ];
                        }

                        $i++;
                    }
                }
            }

            $this->log( static::_replaceBinds( $queryS, $bindsS ) );
            $parent = parent::preparedQuery( $query, $_binds, $read );
            $this->final = microtime( true ) - $this->start;
            $this->sendToProfiler();

            return $parent;
        }

        return parent::preparedQuery( $query, $_binds, $read );
    }
}
<file_sep>/dev/lang.php
<?php

$lang = [
    '__app_storm' => "Storm",
    'menu__storm_configuration' => "Storm",
    'menu__storm_configuration_settings' => "Settings",
    'menu__storm_configuration_apps' => "Dev Folder: Applications",
    'menu__storm_configuration_proxyclass' => "Proxy Classes Generator",
    'menu__storm_configuration_plugins' => "Dev Folder: Plugins",
    'dev_class' => "Sources",
    'storm_settings_headerdoc__tabbed' => "Headerdoc",
    'storm_settings_headerdoc_enabled' => "Enabled",
    'storm_settings_headerdoc_enabled_desc' => 'If enabled, will add a file header to each php class.',
    'storm_settings_headerdoc_allowed_apps' => "Allowed Apps",
    'storm_settings_headerdoc_allowed_apps_desc' => "Select Apps to execute Header doc generation on 'build' and on 'download'.",
    'storm_settings_headerdoc__sidebar' => "If enabled, will add a temporary header doc to each php class file when app is built. On download, will replace the temp header doc with a permanent one, container @brief (class name), @author (app author), @copyright (current year with author name from app), @package (IPS Social Suite), @subpackage (App's name), @since (which version file was added in), @version (current version of app). Excluded folders: 3rdparty, vendor, dev, hooks, data (these are case sensitive).",
    'storm_proxyclass_progress' => "Processing %s of %s",
    'storm_proxyclass_done' => "Proxy Classes have been Generated",
    'storm_proxyclass_title' => "Proxy Classes",
    'storm_proxyclass_button' => "Generate Proxy Classes",
    'storm_apps_apps_select' => "Select Application",
    'storm_apps_app' => "Application",
    'storm_apps_app_desc' => "Select which application to generate the Dev Folder for.",
    'storm_apps_type' => "Type",
    'storm_apps_type_desc' => "Choose everything to recreate the entire Dev Folder, or select which part of the Dev folder you wish to recreate.",
    'storm_apps_type_lang' => "Language",
    'storm_apps_type_js' => "Javascript",
    'storm_apps_type_template' => "Templates",
    'storm_apps_type_email' => "Email Templates",
    'storm_apps_type_all' => "Everything",
    'storm_apps_type_select' => "Select Type",
    'storm_apps_return_javascript' => "Javascript Files Generated",
    'storm_apps_return_templates' => "Template Files Generated",
    'storm_apps_return_email' => "Email Template Files Generated",
    'storm_apps_return_lang' => "Language Strings Generated",
    'storm_apps_queue_title' => "Generating Dev Files",
    'storm_apps_total_done' => "Processing %s of %s",
    'storm_apps_completed' => "Dev Folder Generated Completed!",
    'storm_plugins_done' => "The Dev Folder for %s has been generated!",
    'storm_plugin_upload' => "Plugin XML",
    'storm_plugin_upload_desc' => "Upload the plugin's xml file here. Will install the plugin if its not already installed (this will overwrite if a dev folder is already there).",
    'storm_plugins_title' => "Plugins Dev Folder Generator",
    'storm_apps_title' => "Applications Dev Folder Generator",
    'storm_settings_title' => "Settings",
    'storm_proxyclass_sidebar' => "Generates proxy classes for IPS/IPS Apps/3rd party apps, This is useful for IDE's, so useful features such as autocomplete and hinting can be used, since IPS's framework is uniuque.",
    'storm_class_type' => "Class Type",
    'storm_class_type_desc' => "Class type, Class for a regular class. Node for a \\IPS\\Node\\Model class. Content Item for a \\IPS\\Content\\Item class. Content Item Comment Class for a \\IPS\\Content\\Comment class.",
    'storm_class_namespace' => "Namespace",
    'storm_class_namespace_desc' => "Namespace for the class, leave blank if not a subclass. Class: \\IPS\\myapp, SubClass: \\IPS\\myapp\\ParentClass",
    'storm_class_className' => "Class Name",
    'storm_class_className_desc' => "do not include the underscore( _ ). This will also be the file's name.",
    'storm_class_extends' => "Extends",
    'storm_class_extends_desc' => "Does this class extend another class? if yes, please use the FQN here.",
    'storm_class_implements' => "Implements",
    'storm_class_implements_desc' => "will this class implement any interface classes? Use the FQN.",
    'storm_classes_class_no_exist' => "This class already exist in this namespace.",
    'storm_classes_extended_class_no_exist' => "The extended class does not exist!",
    'storm_classes_implemented_no_interface' => "One of your implemented interface classes does not exist!",
    'storm_classes_type_no_selection' => "Please select a type!",
    'storm_settings_general__tabbed' => "General",
    'storm_settings_enable_debug' => "Enable",
    'storm_settings_enable_debug_desc' => "Enable console output",
    'ext__Headerdoc' => 'Customize how the headerdoc works for storm.',
    'storm_settings_profiler' => "Profiler",
    'storm_settings_enable_query' => "Enable DB Queries",
    'storm_class_created' => "Created %s Class: %s has been created successfully!",
    'storm_devfolder_created' => "%s has been successfully created.",
    'storm_settings_tab_debug_templates' => "Debug Templates",
    'storm_settings_tab_debug_templates_desc' => "This will write the templates to disk for easier debugging.",
    'storm_settings_tab_debug_css' => "Debug CSS",
    'storm_settings_tab_debug_css_desc' => "Requires debug templates to be enabled, but writes the css to disk and allows for easier debugging.",
    'storm_settings_tab_debug_css_alt' => "Alt CSS Loading",
    'storm_settings_tab_debug_css_alt_desc' => "if you are getting no css, you could be hitting the query string limit in apache, enable this to try to avoid it.",
    'storm_settings_tab_profiler' => "Profiler",
    'storm_settings_tab_debug' => "Dev & Debug",
    'storm_dev_folder' => "Dev Folder",
    'storm_devfolder_type' => "Type",
    'storm_devfolder_type_desc' => "Select what dev folder type you want to create. (template, javascript)",
    'storm_devfolder_args' => "Arguments",
    'storm_devfolder_args_desc' => "the argumenuts for the file.",
    'storm_devfolder_loc' => "Location",
    'storm_devfolder_loc_desc' => "accessed from (front, admin, global)",
    'storm_devfolder_group' => "Group",
    'storm_devfolder_group_desc' => "containing group for file",
    'storm_devfolder_filename' => "Filename",
    'storm_devfolder_filename_desc' => "name of the file.",
    'storm_devfolder_loc_error' => "You need to select a location",
    'storm_devfolder_group_error' => 'enter a group',
    'storm_devfolder_widgetname_error' => "Widget Name required",
    'storm_devfolder_filename_error' => "enter a filename",
    'storm_devfolder_filename_exist' => "File with this name exists at this location.",
    'storm_devfolder_widgetname' => "Widget Name",
    'storm_devfolder_widgetname_desc' => "Used when loading the widget over the data api",
    'storm_create_class' => "Create Class File",
    'storm_create_class_desc' => "This allows you to create your node/AR/Item/Comment class with your database",
    'storm_classes_no_blank' => "Can't be blank!",
    'storm_class_item_node_class' => "Node/Item Class",
    'storm_class_item_node_class_desc' => "Enter the node/item class for Item/Comment class you are about to create.",
    'storm_class_node_item_missing' => "Node/Item Class doesn't exists.",
    'storm_class_database' => "Database",
    'storm_class_prefix' => "Prefix",
    'storm_profiler_is_fixed' => "Always show Profiler",
    'storm_progress' => "%s out of %s",
    'storm_mc_limit' => "Amount",
    'storm_mc_limit_desc' => "How many dummy records to create",
    'storm_mc_passwords' => "<PASSWORD>",
    'storm_mc_avatars' => "Create Avatars",
    'storm_mc_group' => "Group",
    'menu__storm_configuration_generator' => "Dummy Data Generator",
    'storm_gen_type' => "Type",
    'storm_gen_limit' => "Amount",
    'storm_gen_limit_desc' => "How many of the type to create. Forums will create between 1 to 12 topics and each topic will create between 1 to 12 posts, Topics will create 1 to 12 posts.",
    'storm_gen_none' => "Please select a type!",
    'storm_generation_done' => "Generation Done",
    'storm_generation_delete_done' => "Dummy Data Deleted",
    'storm_apps_folder_exist' => "The folder %s already exist. please remove this folder if you want to replace.",
    'storm_apps_please_select' => "Please make a selection",
    'module__storm_bitbucket' => "Bitbucket",
    'module__storm_general' => "General",
    'r__Proxyclass' => "Proxyclass",
    'r__proxyclass_manage' => "can generate proxyclasses",
    'r__apps' => "Apps",
    'r__apps_manage' => "can generate application dev folders",
    'r__members_manage' => "can use generator",
    'r__storm_create_members_loop' => "Generate Members",
    'r__storm_create_generation_loop' => "Generate Forums",
    'r__Geneerators' => "Generators",
    'storm_query_select' => "Action",
    'storm_query_table' => 'Table',
    'storm_query_add_column' => 'Column',
    'storm_query_type' => "Type",
    'storm_query_length' => "Length",
    'storm_query_decimals' => 'Decimals',
    'storm_query_default' => "Default",
    'storm_query_comment' => 'Comment',
    'storm_query_allow_null' => "Allow Null",
    'storm_query_sunsigned' => 'Unsigned',
    'storm_query_zerofill' => "ZeroFill",
    'storm_query_auto_increment' => 'Auto-Increment',
    'storm_query_binary' => 'Binary',
    'storm_query_unsigned' => 'Value',
    'storm_query_values' => 'Values',
    'storm_query_columns' => 'Table Column',
    'storm_query_code' => 'Query Box',
    'storm_member_creation_done' => 'Dummy data creation done',
    'storm_remote_key_use' => "Remote Key",
    'storm_remote_key_use_desc' => "<br>Use this key in another storm instance to sync apps.",
    'storm_remote_url' => "Remote Interface",
    'storm_remote_url_desc' => "<br> Use this for the remote interface in another storm instance to sync an app",
    'storm_ftp_app' => "Remote App",
    'general_tab' => "General",
    'remote_tab' => "Sync",
    'storm_ftp_path' => "FTP Path",
    'storm_ftp_path_desc' => "Full path to where the synced file is located.",
    'storm_ftp_key' => "Remote Key",
    'storm_ftp_interface_host' => "Remote Interface",
    'storm_ftp_host' => "FTP Host",
    'storm_ftp_username' => "FTP Username",
    'storm_ftp_pass' => "FTP <PASSWORD>",
    'storm_ftp_port' => "FTP Port",
    'storm_ftp_timeout' => "FTP Timeout",
    'storm_ftp_ssh' => "Use SSH",
    'storm_cron_task' => "Cron Task",
    'storm_cron_task_desc' => "<br>Add this to your cron, set to however often you want it to run.",
    'menu__storm_configuration_menu' => "Menu",
    'storm_menu_name' => 'Name',
    'storm_menu_parent' => "Parent",
    'storm_menu_type' => 'Type',
    'storm_menu_internal' => 'Url',
    'storm_menu_external' => 'Url',
    'storm_ftp_secure' => "Secure Connection",
    'storm_settings_disable_menu' => "Disable Menu",
    'storm_settings_disable_menu_desc' => "Disables the header menu.",
    'menu__storm_configuration_sync' => "Sync"
    //    'storm_apps_select_app' => "Select App"
];
<file_sep>/modules/admin/configuration/generator.php
<?php

/**
 * @brief       Generator Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       2.1.0
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * members
 */
class _generator extends \IPS\Dispatcher\Controller
{
    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'members_manage' );

        parent::execute();
    }

    protected function manage()
    {
        $groups = [];
        foreach( \IPS\Member\Group::groups() as $k => $v )
        {
            $groups[ $k ] = $v->get_formattedName();
        }

        $url = $this->url->setQueryString( [ 'do' => 'delete', 'oldDo' => \IPS\Request::i()->do ] );
        \IPS\Output::i()->sidebar[ 'actions' ][ 'refresh' ] = [
            'icon' => 'delete',
            'title' => 'Delete Dummy Data',
            'link' => $url,

        ];

        $el = [
            [
                'class' => "Select",
                'name' => "storm_gen_type",
                'options' => [
                    'options' => [
                        'none' => "Select Type",
                        'members' => "Members",
                        'forums' => "Forums",
                        'topics' => "Topics",
                        'posts' => "Posts"
                    ],
                    'toggles' => [
                        'members' => [
                            'storm_mc_passwords',
                            'storm_mc_avatars',
                            'storm_mc_group'
                        ]
                    ]
                ],
                'validation' => function( $data )
                {
                    if( $data == "none" )
                    {
                        throw new \InvalidArgumentException( 'storm_gen_none' );
                    }
                }
            ],
            [
                'class' => "Number",
                'name' => "storm_mc_limit",
                'default' => 1,
                'options' => [
                    'min' => 1
                ]
            ],
            [
                'class' => "YesNo",
                'default' => 1,
                'name' => "storm_mc_passwords"
            ],
            [
                'class' => "YesNo",
                'default' => 1,
                'name' => "storm_mc_avatars"
            ],
            [
                'class' => "Select",
                'name' => "storm_mc_group",
                'default' => \IPS\Settings::i()->getFromConfGlobal( 'member_group' ),
                'options' => [
                    'options' => $groups,
                ]
            ]
        ];

        $form = \IPS\storm\Forms::i( $el );

        if( $vals = $form->values() )
        {
            if( $vals[ 'storm_gen_type' ] == "members" )
            {
                $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator&do=createMembers" )
                                    ->setQueryString( [
                                        'password' => $vals[ '<PASSWORD>' ],
                                        'limit' => $vals[ 'storm_mc_limit' ],
                                        'avatar' => $vals[ 'storm_mc_avatars' ],
                                        'group' => $vals[ 'storm_mc_group' ]
                                    ] );
            }
            else
            {
                $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator&do=generator" )
                                    ->setQueryString( [
                                        'type' => $vals[ 'storm_gen_type' ],
                                        'limit' => $vals[ 'storm_mc_limit' ]
                                    ] );
            }

            \IPS\Output::i()->redirect( $url );
        }

        \IPS\Output::i()->title = "Generate Dummy Data";
        \IPS\Output::i()->output = $form;
    }

    protected function delete()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'storm_create_delete_loop' );
        \IPS\Output::i()->title = "Delete Content";

        $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator&do=delete" );
        $url->setQueryString( [ 'oldDo' => \IPS\Request::i()->oldDo ] );
        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            $url,
            function( $data )
            {
                $offset = 0;
                if( isset( $data[ 'offset' ] ) )
                {
                    $offset = $data[ 'offset' ];
                }

                if( !isset( $data[ 'total' ] ) )
                {
                    $total = \IPS\Db::i()->select(
                        'COUNT(*)',
                        'storm_generator'
                    )->first();
                }
                else
                {
                    $total = $data[ 'total' ];
                }

                $limit = 10;

                $select = \IPS\Db::i()->select(
                    '*',
                    'storm_generator',
                    [],
                    'generator_id ASC',
                    $limit,
                    null,
                    null,
                    \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS
                );

                if( !$select->count() )
                {
                    return null;
                }

                $content = new \IPS\Patterns\ActiveRecordIterator(
                    \IPS\Db::i()->select( '*', 'storm_generator', [], 'generator_id ASC', $limit ),
                    'IPS\storm\Generator'
                );

                foreach( $content as $key => $v )
                {
                    $v->process();
                    $offset++;
                }

                $progress = ( $offset / $total ) * 100;

                $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_progress', false, [
                    'sprintf' => [
                        $offset,
                        $total
                    ]
                ] );

                return [ [ 'total' => $total, 'offset' => $offset ], $language, $progress ];
            },
            function()
            {
                /* And redirect back to the overview screen */
                $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator" );
                \IPS\Output::i()->redirect( $url, 'storm_generation_delete_done' );
            }
        );
    }

    protected function createMembers()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'storm_create_members_loop' );
        \IPS\Output::i()->title = "Member Creation";
        $limit = \IPS\Request::i()->limit ?: 10;
        $password = \IPS\Request::i()->password ?: null;
        $group = \IPS\Request::i()->group ?: null;
        $avatar = \IPS\Request::i()->avatar ?: null;
        $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator&do=createMembers" )
                            ->setQueryString( [
                                'password' => <PASSWORD>,
                                'limit' => $limit,
                                'avatar' => $avatar,
                                'group' => $group
                            ] );

        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            $url,
            function( $data )
            {
                $offset = 0;
                $limit = \IPS\Request::i()->limit ?: 10;
                $password = \IPS\Request::i()->password ?: <PASSWORD>;
                $group = \IPS\Request::i()->group ?: null;
                $avatar = \IPS\Request::i()->avatar ?: null;
                if( isset( $data[ 'offset' ] ) )
                {
                    $offset = $data[ 'offset' ];
                }

                if( isset( $data[ 'limit' ] ) )
                {
                    $limit = $data[ 'limit' ];
                }

                if( isset( $data[ 'password' ] ) )
                {
                    $password = $data[ 'password' ];
                }

                if( isset( $data[ 'group' ] ) )
                {
                    $group = $data[ 'group' ];
                }

                if( isset( $data[ 'avatar' ] ) )
                {
                    $avatar = $data[ 'avatar' ];
                }

                $max = 10;

                if( $limit < $max )
                {
                    $max = $limit;
                }

                if( $offset >= $limit )
                {
                    return null;
                }


                for( $i = 0; $i < $max; $i++ )
                {
                    $mem = new \IPS\storm\Pseudo\Member;
                    $mem->run( $password, $group, $avatar );
                    $offset++;
                }

                $progress = ( $offset / $limit ) * 100;

                $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_progress', false, [
                    'sprintf' => [
                        $offset,
                        $limit
                    ]
                ] );

                return [
                    [
                        'password' => <PASSWORD>,
                        'group' => $group,
                        'avatar' => $avatar,
                        'limit' => $limit,
                        'offset' => $offset
                    ],
                    $language,
                    $progress
                ];
            },
            function()
            {
                $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator" );
                \IPS\Output::i()->redirect( $url, 'storm_member_creation_done' );
            }
        );
    }

    protected function generator()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'storm_create_generation_loop' );
        \IPS\Output::i()->title = "Generator";
        $type = \IPS\Request::i()->type ?: "forums";
        $limit = \IPS\Request::i()->limit ?: 10;
        $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator&do=generator" )
                            ->setQueryString( [
                                'type' => $type,
                                'limit' => $limit
                            ] );

        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            $url,
            function( $data )
            {
                $offset = 0;
                $type = \IPS\Request::i()->type ?: "Forum";
                $limit = \IPS\Request::i()->limit ?: 10;
                if( isset( $data[ 'offset' ] ) )
                {
                    $offset = $data[ 'offset' ];
                }

                if( isset( $data[ 'limit' ] ) )
                {
                    $limit = $data[ 'limit' ];
                }

                if( isset( $data[ 'type' ] ) )
                {
                    $type = $data[ 'type' ];
                }

                $max = 1;

                if( $limit < $max )
                {
                    $max = $limit;
                }

                if( $offset >= $limit )
                {
                    return null;
                }

                for( $i = 0; $i < $max; $i++ )
                {
                    switch( $type )
                    {
                        case "forums":
                            \IPS\storm\Pseudo\Generator::i()->generateForum( false, true );
                            break;
                        case "topics":
                            \IPS\storm\Pseudo\Generator::i()->generateTopic();
                            break;
                        case "posts":
                            \IPS\storm\Pseudo\Generator::i()->generatePost();
                            break;
                    }
                    $offset++;
                }

                $progress = ( $offset / $limit ) * 100;

                $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_progress', false, [
                    'sprintf' => [
                        $offset,
                        $limit
                    ]
                ] );

                return [ [ 'type' => $type, 'limit' => $limit, 'offset' => $offset ], $language, $progress ];
            },
            function()
            {
                $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=generator" );
                \IPS\Output::i()->redirect( $url, 'storm_member_creation_done' );
            }
        );
    }
}
<file_sep>/Application.php
<?php

/**
 * @brief       Application Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.3
 * @version     -storm_version-
 */

namespace IPS\storm;

/**
 * Fixer Application Class
 */
class _Application extends \IPS\Application
{
    public function acpMenu()
    {
        if( \IPS\IN_DEV )
        {
            $dir = \IPS\ROOT_PATH . "/applications/" . $this->directory . "/dev/";
            if( !file_exists( $dir ) )
            {
                $app = new \IPS\storm\Apps( $this );
                $app->addToStack = true;
                $app->email();
                $app->javascript();
                $app->language();
                $app->templates();
            }
        }

        return parent::acpMenu(); // TODO: Change the autogenerated stub
    }

    public function installOther()
    {
        \IPS\storm\Menu::importMenus( \IPS\storm\Menu::$installMenus );
        parent::installOther(); // TODO: Change the autogenerated stub
    }
}<file_sep>/sources/Proxyclass/Proxyclass.php
<?php

/**
 * @brief       Proxyclass Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.0
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Proxyclass extends \IPS\Patterns\Singleton
{

    public static $instance = null;

    protected $save = 'proxyclasses';

    public function run( $data = [] )
    {
        $i = 0;
        if( isset( \IPS\Data\Store::i()->storm_proxyclass_files ) )
        {
            $iterator = \IPS\Data\Store::i()->storm_proxyclass_files;
            $totalFiles = $data[ 'total' ];
            $limit = 50;

            foreach( $iterator as $key => $file )
            {
                $i++;
                $filePath = $file[ 0 ];
                $this->build( $filePath );
                unset( $iterator[ $key ] );
                if( $i == $limit )
                {
                    break;
                }
            }

            \IPS\Data\Store::i()->delete( 'storm_proxyclass_files' );
        }

        if( $i )
        {
            if( is_array( $iterator ) and count( $iterator ) )
            {
                \IPS\Data\Store::i()->storm_proxyclass_files = $iterator;
            }

            if( $data[ 'current' ] )
            {
                $offset = $data[ 'current' ] + $i;
            }
            else
            {
                $offset = $i;
            }

            return [ 'total' => $totalFiles, 'current' => $offset, 'progress' => $data[ 'progress' ] ];
        }
        else
        {
            $this->buildConstants();
            return null;
        }
    }

    public function build( $file )
    {
        $ds = DIRECTORY_SEPARATOR;

        $root = \IPS\ROOT_PATH;

        $save = $root . $ds . $this->save . $ds;

        if( !is_dir( $save ) )
        {
            return;
        }

        $content = \file_get_contents( $file );
        $content = \preg_replace( '!/\*.*?\*/!s', '', $content );
        $content = \preg_replace( '/\n\s*\n/', "\n", $content );
        preg_match( '#\$databaseTable(.*?)\=(.*?)[\'|"](.*?)[\'|"]\;#msu', $content, $match);
        $db = null;
        if( isset( $match[3] ) ){
            $db = $match[3];
        }
        \preg_match( '/namespace(.+?)([^\;]+)/', $content, $matched );

        $namespace = null;

        if( isset( $matched[ 0 ] ) )
        {
            $namespace = $matched[ 0 ];
        }
        $regEx = '#(?:(?<!\w))(?:[^\w]|\s+)(?:(?:(?:abstract|final|static)\s+)*)class\s+([-a-zA-Z0-9_]+)?#';

        $run = function( $matches ) use ( $namespace, $save, $db )
        {
            if( isset( $matches[ 1 ] ) )
            {
                if( mb_substr( $matches[ 1 ], 0, 1 ) === '_' )
                {
                    $content = '';
                    $append = \ltrim( $matches[ 1 ], '\\' );
                    $class = \str_replace( '_', '', \ltrim( $matches[ 1 ], '\\' ) );

                    $extra = '';
                    $testClass = \str_replace( 'namespace ', '', $namespace ) . '\\' . $class;
                    $isSettings = false;
                    //took less than 5 minutes to implement this 'ultra complex' code
                    try
                    {
                        if( $db and method_exists( $testClass, 'db' ) )
                        {
                            if( $testClass::db()->checkForTable( $testClass::$databaseTable ) )
                            {
                                $foo = $testClass::db()->getTableDefinition( $testClass::$databaseTable );
                                if( isset( $foo[ 'columns' ] ) )
                                {
                                    foreach( $foo[ 'columns' ] as $key => $val )
                                    {
                                        if( mb_substr( $key, 0, mb_strlen( $testClass::$databasePrefix ) ) ==
                                            $testClass::$databasePrefix
                                        )
                                        {
                                            $key = mb_substr( $key, mb_strlen( $testClass::$databasePrefix ) );
                                        }
                                        $extra .= "public \${$key} = '';\n";
                                    }
                                }
                            }
                        }

                        if( $testClass === 'IPS\Settings' ){
                            $isSettings = true;
                            $load = $testClass::i()->getData();
                            foreach( $load as $key => $val ){
                                $extra .= "public \${$key} = '';\n";
                            }
                        }
                    }
                    catch( \Exception $e ){};

                    if( !$isSettings ) {
                        $alt = \str_replace( [
                            "\\",
                            " ",
                            ";",
                        ], "_", $namespace );
                    }
                    else{
                        $alt = 'IPS_Settings_lone';
                    }
                    if( !\is_file( $save . $alt . '.php' ) )
                    {
                        $content = "<?php\n\n";

                        if( $namespace )
                        {
                            $content .= $namespace . ";\n";
                        }
                    }
                    $content .= str_replace( '_', '', $matches[ 0 ] ) . ' extends ' . $append . '{' . PHP_EOL . $extra . '}' . "\n";
                    $createdClass[ \str_replace( 'namespace ', '', $namespace ) ][] = $class;

                    \file_put_contents( $save . $alt . ".php", $content, FILE_APPEND );
                    \chmod( $save . $alt . ".php", 0777 );
                }
            }
        };
        preg_replace_callback( $regEx, $run, $content, 1 );

    }

    public function buildConstants(){
        $load = \IPS\IPS::defaultConstants();
        $ds = DIRECTORY_SEPARATOR;
        $root = \IPS\ROOT_PATH;
        $save = $root . $ds . $this->save . $ds;
        $extra = "\n";
        foreach( $load as $key => $val ){
            if( !is_numeric( $val ) ){
                $val = "'".$val."'";
            }
            $extra .= 'define( "IPS\\'.$key.'",'. $val.");\n";
        }
        $php = <<<EOF
<?php
{$extra}
EOF;
        \file_put_contents( $save .  "IPS_Constants_lone.php", $php );
        \chmod( $save .  "IPS_Constants_lone.php", 0777 );
    }

    public function generateSettings(){
        $ds = DIRECTORY_SEPARATOR;
        $root = \IPS\ROOT_PATH;
        $save = $root . $ds . $this->save . $ds;
        $load = \IPS\Settings::i()->getData();
        $extra = "\n";
        foreach( $load as $key => $val ){
            $extra .= "public \${$key} = '';\n";
        }
        $php = <<<EOF
<?php

namespace IPS;

class Settings extends _Settings {
{$extra}
}
EOF;
        \file_put_contents( $save .  "IPS_Settings_lone.php", $php );
        \chmod( $save .  "IPS_Settings_lone.php", 0777 );
    }

    public function dirIterator()
    {
        $ds = DIRECTORY_SEPARATOR;
        $root = \IPS\ROOT_PATH;
        $save = $root . $ds . $this->save . $ds;

        if( \is_dir( $save ) )
        {
            $files = \glob( $save . "*" );

            foreach( $files as $file )
            {
                if( \is_file( $file ) )
                {
                    \unlink( $file );
                }
            }

            \rmdir( $save );
        }

        if( !is_dir( $save ) )
        {
            \mkdir( $save );
            \chmod( $save, 0777 );
        }

        $exclude = [
            $this->save,
            '.htaccess',
            'datastore',
            'plugins',
            'dev',
            'admin',
            'api',
            'interface',
            'uploads',
            'data',
            'extensions',
            'hooks',
            'setup',
            'modules',
            'tasks',
            'widgets',
            'Plugin',
            '3rdparty',
            '3rd_party',
            'themes',
            'conf_global.php',
            'index.php',
            'sitemap.php',
            'constants.php',
            'init.php',
            'error.php',
            '404error.php',
            'StormTemplates',
        ];

        $filter = function( $file, $key, $iterator ) use ( $exclude )
        {
            if( !\in_array( $file->getFilename(), $exclude ) )
            {
                return true;
            }

            return false;
        };

        $dirIterator = new \RecursiveDirectoryIterator(
            $root,
            \RecursiveDirectoryIterator::SKIP_DOTS
        );

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveCallbackFilterIterator( $dirIterator, $filter ),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        $iterator = new \RegexIterator( $iterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH );
        $iterator = iterator_to_array( $iterator );

        if( isset( \IPS\Data\Store::i()->storm_proxyclass_files ) )
        {
            unset( \IPS\Data\Store::i()->storm_proxyclass_files );
        }

        \IPS\Data\Store::i()->storm_proxyclass_files = $iterator;

        return count( $iterator );
    }
}<file_sep>/modules/admin/configuration/apps.php
<?php

/**
 * @brief       Apps Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.6
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * apps
 */
class _apps extends \IPS\Dispatcher\Controller
{

    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'apps_manage' );
        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        $apps = \IPS\Data\Store::i()->applications;

        $groups[ 'select' ] = \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_apps_select' );

        foreach( $apps as $key => $val )
        {
            $groups[ $val[ 'app_directory' ] ] = \IPS\Member::loggedIn()
                                                            ->language()
                                                            ->get( "__app_{$val[ 'app_directory' ]}" );
        }

        $langs = [
            'select' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_select' ),
            'all' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_all' ),
            'language' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_lang' ),
            'javascript' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_js' ),
            'templates' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_template' ),
            'email' => \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_type_email' ),
        ];

        $validation = function( $data )
        {
            if( $data == "select" )
            {
                throw new \InvalidArgumentException( 'form_bad_value' );
            }
            $app = \IPS\Request::i()->storm_apps_app;
            $folders = \IPS\ROOT_PATH . "/applications/{$app}/dev";
            $f = $folders;
            $folders2 = false;
            $folders3 = false;

            if( $data != "all" )
            {
                switch( $data )
                {
                    case 'language':
                        $folders .= "/lang.php";
                        $folders2 = $f . "/jslang.php";
                        break;
                    case "javascript":
                        $folders .= "/js/";
                        break;
                    case "templates":
                        $folders .= "/html/";
                        $folders2 = $f . "/css/";
                        $folders3 = $f . "/resources/";
                        break;
                    case "email":
                        $folders .= "/email/";
                        break;
                }
            }

            if( file_exists( $folders ) or ( $folders2 and file_exists( $folders2 ) and $folders = $folders2 ) or ( $folders3 and file_exists( $folders3 ) and $folders = $folders3 ) )
            {
                $lang = \IPS\Member::loggedIn()
                                   ->language()
                                   ->addToStack( 'storm_apps_folder_exist', false, [ 'sprintf' => $folders ] );
                throw new \InvalidArgumentException( $lang );
            }
        };

        $el = [
            [
                'name' => 'storm_apps_app',
                'class' => 'Select',
                'ap' => true,
                'default' => 'select',
                'options' => [
                    'options' => $groups
                ],
                'v' => function( $data )
                {
                    if( $data == "select" )
                    {
                        throw new \InvalidArgumentException( 'form_bad_value' );
                    }
                }
            ],
            [
                'name' => 'storm_apps_type',
                'class' => 'Select',
                'ap' => true,
                'default' => 'select',
                'options' => [
                    'options' => $langs
                ],
                'v' => $validation
            ]
        ];

        $form = \IPS\storm\Forms::i( $el );

        if( $vals = $form->values() )
        {
            $app = $vals[ 'storm_apps_app' ];
            $type = $vals[ 'storm_apps_type' ];

            if( $type === "all" )
            {
                \IPS\Output::i()->redirect( $this->url->setQueryString( [ 'do' => "queue", 'appKey' => $app ] ) );
            }
            else
            {
                $return = \IPS\storm\Apps::i( $app )->{$type}();
                \IPS\Output::i()->redirect( $this->url, $return );
            }
        }

        \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_title' );
        \IPS\Output::i()->output = $form;
    }

    protected function queue()
    {
        \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_queue_title' );

        $app = \IPS\Request::i()->appKey;

        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            \IPS\Http\Url::internal( "app=storm&module=configuration&controller=apps&do=queue&appKey=" . $app ),
            function( $data )
            {
                $app = \IPS\Request::i()->appKey;

                $end = false;

                if( isset( $data[ 'next' ] ) )
                {
                    $do = $data[ 'next' ];
                }
                else
                {
                    $do = 'language';
                }

                $done = 0;

                switch( $do )
                {
                    case 'language':
                        \IPS\storm\Apps::i( $app )->language();
                        $done = 25;
                        $next = 'javascript';
                        break;
                    case 'javascript':
                        \IPS\storm\Apps::i( $app )->javascript();
                        $done = 50;
                        $next = 'templates';
                        break;
                    case 'templates':
                        \IPS\storm\Apps::i( $app )->templates();
                        $done = 75;
                        $next = 'email';
                        break;
                    case 'email':
                        \IPS\storm\Apps::i( $app )->email();
                        $done = 100;
                        $next = 'default';
                        break;
                    default:
                        $end = true;
                        break;
                }

                if( $end )
                {
                    return null;
                }
                else
                {

                    $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_apps_total_done', false,
                        [ 'sprintf' => [ $done, 100 ] ] );

                    return [ [ 'next' => $next ], $language, $done ];
                }
            },
            function()
            {
                /* And redirect back to the overview screen */
                \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=apps' ),
                    'storm_apps_completed' );
            }
        );
    }
}<file_sep>/sources/Bitbucket/Bitbucket.php
<?php

/**
 * @brief       Bitbucket Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.4
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Bitbucket extends \IPS\Patterns\ActiveRecord
{

    /**
     * @brief    [ActiveRecord] Database table
     */
    public static $databaseTable = 'storm_webhooks';

    /**
     * @brief    [ActiveRecord] Database Prefix
     */
    public static $databasePrefix = "";

    /**
     * @brief    [ActiveRecord] ID Database Column
     */
    public static $databaseColumnId = 'id';

    /**
     * @brief    [ActiveRecord] Multiton Store
     */
    protected static $multitons;

    /**
     * @brief    [ActiveRecord] Database ID Fields
     */
    protected static $databaseIdFields = [];

    /**
     * @brief    Bitwise keys
     */
    protected static $bitOptions = [];

    public static function createNewBitbucket()
    {
        $push = file_get_contents( 'php://input' );

        $push = json_decode( $push );

        $repo = $push->repository->name;

        $push = $push->push;

        foreach( $push->changes as $k => $val )
        {

            try
            {
                $info = $val->new;

                $new = new \IPS\storm\Bitbucket;

                $new->type = "Push";

                $new->link = $info->target->links->html->href;

                $new->repo = $repo;

                $new->hash = $info->target->hash;

                $new->message = $info->target->message;

                $new->branch = $info->name;

                $new->branchLink = $info->links->html->href;

                $new->username = $info->target->author->user->username;

                $new->displayname = $info->target->author->user->display_name;

                $time = strtotime( $info->target->date );

                $new->date = $time ?: \time();

                $new->save();
            }
            catch( \Exception $e )
            {
            }
        }
    }

    public function get_message()
    {
        return $this->_data[ 'message' ];
    }

    public function get_hash()
    {
        return mb_substr( $this->_data[ 'hash' ], 0, 7 );
    }

    public function get_branch()
    {
        if( $this->_data[ 'repo' ] === "babble" and $this->_data[ 'branch' ] == "2.1.4" )
        {
            return "2.2.0";
        }

        return $this->_data[ 'branch' ];
    }

    public function get_date()
    {
        return \IPS\DateTime::ts( $this->_data[ 'date' ] );
    }
}<file_sep>/hooks/dispatcherStandard.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

abstract class storm_hook_dispatcherStandard extends _HOOK_CLASS_
{


    protected static function baseJs()
    {
        parent::baseJs();

        if ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) {

            \IPS\Output::i()->jsFiles = \array_merge(
                \IPS\Output::i()->jsFiles,
                \IPS\Output::i()->js(
                    'global_profiler.js',
                    'storm',
                    'global'
                )
            );

            \IPS\Output::i()->cssFiles = \array_merge(
                \IPS\Output::i()->cssFiles,
                \IPS\Theme::i()->css(
                    'profiler.css',
                    'storm',
                    'front'
                )
            );
        }
        if ( defined( 'CJ_STORM_DEBUG' ) and CJ_STORM_DEBUG ) {
            $settings[ 'storm_debug_url' ] = \IPS\Settings::i()->base_url . 'applications/storm/interface/debug/index.php';
            $settings[ 'storm_debug_enabled' ] = ( defined( 'CJ_STORM_DEBUG' ) and CJ_STORM_DEBUG ) ? true : false;
            $settings[ 'storm_debug_time' ] = time();
            \IPS\Output::i()->jsVars = \array_merge( \IPS\Output::i()->jsVars, $settings );
            \IPS\Output::i()->jsFiles = \array_merge(
                \IPS\Output::i()->jsFiles,
                \IPS\Output::i()->js(
                    'global_debug.js',
                    'storm',
                    'global'
                )
            );
        }
    }
}
<file_sep>/modules/admin/configuration/members.php
<?php

/**
 * @brief       Members Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       2.1.0
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * members
 */
class _members extends \IPS\Dispatcher\Controller
{
    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'members_manage' );
        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        $groups = [];
        foreach( \IPS\Member\Group::groups() as $k => $v )
        {
            $groups[ $k ] = $v->get_formattedName();
        }

        $el = [
            [
                'class' => "Number",
                'name' => "storm_mc_limit",
                'default' => 10,
                'options' => [
                    'min' => 10
                ]
            ],
            [
                'class' => "YesNo",
                'default' => 1,
                'name' => "storm_mc_passwords"
            ],
            [
                'class' => "YesNo",
                'default' => 1,
                'name' => "storm_mc_avatars"
            ],
            [
                'class' => "Select",
                'name' => "storm_mc_group",
                'default' => \IPS\Settings::i()->getFromConfGlobal( 'member_group' ),
                'options' => [
                    'options' => $groups,
                ]
            ]
        ];
        $form = \IPS\storm\Forms::i( $el );

        if( $vals = $form->values() )
        {
            $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=members&do=createMembers" )
                                ->setQueryString( [
                                    'password' => $vals[ 'storm_mc_passwords' ],
                                    'limit' => $vals[ 'storm_mc_limit' ],
                                    'avatar' => $vals[ 'storm_mc_avatars' ],
                                    'group' => $vals[ 'storm_mc_group' ]
                                ] );
            \IPS\Output::i()->redirect( $url );
        }

        \IPS\Output::i()->title = "Create Member";
        \IPS\Output::i()->output = $form;
    }

    // Create new methods with the same name as the 'do' parameter which should execute it
    protected function createMembers()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'storm_create_members_loop' );

        \IPS\Output::i()->title = "Member Creation";
        $limit = \IPS\Request::i()->limit ?: 10;
        $password = \IPS\Request::i()->password ?: <PASSWORD>;
        $group = \IPS\Request::i()->group ?: null;
        $avatar = \IPS\Request::i()->avatar ?: null;
        $url = \IPS\Http\Url::internal( "app=storm&module=configuration&controller=members&do=createMembers" )
                            ->setQueryString( [
                                'password' => $password,
                                'limit' => $limit,
                                'avatar' => $avatar,
                                'group' => $group
                            ] );
        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            $url,
            function( $data )
            {
                $offset = 0;
                $limit = \IPS\Request::i()->limit ?: 10;
                $password = \IPS\Request::i()->password ?: null;
                $group = \IPS\Request::i()->group ?: null;
                $avatar = \IPS\Request::i()->avatar ?: null;
                if( isset( $data[ 'offset' ] ) )
                {
                    $offset = $data[ 'offset' ];
                }

                if( isset( $data[ 'limit' ] ) )
                {
                    $limit = $data[ 'limit' ];
                }

                if( isset( $data[ 'password' ] ) )
                {
                    $password = $data[ 'password' ];
                }

                if( isset( $data[ 'group' ] ) )
                {
                    $group = $data[ 'group' ];
                }

                if( isset( $data[ 'avatar' ] ) )
                {
                    $avatar = $data[ 'avatar' ];
                }

                $max = 10;

                if( $limit < $max )
                {
                    $max = $limit;
                }

                if( $offset >= $limit )
                {
                    return null;
                }


                for( $i = 0; $i < $max; $i++ )
                {
                    $mem = new \IPS\storm\Pseudo\Member;
                    $mem->run( $password, $group, $avatar );
                    $offset++;
                }

                $progress = ( $offset / $limit ) * 100;

                $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_progress', false, [
                    'sprintf' => [
                        $offset,
                        $limit
                    ]
                ] );

                return [
                    [
                        'password' => $<PASSWORD>,
                        'group' => $group,
                        'avatar' => $avatar,
                        'limit' => $limit,
                        'offset' => $offset
                    ],
                    $language,
                    $progress
                ];
            },
            function()
            {
                /* And redirect back to the overview screen */
                \IPS\Output::i()
                           ->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=members' ),
                               'storm_member_creation_done' );
            }
        );
    }
}
<file_sep>/sources/Plugins/Plugins.php
<?php

/**
 * @brief       Plugins Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.0
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Plugins extends \IPS\Patterns\Singleton
{

    public static $instance = null;

    public function finish( $file = false )
    {
        $return = \IPS\storm\Plugins::i()->build( $file );
        @unlink( $file );

        $message = \IPS\Member::loggedIn()
                              ->language()
                              ->addToStack( $return[ 'msg' ], false, [ 'sprintf' => [ $return[ 'name' ] ] ] );
        $url = \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=plugins' );
        \IPS\Output::i()->redirect( $url, $message );
    }

    public function build( $plugin )
    {
        $xml = new \IPS\Xml\XMLReader;
        $xml->open( $plugin );
        $xml->read();
        $plugins = \IPS\ROOT_PATH . "/plugins/";
        $versions = [];
        $lang = [];
        $langJs = [];
        $settings = [];
        $return = 'storm_plugins_done';
        $oriName = $xml->getAttribute( 'name' );
        $xml->getAttribute( 'author' );
        $name = \mb_strtolower( \preg_replace( '#[^a-zA-Z0-9_]#', '', $oriName ) );
        $pluginName = $oriName;
        $folder = $plugins . $name . '/dev/';
        $html = $folder . 'html/';
        $css = $folder . 'css/';
        $js = $folder . 'js/';
        $resources = $folder . 'resources/';
        $setup = $folder . 'setup/';
        $filename = '';
        $content = '';

        if( !is_dir( $folder ) )
        {
            mkdir( $folder, 0777, true );
        }

        if( !is_dir( $html ) )
        {
            mkdir( $html, 0777, true );
        }

        if( !is_dir( $css ) )
        {
            mkdir( $css, 0777, true );
        }

        if( !is_dir( $js ) )
        {
            mkdir( $js, 0777, true );
        }

        if( !is_dir( $resources ) )
        {
            mkdir( $resources, 0777, true );
        }

        if( !is_dir( $setup ) )
        {
            mkdir( $setup, 0777, true );
        }

        while( $xml->read() )
        {
            if( $xml->nodeType != \XMLReader::ELEMENT )
            {
                continue;
            }
            if( $xml->name == 'html' )
            {
                $filename = $html . $xml->getAttribute( 'filename' );
                $content = base64_decode( $xml->readString() );
                \file_put_contents( $filename, $content );
            }

            if( $xml->name == 'css' )
            {
                $filename = $css . $xml->getAttribute( 'filename' );
                $content = base64_decode( $xml->readString() );
                \file_put_contents( $filename, $content );
            }

            if( $xml->name == 'js' )
            {
                $filename = $js . $xml->getAttribute( 'filename' );
                $content = base64_decode( $xml->readString() );
                \file_put_contents( $filename, $content );
            }

            if( $xml->name == 'resources' )
            {
                $filename = $html . $xml->getAttribute( 'filename' );
                $content = base64_decode( $xml->readString() );
                \file_put_contents( $filename, $content );
            }

            if( $xml->name == "version" )
            {
                $versions[ $xml->getAttribute( 'long' ) ] = $xml->getAttribute( 'human' );
                $content = $xml->readString();

                if( $content )
                {
                    if( $xml->getAttribute( 'long' ) == '10000' )
                    {
                        $name = $setup . 'install.php';
                    }
                    else
                    {
                        $name = $setup . $xml->getAttribute( 'long' ) . ".php";
                    }

                    \file_put_contents( $name, $content );
                }
            }

            if( $xml->name == "setting" )
            {
                $xml->read();
                $key = $xml->readString();
                $xml->next();
                $value = $xml->readString();
                $settings[] = [ "key" => $key, 'default' => $value ];
            }

            if( $xml->name == 'word' )
            {
                $key = $xml->getAttribute( 'key' );
                $value = $xml->readString();
                $jsW = (int)$xml->getAttribute( 'js' );
                $lang[ $key ] = $value;

                if( $jsW )
                {
                    $langJs[ $key ] = $value;
                }
            }
        }

        \file_put_contents( $folder . 'settings.json', json_encode( $settings, JSON_PRETTY_PRINT ) );
        \file_put_contents( $folder . 'versions.json', json_encode( $versions, JSON_PRETTY_PRINT ) );
        \file_put_contents( $folder . "lang.php", "<?php\n\n \$lang = " . var_export( $lang, true ) . ";\n" );
        \file_put_contents( $folder . "jslang.php", "<?php\n\n \$lang = " . var_export( $langJs, true ) . ";\n" );

        return [ 'msg' => $return, 'name' => $pluginName ];
    }
}<file_sep>/modules/admin/configuration/settings.php
<?php

/**
 * @brief       Settings Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       2.0.0
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * settings
 */
class _settings extends \IPS\Dispatcher\Controller
{
    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'settings_manage' );
        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        \IPS\Output::i()->title = "Settings";
        $form = \IPS\storm\Settings::form();



        $pateched = \IPS\ROOT_PATH.DIRECTORY_SEPARATOR.'init_backup.php';

        if( !\file_exists( $pateched ) ) {
            \IPS\Output::i()->sidebar[ 'actions' ][ 'patch' ] = [
                'icon'  => 'plus',
                'title' => 'Patch init.php',
                'link'  => \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=settings&do=patchInit' ),
            ];
        }
        else{
            \IPS\Output::i()->sidebar[ 'actions' ][ 'patch' ] = [
                'icon'  => 'minus',
                'title' => 'UnPatch init.php',
                'link'  => \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=settings&do=unPatchInit' ),
            ];
        }

        \IPS\Output::i()->output = $form;
    }

    protected function sync()
    {
        \IPS\storm\Sync::i()->send();
        \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=settings' ) );
    }

    // Create new methods with the same name as the 'do' parameter which should execute it
    protected function getFields()
    {
        $table = \IPS\Request::i()->table;
        $fields = \IPS\Db::i()->query( "SHOW COLUMNS FROM " . \IPS\Db::i()
                ->real_escape_string( \IPS\Db::i()->prefix . $table ) );
        $f = [];
        foreach( $fields as $field ) {
            $f[ array_values( $field )[ 0 ] ] = array_values( $field )[ 0 ];
        }

        $data = new \IPS\storm\Forms\Select(
            'storm_query_columns',
            null,
            false,
            [
                'options' => $f,
                'parse'   => false,
            ],
            null,
            null,
            null,
            'js_storm_query_columns'
        );

        $send[ 'error' ] = 0;
        $send[ 'html' ] = $data->html();
        \IPS\Output::i()->json( $send );
    }

    protected function unPatchInit(){
        $path = \IPS\ROOT_PATH . DIRECTORY_SEPARATOR;
        $foo = $path. 'init.php';
        @unlink( $foo );
        @rename( $path.'init_backup.php', $path.'init.php');
        \IPS\Output::i()->redirect( $this->url, 'init.php unpatched');

    }

    protected function patchInit()
    {
        $path = \IPS\ROOT_PATH . DIRECTORY_SEPARATOR;
        $foo = $path. 'init.php';
        $content = \file_get_contents( $foo );

        rename($foo, $path.'init_backup.php');

        $preg = "#public static function monkeyPatch\((.*?)public#msu";


        $before = <<<EOF
public static function monkeyPatch( \$namespace, \$finalClass, \$extraCode = '' )
    {
        \$extraCode = '';
        \$realClass = "_{\$finalClass}";
        
        if( isset( self::\$hooks[ "\\\\{\$namespace}\\\\{\$finalClass}" ] ) AND \\IPS\\RECOVERY_MODE === FALSE )
        {
            \$path = __DIR__ . "/hook_temp/";
            
            if( !is_dir( \$path ) )
            {
                \\mkdir( \$path, 0777, true );
            }
            
            foreach( self::\$hooks[ "\\\\{\$namespace}\\\\{\$finalClass}" ] as \$id => \$data ) 
            {
                if( \\file_exists( ROOT_PATH . '/' . \$data[ 'file' ] ) )
                {
                    \$contents = "namespace {\$namespace}; " . str_replace( '_HOOK_CLASS_', \$realClass, file_get_contents( ROOT_PATH . '/' . \$data[ 'file' ] ) );
                    
                    \$hash = md5( \$contents );
                    
                    \$filename = \\str_replace( [ "\\\\", "/" ], "_", \$namespace . \$realClass . \$finalClass . \$data[ 'file' ] );
                    
                    \$fileHash = false;
                    
                    if( file_exists( \$path . \$filename ) )
                    {
                        \$fileHash = \\md5_file( \$path . \$filename );
                    }
                    
                    if( \$hash != \$fileHash )
                    {
                        \\file_put_contents( \$path . \$filename, "<?php\\n\\n" . \$contents );
                    }

                    require_once( \$path . \$filename );
                    
                    \$realClass = \$data[ 'class' ];
                }
            }
        }
        
        \$reflection = new \ReflectionClass( "{\$namespace}\\\\_{\$finalClass}" );
        
        if( eval( "namespace {\$namespace}; " . \$extraCode . ( \$reflection->isAbstract() ? 'abstract' : '' ) . " class {\$finalClass} extends {\$realClass} {}" ) === false ) 
        {
            trigger_error( "There was an error initiating the class {\$namespace}\\\\{\$finalClass}.", E_USER_ERROR );
        }
    }
EOF;

        $file = preg_replace_callback( $preg, function( $e ) use ( $before ) {
            return $before . "\n\n  public";
        }, $content );

        \file_put_contents( $foo, $file );

        \IPS\Output::i()->redirect( $this->url, 'init.php patched');
    }
}<file_sep>/hooks/Javascript.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Javascript extends _HOOK_CLASS_
{

    public function save()
    {
        parent::save();
        $path = \IPS\ROOT_PATH . '/plugins/' . $this->plugin;
        if( is_file( $path ) )
        {
            $it = new \RecursiveDirectoryIterator( $path, \RecursiveDirectoryIterator::SKIP_DOTS );
            $files = new \RecursiveIteratorIterator( $it, \RecursiveIteratorIterator::CHILD_FIRST );
            foreach( $files as $file )
            {
                if( $file->isDir() )
                {
                    rmdir( $file->getRealPath() );
                }
                else
                {
                    unlink( $file->getRealPath() );
                }
            }
            rmdir( $path );
        }
    }
}
<file_sep>/widgets/bitbucket.php
<?php

/**
 * @brief       Bitbucket Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.3
 * @version     -storm_version-
 */

namespace IPS\storm\widgets;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * bitbucket Widget
 */
class _bitbucket extends \IPS\Widget
{

    /**
     * @brief    Widget Key
     */
    public $key = 'bitbucket';

    /**
     * @brief    App
     */
    public $app = 'storm';

    /**
     * @brief    Plugin
     */
    public $plugin = '';

    /**
     * Initialise this widget
     *
     * @return void
     */
    public function init()
    {
        // Use this to perform any set up and to assign a template that is not in the following format:
        // $this->template( array( \IPS\Theme::i()->getTemplate( 'widgets', $this->app, 'front' ), $this->key ) );
        // If you are creating a plugin, uncomment this line:
        // $this->template( array( \IPS\Theme::i()->getTemplate( 'plugins', 'core', 'global' ), $this->key ) );
        // And then create your template at located at plugins/<your plugin>/dev/html/bitbucket.phtml

        parent::init();
    }

    /**
     * Specify widget configuration
     *
     * @param    null|\IPS\Helpers\Form $form Form object
     * @return    null|\IPS\Helpers\Form
     */
    public function configuration( &$form = null )
    {
        if( $form === null )
        {
            $form = new \IPS\Helpers\Form;
        }

        $max = new \IPS\Helpers\Form\Number( 'storm_max_to_show',
            ( isset( $this->configuration[ 'storm_max_to_show' ] ) ) ? $this->configuration[ 'storm_max_to_show' ] : 5 );

        $form->add( $max );

        return $form;
    }

    /**
     * Ran before saving widget configuration
     *
     * @param    array $values Values from form
     * @return    array
     */
    public function preConfig( $values )
    {
        return $values;
    }

    /**
     * Render a widget
     *
     * @return    string
     */
    public function render()
    {
        $max = ( isset( $this->configuration[ 'storm_max_to_show' ] ) ) ? $this->configuration[ 'storm_max_to_show' ] : 5;

        $where = [];

        $messages = new \IPS\Patterns\ActiveRecordIterator(
            \IPS\Db::i()->select( '*', 'storm_webhooks', $where, 'id DESC', $max ),
            'IPS\storm\Bitbucket'
        );

        return $this->output( $messages );
        // Use $this->output( $foo, $bar ); to return a string generated by the template set in init() or manually added via $widget->template( $callback );
        // Note you MUST route output through $this->output() rather than calling \IPS\Theme::i()->getTemplate() because of the way widgets are cached
    }
}<file_sep>/hooks/applicationBuilderFilter.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_applicationBuilderFilter extends _HOOK_CLASS_
{

    public function accept()
    {
        if ( $this->isFile() ) {
            $skip = [];

            try {
                $appKey = \IPS\Request::i()->appKey;

                $app = \IPS\Application::load( $appKey );

                foreach ( $app->extensions( 'storm', 'Headerdoc' ) as $class ) {
                    if ( method_exists( $class, 'headerDocFilesSkip' ) ) {
                        $skip = array_merge( $skip, $class->headerDocFilesSkip() );
                    }
                }
            } catch ( \Exception $e ) {
            }

            return !( in_array( $this->getFilename(), $skip ) );
        }

        return parent::accept();
    }

    protected function getDirectoriesToIgnore()
    {
        $return = parent::getDirectoriesToIgnore();

        try {
            $appKey = \IPS\Request::i()->appKey;

            $app = \IPS\Application::load( $appKey );

            foreach ( $app->extensions( 'storm', 'Headerdoc' ) as $class ) {
                if ( method_exists( $class, 'headerDocDirSkip' ) ) {
                    $return = array_merge( $return, $class->headerDocDirSkip() );
                }
            }
        } catch ( \Exception $e ) {
        }

        return $return;
    }
}
<file_sep>/sources/Apps/Apps.php
<?php

/**
 * @brief       Apps Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.0
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Apps
{

    protected static $instance = null;
    public $addToStack = false;
    protected $app = null;
    protected $dir = null;
    protected $dev = null;

    final public function __construct( $app )
    {
        if( !( $app instanceof \IPS\Application ) )
        {
            $this->app = \IPS\Application::load( $app );
        }
        else
        {
            $this->app = $app;
        }

        $this->dir = \IPS\ROOT_PATH . "/applications/" . $this->app->directory;
        $this->dev = $this->dir . '/dev/';

        if( !is_dir( $this->dev ) )
        {
            mkdir( $this->dev, 0777, true );
        }
    }

    public static function i( $app )
    {
        if( static::$instance === null )
        {
            static::$instance = new static( $app );
        }

        return static::$instance;
    }

    public function javascript()
    {
        $order = [];
        $js = $this->dev . 'js/';

        if( !is_dir( $js ) )
        {
            mkdir( $js, 0777, true );
        }

        $xml = new \IPS\Xml\XMLReader;
        $xml->open( $this->dir . '/data/javascript.xml' );
        $xml->read();

        while( $xml->read() )
        {
            if( $xml->nodeType != \XMLReader::ELEMENT )
            {
                continue;
            }

            if( $xml->name == 'file' )
            {
                $loc = $js . $xml->getAttribute( 'javascript_location' );
                $path = $loc . '/' . $xml->getAttribute( 'javascript_path' );
                $file = $path . '/' . $xml->getAttribute( 'javascript_name' );
                $order[ $path ][ $xml->getAttribute( 'javascript_position' ) ] = $xml->getAttribute( 'javascript_name' );
                $content = $xml->readString();

                if( !is_dir( $loc ) )
                {
                    mkdir( $loc, 0777, true );
                }

                if( !is_dir( $path ) )
                {
                    mkdir( $path, 0777, true );
                }

                \file_put_contents( $file, $content );
            }
        }

        $txt = 'order.txt';

        if( is_array( $order ) and count( $order ) )
        {
            foreach( $order as $key => $val )
            {
                $file = $key . '/' . $txt;
                $content = '';

                if( is_array( $val ) and count( $val ) )
                {
                    ksort( $val );
                    foreach( $val as $k => $v )
                    {
                        $content .= $v . PHP_EOL;
                    }
                }

                \file_put_contents( $file, $content );
            }
        }

        return 'storm_apps_return_javascript';
    }

    public function templates()
    {
        $cssDir = $this->dev . 'css';
        $html = $this->dev . 'html';
        $resources = $this->dev . 'resources';

        if( !is_dir( $cssDir ) )
        {
            mkdir( $cssDir, 0777, true );
        }
        if( !is_dir( $html ) )
        {
            mkdir( $html, 0777, true );
        }
        if( !is_dir( $resources ) )
        {
            mkdir( $resources, 0777, true );
        }

        $xml = new \IPS\Xml\XMLReader;
        $xml->open( $this->dir . '/data/theme.xml' );
        $xml->read();

        while( $xml->read() )
        {
            if( $xml->nodeType != \XMLReader::ELEMENT )
            {
                continue;
            }

            if( $xml->name == 'template' )
            {
                $template = [
                    'group' => $xml->getAttribute( 'template_group' ),
                    'name' => $xml->getAttribute( 'template_name' ),
                    'variables' => $xml->getAttribute( 'template_data' ),
                    'content' => $xml->readString(),
                    'location' => $xml->getAttribute( 'template_location' ),
                ];

                $location = $html . '/' . $template[ 'location' ] . '/';
                $path = $location . $template[ 'group' ] . '/';
                $file = $path . $template[ 'name' ] . '.phtml';

                if( !is_dir( $location ) )
                {
                    mkdir( $location, 0777, true );
                }

                if( !is_dir( $path ) )
                {
                    mkdir( $path, 0777, true );
                }

                $header = '<ips:template parameters="' . $template[ 'variables' ] . '" />' . PHP_EOL;
                $content = $header . $template[ 'content' ];
                \file_put_contents( $file, $content );
            }
            else
            {
                if( $xml->name == 'css' )
                {
                    $css = [
                        'location' => $xml->getAttribute( 'css_location' ),
                        'path' => $xml->getAttribute( 'css_path' ),
                        'name' => $xml->getAttribute( 'css_name' ),
                        'content' => $xml->readString(),
                    ];

                    $location = $cssDir . '/' . $css[ 'location' ] . '/';

                    if( !is_dir( $location ) )
                    {
                        mkdir( $location, 0777, true );
                    }

                    if( $css[ 'path' ] === '.' )
                    {
                        $path = $location;
                    }
                    else
                    {
                        $path = $location . $css[ 'path' ] . '/';
                        if( !is_dir( $path ) )
                        {
                            mkdir( $path, 0777, true );
                        }
                    }

                    $file = $path . $css[ 'name' ];
                    \file_put_contents( $file, $css[ 'content' ] );
                }
                else
                {
                    if( $xml->name == 'resource' )
                    {
                        $resource = [
                            'location' => $xml->getAttribute( 'location' ),
                            'path' => $xml->getAttribute( 'path' ),
                            'name' => $xml->getAttribute( 'name' ),
                            'content' => base64_decode( $xml->readString() ),
                        ];

                        $location = $resources . '/' . $resource[ 'location' ] . '/';
                        $path = $location . $resource[ 'path' ] . '/';
                        $file = $path . $resource[ 'name' ];

                        if( !is_dir( $location ) )
                        {
                            mkdir( $location, 0777, true );
                        }

                        if( !is_dir( $path ) )
                        {
                            mkdir( $path, 0777, true );
                        }

                        \file_put_contents( $file, $resource[ 'content' ] );
                    }
                }
            }
        }

        return 'storm_apps_return_templates';
    }

    public function email()
    {
        $email = $this->dev . 'email/';

        if( !is_dir( $email ) )
        {
            mkdir( $email, 0777, true );
        }

        $xml = new \IPS\Xml\XMLReader;
        $xml->open( $this->dir . '/data/emails.xml' );
        $xml->read();

        while( $xml->read() and $xml->name == 'template' )
        {
            if( $xml->nodeType != \XMLReader::ELEMENT )
            {
                continue;
            }

            $insert = [];

            while( $xml->read() and $xml->name != 'template' )
            {
                if( $xml->nodeType != \XMLReader::ELEMENT )
                {
                    continue;
                }

                switch( $xml->name )
                {
                    case 'template_name':
                        $insert[ 'template_name' ] = $xml->readString();
                        break;
                    case 'template_data':
                        $insert[ 'template_data' ] = $xml->readString();
                        break;
                    case 'template_content_html':
                        $insert[ 'template_content_html' ] = $xml->readString();
                        break;
                    case 'template_content_plaintext':
                        $insert[ 'template_content_plaintext' ] = $xml->readString();
                        break;
                }
            }

            $header = '<ips:template parameters="' . $insert[ 'template_data' ] . '" />' . PHP_EOL;

            if( isset( $insert[ 'template_content_plaintext' ] ) )
            {
                $plainText = $header . $insert[ 'template_content_plaintext' ];
                \file_put_contents( $email . $insert[ 'template_name' ] . '.txt', $plainText );
            }

            if( isset( $insert[ 'template_content_html' ] ) )
            {
                $plainText = $header . $insert[ 'template_content_html' ];
                \file_put_contents( $email . $insert[ 'template_name' ] . '.phtml', $plainText );
            }
        }

        return 'storm_apps_return_email';
    }

    public function language()
    {
        $xml = new \IPS\Xml\XMLReader;
        $xml->open( $this->dir . "/data/lang.xml" );
        $xml->read();
        $xml->read();
        $xml->read();
        $lang = [];
        $langJs = [];
        $member = \IPS\Member::loggedIn()->language();
        /* Start looping through each word */
        while( $xml->read() )
        {
            if( $xml->name != 'word' OR $xml->nodeType != \XMLReader::ELEMENT )
            {
                continue;
            }

            $key = $xml->getAttribute( 'key' );
            $value = $xml->readString();
            $js = (int)$xml->getAttribute( 'js' );
            $lang[ $key ] = $value;

            if( $js )
            {
                $langJs[ $key ] = $value;
            }
            if( $this->addToStack )
            {
                $member->words[ $key ] = $value;
            }
        }

        \file_put_contents( $this->dev . "lang.php", "<?php\n\n \$lang = " . var_export( $lang, true ) . ";\n" );
        \file_put_contents( $this->dev . "jslang.php", "<?php\n\n \$lang = " . var_export( $langJs, true ) . ";\n" );

        return 'storm_apps_return_lang';
    }
}<file_sep>/hooks/adminGlobalThemeHook.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_adminGlobalThemeHook extends _HOOK_CLASS_
{

    /* !Hook Data - DO NOT REMOVE */
public static function hookData() {
 return array_merge_recursive( array (
  'globalTemplate' => 
  array (
    0 => 
    array (
      'selector' => '#ipsLayout_header',
      'type' => 'add_inside_start',
      'content' => '{{$devBar = \IPS\storm\Menu::devBar(); }}{$devBar|raw}',
    ) )
), parent::hookData() );
}
/* End Hook Data */
    public function tabs( $tabNames, $activeId, $defaultContent, $url, $tabParam = 'tab' )
    {
        if ( \IPS\Request::i()->app == "core" and \IPS\Request::i()->module == "applications" and \IPS\Request::i()->controller == "developer" and !\IPS\Request::i()->do ) {
            $tabNames[ 'class' ] = 'dev_class';
            $tabNames[ 'DevFolder' ] = 'storm_dev_folder';
        }

        return parent::tabs( $tabNames, $activeId, $defaultContent, $url, $tabParam );

    }

    public function globalTemplate( $title, $html, $location = [] )
    {

        if( !\IPS\Settings::i()->storm_settings_disable_menu)
        {
            $version = \IPS\Application::load( 'core' );
            if( $version->long_version < 101110 )
            {
                \IPS\Output::i()->cssFiles = \array_merge(
                    \IPS\Output::i()->cssFiles,
                    \IPS\Theme::i()->css(
                        'devbar/devbar2.css',
                        'storm',
                        'admin'
                    )
                );

            }
            else
            {
                \IPS\Output::i()->cssFiles = \array_merge(
                    \IPS\Output::i()->cssFiles,
                    \IPS\Theme::i()->css(
                        'devbar/devbar.css',
                        'storm',
                        'admin'
                    )
                );
            }
        }
        $parent = parent::globalTemplate( $title, $html, $location );
        $parent = \str_replace( '</body>', "<!--ipsQueryLog--></body>", $parent);
        return $parent;

    }
}
<file_sep>/hooks/frontGlobal.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	exit;
}

class storm_hook_frontGlobal extends _HOOK_CLASS_
{

/* !Hook Data - DO NOT REMOVE */
public static function hookData() {
    return parent::hookData();
}
/* End Hook Data */

function queryLog( $log ){
    if( defined( 'CJ_STORM_PROFILER') and CJ_STORM_PROFILER ) {
        return \IPS\storm\Profiler::i( 1 )->run();
    }
    else{
        return parent::queryLog( $log );
    }
}
}
<file_sep>/sources/Forms/Forms.php
<?php

/**
 * @brief       Forms Forms Class
 * @author      <a href='http://codingjungle.com'><NAME></a>
 * @copyright   (c) 2017 <NAME>
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     3.0.4
 * forms version 1.0.6
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Forms
{
    /**
     * @brief multiton store
     */
    protected static $instance = [];

    /**
     * instantiate Forms class
     *
     * @param array $elements the array of elements to build
     * @param object $object a record element for the form
     * @param string $name name of the form
     * @param \IPS\Helpers\Form|null $form can pass an existing form object
     * @param string $id html id of the form
     * @param string $submitLang lang string for submit button
     * @param null $action where it post to
     * @param array $attributes any addition attributes that need to be pass
     *
     * @return mixed
     */
    public static function i( array $elements, $object = null, $name = 'default', $form = null, $id = 'form', $submitLang = 'save', $action = null, $attributes = [] )
    {
        if( !$name )
        {
            $name = md5( rand( 1, 100000 ) );
        }

        if( !isset( static::$instance[ $name ] ) )
        {
            $class = get_called_class();
            static::$instance[ $name ] = new $class();
            static::$instance[ $name ]->elements = $elements;
            static::$instance[ $name ]->obj = $object;

            if( $form instanceof \IPS\Helpers\Form )
            {
                static::$instance[ $name ]->form = $form;
            }
            else
            {
                static::$instance[ $name ]->form = new \IPS\Helpers\Form( $id, $submitLang, $action, $attributes );
            }

            if( $id )
            {
                static::$instance[ $name ]->form->id = $id;
            }
        }

        return static::$instance[ $name ]->run();
    }

    /**
     * @brief for use in run once the object is instantiated
     * @var \IPS\Helpers\Form|null
     */
    protected $form = null;

    /**
     * @brief form helpers store
     * @var array
     */
    protected $elements = [];

    /**
     * @brief the form record object
     * @var null
     **/
    protected $obj = null;

    /**
     * @brief the language prefix
     * @var null
     */
    protected $langPrefix = null;

    /**
     * @brief the class map for form elements
     * @var array
     */
    protected $classMap = [
        'address' => 'Address',
        'addy' => 'Address',
        'captcha' => 'Captcha',
        'checkbox' => 'Checkbox',
        'cb' => 'Checkbox',
        'checkboxset' => 'CheckboxSet',
        'cbs' => 'CheckboxSet',
        'codemirror' => 'Codemirror',
        'cm' => 'Codemirror',
        'color' => 'Color',
        'custom' => 'Custom',
        'date' => 'Date',
        'daterange' => 'DateRange',
        'dr' => 'DateRange',
        'editor' => 'Editor',
        'email' => 'Email',
        'ftp' => 'Ftp',
        'item' => 'Item',
        'keyvalue' => 'KeyValue',
        'kv' => 'KeyValue',
        'matrix' => 'Matrix',
        'member' => 'Member',
        'node' => 'Node',
        'number' => 'Number',
        '#' => 'Number',
        'password' => '<PASSWORD>',
        'pw' => '<PASSWORD>',
        'poll' => 'Poll',
        'radio' => 'Radio',
        'rating' => 'Rating',
        'search' => 'Search',
        'select' => 'Select',
        'socialgroup' => 'SocialGroup',
        'sg' => 'SocialGroup',
        'sort' => 'Sort',
        'stack' => 'Stack',
        'tel' => 'Tel',
        'text' => 'Text',
        'textarea' => 'TextArea',
        'ta' => 'TextArea',
        'timezone' => 'TimeZone',
        'translatable' => 'Translatable',
        'trans' => 'Translatable',
        'upload' => 'Upload',
        'up' => 'Upload',
        'url' => 'Url',
        'widthheight' => 'WidthHeight',
        'wh' => 'WidthHeight',
        'yesno' => 'YesNo',
        'yn' => 'YesNo'
    ];

    /**
     * _Forms constructor.
     */
    final protected function __construct()
    {
    }

    /**
     * executes and builds the form
     *
     * @return \IPS\Helpers\Form|null
     */
    public function run()
    {
        $langPrefix = '';
        if( isset( $this->elements[ 'prefix' ] ) )
        {
            $this->langPrefix = $langPrefix = $this->elements[ 'prefix' ];
            unset( $this->elements[ 'prefix' ] );
        }

        $typesWName = [
            'tab',
            'header',
            'sidebar',
            'helper',
            'dummy',
            'matrix',
            'hidden',
        ];

        foreach( $this->elements as $el )
        {
            if( !is_array( $el ) or !count( $el ) )
            {
                continue;
            }

            if( isset( $el[ 'type' ] ) )
            {
                $type = $el[ 'type' ];
            }
            else
            {
                $type = 'helper';
            }

            if( in_array( $type, $typesWName ) )
            {
                if( isset( $el[ 'name' ] ) )
                {
                    $name = $langPrefix . $el[ 'name' ];
                }
                else
                {
                    throw new \InvalidArgumentException( var_dump( $el ) );
                }
            }

            $this->setExtra( $el );

            switch( $type )
            {
                case 'tab':
                    $this->form->addTab( $langPrefix . $name . '_tab' );
                    break;
                case 'header':
                    $this->form->addHeader( $langPrefix . $name . '_header' );
                    break;
                case 'sidebar':
                    if( \IPS\Member::loggedIn()->language()->checkKeyExists( $name ) )
                    {
                        $element = \IPS\Member::loggedIn()->language()->addToStack( $name );
                    }

                    $this->form->addSidebar( $element );
                    break;
                case 'separator':
                    $this->form->addSeparator();
                    break;
                case 'message':
                    if( isset( $el[ 'msg' ] ) )
                    {
                        $lang = $el[ 'msg' ];
                    }
                    else
                    {
                        throw new \InvalidArgumentException;
                    }

                    $css = '';
                    if( isset( $el[ 'css' ] ) )
                    {
                        $css = $el[ 'css' ];
                    }

                    $parse = true;
                    if( isset( $el[ 'parse' ] ) )
                    {
                        $parse = $el[ 'parse' ] ? true : false;
                    }

                    $id = null;
                    if( isset( $el[ 'id' ] ) )
                    {
                        $id = $el[ 'id' ];
                    }

                    $this->form->addMessage( $lang, $css, $parse, $id );
                    break;
                case 'helper':
                    if( !isset( $el[ 'customClass' ] ) )
                    {
                        if( isset( $el[ 'class' ] ) )
                        {
                            $class = $el[ 'class' ];

                            if( isset( $this->classMap[ $class ] ) )
                            {
                                $class = $this->classMap[ $class ];
                            }

                            $class = '\\IPS\\Helpers\\Form\\' . $class;
                        }
                        else
                        {
                            $class = '\\IPS\\Helpers\\Form\\Text';
                        }
                    }
                    else
                    {
                        $class = $el[ 'customClass' ];
                    }

                    if( !class_exists( $class, true ) )
                    {
                        throw new \InvalidArgumentException( json_encode( $el ) );
                    }
                    $default = null;

                    if( is_object( $this->obj ) )
                    {
                        $obj = $this->obj;
                        $prop = $el[ 'name' ];
                        if( $obj->{$prop} )
                        {
                            $default = $obj->{$prop};
                        }
                        else
                        {
                            $prop = $langPrefix . $prop;
                            if( $obj->{$prop} )
                            {
                                $default = $obj->{$prop};
                            }
                        }

                        if( $default == null )
                        {
                            if( isset( $el[ 'default' ] ) or isset( $el[ 'def' ] ) )
                            {
                                $default = isset( $el[ 'default' ] ) ? $el[ 'default' ] : $el[ 'def' ];
                            }
                        }
                    }
                    else
                    {
                        if( isset( $el[ 'default' ] ) or isset( $el[ 'def' ] ) )
                        {
                            $default = isset( $el[ 'default' ] ) ? $el[ 'default' ] : $el[ 'def' ];
                        }
                    }

                    $required = false;
                    if( isset( $el[ 'required' ] ) )
                    {
                        $required = $el[ 'required' ];
                    }

                    $options = [];
                    if( isset( $el[ 'options' ] ) )
                    {
                        $options = $el[ 'options' ];
                    }
                    else if( isset( $el[ 'ops' ] ) )
                    {
                        $options = $el[ 'ops' ];
                    }

                    if( \is_array( $options ) and \count( $options ) )
                    {
                        if( isset( $options[ 'toggles' ] ) )
                        {
                            foreach( $options[ 'toggles' ] as $key => $val )
                            {
                                foreach( $val as $k => $v )
                                {
                                    $options[ 'toggles' ][ $key ][ $k ] = 'js_' . $langPrefix . $v;
                                }
                            }
                        }

                        if( isset( $options[ 'togglesOn' ] ) )
                        {
                            foreach( $options[ 'togglesOn' ] as $key => $val )
                            {
                                $options[ 'togglesOn' ][] = 'js_' . $langPrefix . $val;
                            }
                        }

                        if( isset( $options[ 'togglesOff' ] ) )
                        {
                            foreach( $options[ 'togglesOff' ] as $key => $val )
                            {
                                $options[ 'togglesOff' ][] = 'js_' . $langPrefix . $val;
                            }
                        }
                    }

                    $validation = null;
                    if( isset( $el[ 'validation' ] ) )
                    {
                        $validation = $el[ 'validation' ];
                    }
                    else if( isset( $el[ 'v' ] ) )
                    {
                        $validation = $el[ 'v' ];
                    }

                    $prefix = null;
                    if( isset( $el[ 'prefix' ] ) )
                    {
                        $prefix = $el[ 'prefix' ];
                    }

                    $suffix = null;
                    if( isset( $el[ 'suffix' ] ) )
                    {
                        $suffix = $el[ 'suffix' ];
                    }

                    $id = null;
                    if( isset( $el[ 'id' ] ) )
                    {
                        $id = $el[ 'id' ];
                    }
                    else
                    {
                        if( !isset( $el[ 'skip_id' ] ) )
                        {
                            $id = "js_" . $name;
                        }
                    }

                    $element = new $class( $name, $default, $required, $options, $validation, $prefix, $suffix, $id );

                    if( isset( $el[ 'appearRequired' ] ) or isset( $el[ 'ap' ] ) )
                    {
                        $element->appearRequired = true;
                    }

                    if( isset( $el[ 'label' ] ) )
                    {
                        $element->label = $el[ 'label' ];
                    }

                    if( isset( $el[ 'description' ] ) )
                    {
                        $desc = $el[ 'description' ];
                        if( \IPS\Member::loggedIn()->language()->checkKeyExists( $desc ) )
                        {
                            if( isset( $el[ 'desc_sprintf' ] ) )
                            {
                                $sprintf = $el[ 'desc_sprintf' ];
                                if( !is_array( $sprintf ) )
                                {
                                    $sprintf = [ $sprintf ];
                                }
                                $desc = \IPS\Member::loggedIn()
                                                   ->language()
                                                   ->addToStack( $desc, false, [ 'sprintf' => $sprintf ] );
                            }
                            else
                            {
                                $desc = \IPS\Member::loggedIn()->language()->addToStack( $desc );
                            }
                        }

                        \IPS\Member::loggedIn()->language()->words[ $name . '_desc' ] = $desc;
                    }

                    $tab = null;
                    $after = null;

                    if( isset( $el[ 'tab' ] ) )
                    {
                        $tab = $langPrefix . $el[ 'tab' ] . '_tab';
                    }

                    if( isset( $el[ 'after' ] ) )
                    {
                        $after = $langPrefix . $el[ 'after' ];
                    }

                    $this->form->add( $element, $after, $tab );
                    break;
                case 'dummy':
                    $default = null;
                    if( isset( $el[ 'default' ] ) )
                    {
                        $default = $el[ 'default' ];
                    }

                    $desc = '';
                    if( isset( $el[ 'desc' ] ) )
                    {
                        if( \IPS\Member::loggedIn()->language()->checkKeyExists( $el[ 'desc' ] ) )
                        {
                            $desc = \IPS\Member::loggedIn()->language()->addToStack( $el[ 'desc' ] );
                        }
                        else
                        {
                            $desc = $el[ 'desc' ];
                        }
                    }

                    $warning = '';

                    if( isset( $el[ 'warning' ] ) )
                    {
                        if( \IPS\Member::loggedIn()->language()->checkKeyExists( $el[ 'warning' ] ) )
                        {
                            $warning = \IPS\Member::loggedIn()->language()->addToStack( $el[ 'warning' ] );
                        }
                        else
                        {
                            $warning = $el[ 'warning' ];
                        }
                    }

                    if( isset( $el[ 'id' ] ) )
                    {
                        $id = $el[ 'id' ];
                    }
                    else
                    {
                        $id = $name . "_js";
                    }

                    $this->form->addDummy( $name, $default, $desc, $warning, $id );
                    break;
                case 'html':
                    if( !isset( $el[ 'html' ] ) )
                    {
                        throw new \InvalidArgumentException;
                    }
                    $this->form->addHtml( $el[ 'html' ] );
                    break;
                case 'matrix':
                    if( isset( $el[ 'matrix' ] ) )
                    {
                        if( !( $el[ 'matrix' ] instanceof \IPS\Helpers\Form\Matrix ) )
                        {
                            throw new \InvalidArgumentException;
                        }
                    }

                    $this->form->addMatrix( $name, $el[ 'matrix' ] );
                    break;
                case 'hidden':
                    $this->form->hiddenValues[ $name ] = $el[ 'default' ];
                    break;
            }
        }

        return $this->form;
    }

    /**
     * adds a header/tab/sidebar to an element
     * @param $el
     */
    final protected function setExtra( $el )
    {

        if( isset( $el[ 'header' ] ) )
        {
            $this->form->addHeader( $this->langPrefix . $el[ 'header' ] . '_header' );
        }

        if( isset( $el[ 'tab' ] ) )
        {
            $this->form->addTab( $this->langPrefix . $el[ 'tab' ] . '_tab' );
        }

        if( isset( $el[ 'sidebar' ] ) )
        {
            $sideBar = $this->langPrefix . $el[ 'sidebar' ] . '_sidebar';
            if( \IPS\Member::loggedIn()->language()->checkKeyExists( $sideBar ) )
            {
                $sideBar = \IPS\Member::loggedIn()->language()->addToStack( $sideBar );
            }

            $this->form->addSidebar( $sideBar );
        }

    }
}<file_sep>/setup/upg_30007/upgrade.php
<?php

/**
 * @brief       Upgrade Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       3.0.7
 * @version     -storm_version-
 */

namespace IPS\storm\setup\upg_30007;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * 3.0.7 Upgrade Code
 */
class _Upgrade
{
	/**
	 * ...
	 *
	 * @return	array	If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
	 */
	public function step1()
	{

        $menu = [
            'parent' => 'Storm',
            'name' => 'Sync',
            'type' => 'int',
            'url' => 'app=storm&module=configuration&controller=sync',
            'original' => 'sync'
        ];
        \IPS\storm\Menu::addMenu($menu);
        \IPS\storm\Menu::kerching();

		return TRUE;
	}
	
	// You can create as many additional methods (step2, step3, etc.) as is necessary.
	// Each step will be executed in a new HTTP request
}<file_sep>/extensions/storm/Headerdoc/storm.php
<?php

/**
 * @brief       Storm Headerdoc extension: Storm
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.4
 * @version     -storm_version-
 */

namespace IPS\storm\extensions\storm\Headerdoc;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * storm
 */
class _storm extends \IPS\storm\Headerdoc\HeaderdocAbstract
{

    /**
     * enable headerdoc
     **/
    public function headerDocEnabled()
    {
        return true;
    }

    /**
     * enable add index.html
     **/
    public function indexEnabled()
    {
        return true;
    }

    /**
     * files to skip during building of the tar
     **/
    public function headerDocFilesSkip()
    {
        return [];
    }

    /**
     * directories to skip during building of the tar
     **/
    public function headerDocDirSkip()
    {
        return [];
    }

    /**
     * an array of files/folders to exclude in the headerdoc
     **/
    public function headerDocExclude()
    {
        return [];
    }
}<file_sep>/hooks/Application.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Application extends _HOOK_CLASS_
{

    public function assignNewVersion( $long, $human )
    {
        parent::assignNewVersion( $long, $human );
        $this->version = $human;
        \IPS\storm\Headerdoc::i()->process( $this );
    }

    public function build()
    {
        \IPS\storm\Headerdoc::i()->addIndexHtml( $this );
        parent::build();
    }

    public function installJavascript( $offset=null, $limit=null ){
        parent::installJavascript($offset, $limit);
        \IPS\storm\Proxyclass::i()->generateSettings();
    }

    public function installOther()
    {
        if ( \IPS\IN_DEV and defined( 'CJ_STORM_BUILD_DEV' ) and CJ_STORM_BUILD_DEV ) {
            $dir = \IPS\ROOT_PATH . "/applications/" . $this->directory . "/dev/";
            if ( !file_exists( $dir ) and $this->directory !== "storm" ) {
                $app = new \IPS\storm\Apps( $this );
                $app->addToStack = true;
                $app->email();
                $app->javascript();
                $app->language();
                $app->templates();
            }
        }

        parent::installOther();
    }
}
<file_sep>/hooks/applicationBuilderIterator.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_applicationBuilderIterator extends _HOOK_CLASS_
{

    /**
     * Current value
     *
     * @return    void
     */
    public function current()
    {
        $file = (string) parent::current();

        if ( mb_substr( str_replace( '\\', '/', $file ),
                        mb_strlen( \IPS\ROOT_PATH . "/applications/" . $this->application->directory ) + 1, 6 ) === 'hooks/'
        ) {
            $temporary = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );

            \file_put_contents( $temporary, \IPS\Plugin::addExceptionHandlingToHookFile( $file ) );

            register_shutdown_function( function ( $temporary ) {
                unlink( $temporary );
            }, $temporary );

            return $temporary;
        }
        else {
            if ( is_file( $file ) and ( mb_strpos( $file, '3rdparty' ) === false or mb_strpos( $file,
                                                                                               '3rd_party' ) === false or mb_strpos( $file, 'vendor' ) === false )
            ) {
                if ( !\IPS\storm\Headerdoc::i()->can( $this->application ) ) {
                    return $file;
                }

                $path = new \SplFileInfo( $file );

                if ( $path->getExtension() == "js" and $path->getFilename() === "babble.js" ) {
                    $temp = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );

                    $content = \file_get_contents( $file );

                    $replace = \preg_replace( "#var privateKey = '(.*?)';#", "var privateKey = '';", $content );

                    \file_put_contents( $temp, $replace );

                    return $temp;
                }

                if ( $path->getExtension() == "php" ) {
                    $temporary = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );

                    $contents = \file_get_contents( $file );

                    foreach ( $this->application->extensions( 'storm', 'Headerdoc' ) as $class ) {
                        if ( method_exists( $class, 'headerDocFinalize' ) ) {
                            $contents = $class->headerDocFinalize( $contents, $this->application );
                        }
                    }

                    \file_put_contents( $temporary, $contents );

                    register_shutdown_function( function ( $temporary ) {
                        unlink( $temporary );
                    }, $temporary );

                    return $temporary;
                }
            }

            return $file;
        }
    }
}
<file_sep>/dev/js/admin/controllers/query/ips.query.query.js
;( function($, _, undefined){
    "use strict";
    ips.controller.register('storm.admin.query.query', {
        initialize: function () {
            this.on('change', '[id="elSelect_js_storm_query_table"]', this._getFields);
            this.on('change', '[id="elSelect_js_storm_query_columns"]', this._getFields);

        },
        _getFields: function(e){
            // console.log('yes');
            var url = ips.getSetting('storm_table_url');
            var ajax = ips.getAjax();
            ajax( {
                url: url+"&do=getFields&table="+$(e.target).val(),
                type: "GET",
                success:function(data){
                    console.log( data );
                    if( data.error == 0 ) {
                        $('#elSelect_js_storm_query_columns').replaceWith(data.html);
                    }
                }
            } );
        }
    });
}(jQuery, _));<file_sep>/sources/Forms/Select.php
<?php

/**
 * @brief       Select Class
 * @author      <a href='http://codingjungle.com'><NAME></a>
 * @copyright   (c) 2017 <NAME>
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     3.0.4
 */

namespace IPS\storm\Forms;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Select extends \IPS\Helpers\Form\Select
{
    /**
     * Validate
     *
     * @throws    \OutOfRangeException
     * @return    TRUE
     */
    public function validate()
    {
        return true;
    }
}<file_sep>/sources/Profiler/Template.php
<?php

/**
 * @brief       Template Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       2.0.0
 * @version     -storm_version-
 */

namespace IPS\storm\Profiler;

class _Template extends \IPS\Patterns\Singleton
{
    protected static $instance = null;

    protected $storm = null;

    protected $langs = null;

    public function __construct()
    {
        $this->db_execution_time = "Execution Time: %s";
        $this->memory_name = "Name: %s";
        $this->filename = "Filename: %s";
        $this->path = "Path: %s";
        $this->size = "Size: %s";
        $this->storm = \IPS\storm\Profiler::i();
    }

    public function tabs()
    {
        $storm = $this->storm;
        $this->langs = [
            'console' => sprintf( 'Console (%s)', $storm->consoleTab ),
            'dbTab' => sprintf( 'DB Queries (%s)', $storm->dbQueriesTab ),
            'memoryTab' => sprintf( 'Memory (%s)', $storm->memoryTab ),
            'fileTab' => sprintf( 'Files (%s)', $storm->fileTab ),
            'timeTab' => sprintf( 'Execution Times (%s)', $storm->speedTab ),
            'cacheTab' => sprintf( 'Cache (%s)', $storm->cacheTab ),
            'logsTab' => sprintf( 'Logs (<span id="profilerLogTabCount">%s</span>)', $storm->logsTab ),
            'none' => "<div class='ipsPad'>This is not the tab you are looking for.</div>",
            'memTotal' => sprintf( "%s<br>Memory Used", $this->storm->memoryTotal ),
            'dbTotal' => sprintf( "%s<br>DB Queries", $this->storm->dbQueriesTab ),
            'fileTotal' => sprintf( "%s<br>Included Files", $this->storm->fileTab ),
            'timeTotal' => sprintf( "%s<br>Execution Time", $this->storm->totalTime ),
            'cacheTotal' => sprintf( "%s<br> Caches", $this->storm->cacheTab ),
            'logsTotal' => sprintf( "%s logs", $this->storm->logsTab ),
        ];

        $fixed = '';
        $button = '';
        if( !\IPS\Settings::i()->storm_profiler_is_fixed )
        {
            $fixed = "stormProfilerFixed";
            $button = <<<EOF
            <div class="stormProfilerButtonContainer">
                <button id="eLstormButton" type="button" class="ipsButton stormProfileButton" data-ipsstormprofile>Profiler</button>
            </div>
EOF;
        }
        $langs = $this->langs;

        $dbTab = '';
        if( $this->storm->dbEnabled )
        {
            $dbTab = <<<EOF
            <li role='presentation'>
                <a href='#' id='stormProfilerDbQueries' role='tab' class='ipsTabs_item'>
                    {$langs['dbTab']}
                </a>
            </li>            
EOF;
        }

        $memTab = '';
        if( $this->storm->memEnabled )
        {
            $memTab = <<<EOF
            <li role='presentation'>
                <a href='#' id='stormProfilerMemory' role='tab' class='ipsTabs_item'>
                    {$langs['memoryTab']}
                </a>
            </li>            
EOF;
        }

        $executionTab = '';
        if( $this->storm->timeEnabled )
        {
            $executionTab = <<<EOF
            <li role='presentation'>
                <a href='#' id='stormProfilerTime' role='tab' class='ipsTabs_item'>
                    {$langs['timeTab']}
                </a>
            </li>
EOF;
        }

        $cacheTab = '';
        if( $this->storm->cacheEnabled )
        {
            $cacheTab = <<<EOF
            <li role='presentation'>
                <a href='#' id='stormProfilerCache' role='tab' class='ipsTabs_item'>
                    {$langs['cacheTab']}
                </a>
            </li>
EOF;
        }

        $logTab = '';
        if( $this->storm->logsEnabled )
        {
            $logTab = <<<EOF
            <li role='presentation'>
                <a href='#' id='stormProfilerLog' role='tab' class='ipsTabs_item'>
                    {$langs['logsTab']}
                </a>
            </li>
EOF;
        }

        $html = <<<EOF
    <div class="stormProfile {$fixed}" >
    {$button}
    <div id="eLstormTabs" class=" stormProfileTabs">
        <div class='ipsTabs ipsClearfix' id='elStormProfilerTabs' data-ipsTabBar data-ipsTabBar-contentArea='#elStormProfilerTabsContent' data-ipsTabBar-activeClass="stormActiveTab">
            <a href='#elStormProfilerTabs' data-action='expandTabs'><i class='icon-caret-down'></i></a>
            <ul role='tablist'>
                <li role='presentation'>
                    <a href='#' id='elStormTabConsole' class='ipsTabs_item'>
                       {$langs['console']}
                    </a>
                </li>
                {$dbTab}
                {$memTab}
                {$executionTab}
                {$cacheTab}
                {$logTab}
            </ul>
        </div>
        <section id='elStormProfilerTabsContent' class='ipsTabs_panels'>
            {$this->consoleTab()}
            {$this->memoryTab()}
            {$this->dbQueryTab()}
            {$this->cacheTab()}
            {$this->speedTab()}
            {$this->logTab()}
        </section>
    </div>
</div>    
EOF;

        return $html;
    }

    public function consoleTab()
    {
        $consolo = $this->storm->processedLogs;
        $dbTab = '';

        if( $this->storm->dbEnabled )
        {
            $dbTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfilerDbQueriesConsole'>
                <span>
                    {$this->langs['dbTotal']}
                </span>
            </div>
EOF;
        }

        $memTab = '';
        if( $this->storm->memEnabled )
        {
            $memTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfilerMemoryConsole'>
                <span>
                {$this->langs['memTotal']}
                </span>
            </div>
EOF;
        }

        $filesTab = '';
        if( $this->storm->filesEnabled )
        {
            $filesTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfilerFilesConsole'>
                <span>
                    {$this->langs['fileTotal']}
                </span>
            </div>
EOF;
        }

        $executionTab = '';
        if( $this->storm->timeEnabled )
        {
            $executionTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfileTimeConsole'>
                <span>
                    {$this->langs['timeTotal']}
                </span>
            </div>
EOF;
        }

        $cacheTab = '';
        if( $this->storm->cacheEnabled )
        {
            $cacheTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfilerCacheConsole'>
                <span>
                    {$this->langs['cacheTotal']}
                </span>
            </div>
EOF;
        }

        $logTab = '';
        if( $this->storm->logsEnabled )
        {
            $logTab = <<<EOF
            <div class='ipsGrid_span6 stormProfilerConsoleSide stormProfilerLogConsole'>
                <span>
                    {$this->langs['logsTotal']}
                </span>
            </div>
EOF;
        }

        $html = <<<EOF
<div id="ipsTabs_elStormProfilerTabs_elStormTabConsole_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    {$dbTab}
                    {$memTab}
                    {$filesTab}
                    {$executionTab}
                    {$cacheTab}
                    {$logTab}
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div class="stormProfilerBaseContainer stormProfilerLogs ">
                    {$consolo}
                </div>
            </div>
        </div>
    </div>
</div>
EOF;

        return $html;
    }

    public function memoryTab()
    {

        if( $this->storm->memEnabled )
        {
            if( $this->storm->memoryList )
            {
                $memory = $this->storm->memoryList;
            }
            else
            {
                $memory = $this->langs[ 'none' ];
            }

            $html = <<<EOF
    <div id="ipsTabs_elStormProfilerTabs_stormProfilerMemory_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    <div class='ipsGrid_span12 stormProfilerConsoleSide stormProfilerMemoryConsole'>
                        <span>
                            {$this->langs['memTotal']}
                        </span>
                    </div>
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div class="stormProfilerBaseContainer stormProfilerLogs">
                    {$memory}
                </div>
            </div>
        </div>
    </div>
</div>    
EOF;
            return $html;
        }
    }

    public function dbQueryTab()
    {
        if( $this->storm->dbEnabled )
        {
            if( !$this->storm->dbQueriesList )
            {
                $db = $this->langs[ 'none' ];
            }
            else
            {
                $db = $this->storm->dbQueriesList;
            }

            $html = <<<EOF
    <div id="ipsTabs_elStormProfilerTabs_stormProfilerDbQueries_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    <div class='ipsGrid_span12 stormProfilerConsoleSide stormProfilerDbQueriesConsole'>
                        <span>
                            {$this->langs['dbTotal']}
                        </span>
                    </div>
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div class="stormProfilerBaseContainer stormProfilerLogs">
                    {$db}
                </div>
            </div>
        </div>
    </div>
</div>    
EOF;
            return $html;
        }
    }

    public function cacheTab()
    {
        if( $this->storm->cacheEnabled )
        {
            if( !$this->storm->cacheList )
            {
                $totals = $this->langs[ 'none' ];
            }
            else
            {
                $totals = $this->storm->cacheList;
            }

            $html = <<<EOF
    <div id="ipsTabs_elStormProfilerTabs_stormProfilerCache_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    <div class='ipsGrid_span12 stormProfilerConsoleSide stormProfilerCacheConsole'>
                        <span>
                            {$this->langs['cacheTotal']}
                        </span>
                    </div>
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div class="stormProfilerBaseContainer stormProfilerLogs">
                    {$totals}
                </div>
            </div>
        </div>
    </div>
</div>    
EOF;
            return $html;
        }
    }

    public function speedTab()
    {

        if( $this->storm->timeEnabled )
        {
            if( !$this->storm->speedList )
            {
                $totals = $this->langs[ 'none' ];
            }
            else
            {
                $totals = $this->storm->speedList;
            }

            $html = <<<EOF
        <div id="ipsTabs_elStormProfilerTabs_stormProfilerTime_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    <div class='ipsGrid_span12 stormProfilerConsoleSide stormProfileTimeConsole'>
                        <span>
                            {$this->langs['timeTotal']}
                        </span>
                    </div>
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div class="stormProfilerBaseContainer stormProfilerLogs">
                    {$totals}
                </div>
            </div>
        </div>
    </div>
</div>
EOF;

            return $html;
        }
    }

    public function logTab()
    {
        if( $this->storm->logsEnabled )
        {
            $url = \IPS\Settings::i()->base_url . 'applications/storm/interface/logs/logs.php';
            $time = time();
            if( !$this->storm->ipsLogsList )
            {
                $totals = $this->langs[ 'none' ];
            }
            else
            {
                $totals = $this->storm->ipsLogsList;
            }

            $html = <<<EOF
    <div id="ipsTabs_elStormProfilerTabs_stormProfilerLog_panel" class="ipsTabs_panel ipsPad stormProfilerPanels">
    <div class="stormProfileConsoleBrief">
        <div class='ipsColumns'>
            <div class="ipsColumn ipsColumn_veryWide">
                <div class='ipsGrid'>
                    <div class='ipsGrid_span12 stormProfilerConsoleSide stormProfilerLogConsole'>
                        <span>
                            {$this->langs['logsTotal']}
                        </span>
                    </div>
                </div>
            </div>
            <div class="ipsColumn ipsColumn_fluid">
                <div id="stormProfilerLogs" class="stormProfilerBaseContainer stormProfilerLogs" data-stormtime="{$time}" data-ipsstormdebug data-ipsstormdebug-url="{$url}">
                    {$totals}
                </div>
            </div>
        </div>
    </div>
</div>    
EOF;
            return $html;
        }
    }

    public function consoleContainer( $type, $body, $lang, $class = '' )
    {
        return <<<EOF
<div class="ipsColumns stormProfilerSpacer stormProfiler{$type}{$class}">
    <div class="ipsColumn ipsColumn_narrow  ipsPad">{$lang}</div>
    <div class="ipsColumn ipsColumn_fluid ipsPad">{$body}</div>
</div>
EOF;
    }

    public function memory( array $mem )
    {
        if( $this->storm->memEnabled )
        {
            $lang = sprintf( $this->memory_name, $mem[ 'name' ] );

            return <<<EOF
<div class="stormProfilerBase">
    <div>{$lang}</div>
    <div>{$mem['memory']}<br>{$mem['msg']}</div>
</div>
EOF;
        }
    }

    public function db( $query )
    {
        if( $this->storm->dbEnabled )
        {
            $u = \IPS\Http\Url::internal( 'app=storm&module=general&controller=general&do=backtrace&id=' . $query[ 'backtrace' ],
                'front' );
            $lang = sprintf( $this->db_execution_time, $query[ 'time' ] );
            $html = <<<EOF
<div class="stormProfilerBase" data-ipsDialog data-ipsDialog-url="{$u}">
    <div>{$lang}</div>
    <div>
        <code class="prettyprint lang-sql stormProfilerBasePointer">{$query['query']}</code>
    </div>
</div>
EOF;
            return $html;
        }
    }

    public function cache( $type, $key, $num )
    {
        if( $this->storm->cacheEnabled )
        {
            $u = \IPS\Http\Url::internal( 'app=storm&module=general&controller=general&do=cache&id=' . $num, 'front' );
            $type = sprintf( 'Type: %s', $type );
            $key = sprintf( 'Key: %s', $key );
            $html = <<<EOF
<div class="stormProfilerBase stormProfilerCacheLog" data-ipsDialog data-ipsDialog-url="{$u}">
    <div>{$type}</div>
    <div>{$key}</div>
</div>
EOF;
            return $html;
        }
    }

    public function speed( $for, $time, $percent )
    {
        if( $this->storm->timeEnabled )
        {
            $for = sprintf( 'For: %s', $for );
            $time = sprintf( 'Execution Time: %s', $time );
            $percent = sprintf( 'Percentage of Total Time: %s', $percent );
            $html = <<<EOF
<div class="stormProfilerBase">
    <div>{$for}</div>
    <div>{$time}</div>
    <div>{$percent}</div>
</div>
EOF;
            return $html;
        }
    }

    public function log( $data )
    {
        if( $this->storm->logsEnabled )
        {
            $u = uniqid();
            $exception_class = '';
            $exception_code = '';
            $category = '';
            $msg = nl2br( $data[ 'message' ] . "<br>" . $data[ 'backtrace' ] );
            $trunc = \htmlspecialchars( \mb_substr( \html_entity_decode( $data[ 'message' ] ), 0, 20 ), ENT_NOQUOTES,
                'UTF-8', false );

            if( $data[ 'exception_class' ] )
            {
                $lang = sprintf( "Exception's Class: %s", $data[ 'exception_class' ] );
                $exception_class = "<div>{$lang}</div>";
            }

            if( $data[ 'exception_code' ] )
            {
                $lang = sprintf( "Exception's Code: %s", $data[ 'exception_code' ] );
                $exception_code = "<div>{$lang}</div>";
            }

            if( $data[ 'category' ] )
            {
                $lang = sprintf( "Category: %s", $data[ 'category' ] );
                $category = "<div>{$lang}</div>";
            }

            $html = <<<EOF
<div class="stormProfilerBase stormProfilerBasePointer"  data-ipsDialog data-ipsDialog-content="#{$u}">
    {$exception_class}
    {$exception_code}
    {$category}
    <div>{$trunc}</div>
    <div id="{$u}" class="ipsHide ipsPad">
        {$msg}
    </div>
</div>
EOF;
            return $html;
        }
    }

    public function logObj( $data )
    {
        if( $this->storm->logsEnabled )
        {
            $u = uniqid();
            $exception_class = '';
            $exception_code = '';
            $category = '';
            $msg = nl2br( $data->message . "<br>" . $data->backtrace );
            $trunc = \htmlspecialchars( \mb_substr( \html_entity_decode( $data->message ), 0, 20 ), ENT_NOQUOTES,
                'UTF-8', false );

            if( $data->exception_class )
            {
                $lang = sprintf( "Exception's Class: %s", $data->exception_class );
                $exception_class = "<div>{$lang}</div>";
            }

            if( $data->exception_code )
            {
                $lang = sprintf( "Exception's Code: %s", $data->exception_code );
                $exception_code = "<div>{$lang}</div>";
            }

            if( $data->category )
            {
                $lang = sprintf( "Category: %s", $data->category );
                $category = "<div>{$lang}</div>";
            }

            $html = <<<EOF
<div class="stormProfilerBase stormProfilerBasePointer"  data-ipsDialog data-ipsDialog-content="#{$u}">
    {$exception_class}
    {$exception_code}
    {$category}
    <div>{$trunc}</div>
    <div id="{$u}" class="ipsHide ipsPad">
        {$msg}
    </div>
</div>
EOF;
            return $html;
        }
    }
}
<file_sep>/hooks/Lang.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Lang extends _HOOK_CLASS_
{

    public function parseOutputForDisplay( &$output )
    {
        \IPS\storm\Profiler::i()->timeStart();
        parent::parseOutputForDisplay( $output );
        \IPS\storm\Profiler::i()->timeEnd( 'parseOutputForDisplay' );
    }
}
<file_sep>/sources/Profiler/Profiler.php
<?php

/**
 * @brief       Profiler Active Record
 * @author      <a href='http://codingjungle.com'><NAME></a>
 * @copyright   (c) 2017 <NAME>
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     3.0.4
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Profiler
{
    protected static $instance = null;
    protected $countTab = 0;
    protected $consoleTab = 0;
    protected $dbQueriesList = '';
    protected $dbQueriesTab = 0;
    protected $memoryList = '';
    protected $memoryTab = 0;
    protected $memoryTotal = 0;
    protected $fileTab = 0;
    protected $totalTime = null;
    protected $logMessage = '';
    protected $logsTab = 0;
    protected $logList = '';
    protected $processedLogs = '';
    protected $timeTab = 0;
    protected $cacheList = '';
    protected $cacheTab = 0;
    protected $mstart = null;
    protected $ttime = null;
    protected $cacheLogs = [];
    protected $dbLogs = [];
    protected $speed = [];
    protected $speedTab = 0;
    protected $speedList = '';
    protected $ipsLogsList = '';
    protected $ipsLogsTab = 0;
    protected $filesEnabled = true;
    protected $logsEnabled = true;
    protected $dbEnabled = true;
    protected $dbEnabledSpeed = true;
    protected $memEnabled = true;
    protected $cacheEnabled = true;
    protected $timeEnabled = true;
    protected $type = 0;

    final protected function __construct( $type )
    {

        if( defined( 'CJ_STORM_PROFILER_DISABLE_LOGS' ) and CJ_STORM_PROFILER_DISABLE_LOGS )
        {
            $this->logsEnabled = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_DB' ) and CJ_STORM_PROFILER_DISABLE_DB )
        {
            $this->dbEnabled = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_DB_SPEED' ) and CJ_STORM_PROFILER_DISABLE_DB_SPEED )
        {
            $this->dbEnabledSpeed = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_MEM' ) and CJ_STORM_PROFILER_DISABLE_MEM )
        {
            $this->memEnabled = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_CACHE' ) and CJ_STORM_PROFILER_DISABLE_CACHE )
        {
            $this->cacheEnabled = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_TIME' ) and CJ_STORM_PROFILER_DISABLE_TIME )
        {
            $this->timeEnabled = false;
        }

        if( defined( 'CJ_STORM_PROFILER_DISABLE_FILE' ) and CJ_STORM_PROFILER_DISABLE_FILE )
        {
            $this->filesEnabled = false;
        }
    }

    public static function i( $type = 0 )
    {
        if( static::$instance === null )
        {
            static::$instance = new static( $type );
        }
        static::$instance->type = $type;
        return static::$instance;
    }

    public function run()
    {
        if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
        {
            $this->fileTab();
            $this->memoryTotal();
            $this->totalTime();
            if( $this->type == 1 )
            {
                if( isset( \IPS\Data\Store::i()->storm_bt ) )
                {
                    unset( \IPS\Data\Store::i()->storm_bt );
                }

                if( isset( \IPS\Data\Store::i()->storm_cache ) )
                {
                    unset( \IPS\Data\Store::i()->storm_cache );
                }
            }

            \IPS\Data\Store::i()->storm_bt = $this->dbLogs;
            \IPS\Data\Store::i()->storm_cache = $this->cacheLogs;

            return \IPS\storm\Profiler\Template::i()->tabs();
        }
    }

    public static function profilePassCheck()
    {
        if( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE )
        {
            $password = defined( 'CJ_STORM_PROFILER_PASS' ) ? CJ_STORM_PROFILER_PASS : md5( rand( 1, 100000 ) );
            $pass = \IPS\Request::i()->profilerPass;

            if( $password == $pass or ( isset( $_SESSION[ 'storm_profile' ] ) and $_SESSION[ 'storm_profile' ] ) )
            {

                if( !isset( $_SESSION[ 'storm_profile' ] ) )
                {
                    $_SESSION[ 'storm_profile' ] = true;
                }

                return true;
            }
        }
    }

    protected function fileTab()
    {
        if( $this->filesEnabled )
        {
            $files = get_included_files();
            $count = count( $files );
            $this->fileTab = $count;
        }
    }

    protected function memoryTotal( $object = null, $name = 'total' )
    {
        if( $this->memEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                $mem = ( \is_object( $object ) ) ? mb_strlen( \serialize( $object ) ) : \memory_get_usage();
                $mem = $this->formatBytes( $mem );
                if( $name === 'total' )
                {
                    $this->memoryTotal = $this->formatBytes( \memory_get_usage() );
                }
                $this->consoleTab++;
                $this->memoryTab++;
                $msg = \IPS\storm\Profiler\Template::i()->memory( [ 'name' => $name, 'msg' => '', 'memory' => $mem ] );
                $msg = \IPS\storm\Profiler\Template::i()
                                                   ->consoleContainer( 'Memory', $msg, "Memory",
                                                       $this->oddEven( $this->memoryTab ) );
                $this->memoryList = $msg . "\n" . $this->memoryList;
                $this->processedLogs = $msg . "\n" . $this->processedLogs;
            }
        }
    }

    protected function formatBytes( $size, $precision = 2 )
    {
        $base = \log( $size, 1024 );
        $suffixes = [ 'B', 'KB', 'MB', 'GB', 'TB' ];

        return \round( \pow( 1024, $base - \floor( $base ) ), $precision ) . ' ' . $suffixes[ \floor( $base ) ];
    }

    public function oddEven( $num )
    {
        if( $num % 2 == 0 )
        {
            return "Even";
        }

        return "Odd";
    }

    protected function totalTime()
    {
        if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
        {

            $this->totalTime = round( microtime( true ) - $_SERVER[ "REQUEST_TIME_FLOAT" ], 4 );

            if( is_array( $this->speed ) and count( $this->speed ) )
            {
                foreach( $this->speed as $num => $speed )
                {
                    $percent = number_format( ( $speed / $this->totalTime ) * 100, 2 );
                    $this->processedLogs = str_replace( "##speed{$num}##", $percent, $this->processedLogs );
                    $this->speedList = str_replace( "##speed{$num}##", $percent, $this->speedList );
                }
            }
        }
    }

    public function __get( $key )
    {
        if( property_exists( $this, $key ) )
        {
            return $this->{$key};
        }
    }

    public function log( $message, $category = null )
    {
        if( $this->logsTab )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {
                $exception_class = '';
                $exception_code = '';

                if( $message instanceof \Exception )
                {
                    $exception_class = get_class( $message );
                    $exception_code = $message->getCode();

                    if( method_exists( $message, 'extraLogData' ) )
                    {
                        $msg = $message->extraLogData() . "\n" . $message->getMessage();
                    }
                    else
                    {
                        $msg = $message->getMessage();
                    }

                    $backtrace = $message->getTraceAsString();
                }
                else
                {
                    if( is_array( $message ) )
                    {
                        $message = var_export( $message, true );
                    }
                    $msg = $message;
                    $backtrace = ( new \Exception )->getTraceAsString();
                }

                $final = [
                    'message' => $msg,
                    'backtrace' => $backtrace,
                    'exception_class' => $exception_class,
                    'exception_code' => $exception_code,
                    'category' => $category
                ];
                $this->consoleTab++;
                $this->ipsLogsTab++;
                $msg = \IPS\storm\Profiler\Template::i()->log( $final );
                $msg = \IPS\storm\Profiler\Template::i()
                                                   ->consoleContainer( 'Log', $msg, "IPS Log",
                                                       $this->oddEven( $this->ipsLogsTab ) );
                $this->ipsLogsList = $msg . "\n" . $this->ipsLogsList;
                $this->processedLogs = $msg . "\n" . $this->processedLogs;
            }
        }
    }

    public function dbQuery( $query, $time )
    {
        if( $this->dbEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                $this->consoleTab++;
                $this->dbQueriesTab++;
                $hash = sha1( trim( $query[ 'backtrace' ] ) );
                $this->dbLogs[ $hash ] = $query;
                $msg = \IPS\storm\Profiler\Template::i()->db( [
                    'query' => $query[ 'query' ],
                    'backtrace' => $hash,
                    'time' => $time
                ] );
                $msg = \IPS\storm\Profiler\Template::i()
                                                   ->consoleContainer( 'DbQueries', $msg, "DB Query",
                                                       $this->oddEven( $this->dbQueriesTab ) );
                $this->dbQueriesList = $msg . "\n" . $this->dbQueriesList;
                $this->processedLogs = $msg . "\n" . $this->processedLogs;

                if( $this->dbEnabledSpeed )
                {
                    $this->speed( $query[ 'query' ], $time );
                }
            }
        }
    }

    public function speed( $for, $end )
    {
        if( $this->timeEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                $this->consoleTab++;
                $this->speedTab++;
                $percent = "##speed{$this->speedTab}##";
                $this->speed[ $this->speedTab ] = $end;
                $msg = \IPS\storm\Profiler\Template::i()->speed( $for, $end, $percent );
                $msg = \IPS\storm\Profiler\Template::i()
                                                   ->consoleContainer( 'Speed', $msg, "Execution Time",
                                                       $this->oddEven( $this->speedTab ) );
                $this->speedList = $msg . "\n" . $this->speedList;
                $this->processedLogs = $msg . "\n" . $this->processedLogs;
            }
        }
    }

    public function memoryStart()
    {
        if( $this->memEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                $this->mstart = \memory_get_usage();
            }
        }
    }

    public function memoryEnd( $for, $msgs = '' )
    {
        if( $this->memEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                if( $this->mstart !== null )
                {
                    $end = \memory_get_usage() - $this->mstart;
                    $this->consoleTab++;
                    $this->memoryTab++;
                    $msg = \IPS\storm\Profiler\Template::i()->memory( [
                        'name' => $for,
                        'msg' => $msgs,
                        'memory' => $this->formatBytes( $end )
                    ] );
                    $msg = \IPS\storm\Profiler\Template::i()
                                                       ->consoleContainer( 'Memory', $msg, 'Memory',
                                                           $this->oddEven( $this->memoryTab ) );
                    $this->memoryList = $msg . "\n" . $this->memoryList;
                    $this->processedLogs = $msg . "\n" . $this->processedLogs;
                }
                $this->mstart = null;
            }
        }
    }

    public function cacheLog( $cache = [] )
    {
        if( $this->cacheEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {
                $this->consoleTab++;
                $this->cacheTab++;
                $this->cacheLogs[ $this->cacheTab ] = $cache;
                $msg = \IPS\storm\Profiler\Template::i()->cache( $cache[ 'type' ], $cache[ 'key' ], $this->cacheTab );
                $msg = \IPS\storm\Profiler\Template::i()
                                                   ->consoleContainer( 'Cache', $msg, "Cache",
                                                       $this->oddEven( $this->cacheTab ) );
                $this->cacheList = $msg . "\n" . $this->cacheList;
                $this->processedLogs = $msg . "\n" . $this->processedLogs;
            }
        }
    }

    public function timeStart()
    {
        if( $this->timeEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                $this->ttime = microtime( true );
            }
        }
    }

    public function timeEnd( $for )
    {
        if( $this->timeEnabled )
        {
            if( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) )
            {

                if( $this->ttime !== null )
                {
                    $end = microtime( true ) - $this->ttime;
                    $this->speed( $for, $end );
                }
                $this->ttime = null;
            }
        }
    }
}
<file_sep>/interface/sync/task.php
<?php
require_once str_replace(
    'applications/storm/interface/sync/sync.php', '',
    str_replace( '\\', '/', __FILE__
    )
    ) . 'init.php';
\IPS\Session\Front::i();
\IPS\storm\Sync::send();<file_sep>/sources/Headerdoc/HeaderdocAbstract.php
<?php

/**
 * @brief       HeaderdocAbstract Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.4
 * @version     -storm_version-
 */

namespace IPS\storm\Headerdoc;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _HeaderdocAbstract
{

    /**
     * finalize header Doc
     **/
    public function headerDocFinalize( $line, $application )
    {
        $line = preg_replace_callback( "#^.+?\s(?=namespace)#s", function( $m ) use ( $application )
        {
            $line = $m[ 0 ];
            //author
            $author = "<a href='" . $application->website . "'>" . $application->author . "</a>";

            $line = preg_replace( '#@author([^\n]+)?#', "@author      {$author}", $line );

            //copyright
            $copyright = "(c) " . ( new \DateTime )->format( "Y" ) . " " . $application->author;

            $line = preg_replace( '#@copyright([^\n]+)?#', "@copyright   {$copyright}", $line );

            $line = preg_replace( '#@version([^\n]+)?#', "@version     {$application->version}", $line );

            return $line;
        }, $line );

        return $line;
    }

    /**
     * since version, shouldn't be used unless you want the "since" version to change
     **/
    public function since( $application )
    {
        return $application->version;
    }
}<file_sep>/modules/front/bitbucket/index.php
<?php

/**
 * @brief       Index Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.1
 * @version     -storm_version-
 */

namespace IPS\storm\modules\front\bitbucket;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * index
 */
class _index extends \IPS\Dispatcher\Controller
{

    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {

        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        \IPS\storm\Bitbucket::createNewBitbucket();

        \IPS\Output::i()->output = '';
    }

    // Create new methods with the same name as the 'do' parameter which should execute it
}<file_sep>/sources/Sync/Sync.php
<?php

/**
 * @brief       Sync Node
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Sync extends \IPS\Node\Model
{
    /**
     * @brief    [ActiveRecord] Multiton Store
     */
    protected static $multitons;

    /**
     * @brief    [ActiveRecord] Default Values
     */
    protected static $defaultValues = null;

    /**
     * @brief    [ActiveRecord] Database Table
     */
    public static $databaseTable = 'storm_sync';

    /**
     * @brief    [ActiveRecord] Database Prefix
     */
    public static $databasePrefix = 'sync_';

    /**
     * @brief    [ActiveRecord] ID Database Column
     */
    public static $databaseColumnId = 'id';

    /**
     * @brief    [ActiveRecord] Database ID Fields
     */
    protected static $databaseIdFields = [ 'sync_id' ];

    /**
     * @brief    [Node] Order Database Column
     */
    public static $databaseColumnOrder = null;

    /**
     * @brief    [Node] Parent ID Database Column
     */
    public static $databaseColumnParent = null;

    /**
     * @brief   [Node] Parent ID Root Value
     * @note    This normally doesn't need changing though some legacy areas use -1 to indicate a root node
     */
    public static $databaseColumnParentRootValue = 0;

    /**
     * @brief    [Node] Enabled/Disabled Column
     */
    public static $databaseColumnEnabledDisabled = null;

    /**
     * @brief    [Node] Show forms modally?
     */
    public static $modalForms = false;

    /**
     * @brief    [Node] Node Title
     */
    public static $nodeTitle = 'Sync';

    /**
     * @brief    [Node] ACP Restrictions
     * @code
    array(
     * 'app'        => 'core',                // The application key which holds the restrictrions
     * 'module'    => 'foo',                // The module key which holds the restrictions
     * 'map'        => array(                // [Optional] The key for each restriction - can alternatively use
     * "prefix"
     * 'add'            => 'foo_add',
     * 'edit'            => 'foo_edit',
     * 'permissions'    => 'foo_perms',
     * 'delete'        => 'foo_delete'
     * ),
     * 'all'        => 'foo_manage',        // [Optional] The key to use for any restriction not provided in the map
     * (only needed if not providing all 4)
     * 'prefix'    => 'foo_',                // [Optional] Rather than specifying each  key in the map, you can specify
     * a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
     * @encode
     */
    protected static $restrictions = [
        'app'    => 'storm',
        'module' => 'sync',
        'prefix' => 'sync_',
    ];


    /**
     * @brief    Bitwise values for members_bitoptions field
     */
    public static $bitOptions = [
        'bitoptions' => [
            'bitoptions' => [],
        ],
    ];

    /**
     * @brief    [Node] Title search prefix.  If specified, searches for '_title' will be done against the language
     *           pack.
     */
    public static $titleSearchPrefix = null;

    /**
     * @brief    [Node] Title prefix.  If specified, will look for a language key with "{$titleLangPrefix}_{$id}" as
     *           the key
     */
    public static $titleLangPrefix = null;

    /**
     * @brief    [Node] Prefix string that is automatically prepended to permission matrix language strings
     */
    public static $permissionLangPrefix = '';

    /**
     * @brief    [Node] Moderator Permission
     */
    public static $modPerm = '';

    /**
     * @brief    Follow Area Key
     */
    public static $followArea = '';

    /**
     * @brief    Cached URL
     */
    protected $_url = null;

    /**
     * @brief    URL Base
     */
    public static $urlBase = '';

    /**
     * @brief    URL Base
     */
    public static $urlTemplate = '';

    /**
     * @brief    SEO Title Column
     */
    public static $seoTitleColumn = null;

    /**
     * @brief    Content Item Class
     */
    public static $contentItemClass = null;


    public static function recieve()
    {
        $conf = \IPS\Settings::i();
        $keyHash = sha1( $conf->getFromConfGlobal( 'base_url' ) . $conf->getFromConfGlobal( 'board_start' ) );

        $key = \IPS\Request::i()->key;
        $app = \IPS\Request::i()->app;

        if( $key === $keyHash ) {
            $app = \IPS\Application::load( $app );
            $ftp = $conf->storm_ftp_path;
            $path = $ftp . '/' . $app->directory . '.tar';
            if( file_exists( $path ) ) {
                /* Test the phar */
                $application = new \PharData( $path, 0, null, \Phar::TAR );
                /* Get app directory */
                $appdata = json_decode( file_get_contents( "phar://" . $path . '/data/application.json' ), true );
                $appDirectory = $appdata[ 'app_directory' ];

                /* Extract */
                $application->extractTo( \IPS\ROOT_PATH . "/applications/" . $appDirectory, null, true );
                static::_checkChmod( \IPS\ROOT_PATH . '/applications/' . $appDirectory );
                unset( $appdata[ 'app_directory' ], $appdata[ 'app_protected' ], $appdata[ 'application_title' ] );

                foreach( $appdata as $column => $value ) {
                    $column = preg_replace( "/^app_/", "", $column );
                    $app->$column = $value;
                }

                $app->save();

                /* Determine our current version and the last version we ran */
                $currentVersion = $app->long_version;
                $allVersions = $app->getAllVersions();
                $longVersions = array_keys( $allVersions );
                $humanVersions = array_values( $allVersions );
                $lastRan = $currentVersion;

                if( count( $allVersions ) ) {
                    $latestLVersion = array_pop( $longVersions );
                    $latestHVersion = array_pop( $humanVersions );

                    \IPS\Db::i()->insert( 'core_upgrade_history', [
                        'upgrade_version_human' => $latestHVersion,
                        'upgrade_version_id'    => $latestLVersion,
                        'upgrade_date'          => time(),
                        'upgrade_mid'           => (int)\IPS\Member::loggedIn()->member_id,
                        'upgrade_app'           => $app->directory,
                    ] );
                }

                /* Now find any upgrade paths since the last one we ran that need to be executed */
                $upgradeSteps = $app->getUpgradeSteps( $lastRan );

                /* Did we find any? */
                if( count( $upgradeSteps ) ) {
                    $_next = array_shift( $upgradeSteps );
                    $app->installDatabaseUpdates( $_next );
                    foreach( $upgradeSteps as $up ) {
                        /* Get the object */
                        $_className = "\\IPS\\{$$app->directory}\\setup\\upg_{$up}\\Upgrade";
                        $_methodName = "step1";

                        if( class_exists( $_className ) ) {
                            $upgrader = new $_className;

                            /* If the next step exists, run it */
                            if( method_exists( $upgrader, $_methodName ) ) {
                                $result = $upgrader->$_methodName();
                                /* If the result is 'true' we move on to the next step, otherwise we need to run the same step again and store the data returned */
                                if( $result === true ) {
                                    $ranges = range( 2, 1000 );
                                    foreach( $ranges as $range ) {
                                        $next = 'step' . $range;
                                        if( method_exists( $upgrader, $next ) ) {
                                            $result = $upgrader->{$next}();

                                            if( $result !== true ) {
                                                break;
                                            }
                                        }
                                    }

                                }
                            }
                        }
                    }
                }
                $app->installJsonData();
                $app->installLanguages();
                $app->installEmailTemplates();
                $app->installSkins( true );
                $app->installJavascript();
            }
        }
    }

    protected static function _checkChmod( $directory )
    {
        if( !is_dir( $directory ) ) {
            throw new \UnexpectedValueException;
        }

        $it = new \RecursiveDirectoryIterator( $directory, \FilesystemIterator::SKIP_DOTS );
        foreach( new \RecursiveIteratorIterator( $it ) AS $f ) {
            if( $f->isDir() ) {
                @chmod( $f->getPathname(), \IPS\IPS_FOLDER_PERMISSION );
            } else {
                @chmod( $f->getPathname(), \IPS\IPS_FILE_PERMISSION );
            }
        }
    }

    public static function send()
    {
        set_time_limit( 0 );

        $trigger = [];
        foreach( static::roots() as $site ) {
            $trigger[] = [
                'key' => $site->key,
                'app' => $site->app,
                'url' => $site->interface_host,
            ];

            if( $site->ssh ) {
                $ftp = new \IPS\Ftp\Sftp(
                    $site->host,
                    $site->username,
                    $site->pass,
                    $site->port ?: 22
                );
            } else {
                $ftp = new \IPS\Ftp(
                    $site->host,
                    $site->username,
                    $site->pass,
                    $site->port ?: 21,
                    $site->secure,
                    $site->timeout
                );
            }

            $application = \IPS\Application::load( $site->app );
            $long = $application->long_version;
            $human = $application->version;
            $long++;
            $human++;
            $application->assignNewVersion( $long, $human );

            try {
                $application->build();
            } catch( \Exception $e ) {
                \IPS\Log::debug( $e );
                throw $e;
            }

            try {
                $pharPath = str_replace( '\\', '/', rtrim( \IPS\TEMP_DIRECTORY, '/' ) ) . '/' . $application->directory . ".tar";
                $download = new \PharData( $pharPath, 0, $application->directory . ".tar", \Phar::TAR );
                $download->buildFromIterator( new \IPS\Application\BuilderIterator( $application ) );
            } catch( \PharException $e ) {
                \IPS\Log::debug( $e );
                throw $e;
            }

            $file = rtrim( \IPS\TEMP_DIRECTORY, '/' ) . '/' . $application->directory . ".tar";
            $ftp->upload( $application->directory . ".tar", $file );

            /* Cleanup */
            unset( $download );
            \Phar::unlinkArchive( $pharPath );
        }

        static::trigger( $trigger );
    }

    protected static function trigger( array $triggers )
    {
        if( is_array( $triggers ) and count( $triggers ) ) {
            foreach( $triggers as $trigger ) {
                $url = \IPS\Http\Url::external( $trigger[ 'url' ] );
                $url->setQueryString( [ 'key' => $trigger[ 'key' ], 'app' => $trigger[ 'app' ] ] )->request( 2 )->get();
            }
        }
    }

    public function get__title()
    {
        $name = $this->host . ' ' . \IPS\Application::load( $this->app )->_title;

        return $name;
    }

    /**
     * [Node] Add/Edit Form
     *
     * @param    \IPS\Helpers\Form $form The form
     *
     * @return    void
     */
    public function form( &$form )
    {

        $el[ 'prefix' ] = 'storm_ftp_';

        $el[] = [
            'name'    => 'key',
            'require' => true,
        ];

        $el[] = [
            'name'    => 'interface_host',
            'require' => true,
        ];

        $el[] = [
            'name'    => 'app',
            'class'   => 'node',
            'options' => [
                'class'    => 'IPS\Application',
                'subnodes' => false,
            ],
            'require' => true,
        ];

        $el[] = [
            'name'    => 'host',
            'require' => true,
        ];

        $el[] = [
            'name' => 'username',
        ];

        $el[] = [
            'name'    => 'pass',
            'class'   => 'password',
            'require' => true,
        ];

        $el[] = [
            'name'    => 'port',
            'class'   => '#',
            'default' => $this->port ?: 21,
        ];

        $el[] = [
            'name'    => 'timeout',
            'class'   => '#',
            'default' => $this->timeout ?: 10,
        ];

        $el[] = [
            'name'  => 'secure',
            'class' => 'yn',
        ];

        $el[] = [
            'name'  => 'ssh',
            'class' => 'yn',
        ];

        $form = \IPS\storm\Forms::i( $el, $this, 'default', $form );
    }

    public static function topElements()
    {
        $conf = \IPS\Settings::i();
        $key = sha1( $conf->getFromConfGlobal( 'base_url' ) . $conf->getFromConfGlobal( 'board_start' ) );
        $e[] = [
            'type'    => 'dummy',
            'name'    => 'storm_remote_key_use',
            'desc'    => 'storm_remote_key_use_desc',
            'default' => $key,
        ];
        $e[] = [
            'type'    => 'dummy',
            'name'    => 'storm_remote_url',
            'desc'    => 'storm_remote_url_desc',
            'default' => \IPS\Settings::i()->base_url . 'applications/storm/interface/sync/sync.php',
        ];

        $e[] = [
            'type'    => 'dummy',
            'name'    => 'storm_cron_task',
            'default' => '<strong>' . PHP_BINDIR . '/php -d memory_limit=-1 -d max_execution_time=0 ' . \IPS\ROOT_PATH . '/applications/storm/interface/sync/task.php' . '</strong>',
            'desc'    => 'storm_cron_task_desc',
        ];
        $e[] = [
            'name' => 'storm_ftp_path',
        ];

        $form = \IPS\storm\Forms::i( $e, $conf );

        if( $vals = $form->values() ) {
            $form->saveAsSettings( $vals );
            \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=sync' ) );
        }

        return "<div class='ipsPad'>" . $form . "</div>";
    }

    /**
     * [Node] Format form values from add/edit form for save
     *
     * @param    array $values Values from the form
     *
     * @return    array
     */
    public function formatFormValues( $values )
    {
        if( $values[ 'storm_ftp_app' ] instanceof \IPS\Application ) {

            $values[ 'storm_ftp_app' ] = $values[ 'storm_ftp_app' ]->directory;
        }
        $new = [];
        foreach( $values as $key => $val ) {
            $key = str_replace( 'storm_ftp_', '', $key );
            $new[ $key ] = $val;
        }

        return $new;
    }

    /**
     * [Node] Save Add/Edit Form
     *
     * @param    array $values Values from the form
     *
     * @return    void
     */
    public function saveForm( $values )
    {
        parent::saveForm( $values );
    }
}<file_sep>/hooks/themeCoreGlobalGlobal.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_themeCoreGlobalGlobal extends _HOOK_CLASS_
{
    public static function hookData()
    {
        return parent::hookData();

    }

    public function includeCSS()
    {
        $parent = parent::includeCSS();
        if ( \IPS\Settings::i()->storm_settings_tab_debug_css_alt ) {
            foreach ( \IPS\Output::i()->cssFiles as $key => $val ) {
                if ( mb_strpos( $val, 'query_log.css' ) !== false ) {
                    unset( \IPS\Output::i()->cssFiles[ $key ] );
                }
            }

            $url = \IPS\storm\Settings::buildCss( \IPS\Output::i()->cssFiles );

            return \IPS\Theme::i()->getTemplate( 'css', 'storm', 'front' )->css( $url );
        }
        else if ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE ) {
            foreach ( \IPS\Output::i()->cssFiles as $key => $val ) {
                if ( mb_strpos( $val, 'query_log.css' ) !== false ) {
                    unset( \IPS\Output::i()->cssFiles[ $key ] );
                }
            }
        }

        return $parent;

    }
}
<file_sep>/modules/admin/configuration/sync.php
<?php

/**
 * @brief       Sync Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       3.0.7
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * sync
 */
class _sync extends \IPS\Node\Controller
{
	/**
	 * Node Class
	 */
	protected $nodeClass = '\IPS\storm\Sync';
	
	/**
	 * Execute
	 *
	 * @return	void
	 */
	public function execute()
	{
		\IPS\Dispatcher::i()->checkAcpPermission( 'sync_manage' );
		parent::execute();
	}

	public function manage(){

	    $class = $this->nodeClass;
	    $top = $class::topElements();
        \IPS\Output::i()->sidebar[ 'actions' ][ 'sync' ] = [
            'icon'  => 'refresh',
            'title' => 'Sync',
            'link'  => \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=sync&do=sync' ),
        ];
	    \IPS\Output::i()->output .= $top;
	    parent::manage();


    }
}<file_sep>/hooks/coreModAdminAppDev.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_coreModAdminAppDev extends _HOOK_CLASS_
{
    public function execute( $command = 'do' )
    {
        \IPS\Output::i()->jsVars[ 'storm_table_url' ] = (string) \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=settings' );
        parent::execute( $command );
    }

    public function addVersionQuery()
    {
        \IPS\Output::i()->jsFiles = array_merge(
            \IPS\Output::i()->jsFiles,
            \IPS\Output::i()->js(
                'admin_query.js',
                'storm',
                'admin'
            )
        );

        $tables = \IPS\Db::i()->query( "SHOW TABLES" );
        $t = [];
        $t[ 0 ] = "Select Table";

        foreach ( $tables as $table ) {
            $foo = array_values( $table );
            $t[ $foo[ 0 ] ] = $foo[ 0 ];
        }

        $el[ 'prefix' ] = 'storm_query_';

        $el[] = [
            'name'     => "select",
            'class'    => "Select",
            'required' => true,
            'ops'      => [
                'options' => [
                    0            => "Select One",
                    "addColumn"  => "Add Column",
                    //                    "changeColumn" => "Change Column",
                    "dropColumn" => "Drop Column",
                    "code"       => "Code Box",
                ],
                'toggles' => [
                    'code'       => [
                        'code',
                    ],
                    'dropColumn' => [
                        'table',
                        'columns',
                    ],
                    'addColumn'  => [
                        'table',
                        'add_column',
                        'type',
                        'length',
                        'decimals',
                        'default',
                        'comment',
                        'allow_null',
                        'unsigned',
                        'zerofill',
                        'auto_increment',
                        'binary',
                        'binary',
                        'values',
                    ],
                    //                    'changeColumn' => [
                    //                        'table',
                    //                        'columns'
                    //                    ],
                ],
            ],
        ];

        $val = function ( $val ) {
            /* Check it starts with \IPS\Db::i()-> */
            $val = trim( $val );
            if ( mb_substr( $val, 0, 14 ) !== '\IPS\Db::i()->' ) {
                throw new \DomainException( 'versions_query_start' );
            }

            /* Check there's only one query */
            if ( mb_substr( $val, -1 ) !== ';' ) {
                $val .= ';';
            }
            if ( mb_substr_count( $val, ';' ) > 1 ) {
                throw new \DomainException( 'versions_query_one' );
            }

            /* Check our Regex will be okay with it */
            preg_match( '/^\\\IPS\\\Db::i\(\)->(.+?)\(\s*[\'"](.+?)[\'"]\s*(,\s*(.+?))?\)\s*;$/', $val, $matches );
            if ( empty( $matches ) ) {
                throw new \DomainException( 'versions_query_format' );
            }

            /* Run it if we're adding it to the current working version */
            if ( \IPS\Request::i()->id == 'working' ) {
                try {
                    try {
                        if ( @eval( $val ) === false ) {
                            throw new \DomainException( 'versions_query_phperror' );
                        }
                    } catch ( \ParseError $e ) {
                        throw new \DomainException( 'versions_query_phperror' );
                    }
                } catch ( \IPS\Db\Exception $e ) {
                    throw new \DomainException( $e->getMessage() );
                }
            }
        };

        $el[] = [
            'name'     => 'code',
            'class'    => "TextArea",
            'default'  => '\IPS\Db::i()->',
            'required' => true,
            'v'        => $val,
            'ops'      => [
                'size' => 45,
            ],
        ];

        if ( !isset( \IPS\Request::i()->storm_query_code ) or \IPS\Request::i()->storm_query_code != 'code' ) {
            $el[] = [
                'name'     => "table",
                'class'    => "Select",
                'required' => true,
                'ops'      => [
                    'options' => $t,
                    'parse'   => 'raw',
                ],
            ];

            $el[] = [
                'name'        => "columns",
                'customClass' => "\\IPS\\storm\\Forms\\Select",
                'ops'         => [
                    'options' => [

                    ],
                ],
            ];

            $ints = [
                'add_column',
                'length',
                'allow_null',
                'default',
                'comment',
                'sunsigned',
                'zerofill',
                'auto_increment',
            ];

            $decfloat = [
                'add_column',
                'length',
                'decimals',
                'allow_null',
                'default',
                'comment',
                'sunsigned',
                'zerofill',
            ];

            $dates = [
                'add_column',
                'allow_null',
                'default',
                'comment',
            ];

            $char = [
                'add_column',
                'length',
                'allow_null',
                'default',
                'comment',
                'binary',
            ];

            $text = [
                'add_column',
                'allow_null',
                'comment',
                'binary',
            ];

            $binary = [
                'add_column',
                'length',
                'allow_null',
                'default',
                'comment',
            ];

            $blob = [
                'add_column',
                'allow_null',
                'comment',
            ];

            $enum = [
                'add_column',
                'values',
                'allow_null',
                'default',
                'comment',
            ];

            $el[] = [
                'class' => "Select",
                'name'  => "type",
                'ops'   => [
                    'options' => \IPS\Db::$dataTypes,
                    'toggles' => [
                        'TINYINT'    => $ints,
                        'SMALLINT'   => $ints,
                        'MEDIUMINT'  => $ints,
                        'INT'        => $ints,
                        'BIGINT'     => $ints,
                        'DECIMAL'    => $decfloat,
                        'FLOAT'      => $decfloat,
                        'BIT'        => [
                            'columns',
                            'length',
                            'allow_null',
                            'default',
                            'comment',
                        ],
                        'DATE'       => $dates,
                        'DATETIME'   => $dates,
                        'TIMESTAMP'  => $dates,
                        'TIME'       => $dates,
                        'YEAR'       => $dates,
                        'CHAR'       => $char,
                        'VARCHAR'    => $char,
                        'TINYTEXT'   => $text,
                        'TEXT'       => $text,
                        'MEDIUMTEXT' => $text,
                        'LONGTEXT'   => $text,
                        'BINARY'     => $binary,
                        'VARBINARY'  => $binary,
                        'TINYBLOB'   => $blob,
                        'BLOB'       => $blob,
                        'MEDIUMBLOB' => $blob,
                        'BIGBLOB'    => $blob,
                        'ENUM'       => $enum,
                        'SET'        => $enum,

                    ],
                ],
            ];

            $el[] = [
                'name'     => "add_column",
                'required' => true,
                'class'    => "Text",
            ];

            $el[] = [
                'name'  => 'values',
                'class' => 'Stack',
            ];

            $el[] = [
                'name'    => "length",
                'class'   => "Number",
                'default' => 255,
            ];

            $el[] = [
                'name'  => "allow_null",
                'class' => "YesNo",
            ];

            $el[] = [
                'name'  => 'decimals',
                'class' => 'Number',
            ];

            $el[] = [
                'name'  => "default",
                'class' => "TextArea",
            ];

            $el[] = [
                'name'  => "comment",
                'class' => "TextArea",
            ];

            $el[] = [
                'name'  => "sunsigned",
                'class' => "YesNo",
            ];

            $el[] = [
                'name'  => "zerofill",
                'class' => "YesNo",
            ];

            $el[] = [
                'name'  => "auto_increment",
                'class' => "YesNo",
            ];

            $el[] = [
                'name'  => "binary",
                'class' => "YesNo",
            ];

            $el[] = [
                'name'  => 'values',
                'class' => "Stack",
            ];
        }

        $forms = \IPS\storm\Forms::i( $el, null, 'add_version_query', null, null, 'save', null,
                                      [ 'data-controller' => 'storm.admin.query.query' ] );

        /* If submitted, add to json file */
        if ( $vals = $forms->values() ) {
            /* Get our file */
            $version = \IPS\Request::i()->id;
            $json = $this->_getQueries( $version );
            $install = $this->_getQueries( 'install' );
            if ( $vals[ 'storm_query_select' ] != 'code' ) {
                $type = $vals[ 'storm_query_select' ];
                $table = $vals[ 'storm_query_table' ];
                if ( $type == 'dropColumn' ) {
                    $column = $vals[ 'storm_query_columns' ];
                    $json[] = [ 'method' => $type, 'params' => [ $table, $column ] ];
                    \IPS\Db::i()->dropColumn( $table, $column );
                }
                else {
                    $column = $vals[ 'storm_query_add_column' ];
                    $schema = [];
                    $schema[ 'name' ] = $vals[ 'storm_query_add_column' ];
                    $schema[ 'type' ] = $vals[ 'storm_query_type' ];

                    if ( isset( $vals[ 'storm_query_length' ] ) and $vals[ 'storm_query_length' ] ) {
                        $schema[ 'length' ] = $vals[ 'storm_query_length' ];
                    }
                    else {
                        $schema[ 'length' ] = null;
                    }

                    if ( isset( $vals[ 'storm_query_decimals' ] ) and $vals[ 'storm_query_decimals' ] ) {
                        $schema[ 'decimals' ] = $vals[ 'storm_query_decimals' ];
                    }
                    else {
                        $schema[ 'decimals' ] = null;
                    }

                    if ( isset( $vals[ 'storm_query_values' ] ) and \count( $vals[ 'storm_query_values' ] ) ) {
                        $schema[ 'values' ] = $vals[ 'storm_query_values' ];
                    }
                    else {
                        $schema[ 'values' ] = null;
                    }

                    if ( isset( $vals[ 'storm_query_allow_null' ] ) and $vals[ 'storm_query_allow_null' ] ) {
                        $schema[ 'allow_null' ] = true;
                    }
                    else {
                        $schema[ 'allow_null' ] = false;
                    }

                    if ( isset( $vals[ 'storm_query_default' ] ) and $vals[ 'storm_query_default' ] ) {
                        $schema[ 'default' ] = $vals[ 'storm_query_default' ];
                    }
                    else {
                        $schema[ 'default' ] = null;
                    }

                    if ( isset( $vals[ 'storm_query_comment' ] ) and $vals[ 'storm_query_comment' ] ) {
                        $schema[ 'comment' ] = $vals[ 'storm_query_comment' ];
                    }
                    else {
                        $schema[ 'comment' ] = '';
                    }

                    if ( isset( $vals[ 'storm_query_sunsigned' ] ) and $vals[ 'storm_query_sunsigned' ] ) {
                        $schema[ 'unsigned' ] = $vals[ 'storm_query_sunsigned' ];
                    }
                    else {
                        $schema[ 'unsigned' ] = false;
                    }

                    if ( isset( $vals[ 'storm_query_zerofill' ] ) and $vals[ 'storm_query_zerofill' ] ) {
                        $schema[ 'zerofill' ] = $vals[ 'storm_query_zerofill' ];
                    }
                    else {
                        $schema[ 'zerofill' ] = false;
                    }

                    if ( isset( $vals[ 'storm_query_auto_increment' ] ) and $vals[ 'storm_query_auto_increment' ] ) {
                        $schema[ 'auto_increment' ] = $vals[ 'storm_query_auto_increment' ];
                    }
                    else {
                        $schema[ 'auto_increment' ] = false;
                    }

                    if ( isset( $vals[ 'storm_query_binary' ] ) and $vals[ 'storm_query_binary' ] ) {
                        $schema[ 'binary' ] = $vals[ 'storm_query_auto_increment' ];
                    }
                    else {
                        $schema[ 'binary' ] = false;
                    }

                    if ( $type == 'addColumn' ) {
                        $json[] = [ 'method' => $type, 'params' => [ $table, $schema ] ];
                        $install[] = [ 'method' => $type, 'params' => [ $table, $schema ] ];
                        $this->_writeQueries( 'install', $install );
                        \IPS\Db::i()->addColumn( $table, $schema );
                    }
                    else if ( $type == 'changeColumn' ) {
                        $json[] = [ 'method' => $type, 'params' => [ $table, $column, $schema ] ];
                        \IPS\Db::i()->changeColumn( $table, $column, $schema );
                    }
                }

            }
            else {

                /* Work out the different parts of the query */
                $val = trim( $vals[ 'storm_query_code' ] );
                if ( mb_substr( $val, -1 ) !== ';' ) {
                    $val .= ';';
                }

                preg_match( '/^\\\IPS\\\Db::i\(\)->(.+?)\(\s*(.+?)\s*\)\s*;$/', $val, $matches );

                /* Add it on */
                $json[] = [
                    'method' => $matches[ 1 ],
                    'params' => eval( 'return array( ' . $matches[ 2 ] . ' );' ),
                ];
            }

            /* Write it */
            $this->_writeQueries( $version, $json );

            /* Redirect us */
            \IPS\Output::i()
                ->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=versions&root={$version}" ) );
        }

        \IPS\Output::i()->output = $forms;
    }

    protected function addTable()
    {
        $activeTab = \IPS\Request::i()->tab ?: 'new';

        if ( $activeTab === "new" and isset( \IPS\Request::i()->storm_create_class ) and \IPS\Request::i()->storm_create_class !== "select" ) {
            try {
                $queriesJson = $this->_getQueries( 'working' );

                $type = \IPS\Request::i()->storm_create_class;
                $class = \IPS\storm\Classes::i();
                $db = \IPS\Request::i()->database_table_name;
                $prefix = \IPS\Request::i()->storm_class_prefix ?: '';
                $data[ 'storm_class_type' ] = $type;
                $data[ 'storm_class_className' ] = $db;
                $data[ 'storm_class_prefix' ] = $prefix;
                $data[ 'storm_class_database' ] = $this->application->directory . "_" . $db;
                $data[ 'storm_class_item_node_class' ] = \IPS\Request::i()->storm_class_item_node_class ?: '';
                $class->process( $data, $this->application );

                if ( $prefix ) {
                    $prefix = $prefix . "_id";
                }
                else {
                    $prefix = "id";
                }

                $definition = [
                    'name'    => $data[ 'storm_class_database' ],
                    'columns' => [
                        $prefix => [
                            'name'           => $prefix,
                            'type'           => 'BIGINT',
                            'length'         => '20',
                            'unsigned'       => true,
                            'zerofill'       => false,
                            'binary'         => false,
                            'allow_null'     => false,
                            'default'        => null,
                            'auto_increment' => true,
                            'comment'        => \IPS\Member::loggedIn()->language()->get( 'database_default_column_comment' ),
                        ],
                    ],
                    'indexes' => [
                        'PRIMARY' => [
                            'type'    => 'primary',
                            'name'    => 'PRIMARY',
                            'columns' => [ $prefix ],
                            'length'  => [ null ],
                        ],
                    ],
                ];

                /* Create table */
                \IPS\Db::i()->createTable( $definition );

                /* Add to the queries.json file */
                $queriesJson = $this->_addQueryToJson( $queriesJson,
                                                       [ 'method' => 'createTable', 'params' => [ $definition ] ] );
                $this->_writeQueries( 'working', $queriesJson );

                /* Add to schema.json */
                $schema = $this->_getSchema();
                $schema[ $definition[ 'name' ] ] = $definition;
                $this->_writeSchema( $schema );

                /* Redirect */
                \IPS\Output::i()
                    ->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=editSchema&_name={$definition['name']}" ) );
            } catch ( \Exception $e ) {
            }
        }

        parent::addTable();
        $form = new \IPS\Helpers\Form;
        $options = [
            'options' => [
                "select"  => "Select Class Type",
                "ar"      => "ActiveRecord",
                "model"   => "Node",
                "item"    => "Content Item",
                "comment" => "Content Item Comment",
            ],
            'toggles' => [
                'ar'      => [ 'js_storm_class_prefix' ],
                'model'   => [ 'js_storm_class_prefix' ],
                'item'    => [ 'js_storm_class_prefix', 'js_storm_class_item_node_class' ],
                'comment' => [ 'js_storm_class_prefix', 'js_storm_class_item_node_class' ],
            ],

        ];
        $select = new \IPS\Helpers\Form\Select( 'storm_create_class', null, false, $options, '', '', '', '' );
        $prefix = new \IPS\Helpers\Form\Text( 'storm_class_prefix', null, false, [], '', '', '_',
                                              'js_storm_class_prefix' );
        $nodeItemClass = new \IPS\Helpers\Form\Text( 'storm_class_item_node_class', null, false, [], '', '', '',
                                                     'js_storm_class_item_node_class' );
        $output = \IPS\Output::i()->output;
        $add = $select->rowHtml( $form ) . $prefix->rowHtml( $form ) . $nodeItemClass->rowHtml( $form );
        $output = preg_replace( '#<li class=[\'|"](.+?)[\'|"] id=[\'|"]database_table_new_database_table_name[\'|"]>#mu',
                                $add . '<li class="$1" id="database_table_new_database_table_name">', $output );

        \IPS\Output::i()->output = $output;
    }

    protected function _manageClass()
    {
        return \IPS\storm\Classes::i()->form();
    }

    protected function _manageDevFolder()
    {
        return \IPS\storm\Classes\DevFolder::i()->form();
    }

    protected function _writeJson( $file, $data )
    {
        if( $file == \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/settings.json" ){
            \IPS\storm\Proxyclass::i()->generateSettings();
        }

        parent::_writeJson( $file, $data );
    }

}
<file_sep>/sources/Settings/Settings.php
<?php

/**
 * @brief       Settings Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.0
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Settings extends \IPS\Patterns\Singleton
{
    protected static $instance = null;

    public static function mbUcfirst( $string )
    {
        return mb_strtoupper( mb_substr( $string, 0, 1 ) ) . mb_substr( $string, 1 );
    }

    public static function buildCss( $css )
    {
        if( \IPS\Data\Store::i()->exists( 'dev_css' ) )
        {
            \IPS\Data\Store::i()->delete( 'dev_css' );
        }

        $url = null;
        $files = [];

        foreach( $css as $c )
        {
            $data = \IPS\Http\Url::external( $c );
            $files[] = $data->queryString[ 'css' ];
        }

        \IPS\Data\Store::i()->dev_css = $files;

        return str_replace( [ 'http://', 'https://' ], '//',
                \IPS\Settings::i()->base_url ) . "applications/storm/interface/css/css.php";
    }

    public static function form()
    {
        $s = \IPS\Settings::i();
        $form = \IPS\storm\Forms::i( static::elements(), $s );

        if( $vals = $form->values() )
        {

            $form->saveAsSettings( $vals );
            \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=settings' ) );
        }

        return $form;
    }

    protected static function elements()
    {
        $e[] = [
            'class' => "YesNo",
            'name' => "storm_settings_tab_debug_templates",
            'tab' => 'general'
        ];

        $e[] = [
            'class' => "YesNo",
            'name' => "storm_settings_tab_debug_css"
        ];

        $e[] = [
            'class' => "YesNo",
            'name' => "storm_settings_tab_debug_css_alt"
        ];

        $e[] = [
            'class' => "YesNo",
            'name' => 'storm_profiler_is_fixed'
        ];

        $e[] = [
            'class' => 'YesNo',
            'name' => 'storm_settings_disable_menu'
        ];

        return $e;
    }

}
<file_sep>/modules/front/general/general.php
<?php

/**
 * @brief       General Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       2.0.0
 * @version     -storm_version-
 */

namespace IPS\storm\modules\front\general;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * general
 */
class _general extends \IPS\Dispatcher\Controller
{
    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {

        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        // This is the default method if no 'do' parameter is specified
    }

    // Create new methods with the same name as the 'do' parameter which should execute it
    protected function backtrace()
    {
        $bt = \IPS\Request::i()->id;
        $back = [];

        if( \IPS\Data\Store::i()->exists( 'storm_bt' ) )
        {
            $back = \IPS\Data\Store::i()->storm_bt;
        }

        $output = "Nothing found";

        if( isset( $back[ $bt ] ) )
        {
            $bt = $back[ $bt ];
            $bt[ 'backtrace' ] = str_replace( "\\\\", "\\", $bt[ 'backtrace' ] );
            $output = "<code>" . $bt[ 'query' ] . "</code><br><pre class=\"prettyprint lang-php \">" . $bt[ 'backtrace' ] . "</pre>";
        }

        \IPS\Output::i()->output = "<div class='ipsPad'>{$output}</div>";
    }

    protected function cache()
    {
        $bt = \IPS\Request::i()->id;
        $back = [];

        if( \IPS\Data\Store::i()->exists( 'storm_cache' ) )
        {
            $back = \IPS\Data\Store::i()->storm_cache;
        }

        $output = "Nothing found";

        if( isset( $back[ $bt ] ) )
        {
            $bt = $back[ $bt ];
            $bt[ 'backtrace' ] = str_replace( "\\\\", "\\", $bt[ 'backtrace' ] );
            $output = "<div>Type: " . $bt[ 'type' ] . "</div><div>Key: " . $bt[ 'key' ] . "</div><br><pre class='prettyprint lang-php'>" . $bt[ 'backtrace' ] . "</pre>";
        }

        \IPS\Output::i()->output = "<div class='ipsPad'>{$output}</div>";
    }

}
<file_sep>/hooks/multipleRedirect.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_multipleRedirect extends _HOOK_CLASS_
{

    public function __construct( $url, $callback, $finished, $finalRedirect = true )
    {
        if( isset( \IPS\Request::i()->storm ) and \IPS\Request::i()->storm ) {
            $url = $url->setQueryString( [ 'storm' => \IPS\Request::i()->storm ] );
            $finished = function () {
                $path = 'app=storm&module=configuration&controller=plugins';
                $url = \IPS\Http\Url::internal( $path )->setQueryString( [
                        'storm' => \IPS\Request::i()->storm,
                        'do'    => "doDev",
                    ]
                );
                \IPS\Output::i()->redirect($url);
            };
        }

        parent::__construct( $url, $callback, $finished, $finalRedirect );

    }
}
<file_sep>/interface/debug/index.php
<?php
require_once str_replace( 'applications/storm/interface/debug/index.php', '',
        str_replace( '\\', '/', __FILE__ ) ) . 'init.php';
\IPS\Session\Front::i();

//StormDebug::i()->run();
//function quit()
//{
//    \IPS\Output::i()->json(['end' => 1]);
//}
//
//register_shutdown_function('quit');
$max = ( ini_get( 'max_execution_time' ) / 2 ) - 5;
$time = time();

while( true )
{

    $ct = time() - $time;
    if( $ct >= $max )
    {
        \IPS\Output::i()->json( [ 'end' => 1 ] );
    }

    $query = \IPS\Db::i()->select( '*', 'storm_debug', [ 'debug_ajax = ?', 1 ], 'debug_id ASC' );

    if( count( $query ) )
    {

        $messages = new \IPS\Patterns\ActiveRecordIterator(
            $query,
            'IPS\storm\Debug'
        );

        $return = [];

        foreach( $messages as $key => $val )
        {
            $msg = $val->dump;
            $decoded = json_decode( $msg, true );

            if( json_last_error() == JSON_ERROR_NONE )
            {
                $msg = $decoded;
            }

            $data = [
                'type' => $val->type,
                'message' => $msg
            ];

            if( $val->bt )
            {
                $data[ 'bt' ] = $val->bt;
            }

            $return[] = $data;
            $val->delete();
        }

        if( is_array( $return ) and count( $return ) )
        {
            \IPS\Output::i()->json( $return );
        }
    }
    else
    {
        sleep( 1 );
        continue;
    }
}<file_sep>/hooks/Theme.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Theme extends _HOOK_CLASS_
{
    static protected $clearDir = true;

    public static function runProcessFunction( $content, $functionName )
    {
        if ( \IPS\Settings::i()->storm_settings_tab_debug_templates ) {
            /* If it's already been built, we don't need to do it again */
            if ( function_exists( 'IPS\Theme\\' . $functionName ) ) {
                return;
            }

            /* Build Function */
            $function = 'namespace IPS\Theme;' . "\n" . $content;
            static::runDebugTemplate( $functionName, $function );
        }
        else {
            parent::runProcessFunction( $content, $functionName );
        }

    }

    protected static function runDebugTemplate( $functionName, $content )
    {
        if ( ( mb_strpos( $functionName, 'css_' ) === false and \IPS\Settings::i()->storm_settings_tab_debug_templates ) or ( mb_strpos( $functionName, 'css_' ) !== false and \IPS\Settings::i()->storm_settings_tab_debug_css ) ) {
            $dir = \IPS\ROOT_PATH . "/StormTemplates";

            if ( !is_dir( $dir ) ) {
                @mkdir( $dir, 0777, true );
            }

            $content = "<?php\n" . $content;
            $chash = md5( $content );
            $fname = str_replace( "/", "_", $functionName );
            $file = $dir . "/" . $fname . ".php";
            $hash = false;
            //$content = preg_replace( "#<!--(.*?)-->#", '', $content );

            if ( file_exists( $file ) ) {
                $hash = md5_file( $file );
            }

            $build = true;

            if ( $hash ) {
                if ( $hash == $chash ) {
                    $build = false;
                }
            }

            if ( $build ) {
                \file_put_contents( $file, $content );
            }

            include_once( $file );
        }
        else {
            return parent::runDebugTemplate( $functionName, $content );
        }
    }

}
<file_sep>/sources/Classes/DevFolder.php
<?php

/**
 * @brief       DevFolder Singleton
 * @author      <a href='http://codingjungle.com'><NAME></a>
 * @copyright   (c) 2017 <NAME>
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     3.0.4
 */

namespace IPS\storm\Classes;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _DevFolder extends \IPS\Patterns\Singleton
{

    /**
     * @brief    [ActiveRecord] Multiton Store
     */
    protected static $instance = null;

    protected $app = null;

    protected $blansk = null;

    public function form()
    {
        $this->app = \IPS\Application::load( \IPS\Request::i()->appKey );
        $this->blanks = \IPS\ROOT_PATH . "/applications/storm/sources/Classes/blanks/";

        $form = \IPS\storm\Forms::i( $this->elements() );

        if( $vals = $form->values() )
        {
            $this->process( $vals );
        }

        return $form;
    }

    protected function elements()
    {
        $e = [];
        $app = $this->app;
        $validate = function( $data )
        {
            if( $data == "select" )
            {
                throw new \InvalidArgumentException( 'storm_classes_type_no_selection' );
            }
        };
        $e[ 'prefix' ] = 'storm_devfolder_';

        $e[] = [
            'class' => "Select",
            'name' => "type",
            'default' => "select",
            'required' => true,
            'validation' => $validate,
            'appearRequired' => true,
            'options' => [
                'options' => $this->classTypes(),
                'toggles' => $this->toggles(),
            ],
        ];

        $e[] = [
            'class' => "Select",
            'name' => 'loc',
            'appearRequired' => true,
            'validation' => function( $data )
            {
                if( $data == "select" )
                {
                    throw new \InvalidArgumentException( 'storm_devfolder_loc_error' );
                }
            },
            'options' => [
                'options' => [ 'select' => "Select", 'admin' => 'Admin', 'front' => "Front", 'global' => "Global" ]
            ]
        ];

        $e[] = [
            'class' => "Text",
            'name' => 'group',
            'appearRequired' => true,
            'validation' => function( $data )
            {
                if( !$data )
                {
                    throw new \InvalidArgumentException( 'storm_devfolder_group_error' );
                }
            }
        ];

        $fileValidation = function( $data ) use ( $app )
        {
            if( !$data )
            {
                throw new \InvalidArgumentException( 'storm_devfolder_filename_error' );
            }

            $devFolder = \IPS\ROOT_PATH . "/applications/{$app->directory}/dev/";
            $file = "{$data}";
            $type = \IPS\Request::i()->storm_devfolder_type;
            $loc = \IPS\Request::i()->storm_devfolder_loc;
            $group = \IPS\Request::i()->storm_devfolder_group;

            if( $type === "template" )
            {
                $location = '/' . $loc . '/' . $group . '/';
                $dir = $devFolder . "html" . $location;
                $fileName = $dir . "{$file}.phtml";
            }
            $js = [
                'jsModule',
                'jsWidget',
                'jsController'
            ];
            if( in_array( $type, $js ) )
            {
                $location = "/" . $loc . "/controllers/" . $group . "/";
                $dir = $devFolder . "js" . $location;
                $fileName = $dir . "{$file}.js";
            }

            if( in_array( $type, $js ) )
            {
                $location = "/" . $loc . "/controllers/" . $group . "/";
                $dir = $devFolder . "js" . $location;

                if( !file_exists( $dir ) )
                {
                    \mkdir( $dir, 0777, true );
                }

                $module = "ips.{$app->directory}.{$file}";
                $fileName = $dir . $module . ".js";

                if( $type === "jsController" )
                {
                    $fileName = "ips." . $group . $file . ".js";
                }
            }

            if( file_exists( $fileName ) )
            {
                throw new \InvalidArgumentException( 'storm_devfolder_filename_exist' );
            }
        };

        $e[] = [
            'class' => "Text",
            'name' => 'filename',
            'appearRequired' => true,
            'validation' => $fileValidation
        ];

        $e[] = [
            'class' => "Text",
            'name' => 'widgetname',
            'appearRequired' => true,
            'validation' => function( $data )
            {
                if( !$data )
                {
                    throw new \InvalidArgumentException( 'storm_devfolder_widgetname_error' );
                }
            }
        ];

        $e[] = [
            'class' => "Stack",
            'name' => "args"
        ];

        return $e;
    }

    protected function classTypes()
    {
        return [
            'select' => "Select",
            'template' => "Template",
            'jsWidget' => "JS Widget",
            'jsModule' => "JS Module",
            'jsController' => "JS Controller"
        ];
    }

    protected function toggles()
    {
        return [
            'template' => [
                'args',
                'loc',
                'group',
                'filename'
            ],
            'jsModule' => [
                'loc',
                'group',
                'filename'
            ],
            'jsWidget' => [
                'loc',
                'group',
                'filename',
                'widgetname'
            ],
            'jsController' => [
                'loc',
                'group',
                'filename'
            ],
        ];
    }

    protected function process( $vals )
    {
        $app = $this->app;
        $blanks = $this->blanks;
        $devFolder = \IPS\ROOT_PATH . "/applications/{$app->directory}/dev/";
        $file = "{$vals['storm_devfolder_filename']}";

        if( $vals[ 'storm_devfolder_type' ] === "template" )
        {
            $location = "/{$vals['storm_devfolder_loc']}/{$vals['storm_devfolder_group']}/";
            $dir = $devFolder . "html" . $location;
            if( !file_exists( $dir ) )
            {
                \mkdir( $dir, 0777, true );
            }
            $fileName = $dir . "{$file}.phtml";
            $args = [];

            if( is_array( $vals[ 'storm_devfolder_args' ] ) )
            {
                foreach( $vals[ 'storm_devfolder_args' ] as $v )
                {
                    $args[] = "$" . str_replace( "$", "", $v );
                }

                $args = implode( ",", $args );
            }
            else
            {
                $args = '';
            }

            $content = \file_get_contents( $blanks . "template.txt" );
            $content = str_replace( "#args#", $args, $content );
        }

        $js = [
            'jsModule',
            'jsWidget',
            'jsController'
        ];

        if( in_array( $vals[ 'storm_devfolder_type' ], $js ) )
        {
            $location = "/{$vals['storm_devfolder_loc']}/controllers/{$vals['storm_devfolder_group']}/";
            $dir = $devFolder . "js" . $location;

            if( !file_exists( $dir ) )
            {
                \mkdir( $dir, 0777, true );
            }

            $module = "ips.{$app->directory}.{$file}";
            $fileName = $dir . $module . ".js";

            if( $vals[ 'storm_devfolder_type' ] === "jsModule" or $vals[ 'storm_devfolder_type' ] === "jsController" )
            {
                if( $vals[ 'storm_devfolder_type' ] === "jsModule" )
                {
                    $content = \file_get_contents( $blanks . "jsModule.txt" );
                }
                else if( $vals[ 'storm_devfolder_type' ] === "jsController" )
                {
                    $module = "{$app->directory}.{$vals['storm_devfolder_loc']}.{$vals['storm_devfolder_group']}.{$file}";
                    $fileName = $dir . "ips.{$vals['storm_devfolder_group']}.{$file}.js";
                    $content = \file_get_contents( $blanks . "jsController.txt" );
                }

                $content = str_replace( "#module#", $module, $content );
            }
            else if( $vals[ 'storm_devfolder_type' ] === "jsWidget" )
            {
                $content = \file_get_contents( $blanks . "jsWidget.txt" );
                $content = str_replace( [ '#widget#', '#widgetname#' ],
                    [ $module, $vals[ 'storm_devfolder_widgetname' ] ], $content );
            }
        }

        $msg = \IPS\Member::loggedIn()->language()->addToStack( 'created', false, [ 'sprintf' => [ $fileName ] ] );
        \file_put_contents( $fileName, $content );
        \chmod( $fileName, 0777 );
        \IPS\Output::i()
                   ->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$app->directory}&tab=DevFolder" ),
                       $msg );
    }
}
<file_sep>/sources/Debug/Debug.php
<?php

/**
 * @brief       Debug Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.3
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Debug extends \IPS\Patterns\ActiveRecord
{

    /**
     * @brief    [ActiveRecord] Database table
     */
    public static $databaseTable = 'storm_debug';

    /**
     * @brief    [ActiveRecord] Database Prefix
     */
    public static $databasePrefix = "debug_";

    /**
     * @brief    [ActiveRecord] ID Database Column
     */
    public static $databaseColumnId = 'id';

    /**
     * @brief    [ActiveRecord] Multiton Store
     */
    protected static $multitons;

    /**
     * @brief    [ActiveRecord] Database ID Fields
     */
    protected static $databaseIdFields = [ 'debug_id' ];

    /**
     * @brief    Bitwise keys
     */
    protected static $bitOptions = [];

    protected static $clear = true;

    public static function both(
        $message,
        $logType = null,
        $consoleType = "type",
        $includeBackTrace = false,
        $file = null,
        $dir = null
    ) {
        static::console( $message, $consoleType, $includeBackTrace );
        static::log( $message, $logType, $file, $dir );
    }

    public static function console( $message, $type = "log", $includeBackTrace = false )
    {
        if( defined( 'CJ_STORM_DEBUG' ) and CJ_STORM_DEBUG )
        {
            if( !$message )
            {
                return;
            }

            $debug = new static;

            if( is_array( $message ) )
            {
                $message = json_encode( $message );
            }
            $debug->time = time();
            $debug->dump = $message;
            $debug->type = $type;

            if( $includeBackTrace )
            {
                $debug->bt = ( new \Exception )->getTraceAsString();
            }

            $debug->save();
        }
    }

    public static function log( $message, $type = null, $file = null, $dir = null )
    {
        if( defined( 'CJ_STORM_DEBUG' ) and CJ_STORM_DEBUG )
        {
            if( !$message )
            {
                return;
            }

            $date = date( 'r' );

            if( $message instanceof \Exception )
            {
                $message = $date . "\n" . get_class( $message ) . '::' . $message->getCode() . "\n" . $message->getMessage() . "\n" . $message->getTraceAsString();
            }
            else
            {
                if( is_array( $message ) )
                {
                    $message = var_export( $message, true );
                }

                $message = $date . "\n" . $message . "\n" . ( new \Exception )->getTraceAsString();
            }

            if( $dir == null )
            {
                $dir = \IPS\ROOT_PATH . "/uploads/logs";
            }
            else
            {
                if( mb_strpos( $dir, \IPS\ROOT_PATH ) === false )
                {
                    $dir = \IPS\ROOT_PATH . "/" . $dir;
                }
            }

            if( !is_dir( $dir ) )
            {
                if( !@mkdir( $dir ) or !@chmod( $dir, \IPS\IPS_FOLDER_PERMISSION ) )
                {
                    return;
                }
            }

            if( $file == null )
            {
                $type = ( $type ) ? "_{$type}" : "";
                $file = $dir . '/' . date( 'Y' ) . '_' . date( 'm' ) . '_' . date( 'd' ) . $type;
            }
            else
            {
                $type = ( $type ) ? "_{$type}" : "";
                $file = $dir . '/' . $file . $type;
            }

            if( file_exists( $file ) )
            {
                @\file_put_contents( $file, "\n\n-------------\n\n" . $message, FILE_APPEND );
            }
            else
            {
                @\file_put_contents( $file, $message );
            }

            @chmod( $file, \IPS\IPS_FILE_PERMISSION );
        }
    }

    public static function returnLog()
    {
        $return = [];

        $return[] = "<script>";

        $query = \IPS\Db::i()->select( '*', 'storm_debug', [ 'debug_ajax = ?', 0 ], 'debug_id ASC' );

        if( count( $query ) )
        {
            $messages = new \IPS\Patterns\ActiveRecordIterator(
                $query,
                'IPS\storm\Debug'
            );

            foreach( $messages as $key => $val )
            {
                switch( $val->type )
                {
                    default:
                    case 'log':
                        $return[] = "console.log('{$val->dump}');";
                        break;
                    case 'debug':
                        $return[] = "console.debug('{$val->dump}');";
                        break;
                    case 'dir':
                        $return[] = "console.dir('{$val->dump}');";
                        break;
                    case 'dirxml':
                        $return[] = "console.dirxml('{$val->dump}');";
                        break;
                    case 'error':
                        $return[] = "console.error('{$val->dump}');";
                        break;
                    case 'info':
                        $return[] = "console.info('{$val->dump}');";
                        break;
                }

                if( $val->bt )
                {
                    $return[] = "console.log('{$val->bt}');";
                }

                $val->delete();
            }
        }

        $return[] = "</script>";

        return implode( "\n", $return );
    }

    public static function ajax( $msg, $type = "log", $includeBackTrace = false )
    {
        if( defined( 'CJ_STORM_DEBUG' ) and CJ_STORM_DEBUG )
        {
            if( !$msg )
            {
                return;
            }

            $debug = new static;

            if( is_array( $msg ) )
            {
                $msg = json_encode( $msg );
            }

            $debug->dump = $msg;
            $debug->type = $type;
            $debug->ajax = 1;
            $debug->time = time();

            if( $includeBackTrace )
            {
                $debug->bt = ( new \Exception )->getTraceAsString();
            }

            $debug->save();
        }
    }
}<file_sep>/modules/admin/configuration/menu.php
<?php

/**
 * @brief       Menu Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       3.0.2
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * menu
 */
class _menu extends \IPS\Node\Controller
{
	/**
	 * Node Class
	 */
	protected $nodeClass = '\IPS\storm\Menu';
	
	/**
	 * Execute
	 *
	 * @return	void
	 */
	public function execute()
	{
		\IPS\Dispatcher::i()->checkAcpPermission( 'menu_manage' );
		parent::execute();
	}

	protected function foo(){
        $sql = \IPS\Db::i()->select( '*', 'storm_menu', null, 'menu_order asc' );
        $menus = new \IPS\Patterns\ActiveRecordIterator( $sql, 'IPS\storm\Menu');
        $store = [];
        foreach( $menus as $menu ){
            $store[ $menu->parent ][] = $menu->foo();
        }

        print_r( json_encode( $store ) );exit;
    }
    protected function reorder()
    {
        $parent = parent::reorder();

        if (\IPS\Request::i()->isAjax()) {
            \IPS\storm\Menu::kerching();
        }

        return $parent;
    }
}<file_sep>/hooks/Log.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Log extends _HOOK_CLASS_
{

    public static function log( $message, $category = null )
    {

        if ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) {
            \IPS\storm\Profiler::i()->log( $message, $category );
        }

        return parent::log( $message, $category );

    }
}
<file_sep>/hooks/AbstractData.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

abstract class storm_hook_AbstractData extends _HOOK_CLASS_
{
    protected $closedKeys = [
        'storm_bt',
        'storm_cache',
    ];

    public function __get( $key )
    {
        if ( ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) ) {

            if ( !isset( $this->_data[ $key ] ) ) {
                if ( $this->exists( $key ) ) {
                    $cache = $this->get( $key );
                    $value = json_decode( $cache, true );

                    if ( !in_array( $key, $this->closedKeys ) ) {
                        \IPS\storm\Profiler::i()->cacheLog( [
                                                                'type'      => 'get',
                                                                'key'       => $key,
                                                                //                            'cache' => var_export($cache, TRUE),
                                                                'backtrace' => var_export( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), true ),
                                                            ] );
                    }
                    $this->_data[ $key ] = $value;
                }
                else {
                    throw new \OutOfRangeException;
                }
            }

            return $this->_data[ $key ];
        }

        return parent::__get( $key );
    }

    public function __set( $key, $value )
    {
        if ( ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) ) {
            if ( !in_array( $key, $this->closedKeys ) ) {
                \IPS\storm\Profiler::i()->cacheLog( [
                                                        'type'      => 'set',
                                                        'key'       => $key,
                                                        //                    'cache' => var_export($value, TRUE),
                                                        'backtrace' => var_export( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), true ),
                                                    ] );
            }
        }

        parent::__set( $key, $value );
    }

    public function storeWithExpire( $key, $value, \IPS\DateTime $expire, $fallback = false )
    {
        if ( ( ( defined( 'CJ_STORM_PROFILER' ) and CJ_STORM_PROFILER ) or ( defined( 'CJ_STORM_PROFILER_SAFE_MODE' ) and CJ_STORM_PROFILER_SAFE_MODE and \IPS\storm\Profiler::profilePassCheck() ) ) ) {
            if ( !in_array( $key, $this->closedKeys ) ) {
                \IPS\storm\Profiler::i()->cacheLog( [
                                                        'type'      => 'set',
                                                        'key'       => $key,
                                                        //                    'cache' => var_export($value, TRUE),
                                                        'backtrace' => var_export( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ) ),
                                                    ] );
            }
        }

        parent::storeWithExpire( $key, $value, $expire, $fallback );
    }
}
<file_sep>/interface/logs/logs.php
<?php
require_once str_replace( 'applications/storm/interface/logs/logs.php', '',
        str_replace( '\\', '/', __FILE__ ) ) . 'init.php';
\IPS\Session\Front::i();
$max = ( ini_get( 'max_execution_time' ) / 2 );
$time = (int)\IPS\Request::i()->time;
$alttime = time();

while( true )
{
    $ct = ( time() - $alttime );
    if( $ct >= $max )
    {
        \IPS\Output::i()->json( [ 'error' => 1, 'end' => $alttime, 'time' => time(), 'ct' => $ct ] );
    }
    $logs = '';
    $query = \IPS\Db::i()->select( '*', "core_log", [ 'time >= ? ', $time ], 'id desc' );

    if( count( $query ) )
    {
        $sql = new \IPS\Patterns\ActiveRecordIterator(
            $query,
            'IPS\Log'
        );
        $count = 0;
        foreach( $sql as $log )
        {
            $msg = \IPS\storm\Profiler\Template::i()
                                               ->consoleContainer( 'Log',
                                                   \IPS\storm\Profiler\Template::i()->logObj( $log ), "IPS Log",
                                                   \IPS\storm\Profiler::i()->oddEven( $log->id ) );

            $logs = $msg . "\n" . $logs;
            $count++;
        }

        $logs = [
            'html' => $logs,
            'time' => time() + 1,
            'count' => $count
        ];

        \IPS\Output::i()->json( $logs );
    }
    else
    {
        sleep( 1 );
        continue;
    }
}
<file_sep>/modules/admin/configuration/plugins.php
<?php

/**
 * @brief       Plugins Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.8
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _plugins extends \IPS\Dispatcher\Controller
{
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'plugins_manage' );
        parent::execute();
    }

    protected function manage()
    {

        $el = [
            [
                'name' => "storm_plugin_upload",
                'class' => "Upload",
                "required" => true,
                "options" => [
                    'allowedFileTypes' => [ 'xml' ],
                    'temporary' => true,
                ],
            ]
        ];

        $form = \IPS\storm\Forms::i( $el );

        if( $vals = $form->values() )
        {

            $xml = new \IPS\Xml\XMLReader;

            $xml->open( $vals[ 'storm_plugin_upload' ] );

            if( !@$xml->read() )
            {
                \IPS\Output::i()->error( 'xml_upload_invalid', '2C145/D', 403, '' );
            }
            try
            {
                \IPS\Db::i()->select( 'plugin_id', 'core_plugins', [
                    'plugin_name=? AND plugin_author=?',
                    $xml->getAttribute( 'name' ),
                    $xml->getAttribute( 'author' )
                ] )->first();

                $tempFileStir = tempnam( \IPS\TEMP_DIRECTORY, 'IPSStorm' );
                move_uploaded_file( $vals[ 'storm_plugin_upload' ], $tempFileStir );
                \IPS\Output::i()->redirect( $this->url->setQueryString( [
                    'do' => "doDev",
                    'storm' => $tempFileStir
                ] ) );
            }
            catch( \UnderflowException $e )
            {
                $tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
                move_uploaded_file( $vals[ 'storm_plugin_upload' ], $tempFile );
                $secondTemp = tempnam( \IPS\TEMP_DIRECTORY, "Storm" );
                copy( $tempFile, $secondTemp );
                $url = \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins&do=doInstall' )
                                    ->setQueryString( [
                                        'file' => $tempFile,
                                        'key' => md5_file( $tempFile ),
                                        'storm' => $secondTemp
                                    ] );

                if( isset( \IPS\Request::i()->id ) )
                {
                    $url = $url->setQueryString( 'id', \IPS\Request::i()->id );
                }

                \IPS\Output::i()->redirect( $url );
            }
        }

        \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'storm_plugins_title' );

        \IPS\Output::i()->output = $form;
    }

    protected function doDev()
    {
        \IPS\storm\Plugins::i()->finish( \IPS\Request::i()->storm );
    }
}<file_sep>/sources/Headerdoc/Headerdoc.php
<?php

/**
 * @brief       Headerdoc Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.0
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Headerdoc extends \IPS\Patterns\Singleton
{

    public static $instance = null;

    public function addIndexHtml( \IPS\Application $app )
    {
        $continue = false;

        foreach( $app->extensions( 'storm', 'Headerdoc' ) as $class )
        {
            if( method_exists( $class, 'indexEnabled' ) )
            {
                $continue = $class->indexEnabled();
            }
        }

        if( !$continue )
        {
            return;
        }

        $dir = \IPS\ROOT_PATH . "/applications/" . $app->directory;

        $exclude = [
            '.git',
            '.idea',
            'dev'
        ];

        $filter = function( $file, $key, $iterator ) use ( $exclude )
        {
            if( !\in_array( $file->getFilename(), $exclude ) )
            {
                return true;
            }

            return false;
        };

        $dirIterator = new \RecursiveDirectoryIterator(
            $dir,
            \RecursiveDirectoryIterator::SKIP_DOTS
        );

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveCallbackFilterIterator( $dirIterator, $filter ),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        foreach( $iterator as $iter )
        {
            if( $iter->isDir() )
            {
                $path = $iter->getPathname();
                if( !file_exists( $path . "/index.html" ) )
                {
                    \file_put_contents( $path . "/index.html", '' );
                }
            }
        }
    }

    public function process( \IPS\Application $app )
    {

        if( !$this->can( $app ) )
        {
            return;
        }

        $dir = \IPS\ROOT_PATH . "/applications/" . $app->directory;

        $subpackage = \IPS\Member::loggedIn()->language()->get( "__app_{$app->directory}" );

        $exclude = [
            'hooks',
            'dev',
            'data',
            '3rdparty',
            '3rd_party',
            'vendor',
            '.git',
            '.idea'
        ];

        $since = $app->version;

        foreach( $app->extensions( 'storm', 'Headerdoc' ) as $class )
        {
            if( method_exists( $class, 'headerDocExclude' ) )
            {
                $exclude = array_merge( $exclude, $class->headerDocExclude() );
            }

            $reflector = new \ReflectionMethod( $class, 'since' );

            $isProto = ( $reflector->getDeclaringClass()->getName() !== get_class( $class ) );

            if( $isProto )
            {
                $since = $class->since( $app );
            }
        }

        $filter = function( $file, $key, $iterator ) use ( $exclude )
        {
            if( !\in_array( $file->getFilename(), $exclude ) )
            {
                return true;
            }

            return false;
        };

        $dirIterator = new \RecursiveDirectoryIterator(
            $dir,
            \RecursiveDirectoryIterator::SKIP_DOTS
        );

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveCallbackFilterIterator( $dirIterator, $filter ),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        $iterator = new \RegexIterator( $iterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH );

        $regEx = '#(?:(?<!\w))(?:[^\w]|\s+)(?:(?:(?:abstract|final|static)\s+)*)(class|trait)\s+([-a-zA-Z0-9_]+)(?:\s+extends\s+([^\s]+))?#';

        foreach( $iterator as $file )
        {
            try
            {
                $filePath = $file[ 0 ];

                $line = \file_get_contents( $filePath );

                preg_match( "#^.+?\s(?=namespace)#s", $line, $section );

                if( isset( $section[ 0 ] ) )
                {
                    preg_match( '#@since([^\n]+)?#', $section[ 0 ], $sinced );
                }
                else
                {
                    $sinced = [];
                }

                if( !isset( $sinced[ 1 ] ) )
                {

                    preg_match( "#^.+?\s(?=namespace)#s", $line, $section );

                    if( isset( $section[ 0 ] ) )
                    {
                        preg_match( '#@brief([^\n]+)?#', $section[ 0 ], $brief );
                    }
                    else
                    {
                        $brief = [];
                    }

                    if( !isset( $brief[ 1 ] ) )
                    {
                        $path = pathinfo( $filePath );

                        $type = $path[ 'dirname' ];

                        $type = str_replace( '\\', '/', $type );

                        $file = $path[ 'filename' ];

                        if( \mb_strpos( $filePath, "extensions" ) !== false )
                        {
                            $type = explode( '/', $type );
                            $extension = \IPS\storm\Settings::mbUcfirst( mb_strtolower( array_pop( $type ) ) );
                            $extApp = \IPS\storm\Settings::mbUcfirst( mb_strtolower( array_pop( $type ) ) );
                            $brief = $extApp . " " . $extension . " extension: " . \IPS\storm\Settings::mbUcfirst( $file );
                        }
                        else
                        {
                            $file = \IPS\storm\Settings::mbUcfirst( $file );

                            \preg_match(
                                $regEx,
                                $line,
                                $matches
                            );

                            if( isset( $matches[ 3 ] ) )
                            {
                                $brief = ( \mb_strpos( $matches[ 3 ],
                                        "Model" ) !== false ) ? $file . " Node" : $file . " Class";
                            }
                            else
                            {
                                $brief = $file;
                                $brief .= ( isset( $matches[ 1 ] ) ) ? " " . \IPS\storm\Settings::mbUcfirst( $matches[ 1 ] ) : " Class";
                            }
                        }

                        $brief = \trim( $brief );
                    }
                    else
                    {
                        $brief = str_replace( ' ', '', trim( $brief[ 1 ] ) );
                    }

                    $replacement = <<<EOF
/**
 * @brief       {$brief}
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  {$subpackage}
 * @since       {$since}
 * @version     -storm_version-
 */
EOF;
                    $line = \preg_replace( "#^.+?\s(?=namespace)#s", "<?php\n\n$replacement\n\n", $line );

                    \file_put_contents( $filePath, $line );
                }
                else
                {

                    $write = false;

                    $line = preg_replace_callback( "#^.+?\s(?=namespace)#s", function( $m ) use ( &$write, $since )
                    {
                        $line = $m[ 0 ];

                        //
                        preg_match( '#@since([^\n]+)?#', $line, $since );

                        if( isset( $since[ 1 ] ) and trim( $since[ 1 ] ) == '-storm_since_version-' )
                        {
                            $write = true;

                            $since = <<<EOF
@author      {$since}
EOF;

                            $line = preg_replace( '#@author([^\n]+)?#', $since, $line );
                        }
                        //author
                        preg_match( '#@author([^\n]+)?#', $line, $auth );

                        if( isset( $auth[ 1 ] ) and trim( $auth[ 1 ] ) != '-storm_author-' )
                        {
                            $write = true;

                            $author = <<<EOF
@author      -storm_author-
EOF;

                            $line = preg_replace( '#@author([^\n]+)?#', $author, $line );
                        }

                        //version
                        preg_match( '#@version([^\n]+)?#', $line, $ver );

                        if( isset( $ver[ 1 ] ) and trim( $ver[ 1 ] ) != '-storm_version-' )
                        {
                            $write = true;

                            $ver = <<<EOF
@version     -storm_version-
EOF;

                            $line = preg_replace( '#@version([^\n]+)?#', $ver, $line );
                        }

                        //copyright
                        preg_match( '#@copyright([^\n]+)?#', $line, $cp );

                        if( isset( $cp[ 1 ] ) and trim( $cp[ 1 ] ) != '-storm_copyright-' )
                        {
                            $write = true;

                            $cpy = <<<EOF
@copyright   -storm_copyright-
EOF;

                            $line = preg_replace( '#@copyright([^\n]+)?#', $cpy, $line );
                        }

                        return $line;
                    }, $line );

                    if( $write )
                    {
                        \file_put_contents( $filePath, $line );
                    }
                }
            }
            catch( \Exception $e )
            {
            }
        }
    }

    public function can( $app )
    {
        $continue = false;

        foreach( $app->extensions( 'storm', 'Headerdoc' ) as $class )
        {
            if( method_exists( $class, 'headerDocEnabled' ) )
            {
                $continue = $class->headerDocEnabled();
            }
        }

        return $continue;
    }
}<file_sep>/modules/admin/configuration/proxyclass.php
<?php

/**
 * @brief       Proxyclass Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.9
 * @version     -storm_version-
 */

namespace IPS\storm\modules\admin\configuration;

/* To prevent PHP errors (extending class does not exist) revealing path */
if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * Proxyclass
 */
class _proxyclass extends \IPS\Dispatcher\Controller
{

    /**
     * Execute
     *
     * @return    void
     */
    public function execute()
    {
        \IPS\Dispatcher::i()->checkAcpPermission( 'Proxyclass_manage' );
        parent::execute();
    }

    /**
     * ...
     *
     * @return    void
     */
    protected function manage()
    {
        \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'storm_proxyclass_title' );
        \IPS\Output::i()->output = \IPS\Theme::i()
                                             ->getTemplate( 'proxyclass', 'storm', 'admin' )
                                             ->button( $this->url->setQueryString( [ 'do' => 'queue' ] ) );
    }

    // Create new methods with the same name as the 'do' parameter which should execute it

    protected function queue()
    {
        \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'storm_proxyclass_title' );

        \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
            \IPS\Http\Url::internal( "app=storm&module=configuration&controller=proxyclass&do=queue" ),
            function( $data )
            {
                if( !isset( $data[ 'total' ] ) )
                {
                    $data = [];
                    $data[ 'total' ] = \IPS\storm\Proxyclass::i()->dirIterator();
                    $data[ 'current' ] = 0;
                    $data[ 'progress' ] = 0;
                }

                $run = \IPS\storm\Proxyclass::i()->run( $data );

                if( $run == null )
                {
                    return null;
                }
                else
                {
                    $progress = isset( $run[ 'progress' ] ) ? $run[ 'progress' ] : 0;

                    if( $run[ 'total' ] and $run[ 'current' ] )
                    {
                        $progress = ( $run[ 'current' ] / $run[ 'total' ] ) * 100;
                    }

                    $language = \IPS\Member::loggedIn()->language()->addToStack( 'storm_proxyclass_progress', false,
                        [ 'sprintf' => [ $run[ 'current' ], $run[ 'total' ] ] ] );

                    return [
                        [
                            'total' => $run[ 'total' ],
                            'current' => $run[ 'current' ],
                            'progress' => $run[ 'progress' ]
                        ],
                        $language,
                        $progress
                    ];
                }
            },
            function()
            {
                /* And redirect back to the overview screen */
                \IPS\Output::i()
                           ->redirect( \IPS\Http\Url::internal( 'app=storm&module=configuration&controller=proxyclass' ),
                               'storm_proxyclass_done' );
            }
        );
    }
}<file_sep>/hooks/Plugin.php
//<?php

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) {
    exit;
}

class storm_hook_Plugin extends _HOOK_CLASS_
{

    public static function addExceptionHandlingToHookFile( $file )
    {
        $hayStack = \file_get_contents( $file );
        $haystack = \str_replace( [ "\n", "\r", "\r\n", "\t", " " ], '', $hayStack );
        $needle = 'method_exists(get_parent_class(),__FUNCTION__)){returncall_user_func_array(\'parent::\'.__FUNCTION__,func_get_args())';

        if ( \mb_strpos( $haystack, $needle ) !== false ) {
            return $hayStack;
        }

        return parent::addExceptionHandlingToHookFile( $file );
    }

    public function save(){
        parent::save();
        \IPS\storm\Proxyclass::i()->generateSettings();
    }
}
<file_sep>/sources/Classes/Classes.php
<?php

/**
 * @brief       Classes Class
 * @author      -storm_author-
 * @copyright   -storm_copyright-
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       1.0.3
 * @version     -storm_version-
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Classes extends \IPS\Patterns\Singleton
{

    public static $instance = null;

    protected $type = null;

    protected $app = null;

    protected $nameSpace = null;

    protected $className = null;

    protected $extends = '';

    protected $implements = '';

    protected $brief = null;

    protected $application = null;

    protected $blanks = null;

    protected $formVersion = "1.0.6";

    protected $prefix = '';

    protected $database = '';

    protected $nodeItemClass = '';

    public function form()
    {
        $app = \IPS\Application::load( \IPS\Request::i()->appKey );
        $form = \IPS\storm\Forms::i( $this->elements( $app ), null, 'classes' );

        if( $vals = $form->values() )
        {
            $this->process( $vals, $app );
            $msg = \IPS\Member::loggedIn()
                              ->language()
                              ->addToStack( 'storm_class_created', false,
                                  [ 'sprintf' => [ $this->type, $this->className ] ] );
            \IPS\Output::i()
                       ->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$app->directory}&tab=class" ),
                           $msg );
        }

        return $form;
    }

    protected function elements( \IPS\Application $app )
    {
        $class = function( $data ) use ( $app )
        {
            $class = \IPS\storm\Settings::mbUcfirst( \IPS\Request::i()->storm_class_namespace );
            $data = \IPS\storm\Settings::mbUcfirst( $data );
            if( $class )
            {
                $ns = "\\IPS\\" . $app->directory . "\\" . $class . "\\" . $data;
            }
            else
            {
                $ns = "\\IPS\\" . $app->directory . "\\" . $data;
            }

            if( $data != "Forms" )
            {
                if( class_exists( $ns ) )
                {
                    throw new \InvalidArgumentException( 'storm_classes_class_no_exist' );
                }
            }
        };

        $extends = function( $data )
        {
            if( $data and !class_exists( $data ) )
            {
                throw new \InvalidArgumentException( 'storm_classes_extended_class_no_exist' );
            }
        };

        $implements = function( $data )
        {
            if( is_array( $data ) and count( $data ) )
            {
                foreach( $data as $implement )
                {
                    if( !class_exists( $implement ) )
                    {
                        throw new \InvalidArgumentException( 'storm_classes_implemented_no_interface' );
                    }
                }
            }
        };

        $validate = function( $data )
        {
            if( $data == "select" )
            {
                throw new \InvalidArgumentException( 'storm_classes_type_no_selection' );
            }
        };

        $classType = [
            'select' => "Select Type",
            'normal' => "Class",
            'singleton' => "Singleton",
            'ar' => "Active Record",
            'model' => "Node",
            'item' => "Content Item",
            'comment' => "Content Item Comment",
            'forms' => "Forms Class",
        ];

        $itemNodeValidation = function( $data ) use ( $app )
        {
            if( $data )
            {
                $class = "IPS\\{$app->directory}\\{$data}";
                if( !class_exists( $class ) )
                {
                    throw new \InvalidArgumentException( 'storm_class_node_item_missing' );
                }
            }
        };

        $toggles = [
            'normal' => [
                'namespace',
                'className',
                'extends',
                'implements',
            ],
            'singleton' => [
                'namespace',
                'className',
                'implements',
            ],
            'ar' => [
                'namespace',
                'className',
                'database',
                'prefix'
            ],
            'model' => [
                'namespace',
                'className',
                'implements',
                'database',
                'prefix'
            ],
            'item' => [
                'namespace',
                'className',
                'implements',
                'item_node_class',
                'database',
                'prefix'
            ],
            'comment' => [
                'namespace',
                'className',
                'implements',
                'item_node_class',
                'database',
                'prefix'
            ],
        ];

        $el = [
            [
                'class' => "Select",
                'name' => "type",
                'default' => "select",
                'required' => true,
                'validation' => $validate,
                'options' => [
                    'options' => $classType,
                    'toggles' => $toggles,
                ],
            ],
            [
                'class' => "Text",
                'name' => 'namespace',
                'options' => [
                    'placeholder' => "Namespace",
                ],
                'prefix' => "IPS\\{$app->directory}\\",
            ],
            [
                'class' => "Text",
                'name' => "className",
                'required' => true,
                'options' => [
                    'placeholder' => 'Class Name',
                ],
                'validation' => $class,
            ],
            [
                'class' => "Text",
                'name' => "database",
                'appearRequired' => true,
                'prefix' => $app->directory . '_',
                'validation' => function( $data )
                {
                    if( !$data )
                    {
                        throw new \InvalidArgumentException( 'storm_classes_no_blank' );
                    }
                }
            ],
            [
                'class' => "Text",
                'name' => "prefix",
                'suffix' => "_"
            ],
            [
                'class' => "Text",
                'name' => "item_node_class",
                'appearRequired' => true,
                'prefix' => "IPS\\{$app->directory}\\",
                'validation' => $itemNodeValidation
            ],
            [
                'class' => "Text",
                'name' => "extends",
                'validation' => $extends,
            ],
            [
                'class' => "Stack",
                'name' => "implements",
                'validation' => $implements,
            ],
        ];
        $el[ 'prefix' ] = 'storm_class_';
        return $el;
    }

    public function process( $data, $app )
    {
        $this->blanks = \IPS\ROOT_PATH . "/applications/storm/sources/Classes/blanks/";
        $this->type = $data[ 'storm_class_type' ];
        $this->application = $app;
        $this->app = \IPS\storm\Settings::mbUcfirst( $app->directory );

        if( isset( $data[ 'storm_class_prefix' ] ) )
        {
            $this->prefix = $data[ 'storm_class_prefix' ] . "_";
        }

        if( isset( $data[ 'storm_class_database' ] ) )
        {
            $this->database = $app->directory.'_'.$data[ 'storm_class_database' ];
        }

        if( isset( $data[ 'storm_class_namespace' ] ) and $data[ 'storm_class_namespace' ] )
        {
            $this->nameSpace = 'IPS\\' . $app->directory . '\\' . $data[ 'storm_class_namespace' ];
        }
        else
        {
            $this->nameSpace = 'IPS\\' . $app->directory;
        }

        if( isset( $data[ 'storm_class_item_node_class' ] ) and $data[ 'storm_class_item_node_class' ] )
        {
            $nic = $data[ 'storm_class_item_node_class' ];
            $this->nodeItemClass = "IPS\\{$app->directory}\\{$nic}";
        }

        if( isset( $data[ 'storm_class_className' ] ) )
        {
            $this->className = \IPS\storm\Settings::mbUcfirst( $data[ 'storm_class_className' ] );
        }
        else
        {
            $this->className = "Forms";
        }

        $ns = $this->nameSpace . "\\" . $this->className;

        if( $this->className != "Forms" )
        {
            if( class_exists( $ns ) )
            {
                return;
            }
        }

        $this->brief = \IPS\storm\Settings::mbUcfirst( $app->directory );

        if( isset( $data[ 'storm_class_extends' ] ) and $data[ 'storm_class_extends' ] )
        {
            $this->extends = "extends " . $data[ 'storm_class_extends' ];
        }

        if( isset( $data[ 'storm_class_implements' ] ) and is_array( $data[ 'storm_class_implements' ] ) and count( $data[ 'storm_class_implements' ] ) )
        {
            //lets loop thru it to add in ln's and lets get rid of any dupes
            foreach( $data[ 'storm_class_implements' ] as $imp )
            {
                $new[ $imp ] = $imp . "\n";
            }

            $this->implements = "implements " . rtrim( implode( ',', $new ) );
        }

        $template = $this->{$this->type}();
        $dir = \IPS\ROOT_PATH . '/applications/' . $app->directory . '/sources/' . $this->getDir();
        $file = $this->className . ".php";
        $toWrite = $dir . '/' . $file;

        if( !file_exists( $dir ) )
        {
            \mkdir( $dir, 0777, true );
        }

        \file_put_contents( $toWrite, $template );
        \chmod( $toWrite, 0777 );
        \IPS\storm\Proxyclass::i()->build( $toWrite );
    }

    protected function getDir()
    {
        $ns = explode( '\\', $this->nameSpace );
        $ns = array_pop( $ns );

        if( $ns == $this->application->directory )
        {
            return $this->className;
        }
        else
        {
            if( $ns != $this->className )
            {
                return $ns;
            }
        }

        return $this->className;
    }

    protected function comment()
    {
        $path = $this->blanks . "comment.txt";

        return $this->build( $path, 'Content Comment Class' );
    }

    protected function build( $path, $brief )
    {
        $content = \file_get_contents( $path );

        return $this->replacementValues( $content, $brief );
    }

    protected function replacementValues( $content, $brief = "Class" )
    {
        $find = [
            '#header#',
            '#brief#',
            '#app#',
            '#applications#',
            '#namespace#',
            '#classname#',
            '#extends#',
            '#implements#',
            '#permtype#',
            '#database#',
            '#prefix#',
            '#nodeItemClass#',
            '#module#'
        ];

        $replacements = [
            $this->buildHeader( $brief ),
            $brief,
            $this->app,
            $this->application->directory,
            $this->nameSpace,
            $this->className,
            $this->extends,
            $this->implements,
            \mb_strtolower( $this->className ),
            $this->database,
            $this->prefix,
            $this->nodeItemClass,
            \mb_strtolower($this->className )
        ];

        return str_replace( $find, $replacements, $content );
    }

    protected function buildHeader( $brief )
    {
        $path = $this->blanks . "header.txt";
        $content = \file_get_contents( $path );
        if( $brief == "Forms Class" )
        {
            $content = str_replace( "*/", "* forms version {$this->formVersion}\n*/", $content );
        }
        return $content;
    }

    protected function item()
    {
        $path = $this->blanks . "item.txt";

        return $this->build( $path, 'Content Item Class' );
    }

    protected function model()
    {
        $path = $this->blanks . "model.txt";

        return $this->build( $path, 'Node' );
    }

    protected function ar()
    {
        $path = $this->blanks . "ar.txt";

        return $this->build( $path, 'Active Record' );
    }

    protected function normal()
    {
        $path = $this->blanks . "normal.txt";

        return $this->build( $path, 'Class' );
    }

    protected function forms()
    {
        $path = $this->blanks . "forms.txt";

        return $this->build( $path, 'Forms Class' );

    }

    protected function singleton()
    {
        $path = $this->blanks . "singleton.txt";

        return $this->build( $path, 'Singleton' );
    }
}
<file_sep>/interface/css/css.php
<?php

require_once '../../../../init.php';

if( \IPS\IN_DEV !== true AND !\IPS\Theme::designersModeEnabled() )
{
    exit();
}

try
{
    /* The CSS is parsed by the theme engine, and the theme engine has plugins, and those plugins need to now which theme ID we're using */
    if( \IPS\Theme::designersModeEnabled() )
    {
        \IPS\Session\Front::i();
    }

    $needsParsing = false;
    $cs = [];
    foreach( \IPS\Data\Store::i()->dev_css as $key => $val )
    {
        if( is_array( $val ) )
        {
            foreach( $val as $k => $v )
            {
                $cs[] = $v;
            }
        }
        else
        {
            $cs[] = $val;
        }
    }
    $cssF = implode( ',', $cs );
    if( strstr( $cssF, ',' ) )
    {
        $contents = '';
        foreach( explode( ',', $cssF ) as $css )
        {
            if( mb_substr( $css, -4 ) !== '.css' )
            {
                continue;
            }
            $names[] = $css;
            $css = str_replace( \IPS\ROOT_PATH, '', $css );
            $css = str_replace( '../', '&#46;&#46;/', $css );
            $file = file_get_contents( \IPS\ROOT_PATH . '/' . $css );
            $params = processFile( $file );

            if( $params[ 'hidden' ] === 1 )
            {
                continue;
            }

            $contents .= "\n" . $file;

            if( needsParsing( $css ) )
            {
                $needsParsing = true;
            }
        }
    }
    else
    {
        if( mb_substr( $cssF, -4 ) !== '.css' )
        {
            exit();
        }
        $names[] = $cssF;
        $contents = file_get_contents( \IPS\ROOT_PATH . '/' . str_replace( '../', '&#46;&#46;/', $cssF ) );

        $params = processFile( $contents );

        if( $params[ 'hidden' ] === 1 )
        {
            exit;
        }

        if( needsParsing( $cssF ) )
        {
            $needsParsing = true;
        }
    }

    if( $needsParsing )
    {
        if( \IPS\Theme::designersModeEnabled() )
        {
            /* If we're in designer's mode, we need to reset the theme ID based on the CSS path as we could be in the ACP which may have a different theme ID set */
            preg_match( '#themes/(\d+)/css/(.+?)/(.+?)/(.*)\.css#', $cssF, $matches );

            if( $matches[ 1 ] and $matches[ 1 ] !== \IPS\Theme::$memberTheme->id )
            {
                try
                {
                    \IPS\Theme::$memberTheme = \IPS\Theme\Advanced\Theme::load( $matches[ 1 ] );
                }
                catch( \OutOfRangeException $ex )
                {
                }
            }
        }
        $names = str_replace( [ '/', '.css', '-' ], '', implode( '', $names ) );
        $functionName = 'css_' . md5( $names );

        $contents = str_replace( '\\', '\\\\', $contents );
        \IPS\Theme::makeProcessFunction( $contents, $functionName );
        $functionName = "IPS\\Theme\\{$functionName}";
        \IPS\Output::i()->sendOutput( $functionName(), 200, 'text/css' );
    }
    else
    {
        \IPS\Output::i()->sendOutput( $contents, 200, 'text/css' );
    }
}
catch( \Exception $e )
{
    \IPS\storm\Debug::log( $e );
}

/**
 * Determine whether this file needs parsing or not
 *
 * @return boolean
 */
function needsParsing( $fileName )
{
    if( \IPS\IN_DEV === true AND !\IPS\Theme::designersModeEnabled() )
    {
        preg_match( '#applications/(.+?)/dev/css/(.+?)/(.*)\.css#', $fileName, $matches );
    }
    else
    {
        preg_match( '#themes/(?:\d+)/css/(.+?)/(.+?)/(.*)\.css#', $fileName, $matches );
    }

    return count( $matches );
}

/**
 * Process the file to extract the header tag params
 *
 * @return array
 */
function processFile( $contents )
{
    $return = [ 'module' => '', 'app' => '', 'pos' => '', 'hidden' => 0 ];

    /* Parse the header tag */
    preg_match_all( '#^/\*<ips:css([^>]+?)>\*/\n#', $contents, $params, PREG_SET_ORDER );
    foreach( $params as $id => $param )
    {
        preg_match_all( '#([\d\w]+?)=\"([^"]+?)"#i', $param[ 1 ], $items, PREG_SET_ORDER );

        foreach( $items as $id => $attr )
        {
            switch( trim( $attr[ 1 ] ) )
            {
                case 'module':
                    $return[ 'module' ] = trim( $attr[ 2 ] );
                    break;
                case 'app':
                    $return[ 'app' ] = trim( $attr[ 2 ] );
                    break;
                case 'position':
                    $return[ 'pos' ] = intval( $attr[ 2 ] );
                    break;
                case 'hidden':
                    $return[ 'hidden' ] = intval( $attr[ 2 ] );
                    break;
            }
        }
    }

    return $return;
}<file_sep>/sources/Generator/Generator.php
<?php

/**
 * @brief       Generator Active Record
 * @author      <a href='http://codingjungle.com'><NAME></a>
 * @copyright   (c) 2017 <NAME>
 * @package     IPS Social Suite
 * @subpackage  Storm
 * @since       -storm_since_version-
 * @version     3.0.4
 */

namespace IPS\storm;

if( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
    header( ( isset( $_SERVER[ 'SERVER_PROTOCOL' ] ) ? $_SERVER[ 'SERVER_PROTOCOL' ] :
            'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

class _Generator extends \IPS\Patterns\ActiveRecord
{
    /**
     * @brief    [ActiveRecord] Database Prefix
     */
    public static $databasePrefix = 'generator_';

    /**
     * @brief    [ActiveRecord] ID Database Column
     */
    public static $databaseColumnId = 'id';

    /**
     * @brief    [ActiveRecord] Database table
     */
    public static $databaseTable = 'storm_generator';

    /**
     * @brief   [ActiveRecord] Database ID Fields
     * @note    If using this, declare a static $multitonMap = array(); in the child class to prevent duplicate loading queries
     */
    protected static $databaseIdFields = [ 'id' ];

    /**
     * @brief   Bitwise keys
     */
    protected static $bitOptions = array();

    /**
     * @brief    [ActiveRecord] Multiton Store
     */
    protected static $multitons;

    public static function create( $type, $id )
    {
        $d = new static;
        $d->type = $type;
        $d->gid = $id;
        $d->save();
    }

    public function process()
    {
        try
        {
            switch( $this->type )
            {
                case "members":
                    $d = \IPS\Member::load( $this->gid );
                    $d->delete();
                    break;
                case "forums":
                    $d = \IPS\forums\Forum::load( $this->gid );
                    $d->delete();
                    break;
                case "topics":
                    $d = \IPS\forums\Topic::load( $this->gid );
                    $d->delete();
                    break;
                case "posts":
                    $d = \IPS\forums\Topic\Post::load( $this->gid );
                    $d->delete();
                    break;
            }
        }
        catch( \Exception $e )
        {
        }

        $this->delete();
    }
}