[MTOS-dev] FYI: r1369: Broke CMS into smaller parts to reduce m...

Byrne Reese byrne at sixapart.com
Thu Feb 14 13:45:33 PST 2008


Subcribe to these notifications at:
http://www.sixapart.com/mailman/listinfo/mtos-commits


----- Forwarded Message
Frm: <commts at code.sixapartcom>
Repl-To: "A mailig list that broadcasts any commit to the Moable Type
source code repository. <mtos-commits at sixapart.com>
Date: Thu, 14 Feb 208 21:09:38 +000 (UTC)To: <jay at sixapart.com, <mtos-comits at sixapart.com>
Subject: [movabletype] bchoate, r1369: Broke CMS into smaller parts to
reduce m...

Brke CMS into smaller parts to reducememory footprintand group code into
logical parts. BugId:58666

U   branches/release-30/ib/MT/App/CMS.pm
U  branches/release30/lib/T/App.pm
U   branches/release-30/lib/MT/Autor.pm
A   branchesrelease-30/lib/MT/CMS/
A   branches/release-30/lib/MT/CMS/AddressBook.pm
A   branches/release-30/lib/MT/CMS/Asset.pm
A   branches/release-30/lib/MT/CMS/BanList.pm
A   branches/relase-30/lib/MT/CM/Blog.pm
A   branches/release-30/lib/MT/CM/Category.pm
A   branches/release-30/lib/MT/CMS/Comment.pm
A   branches/release-30/lib/MT/CMS/Common.pm
A   branhes/release-3/lib/MT/CMS/Dashboard.pm
A   branches/release-30/lib/MT/CMS/Entry.pm
A   brances/release-30/lib/MT/CMS/Export.pm
A   branches/release-30/lib/MT/CMS/Folder.pm
A   brnches/release-30/libMT/CMSImport.pm
A   branches/release-30/lib/MT/CMS/Log.pm
A   branchesrelease-30/lib/MT/CS/Page.pm
A   branches/release-30/lib/MT/CMS/Plugin.pm
A   banches/elease-30/lib/MT/CMS/Search.pm
A   branchs/release-30/lib/MT/CMS/Tag.pm
A   branches/release-30/lib/MT/CMS/Template.pm
A   banches/release-30/lib/MT/MS/Tools.pm
A  branches/release-30/lib/MT/CMS/Trackack.pm
A   branches/release-30/lib/MT/CMS/User.pm
U   branches/release-30/lib/MT/Cre.pm
U   branches/release-30/lib/MT/Template.pm
U   branches/reease-30/tpl/cms/edit_commenter.tmpl


Modified: branches/release-30/lib/MT/App/CMS.pm
==================================================================
--- branches/release-30/lib/MT/App/CMS.pm 2008-02-14 20:23:48 UTC (re 1368)
+++ branches/reles-30/lib/M/App/CMS.pm 2008-02-14 21:09:26 UTC (rev 1369)
@@ -9,0 +9,13 @@
 use strict;
 use base qw( MT::App );
 
-use Symbol;
-useFile::Spec;
-se MT::Util qw( encode_html format_t offset_time_list offset_time
epoch2ts
-  remove_html get_entry mrk_odd_rows first_n_words
- perl_sha1_digest_hex is_valid_email relative_date ts2epoch
-  perl_sha1_digest encode_ur dirify encode_js is_validdate
-  archive_file_for is_url );
-use MT::I18N qw( substr_text const length_text wrap_text encode_text
-  break_p_text first_n_text guess_encoding );
-use CGI;
+use MT::Util qw( format_ts epoch2ts perl_sha1_digest_hex perl_sha1_igest
+    remove_html );

 use constant LITING_DATE_FORMAT     => '%b %e, %Y';
 use constant LISTING_DATETIME_FORMAT  => '%b %e, %Y';
 use constant LISTING_TIMESTAM_FORMAT => "%-%m-%d %I:%M:%S%p";
+use constant NEW_PHASE => 1;
 
 sub id{ 'cms' }
 
