﻿Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.87
diff -u -r1.87 system.api.php
--- modules/system/system.api.php	14 Oct 2009 10:56:35 -0000	1.87
+++ modules/system/system.api.php	14 Oct 2009 18:13:24 -0000
@@ -2507,5 +2507,30 @@
 }
 
 /**
+ * Defines one or more hooks that are exposed by a module.
+ *
+ * Normally hooks do not need to be explicitly defined.  However,
+ * by declaring a hook explicitly a module may define a
+ * "hook group" for it.  Modules that implement a hook may
+ * then place their implementation in either $module.module or
+ * in $module.$group.inc.  If the hook is in the second file,
+ * that file will be lazy-loaded as needed.  In general, hooks
+ * that are rarely invoked and/or are very large should be placed
+ * in a separate include file while hooks that are very short
+ * or are very frequently called should be left in the main
+ * module file so that they are always available.
+ */
+function hook_hook_info() {
+  $hooks['menu'] = array(
+    'group' => 'registry',
+  );
+  $hooks['theme'] = array(
+    'group' => 'registry',
+  );
+
+  return $hooks;
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.810
diff -u -r1.810 system.module
--- modules/system/system.module	13 Oct 2009 21:34:15 -0000	1.810
+++ modules/system/system.module	14 Oct 2009 18:13:24 -0000
@@ -2489,6 +2489,26 @@
 }
 
 /**
+ * Implement hook_hook_info();
+ */
+function system_hook_info() {
+  $hooks['menu'] = array(
+    'group' => 'registry',
+  );
+  $hooks['theme'] = array(
+    'group' => 'registry',
+  );
+  $hooks['token_info'] = array(
+    'group' => 'tokens',
+  );
+  $hooks['tokens'] = array(
+    'group' => 'tokens',
+  );
+
+  return $hooks;
+}
+
+/**
  * Implement hook_cron().
  *
  * Remove older rows from flood and batch table. Remove old temporary files.
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1145
diff -u -r1.1145 node.module
--- modules/node/node.module	11 Oct 2009 03:07:18 -0000	1.1145
+++ modules/node/node.module	14 Oct 2009 18:13:24 -0000
@@ -117,50 +117,6 @@
 }
 
 /**
- * Implement hook_theme().
- */
-function node_theme() {
-  return array(
-    'node' => array(
-      'arguments' => array('elements' => NULL),
-      'template' => 'node',
-    ),
-    'node_list' => array(
-      'arguments' => array('items' => NULL, 'title' => NULL),
-    ),
-    'node_search_admin' => array(
-      'arguments' => array('form' => NULL),
-    ),
-    'node_filter_form' => array(
-      'arguments' => array('form' => NULL),
-      'file' => 'node.admin.inc',
-    ),
-    'node_filters' => array(
-      'arguments' => array('form' => NULL),
-      'file' => 'node.admin.inc',
-    ),
-    'node_add_list' => array(
-      'arguments' => array('content' => NULL),
-      'file' => 'node.pages.inc',
-    ),
-    'node_form' => array(
-      'arguments' => array('form' => NULL),
-      'file' => 'node.pages.inc',
-    ),
-    'node_preview' => array(
-      'arguments' => array('node' => NULL),
-      'file' => 'node.pages.inc',
-    ),
-    'node_log_message' => array(
-      'arguments' => array('log' => NULL),
-    ),
-    'node_admin_overview' => array(
-      'arguments' => array('name' => NULL, 'type' => NULL),
-    ),
-  );
-}
-
-/**
  * Implement hook_cron().
  */
 function node_cron() {
@@ -1102,7 +1058,7 @@
   $build = $node->content;
   // We don't need duplicate rendering info in node->content.
   unset($node->content);
-  
+
   $build += array(
     '#theme' => 'node',
     '#node' => $node,
@@ -1274,7 +1230,7 @@
 
   // Flatten the node object's member fields.
   $variables = array_merge((array)$node, $variables);
-  
+
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
     $variables['content'][$key] = $variables['elements'][$key];
@@ -1448,7 +1404,7 @@
   $form['content_ranking']['info'] = array(
     '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
   );
-  
+
   // Note: reversed to reflect that higher number = higher ranking.
   $options = drupal_map_assoc(range(0, 10));
   foreach (module_invoke_all('ranking') as $var => $values) {
@@ -1473,7 +1429,7 @@
     ->condition('n.status', 1)
     ->addTag('node_access')
     ->searchExpression($keys, 'node');
-  
+
   // Insert special keywords.
   $query->setOption('type', 'n.type');
   $query->setOption('language', 'n.language');
@@ -1484,10 +1440,10 @@
   if (!$query->executeFirstPass()) {
     return array();
   }
-  
+
   // Add the ranking expressions.
   _node_rankings($query);
-  
+
   // Add a count query.
   $inner_query = clone $query;
   $count_query = db_select($inner_query->fields('i', array('sid')));
@@ -1496,7 +1452,7 @@
   $find = $query
     ->limit(10)
     ->execute();
-  
+
   // Load results.
   $results = array();
   foreach ($find as $item) {
@@ -1504,14 +1460,14 @@
     $node = node_load($item->sid);
     node_build_content($node, 'search_result');
     $node->rendered = drupal_render($node->content);
-  
+
     // Fetch comments for snippet.
     $node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
     // Fetch terms for snippet.
     $node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);
-  
+
     $extra = module_invoke_all('node_search_result', $node);
-  
+
     $results[] = array(
       'link' => url('node/' . $item->sid, array('absolute' => TRUE)),
       'type' => check_plain(node_type_get_name($node)),
@@ -1688,189 +1644,6 @@
 }
 
 /**
- * Implement hook_menu().
- */
-function node_menu() {
-  $items['admin/content'] = array(
-    'title' => 'Content',
-    'description' => 'Find and manage content.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_admin_content'),
-    'access arguments' => array('administer nodes'),
-    'weight' => -10,
-    'file' => 'node.admin.inc',
-  );
-  $items['admin/content/node'] = array(
-    'title' => 'Content',
-    'description' => "View, edit, and delete your site's content.",
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-
-  $items['admin/reports/status/rebuild'] = array(
-    'title' => 'Rebuild permissions',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_configure_rebuild_confirm'),
-    // Any user than can potentially trigger a node_access_needs_rebuild(TRUE)
-    // has to be allowed access to the 'node access rebuild' confirm form.
-    'access arguments' => array('access administration pages'),
-    'type' => MENU_CALLBACK,
-    'file' => 'node.admin.inc',
-  );
-
-  $items['admin/structure/types'] = array(
-    'title' => 'Content types',
-    'description' => 'Manage posts by content type, including default status, front page promotion, comment settings, etc.',
-    'page callback' => 'node_overview_types',
-    'access arguments' => array('administer content types'),
-    'file' => 'content_types.inc',
-  );
-  $items['admin/structure/types/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-  $items['admin/structure/types/add'] = array(
-    'title' => 'Add content type',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_type_form'),
-    'access arguments' => array('administer content types'),
-    'type' => MENU_LOCAL_ACTION,
-    'file' => 'content_types.inc',
-  );
-  $items['admin/structure/types/manage/%node_type'] = array(
-    'title' => 'Edit content type',
-    'title callback' => 'node_type_page_title',
-    'title arguments' => array(4),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_type_form', 4),
-    'access arguments' => array('administer content types'),
-    'file' => 'content_types.inc',
-  );
-  $items['admin/structure/types/manage/%node_type/edit'] = array(
-    'title' => 'Edit',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/structure/types/manage/%node_type/delete'] = array(
-    'title' => 'Delete',
-    'page arguments' => array('node_type_delete_confirm', 4),
-    'access arguments' => array('administer content types'),
-    'type' => MENU_CALLBACK,
-    'file' => 'content_types.inc',
-  );
-
-  $items['node'] = array(
-    'title' => 'Content',
-    'page callback' => 'node_page_default',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-  $items['node/add'] = array(
-    'title' => 'Add new content',
-    'page callback' => 'node_add_page',
-    'access callback' => '_node_add_access',
-    'weight' => 1,
-    'menu_name' => 'management',
-    'theme callback' => '_node_custom_theme',
-    'file' => 'node.pages.inc',
-  );
-  $items['rss.xml'] = array(
-    'title' => 'RSS feed',
-    'page callback' => 'node_feed',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-  // @todo Remove this loop when we have a 'description callback' property.
-  // Reset internal static cache of _node_types_build(), forces to rebuild the
-  // node type information.
-  drupal_static_reset('_node_types_build');
-  foreach (node_type_get_types() as $type) {
-    $type_url_str = str_replace('_', '-', $type->type);
-    $items['node/add/' . $type_url_str] = array(
-      'title' => $type->name,
-      'title callback' => 'check_plain',
-      'page callback' => 'node_add',
-      'page arguments' => array(2),
-      'access callback' => 'node_access',
-      'access arguments' => array('create', $type->type),
-      'description' => $type->description,
-      'file' => 'node.pages.inc',
-    );
-  }
-  $items['node/%node'] = array(
-    'page callback' => 'node_page_view',
-    'page arguments' => array(1),
-    'access callback' => 'node_access',
-    'access arguments' => array('view', 1),
-    'type' => MENU_CALLBACK);
-  $items['node/%node/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10);
-  $items['node/%node/edit'] = array(
-    'title' => 'Edit',
-    'page callback' => 'node_page_edit',
-    'page arguments' => array(1),
-    'access callback' => 'node_access',
-    'access arguments' => array('update', 1),
-    'theme callback' => '_node_custom_theme',
-    'weight' => 1,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'node.pages.inc',
-  );
-  $items['node/%node/delete'] = array(
-    'title' => 'Delete',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_delete_confirm', 1),
-    'access callback' => 'node_access',
-    'access arguments' => array('delete', 1),
-    'weight' => 1,
-    'type' => MENU_CALLBACK,
-    'file' => 'node.pages.inc',
-  );
-  $items['node/%node/revisions'] = array(
-    'title' => 'Revisions',
-    'page callback' => 'node_revision_overview',
-    'page arguments' => array(1),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(1),
-    'weight' => 2,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'node.pages.inc',
-  );
-  $items['node/%node/revisions/%/view'] = array(
-    'title' => 'Revisions',
-    'load arguments' => array(3),
-    'page callback' => 'node_show',
-    'page arguments' => array(1, TRUE),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(1),
-    'type' => MENU_CALLBACK,
-  );
-  $items['node/%node/revisions/%/revert'] = array(
-    'title' => 'Revert to earlier revision',
-    'load arguments' => array(3),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_revision_revert_confirm', 1),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(1, 'update'),
-    'type' => MENU_CALLBACK,
-    'file' => 'node.pages.inc',
-  );
-  $items['node/%node/revisions/%/delete'] = array(
-    'title' => 'Delete earlier revision',
-    'load arguments' => array(3),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_revision_delete_confirm', 1),
-    'access callback' => '_node_revision_access',
-    'access arguments' => array(1, 'delete'),
-    'type' => MENU_CALLBACK,
-    'file' => 'node.pages.inc',
-  );
-  return $items;
-}
-
-/**
  * Title callback for a node type.
  */
 function node_type_page_title($type) {
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.160
diff -u -r1.160 module.inc
--- includes/module.inc	10 Oct 2009 12:12:15 -0000	1.160
+++ includes/module.inc	14 Oct 2009 18:13:23 -0000
@@ -376,18 +376,25 @@
   }
 
   if (!isset($implementations[$hook])) {
+    $hook_info = module_hook_info();
     $implementations[$hook] = array();
     $list = module_list(FALSE, FALSE, $sort);
     foreach ($list as $module) {
-      if (module_hook($module, $hook)) {
-        $implementations[$hook][$module] = $module;
+      $include_file = FALSE;
+      if (module_hook($module, $hook) || (isset($hook_info[$hook]['group']) && $include_file = module_load_include('inc', $module, "$module.{$hook_info[$hook]['group']}") && module_hook($module, $hook))) {
+        $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
         // We added something to the cache, so write it when we are done.
         $implementations['#write_cache'] = TRUE;
       }
     }
   }
   else {
-    foreach ($implementations[$hook] as $module) {
+    foreach ($implementations[$hook] as $module => $group) {
+      // If this hook implementation is stored in a lazy-loaded file,
+      // include that file first.
+      if ($group) {
+        module_load_include('inc', $module, "$module.$group");
+      }
       // It is possible that a module removed a hook implementation without the
       // implementations cache being rebuilt yet, so we check module_hook() on
       // each request to avoid undefined function errors.
@@ -400,13 +407,46 @@
     }
   }
 
-  // The explicit cast forces a copy to be made. This is needed because
-  // $implementations[$hook] is only a reference to an element of
-  // $implementations and if there are nested foreaches (due to nested node
-  // API calls, for example), they would both manipulate the same array's
-  // references, which causes some modules' hooks not to be called.
-  // See also http://www.zend.com/zend/art/ref-count.php.
-  return (array)$implementations[$hook];
+  return array_keys($implementations[$hook]);
+}
+
+/**
+ * Retrieve a list of what hooks are explicitly declared.
+ */
+function module_hook_info() {
+  $hook_info = &drupal_static(__FUNCTION__, array());
+
+  if (empty($hook_info)) {
+    $cache = cache_get('hook_info');
+    if ($cache === FALSE) {
+      // rebuild the cache and save it.
+
+      // We can't use module_invoke_all() here or it would cause
+      // an infinite loop.
+      foreach (module_list() as $module) {
+        $function = $module . '_hook_info';
+        if (function_exists($function)) {
+          $result = $function();
+          if (isset($result) && is_array($result)) {
+            $hook_info = array_merge_recursive($hook_info, $result);
+          }
+        }
+      }
+      // We can't use drupal_alter() for the same reason as above.
+      foreach (module_list() as $module) {
+        $function = $module . '_hook_info_alter';
+        if (function_exists($function)) {
+          $function($hook_info);
+        }
+      }
+      cache_set('hook_info', $hook_info);
+    }
+    else {
+      $hook_info = $cache->data;
+    }
+  }
+
+  return $hook_info;
 }
 
 /**
Index: includes/token.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/token.inc,v
retrieving revision 1.5
diff -u -r1.5 token.inc
--- includes/token.inc	25 Aug 2009 02:50:08 -0000	1.5
+++ includes/token.inc	14 Oct 2009 18:13:23 -0000
@@ -153,7 +153,6 @@
 function token_generate($type, array $tokens, array $data = array(), array $options = array()) {
   $results = array();
   $options += array('sanitize' => TRUE);
-  _token_initialize();
 
   $result = module_invoke_all('tokens', $type, $tokens, $data, $options);
   foreach ($result as $original => $replacement) {
@@ -227,25 +226,8 @@
 function token_info() {
   $data = &drupal_static(__FUNCTION__);
   if (!isset($data)) {
-    _token_initialize();
     $data = module_invoke_all('token_info');
     drupal_alter('token_info', $data);
   }
   return $data;
 }
-
-/**
- * Load modulename.tokens.inc for all enabled modules.
- */
-function _token_initialize() {
-  $initialized = &drupal_static(__FUNCTION__);
-  if (!$initialized) {
-    foreach (module_list() as $module) {
-      $filename = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$module.tokens.inc";
-      if (file_exists($filename)) {
-        include_once $filename;
-      }
-    }
-    $initialized = TRUE;
-  }
-}
Index: modules/node/node.registry.inc
===================================================================
RCS file: modules/node/node.registry.inc
diff -N modules/node/node.registry.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/node/node.registry.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,234 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Hook implementations for the 'registry' group.
+ */
+
+/**
+ * Implement hook_theme().
+ */
+function node_theme() {
+  return array(
+    'node' => array(
+      'arguments' => array('elements' => NULL),
+      'template' => 'node',
+    ),
+    'node_list' => array(
+      'arguments' => array('items' => NULL, 'title' => NULL),
+    ),
+    'node_search_admin' => array(
+      'arguments' => array('form' => NULL),
+    ),
+    'node_filter_form' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'node.admin.inc',
+    ),
+    'node_filters' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'node.admin.inc',
+    ),
+    'node_add_list' => array(
+      'arguments' => array('content' => NULL),
+      'file' => 'node.pages.inc',
+    ),
+    'node_form' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'node.pages.inc',
+    ),
+    'node_preview' => array(
+      'arguments' => array('node' => NULL),
+      'file' => 'node.pages.inc',
+    ),
+    'node_log_message' => array(
+      'arguments' => array('log' => NULL),
+    ),
+    'node_admin_overview' => array(
+      'arguments' => array('name' => NULL, 'type' => NULL),
+    ),
+  );
+}
+
+/**
+ * Implement hook_menu().
+ */
+function node_menu() {
+  $items['admin/content'] = array(
+    'title' => 'Content',
+    'description' => 'Find and manage content.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_admin_content'),
+    'access arguments' => array('administer nodes'),
+    'weight' => -10,
+    'file' => 'node.admin.inc',
+  );
+  $items['admin/content/node'] = array(
+    'title' => 'Content',
+    'description' => "View, edit, and delete your site's content.",
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+
+  $items['admin/reports/status/rebuild'] = array(
+    'title' => 'Rebuild permissions',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_configure_rebuild_confirm'),
+    // Any user than can potentially trigger a node_access_needs_rebuild(TRUE)
+    // has to be allowed access to the 'node access rebuild' confirm form.
+    'access arguments' => array('access administration pages'),
+    'type' => MENU_CALLBACK,
+    'file' => 'node.admin.inc',
+  );
+
+  $items['admin/structure/types'] = array(
+    'title' => 'Content types',
+    'description' => 'Manage posts by content type, including default status, front page promotion, comment settings, etc.',
+    'page callback' => 'node_overview_types',
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/types/add'] = array(
+    'title' => 'Add content type',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form'),
+    'access arguments' => array('administer content types'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/manage/%node_type'] = array(
+    'title' => 'Edit content type',
+    'title callback' => 'node_type_page_title',
+    'title arguments' => array(4),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form', 4),
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
+  );
+  $items['admin/structure/types/manage/%node_type/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['admin/structure/types/manage/%node_type/delete'] = array(
+    'title' => 'Delete',
+    'page arguments' => array('node_type_delete_confirm', 4),
+    'access arguments' => array('administer content types'),
+    'type' => MENU_CALLBACK,
+    'file' => 'content_types.inc',
+  );
+
+  $items['node'] = array(
+    'title' => 'Content',
+    'page callback' => 'node_page_default',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['node/add'] = array(
+    'title' => 'Add new content',
+    'page callback' => 'node_add_page',
+    'access callback' => '_node_add_access',
+    'weight' => 1,
+    'menu_name' => 'management',
+    'theme callback' => '_node_custom_theme',
+    'file' => 'node.pages.inc',
+  );
+  $items['rss.xml'] = array(
+    'title' => 'RSS feed',
+    'page callback' => 'node_feed',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  // @todo Remove this loop when we have a 'description callback' property.
+  // Reset internal static cache of _node_types_build(), forces to rebuild the
+  // node type information.
+  drupal_static_reset('_node_types_build');
+  foreach (node_type_get_types() as $type) {
+    $type_url_str = str_replace('_', '-', $type->type);
+    $items['node/add/' . $type_url_str] = array(
+      'title' => $type->name,
+      'title callback' => 'check_plain',
+      'page callback' => 'node_add',
+      'page arguments' => array(2),
+      'access callback' => 'node_access',
+      'access arguments' => array('create', $type->type),
+      'description' => $type->description,
+      'file' => 'node.pages.inc',
+    );
+  }
+  $items['node/%node'] = array(
+    'page callback' => 'node_page_view',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('view', 1),
+    'type' => MENU_CALLBACK);
+  $items['node/%node/view'] = array(
+    'title' => 'View',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10);
+  $items['node/%node/edit'] = array(
+    'title' => 'Edit',
+    'page callback' => 'node_page_edit',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('update', 1),
+    'theme callback' => '_node_custom_theme',
+    'weight' => 1,
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_delete_confirm', 1),
+    'access callback' => 'node_access',
+    'access arguments' => array('delete', 1),
+    'weight' => 1,
+    'type' => MENU_CALLBACK,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions'] = array(
+    'title' => 'Revisions',
+    'page callback' => 'node_revision_overview',
+    'page arguments' => array(1),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1),
+    'weight' => 2,
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions/%/view'] = array(
+    'title' => 'Revisions',
+    'load arguments' => array(3),
+    'page callback' => 'node_show',
+    'page arguments' => array(1, TRUE),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1),
+    'type' => MENU_CALLBACK,
+  );
+  $items['node/%node/revisions/%/revert'] = array(
+    'title' => 'Revert to earlier revision',
+    'load arguments' => array(3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_revert_confirm', 1),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1, 'update'),
+    'type' => MENU_CALLBACK,
+    'file' => 'node.pages.inc',
+  );
+  $items['node/%node/revisions/%/delete'] = array(
+    'title' => 'Delete earlier revision',
+    'load arguments' => array(3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_revision_delete_confirm', 1),
+    'access callback' => '_node_revision_access',
+    'access arguments' => array(1, 'delete'),
+    'type' => MENU_CALLBACK,
+    'file' => 'node.pages.inc',
+  );
+  return $items;
+}