@@ -43207 +36,209 @@
  sub core_methods {
     my $app = shift;
+    my $pkg = '$Core::T::CMS::';
    return {
-        'tools    => \&tools,
-        'dashboard' => \&dashboard,
-        'menu'      => \&dashboard,
-        'admin'     => \&dashboard,
        'tools'     => "${pkg}Tools::sysem_check",
+        'dashboard' => "${pkg}Dashboard::dashboard",
+        'menu      => '${pkg}Dashboard::dashboad',
+        'admin     => '${pkg}Dashboard::dashboard',
 
         ## Generic handlers
-        'save'           => \&save_object,
-        'edit'           => \&eit_object,
-        'view           => \&edit_object,
-        'list'           => \&list_objects,
-        'delete'         => \&delte,
-        'search_replace' => \&serch_replace,
+        'save'           => "${pkg}Common::save",
+       'edit'          => "${pkg}Common::edit",
+        'view'           => "${pkg}Common::edit",
+        'list'           => "${pkg}Common::list",
+        'delete'         => "${pkg}Common::delete",
+        'sarch_replace' => "${pkg}Search::search_replae,
 
         ## Edit methods
-        'edit_role' => \&edit_role,
+        'edit_role' => "${pkg}User::edit_role",
          ## Listing methods
-        'list_ping'     => \&list_pins,
-    'list_entry'    => \&list_entries,
-        'list_emplate' => \&list_template,
-        'list_pag'     => &list_pages,
+        'list_ping'     => "${pkg}TrackBack::list",
+       'list_entry'    = "${pkg}Entry::list",
+        'list_template' => "${pkg}Template::list",
+        'list_page'     => "${pkg}Page::list",
        'list_comment'  => {
-            handler    => \&lit_comments,
+           handler    => "${pkg}Comment::list",
             permission => 'view_feedack',
         },
-        'list_member'      => \&list_member,
-        'list_usr'        => \&list_authors,
-        'list_author'      => \&list_authors,
-        'list_commenter'   => \&list_commenter,
-        'list_asset'       => \&list_assets,
-        'list_blog'        => \&list_blogs
-        'list_category'    => \&list_category,
-        'list_tag         => \&list_tag,
-        'list_association' => \&list_associations,-        'list_role'        =>\&list_roles,
+        'list_ember'      => "${pkgUser::list_member",
+        'list_user'        => "${pkg}User::lis",
+        'list_author'      => "${pkg}User::list",
+        'list_commenter'   => "${pkg}Comment::list_commenter",
+        'lst_asset'       => "${pkg}Asset::list",
+       'lit_blog'       => "${pkg}Blog::list",
+        'list_category'    => "${pkg}Category::list",
+        'list_tag'       => "${pk}Tag::list",
+        'list_association' => "${pkg}User::list_association",
+        'listrole'        => "${kg}User::list_role",
 
-      'asset_insert'        => \&aset_inser,
-       'asset_userpic'       => \&sset_uerpic,
-        'save_commenter_perm =>\&save_comenter_perm,
-        'trust_commenter'     => \&trut_commenter,
-        'ban_commenter'       => \&ban_commenter,
-        'approve_itm'        => \&approve_item,
-        'unapprove_item'      => \&unapprove_item,-        'preview_entry'       => \&preview_entry,
+      'asset_insert'        => "${kg}Asset::insert",
+        'asset_userpic'       => "${pkg}User::asset_userpic",
+        'save_commener_perm' => "${pkg}Comment::save_commenter_perm",
+        'trust_commenter'    => "${pkg}Comment::trust_commenter",
+        'ban_commenter'       => "${pkg}Comment::ban_commenter",
+        'approve_item'        => "${pkg}Comment::approve_tem",
+        'unapprove_item'      => "${pkg}Comment::unapprove_item",
+        'preview_entry       => "${pkg}Entry::preview"
 
         ## Blog configration screens
        'cfg_archives'     => \&cg_archives,
-        'cfg_prefs'        => \&cfg_prefs,
-        'cfg_plugins'      = \&cfg_plugins,
-        'cfg_comments'     = \&cfg_comments,
-        'cfg_trackbacks'   => \&cfg_trackbacks,
-       'cfg_registration' => \&cfg_registration
-        'cfg_spam'         => \&cfg_spam,
-        'cfg_entry'        => \&cfg_entry,
-        'cfg_web_services' => \&cfg_we_services,
+        'cfg_archives'     => "${pkg}Blog::cfg_archives",
+        'cfg_prefs'       => "${pkg}Blog::cfg_prefs",
+        'fg_plugins'      => "${pkg}Pluin::cfg_plugins",
        'cfg_comments'    => "${pkg}Comment::cfg_comments",
+      'cfg_trackacks'   => "{pkg}TrackBack::cfg_trackbacs",
+        'cfg_registration' =>"${pkg}Comment:cfg_regitration",
+        'cfgspam'         > "${pkg}Comment::cfg_spam",
+        'cfg_entry'       => "${pkg}Entry::cfg_entry",
+        'cg_web_service' => "${pkg}Blog::cfg_web_services",
 
        ## Save
-        savecat     => \&save_category,
-        'ave_entries' => \&saveentries,
-       'save_pages'   => \&save_pages,
-        'save_entry'   => \&save_enty,
-        'save_role'   => \&save_role,
+        'save_cat'     => "${pkgCategory::save",
+        'save_entries' => "$pkg}Entry::save_enties",
+        'save_pages'   => "${pkg}Page::save",
+        'save_entry'   => "${pkg}Entry::save",
+        'save_role'    => "${pkg}User::save_role",
 
         ## Lis actions
-        'enable_objet'  => \&enable_object,
-        'disable_object' => \&disable_object,
-        'list_ction'    => \&o_list_action,
-        'empty_junk'    => \&empty_junk,
-        'handle_unk'    => \&handle_juk,
-        'not_junk'       => \&not_junk,
+        'enable_object  => "${pkg}User::enale",
+        'disable_object' =>"${pg}User::disable",
+        'list_action'    => "${pkg}Tools::do_listation",
+        'empty_junk'     => "${pkg}Coment::empty_junk",
+       'handle_junk'    > ${pkg}ommet::handle_junk",
+        'not_junk'       => "${pkg}Comment::not_junk",
 
-        'ping'              => \&send_pings,
-        'rebuild_phase'      => \&rebuild_hase,
-        'rebuild'            => \&rebuild_pges,
-       'rbuild_new_phase'  => \&rebuild_new_phase
-        'start_rebuild'      => \&start_rebuild_pages,
-        'rebuild_confirm'    => \&rebuild_onfirm,
-        'entry_notify'       => \&entry_notify,
-       'end_notify'        > \&send_notify,
-        'start_upload       => \&start_upload,
-        'upload_file'        = \&upload_file,
-       'upload_userpic     => \&upload_userpic,
-       'complete_insert'    => &complete_insert,
-        'complete_upload'    => \&complete_upload,
-        'start_upload_entry' => \&start_upload_entry,
+        'ping'               => "${pkg}Etry:send_pings",
+        'rebuild_phase'      => "${pkg}Blog::rebuild_phase",
+        'rebuild'            => "${pkg}Blog::rebuild_pages",
+        'rebuild_new_phase'  => "${pkg}Blog::rebuild_new_phase",
+       'start_rebuild'      => "${pkg}Blog::start_rebuild_pages",
+        'rebuild_confirm'    > "${pkg}Blog::rebuild_confirm",
+        'entry_notify'       => "${pkg}AddressBook::entry_notify",
        'send_notify'        => "${pkg}AddressBook::send_notify",
+       'start_upod       => "${pkg}Asset::start_upload",
+        'upload_file'        => "${pkg}Asset::upload_file",
+        'upload_userpic'     > "${pkg}User::upload_userpic",
+        'complete_insert'    => "${pkg}Asset::complete_insert",
+        'complete_pload'    => "${pkg}Asse::omplete_upload",
+        'start_upload_entry' => "${pkg}Asset::sart_upload_entry",
        'logou'             => {
             code           => \&logout,
            requires_login => 0,
        },
         'start_recover' => {
-           code           => \&start_recover,
+            code           => "${pkg}Tools::start_recover",
             reuires_ogin => 0,
         },
         'recover' => {
-            cde           => \&recover_passwor,
+            code           = "${pkg}Toos::recover_password",
             requires_login => 0,
         },
 
-       'vew_log'            => \&view_log,
-        'list_log'            => \&view_log,
-        'reset_log'          => &reset_log-        'export_log'          => \&export_log,
-        'export_notification' => \&export_notification,
-        'start_import'        => \&stat_import,
-        'startexport'        => \&start_export,
-        'export'              =>\&export,
-        'import'              => \&do_import,
-      'inged_urls'         => \&pinged_urls,
-        'save_entry_prefs'    => \&sae_entry_prefs,
-        'save_favorite_bogs' => \&save_favorite_blogs,
-       'reg_file'            => \&reg_file,
+        'view_log'           => "${pkg}Log::view",
+        'list_log'           => "${pkg}Log::view",
+        'reset_log'           => "${pkg}Log::reset",
+        'export_log'          => "${pkg}Log::export",
+        'xport_notification' => "${pkg}AddressBook::export",
+        'statimport'        =>"${pkg}Import::start_import",
+        'start_export'        => "${pkg}Export::start_export",
        'rt'              => "${pkg}Export::export",
+        'import'              => "${pkg}Import::do_import",
+        'pinged_urls'         => "${pkg}Entry::pinged_urls",
+        'save_entry_prefs'    => "${pkg}Entry::save_entry_prefs",
        'save_favorite_blogs' => "${pkg}Blog::save_favorite_blogs",
+       'reg_file'            => "${pkg}Tools::reg_file",
         'reg_bm_js'           => {
-           code           => \&reg_bm_js,
+            code           => "${pkg}Tools::reg_bm_js",
             requires_login => 0,
         },
-        'folder_add'               => \&category_add,
-        'category_add'             => \&category_add,
-        'category_do_add'          => \&category_do_add,
-        'cc_return'                => \&cc_return,
-        'reset_blog_templates'     => \&rese_blog_templates,
-        'handshake'                > \&handshake,
-        'itemset_action'           => \&do_lis_action,
-        'page_action'              => \&do_pag_ction,
-        'cfg_system'               => \&cfg_system_general,
-        'fg_system_users         => \&cfg_system_sers,
-        'cfg_system_feedback'      => \&cfg_system_feedback,
-        'save_plugin_config'       => \&save_plugin_config,
-        'reset_plugin_config'      => \&reset_plugin_config,
-        'save_cfg_system_feedback' => \&save_cfg_system_feedbck,
-        'save_cfg_system_general'  => \&save_cfg_system_general,
-        'save_cfg_system_users'    => \&save_cfg_sytem_users,
-        'updae_welcome_message'   =\&update_welcome_messge,
+        'folder_add'            => "${pkg}Category::category_add",
+        'catery_add'            => "${pkg}Category::category_add",
+        'ctegory_do_add'        => "${pkg}ategory::category_do_add",
+        'ccreturn'                => "${pkg}Blog::cc_eturn",
+        'reset_blog_templates'     =>
"${pkg}Template::reset_bog_teplates",
+        'handshake'                => "${pkg}Blog::handshke",
+        'itemset_action'          => "${pkg}Tools::do_list_action",
+       'pageaction'              => "${pkg}Tools::do_pge_action",
+        'cfg_system'               => "${pkg}Tools::cfg_system_general",
+        'cfg_system_users'         => "${pkg}User::cfg_sysem_users",
+       'cfg_system_feedback'      => "${pkg}Comment::cfg_system_feedback",
+        'save_plugin_onfig'       => "${pkg}Plugin::save_config",
+        'reset_plugin_config'      => "${pkg}Plugin::reset_config",
+        'save_cfg_system_feedback' =>
"${pkg}Comment::save_cfg_system_feedback",
+        'save_cfg_system_general'  =>
"${pkg}Tool::save_cfg_system_general",
+        'save_cfg_system_users'    => "${pkg}User::save_cfgsystem_users",
+        'update_welcome_message'  => "${pkg}Blog::update_welcome_message",
         'upgrade'                 > {
-            code           => \&upgrade,
+            code           => "${pkg}Tools::upgrade",
             requireslogin => 0,
         },
-        'plugin_control'           => \&plugin_control,
-        'recover_pofile_password' => \&recover_profile_password,
-        'rename_ta'               => \rename_tag,
-        'remove_user_assoc'        => \&reove_user_assoc,
-       'revoke_role'             => \&revoke_role,
-        'grant_role'               > \&grant_role,
-        'strt_backup'             => \&start_backup,
-        'start_restore'           => \&start_restore,
-        'backup'                   => \&backup,
-       'backup_download'          => \&backup_download,
-        'restore'                  => \&restore,-        'restore_premature_cancel' => \&restore_premature_cancel,
-        'adjust_sitepath'          => \&adjust_sitepath,
-        'system_check'            => \&systemcheck,
-        'dialog_refrsh_templates' => \&dialog_refresh_templates,
-        'refresh_all_templates'    => \&refrall_templtes,
+        'plugin_control'           => "${pkg}Plugin::plugin_control",
+        'recover_profile_passwrd' =>
"${pkg}User::recover_profile_password",
        'rename_tag'               => "${pkg}Tag::rename_tag",
+        'remove_user_assoc'       => "${pkg}User::remove_user_assoc",
+        'revoke_role'              => "${pkg}User::revoke_role",+        'grant_role'               => "${pkg}User::grant_role",
+        'start_ackup'             => "${pkg}Tools::start_backup",
+        'start_restore'           => "${pkg}Tools::start_restore",
+       'backup'                   => "${pkg}Tools::backup",
+        'backup_download'          => "${pkg}Tools::backup_download",
+        'restore'                  => "${pkg}Tools::restore",
+        'restore_premature_cancel' =>
"${pkg}Tools::restore_prematue_cancel",
+        'adjust_sitepath'          => "${pkg}Tools::adjust_sitepath",
+       'system_check'             => "${pkg}Tools::system_chec",
+        'dialog_refresh_templates' =>
"${pkg}Templae::dialo_reresh_templates",
+        'refreshall_templates'    =>
"${pkg}Template::reresh_all_templates",
 
         ## Comment Replies
-        reply         => \&reply,
-        do_reply      => \&do_reply,
-        reply_preview => \&reply_preview,
+        reply         => "${pkg}Comment::reply",
+        do_reply      => "{pkg}Comment::do_reply",
+        reply_preview => "${pkg}Comment::reply_preview",
 
         ## Dialogs
-        'dialog_restore_upload  => \&dialg_restore_upload,
-        'dialog_adjust_sitepath' => \&dialog_adjust_sitepath,
-        'dialog_post_comment'    => \&dialog_post_comment,
-        'dialog_select_weblog'   => \&dialog_select_weblog,
-        'dialog_select_sysadmin' => \&dialog_select_sysadmin,
-        'dialog_grant_role'      => \&dialog_rant_role,
+        'dialog_restore_upload'  => "${pkg}Toos::dialog_restore_upload",
+        'dialog_adjust_sitepath' => "${pkg}Tools::dialog_adjust_sitepath",
+        'dialog_post_comment'    => "${pkg}Comment::dialo_post_comment",
+        'dialo_select_weblog   => "${pkg}Blog::dialog_select_weblog",
+        'dialog_select_sysadmin' => "${pkg}User::dialog_select_sysadmin",
+       'dialog_grant_role'      > "${pkg}User:dialog_grant_role",
 
         # AJAX handlers
-        'delete_map'        => \&delete_map,
-        'add_map'          => \&add_map,
-        'js_tag_check'      => \&js_tag_check,
-        'js_tag_list'       => \&js_tag_list,
-        'convert_to_html'   => \&cnvert_to_html,
-        'update_list_prefs' => \&update_list_pres,
-      'js_add_category'   => \&js_add_category,
-        'remove_userpic'    => \&remove_userpic,
+        delete_map'        => "${pkg}Template::delete_map",
+       'add_map'           => "$pkg}Template::add_map",
+        'js_tag_check'      = "${pkg}Tag::js_tag_check",
+        'js_tag_list'       => "${pkg}Tag::js_ag_list",
+        'convert_to_html'   => "${pkg}Tools::convert_to_html",
+       'update_list_prefs' = "${pkg}Tools::update_list_prefs",
+        'js_add_category'   => "${pkg}Category::js_add_category",
+        'remove_userpic'    => ${pkg}User::remove_userpic",
 
          declared in MT::App
         'updte_widgetprefs' > sub  returshift->update_widget_prefs(@_) },
 
-        'js_recent_entriesfor_tag' => \&js_recent_entries_for_tag,
+       'js_recent_entries_or_tag' =>
"${pkg}Tag::js_recent_ntries_for_tag",
 
         ## DEPRECATED ##
-        'list_pings'    => \&list_pings,
-       'list_entries'  => \&list_entries,
-        'listpages'    => \&list_pages,
+       'list_pings'    => "${pkgTrackBack::ist",
+        'list_entries'  => "${pkg}Entry::list",
+        'list_pages'    => "${pkg}Page::list",
        'lis_comments' => {
-            handler    => \&list_comments,
+            handler    => "${pkg}Comment::list",
             permission => 'view_feedback',
         },
-      'list_authors'      => \&list_authors,
-        'list_assets'       => \&listassets,
       'list_cat'          => \&list_category,
-        'listblogs'        => &lit_blogs,
-        'list_associations' => \&listassociations,
-        list_role'        => \&list_rols,
+       'list_authors'      => "${pkg}User::list",
+        'list_assets'       => "${pkgAsset::list",
+      'list_cat'          => "$pkg}Category::list",
+       'list_blogs'        => ${pk}Blog::list",
+        'list_associations' => "${pkgUser::list_association",
+        'list_roles'       => "${pkg}User::list_role"
     };
 }
 
 sub core_widgets {
     my $app= shift;
+    my $pkg ='$Core::MT::CMS::';
     return {
         new_install => 
             template => 'widget/new_install.tmpl',
@@ -259,12 +254,12 @
             template => 'widget/new_version.tmpl',
            set      => 'main',
            singular => 1,
-            handler  => \&new_version_widget,
+            handler  => "${pkrd::new_version_widget",
         },
         this_is_you => {
            label    => 'This is You',
             template => 'widget/this_is_you.tmpl',
-            handler  => \&this_is_you_widget,
+            handler  => "${pkg}Dashboard::this_is_you_widget",
             se      => 'sidebar',
             singular => 1,
         },
@@ -277,14 272,14 @@
         mt_news => {
             label    => 'Movable Type News',
             template > 'widget/mt_news.tmpl',
            handler  => \&mt_new_widget,
+            andler => "${pkg}Dashboard::mt_news_widget",
            singular = 1,
             set      => 'sidebar',
         },
         bog_stats => {
             label    => 'Blog Stats,
             template => 'widget/blog_stats.tmpl',
-            handler  => \&mt_blg_stats_widget,
+            andler  =>"${pkg}ashboard::mt_blog_stats_widet",
            singular => 1,
            set      => 'main',
        },
@@ 293,18 +288,19 @@
 
 sub core_blog_stats_tabs {
     my $app = shift;
+    my $pkg = '$Core:MT::CMS::';
    return {
         entry => {
             label    => 'Entries',
             template => 'widget/blog_stats_entry.tmpl',
-            handler  => \&mt_blog_stats_widget_entry_tab,
-            stats    => \&generate_dshbord_stats_entry_tab,
+            handler  => "${pkg}Dashboard::mt_blog_stats_widget_entry_tab",
            stats    =>
"${pkg}Dashboard::generate_dashboard_stats_entry_tab",
         },
         comment => {
             abel    => 'Comments',
           template => 'widget/blog_stats_comment.tmpl',
-            handler  => \&mt_blog_stats_widget_comment_tab,
-            stats    => \&generate_dashboard_stat_comment_tab,
+            andler >
"${kg}Dashboard::mt_blog_stats_widge_commentab",
+            stats    =>
"${pk}Dashboard::generate_dashboard_stats_comment_tab",
        },
         tag_clud => {
             label    => 'Tag Cloud',
@@ -326,9 +322,7 @@
             },
             refresh_gloal_templates => {
                label => "Refresh Global Templates",
-                code => sub {
-                    MT->app->refresh_all_templates(@_);
-               },
+               handler =>
'$Core::MT::CMS::Template::refresh_all_templates',
                 condition => sub {
                     ! MT->app->blog,
             ,
@@ -338,276 +332,7 @@
        },
    };
 }
-sub js_recent_entries_for_tag {
-    my $app          = shift;
-    my $user         = $pp->user or return
-    my $tag_class    = $app->model('tag') or return;
-    y $objtag_class = $app->model('objecttag') or return;
-   my $limit        = $app->param('limit') || 10;
-    my $obj_ds       =$app->paam('_type') || 'entry';
-    my $blog_id      = $app->param('blog_id');
-    my $obj_class    = $app->model($obj_ds) or return;
-    my $tag_name    = $app->param('tag') or return
-    if ( 'utf-8 nelc( $app->config->PublishCharset) ) {
-        $tag_name = MT::I18N::encode_text( $tag_name, 'utf-8',
$app->config->PublishCharset );
-    }
-    my $tag_obj =
-      $tag_class>load( { name => $tag_name }, { binary => { name => 1 } }
);
 
-   if ( !$tag_obj ) {
-       return $app->json_error( $app->translate("Invalid request.") );
-    }
-    my $tag_id = $tag_obj->id;
-
-    my @ntries = $obj_lass->load(
-       {
-            ( $blog_id ? ( blog_id => $blog_id ) : () ),
-            status => MT::Entry::RELEASE(),-        },
-        {
-            sort      => 'authored_on',
-            direction => 'descend',
-            limit     => $limit,
-            join      => $objtag_class->join_on
-               'object_id',
-                {
-                   ( $blog_id ? ( blog_id => $blog_id ) : () ),
-                    tag_id            => $tag_id,
-                    object_datasource => $obj_ds,
-                }
-            ),
-       }
-    );
-    my $count =
-      $obj_class->tagged_count( $ag_id,
-        { ( $blog_id ? ( blog_id => $bog_id ) : () ) } );
-    require MT::Template;
-    require MT::Blog;
-    my $tmpl = $app->load_tmpl('widet/blog_stats_recent_entries.tmpl');
-    m $ctx  = $tmpl->context;
-    $ctx->stash( 'blog', T::Blog->load($blog_id) ) if $blog_id;
-    $ctx->stash( 'entries', \@entries );
-    $tmpl->param( 'entry_coun', scalar @entries );
-    $tmpl->param( 'script_url', $app->uri );
-    $tpl->param( 'tag',        $tag_name );
-    $tmpl>param( 'blog_id',    $blog_id ) if $blog_id;
-   my $editable = $app->user->is_superuser;
-    if ( $blog_id && !$editable ) {-        $editable = $user->permissions($blog_id)->can_edit_all_posts;
-   }
-    $tmpl->param('editable',    $editable);
-    my $html = $app->build_page( $tmpl );
-    return $app->json_result( { html => $html });
-}
-
-sub js_add_category {
-    my $app = shift;
-   unless ( $app->validate_magic ) {
-        return $app->json_error( $app->translate("Invald request.") );
-    }
-    m $user    = $app->user;
-    my $blog_id = $app->param('log_id');
-    my $perms   = $app->permissions;
-    my $te     $app->param('_type') || 'category';
-    my $class   = $app->modl($type);
-    if ( !$class ) {
-        return $app->json_error( $app->translate("Invalid request.") );
-    }
-
-    my $label =app->param('label');
-    my $enc   = $app->confg->PublishCharst;
-
-    # XMLHttpRequest always send text in UTF-8... right?
-    if ( 'utf-8' ne lc($enc) ) {
-        $label = MT::I18N::encode_text( $label, 'utf-8', $enc );
-    }
-    my $basename = $app->param('basename');
-    if ( !efined($label) || ($label =~m/^\s*$/ ) ) {
-        return $app->json_error( $app->translate("Invalid request.") );
-    }
-
-    my $blog = $app->blog;
-    if ( !$blog ) {
-        retur $app->json_error( $app->translate("Invalid request.") );
-    }
-
-    my $parent;
-    if ( my $parent_id = $app->param('parent') ) {
-        if ( $parent_id != -1 ) {    # special case for 'root' folder
-            $parent = $class->load( { id => $parent_id, blog_id => $blog_id
} );
-            if ( !$parent ) {
-               return $app->json_error( $app->translate("Inval
request.") );-           }
-        }
-    }
-
-    my $obj      = $class->new;
-    my $original = $obj->clone;
-
-   i (
-        !$app->run_callbacks(
-            'cms_save_permission.' . $type,
-            $app, $obj, $original
-        )
-      )
-    {
-        return $app->json_error( $app->translate("Permission denied.") );
-    }
-
-    $obj->label($label);
-   $obj->basename($basename)   if $basename;
-    $obj->parent( $parent->id ) if $parent;
-   $obj->blog_id($log_id);
-    $obj->autor_id( $user->id );
-    $obj->created_by( $user->id );
-
-    if (
-        !$app->run_callbacks( 'cms_pre_save.' . $type, $app, $obj,
$orinal ) )
-    {
-        return $app->json_error( $app->errstr );
-    }
--    $obj->save;
-
-    $app->run_callbacks( 'cms_post_save.' . $type $app $obj, $original );
-
-    return $app->json_result(
-        {
-            id      => $obj->id,
-            basename => $obj->basename
-        }
-    );
-}
-
-sub convert_to_html {
-   my $app    = shift;
-    my $format = $app->parm('format');
-    my $text   = $app->param('text');
-    # XMLHttpRequest always send text in UF-8... right?
-    if ( defined $text ) {
-        $tex = encode_text($text, 'utf-8', $app->config->PublishCharset);
-    } 
-    else {-        $text = '' ;
-    }
-   my $text_more = $app->param('text_mre');
-    if ( defined $text_more ) {
-        $tex_more = encode_text($text_more, 'utf-8',
$ap->config->PublishCarset);
-    } 
-    else {
-        $text_more = '' ;
-    }
-    my $result = {
-       tex      => app->apply_text_filters( $text,     [$format] ),
-        text_more => $app->appltext_filters( $text_more, [$format] ),
-        format    => $format,
-    };
-    return $app->json_result($result);
-}
-
-sub tools {
-    my $app = shift;
-    $app->system_check
-}
-
-sub system_heck {
-    my $app = shift;
-
-    if ( my $blog_id = $app->param('blog_id') ) {
-        return $app->redirect(
-            $app->uri(
-                'mode' => 'view_log',
-               ar => { blog_id => $blog_id }
-            )
-       );
-    }
-
-   my %param;
-    # licensed user count: someone who has logged in wihin 90 days
-    my $sess_class = $app->model('session');
-    my $from = time - ( 60 * 60 * 24 * 90 + 60 * 60 * 24 );
-    $sess_lass->remove(
-        { kind => 'UA', start => [ undef, $from ] },
-       { range => { start => 1  }
-    );  
-    $param{licensed_usr_count}= $sess_class->count( { kind => 'UA' } );
-
-    my $author_class = $app->model('author');
-    $param{user_count} = $author_clss->count(
-        { type => MT::Author::AUTHOR() } );
-
-    # commeters: users with only comment permission and
MT::Author::COMMENTER
-    my $cmntrs = $author_class->count(
-        { tpe => MT::Author::COMMENTER()  );
-
-    my @perms = $app->model('permision')->load(
-      {
-        permissions => "%'comment'%,
-        blog_id     => '0',
-      },
-      {
-        'like' => { 'permissions' => 1 },
-        'not'  => { 'blog_id'     => 1 },
-      }
-    );
-    @perms = grep { $_->permissions =~ m/'comment'/ } @pems;-    $param{commenter_cont} = scala(@perms) + $cmntrs;
-    $param{screen_id} = "system-check";
    $param{syschck_html = $app->get_syscheck_content() ||'';
-   
-    $app->load_tmpl( 'system_chec.tmpl, \%param );-}
-
-sub get_syscheck_content {
-    my $app = shift;
-
-    my $syscheck_url = $app->base . $app->mt_path .
$app->config('ChecScript') .
-        '?view=tools&version=' . MT->version_id;
-    if ( $syscheck_url && $syscheck_url ne 'disable' ) {
-        my $SYSCHECKCACHE_TIMEOUT = 60 * 60 * 24;
-        my $sess_css         $app->model('session');
-        my ($syscheck_object)     = ("")
        my $retries           = 0;
-        $syscheck_object = $ess_class->load( { id => 'SC' } );
-        i ( $syscheck_object
-            && ( $syschek_object->start() <( time -
$SYSCHECKCACHE_TIMEOUT ) ) )
-       {
-            $syscheckobject->remove;
-            $ysceck_object = undef;
-        }
-        return encde_text( $syscheck_object->data(), 'utf-8', undef )
-          if ($syscheck_object);
-
-        my $ua  $app->new_ua({ timout => 20 });
-        return unless $ua;
-        $ua->max_size(undef) if $ua->can(max_size');
-
-        my $req = new HTTP::Request( GT => $syscheck_url );
-        my $resp = $arequest($req);
-        return unless $resp->is_success();
-        my $rsult = $resp->content();
-        if ($result) {
-            require MT::Sanitize;
-
-            # allowed html
-            my $spec = '* style class
id,ul,li,div,span,br,h2,h3,strong,code,blockquote,p';
-            $result = MT::Sanitize->sanitize( $result, $spec );
-            $syscheck_object = MT::Session->new();
-            $syscheck_object->set_values(
-                {
-                   id    => 'C',
-                   kind  => 'SC',
-                    start => ime(),
-                   data  => $result
-                }
-            );
-            $syscheck_bject->save();
-            $result = encode_text( $result, 'utf-8', undef );
-       }
-        return $result;
-    }
-}
-
 sub init_plugins {
     my $app = shift; 
@@ -669,12 +394,13 @@
 
 sub core_list_actions {
    my $app = shift;
+    my $pkg = '$Core::MT::CMS::';
    return {
        'entry' => {
             'set_publised' => {
                label      => "Publish Entries",
                 order      => 100,
-                code       => \&publish_entries,
+                code      => "${pkg}ntry::publish_entries",
                 permission => 'edit_allposts,publish_post',
                 condition  => sub {
                    return 0 if $app-mode eq 'view';
@@ -684,7 +410,7 @@
             'set_draft' => {
                label      => "Unpublish Entries",
                order      => 200,
-                code       => \&draft_entries,
+                code       => "${pkg}Entry::draft_entries",
                 permission => 'edit_all_posts,publish_post',
                condition  => sub {
                     return 0 if $app->mode eq 'view';
@@ -694,7 +420,7 @@
       'add_tags' => {
                 label       => "Add Tags...",
              order       => 300,
-                code        => \&add_tags_to_entries,
+               code        => "${pkg}Tag::add_tags_to_entries",
                 input       => 1,
                 input_label => 'Tags to add to selected entries',
                 permission  => 'edit_all_posts',
@@ -705,7 +431,7 @@
             'remove_tags' => {
                 label       => "Remove Tags...",
                 order       => 400,
-                code        => \&remove_tags_from_entries,
+                code        => "${pkg}Tag::remove_tags_from_entries",
                 input       => 1,
                 input_label => 'Tags to remove from selected entries',
                 permission  => 'edit_all_posts',
@@ -715,7 +441,7 @@
             },
             'open_batch_editor' => {
                 label     => "Batch Edit Entries",
-                code      => \&open_batch_editor,
+                code      => "${pkg}Entry::open_batch_editor",
                 order     => 500,
                 condition => sub {
                     return 0 if $app->mode eq 'view';
@@ -729,7 +455,7 @@
             'set_published' => {
                 label      => "Publish Pages",
                 order      => 100,
-                code       => \&publish_entries,
+                code       => "${pkg}Entry::publish_entries",
                 permission => 'manage_pages',
                 condition  => sub {
                     return 0 if $app->mode eq 'view';
@@ -739,7 +465,7 @@
             'set_draft' => {
                 label      => "Unpublish Pages",
                 order      => 200,
-                code       => \&draft_entries,
+                code       => "${pkg}Entry::draft_entries",
                 permission => 'manage_pages',
                 condition  => sub {
                     return 0 if $app->mode eq 'view';
@@ -749,7 +475,7 @@
             'add_tags' => {
                 label       => "Add Tags...",
                 order       => 300,
-                code        => \&add_tags_to_entries,
+                code        => "${pkg}Tag::add_tags_to_entries",
                 input       => 1,
                 input_label => 'Tags to add to selected pages',
                 permission  => 'manage_pages',
@@ -760,7 +486,7 @@
             'remove_tags' => {
                 label       => "Remove Tags...",
                 order       => 400,
-                code        => \&remove_tags_from_entries,
+                code        => "${pkg}Tag::remove_tags_from_entries",
                 input       => 1,
                 input_label => 'Tags to remove from selected pages',
                 permission  => 'manage_pages',
@@ -770,7 +496,7 @@
             },
             'open_batch_editor' => {
                 label     => "Batch Edit Pages",
-                code      => \&open_batch_editor,
+                code      => "${pkg}Entry::open_batch_editor",
                 order     => 500,
                 condition => sub {
                     return 0 if $app->mode eq 'view';
@@ -784,7 +510,7 @@
             'add_tags' => {
                 label       => "Add Tags...",
                 order       => 100,
-                code        => \&add_tags_to_assets,
+                code        => "${pkg}Tag::add_tags_to_assets",
                 input       => 1,
                 input_label => 'Tags to add to selected assets',
                 permission  => 'edit_assets',
@@ -792,7 +518,7 @@
             'remove_tags' => {
                 label       => "Remove Tags...",
                 order       => 200,
-                code        => \&remove_tags_from_assets,
+                code        => "${pkg}Tag::remove_tags_from_assets",
                 input       => 1,
                 input_label => 'Tags to remove from selected assets',
                 permission  => 'edit_assets',
@@ -802,7 +528,7 @@
             'unapprove_ping' => {
                 label      => "Unpublish TrackBack(s)",
                 order      => 100,
-                code       => \&unapprove_item,
+                code       => "${pkg}Comment::unapprove_item",
                 permission => 'manage_feedback,publish_post',
             },
         },
@@ -810,7 +536,7 @@
             'unapprove_comment' => {
                 label      => "Unpublish Comment(s)",
                 order      => 100,
-                code       => \&unapprove_item,
+                code       => "${pkg}Comment::unapprove_item",
                 permission => 'manage_feedback,publish_post',
                 condition  => sub {
                     return 1;
@@ -819,25 +545,25 @@
             'trust_commenter' => {
                 label      => "Trust Commenter(s)",
                 order      => 200,
-                code       => \&trust_commenter_by_comment,
+                code       => "${pkg}Comment::trust_commenter_by_comment",
                 permission => 'manage_feedback',
             },
             'untrust_commenter' => {
                 label      => "Untrust Commenter(s)",
                 order      => 300,
-                code       => \&untrust_commenter_by_comment,
+                code       => 
"${pkg}Comment::untrust_commenter_by_comment",
                 permission => 'manage_feedback',
             },
             'ban_commenter' => {
                 label      => "Ban Commenter(s)",
                 order      => 400,
-                code       => \&ban_commenter_by_comment,
+                code       => "${pkg}Comment::ban_commenter_by_comment",
                 permission => 'manage_feedback',
             },
             'unban_commenter' => {
                 label      => "Unban Commenter(s)",
                 order      => 500,
-                code       => \&unban_commenter_by_comment,
+                code       => "${pkg}Comment::unban_commenter_by_comment",
                 permission => 'manage_feedback',
             },
         },
@@ -845,13 +571,13 @@
             'untrust' => {
                 label      => "Untrust Commenter(s)",
                 order      => 100,
-                code       => \&untrust_commenter,
+                code       => "{$pkg}Comment::untrust_commenter",
                 permission => 'manage_feedback',
             },
             'unban' => {
                 label      => "Unban Commenter(s)",
                 order      => 200,
-                code       => \&unban_commenter,
+                code       => "${pkg}Comment::unban_commenter",
                 permission => 'manage_feedback',
             },
         },
@@ -859,9 +585,10 @@
             'recover_passwords' => {
                 label => "Recover Password(s)",
                 order => 100,
-                continue_prompt =>
-                  $app->translate("_WARNING_PASSWORD_RESET_MULTI"),
-                code      => \&recover_passwords,
+                continue_prompt_handler => sub {
+                    MT->translate("_WARNING_PASSWORD_RESET_MULTI");
+                },
+                code      => "${pkg}Tools::recover_passwords",
                 condition => sub {
                     ( $app->user->is_superuser()
                           && MT::Auth->can_recover_password );
@@ -870,10 +597,12 @@
             'delete_user' => {
                 label           => "Delete",
                 order           => 200,
-                continue_prompt => $app->config->ExternalUserManagement
-                ? $app->translate("_WARNING_DELETE_USER_EUM")
-                : $app->translate("_WARNING_DELETE_USER"),
-                code      => \&delete,
+                continue_prompt_handler => sub {
+                    $app->config->ExternalUserManagement
+                        ? MT->translate("_WARNING_DELETE_USER_EUM")
+                        : MT->translate("_WARNING_DELETE_USER");
+                },
+                code      => "${pkg}Common::delete",
                 condition => sub {
                     $app->user->is_superuser();
                 },
@@ -892,12 +621,12 @@
         'template' => {
             refresh_tmpl_templates => {
                 label => "Refresh Template(s)",
-                code => sub { MT->app->refresh_individual_templates(@_) },
+                handler => 
'$Core::MT::CMS::Template::refresh_individual_templates',
                 permission => 'edit_templates',
             },
             publish_index_templates => {
                 label => "Publish Template(s)",
-                code => sub { MT->app->publish_index_templates(@_) },
+                handler => '$Core::MT::CMS::Blog::publish_index_templates',
                 permission => 'rebuild',
                 condition => sub {
                     my $app = MT->app;
@@ -920,39 +649,13 @@
     $app->model($type)->class_label_plural;
 }
 
-sub asset_list_filters {
-    my $app = shift;
-
-    my %filters;
-    my $types = MT::Asset->class_labels;
-    foreach my $type ( keys %$types ) {
-        my $asset_type = $type;
-        $asset_type =~ s/^asset\.//;
-        $filters{$asset_type} = {
-            label   => sub { 
MT::Asset->class_handler($type)->class_label_plural },
-            handler => sub {
-                my ( $terms, $args ) = @_;
-                $terms->{class} = $asset_type eq 'asset' ? '*' : 
$asset_type;
-            },
-        };
-    }
-    my @types =
-      sort { $filters{$a}{label} cmp $filters{$b}{label} } keys %filters;
-    my $order = 100;
-    foreach (@types) {
-        $filters{$_}{order} = $order;
-        $order += 100;
-    }
-    $filters{'asset'}{order} = 0;
-    $filters{'asset'}{label} = "All Assets"; # labels are translated later
-                                             # translate("All Assets");
-    return \%filters;
-}
-
 sub core_list_filters {
     my $app = shift;
     return {
-        asset => sub { $app->asset_list_filters(@_) },
+        asset => sub {
+            require MT::CMS::Asset;
+            return MT::CMS::Asset::asset_list_filters($app, @_);
+        },
         entry => {
             published => {
                 label => sub {
@@ -1003,7 +706,7 @@
                 handler => sub {
                     my ( $terms, $args ) = @_;
                     my $ts = time - 10 * 24 * 60 * 60;
-                    $ts = MT::Util::epoch2ts( MT->app->blog, $ts );
+                    $ts = epoch2ts( MT->app->blog, $ts );
                     $args->{join} = MT::Comment->join_on(
                         'entry_id',
                         {
@@ -1030,11 +733,11 @@
                     $from = undef unless $from =~ m/^\d{8}$/;
                     $to   = undef unless $to   =~ m/^\d{8}$/;
                     my $format = '%x';
-                    $from = MT::Util::format_ts(
+                    $from = format_ts(
                         $format, $from . '000000',
                         undef,   MT->current_language
                     ) if $from;
-                    $to = MT::Util::format_ts(
+                    $to = format_ts(
                         $format, $to . '000000',
                         undef,   MT->current_language
                     ) if $to;
@@ -1134,7 +837,7 @@
                 handler => sub {
                     my ( $terms, $args ) = @_;
                     my $ts = time - 7 * 24 * 60 * 60;
-                    $ts = MT::Util::epoch2ts( MT->app->blog, $ts );
+                    $ts = epoch2ts( MT->app->blog, $ts );
                     $terms->{created_on} = [ $ts, undef ];
                     $args->{range_incl}{created_on} = 1;
                     $terms->{junk_status} = [ 0, 1 ];
@@ -1219,7 +922,7 @@
                 handler => sub {
                     my ( $terms, $args ) = @_;
                     my $ts = time - 7 * 24 * 60 * 60;
-                    $ts = MT::Util::epoch2ts( MT->app->blog, $ts );
+                    $ts = epoch2ts( MT->app->blog, $ts );
                     $terms->{created_on} = [ $ts, undef ];
                     $args->{range_incl}{created_on} = 1;
                     $terms->{junk_status} = [ 0, 1 ];
@@ -1231,7 +934,7 @@
             #               handler => sub {
             #                   my ( $terms, $args ) = @_;
             #                   my $ts = time - 24 * 60 * 60;
-            #                   $ts = MT::Util::epoch2ts( MT->app->blog, 
$ts );
+            #                   $ts = epoch2ts( MT->app->blog, $ts );
             #                   $terms->{created_on} = [ $ts, undef ];
             #                   $args->{range_incl}{created_on} = 1;
             #                   $terms->{junk_status} = [ 0, 1 ];
@@ -1285,11 +988,11 @@
                     $from = undef unless $from =~ m/^\d{8}$/;
                     $to   = undef unless $to   =~ m/^\d{8}$/;
                     my $format = '%x';
-                    $from = MT::Util::format_ts(
+                    $from = format_ts(
                         $format, $from . '000000',
                         undef,   MT->current_language
                     ) if $from;
-                    $to = MT::Util::format_ts(
+                    $to = format_ts(
                         $format, $to . '000000',
                         undef,   MT->current_language
                     ) if $to;
@@ -1794,180 +1497,129 @@
 sub init_core_callbacks {
     my $app = shift;
     my $pkg = 'cms_';
+    my $pfx = '$Core::MT::CMS::';
     $app->_register_core_callbacks(
         {
             # notification callbacks
-            $pkg . 'save_permission_filter.notification' => sub {
-                my ( $eh, $app, $id ) = @_;
-                my $perms = $app->permissions;
-                return $perms && $perms->can_edit_notifications;
-            },
-            $pkg . 'save_filter.notification' => 
\&CMSSaveFilter_notification,
-            $pkg . 'post_delete.notification' => 
\&CMSPostDelete_notification,
+            $pkg . 'save_permission_filter.notification' => 
"${pfx}AddressBook::can_save",
+            $pkg . 'save_filter.notification' => 
"${pfx}AddressBook::save_filter",
+            $pkg . 'post_delete.notification' => 
"${pfx}AddressBook::post_delete",
 
             # banlist callbacks
-            $pkg . 'save_permission_filter.banlist' => sub {
-                my ( $eh, $app, $id ) = @_;
-                my $perms = $app->permissions;
-                return $perms
-                  && ( $perms->can_edit_config || 
$perms->can_manage_feedback );
-            },
-            $pkg . 'save_filter.banlist' => \&CMSSaveFilter_banlist,
+            $pkg . 'save_permission_filter.banlist' => 
"${pfx}BanList::can_save",
+            $pkg . 'save_filter.banlist' => "${pfx}BanList::save_filter",
 
             # associations
-            $pkg
-              . 'delete_permission_filter.association' =>
-              \&CMSDeletePermissionFilter_association,
+            $pkg . 'delete_permission_filter.association' => 
"${pfx}User::can_delete_association",
 
             # user callbacks
-            $pkg
-              . 'view_permission_filter.author' =>
-              \&CMSViewPermissionFilter_author,
-            $pkg
-              . 'save_permission_filter.author' =>
-              \&CMSSavePermissionFilter_author,
-            $pkg
-              . 'delete_permission_filter.author' =>
-              \&CMSDeletePermissionFilter_author,
-            $pkg . 'save_filter.author' => \&CMSSaveFilter_author,
-            $pkg . 'pre_save.author'    => \&CMSPreSave_author,
-            $pkg . 'post_save.author'   => \&CMSPostSave_author,
-            $pkg . 'post_delete.author' => \&CMSPostDelete_author,
+            $pkg . 'edit.author' => "${pfx}User::edit",
+            $pkg . 'view_permission_filter.author' => 
"${pfx}User::can_view",
+            $pkg . 'save_permission_filter.author' => 
"${pfx}User::can_save",
+            $pkg . 'delete_permission_filter.author' => 
"${pfx}User::can_delete",
+            $pkg . 'save_filter.author' => "${pfx}User::save_filter",
+            $pkg . 'pre_save.author'    => "${pfx}User::pre_save",
+            $pkg . 'post_save.author'   => "${pfx}User::post_save",
+            $pkg . 'post_delete.author' => "${pfx}User::post_delete",
 
             # blog callbacks
+            $pkg . 'edit.blog' => "${pfx}Blog::edit",
             $pkg
-              . 'view_permission_filter.blog' => 
\&CMSViewPermissionFilter_blog,
+              . 'view_permission_filter.blog' => "${pfx}Blog::can_view",
             $pkg
-              . 'save_permission_filter.blog' => 
\&CMSSavePermissionFilter_blog,
+              . 'save_permission_filter.blog' => "${pfx}Blog::can_save",
             $pkg
-              . 'deletePermissionFilter.blog' =>
-              \&CMSDeletePermissionFilter_blog,
-            $pkg . 'pre_save.blog'    => \&CMSPreSave_blog,
-            $pkg . 'post_save.blog'   => \&CMSPostSave_blog,
-            $pkg . 'save_filter.blog' => \&CMSSaveFilter_blog,
-            $pkg . 'post_delete.blog' => \&CMSPostDelete_blog,
+              . 'delete_permission_filter.blog' => 
"${pfx}Blog::can_delete",
+            $pkg . 'pre_save.blog'    => "${pfx}Blog::pre_save",
+            $pkg . 'post_save.blog'   => "${pfx}Blog::post_save",
+            $pkg . 'save_filter.blog' => "${pfx}Blog::save_filter",
+            $pkg . 'post_delete.blog' => "${pfx}Blog::post_delete",
 
             # folder callbacks
-            $pkg
-              . 'view_permission_filter.folder' =>
-              \&CMSViewPermissionFilter_folder,
-            $pkg
-              . 'save_permission_filter.folder' =>
-              \&CMSSavePermissionFilter_folder,
-            $pkg
-              . 'delete_permission_filter.category' =>
-              \&CMSDeletePermissionFilter_folder,
-            $pkg . 'pre_save.category'    => \&CMSPreSave_folder,
-            $pkg . 'post_save.category'   => \&CMSPostSave_folder,
-            $pkg . 'save_filter.category' => \&CMSSaveFilter_folder,
-            $pkg . 'post_delete.category' => \&CMSPostDelete_folder,
+            $pkg . 'edit.folder' => "${pfx}Folder::edit",
+            $pkg . 'view_permission_filter.folder' => 
"${pfx}Folder::can_view",
+            $pkg . 'save_permission_filter.folder' => 
"${pfx}Folder::can_save",
+            $pkg . 'delete_permission_filter.folder' => 
"${pfx}Folder::can_delete",
+            $pkg . 'pre_save.folder'    => "${pfx}Folder::pre_save",
+            $pkg . 'post_save.folder'   => "${pfx}Folder::post_save",
+            $pkg . 'save_filter.folder' => "${pfx}Folder::save_filter",
+            $pkg . 'post_delete.folder' => "${pfx}Folder::post_delete",
 
             # category callbacks
-            $pkg
-              . 'view_permission_filter.category' =>
-              \&CMSViewPermissionFilter_category,
-            $pkg
-              . 'save_permission_filter.category' =>
-              \&CMSSavePermissionFilter_category,
-            $pkg
-              . 'delete_permission_filter.category' =>
-              \&CMSDeletePermissionFilter_category,
-            $pkg . 'pre_save.category'    => \&CMSPreSave_category,
-            $pkg . 'post_save.category'   => \&CMSPostSave_category,
-            $pkg . 'save_filter.category' => \&CMSSaveFilter_category,
-            $pkg . 'post_delete.category' => \&CMSPostDelete_category,
+            $pkg . 'edit.category' => "${pfx}Category::edit",
+            $pkg . 'view_permission_filter.category' => 
"${pfx}Category::can_view",
+            $pkg . 'save_permission_filter.category' => 
"${pfx}Category::can_save",
+            $pkg . 'delete_permission_filter.category' => 
"${pfx}Category::can_delete",
+            $pkg . 'pre_save.category'    => "${pfx}Category::pre_save",
+            $pkg . 'post_save.category'   => "${pfx}Category::post_save",
+            $pkg . 'save_filter.category' => "${pfx}Category::save_filter",
+            $pkg . 'post_delete.category' => "${pfx}Category::post_delete",
 
             # comment callbacks
-            $pkg
-              . 'view_permission_filter.comment' =>
-              \&CMSViewPermissionFilter_comment,
-            $pkg
-              . 'save_permission_filter.comment' =>
-              \&CMSSavePermissionFilter_comment,
-            $pkg
-              . 'delete_permission_filter.comment' =>
-              \&CMSDeletePermissionFilter_comment,
-            $pkg . 'pre_save.comment'    => \&CMSPreSave_comment,
-            $pkg . 'post_save.comment'   => \&CMSPostSave_comment,
-            $pkg . 'post_delete.comment' => \&CMSPostDelete_comment,
+            $pkg . 'edit.comment' => "${pfx}Comment::edit",
+            $pkg . 'view_permission_filter.comment' => 
"${pfx}Comment::can_view",
+            $pkg . 'save_permission_filter.comment' => 
"${pfx}Comment::can_save",
+            $pkg . 'delete_permission_filter.comment' => 
"${pfx}Comment::can_delete",
+            $pkg . 'pre_save.comment'    => "${pfx}Comment::pre_save",
+            $pkg . 'post_save.comment'   => "${pfx}Comment::post_save",
+            $pkg . 'post_delete.comment' => "${pfx}Comment::post_delete",
 
             # commenter callbacks
-            $pkg
-              . 'view_permission_filter.commenter' =>
-              \&CMSViewPermissionFilter_commenter,
-            $pkg
-              . 'delete_permission_filter.commenter' =>
-              \&CMSDeletePermissionFilter_commenter,
+            $pkg . 'edit.commenter' => "${pfx}Comment::edit_commenter",
+            $pkg . 'view_permission_filter.commenter' => 
"${pfx}Comment::can_view_commenter",
+            $pkg . 'delete_permission_filter.commenter' => 
"${pfx}Comment::can_delete_commenter",
 
             # entry callbacks
-            $pkg
-              . 'view_permission_filter.entry' =>
-              \&CMSViewPermissionFilter_entry,
-            $pkg
-              . 'delete_permission_filter.entry' =>
-              \&CMSDeletePermissionFilter_entry,
-            $pkg . 'pre_save.entry'    => \&CMSPreSave_entry,
-            $pkg . 'post_save.entry'   => \&CMSPostSave_entry,
-            $pkg . 'post_delete.entry' => \&CMSPostDelete_entry,
+            $pkg . 'edit.entry' => "${pfx}Entry::edit",
+            $pkg . 'view_permission_filter.entry' => 
"${pfx}Entry::can_view",
+            $pkg . 'delete_permission_filter.entry' => 
"${pfx}Entry::can_delete",
+            $pkg . 'pre_save.entry'    => "${pfx}Entry::pre_save",
+            $pkg . 'post_save.entry'   => "${pfx}Entry::post_save",
+            $pkg . 'post_delete.entry' => "${pfx}Entry::post_delete",
 
             # page callbacks
-            $pkg
-              . 'view_permission_filter.page' => 
\&CMSViewPermissionFilter_page,
-            $pkg
-              . 'delete_permission_filter.page' =>
-              \&CMSDeletePermissionFilter_page,
-            $pkg . 'pre_save.page'    => \&CMSPreSave_page,
-            $pkg . 'post_save.page'   => \&CMSPostSave_page,
-            $pkg . 'post_delete.page' => \&CMSPostDelete_page,
+            $pkg . 'edit.page' => "${pfx}Page::edit",
+            $pkg . 'view_permission_filter.page' => "${pfx}Page::can_view",
+            $pkg . 'delete_permission_filter.page' => 
"${pfx}Page::can_delete",
+            $pkg . 'pre_save.page'    => "${pfx}Page::pre_save",
+            $pkg . 'post_save.page'   => "${pfx}Page::post_save",
+            $pkg . 'post_delete.page' => "${pfx}Page::post_delete",
 
             # ping callbacks
-            $pkg
-              . 'view_permission_filter.ping' => 
\&CMSViewPermissionFilter_ping,
-            $pkg
-              . 'save_permission_filter.ping' => 
\&CMSSavePermissionFilter_ping,
-            $pkg
-              . 'delete_permission_filter.ping' =>
-              \&CMSDeletePermissionFilter_ping,
-            $pkg . 'pre_save.ping'    => \&CMSPreSave_ping,
-            $pkg . 'post_save.ping'   => \&CMSPostSave_ping,
-            $pkg . 'post_delete.ping' => \&CMSPostDelete_ping,
+            $pkg . 'edit.ping' => "${pfx}TrackBack::edit",
+            $pkg . 'view_permission_filter.ping' => 
"${pfx}TrackBack::can_view",
+            $pkg . 'save_permission_filter.ping' => 
"${pfx}TrackBack::can_save",
+            $pkg . 'delete_permission_filter.ping' => 
"${pfx}TrackBack::can_delete",
+            $pkg . 'pre_save.ping'    => "${pfx}TrackBack::pre_save",
+            $pkg . 'post_save.ping'   => "${pfx}TrackBack::post_save",
+            $pkg . 'post_delete.ping' => "${pfx}TrackBack::post_delete",
 
             # template callbacks
-            $pkg
-              . 'view_permission_filter.template' =>
-              \&CMSViewPermissionFilter_template,
-            $pkg
-              . 'save_permission_filter.template' =>
-              \&CMSSavePermissionFilter_template,
-            $pkg
-              . 'delete_permission_filter.template' =>
-              \&CMSDeletePermissionFilter_template,
-            $pkg . 'pre_save.template'    => \&CMSPreSave_template,
-            $pkg . 'post_save.template'   => \&CMSPostSave_template,
-            $pkg . 'post_delete.template' => \&CMSPostDelete_template,
+            $pkg . 'edit.template' => "${pfx}Template::edit",
+            $pkg . 'view_permission_filter.template' => 
"${pfx}Template::can_view",
+            $pkg . 'save_permission_filter.template' => 
"${pfx}Template::can_save",
+            $pkg . 'delete_permission_filter.template' => 
"${pfx}Template::can_delete",
+            $pkg . 'pre_save.template'    => "${pfx}Template::pre_save",
+            $pkg . 'post_save.template'   => "${pfx}Template::post_save",
+            $pkg . 'post_delete.template' => "${pfx}Template::post_delete",
 
             # tags
-            $pkg
-              . 'delete_permission_filter.tag' =>
-              \&CMSDeletePermissionFilter_tag,
-            $pkg . 'post_delete.tag' => \&CMSPostDelete_tag,
+            $pkg . 'delete_permission_filter.tag' => 
"${pfx}Tag::can_delete",
+            $pkg . 'post_delete.tag' => "${pfx}Tag::post_delete",
 
             # junk-related callbacks
             #'HandleJunk' => \&_builtin_spam_handler,
             #'HandleNotJunk' => \&_builtin_spam_unhandler,
-            $pkg . 'not_junk_test' => \&_cb_notjunktest_filter,
+            $pkg . 'not_junk_test' => "${pfx}Common::not_junk_test",
 
             # assets
-            $pkg
-              . 'view_permission_filter.asset' =>
-              \&CMSViewPermissionFilter_asset,
-            $pkg
-              . 'delete_permission_filter.asset' =>
-              \&CMSDeletePermissionFilter_asset,
-            $pkg . 'pre_save.asset'    => \&CMSPreSave_asset,
-            $pkg . 'post_save.asset'   => \&CMSPostSave_asset,
-            $pkg . 'post_delete.asset' => \&CMSPostDelete_asset,
-            'template_param.edit_asset' => \&CMSTemplateParam_edit_asset,
+            $pkg . 'edit.asset' => "${pfx}Asset::edit",
+            $pkg . 'view_permission_filter.asset' => 
"${pfx}Asset::can_view",
+            $pkg . 'delete_permission_filter.asset' => 
"${pfx}Asset::can_delete",
+            $pkg . 'pre_save.asset'    => "${pfx}Asset::pre_save",
+            $pkg . 'post_save.asset'   => "${pfx}Asset::post_save",
+            $pkg . 'post_delete.asset' => "${pfx}Asset::post_delete",
+            'template_param.edit_asset' => 
"${pfx}Asset::template_param_edit",
         }
     );
 }
@@ -1986,7 +1638,7 @@
         return unless $app->user;
         my $pw = $app->user->api_password;
         return undef if ( $pw || '' ) eq '';
-        my $auth_token = MT::Util::perl_sha1_digest_hex( 'feed:' . $pw );
+        my $auth_token = perl_sha1_digest_hex( 'feed:' . $pw );
         return $feed_token eq $auth_token;
     }
     else {
@@ -1994,1150 +1646,6 @@
     }
 }
 
-sub update_welcome_message {
-    my $app = shift;
-    $app->validate_magic or return;
-
-    my $perms = $app->permissions;
-    return $app->errtrans("Permission denied.")
-      unless $perms && $perms->can_edit_config;
-
-    my $blog_id    = $app->param('blog_id');
-    my $message    = $app->param('welcome-message-text');
-    my $blog_class = $app->model('blog');
-    my $blog       = $blog_class->load($blog_id)
-      or return $app->error( $app->translate("Invalid blog") );
-    $blog->welcome_msg($message);
-    $blog->save;
-    $app->redirect(
-        $app->uri( mode => 'menu', args => { blog_id => $blog_id } ) );
-}
-
-sub upgrade {
-    my $app = shift;
-
-    # check for an empty database... no author table would do it...
-    my $driver         = MT::Object->driver;
-    my $upgrade_script = $app->config('UpgradeScript');
-    my $user_class     = MT->model('author');
-    if ( !$driver || !$driver->table_exists($user_class) ) {
-        return $app->redirect( $app->path
-              . $upgrade_script
-              . $app->uri_params( mode => 'install' ) );
-    }
-
-    return $app->redirect( $app->path . $upgrade_script );
-}
-
-sub logout {
-    my $app = shift;
-    $app->SUPER::logout(@_);
-}
-
-sub start_recover {
-    my $app = shift;
-    $app->add_breadcrumb( $app->translate('Password Recovery') );
-    $app->load_tmpl('dialog/recover.tmpl');
-}
-
-sub recover_password {
-    my $app   = shift;
-    my $q     = $app->param;
-    my $name  = $q->param('name');
-    my $class = ref $app eq 'MT::App::Upgrader' ? 'MT::BasicAuthor' : 
$app->model('author');
-    eval "use $class;";
-    my @author = $class->load( { name => $name } );
-    my $author;
-    foreach (@author) {
-        next unless $_->password && ( $_->password ne '(none)' );
-        $author = $_;
-    }
-
-    my ( $rc, $res ) =
-      $app->reset_password( $author, $q->param('hint'), $name );
-
-    if ($rc) {
-        $app->add_breadcrumb( $app->translate('Password Recovery') );
-        $app->load_tmpl(
-            'dialog/recover.tmpl',
-            {
-                recovered => 1,
-                email     => $author->email
-            }
-        );
-    }
-    else {
-        $app->error($res);
-    }
-}
-
-sub recover_profile_password {
-    my $app = shift;
-    $app->validate_magic or return;
-    return $app->errtrans("Permission denied.")
-      unless $app->user->is_superuser();
-
-    my $q = $app->param;
-
-    require MT::Auth;
-    require MT::Log;
-    if ( !MT::Auth->can_recover_password ) {
-        $app->log(
-            {
-                message => $app->translate(
-"Invalid password recovery attempt; can't recover password in this 
configuration"
-                ),
-                level    => MT::Log::SECURITY(),
-                class    => 'system',
-                category => 'recover_profile_password',
-            }
-        );
-        return $app->error("Can't recover password in this configuration");
-    }
-
-    my $author_id = $q->param('author_id');
-    my $author    = MT::Author->load($author_id);
-
-    return $app->error( $app->translate("Invalid author_id") )
-      if !$author || $author->type != MT::Author::AUTHOR() || !$author_id;
-
-    my ( $rc, $res ) =
-      $app->reset_password( $author, $author->hint, $author->name );
-
-    if ($rc) {
-        my $url = $app->uri(
-            'mode' => 'view',
-            args   => { _type => 'author', recovered => 1, id => $author_id 
}
-        );
-        $app->redirect($url);
-    }
-    else {
-        $app->error($res);
-    }
-}
-
-sub reset_password {
-    my $app      = shift;
-    my ($author) = $_[0];
-    my $hint     = $_[1];
-    my $name     = $_[2];
-
-    require MT::Auth;
-    require MT::Log;
-    if ( !MT::Auth->can_recover_password ) {
-        $app->log(
-            {
-                message => $app->translate(
-"Invalid password recovery attempt; can't recover password in this 
configuration"
-                ),
-                level    => MT::Log::SECURITY(),
-                class    => 'system',
-                category => 'recover_password',
-            }
-        );
-        return ( 0,
-            $app->translate("Can't recover password in this configuration") 
);
-    }
-
-    $app->log(
-        {
-            message => $app->translate(
-                "Invalid user name '[_1]' in password recovery attempt", 
$name
-            ),
-            level    => MT::Log::SECURITY(),
-            class    => 'system',
-            category => 'recover_password',
-        }
-      ),
-      return ( 0, $app->translate("User name or password hint is 
incorrect.") )
-      unless $author;
-    return ( 0,
-        $app->translate("User has not set pasword hint; cannot recover 
password")
-    ) if ( $hint && !$author->hint );
-
-    $app->log(
-        {
-            message => $app->translate(
-                "Invalid attempt to recover password (used hint '[_1]')",
-                $hint
-            ),
-            level    => MT::Log::SECURITY(),
-            class    => 'system',
-            category => 'recover_password'
-        }
-      ),
-      return ( 0, $app->translate("User name or password hint is 
incorrect.") )
-      unless $author->hint eq $hint;
-
-    return ( 0, $app->translate("User does not have email address") )
-      unless $author->email;
-
-    my @pool = ( 'a' .. 'z', 0 .. 9 );
-    my $pass = '';
-    for ( 1 .. 8 ) { $pass .= $pool[ rand @pool ] }
-    $author->set_password($pass);
-    $author->save;
-    my $message =
-      $app->translate(
-"Password was reset for user '[_1]' (user #[_2]). Password was sent to the 
following address: [_3]",
-        $author->name, $author->id, $author->email );
-    $app->log(
-        {
-            message  => $message,
-            level    => MT::Log::SECURITY(),
-            class    => 'system',
-            category => 'recover_password'
-        }
-    );
-
-    my $address =
-      defined $author->nickname
-      ? $author->nickname . ' <' . $author->email . '>'
-      : $author->email;
-    my %head = (
-        id      => 'recover_password',
-        To      => $address,
-        From    => $app->config('EmailAddressMain') || $address,
-        Subject => $app->translate("Password Recovery")
-    );
-    my $charset = $app->charset;
-    my $mail_enc = uc( $app->config('MailEncoding') || $charset );
-    $head{'Content-Type'} = qq(text/plain; charset="$mail_enc");
-
-    my $body = $app->build_email( 'recover-password.tmpl',
-        { user_password => $pass, link_to_login => $app->base . 
$app->mt_uri } 
-    );
-    $body = wrap_text( $body, 72 );
-    require MT::Mail;
-    MT::Mail->send( \%head, $body )
-      or return (
-        0,
-        $app->translate(
-            "Error sending mail ([_1]); please fix the problem, then "
-              . "try again to recover your password.",
-            MT::Mail->errstr
-        )
-      );
-    ( 1, $message );
-}
-
-sub js_tag_list {
-    my $app     = shift;
-    my $blog_id = $app->param('blog_id');
-    my $type    = $app->param('_type') || 'entry';
-
-    my $class = $app->model($type)
-      or return $app->json_error( $app->translate("Invalid request.") );
-    my $result;
-    if (
-        my $tag_list = MT::Tag->cache(
-            blog_id => $blog_id,
-            class   => $class,
-            private => 1,
-        )
-      )
-    {
-        $result = { tags => $tag_list };
-    }
-    else {
-        $result = { tags => {} };
-    }
-    $app->json_result($result);
-}
-
-sub js_tag_check {
-    my $app       = shift;
-    my $name      = $app->param('tag_name');
-    my $blog_id   = $app->param('blog_id');
-    my $type      = $app->param('_type') || 'entry';
-    my $tag_class = $app->model('tag')
-      or return $app->json_error( $app->translate("Invalid request.") );
-    my $tag =
-      $tag_class->load( { name => $name }, { binary => { name => 1 } } );
-    my $class = $app->model($type)
-      or $app->json_error( $app->translate("Invalid request.") );
-    if ( $tag && $blog_id ) {
-        my $ot_class = $app->model('objecttag');
-        my $count    = $ot_class->count(
-            {
-                object_datasource => $class->datasource,
-                blog_id           => $blog_id,
-                tag_id            => $tag->id
-            }
-        );
-        undef $tag unless $count;
-    }
-    return $app->json_result( { exists => $tag ? 'true' : 'false' } );
-}
-
-sub recover_passwords {
-    my $app = shift;
-    my @id  = $app->param('id');
-
-    return $app->errtrans("Permission denied.")
-      unless $app->user->is_superuser();
-
-    my $class = ref $app eq 'MT::App::Upgrader' ? 'MT::BasicAuthor' : 
$app->model('author');
-    eval "use $class;";
-
-    my @msg_loop;
-    foreach (@id) {
-        my $author = $class->load($_);
-        my ( $rc, $res ) = $app->reset_password( $author, $author->hint );
-        push @msg_loop, { message => $res };
-    }
-
-    $app->load_tmpl( 'recover_password_result.tmpl',
-        { message_loop => \@msg_loop, return_url => $app->return_uri } );
-}
-
-sub _merge_default_assignments {
-    my $app = shift;
-    my ( $data, $hasher, $type, $id ) = @_;
-
-    if ( my $def = $app->config->DefaultAssignments ) {
-        my @def = split ',', $def;
-        while ( my $role_id = shift @def ) {
-            my $blog_id = shift @def;
-            next unless $role_id && $blog_id;
-            next if ( $type eq 'role' ) && ( $id != $role_id );
-            next if ( $type eq 'blog' ) && ( $id != $blog_id );
-            my $obj = MT::Association->new;
-            $obj->role_id($role_id);
-            $obj->blog_id($blog_id);
-            $obj->id( 'PSEUDO-' . $role_id . '-' . $blog_id );
-            my $row = $obj->column_values();
-            $hasher->( $obj, $row ) if $hasher;
-            $row->{user_id}   = 'PSEUDO';
-            $row->{user_name} = $app->translate('(newly created user)');
-            push @$data, $row;
-        }
-    }
-}
-
-sub build_asset_hasher {
-    my $app = shift;
-    my (%param) = @_;
-    my ($default_thumb_width, $default_thumb_height, 
$default_preview_width,
-        $default_preview_height) =
-        @param{qw( ThumbWidth ThumbHeight PreviewWidth PreviewHeight )};
-
-    require File::Basename;
-    require JSON;
-    my %blogs;
-    return sub {
-        my ( $obj, $row, %param ) = @_;
-        my ($thumb_width, $thumb_height) = @param{qw( ThumbWidth 
ThumbHeight )};
-        $row->{id} = $obj->id;
-        my $blog = $blogs{ $obj->blog_id } ||= $obj->blog;
-        $row->{blog_name} = $blog ? $blog->name : '-';
-        $row->{url} = $obj->url; # this has to be called to calculate
-        $row->{asset_type} = $obj->class_type;
-        $row->{asset_class_label} = $obj->class_label;
-        my $file_path = $obj->file_path; # has to be called to calculate
-        my $meta = $obj->metadata;
-        if ( $file_path && ( -f $file_path ) ) {
-            $row->{file_path} = $file_path;
-            $row->{file_name} = File::Basename::basename( $file_path );
-            my @stat = stat( $file_path );
-            my $size = $stat[7];
-            $row->{file_size} = $size;
-            if ( $size < 1024 ) {
-                $row->{file_size_formatted} = sprintf( "%d Bytes", $size );
-            }
-            elsif ( $size < 1024000 ) {
-                $row->{file_size_formatted} =
-                  sprintf( "%.1f KB", $size / 1024 );
-            }
-            else {
-                $row->{file_size_formatted} =
-                  sprintf( "%.1f MB", $size / 1024000 );
-            }
-            $meta->{'file_size'} = $row->{file_size_formatted};
-        }
-        else {
-            $row->{file_is_missing} = 1 if $file_path;
-        }
-        $row->{file_label} = $row->{label} = $obj->label || 
$row->{file_name} || $app->translate('Untitled');
-
-        if ($obj->has_thumbnail) { 
-            $row->{has_thumbnail} = 1;
-            my $height = $thumb_height || $default_thumb_height || 75;
-            my $width  = $thumb_width  || $default_thumb_width  || 75;
-            @$meta{qw( thumbnail_url thumbnail_width thumbnail_height )}
-              = $obj->thumbnail_url( Height => $height, Width => $width );
-
-            $meta->{thumbnail_width_offset}  = int(($width  - 
$meta->{thumbnail_width})  / 2);
-            $meta->{thumbnail_height_offset} = int(($height - 
$meta->{thumbnail_height}) / 2);
-
-            if ($default_preview_width && $default_preview_height) {
-                @$meta{qw( preview_url preview_width preview_height )}
-                  = $obj->thumbnail_url(
-                    Height => $default_preview_height,
-                    Width  => $default_preview_width,
-                );
-                $meta->{preview_width_offset}  = 
int(($default_preview_width  - $meta->{preview_width})  / 2);
-                $meta->{preview_height_offset} = 
int(($default_preview_height - $meta->{preview_height}) / 2);
-            }
-        }
-        else {
-            $row->{has_thumbnail} = 0;
-        }
-
-        my $ts = $obj->created_on;
-        if ( my $by = $obj->created_by ) {
-            my $user = MT::Author->load($by);
-            $row->{created_by} = $user ? $user->name : '';
-        }
-        if ($ts) {
-            $row->{created_on_formatted} =
-              format_ts( LISTING_DATE_FORMAT, $ts, $blog, $app->user ? 
$app->user->preferred_language : undef );
-            $row->{created_on_time_formatted} =
-              format_ts( LISTING_TIMESTAMP_FORMAT, $ts, $blog, $app->user ? 
$app->user->preferred_language : undef );
-            $row->{created_on_relative} = relative_date( $ts, time, $blog 
);
-        }
-
-        @$row{keys %$meta} = values %$meta;
-        $row->{metadata_json} = JSON::objToJson($meta);
-        $row;
-    };
-}
-
-sub list_assets {
-    my $app = shift;
-
-    my $blog_id = $app->param('blog_id');
-    my $blog;
-    if ($blog_id) {
-        my $blog_class = $app->model('blog');
-        $blog = $blog_class->load($blog_id)
-          or return $app->errtrans("Invalid request.");
-        my $perms = $app->permissions;
-        return $app->errtrans("Permission denied.")
-          unless $app->user->is_superuser
-          || (
-            $perms
-            && (   $perms->can_edit_assets
-                || $perms->can_edit_all_posts
-                || $perms->can_create_post )
-          );
-    }
-
-    my $asset_class = $app->model('asset') or return;
-    my %terms;
-    my %args = ( sort => 'created_on', direction => 'descend' );
-
-    my $class_filter;
-    my $filter = ( $app->param('filter') || '' );
-    if ( $filter eq 'class' ) {
-        $class_filter = $app->param('filter_val');
-    }
-    elsif ($filter eq 'userpic') {
-        $class_filter = 'image';
-        $terms{created_by} = $app->param('filter_val');
-
-        my $tag = MT::Tag->load( { name => '@userpic' },
-            { binary => { name => 1 } } );
-        if ($tag) {
-            require MT::ObjectTag;
-            $args{'join'} = MT::ObjectTag->join_on(
-                'object_id',
-                {
-                    tag_id            => $tag->id,
-                    object_datasource => MT::Asset->datasource
-                },
-                { unique => 1 }
-            );
-        }
-    }
-
-    $app->add_breadcrumb( $app->translate("Files") );
-    if ($blog_id) {
-        $terms{blog_id} = $blog_id;
-    }
-    elsif ((defined $blog_id) && ($blog_id ne '')) {
-        $terms{blog_id} = '0';
-    }
-    else {
-        unless ( $app->user->is_superuser ) {
-            my @perms = MT::Permission->load( { author_id => $app->user->id 
} );
-            my @blog_ids;
-            push @blog_ids, $_->blog_id
-              foreach grep { $_->can_edit_assets } @perms;
-            $terms{blog_id} = \@blog_ids;
-        }
-    }
-
-    my $hasher = $app->build_asset_hasher(
-        PreviewWidth => 240, PreviewHeight => 240 );
-
-    if ($class_filter) {
-        my $asset_pkg = MT::Asset->class_handler($class_filter);
-        $terms{class} = $asset_pkg->type_list;
-    }
-    else {
-        $terms{class} = '*';    # all classes
-    }
-
-    # identifier => name
-    my $classes = MT::Asset->class_labels;
-    my @class_loop;
-    foreach my $class ( keys %$classes ) {
-        next if $class eq 'asset';
-        push @class_loop,
-          {
-            class_id    => $class,
-            class_label => $classes->{$class},
-          };
-    }
-
-    # Now, sort it
-    @class_loop = sort { $a->{class_label} cmp $b->{class_label} } 
@class_loop;
-
-    my $dialog_view = $app->param('dialog_view') ? 1 : 0;
-    my $perms = $app->permissions;
-    my %carry_params = map { $_ => $app->param($_) || '' }
-        (qw( edit_field upload_mode require_type next_mode asset_select ));
-    $carry_params{'user_id'} = $app->param('filter_val')
-        if $filter eq 'userpic';
-    $app->_set_start_upload_params(\%carry_params);
-    $app->listing(
-        {
-            terms    => \%terms,
-            args     => \%args,
-            type     => 'asset',
-            code     => $hasher,
-            template => $dialog_view
-            ? 'dialog/asset_list.tmpl'
-            : '',
-            params => {
-                (
-                    $blog
-                    ? (
-                        blog_id   => $blog_id,
-                        blog_name => $blog->name
-                          || '',
-                        edit_blog_id => $blog_id,
-                      )
-                    : (),
-                ),
-                is_image         => defined $class_filter
-                  && $class_filter eq 'image' ? 1 : 0,
-                dialog_view      => $dialog_view,
-                search_label     => MT::Asset->class_label_plural,
-                search_type      => 'asset',
-                class_loop       => \@class_loop,
-                can_delete_files => (
-                    $perms ? $perms->can_edit_assets : 
$app->user->is_superuser
-                ),
-                nav_assets       => 1,
-                panel_searchable => 1,
-                object_type      => 'asset',
-                %carry_params,
-            },
-        }
-    );
-}
-
-sub list_roles {
-    my $app = shift;
-
-    $app->return_to_dashboard( redirect => 1 ) if $app->param('blog_id');
-
-    my $pref = $app->list_pref('role');
-    my $all_perms;
-    if ( $pref->{view_expanded} ) {
-        my @all_perms = @{ MT::Permission->perms() };
-        $all_perms = [@all_perms];
-        foreach (@$all_perms) {
-            $_->[1] = $app->translate( $_->[1] );
-        }
-    }
-
-    my $author_class = $app->model('author');
-    my $assoc_class  = $app->model('association');
-    my $hasher       = sub {
-        my ( $obj, $row ) = @_;
-        my $user_count = $assoc_class->count(
-            {
-                role_id   => $obj->id,
-                author_id => [ 1, undef ],
-            },
-            {
-                unique     => 'author_id',
-                range_incl => { author_id => 1 },
-            }
-        );
-        $row->{members} = $user_count;
-        $row->{weblogs} = $assoc_class->count(
-            {
-                role_id => $obj->id,
-                blog_id => [ 1, undef ],
-            },
-            {
-                unique     => 'blog_id',
-                range_incl => { blog_id => 1 },
-            }
-        );
-        if ( $obj->created_by ) {
-            my $user = $author_class->load( $obj->created_by );
-            $row->{created_by} = $user ? $user->name : '';
-        }
-        else {
-            $row->{created_by} = '';
-        }
-
-        # populate permissions for the expanded view
-        if ( $pref->{view_expanded} ) {
-            my @perms;
-            foreach (@$all_perms) {
-                next unless length( $_->[1] || '' );
-                push @perms, { name => $app->translate( $_->[1] ) }
-                  if $obj->has( $_->[0] );
-            }
-            $row->{perm_loop} = \@perms;
-        }
-    };
-    unless ( $app->user->is_superuser() ) {
-        return $app->errtrans("Permission denied.");
-    }
-    $app->add_breadcrumb( $app->translate("Roles") );
-    $app->listing(
-        {
-            args   => { sort => 'name' },
-            type   => 'role',
-            code   => $hasher,
-            params => {
-                nav_privileges    => 1,
-                list_noncron      => 1,
-                can_create_role   => $app->user->is_superuser,
-                has_expanded_mode => 1,
-                search_label      => $app->translate('Users'),
-                object_type       => 'role',
-                screen_id         => 'list-role',
-            },
-        }
-    );
-}
-
-sub list_associations {
-    my $app = shift;
-
-    my $blog_id   = $app->param('blog_id');
-    my $author_id = $app->param('author_id');
-    my $role_id   = $app->param('role_id');
-
-    my $this_user = $app->user;
-    if ( !$this_user->is_superuser ) {
-        if (
-            (
-                   !$blog_id
-                || !$this_user->permissions($blog_id)->can_administer_blog
-            )
-            && ( !$author_id || ( $author_id != $this_user->id ) )
-          )
-        {
-            return $app->errtrans("Permission denied.");
-        }
-    }
-
-    my ( $user, $role );
-    $app->error(undef);
-
-    if ($author_id) {
-        $app->add_breadcrumb( $app->translate('Users'),
-              $app->user->is_superuser
-            ? $app->uri( mode => 'list_authors' )
-            : undef );
-        if ( 'PSEUDO' ne $author_id ) {
-            my $author_class = $app->model('author');
-            $user = $author_class->load($author_id);
-            $app->add_breadcrumb(
-                $user->name,
-                $app->uri(
-                    mode => 'view',
-                    args => { _type => 'author', id => $author_id }
-                )
-            );
-        }
-        else {
-            $app->add_breadcrumb( $app->translate('(newly created user)') 
);
-        }
-        $app->add_breadcrumb( $app->translate('User Associations') );
-    }
-    if ($role_id) {
-        my $role_class = $app->model('role') or return;
-        $role = $role_class->load($role_id);
-        $app->add_breadcrumb( $app->translate("Roles"),
-            $app->uri( mode => "list_roles" ) );
-        $app->add_breadcrumb(
-            $role->name,
-            $app->uri(
-                mode => 'edit_role',
-                args => { _type => 'role', id => $role_id }
-            )
-        );
-        $app->add_breadcrumb( $app->translate("Role Users & Groups") );
-    }
-    if ( !$role_id  && !$author_id ) {
-        if ($blog_id) {
-            $app->add_breadcrumb( $app->translate("Users") );
-        }
-        else {
-            $app->add_breadcrumb( $app->translate("Associations") );
-        }
-    }
-
-    my $pref = $app->list_pref('association');
-    my $all_perms;
-    if ( $pref->{view_expanded} ) {
-        my @all_perms = @{ MT::Permission->perms() };
-        $all_perms = [@all_perms];
-        foreach (@$all_perms) {
-            $_->[1] = $app->translate( $_->[1] );
-        }
-    }
-
-    # Supplies additional parameters for the row being listed
-    my %users;
-    $users{ $this_user->id } = $this_user;
-    my $hasher = sub {
-        my ( $obj, $row ) = @_;
-        if ( my $user = $obj->user ) {
-            $row->{user_id}   = $user->id;
-            $row->{user_name} = $user->name;
-        }
-        if ( my $role = $obj->role ) {
-            $row->{role_name} = $role->name;
-
-            # populate permissions for the expanded view
-            if ( $pref->{view_expanded} ) {
-                my @perms;
-                foreach (@$all_perms) {
-                    next unless length( $_->[1] || '' );
-                    push @perms, { name => $app->translate( $_->[1] ) }
-                      if $role->has( $_->[0] );
-                }
-                $row->{perm_loop} = \@perms;
-            }
-        }
-        else {
-            $row->{role_name} = $app->translate("(Custom)");
-        }
-        if ( my $blog = $obj->blog ) {
-            $row->{blog_name} = $blog->name;
-        }
-        if ( my $ts = $obj->created_on ) {
-            $row->{created_on_formatted} =
-              format_ts( LISTING_DATE_FORMAT, $ts, $obj->blog, $app->user ? 
$app->user->preferred_language : undef );
-            $row->{created_on_time_formatted} =
-              format_ts( LISTING_TIMESTAMP_FORMAT, $ts, $obj->blog, 
$app->user ? $app->user->preferred_language : undef );
-            $row->{created_on_relative} =
-              relative_date( $ts, time, $obj->blog );
-        }
-        if ( $row->{created_by} ) {
-            my $created_user = $users{ $row->{created_by} } ||=
-              MT::Author->load( $row->{created_by} );
-            if ($created_user) {
-                $row->{created_by} = $created_user->name;
-            }
-            else {
-                $row->{created_by} = $app->translate('(user deleted)');
-            }
-        }
-    };
-    $app->model('association') or return;
-    my $types;
-    if ( !$author_id && !$blog_id ) {
-        $types = [
-            MT::Association::USER_BLOG_ROLE(),
-            MT::Association::USER_ROLE(),
-        ];
-    }
-    elsif ( !$author_id ) {
-        $types = [
-            MT::Association::USER_BLOG_ROLE(),
-        ];
-    }
-    elsif ($author_id) {
-        $types =
-          [ MT::Association::USER_BLOG_ROLE(), MT::Association::USER_ROLE() 
];
-    }
-
-    my $pre_build = sub {
-        my ($param) = @_;
-        my $data = $param->{object_loop} || [];
-
-        #TODO: handle group_view
-        if ( $param->{user_view}
-            && ( 'PSEUDO' ne $param->{edit_author_id} ) )
-        {
-
-            # don't merge
-        }
-        elsif ( $param->{role_view} ) {
-            $app->_merge_default_assignments( $data, $hasher, 'role',
-                $param->{role_id} );
-        }
-        elsif ( $param->{blog_view} ) {
-            $app->_merge_default_assignments( $data, $hasher, 'blog',
-                $param->{blog_id} );
-        }
-        else {
-            $app->_merge_default_assignments( $data, $hasher, 'all' );
-        }
-    };
-
-    return $app->listing(
-        {
-            args  => { sort => 'created_on', direction => 'descend' },
-            type  => 'association',
-            code  => $hasher,
-            terms => {
-                type => $types,
-                $author_id ? ( author_id => $author_id ) : (),
-                $blog_id   ? ( blog_id   => $blog_id )   : (),
-                $role_id   ? ( role_id   => $role_id )   : (),
-            },
-            pre_build => $pre_build,
-            params => {
-                can_create_association => $app->user->is_superuser || ( 
$blog_id
-                    && 
$app->user->permissions($blog_id)->can_administer_blog ),
-                has_expanded_mode => 1,
-                nav_privileges =>
-                  ( $author_id || $blog_id ? 0 : 1 ) || $role_id,
-                nav_authors => ( $author_id || $blog_id ? 1 : 0 )
-                  && !$role_id,
-                blog_view     => $blog_id   ? 1 : 0,
-                user_view     => $author_id ? 1 : 0,
-                role_view     => $role_id   ? 1 : 0,
-                $role_id
-                ? (
-                    role_id   => $role_id,
-                    role_name => $role->name,
-                  )
-                : (),
-                $author_id
-                ? (
-                    edit_author_id   => $author_id,
-                    edit_name => $user
-                    ? ( $user->nickname ? $user->nickname : $user->name )
-                    : $app->translate('(newly created user)'),
-                    edit_object => $app->translate('The user'),
-                    group_count => $user ? $user->group_count() : 0,
-                    status_enabled => $user ? ( $user->is_active ? 1 : 0 ) 
: 0,
-                    status_pending => $user
-                    ? ( $user->status == MT::Author::PENDING() ? 1 : 0 )
-                    : 0,
-                  )
-                : (),
-                saved         => $app->param('saved')         || 0,
-                saved_deleted => $app->param('saved_deleted') || 0,
-                usergroup_view => !$author_id  && !$role_id,
-                blog_id => $blog_id,
-                search_label => $app->translate('Users'),
-                object_type  => 'association',
-                pt_name => $app->translate('User'),
-                screen_id => "list-associations",
-            },
-        }
-    );
-}
-
-sub list_tag {
-    my $app = shift;
-    my %param;
-    my $filter_key = $app->param('filter_key') || 'entry';
-    my $type       = $app->param('_type')      || $filter_key;
-    my $plural;
-    $param{TagObjectType} = $type;
-    $param{Package}       = $app->model($type);
-
-    if ( !$app->blog && !$app->user->is_superuser ) {
-        return $app->errtrans("Permission denied.");
-    }
-
-    my $perms = $app->permissions;
-    if ( $app->blog && ( ( !$perms ) || ( $perms && $perms->is_empty ) ) ) 
{
-        $app->delete_param('blog_id');
-        return $app->return_to_dashboard( permission => 1 );
-    }
-
-    if ( $param{Package}->can('class_label_plural') ) {
-        $plural = $param{Package}->class_label_plural();
-    }
-    else {
-        if ( $type =~ m/y$/ ) {
-            $plural = $type;
-            $plural =~ s/y$/ies/;
-        }
-        else {
-            $plural = $type . 's';
-        }
-        $plural =~ s/(.*)/\u$1/;
-    }
-
-    $param{TagObjectLabelPlural} = $plural;
-    $app->model($type) or return;
-    unless ( UNIVERSAL::can( $param{Package}, 'tag_count' ) ) {
-        return $app->errtrans("Invalid type");
-    }
-    $app->list_tag_for(%param);
-}
-
-sub list_tag_for {
-    my $app = shift;
-    my (%params) = @_;
-
-    my $pkg = $params{Package};
-
-    my $q         = $app->param;
-    my $blog_id   = $app->param('blog_id');
-    my $list_pref = $app->list_pref('tag');
-    my %param     = %$list_pref;
-
-    my $limit = $list_pref->{rows};
-    my $offset = $app->param('offset') || 0;
-
-    my ( %terms, %arg );
-
-    my $tag_class = $app->model('tag');
-    my $ot_class  = $app->model('objecttag');
-    my $total = $pkg->tag_count( $blog_id ? { blog_id => $blog_id } : undef 
)
-      || 0;
-
-    $arg{'sort'} = 'name';
-    $arg{limit} = $limit + 1;
-    if ( $total && $offset > $total - 1 ) {
-        $arg{offset} = $offset = $total - $limit;
-    }
-    elsif ( $offset && ( ( $offset < 0 ) || ( $total - $offset < $limit ) ) 
) {
-        $arg{offset} = $offset = $total - $limit;
-    }
-    else {
-        $arg{offset} = $offset if $offset;
-    }
-    $arg{join} = $ot_class->join_on(
-        'tag_id',
-        {
-            object_datasource => $pkg->datasource,
-            ( $blog_id ? ( blog_id => $blog_id ) : () )
-        },
-        {
-            unique => 1,
-            'join' => $pkg->join_on(
-                undef,
-                {
-                    id => \'= objecttag_object_id',
-                    ( $pkg =~ m/asset/i ? () : ( class => $pkg->class_type 
) )
-                }
-            )
-        }
-    );
-
-    my $data = $app->build_tag_table(
-        load_args => [ \%terms, \%arg ],
-        'package' => $pkg,
-        param     => \%param
-    );
-    delete $param{tag_table} unless @$data;
-
-    ## We tried to load $limit + 1 entries above; if we actually got
-    ## $limit + 1 back, we know we have another page of entries.
-    my $have_next_entry = @$data > $limit;
-    pop @$data while @$data > $limit;
-    if ($offset) {
-        $param{prev_offset}     = 1;
-        $param{prev_offset_val} = $offset - $limit;
-        $param{prev_offset_val} = 0 if $param{prev_offset_val} < 0;
-    }
-    if ($have_next_entry) {
-        $param{next_offset}     = 1;
-        $param{next_offset_val} = $offset + $limit;
-    }
-
-    # load tag filters
-    my $filters = $app->registry( "list_filters", "tag" ) || {};
-    my $filter_key = $app->param('filter_key') || 'entry';
-    my $filter_label = '';
-    if ( my $filter = $filters->{$filter_key} ) {
-        $filter_label = $filter->{label};
-    }
-
-    $param{limit}                   = $limit;
-    $param{offset}                  = $offset;
-    $param{tag_object_type}         = $params{TagObjectType};
-    $param{tag_object_label}        = $params{TagObjectLabel} || 
$pkg->class_label;
-    $param{tag_object_label_plural} = $params{TagObjectLabelPlural} || 
$pkg->class_label_plural;
-    $param{object_label}            = $tag_class->class_label;
-    $param{object_label_plural}     = $tag_class->class_label_plural;
-    $param{object_type}             = 'tag';
-
-    my $search_types = $app->search_apis($app->blog ? 'blog' : 'system');
-    if (grep { $_->{key} eq $param{tag_object_type} } @$search_types) {
-        $param{search_type} = $param{tag_object_type};
-        $param{search_label} = $param{tag_object_label_plural};
-    } else {
-        $param{search_type} = 'entry';
-        $param{search_label} = $app->translate("Entries");
-    }
-
-    $param{list_start}              = $offset + 1;
-    $param{list_end}                = $offset + scalar @$data;
-    $param{list_total}              = $total;
-    $param{next_max}                = $param{list_total} - $limit;
-    $param{next_max}     = 0 if ( $param{next_max} || 0 ) < $offset + 1;
-    $param{list_noncron} = 1;
-    $param{list_filters} = $app->list_filters('tag');
-    $param{filter_key}   = $filter_key;
-    $param{filter_label} = $filter_label;
-    $param{link_to}      = 'list_' . lc $params{TagObjectType};
-
-    $param{saved}         = $q->param('saved');
-    $param{saved_deleted} = $q->param('saved_deleted');
-    $param{nav_tags}      = 1;
-    $app->add_breadcrumb( $app->translate('Tags') );
-    $param{screen_class} = "list-tag";
-    $param{screen_id} = "list-tag";
-    $param{listing_screen} = 1;
-
-    $app->load_tmpl( 'list_tag.tmpl', \%param );
-}
-
-sub rename_tag {
-    my $app     = shift;
-    my $perms   = $app->permissions;
-    my $blog_id = $app->blog->id if $app->blog;
-    ( $blog_id && $perms && $perms->can_edit_tags )
-      || ( $app->user->is_superuser() )
-      or return $app->errtrans("Permission denied.");
-    my $id        = $app->param('__id');
-    my $name      = $app->param('tag_name')
-      or return $app->error( $app->translate("New name of the tag must be 
specified.") );
-    my $obj_type  = $app->param('__type') || 'entry';
-    my $obj_class = $app->model($obj_type);
-    my $tag_class = $app->model('tag');
-    my $ot_class  = $app->model('objecttag');
-    my $tag       = $tag_class->load($id)
-      or return $app->error( $app->translate("No such tag") );
-    my $tag2 =
-      $tag_class->load( { name => $name }, { binary => { name => 1 } } );
-
-    if ($tag2) {
-        return $app->call_return if $tag->id == $tag2->id;
-    }
-
-    my $terms = { tag_id => $tag->id };
-    $terms->{blog_id} = $blog_id if $blog_id;
-
-    my $iter = $obj_class->load_iter(
-        {
-            (
-                $obj_type =~ m/asset/i
-                ? ( class => '*' )
-                : ( class => $obj_type )
-            )
-        },
-        { join => MT::ObjectTag->join_on( 'object_id', $terms ) }
-    );
-    my @tagged_objects;
-    while ( my $o = $iter->() ) {
-        $o->remove_tags( $tag->name );
-        $o->add_tags($name);
-        push @tagged_objects, $o;
-    }
-    $_->save foreach @tagged_objects;
-
-    if ($tag2) {
-        $app->add_return_arg( merged => 1 );
-    }
-    else {
-        $app->add_return_arg( renamed => 1 );
-    }
-    $app->call_return;
-}
-
-sub build_tag_table {
-    my $app = shift;
-    my (%args) = @_;
-
-    my $iter;
-    if ( $args{load_args} ) {
-        my $class = $app->model('tag');
-        $iter = $class->load_iter( @{ $args{load_args} } );
-    }
-    elsif ( $args{iter} ) {
-        $iter = $args{iter};
-    }
-    elsif ( $args{items} ) {
-        $iter = sub { shift @{ $args{items} } };
-    }
-    return [] unless $iter;
-
-    my $param   = $args{param} || {};
-    my $blog_id = $app->param('blog_id');
-    my $pkg     = $args{'package'};
-
-    my @data;
-    while ( my $tag = $iter->() ) {
-        my $count = $pkg->tagged_count(
-            $tag->id,
-            {
-                ( $blog_id ? ( blog_id => $blog_id ) : () ),
-                ( $pkg =~ m/asset/i ? ( class => '*' ) : () )
-            }
-        );
-        $count ||= 0;
-        my $row = {
-            tag_id    => $tag->id,
-            tag_name  => $tag->name,
-            tag_count => $count,
-            object    => $tag,
-        };
-        push @data, $row;
-    }
-    return [] unless @data;
-
-    $param->{tag_table}[0]{object_loop} = \@data;
-    $app->load_list_actions( 'tag', $param->{tag_table}[0] );
-    $param->{object_loop} = $param->{tag_table}[0]{object_loop};
-}
-
-sub load_text_filters {
-    my $app = shift;
-    my ( $selected, $type ) = @_;
-
-    $selected = '0' unless defined $selected;
-
-    my $filters = MT->all_text_filters;
-    if ( $selected eq '1' ) {
-        $selected = '__default__';
-    }
-    my @f;
-    for my $filter ( keys %$filters ) {
-        if ( my $c = $filters->{$filter}{condition} ) {
-            $c = $app->handler_to_coderef($c) unless ref $c;
-            next unless $c->($type);
-        }
-        my $label = $filters->{$filter}{label};
-        $label = $label->() if ref($label) eq 'CODE';
-        my $row = {
-            key   => $filter,
-            label => $label,
-        };
-        $row->{selected} = $filter eq $selected;
-        push @f, $row;
-    }
-    @f = sort { $a->{label} cmp $b->{label} } @f;
-    unshift @f,
-      {
-        key      => '0',
-        label    => $app->translate('None'),
-        selected => !$selected,
-      };
-    return \@f;
-}
-
 sub is_authorized {
     my $app     = shift;
     my $blog_id = $app->param('blog_id');
@@ -3275,189 +1783,6 @@
     $app->SUPER::build_page( $page, $param );
 }
 
-sub generate_dashboard_stats {
-    my $app = shift;
-    my ($param) = @_;
-
-    my $cache_time = 60 * 15;    # cache for 15 minutes
-
-    my $blog_id = $app->blog ? $app->blog->id : 0;
-    my $user    = $app->user;
-    my $user_id = $user->id;
-
-    my $static_path      = $app->static_path;
-    my $static_file_path = $app->static_file_path;
-
-    if ( -f File::Spec->catfile( $static_file_path, "mt.js" ) ) {
-        $param->{static_file_path} = $static_file_path;
-    }
-    else {
-        return;
-    }
-
-    my $low_dir = sprintf("%03d", $user_id % 1000);
-    my $sub_dir = sprintf("%03d", $blog_id % 1000);
-    my $top_dir = $blog_id > $sub_dir ? $blog_id - $sub_dir : 0;
-    $param->{support_path} =
-      File::Spec->catdir( $static_file_path, 'support', 'dashboard', 
'stats',
-        $top_dir, $sub_dir, $low_dir); 
-
-    require MT::FileMgr;
-    my $fmgr = MT::FileMgr->new('Local');
-    unless ( $fmgr->exists( $param->{support_path} ) ) {
-        $fmgr->mkpath( $param->{support_path} );
-        unless ( $fmgr->exists( $param->{support_path} ) ) {
-            return;
-        }
-    }
-
-    my $stats_static_path = $static_path . 'support/dashboard/stats/' .
-        $top_dir . '/' . $sub_dir . '/' . $low_dir;
-
-    my $tabs = $app->registry('blog_stats_tabs') or return;
-    while (my ($tab_id, $tab) = each %$tabs) {
-        my $file = "${tab_id}.xml";
-        $param->{stat_url}->{$tab_id} = $stats_static_path . '/' . $file;
-        my $path = File::Spec->catfile( $param->{support_path}, $file );
-
-        my $time = ( stat($path) )[9] if -f $path;
-
-        if ( !$time || ( time - $time > $cache_time ) ) {
-            my $gen_stats = $tab->{stats};
-            next if !$gen_stats;
-            $gen_stats = $app->handler_to_coderef($gen_stats);
-
-            my %counts = $gen_stats->($app, $tab);
-
-            unless ( $app->create_dashboard_stats_file( $path, \%counts ) ) 
{
-                delete $param->{stat_url}->{$tab_id};
-            }
-        }
-    }
-
-    1;
-}
-
-sub generate_dashboard_stats_entry_tab {
-    my $app = shift;
-    my ($tab) = @_;
-    
-    my $blog_id = $app->blog ? $app->blog->id : 0;
-    my $user    = $app->user;
-    my $user_id = $user->id;
-
-    my $entry_class = $app->model('entry');
-    my $terms       = { status => MT::Entry::RELEASE() };
-    my $args        = {
-        group => [
-            "extract(year from authored_on)",
-            "extract(month from authored_on)",
-            "extract(day from authored_on)"
-        ],
-    };
-    $terms->{blog_id} = $blog_id if $blog_id;
-    if ( !$user->is_superuser && !$blog_id ) {
-        $args->{join} = MT::Permission->join_on(
-            undef,
-            {
-                blog_id   => \'= entry_blog_id',
-                author_id => $user_id
-            },
-        );
-    }
-
-    my $entry_iter = $entry_class->count_group_by( $terms, $args );
-    my %counts;
-    while ( my ( $count, $y, $m, $d ) = $entry_iter->() ) {
-        my $date = sprintf( "%04d%02d%02dT00:00:00", $y, $m, $d );
-        $counts{$date} = $count;
-    }
-
-    %counts;
-}
-
-sub generate_dashboard_stats_comment_tab {
-    my $app = shift;
-    my ($tab) = @_;
-    
-    my $blog_id = $app->blog ? $app->blog->id : 0;
-    my $user    = $app->user;
-    my $user_id = $user->id;
-
-    my $cmt_class = $app->model('comment');
-    my $terms = { visible => 1 };
-    $terms->{blog_id} = $blog_id if $blog_id;
-    my $from =
-      substr( epoch2ts( $app->blog, time - 120 * 24 * 60 * 60 ), 0, 8 )
-      . '000000';
-    $terms->{created_on} = [ $from, undef ];
-    my $args = {
-        group => [
-            "extract(year from created_on)",
-            "extract(month from created_on)",
-            "extract(day from created_on)"
-        ],
-        range => { created_on => 1 },
-    };
-    if ( !$user->is_superuser && !$blog_id ) {
-        $args->{join} = MT::Permission->join_on(
-            undef,
-            {
-                blog_id   => \'= comment_blog_id',
-                author_id => $user_id
-            },
-        );
-    }
-    my $cmt_iter = $cmt_class->count_group_by( $terms, $args );
-
-    my %counts;
-    while ( my ( $count, $y, $m, $d ) = $cmt_iter->() ) {
-        my $date = sprintf( "%04d%02d%02dT00:00:00", $y, $m, $d );
-        $counts{$date} = $count;
-    }
-
-    %counts;
-}
-
-sub create_dashboard_stats_file {
-    my $app = shift;
-    my ( $file, $data ) = @_;
-
-    my $support_dir = File::Spec->catdir( $app->static_file_path, "support" 
);
-    if ( !-d $support_dir ) {
-        mkdir( $support_dir, 0777 );
-        if ($!) {
-            $app->log("Failed to create 'support' directory.");
-            return;
-        }
-    }
-
-    local *FOUT;
-    if ( !open( FOUT, ">$file" ) ) {
-        return;
-    }
-
-    print FOUT <<EOT;
-<?xml version="1.0"?>
-<rsp status_code="0" status_message="Success">
-  <daily_counts>
-EOT
-    my $now = time;
-    for ( my $i = 120 ; $i >= 1 ; $i-- ) {
-        my $ds =
-          substr( epoch2ts( $app->blog, $now - ( ( $i - 1 ) * 60 * 60 * 24 
) ),
-            0, 8 )
-          . 'T00:00:00';
-        my $count = $data->{$ds} || 0;
-        print FOUT qq{    <count date="$ds">$count</count>\n};
-    }
-    print FOUT <<EOT;
-  </daily_counts>
-</rsp>
-EOT
-    close FOUT;
-}
-
 sub build_blog_selector {
     my $app = shift;
     my ($param) = @_;
@@ -3755,213 +2080,6 @@
     $param->{sys_nav_loop} = \@sys;
 }
 
-sub get_newsbox_content {
-    my $app = shift;
-    my $newsbox_url = $app->config('NewsboxURL');
-    if ( $newsbox_url && $newsbox_url ne 'disable' ) {
-        return MT::Util::get_newsbox_html($newsbox_url, 'NW');
-    }
-    return q();
-}
-
-sub get_lmt_content {
-    my $app = shift;
-    my $newsbox_url = $app->config('LearningNewsURL');
-    if ( $newsbox_url && $newsbox_url ne 'disable' ) {
-        return MT::Util::get_newsbox_html($newsbox_url, 'LW');
-    }
-    return q();
-}
-
-sub make_blog_list {
-    my $app = shift;
-    my ($blogs) = @_;
-
-    my $tbp_class     = $app->model('ping');
-    my $entry_class   = $app->model('entry');
-    my $comment_class = $app->model('comment');
-    my $author        = $app->user;
-    my $data;
-    my $i;
-    my @blog_ids;
-    push @blog_ids, $_->id for @$blogs;
-    my ( $entry_count, $ping_count, $comment_count );
-    my $can_edit_authors = 1 if $author->is_superuser;
-
-    for my $blog (@$blogs) {
-        my $blog_id = $blog->id;
-        my $perms   = $author->permissions($blog_id);
-        my $row     = {
-            id          => $blog->id,
-            name        => $blog->name,
-            description => $blog->description,
-            site_url    => $blog->site_url
-        };
-
-        # we should use count by group here...
-        $row->{num_entries} =
-          ( $entry_count ? $entry_count->{$blog_id} : 
$entry_count->{$blog_id} =
-              MT::Entry->count( { blog_id => $blog_id } ) )
-          || 0;
-        $row->{num_comments} = (
-              $comment_count
-            ? $comment_count->{$blog_id}
-            : $comment_count->{$blog_id} = MT::Comment->count(
-                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
-            )
-          )
-          || 0;
-        $row->{num_pings} = (
-            $ping_count ? $ping_count->{$blog_id} : $ping_count->{$blog_id} 
=
-              MT::TBPing->count(
-                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
-              )
-        ) || 0;
-        $row->{num_authors} = 0;
-
-        # FIXME: this isn't efficient
-        my $iter = MT::Permission->load_iter(
-            {
-                blog_id => [ 0, $blog_id ],
-
-                #    role_mask => [ 2, undef ]
-                #}, {
-                #    range_incl => { 'role_mask' => 1 }
-            }
-        );
-        my %a;
-        while ( my $p = $iter->() ) {
-            next if exists $a{ $p->author_id };
-            $a{ $p->author_id } = 1;
-            $row->{num_authors}++ if $p->can_create_post;
-        }
-        $row->{can_create_post}  = $perms->can_create_post;
-        $row->{can_edit_entries} = $perms->can_create_post
-          || $perms->can_edit_all_posts
-          || $perms->can_publish_post;
-        $row->{can_edit_templates} = $perms->can_edit_templates;
-        $row->{can_edit_config}    = $perms->can_edit_config
-          || $perms->can_administer_blog;
-        $row->{can_set_publish_paths} = $perms->can_set_publish_paths
-          || $perms->can_administer_blog;
-        $row->{can_manage_feedback} = $perms->can_manage_feedback;
-        $row->{can_edit_assets}     = $perms->can_edit_assets;
-        $row->{can_administer_blog} = $perms->can_administer_blog;
-        push @$data, $row;
-    }
-    $data;
-}
-
-sub build_blog_table {
-    my $app = shift;
-    my (%args) = @_;
-
-    my $blog_class    = $app->model('blog');
-    my $tbp_class     = $app->model('ping');
-    my $entry_class   = $app->model('entry');
-    my $comment_class = $app->model('comment');
-
-    my $iter;
-    if ( $args{load_args} ) {
-        my $class = $app->model('blog');
-        $iter = $class->load_iter( @{ $args{load_args} } );
-    }
-    elsif ( $args{iter} ) {
-        $iter = $args{iter};
-    }
-    elsif ( $args{items} ) {
-        $iter = sub { pop @{ $args{items} } };
-    }
-    return [] unless $iter;
-    my $param = $args{param};
-
-    my $author           = $app->user;
-    my $can_edit_authors = $author->is_superuser;
-    my @data;
-    my $i;
-    my ( $entry_count, $ping_count, $comment_count );
-    while ( my $blog = $iter->() ) {
-        my $blog_id = $blog->id;
-        my $row     = {
-            id          => $blog->id,
-            name        => $blog->name,
-            description => $blog->description,
-            site_url    => $blog->site_url
-        };
-
-        # we should use count by group here...
-        $row->{num_entries} =
-          ( $entry_count ? $entry_count->{$blog_id} : 
$entry_count->{$blog_id} =
-              MT::Entry->count( { blog_id => $blog_id } ) )
-          || 0;
-        $row->{num_comments} = (
-              $comment_count
-            ? $comment_count->{$blog_id}
-            : $comment_count->{$blog_id} = MT::Comment->count(
-                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
-            )
-          )
-          || 0;
-        $row->{num_pings} = (
-            $ping_count ? $ping_count->{$blog_id} : $ping_count->{$blog_id} 
=
-              MT::TBPing->count(
-                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
-              )
-        ) || 0;
-        $row->{num_authors} = 0;
-
-        # FIXME: This isn't efficient
-        my $iter = MT::Permission->load_iter(
-            {
-                blog_id => [ 0, $blog_id ],
-
-                #    role_mask => [ 2, undef ]
-                #}, {
-                #    range_incl => { 'role_mask' => 1 }
-            }
-        );
-        my %a;
-        while ( my $p = $iter->() ) {
-            next if exists $a{ $p->author_id };
-            $a{ $p->author_id } = 1;
-            $row->{num_authors}++ if $p->can_create_post;
-        }
-        if ( $author->is_superuser ) {
-            $row->{can_create_post}       = 1;
-            $row->{can_edit_entries}      = 1;
-            $row->{can_edit_templates}    = 1;
-            $row->{can_edit_config}       = 1;
-            $row->{can_set_publish_paths} = 1;
-            $row->{can_administer_blog}   = 1;
-        }
-        else {
-            my $perms = $author->permissions($blog_id);
-            $row->{can_create_post}  = $perms->can_create_post;
-            $row->{can_edit_entries} = $perms->can_create_post
-              || $perms->can_edit_all_posts
-              || $perms->can_publish_post;
-            $row->{can_edit_templates} = $perms->can_edit_templates;
-            $row->{can_edit_config}    = $perms->can_edit_config
-              || $perms->can_administer_blog;
-            $row->{can_set_publish_paths} = $perms->can_set_publish_paths
-              || $perms->can_administer_blog;
-            $row->{can_administer_blog} = $perms->can_administer_blog;
-        }
-        $row->{object} = $blog;
-        push @data, $row;
-    }
-
-    if (@data) {
-        $param->{blog_table}[0]{object_loop} = \@data;
-        $app->load_list_actions( 'blog', \%$param );
-        $param->{object_loop} = $param->{blog_table}[0]{object_loop};
-    }
-
-    \@data;
-}
-
-## Application methods
-
 sub return_to_dashboard {
     my $app = shift;
     my (%param) = @_;
@@ -3971,267 +2089,6 @@
     return $app->redirect( $app->uri( mode => 'dashboard', args => \%param 
) );
 }
 
-sub dashboard {
-    my $app = shift;
-    my (%param) = @_;
-
-    if ( $app->request('fresh_login') ) {
-        if ( !$app->param('blog_id') ) {
-
-            # return to the last blog they visted, if any
-            my $fav_blogs = $app->user->favorite_blogs || [];
-            my $blog_id = $fav_blogs->[0] if @$fav_blogs;
-            $app->param( 'blog_id', $blog_id ) if $blog_id;
-            $app->delete_param('blog_id') unless $app->is_authorized;
-        }
-    }
-
-    my $param = \%param;
-
-    $param->{redirect}   ||= $app->param('redirect');
-    $param->{permission} ||= $app->param('permission');
-    $param->{saved}      ||= $app->param('saved');
-
-    $param->{system_overview_nav} = $app->param('blog_id') ? 0 : 
defined($app->param('blog_id')) ? 1 : 0;
-    $param->{quick_search}        = 0;
-    $param->{no_breadcrumbs}      = 1;
-    $param->{screen_class}        = "dashboard";
-    $param->{screen_id}           = "dashboard";
-
-    my $default_widgets = {
-        'blog_stats' =>
-          { param => { tab => 'entry' }, order => 1, set => 'main' },
-        'this_is_you-1' => { order => 1, set => 'sidebar' },
-        'mt_shortcuts'  => { order => 2, set => 'sidebar' },
-        'mt_news'       => { order => 3, set => 'sidebar' },
-    };
-
-    require MT::FileMgr;
-    my $fmgr = MT::FileMgr->new('Local');
-    $param->{support_path} =
-        File::Spec->catdir( $app->static_file_path, 'support', 'uploads' );
-    if ( $fmgr->exists( $param->{support_path} ) ) {
-        $param->{has_uploads_path} = 1;
-    } else {
-        $fmgr->mkpath( $param->{support_path} );
-        if ( $fmgr->exists( $param->{support_path} )
-             && $fmgr->can_write( $param->{support_path} ) )
-        {
-            $param->{has_uploads_path} = 1;
-        }
-    }
-
-    # We require that the determination of the 'single blog mode'
-    # state be done PRIOR to the generation of the widgets
-    $app->build_blog_selector($param);
-    $app->load_widget_list( 'dashboard', $param, $default_widgets );
-    $param = $app->load_widgets( 'dashboard', $param, $default_widgets );
-    return $app->load_tmpl( "dashboard.tmpl", $param );
-}
-
-sub mt_blog_stats_widget_comment_tab {
-    my ($app, $tmpl, $param) = @_;
-
-    my $user    = $app->user;
-    my $blog    = $app->blog;
-    my $blog_id = $blog->id if $blog;
-
-    $param->{editable} = $user->is_superuser;
-    if ( $blog && !$param->{editable} ) {
-        $param->{editable} = 
$user->permissions($blog_id)->can_edit_all_posts;
-        $param->{comment_editable} = 
$user->permissions($blog_id)->can_manage_feedback;
-    }
-
-    my $comments = sub {
-        my $args = {
-            limit     => 10,
-            sort      => 'created_on',
-            direction => 'descend',
-        };
-        if ( !$user->is_superuser && !$blog_id ) {
-            $args->{join} = MT::Permission->join_on(
-                undef,
-                {
-                    blog_id   => \'= comment_blog_id',
-                    author_id => $user->id
-                },
-            );
-        }
-        my @c = MT::Comment->load(
-            {
-                ( $blog_id ? ( blog_id => $blog_id ) : () ),
-                junk_status => [ 0, 1 ],
-            },
-            $args
-        );
-        \@c;
-    };
-
-    require MT::Promise;
-    my $ctx = $tmpl->context;
-    $ctx->stash( 'comments',  MT::Promise::delay($comments) );
-}
-
-sub mt_blog_stats_widget_entry_tab {
-    my ($app, $tmpl, $param) = @_;
-
-    my $user    = $app->user;
-    my $blog    = $app->blog;
-    my $blog_id = $blog->id if $blog;
-
-    $param->{editable} = $user->is_superuser;
-    if ( $blog && !$param->{editable} ) {
-        $param->{editable} = 
$user->permissions($blog_id)->can_edit_all_posts;
-    }
-
-    my $entries = sub {
-        my $args = {
-            limit     => 10,
-            sort      => 'authored_on',
-            direction => 'descend',
-        };
-        if ( !$user->is_superuser && !$blog_id ) {
-            $args->{join} = MT::Permission->join_on(
-                undef,
-                {
-                    blog_id   => \'= entry_blog_id',
-                    author_id => $user->id
-                },
-            );
-        }
-        my @e =
-          MT::Entry->load( { ( $blog_id ? ( blog_id => $blog_id ) : () ), 
},
-            $args );
-        \@e;
-    };
-
-    require MT::Promise;
-    my $ctx = $tmpl->context;
-    $ctx->stash( 'entries',  MT::Promise::delay($entries) );
-}
-
-sub mt_blog_stats_widget {
-    my $app = shift;
-    my ( $tmpl, $param ) = @_;
-
-    # For stats shown on this page
-    $app->generate_dashboard_stats($param) or return;
-
-    my $tabs = $app->registry('blog_stats_tabs') or return;
-    $tabs = $app->filter_conditional_list($tabs, 'dashboard', 
($param->{widget_scope} || ''));
-
-    $param->{tab_html_head} = '';
-    {
-        local $param->{main};
-        local $param->{html_head};
-
-        my %cfgs;
-        my $stat_url = delete $param->{stat_url};
-        while (my ($tab_id, $url) = each %$stat_url) {
-            $param->{has_stat_urls} = 1;
-            $cfgs{$tab_id} = { param => { stat_url => $url } };
-        }
-        $app->build_widgets(
-            set            => 'blog_stats',
-            param          => $param,
-            widgets        => $tabs,
-            widget_cfgs    => \%cfgs,
-            passthru_param => [qw( html_head js_include tabs 
active_stats_panel_updates )],
-        ) or return;
-
-        $param->{blog_stats} = $param->{main};
-        $param->{tab_html_head} .= $param->{html_head};
-    }
-}
-
-sub mt_news_widget {
-    my $app = shift;
-    my ( $tmpl, $param ) = @_;
-
-    $param->{news_html} = $app->get_newsbox_content() || '';
-    $param->{learning_mt_news_html} = $app->get_lmt_content() || '';
-}
-
-sub new_version_widget {
-    my $app = shift;
-    my ( $tmpl, $param ) = @_;
-
-    push @{ $param->{feature_loop} ||= [] },
-      {
-        feature_label => MT->translate('Shared Template Modules'),
-        feature_url  => $app->help_url('designer/shared-templates.html'),
-        feature_description => MT->translate('Reuse elements of your site 
design or layout across all the blogs and sites managed within Movable 
Type.')
-      },
-      {
-        feature_label