diff --git a/.htaccess b/.htaccess
index 82d1d2ca5c1e76412484f6e9d9de00c290b2b020..2f101bd041d509e3bb903e033138e2568323706e 100644
--- a/.htaccess
+++ b/.htaccess
@@ -38,8 +38,6 @@ DirectoryIndex index.php index.html index.htm
   php_value mbstring.http_input             pass
   php_value mbstring.http_output            pass
   php_flag mbstring.encoding_translation    off
-  # Report all PHP errors, including compile-time errors.
-  php_value error_reporting                 -1
 </IfModule>
 
 # Requires mod_expires to be enabled.
@@ -113,4 +111,4 @@ DirectoryIndex index.php index.html index.htm
   RewriteRule ^ index.php [L]
 </IfModule>
 
-# $Id: .htaccess,v 1.108 2010/04/11 18:33:43 dries Exp $
+# $Id: .htaccess,v 1.109 2010/05/05 06:15:59 webchick Exp $
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 505fb32488b10b8025adfa7452f10654feeaa3e4..0e59762d8faed4412dd575bd82e266da350bed58 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,6 +1,6 @@
-// $Id: CHANGELOG.txt,v 1.363 2010/04/26 21:24:54 webchick Exp $
+// $Id: CHANGELOG.txt,v 1.365 2010/05/23 15:26:38 webchick Exp $
 
-Drupal 7.0 alpha 4, 2010-04-26
+Drupal 7.0, alpha 5, 2010-05-23 
 ----------------------
 - Database:
     * Fully rewritten database layer utilizing PHP 5's PDO abstraction layer.
diff --git a/INSTALL.txt b/INSTALL.txt
index cefdc36d2857168d6e5b5bee3c63acd4df95a626..c2b97d6d27a4741ead0846dc1dfbfcc2c24975ce 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -1,4 +1,4 @@
-// $Id: INSTALL.txt,v 1.79 2010/02/13 21:35:08 dries Exp $
+// $Id: INSTALL.txt,v 1.80 2010/04/30 08:09:21 dries Exp $
 
 CONTENTS OF THIS FILE
 ---------------------
@@ -266,35 +266,40 @@ INSTALLATION
    customized similar to the above example, to add your site-specific cron key
    and domain name.)
 
-DRUPAL ADMINISTRATION
----------------------
+
+BUILDING AND CUSTOMIZING YOUR SITE
+----------------------------------
 
 A new installation of Drupal defaults to a very basic configuration with only a
-few active modules and minimal user access rights.
+few active modules and minimal user access rights. When extending your site,
+you use "modules" and "themes". A module is a plugin that adds functionallity to
+Drupal, while a theme changes the front-end look and behavior of your site.
+
+It is important to install these correctly and not mix them in with the core
+Drupal module and theme set (directories modules and themes at the top level).
+So normally you place them under the following paths:
 
-Use your administration panel to enable and configure services. For example:
+Modules:
+  sites/all/modules/example_module
 
-General Settings       Administer > Site configuration > Site information
-Enable Modules         Administer > Structure > Modules
-Configure Themes       Administer > Structure > Themes
-Set User Permissions   Administer > User management > Permissions
+Themes:
+  sites/all/themes/example_theme
 
-For more information on configuration options, read the instructions which
-accompany the different configuration settings and consult the various help
-pages available in the administration panel.
+If you run a multisite installation you will want to do this a bit differently.
+You can read more about that on the multisite part of this file.
 
-Community-contributed modules and themes are available at http://drupal.org/.
+Contributed modules can be found at:
+http://drupal.org/project/Modules
 
-CUSTOMIZING YOUR THEME(S)
--------------------------
+Contributed themes can be found at:
+http://drupal.org/project/Themes
 
-Now that your installation is running, you will want to customize the look of
-your site. Several sample themes are included and more can be downloaded from
-drupal.org.
+Later on you might want to write your own code, but remember to NEVER modify the
+core modules and themes in Drupal directories modules and themes. Instead use
+the hooks available in the Drupal API. You can read more about the Drupal API
+and how to develop modules at
+http://drupal.org/developing/modules
 
-Simple customization of your theme can be done using only CSS. Further changes
-require understanding the phptemplate engine that is part of Drupal. See
-http://drupal.org/handbook/customization to find out more.
 
 MULTISITE CONFIGURATION
 -----------------------
diff --git a/UPGRADE.txt b/UPGRADE.txt
index eae2bd154cbf48cb8f9aef4a6e26edf74fbab733..7521fb32a7aa25ba9a2dd1c2f19329b40ed360ce 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -1,4 +1,4 @@
-// $Id: UPGRADE.txt,v 1.20 2010/04/22 08:15:39 webchick Exp $
+// $Id: UPGRADE.txt,v 1.21 2010/04/29 04:49:02 webchick Exp $
 
 UPGRADING
 ---------
@@ -14,12 +14,10 @@ Prior to upgrading, you should ensure that:
 
 Let's begin!
 
-1.  Backup your database and Drupal directory - especially your "sites"
-    directory which contains your configuration file and added modules and
-    themes, any contributed or custom modules in your "modules" directory,
-    and your "files" directory which contains uploaded files. If other files
-    have modifications, such as .htaccess or robots.txt, those should be
-    backed up as well.
+1.  Back up your Drupal database and site root directory. Be especially sure 
+    to back up your "sites" directory which contains your configuration file, 
+    added modules and themes, and your site's uploaded files. If other files 
+    have modifications, such as .htaccess or robots.txt, back those up as well.
 
     Note: for a single site setup, the configuration file is the "settings.php"
     file located at sites/default/settings.php. The default.settings.php file
diff --git a/includes/actions.inc b/includes/actions.inc
index 77734fe6366543ff69dd51e659fb1ea16a870daa..d7c625c8aecbbe0ca436d192d0f2dac467f18ce2 100644
--- a/includes/actions.inc
+++ b/includes/actions.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: actions.inc,v 1.36 2010/03/07 07:22:41 webchick Exp $
+// $Id: actions.inc,v 1.38 2010/05/06 05:59:30 webchick Exp $
 
 /**
  * @file
@@ -166,7 +166,7 @@ function actions_list($reset = FALSE) {
   }
 
   // See module_implements() for an explanation of this cast.
-  return (array)$actions;
+  return (array) $actions;
 }
 
 /**
@@ -197,7 +197,7 @@ function actions_get_all_actions() {
 }
 
 /**
- * Creates an associative array keyed by md5 hashes of function names or IDs.
+ * Creates an associative array keyed by hashes of function names or IDs.
  *
  * Hashes are used to prevent actual function names from going out into HTML
  * forms and coming back.
@@ -207,14 +207,14 @@ function actions_get_all_actions() {
  *   and associative arrays with keys 'label', 'type', etc. as values.
  *   This is usually the output of actions_list() or actions_get_all_actions().
  * @return
- *   An associative array whose keys are md5 hashes of the input array keys, and
+ *   An associative array whose keys are hashes of the input array keys, and
  *   whose corresponding values are associative arrays with components
  *   'callback', 'label', 'type', and 'configurable' from the input array.
  */
 function actions_actions_map($actions) {
   $actions_map = array();
   foreach ($actions as $callback => $array) {
-    $key = md5($callback);
+    $key = drupal_hash_base64($callback);
     $actions_map[$key]['callback']     = isset($array['callback']) ? $array['callback'] : $callback;
     $actions_map[$key]['label']        = $array['label'];
     $actions_map[$key]['type']         = $array['type'];
@@ -224,12 +224,12 @@ function actions_actions_map($actions) {
 }
 
 /**
- * Given an md5 hash of an action array key, returns the key (function or ID).
+ * Given a hash of an action array key, returns the key (function or ID).
  *
  * Faster than actions_actions_map() when you only need the function name or ID.
  *
  * @param $hash
- *   MD5 hash of a function name or action ID array key. The array key
+ *   Hash of a function name or action ID array key. The array key
  *   is a key into the return value of actions_list() (array key is the action
  *   function name) or actions_get_all_actions() (array key is the action ID).
  * @return
@@ -239,13 +239,20 @@ function actions_function_lookup($hash) {
   // Check for a function name match.
   $actions_list = actions_list();
   foreach ($actions_list as $function => $array) {
-    if (md5($function) == $hash) {
+    if (drupal_hash_base64($function) == $hash) {
       return $function;
     }
   }
-
+  $aid = FALSE;
   // Must be a configurable action; check database.
-  return db_query("SELECT aid FROM {actions} WHERE MD5(aid) = :hash AND parameters <> ''", array(':hash' => $hash))->fetchField();
+  $result = db_query("SELECT aid FROM {actions} WHERE parameters <> ''")->fetchAll(PDO::FETCH_ASSOC);
+  foreach ($result as $row) {
+    if (drupal_hash_base64($row['aid']) == $hash) {
+      $aid = $row['aid'];
+      break;
+    }
+  }
+  return $aid;
 }
 
 /**
diff --git a/includes/ajax.inc b/includes/ajax.inc
index c5f30232141ccbd92f197e6de55769fd464f2412..74b4e73ddabbc7b30fff220f0fcd252d2a953783 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: ajax.inc,v 1.29 2010/03/31 19:34:56 dries Exp $
+// $Id: ajax.inc,v 1.31 2010/04/30 08:07:54 dries Exp $
 
 /**
  * @file
@@ -20,11 +20,10 @@
  * forms, it can be used with the #ajax property.
  * The #ajax property can be used to bind events to the AJAX framework. By
  * default, #ajax uses 'system/ajax' as its path for submission and thus calls
- * @link ajax_form_callback ajax_form_callback @endlink and a defined
- * #ajax['callback'] function. However, you may optionally specify a different
- * path to request or a different callback function to invoke, which can return
- * updated HTML or can also return a richer set of
- * @link ajax_commands AJAX framework commands @endlink.
+ * ajax_form_callback() and a defined #ajax['callback'] function.
+ * However, you may optionally specify a different path to request or a
+ * different callback function to invoke, which can return updated HTML or can
+ * also return a richer set of @link ajax_commands AJAX framework commands @endlink.
  *
  * Standard form handling is as follows:
  *   - A form element has a #ajax member.
@@ -124,9 +123,10 @@
  *   selected automatically for the type of form widget being used, and
  *   is only needed if you need to override the default behavior.
  * - #ajax['method']: The jQuery method to use to place the new HTML.
- *   Defaults to 'replace'. May be: 'replace', 'append', 'prepend',
- *   'before', 'after', or 'html'. See the jQuery documentation for more
- *   information on these methods.
+ *   Defaults to 'replaceWith'. May be: 'replaceWith', 'append', 'prepend',
+ *   'before', 'after', or 'html'. See the
+ *   @link http://api.jquery.com/category/manipulation/ jQuery manipulators documentation @endlink
+ *   for more information on these methods.
  * - #ajax['progress']: Choose either a throbber or progress bar that is
  *   displayed while awaiting a response from the callback, and add an optional
  *   message. Possible keys: 'type', 'message', 'url', 'interval'.
@@ -168,7 +168,7 @@
  *   $commands[] = ajax_command_changed('#object-1');
  *   // Menu 'page callback' and #ajax['callback'] functions are supposed to
  *   // return render arrays. If returning an AJAX commands array, it must be
- *   // encapsulated in a render array structure. 
+ *   // encapsulated in a render array structure.
  *   return array('#type' => 'ajax', '#commands' => $commands);
  * @endcode
  *
@@ -336,13 +336,16 @@ function ajax_deliver($page_callback_result) {
     }
   }
   else {
-    // Like normal page callbacks, simple AJAX callbacks can return html
-    // content, as a string or renderable array, to replace what was previously
-    // there in the wrapper. In this case, in addition to the content, we want
-    // to add the status messages, but inside the new wrapper, so that they get
-    // replaced on subsequent AJAX calls for the same wrapper.
+    // Like normal page callbacks, simple AJAX callbacks can return HTML
+    // content, as a string or render array. This HTML is inserted in some
+    // relationship to #ajax['wrapper'], as determined by which jQuery DOM
+    // manipulation method is used. The method used is specified by
+    // #ajax['method']. The default method is 'replaceWith', which completely
+    // replaces the old wrapper element and its content with the new HTML.
     $html = is_string($page_callback_result) ? $page_callback_result : drupal_render($page_callback_result);
-    $commands[] = ajax_command_replace(NULL, $html);
+    $commands[] = ajax_command_insert(NULL, $html);
+    // Add the status messages inside the new content's wrapper element, so that
+    // on subsequent AJAX requests, it is treated as old content.
     $commands[] = ajax_command_prepend(NULL, theme('status_messages'));
   }
 
@@ -460,10 +463,15 @@ function ajax_process_form($element, &$form_state) {
       'selector' => '#' . $element['#id'],
       'effect' => 'none',
       'speed' => 'none',
-      'method' => 'replace',
+      'method' => 'replaceWith',
       'progress' => array('type' => 'throbber'),
     );
 
+    // @todo Legacy support. Remove in Drupal 8.
+    if ($settings['method'] == 'replace') {
+      $settings['method'] = 'replaceWith';
+    }
+
     // Change path to url.
     $settings['url'] = isset($settings['path']) ? url($settings['path']) : url('system/ajax');
     unset($settings['path']);
@@ -552,6 +560,37 @@ function ajax_command_alert($text) {
   );
 }
 
+/**
+ * Creates a Drupal AJAX 'insert' command using the method in #ajax['method'].
+ *
+ * This command instructs the client to insert the given HTML using whichever
+ * jQuery DOM manipulation method has been specified in the #ajax['method']
+ * variable of the element that triggered the request.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.insert()
+ * defined in misc/ajax.js.
+ *
+ * @param $selector
+ *   A jQuery selector string. If the command is a response to a request from
+ *   an #ajax form element then this value can be NULL.
+ * @param $html
+ *   The data to use with the jQuery method.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_insert($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => NULL,
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
 /**
  * Creates a Drupal AJAX 'insert/replaceWith' command.
  *
@@ -573,7 +612,7 @@ function ajax_command_alert($text) {
  * @return
  *   An array suitable for use with the ajax_render() function.
  *
- * @see http://docs.jquery.com/Manipulation/replaceWith#content
+ * See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
  */
 function ajax_command_replace($selector, $html, $settings = NULL) {
   return array(
diff --git a/includes/authorize.inc b/includes/authorize.inc
index 341fc311059ec198c40ebf8ae3442a2286e11fcf..c5ba6916f357dd7d8807fcb2ebf31f121a3b79fc 100644
--- a/includes/authorize.inc
+++ b/includes/authorize.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: authorize.inc,v 1.10 2010/04/23 05:21:19 webchick Exp $
+// $Id: authorize.inc,v 1.11 2010/05/14 04:50:18 webchick Exp $
 
 /**
  * @file
@@ -83,7 +83,7 @@ function authorize_filetransfer_form($form_state) {
     $form['connection_settings']['authorize_filetransfer_default']['#options'][$name] = $backend['title'];
     $form['connection_settings'][$name] = array(
       '#type' => 'fieldset',
-      '#attributes' => array('class' => "filetransfer-$name filetransfer"),
+      '#attributes' => array('class' => array("filetransfer-$name", 'filetransfer')),
       '#title' => t('@backend connection settings', array('@backend' => $backend['title'])),
     );
 
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 843c475a7b74bc5c964f9aca0dcb63927ab7d431..3a76f2d44826d4cc40eafcc5b8d40fc644fb1e15 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: bootstrap.inc,v 1.377 2010/04/26 21:24:54 webchick Exp $
+// $Id: bootstrap.inc,v 1.391 2010/05/23 15:26:38 webchick Exp $
 
 /**
  * @file
@@ -9,7 +9,7 @@
 /**
  * The current system version.
  */
-define('VERSION', '7.0-alpha4');
+define('VERSION', '7.0-alpha5');
 
 /**
  * Core API compatibility.
@@ -19,7 +19,7 @@ define('DRUPAL_CORE_COMPATIBILITY', '7.x');
 /**
  * Minimum supported version of PHP.
  */
-define('DRUPAL_MINIMUM_PHP',    '5.2.0');
+define('DRUPAL_MINIMUM_PHP',    '5.2.1');
 
 /**
  * Minimum recommended value of PHP memory_limit.
@@ -48,19 +48,12 @@ define('CACHE_PERMANENT', 0);
  */
 define('CACHE_TEMPORARY', -1);
 
-/**
- * Indicates that page caching is disabled.
- */
-define('CACHE_DISABLED', 0);
-
-/**
- * Indicates that page caching is enabled, using "normal" mode.
- */
-define('CACHE_NORMAL', 1);
-
 /**
  * Log message severity -- Emergency: system is unusable.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -69,6 +62,9 @@ define('WATCHDOG_EMERGENCY', 0);
 /**
  * Log message severity -- Alert: action must be taken immediately.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -77,6 +73,9 @@ define('WATCHDOG_ALERT', 1);
 /**
  * Log message severity -- Critical: critical conditions.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -85,6 +84,9 @@ define('WATCHDOG_CRITICAL', 2);
 /**
  * Log message severity -- Error: error conditions.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -93,6 +95,9 @@ define('WATCHDOG_ERROR', 3);
 /**
  * Log message severity -- Warning: warning conditions.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -101,6 +106,9 @@ define('WATCHDOG_WARNING', 4);
 /**
  * Log message severity -- Notice: normal but significant condition.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -109,6 +117,9 @@ define('WATCHDOG_NOTICE', 5);
 /**
  * Log message severity -- Informational: informational messages.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -117,6 +128,9 @@ define('WATCHDOG_INFO', 6);
 /**
  * Log message severity -- Debug: debug-level messages.
  *
+ * The WATCHDOG_* constant definitions correspond to the logging severity levels
+ * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html
+ *
  * @see watchdog()
  * @see watchdog_severity_levels()
  */
@@ -622,7 +636,7 @@ function drupal_settings_initialize() {
     ini_set('session.cookie_secure', TRUE);
   }
   $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
-  session_name($prefix . md5($session_name));
+  session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
 }
 
 /**
@@ -1079,14 +1093,14 @@ function drupal_serve_page_from_cache(stdClass $cache) {
   // drupal_add_http_headers(). Keys are mixed-case.
   $default_headers = array();
 
-  foreach ($cache->headers as $name => $value) {
+  foreach ($cache->data['headers'] as $name => $value) {
     // In the case of a 304 response, certain headers must be sent, and the
     // remaining may not (see RFC 2616, section 10.3.5). Do not override
     // headers set in hook_boot().
     $name_lower = strtolower($name);
     if (in_array($name_lower, array('content-location', 'expires', 'cache-control', 'vary')) && !isset($hook_boot_headers[$name_lower])) {
       drupal_add_http_header($name, $value);
-      unset($cache->headers[$name]);
+      unset($cache->data['headers'][$name]);
     }
   }
 
@@ -1096,7 +1110,7 @@ function drupal_serve_page_from_cache(stdClass $cache) {
   // do not bother caching the page in a public proxy, because the cached copy
   // will only be served to that particular user due to Vary: Cookie, unless
   // the Vary header has been replaced or unset in hook_boot() (see below).
-  $max_age = !variable_get('page_cache_invoke_hooks', TRUE) && (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('cache_lifetime', 0) : 0;
+  $max_age = !variable_get('page_cache_invoke_hooks', TRUE) && (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('page_cache_maximum_age', 0) : 0;
   $default_headers['Cache-Control'] = 'public, max-age=' . $max_age;
 
   // Entity tag should change if the output changes.
@@ -1116,7 +1130,7 @@ function drupal_serve_page_from_cache(stdClass $cache) {
   }
 
   // Send the remaining headers.
-  foreach ($cache->headers as $name => $value) {
+  foreach ($cache->data['headers'] as $name => $value) {
     drupal_add_http_header($name, $value);
   }
 
@@ -1144,19 +1158,20 @@ function drupal_serve_page_from_cache(stdClass $cache) {
     header('Vary: Accept-Encoding', FALSE);
     // If page_compression is enabled, the cache contains gzipped data.
     if ($return_compressed) {
-      // $cache->data is already gzip'ed, so make sure zlib.output_compression
-      // does not compress it once more.
+      // $cache->data['body'] is already gzip'ed, so make sure
+      // zlib.output_compression does not compress it once more.
       ini_set('zlib.output_compression', '0');
       header('Content-Encoding: gzip');
     }
     else {
       // The client does not support compression, so unzip the data in the
       // cache. Strip the gzip header and run uncompress.
-      $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
+      $cache->data['body'] = gzinflate(substr(substr($cache->data['body'], 10), 0, -8));
     }
   }
 
-  print $cache->data;
+  // Print the page.
+  print $cache->data['body'];
 }
 
 /**
@@ -1177,7 +1192,7 @@ function bootstrap_hooks() {
 function drupal_unpack($obj, $field = 'data') {
   if ($obj->$field && $data = unserialize($obj->$field)) {
     foreach ($data as $key => $value) {
-      if (!isset($obj->$key)) {
+      if (!empty($key) && !isset($obj->$key)) {
         $obj->$key = $value;
       }
     }
@@ -1186,12 +1201,13 @@ function drupal_unpack($obj, $field = 'data') {
 }
 
 /**
- * Translate strings to the page language or a given language.
+ * Translates a string to the current language or to a given language.
  *
- * Human-readable text that will be displayed somewhere within a page should
- * be run through the t() function.
+ * All human-readable text that will be displayed on the site or sent to a user
+ * should be passed through the t() function. This ensures that sites can be
+ * fully translated into other languages.
  *
- * Examples:
+ * Here are some examples of translating static text using t():
  * @code
  *   if (!$info || !$info['extension']) {
  *     form_set_error('picture_upload', t('The uploaded file was not an image.'));
@@ -1203,95 +1219,85 @@ function drupal_unpack($obj, $field = 'data') {
  *   );
  * @endcode
  *
- * Any text within t() can be extracted by translators and changed into
- * the equivalent text in their native language.
- *
- * Special variables called "placeholders" are used to signal dynamic
- * information in a string which should not be translated. Placeholders
- * can also be used for text that may change from time to time (such as
- * link paths) to be changed without requiring updates to translations.
- *
- * For example:
- * @code
- *   $output = t('There are currently %members and %visitors online.', array(
- *     '%members' => format_plural($total_users, '1 user', '@count users'),
- *     '%visitors' => format_plural($guests->count, '1 guest', '@count guests')));
- * @endcode
- *
- * There are three styles of placeholders:
- * - !variable, which indicates that the text should be inserted as-is. This is
- *   useful for inserting variables into things like e-mail.
+ * In addition to translating static text, t() can handle text that should not
+ * be translated or that might change from time to time (such as link paths)
+ * and dynamic text from variables, using special "placeholders". There are
+ * three styles of placeholders:
+ * - !variable: Indicates that the text should be inserted as-is. This is
+ *   useful for inserting variables into things like e-mail. Example:
  *   @code
  *     $message[] = t("If you don't want to receive such e-mails, you can change your settings at !url.", array('!url' => url("user/$account->uid", array('absolute' => TRUE))));
  *   @endcode
- *
- * - @variable, which indicates that the text should be run through
- *   check_plain, to escape HTML characters. Use this for any output that's
- *   displayed within a Drupal page.
+ * - @variable: Indicates that the text should be run through check_plain(), to
+ *   escape HTML characters. Use this for any output that is displayed within a
+ *   Drupal page. Example:
  *   @code
  *     drupal_set_title($title = t("@name's blog", array('@name' => format_username($account))), PASS_THROUGH);
  *   @endcode
- *
- * - %variable, which indicates that the string should be HTML escaped and
- *   highlighted with theme_placeholder() which shows up by default as
- *   <em>emphasized</em>.
+ * - %variable: Indicates that the string should be HTML-escaped and highlighted
+ *   with theme_placeholder(), which shows up by default as <em>emphasized</em>.
  *   @code
  *     $message = t('%name-from sent %name-to an e-mail.', array('%name-from' => format_username($user), '%name-to' => format_username($account)));
  *   @endcode
  *
- * When using t(), try to put entire sentences and strings in one t() call.
- * This makes it easier for translators, as it provides context as to what
- * each word refers to. HTML markup within translation strings is allowed, but
- * should be avoided if possible. The exception are embedded links; link
- * titles add a context for translators, so should be kept in the main string.
- *
- * Here is an example of incorrect usage of t():
- * @code
- *   $output .= t('<p>Go to the @contact-page.</p>', array('@contact-page' => l(t('contact page'), 'contact')));
- * @endcode
- *
- * Here is an example of t() used correctly:
- * @code
- *   $output .= '<p>' . t('Go to the <a href="@contact-page">contact page</a>.', array('@contact-page' => url('contact'))) . '</p>';
- * @endcode
- *
- * Avoid escaping quotation marks wherever possible.
- *
- * Incorrect:
- * @code
- *   $output .= t('Don\'t click me.');
- * @endcode
- *
- * Correct:
- * @code
- *   $output .= t("Don't click me.");
- * @endcode
- *
- * Because t() is designed for handling code-based strings, in almost all
- * cases, the actual string and not a variable must be passed through t().
- *
- * Extraction of translations is done based on the strings contained in t()
- * calls. If a variable is passed through t(), the content of the variable
- * cannot be extracted from the file for translation.
+ * When using t(), try to put entire paragraphs in one t() call. This makes it
+ * easier for translators, as it provides context as to what each word refers
+ * to (and also allows translators to adjust word order, which may not be the
+ * same in all languages). HTML markup within translation strings is allowed,
+ * but should be avoided if possible. The exception is embedded links: link
+ * titles add context for translators and need to be translated, so they should
+ * be kept in the main string, while link URLs should be generated using
+ * placeholders.
+ * - Incorrect HTML in t():
+ *   @code
+ *     $output .= t('<p>Go to the @contact-page.</p>', array('@contact-page' => l(t('contact page'), 'contact')));
+ *   @endcode
+ * - Correct HTML in t():
+ *   @code
+ *     $output .= '<p>' . t('Go to the <a href="@contact-page">contact page</a>.', array('@contact-page' => url('contact'))) . '</p>';
+ *   @endcode
  *
- * Incorrect:
- * @code
- *   $message = 'An error occurred.';
- *   drupal_set_message(t($message), 'error');
- *   $output .= t($message);
- * @endcode
+ * Another thing that is helpful is to avoid escaping quotation marks wherever
+ * possible, because it can be confusing to translation teams.
+ * - Less desirable quotation mark escaping:
+ *   @code
+ *     $output .= t('Don\'t click me.');
+ *   @endcode
+ * - Better way to use quotation marks:
+ *   @code
+ *     $output .= t("Don't click me.");
+ *   @endcode
  *
- * Correct:
- * @code
- *   $message = t('An error occurred.');
- *   drupal_set_message($message, 'error');
- *   $output .= $message;
- * @endcode
+ * It is important that all translation uses the t() mechanism, because in
+ * addition to actually translating the text at run-time, the t() function is
+ * also used by text-extraction routines to find text that needs to be
+ * translated, and build databases of text to be translated for translation
+ * teams. For that reason, you must put the actual string into the t() function,
+ * in most cases, and not a variable.
+ * - Incorrect use of a variable in t():
+ *   @code
+ *     $message = 'An error occurred.';
+ *     drupal_set_message(t($message), 'error');
+ *     $output .= t($message);
+ *   @endcode
+ * - Correct translation of a variable with t():
+ *   @code
+ *     $message = t('An error occurred.');
+ *     drupal_set_message($message, 'error');
+ *     $output .= $message;
+ *   @endcode
  *
  * The only case in which variables can be passed safely through t() is when
  * code-based versions of the same strings will be passed through t() (or
  * otherwise extracted) elsewhere.
  *
+ * Also, you cannot use t() early in the bootstrap process, prior to the
+ * DRUPAL_BOOTSTRAP_LANGUAGE phase. The language variables will not be
+ * initialized yet, so the string will not be translated into the correct
+ * language. Examples of places where t() cannot be used include:
+ * - In a PHP define() statement.
+ * - In a hook_boot() implementation.
+ *
  * In some cases, modules may include strings in code that can't use t()
  * calls. For example, a module may use an external PHP application that
  * produces strings that are loaded into variables in Drupal for output.
@@ -1308,7 +1314,7 @@ function drupal_unpack($obj, $field = 'data') {
  *   }
  * @endcode
  *
- * Sample dummy file.
+ * Sample dummy file:
  * @code
  *   // Dummy function included in example.potx.inc.
  *   function example_potx() {
@@ -1322,9 +1328,7 @@ function drupal_unpack($obj, $field = 'data') {
  * @endcode
  *
  * Having passed strings through t() in a dummy function, it is then
- * okay to pass variables through t().
- *
- * Correct (if a dummy file was used):
+ * possible to pass variables through t():
  * @code
  *   $time = new Time();
  *   $output .= t($time->today);
@@ -1334,7 +1338,7 @@ function drupal_unpack($obj, $field = 'data') {
  * sources should not be passed through t(). Doing so leads to the following
  * problems and errors:
  *  - The t() system doesn't support updates to existing strings. When user
- *    data is updated, the next time it's passed through t() a new record is
+ *    data is updated, the next time it's passed through t(), a new record is
  *    created instead of an update. The database bloats over time and any
  *    existing translations are orphaned with each update.
  *  - The t() system assumes any data it receives is in English. User data may
@@ -1344,6 +1348,9 @@ function drupal_unpack($obj, $field = 'data') {
  *    passed through t(), they are added to this text group, which is rendered
  *    inaccurate since it is a mix of actual interface strings and various user
  *    input strings of uncertain origin.
+ * Instead, translation of these data can be done through the locale system,
+ * either directly through hook_local() or through helper functions provided by
+ * contributed modules.
  *
  * Incorrect:
  * @code
@@ -1351,16 +1358,9 @@ function drupal_unpack($obj, $field = 'data') {
  *   $output .= check_plain(t($item['title']));
  * @endcode
  *
- * Instead, translation of these data can be done through the locale system,
- * either directly or through helper functions provided by contributed
- * modules.
- * @see hook_locale()
- *
  * During installation, st() is used in place of t(). Code that may be called
  * during installation or during normal operation should use the get_t()
  * helper function.
- * @see st()
- * @see get_t()
  *
  * @param $string
  *   A string containing the English string to translate.
@@ -1369,15 +1369,16 @@ function drupal_unpack($obj, $field = 'data') {
  *   of any key in this array are replaced with the corresponding value. Based
  *   on the first character of the key, the value is escaped and/or themed:
  *    - !variable: inserted as is
- *    - @variable: escape plain text to HTML (check_plain)
+ *    - @variable: escape plain text to HTML (using check_plain())
  *    - %variable: escape text and theme as a placeholder for user-submitted
- *      content (check_plain + theme_placeholder)
+ *      content (using check_plain() + theme_placeholder())
  * @param $options
  *   An associative array of additional options, with the following keys:
- *     - 'langcode' (default to the current language) The language code to
+ *     - 'langcode' (defaults to the current language) The language code to
  *       translate to a language other than what is used to display the page.
- *     - 'context' (default to the empty context) The context the source string
+ *     - 'context' (defaults to the empty context) The context the source string
  *       belongs to.
+ *
  * @return
  *   The translated string.
  *
@@ -1464,7 +1465,7 @@ function check_plain($text) {
   // drupal_validate_utf8() here. This avoids the overhead of an additional
   // function call, since check_plain() may be called hundreds of times during
   // a request. For PHP 5.2.5+, this check for valid UTF-8 should be handled
-  // internally by PHP in htmlspecialchars(). 
+  // internally by PHP in htmlspecialchars().
   // See http://www.php.net/releases/5_2_5.php.
   // @todo remove this when support for either IE6 or PHP < 5.2.5 is dropped.
 
@@ -1662,6 +1663,48 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
   return array();
 }
 
+/**
+ * Get the title of the current page, for display on the page and in the title bar.
+ *
+ * @return
+ *   The current page's title.
+ */
+function drupal_get_title() {
+  $title = drupal_set_title();
+
+  // During a bootstrap, menu.inc is not included and thus we cannot provide a title.
+  if (!isset($title) && function_exists('menu_get_active_title')) {
+    $title = check_plain(menu_get_active_title());
+  }
+
+  return $title;
+}
+
+/**
+ * Set the title of the current page, for display on the page and in the title bar.
+ *
+ * @param $title
+ *   Optional string value to assign to the page title; or if set to NULL
+ *   (default), leaves the current title unchanged.
+ * @param $output
+ *   Optional flag - normally should be left as CHECK_PLAIN. Only set to
+ *   PASS_THROUGH if you have already removed any possibly dangerous code
+ *   from $title using a function like check_plain() or filter_xss(). With this
+ *   flag the string will be passed through unchanged.
+ *
+ * @return
+ *   The updated title of the current page.
+ */
+function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
+  $stored_title = &drupal_static(__FUNCTION__);
+
+  if (isset($title)) {
+    $stored_title = ($output == PASS_THROUGH) ? $title : check_plain($title);
+  }
+
+  return $stored_title;
+}
+
 /**
  * Check to see if an IP address has been blocked.
  *
@@ -1711,6 +1754,91 @@ function drupal_block_denied($ip) {
   }
 }
 
+/**
+ * Returns a string of highly randomized bytes (over the full 8-bit range).
+ *
+ * This function is better than simply calling mt_rand() or any other built-in
+ * PHP function because it can return a long string of bytes (compared to < 4
+ * bytes normally from mt_rand()) and uses the best available pseudo-random source.
+ *
+ * @param $count
+ *   The number of characters (bytes) to return in the string.
+ */
+function drupal_random_bytes($count)  {
+  // $random_state does not use drupal_static as it stores random bytes.
+  static $random_state, $bytes;
+  // Initialize on the first call. The contents of $_SERVER includes a mix of
+  // user-specific and system information that varies a little with each page.
+  if (!isset($random_state)) {
+    $random_state = print_r($_SERVER, TRUE);
+    if (function_exists('getmypid')) {
+      // Further initialize with the somewhat random PHP process ID.
+      $random_state .= getmypid();
+    }
+    $bytes = '';
+  }
+  if (strlen($bytes) < $count) {
+    // /dev/urandom is available on many *nix systems and is considered the
+    // best commonly available pseudo-random source.
+    if ($fh = @fopen('/dev/urandom', 'rb')) {
+      // PHP only performs buffered reads, so in reality it will always read
+      // at least 4096 bytes. Thus, it costs nothing extra to read and store
+      // that much so as to speed any additional invocations.
+      $bytes .= fread($fh, max(4096, $count));
+      fclose($fh);
+    }
+    // If /dev/urandom is not available or returns no bytes, this loop will
+    // generate a good set of pseudo-random bytes on any system.
+    // Note that it may be important that our $random_state is passed
+    // through hash() prior to being rolled into $output, that the two hash()
+    // invocations are different, and that the extra input into the first one -
+    // the microtime() - is prepended rather than appended. This is to avoid
+    // directly leaking $random_state via the $output stream, which could
+    // allow for trivial prediction of further "random" numbers.
+    while (strlen($bytes) < $count) {
+      $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
+      $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+    }
+  }
+  $output = substr($bytes, 0, $count);
+  $bytes = substr($bytes, $count);
+  return $output;
+}
+
+/**
+ * Calculate a base-64 encoded, URL-safe sha-256 hmac.
+ *
+ * @param $data
+ *   String to be validated with the hmac.
+ * @param $key
+ *   A secret string key.
+ *
+ * @return
+ *   A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
+ *   any = padding characters removed.
+ */
+function drupal_hmac_base64($data, $key) {
+  $hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+  // Modify the hmac so it's safe to use in URLs.
+  return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
+}
+
+/**
+ * Calculate a base-64 encoded, URL-safe sha-256 hash.
+ *
+ * @param $data
+ *   String to be hashed.
+ *
+ * @return
+ *   A base-64 encoded sha-256 hash, with + replaced with -, / with _ and
+ *   any = padding characters removed.
+ */
+function drupal_hash_base64($data) {
+  $hash = base64_encode(hash('sha256', $data, TRUE));
+  // Modify the hash so it's safe to use in URLs.
+  return strtr($hash, array('+' => '-', '/' => '_', '=' => ''));
+}
+
 /**
  * Generates a default anonymous $user object.
  *
@@ -1911,16 +2039,16 @@ function _drupal_bootstrap_page_cache() {
   }
   // Check for a cache mode force from settings.php.
   if (variable_get('page_cache_without_database')) {
-    $cache_mode = CACHE_NORMAL;
+    $cache_enabled = TRUE;
   }
   else {
     drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
-    $cache_mode = variable_get('cache');
+    $cache_enabled = variable_get('cache');
   }
   drupal_block_denied(ip_address());
   // If there is no session cookie and cache is enabled (or forced), try
   // to serve a cached page.
-  if (!isset($_COOKIE[session_name()]) && $cache_mode == CACHE_NORMAL) {
+  if (!isset($_COOKIE[session_name()]) && $cache_enabled) {
     // Make sure there is a user object because it's timestamp will be
     // checked, hook_boot might check for anonymous user etc.
     $user = drupal_anonymous_user();
@@ -1928,13 +2056,16 @@ function _drupal_bootstrap_page_cache() {
     $cache = drupal_page_get_cache();
     // If there is a cached page, display it.
     if (is_object($cache)) {
+      header('X-Drupal-Cache: HIT');
+      // Restore the metadata cached with the page.
+      $_GET['q'] = $cache->data['path'];
+      drupal_set_title($cache->data['title'], PASS_THROUGH);
       date_default_timezone_set(drupal_get_user_timezone());
       // If the skipping of the bootstrap hooks is not enforced, call
       // hook_boot.
       if (variable_get('page_cache_invoke_hooks', TRUE)) {
         bootstrap_invoke_all('boot');
       }
-      header('X-Drupal-Cache: HIT');
       drupal_serve_page_from_cache($cache);
       // If the skipping of the bootstrap hooks is not enforced, call
       // hook_exit.
@@ -1944,6 +2075,9 @@ function _drupal_bootstrap_page_cache() {
       // We are done.
       exit;
     }
+    else {
+      header('X-Drupal-Cache: MISS');
+    }
   }
 }
 
@@ -1958,6 +2092,15 @@ function _drupal_bootstrap_database() {
     header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
     exit;
   }
+
+  // Redirect the user to the installation script if Drupal has not been
+  // installed yet (i.e., if no $databases array has been defined in the
+  // settings.php file) and we are not already installing.
+  if (empty($GLOBALS['databases']) && !drupal_installation_attempted()) {
+    include_once DRUPAL_ROOT . '/includes/install.inc';
+    install_goto('install.php');
+  }
+
   // Initialize the database system. Note that the connection
   // won't be initialized until it is actually requested.
   require_once DRUPAL_ROOT . '/includes/database/database.inc';
@@ -1992,9 +2135,6 @@ function _drupal_bootstrap_variables() {
  */
 function _drupal_bootstrap_page_header() {
   bootstrap_invoke_all('boot');
-  if (!drupal_page_get_cache(TRUE) && drupal_page_is_cacheable()) {
-    header('X-Drupal-Cache: MISS');
-  }
 
   // Prepare for non-cached page workflow.
   require_once DRUPAL_ROOT . '/' . variable_get('lock_inc', 'includes/lock.inc');
@@ -2029,9 +2169,9 @@ function drupal_valid_test_ua($user_agent) {
   // the database is not yet initialized and we can't access any Drupal variables.
   // The file properties add more entropy not easily accessible to others.
   $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
-  $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE);
+  $key = serialize($databases) . filectime($filepath) . fileinode($filepath);
   // The HMAC must match.
-  return $hmac == base64_encode(hash_hmac('sha1', $check_string, $key, TRUE));
+  return $hmac == drupal_hmac_base64($check_string, $key);
 }
 
 /**
@@ -2046,12 +2186,12 @@ function drupal_generate_test_ua($prefix) {
     // check the HMAC before the database is initialized. filectime()
     // and fileinode() are not easily determined from remote.
     $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc';
-    $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE);
+    $key = serialize($databases) . filectime($filepath) . fileinode($filepath);
   }
    // Generate a moderately secure HMAC based on the database credentials.
    $salt = uniqid('', TRUE);
    $check_string = $prefix . ';' . time() . ';' . $salt;
-   return  $check_string . ';' . base64_encode(hash_hmac('sha1', $check_string, $key, TRUE));
+   return  $check_string . ';' . drupal_hmac_base64($check_string, $key);
 }
 
 /**
@@ -2237,6 +2377,54 @@ function request_path() {
   return $path;
 }
 
+/**
+ * Return a component of the current Drupal path.
+ *
+ * When viewing a page at the path "admin/structure/types", for example, arg(0)
+ * returns "admin", arg(1) returns "structure", and arg(2) returns "types".
+ *
+ * Avoid use of this function where possible, as resulting code is hard to read.
+ * In menu callback functions, attempt to use named arguments. See the explanation
+ * in menu.inc for how to construct callbacks that take arguments. When attempting
+ * to use this function to load an element from the current path, e.g. loading the
+ * node on a node page, please use menu_get_object() instead.
+ *
+ * @param $index
+ *   The index of the component, where each component is separated by a '/'
+ *   (forward-slash), and where the first component has an index of 0 (zero).
+ * @param $path
+ *   A path to break into components. Defaults to the path of the current page.
+ *
+ * @return
+ *   The component specified by $index, or NULL if the specified component was
+ *   not found.
+ */
+function arg($index = NULL, $path = NULL) {
+  // Even though $arguments doesn't need to be resettable for any functional
+  // reasons (the result of explode() does not depend on any run-time
+  // information), it should be resettable anyway in case a module needs to
+  // free up the memory used by it.
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['arguments'] = &drupal_static(__FUNCTION__);
+  }
+  $arguments = &$drupal_static_fast['arguments'];
+
+  if (!isset($path)) {
+    $path = $_GET['q'];
+  }
+  if (!isset($arguments[$path])) {
+    $arguments[$path] = explode('/', $path);
+  }
+  if (!isset($index)) {
+    return $arguments[$path];
+  }
+  if (isset($arguments[$path][$index])) {
+    return $arguments[$path][$index];
+  }
+}
+
 /**
  * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
  * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of
@@ -2440,7 +2628,7 @@ function _registry_check_code($type, $name = NULL) {
     if ($lookup_cache[$cache_key]) {
       require DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
     }
-    return (bool)$lookup_cache[$cache_key];
+    return (bool) $lookup_cache[$cache_key];
   }
 
   // This function may get called when the default database is not active, but
diff --git a/includes/cache-install.inc b/includes/cache-install.inc
index 3beebf3ab2f91707775043735fb428a9b52e2480..c4cf081ac0365e84d86c0f8fb7c3507661837526 100644
--- a/includes/cache-install.inc
+++ b/includes/cache-install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: cache-install.inc,v 1.8 2010/04/11 17:16:45 dries Exp $
+// $Id: cache-install.inc,v 1.9 2010/05/18 18:26:30 dries Exp $
 
 /**
  * @file
@@ -24,7 +24,7 @@ class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterfac
     return array();
   }
 
-  function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL) {
+  function set($cid, $data, $expire = CACHE_PERMANENT) {
   }
 
   function clear($cid = NULL, $wildcard = FALSE) {
diff --git a/includes/cache.inc b/includes/cache.inc
index b5dc86e8a35d05913ba62a431a5d8ffc650b0ad3..a625266bff5fe7eb53cb680f2061a646c23884ec 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: cache.inc,v 1.47 2010/03/07 07:26:13 webchick Exp $
+// $Id: cache.inc,v 1.48 2010/05/18 18:26:30 dries Exp $
 
 /**
  * Get the cache object for a cache bin.
@@ -133,11 +133,9 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
  *     general cache wipe.
  *   - A Unix timestamp: Indicates that the item should be kept at least until
  *     the given time, after which it behaves like CACHE_TEMPORARY.
- * @param $headers
- *   A string containing HTTP header information for cached pages.
  */
-function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT, array $headers = NULL) {
-  return _cache_get_object($bin)->set($cid, $data, $expire, $headers);
+function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
+  return _cache_get_object($bin)->set($cid, $data, $expire);
 }
 
 /**
@@ -263,10 +261,8 @@ interface DrupalCacheInterface {
    *     general cache wipe.
    *   - A Unix timestamp: Indicates that the item should be kept at least until
    *     the given time, after which it behaves like CACHE_TEMPORARY.
-   * @param $headers
-   *   A string containing HTTP header information for cached pages.
    */
-  function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL);
+  function set($cid, $data, $expire = CACHE_PERMANENT);
 
 
   /**
@@ -312,7 +308,7 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     try {
       // Garbage collection necessary when enforcing a minimum cache lifetime.
       $this->garbageCollection($this->bin);
-      $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $this->bin . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+      $cache = db_query("SELECT data, created, expire, serialized FROM {" . $this->bin . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
       return $this->prepareItem($cache);
     }
     catch (Exception $e) {
@@ -327,7 +323,7 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
       // Garbage collection necessary when enforcing a minimum cache lifetime.
       $this->garbageCollection($this->bin);
       $query = db_select($this->bin);
-      $query->fields($this->bin, array('cid', 'data', 'created', 'headers', 'expire', 'serialized'));
+      $query->fields($this->bin, array('cid', 'data', 'created', 'expire', 'serialized'));
       $query->condition($this->bin . '.cid', $cids, 'IN');
       $result = $query->execute();
       $cache = array();
@@ -401,19 +397,15 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     if ($cache->serialized) {
       $cache->data = unserialize($cache->data);
     }
-    if (isset($cache->headers)) {
-      $cache->headers = unserialize($cache->headers);
-    }
 
     return $cache;
   }
 
-  function set($cid, $data, $expire = CACHE_PERMANENT, array $headers = NULL) {
+  function set($cid, $data, $expire = CACHE_PERMANENT) {
     $fields = array(
       'serialized' => 0,
       'created' => REQUEST_TIME,
       'expire' => $expire,
-      'headers' => isset($headers) ? serialize($headers) : NULL,
     );
     if (!is_string($data)) {
       $fields['data'] = serialize($data);
diff --git a/includes/common.inc b/includes/common.inc
index b340f02806ce751a415e3a18d010394b6187eabd..b976c90a6e31c0a2b369b089d84ebdb64d17fe9a 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: common.inc,v 1.1151 2010/04/24 14:53:59 dries Exp $
+// $Id: common.inc,v 1.1170 2010/05/21 15:52:19 dries Exp $
 
 /**
  * @file
@@ -660,7 +660,7 @@ function drupal_encode_path($path) {
 function drupal_goto($path = '', array $options = array(), $http_response_code = 302) {
   // A destination in $_GET always overrides the function arguments.
   if (isset($_GET['destination'])) {
-    $destination = drupal_parse_url(urldecode($_GET['destination']));
+    $destination = drupal_parse_url($_GET['destination']);
     $path = $destination['path'];
     $options['query'] = $destination['query'];
     $options['fragment'] = $destination['fragment'];
@@ -758,7 +758,9 @@ function drupal_access_denied() {
  *   - error
  *       If an error occurred, the error message. Otherwise not set.
  *   - headers
- *       An array containing the response headers as name/value pairs.
+ *       An array containing the response headers as name/value pairs. HTTP
+ *       header names are case-insensitive (RFC 2616, section 4.2), so for easy
+ *       access the array keys are returned in lower case.
  *   - data
  *       A string containing the response body that was received.
  */
@@ -877,21 +879,33 @@ function drupal_http_request($url, array $options = array()) {
 
   fwrite($fp, $request);
 
-  // Fetch response.
+  // Fetch response. Due to PHP bugs like http://bugs.php.net/bug.php?id=43782
+  // and http://bugs.php.net/bug.php?id=46049 we can't rely on feof(), but
+  // instead must invoke stream_get_meta_data() each iteration.
+  $info = stream_get_meta_data($fp);
+  $alive = !$info['eof'] && !$info['timed_out'];
   $response = '';
-  while (!feof($fp)) {
+
+  while ($alive) {
     // Calculate how much time is left of the original timeout value.
     $timeout = $options['timeout'] - timer_read(__FUNCTION__) / 1000;
     if ($timeout <= 0) {
-      $result->code = HTTP_REQUEST_TIMEOUT;
-      $result->error = 'request timed out';
-      return $result;
+      $info['timed_out'] = TRUE;
+      break;
     }
     stream_set_timeout($fp, floor($timeout), floor(1000000 * fmod($timeout, 1)));
-    $response .= fread($fp, 1024);
+    $chunk = fread($fp, 1024);
+    $response .= $chunk;
+    $info = stream_get_meta_data($fp);
+    $alive = !$info['eof'] && !$info['timed_out'] && $chunk;
   }
   fclose($fp);
 
+  if ($info['timed_out']) {
+    $result->code = HTTP_REQUEST_TIMEOUT;
+    $result->error = 'request timed out';
+    return $result;
+  }
   // Parse response headers from the response body.
   list($response, $result->data) = explode("\r\n\r\n", $response, 2);
   $response = preg_split("/\r\n|\n|\r/", $response);
@@ -905,14 +919,15 @@ function drupal_http_request($url, array $options = array()) {
 
   // Parse the response headers.
   while ($line = trim(array_shift($response))) {
-    list($header, $value) = explode(':', $line, 2);
-    if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
+    list($name, $value) = explode(':', $line, 2);
+    $name = strtolower($name);
+    if (isset($result->headers[$name]) && $name == 'set-cookie') {
       // RFC 2109: the Set-Cookie response header comprises the token Set-
       // Cookie:, followed by a comma-separated list of one or more cookies.
-      $result->headers[$header] .= ',' . trim($value);
+      $result->headers[$name] .= ',' . trim($value);
     }
     else {
-      $result->headers[$header] = trim($value);
+      $result->headers[$name] = trim($value);
     }
   }
 
@@ -972,7 +987,7 @@ function drupal_http_request($url, array $options = array()) {
     case 301: // Moved permanently
     case 302: // Moved temporarily
     case 307: // Moved temporarily
-      $location = $result->headers['Location'];
+      $location = $result->headers['location'];
       $options['timeout'] -= timer_read(__FUNCTION__) / 1000;
       if ($options['timeout'] <= 0) {
         $result->code = HTTP_REQUEST_TIMEOUT;
@@ -2419,7 +2434,7 @@ function drupal_page_footer() {
   // Commit the user session, if needed.
   drupal_session_commit();
 
-  if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED && ($cache = drupal_page_set_cache())) {
+  if (variable_get('cache', 0) && ($cache = drupal_page_set_cache())) {
     drupal_serve_page_from_cache($cache);
   }
   else {
@@ -2881,10 +2896,7 @@ function drupal_aggregate_css(&$css_groups) {
       // the group's data property to the file path of the aggregate file.
       case 'file':
         if ($group['preprocess'] && $preprocess_css) {
-          // Prefix filename to prevent blocking by firewalls which reject files
-          // starting with "ad*".
-          $filename = 'css_' . md5(serialize($group['items'])) . '.css';
-          $css_groups[$key]['data'] = drupal_build_css_cache($group['items'], $filename);
+          $css_groups[$key]['data'] = drupal_build_css_cache($group['items']);
         }
         break;
       // Aggregate all inline CSS content into the group's data property.
@@ -3010,7 +3022,7 @@ function drupal_pre_render_styles($elements) {
         // for the aggregate file.
         if (isset($group['data'])) {
           $element = $link_element_defaults;
-          $element['#attributes']['href'] = file_create_url($group['data']) . '?' . $query_string;
+          $element['#attributes']['href'] = file_create_url($group['data']);
           $element['#attributes']['media'] = $group['media'];
           $element['#browsers'] = $group['browsers'];
           $elements[] = $element;
@@ -3093,23 +3105,39 @@ function drupal_pre_render_styles($elements) {
 }
 
 /**
- * Aggregate and optimize CSS files, putting them in the files directory.
+ * Aggregates and optimizes CSS files into a cache file in the files directory.
+ *
+ * The file name for the CSS cache file is generated from the hash of the
+ * aggregated contents of the files in $css. This forces proxies and browsers
+ * to download new CSS when the CSS changes.
+ *
+ * The cache file name is retrieved on a page load via a lookup variable that
+ * contains an associative array. The array key is the hash of the file names
+ * in $css while the value is the cache file name. The cache file is generated
+ * in two cases. First, if there is no file name value for the key, which will
+ * happen if a new file name has been added to $css or after the lookup
+ * variable is emptied to force a rebuild of the cache.  Second, the cache
+ * file is generated if it is missing on disk. Old cache files are not deleted
+ * immediately when the lookup variable is emptied, but are deleted after a set
+ * period by drupal_delete_file_if_stale(). This ensures that files referenced
+ * by a cached page will still be available.
  *
  * @param $css
  *   An array of CSS files to aggregate and compress into one file.
- * @param $filename
- *   The name of the aggregate CSS file.
+ *
  * @return
- *   The name of the CSS file, or FALSE if the file could not be saved.
+ *   The URI of the CSS cache file, or FALSE if the file could not be saved.
  */
-function drupal_build_css_cache($css, $filename) {
+function drupal_build_css_cache($css) {
   $data = '';
+  $uri = '';
+  $map = variable_get('drupal_css_cache_files', array());
+  $key = hash('sha256', serialize($css));
+  if (isset($map[$key])) {
+    $uri = $map[$key];
+  }
 
-  // Create the css/ within the files folder.
-  $csspath = 'public://css';
-  $uri = $csspath . '/' . $filename;
-
-  if (!file_exists($uri)) {
+  if (empty($uri) || !file_exists($uri)) {
     // Build aggregate CSS file.
     foreach ($css as $stylesheet) {
       // Only 'file' stylesheets can be aggregated.
@@ -3130,11 +3158,20 @@ function drupal_build_css_cache($css, $filename) {
     $data = preg_replace($regexp, '', $data);
     $data = implode('', $matches[0]) . $data;
 
+    // Prefix filename to prevent blocking by firewalls which reject files
+    // starting with "ad*".
+    $filename = 'css_' . drupal_hash_base64($data) . '.css';
+    // Create the css/ within the files folder.
+    $csspath = 'public://css';
+    $uri = $csspath . '/' . $filename;
     // Create the CSS file.
     file_prepare_directory($csspath, FILE_CREATE_DIRECTORY);
-    if (!file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) {
+    if (!file_exists($uri) && !file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) {
       return FALSE;
     }
+    // Save the updated map.
+    $map[$key] = $uri;
+    variable_set('drupal_css_cache_files', $map);
   }
   return $uri;
 }
@@ -3263,10 +3300,21 @@ function _drupal_load_stylesheet($matches) {
 }
 
 /**
- * Delete all cached CSS files.
+ * Deletes old cached CSS files.
  */
 function drupal_clear_css_cache() {
-  file_scan_directory('public://css', '/.*/', array('callback' => 'file_unmanaged_delete'));
+  variable_del('drupal_css_cache_files');
+  file_scan_directory('public://css', '/.*/', array('callback' => 'drupal_delete_file_if_stale'));
+}
+
+/**
+ * Callback to delete files modified more than a set time ago.
+ */
+function drupal_delete_file_if_stale($uri) {
+  // Default stale file threshold is 30 days.
+  if (REQUEST_TIME - filemtime($uri) > variable_get('drupal_stale_file_threshold', 2592000)) {
+    file_unmanaged_delete($uri);
+  }
 }
 
 /**
@@ -3752,15 +3800,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
 
   // Aggregate any remaining JS files that haven't already been output.
   if ($preprocess_js && count($files) > 0) {
-    // Prefix filename to prevent blocking by firewalls which reject files
-    // starting with "ad*".
     foreach ($files as $key => $file_set) {
-      $filename = 'js_' . md5(serialize($file_set)) . '.js';
-      $uri = drupal_build_js_cache($file_set, $filename);
+      $uri = drupal_build_js_cache($file_set);
       // Only include the file if was written successfully. Errors are logged
       // using watchdog.
       if ($uri) {
-        $preprocess_file = file_create_url($uri) . '?' . $default_query_string;
+        $preprocess_file = file_create_url($uri);
         $js_element = $element;
         $js_element['#attributes']['src'] = $preprocess_file;
         $processed[$key] = theme('html_tag', array('element' => $js_element));
@@ -3879,41 +3924,129 @@ function drupal_process_attached($elements, $weight = JS_DEFAULT, $dependency_ch
 }
 
 /**
- * Adds JavaScript to the element to allow it to have different active states.
+ * Adds JavaScript to change the state of an element based on another element.
  *
- * @param $elements
- *   The structured array that may contain an array item named states. This
- *   array describes the different JavaScript states that can be applied to the
- *   element when certain conditions are met. The #states array is first keyed
- *   by one of the following states:
- *   - enabled
- *   - invisible
- *   - invalid
- *   - untouched
- *   - optional
- *   - filled
- *   - unchecked
- *   - irrelevant
- *   - expanded
- *   - readwrite
- *
- *   Each of these states is an array containing conditions that must be met in
- *   order for this state to be active. The key to this conditioning array is
- *   a jQuery selector for the element that is checked. The value of the
- *   conditioning array are the states that are checked on the element (empty,
- *   checked, value, collapsed, etc) and the expected value of that condition.
- *
- *   @code
- *   $form['email_canceled']['settings'] = array(
- *     '#type' => 'container',
- *     '#states' => array(
- *       // Hide the settings when the cancel notify checkbox is disabled.
- *       'invisible' => array(
- *         'input[name="email_canceled_toggle"]' => array('checked' => FALSE),
- *       ),
+ * A "state" means a certain property on a DOM element, such as "visible" or
+ * "checked". A state can be applied to an element, depending on the state of
+ * another element on the page. In general, states depend on HTML attributes and
+ * DOM element properties, which change due to user interaction.
+ *
+ * Since states are driven by JavaScript only, it is important to understand
+ * that all states are applied on presentation only, none of the states force
+ * any server-side logic, and that they will not be applied for site visitors
+ * without JavaScript support. All modules implementing states have to make
+ * sure that the intended logic also works without JavaScript being enabled.
+ *
+ * #states is an associative array in the form of:
+ * @code
+ * array(
+ *   STATE1 => CONDITIONS_ARRAY1,
+ *   STATE2 => CONDITIONS_ARRAY2,
+ *   ...
+ * )
+ * @endcode
+ * Each key is the name of a state to apply to the element, such as 'visible'.
+ * Each value is a list of conditions that denote when the state should be
+ * applied.
+ *
+ * Multiple different states may be specified to act on complex conditions:
+ * @code
+ * array(
+ *   'visible' => CONDITIONS,
+ *   'checked' => OTHER_CONDITIONS,
+ * )
+ * @endcode
+ *
+ * Every condition is a key/value pair, whose key is a jQuery selector that
+ * denotes another element on the page, and whose value is an array of
+ * conditions, which must bet met on that element:
+ * @code
+ * array(
+ *   'visible' => array(
+ *     JQUERY_SELECTOR => REMOTE_CONDITIONS,
+ *     JQUERY_SELECTOR => REMOTE_CONDITIONS,
+ *     ...
+ *   ),
+ * )
+ * @endcode
+ * All conditions must be met for the state to be applied.
+ *
+ * Each remote condition is a key/value pair specifying conditions on the other
+ * element that need to be met to apply the state to the element:
+ * @code
+ * array(
+ *   'visible' => array(
+ *     ':input[name="remote_checkbox"]' => array('checked' => TRUE),
+ *   ),
+ * )
+ * @endcode
+ *
+ * For example, to show a textfield only when a checkbox is checked:
+ * @code
+ * $form['toggle_me'] = array(
+ *   '#type' => 'checkbox',
+ *   '#title' => t('Tick this box to type'),
+ * );
+ * $form['settings'] = array(
+ *   '#type' => 'textfield',
+ *   '#states' => array(
+ *     // Only show this field when the 'toggle_me' checkbox is enabled.
+ *     'visible' => array(
+ *       ':input[name="toggle_me"]' => array('checked' => TRUE),
  *     ),
- *   );
- *   @endcode
+ *   ),
+ * );
+ * @endcode
+ *
+ * The following states may be applied to an element:
+ * - enabled
+ * - disabled
+ * - visible
+ * - invisible
+ * - checked
+ * - unchecked
+ * - expanded
+ * - collapsed
+ *
+ * The following states may be used in remote conditions:
+ * - enabled
+ * - disabled
+ * - visible
+ * - invisible
+ * - checked
+ * - unchecked
+ * - value
+ *
+ * The following states exist for both states and remote conditions, but are not
+ * fully implemented and may not change anything on the element:
+ * - required
+ * - optional
+ * - relevant
+ * - irrelevant
+ * - valid
+ * - invalid
+ * - touched
+ * - untouched
+ * - filled
+ * - empty
+ * - readwrite
+ * - readonly
+ *
+ * When referencing select lists and radio buttons in remote conditions, a
+ * 'value' condition must be used:
+ * @code
+ *   '#states' => array(
+ *     // Show the settings if 'bar' has been selected for 'foo'.
+ *     'visible' => array(
+ *       ':input[name="foo"]' => array('value' => 'bar'),
+ *     ),
+ *   ),
+ * @endcode
+ *
+ * @param $elements
+ *   A renderable array element having a #states property as described above.
+ *
+ * @see form_example_states_form()
  */
 function drupal_process_states(&$elements) {
   $elements['#attached']['js']['misc/states.js'] = array('weight' => JS_LIBRARY + 1);
@@ -4157,46 +4290,70 @@ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgro
 }
 
 /**
- * Aggregate JS files, putting them in the files directory.
+ * Aggregates JavaScript files into a cache file in the files directory.
+ *
+ * The file name for the JavaScript cache file is generated from the hash of
+ * the aggregated contents of the files in $files. This forces proxies and
+ * browsers to download new JavaScript when the JavaScript changes.
+ *
+ * The cache file name is retrieved on a page load via a lookup variable that
+ * contains an associative array. The array key is the hash of the names in
+ * $files while the value is the cache file name. The cache file is generated
+ * in two cases. First, if there is no file name value for the key, which will
+ * happen if a new file name has been added to $files or after the lookup
+ * variable is emptied to force a rebuild of the cache.  Second, the cache
+ * file is generated if it is missing on disk. Old cache files are not deleted
+ * immediately when the lookup variable is emptied, but are deleted after a set
+ * period by drupal_delete_file_if_stale(). This ensures that files referenced
+ * by a cached page will still be available.
  *
  * @param $files
- *   An array of JS files to aggregate and compress into one file.
- * @param $filename
- *   The name of the aggregate JS file.
+ *   An array of JavaScript files to aggregate and compress into one file.
+ *
  * @return
- *   The name of the JS file, or FALSE if the file could not be saved.
+ *   The URI of the cache file, or FALSE if the file could not be saved.
  */
-function drupal_build_js_cache($files, $filename) {
+function drupal_build_js_cache($files) {
   $contents = '';
+  $uri = '';
+  $map = variable_get('drupal_js_cache_files', array());
+  $key = hash('sha256', serialize($files));
+  if (isset($map[$key])) {
+    $uri = $map[$key];
+  }
 
-  // Create the js/ within the files folder.
-  $jspath = 'public://js';
-  $uri = $jspath . '/' . $filename;
-
-  if (!file_exists($uri)) {
+  if (empty($uri) || !file_exists($uri)) {
     // Build aggregate JS file.
     foreach ($files as $path => $info) {
       if ($info['preprocess']) {
-        // Append a ';' after each JS file to prevent them from running together.
-        $contents .= file_get_contents($path) . ';';
+        // Append a ';' and a newline after each JS file to prevent them from running together.
+        $contents .= file_get_contents($path) . ";\n";
       }
     }
-
+    // Prefix filename to prevent blocking by firewalls which reject files
+    // starting with "ad*".
+    $filename = 'js_' . drupal_hash_base64($contents) . '.js';
+    // Create the js/ within the files folder.
+    $jspath = 'public://js';
+    $uri = $jspath . '/' . $filename;
     // Create the JS file.
     file_prepare_directory($jspath, FILE_CREATE_DIRECTORY);
     if (!file_unmanaged_save_data($contents, $uri, FILE_EXISTS_REPLACE)) {
       return FALSE;
     }
+    $map[$key] = $uri;
+    variable_set('drupal_js_cache_files', $map);
   }
   return $uri;
 }
 
 /**
- * Delete all cached JS files.
+ * Deletes old cached JavaScript files and variables.
  */
 function drupal_clear_js_cache() {
-  file_scan_directory('public://js', '/.*/', array('callback' => 'file_unmanaged_delete'));
-  variable_set('javascript_parsed', array());
+  variable_del('javascript_parsed');
+  variable_del('drupal_js_cache_files');
+  file_scan_directory('public://js', '/.*/', array('callback' => 'drupal_delete_file_if_stale'));
 }
 
 /**
@@ -4232,53 +4389,14 @@ function drupal_json_decode($var) {
  *   (optional) If set, the variable will be converted to JSON and output.
  */
 function drupal_json_output($var = NULL) {
-  // We are returning JavaScript, so tell the browser.
-  drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
+  // We are returning JSON, so tell the browser.
+  drupal_add_http_header('Content-Type', 'application/json');
 
   if (isset($var)) {
     echo drupal_json_encode($var);
   }
 }
 
-/**
- * Returns a string of highly randomized bytes (over the full 8-bit range).
- *
- * This function is better than simply calling mt_rand() or any other built-in
- * PHP function because it can return a long string of bytes (compared to < 4
- * bytes normally from mt_rand()) and uses the best available pseudo-random source.
- *
- * @param $count
- *   The number of characters (bytes) to return in the string.
- */
-function drupal_random_bytes($count)  {
-  // $random_state does not use drupal_static as it stores random bytes.
-  static $random_state;
-  // We initialize with the somewhat random PHP process ID on the first call.
-  if (empty($random_state)) {
-    $random_state = getmypid();
-  }
-  $output = '';
-  // /dev/urandom is available on many *nix systems and is considered the best
-  // commonly available pseudo-random source.
-  if ($fh = @fopen('/dev/urandom', 'rb')) {
-    $output = fread($fh, $count);
-    fclose($fh);
-  }
-  // If /dev/urandom is not available or returns no bytes, this loop will
-  // generate a good set of pseudo-random bytes on any system.
-  // Note that it may be important that our $random_state is passed
-  // through md5() prior to being rolled into $output, that the two md5()
-  // invocations are different, and that the extra input into the first one -
-  // the microtime() - is prepended rather than appended. This is to avoid
-  // directly leaking $random_state via the $output stream, which could
-  // allow for trivial prediction of further "random" numbers.
-  while (strlen($output) < $count) {
-    $random_state = md5(microtime() . mt_rand() . $random_state);
-    $output .= md5(mt_rand() . $random_state, TRUE);
-  }
-  return substr($output, 0, $count);
-}
-
 /**
  * Get a salt useful for hardening against SQL injection.
  *
@@ -4289,7 +4407,7 @@ function drupal_get_hash_salt() {
   global $drupal_hash_salt, $databases;
   // If the $drupal_hash_salt variable is empty, a hash of the serialized
   // database credentials is used as a fallback salt.
-  return empty($drupal_hash_salt) ? sha1(serialize($databases)) : $drupal_hash_salt;
+  return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
 }
 
 /**
@@ -4300,7 +4418,7 @@ function drupal_get_hash_salt() {
  */
 function drupal_get_private_key() {
   if (!($key = variable_get('drupal_private_key', 0))) {
-    $key = md5(drupal_random_bytes(64));
+    $key = drupal_hash_base64(drupal_random_bytes(55));
     variable_set('drupal_private_key', $key);
   }
   return $key;
@@ -4313,10 +4431,7 @@ function drupal_get_private_key() {
  *   An additional value to base the token on.
  */
 function drupal_get_token($value = '') {
-  $private_key = drupal_get_private_key();
-  // A single md5() is vulnerable to length-extension attacks, so use it twice.
-  // @todo:  add md5 and sha1 hmac functions to core.
-  return md5(drupal_get_hash_salt() . md5(session_id() . $value . $private_key));
+  return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
 }
 
 /**
@@ -4347,7 +4462,7 @@ function _drupal_bootstrap_full() {
   require_once DRUPAL_ROOT . '/' . variable_get('path_inc', 'includes/path.inc');
   require_once DRUPAL_ROOT . '/includes/theme.inc';
   require_once DRUPAL_ROOT . '/includes/pager.inc';
-  require_once DRUPAL_ROOT . '/' . variable_get('menu_inc', '/includes/menu.inc');
+  require_once DRUPAL_ROOT . '/' . variable_get('menu_inc', 'includes/menu.inc');
   require_once DRUPAL_ROOT . '/includes/tablesort.inc';
   require_once DRUPAL_ROOT . '/includes/file.inc';
   require_once DRUPAL_ROOT . '/includes/unicode.inc';
@@ -4406,28 +4521,32 @@ function drupal_page_set_cache() {
   if (drupal_page_is_cacheable()) {
     $cache = (object) array(
       'cid' => $base_root . request_uri(),
-      'data' => ob_get_clean(),
+      'data' => array(
+        'path' => $_GET['q'],
+        'body' => ob_get_clean(),
+        'title' => drupal_get_title(),
+        'headers' => array(),
+      ),
       'expire' => CACHE_TEMPORARY,
       'created' => REQUEST_TIME,
-      'headers' => array(),
     );
 
     // Restore preferred header names based on the lower-case names returned
     // by drupal_get_http_header().
     $header_names = _drupal_set_preferred_header_name();
     foreach (drupal_get_http_header() as $name_lower => $value) {
-      $cache->headers[$header_names[$name_lower]] = $value;
+      $cache->data['headers'][$header_names[$name_lower]] = $value;
       if ($name_lower == 'expires') {
         // Use the actual timestamp from an Expires header if available.
         $cache->expire = strtotime($value);
       }
     }
 
-    if ($cache->data) {
+    if ($cache->data['body']) {
       if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
-        $cache->data = gzencode($cache->data, 9, FORCE_GZIP);
+        $cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
       }
-      cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire, $cache->headers);
+      cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire);
     }
     return $cache;
   }
@@ -4534,31 +4653,51 @@ function drupal_cron_cleanup() {
 }
 
 /**
- * Return an array of system file objects.
- *
- * Returns an array of file objects of the given type from the site-wide
- * directory (i.e. modules/), the all-sites directory (i.e. sites/all/modules/),
- * the profiles directory (i.e. profiles/your_site_profile/modules/), and the
- * site-specific directory (i.e. sites/your_site_dir/modules/). The returned
- * array will be keyed using the key specified (uri, filename, or name). Using
- * name or filename will cause site-specific files to be prioritized over
- * similar files in the default directories. That is, if a file with the same
- * name appears in both the site-wide directory and site-specific directory,
- * only the site-specific version will be included.
- *
- * @param $mask
- *   The preg_match() regular expression of the files to find.
- * @param $directory
+ * Returns information about system object files (modules, themes, etc.).
+ * 
+ * This function is used to find all or some system object files (module files,
+ * theme files, etc.) that exist on the site. It searches in several locations,
+ * depending on what type of object you are looking for. For instance, if you
+ * are looking for modules and call:
+ * @code
+ * drupal_system_listing("/\.module$/", "modules", 'name', 0);
+ * @endcode
+ * this function will search the site-wide modules directory (i.e., /modules/),
+ * your install profile's directory (i.e.,
+ * /profiles/your_site_profile/modules/), the all-sites directory (i.e.,
+ * /sites/all/modules/), and your site-specific directory (i.e.,
+ * /sites/your_site_dir/modules/), in that order, and return information about
+ * all of the files ending in .module in those directories.
+ *
+ * The information is returned in an associative array, which can be keyed on
+ * the file name ($key = 'filename'), the file name without the extension ($key
+ * = 'name'), or the full file stream URI ($key = 'uri'). If you use a key of
+ * 'filename' or 'name', files found later in the search will take precedence
+ * over files found earlier; if you choose a key of 'uri', you will get all
+ * files found.
+ *
+ * @param string $mask
+ *   The preg_match() regular expression for the files to find.
+ * @param string $directory
  *   The subdirectory name in which the files are found. For example,
- *   'modules' will search in both modules/ and
- *   sites/somesite/modules/.
- * @param $key
- *   The key to be passed to file_scan_directory().
- * @param $min_depth
- *   Minimum depth of directories to return files from.
- *
- * @return
- *   An array of file objects of the specified type.
+ *   'modules' will search in sub-directories of the top-level /modules
+ *   directory, sub-directories of /sites/all/modules/, etc.
+ * @param string $key
+ *   The key to be used for the associative array returned. Possible values are
+ *   'uri', for the file's URI; 'filename', for the basename of the file; and
+ *   'name' for the name of the file without the extension. If you choose 'name'
+ *   or 'filename', only the highest-precedence file will be returned.
+ * @param int $min_depth
+ *   Minimum depth of directories to return files from, relative to each
+ *   directory searched. For instance, a minimum depth of 2 would find modules
+ *   inside /modules/node/tests, but not modules directly in /modules/node.
+ *
+ * @return array
+ *   An associative array of file objects, keyed on the chosen key. Each element
+ *   in the array is an object containing file information, with properties:
+ *   - 'uri': Full URI of the file.
+ *   - 'filename': File name.
+ *   - 'name': Name of file without the extension.
  */
 function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1) {
   $config = conf_path();
@@ -4836,7 +4975,7 @@ function drupal_render_page($page) {
  * using uasort(). Since this is expensive, when passing already sorted
  * elements to drupal_render(), for example from a database query, set
  * $elements['#sorted'] = TRUE to avoid sorting them a second time.
- * 
+ *
  * drupal_render() flags each element with a '#printed' status to indicate that
  * the element has been rendered, which allows individual elements of a given
  * array to be rendered independently and prevents them from being rendered
@@ -5127,7 +5266,7 @@ function drupal_render_cache_set(&$markup, $elements) {
 function drupal_render_cache_by_query($query, $function, $expire = CACHE_TEMPORARY, $granularity = NULL) {
   $cache_keys = array_merge(array($function), drupal_render_cid_parts($granularity));
   $query->preExecute();
-  $cache_keys[] = md5(serialize(array((string) $query, $query->getArguments())));
+  $cache_keys[] = hash('sha256', serialize(array((string) $query, $query->getArguments())));
   return array(
     '#query' => $query,
     '#pre_render' => array($function . '_pre_render'),
@@ -5378,7 +5517,19 @@ function drupal_common_theme() {
       'variables' => array('links' => NULL, 'attributes' => array('class' => array('links')), 'heading' => array()),
     ),
     'image' => array(
-      'variables' => array('path' => NULL, 'alt' => '', 'title' => '', 'attributes' => array(), 'getsize' => TRUE),
+      // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
+      // allows the alt attribute to be omitted in some cases. Therefore,
+      // default the alt attribute to an empty string, but allow code calling
+      // theme('image') to pass explicit NULL for it to be omitted. Usually,
+      // neither omission nor an empty string satisfies accessibility
+      // requirements, so it is strongly encouraged for code calling
+      // theme('image') to pass a meaningful value for the alt variable.
+      // - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
+      // - http://www.w3.org/TR/xhtml1/dtds.html
+      // - http://dev.w3.org/html5/spec/Overview.html#alt
+      // The title attribute is optional in all cases, so it is omitted by
+      // default.
+      'variables' => array('path' => NULL, 'alt' => '', 'title' => NULL, 'attributes' => array(), 'getsize' => TRUE),
     ),
     'breadcrumb' => array(
       'variables' => array('breadcrumb' => NULL),
@@ -5389,9 +5540,6 @@ function drupal_common_theme() {
     'table' => array(
       'variables' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'colgroups' => array(), 'sticky' => TRUE, 'empty' => ''),
     ),
-    'table_select_header_cell' => array(
-      'variables' => array(),
-    ),
     'tablesort_indicator' => array(
       'variables' => array('style' => NULL),
     ),
@@ -6061,10 +6209,15 @@ function drupal_flush_all_caches() {
   registry_rebuild();
   drupal_clear_css_cache();
   drupal_clear_js_cache();
+
+  // Rebuild the theme data. Note that the module data is rebuilt above, as
+  // part of registry_rebuild().
   system_rebuild_theme_data();
   drupal_theme_rebuild();
+
   menu_rebuild();
   node_types_rebuild();
+
   // Don't clear cache_form - in-progress form submissions may break.
   // Ordered so clearing the page cache will always be the last action.
   $core = array('cache', 'cache_filter', 'cache_bootstrap', 'cache_page');
@@ -6299,7 +6452,7 @@ function entity_extract_ids($entity_type, $entity) {
  *   containing these elements:
  *   0: primary id of the entity
  *   1: revision id of the entity, or NULL if $entity_type is not versioned
- *   2: bundle name of the entity
+ *   2: bundle name of the entity, or NULL if $entity_type has no bundles
  * @return
  *   An entity structure, initialized with the ids provided.
  */
@@ -6307,10 +6460,10 @@ function entity_create_stub_entity($entity_type, $ids) {
   $entity = new stdClass();
   $info = entity_get_info($entity_type);
   $entity->{$info['entity keys']['id']} = $ids[0];
-  if (isset($info['entity keys']['revision']) && !is_null($ids[1])) {
+  if (!empty($info['entity keys']['revision']) && !is_null($ids[1])) {
     $entity->{$info['entity keys']['revision']} = $ids[1];
   }
-  if ($info['entity keys']['bundle']) {
+  if (!empty($info['entity keys']['bundle']) && !is_null($ids[2])) {
     $entity->{$info['entity keys']['bundle']} = $ids[2];
   }
   return $entity;
diff --git a/includes/database/database.inc b/includes/database/database.inc
index 5c771b18dce8c2ef76334e2fc9e22f4df86ee3e6..8c2891f6ca05bae3c0c65d72081e600dfd6da4db 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.119 2010/04/26 14:12:59 dries Exp $
+// $Id: database.inc,v 1.122 2010/05/05 16:51:30 dries Exp $
 
 /**
  * @file
@@ -559,7 +559,6 @@ abstract class DatabaseConnection extends PDO {
       }
     }
     catch (PDOException $e) {
-      _db_check_install_needed();
       if ($options['throw_exception']) {
         // Add additional debug information.
         if ($query instanceof DatabaseStatementInterface) {
@@ -779,6 +778,20 @@ abstract class DatabaseConnection extends PDO {
     return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
   }
 
+  /**
+   * Escapes a field name string.
+   *
+   * Force all field names to be strictly alphanumeric-plus-underscore.
+   * For some database drivers, it may also wrap the field name in
+   * database-specific escape characters.
+   *
+   * @return
+   *   The sanitized field name string.
+   */
+  public function escapeField($field) {
+    return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+  }
+
   /**
    * Escapes characters that work as wildcard characters in a LIKE pattern.
    *
@@ -1408,8 +1421,6 @@ abstract class Database {
   final public static function parseConnectionInfo() {
     global $databases;
 
-    _db_check_install_needed();
-
     $database_info = is_array($databases) ? $databases : array();
     foreach ($database_info as $index => $info) {
       foreach ($database_info[$index] as $target => $value) {
@@ -1496,46 +1507,38 @@ abstract class Database {
     if (empty(self::$databaseInfo)) {
       self::parseConnectionInfo();
     }
-    try {
-      // If the requested database does not exist then it is an unrecoverable
-      // error.
-      if (!isset(self::$databaseInfo[$key])) {
-        throw new DatabaseConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
-      }
 
-      if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
-        throw new DatabaseDriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
-      }
+    // If the requested database does not exist then it is an unrecoverable
+    // error.
+    if (!isset(self::$databaseInfo[$key])) {
+      throw new DatabaseConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
+    }
 
-      // We cannot rely on the registry yet, because the registry requires an
-      // open database connection.
-      $driver_class = 'DatabaseConnection_' . $driver;
-      require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc';
-      $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
-      $new_connection->setTarget($target);
-
-      // If we have any active logging objects for this connection key, we need
-      // to associate them with the connection we just opened.
-      if (!empty(self::$logs[$key])) {
-        $new_connection->setLogger(self::$logs[$key]);
-      }
+    if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
+      throw new DatabaseDriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
+    }
 
-      // We need to pass around the simpletest database prefix in the request
-      // and we put that in the user_agent header. The header HMAC was already
-      // validated in bootstrap.inc.
-      if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
-        $db_prefix_string = is_array($db_prefix) ? $db_prefix['default'] : $db_prefix;
-        $db_prefix = $db_prefix_string . $matches[1];
-      }
-      return $new_connection;
+    // We cannot rely on the registry yet, because the registry requires an
+    // open database connection.
+    $driver_class = 'DatabaseConnection_' . $driver;
+    require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc';
+    $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
+    $new_connection->setTarget($target);
+
+    // If we have any active logging objects for this connection key, we need
+    // to associate them with the connection we just opened.
+    if (!empty(self::$logs[$key])) {
+      $new_connection->setLogger(self::$logs[$key]);
     }
-    catch (Exception $e) {
-      // It is extremely rare that an exception will be generated here other
-      // than when installing. We therefore intercept it and try the installer,
-      // passing on the exception otherwise.
-      _db_check_install_needed();
-      throw $e;
+
+    // We need to pass around the simpletest database prefix in the request
+    // and we put that in the user_agent header. The header HMAC was already
+    // validated in bootstrap.inc.
+    if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
+      $db_prefix_string = is_array($db_prefix) ? $db_prefix['default'] : $db_prefix;
+      $db_prefix = $db_prefix_string . $matches[1];
     }
+    return $new_connection;
   }
 
   /**
@@ -1927,12 +1930,13 @@ interface DatabaseStatementInterface extends Traversable {
    * @param $fetch
    *   The fetchmode to use. If set to PDO::FETCH_ASSOC, PDO::FETCH_NUM, or
    *   PDO::FETCH_BOTH the returned value with be an array of arrays. For any
-   *   other value it will be an array of objects.
+   *   other value it will be an array of objects. By default, the fetch mode
+   *   set for the query will be used.
    *
    * @return
    *   An associative array.
    */
-  public function fetchAllAssoc($key, $fetch = PDO::FETCH_OBJ);
+  public function fetchAllAssoc($key, $fetch = NULL);
 }
 
 /**
@@ -1998,19 +2002,22 @@ class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInt
     return $this->fetchAll(PDO::FETCH_COLUMN, $index);
   }
 
-  public function fetchAllAssoc($key, $fetch = PDO::FETCH_OBJ) {
+  public function fetchAllAssoc($key, $fetch = NULL) {
     $return = array();
-    $this->setFetchMode($fetch);
-    if (in_array($fetch, array(PDO::FETCH_ASSOC, PDO::FETCH_NUM, PDO::FETCH_BOTH))) {
-      foreach ($this as $record) {
-        $return[$record[$key]] = $record;
+    if (isset($fetch)) {
+      if (is_string($fetch)) {
+        $this->setFetchMode(PDO::FETCH_CLASS, $fetch);
       }
-    }
-    else {
-      foreach ($this as $record) {
-        $return[$record->$key] = $record;
+      else {
+        $this->setFetchMode($fetch);
       }
     }
+
+    foreach ($this as $record) {
+      $record_key = is_object($record) ? $record->$key : $record[$key];
+      $return[$record_key] = $record;
+    }
+
     return $return;
   }
 
@@ -2091,7 +2098,7 @@ class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface {
     return array();
   }
 
-  public function fetchAllAssoc($key, $fetch = PDO::FETCH_OBJ) {
+  public function fetchAllAssoc($key, $fetch = NULL) {
     return array();
   }
 
@@ -2430,7 +2437,7 @@ function db_set_active($key = 'default') {
 }
 
 /**
- * Restricts a dynamic table, column, or constraint name to safe characters.
+ * Restricts a dynamic table name to safe characters.
  *
  * Only keeps alphanumeric and underscores.
  *
@@ -2444,6 +2451,21 @@ function db_escape_table($table) {
   return Database::getConnection()->escapeTable($table);
 }
 
+/**
+ * Restricts a dynamic column or constraint name to safe characters.
+ *
+ * Only keeps alphanumeric and underscores.
+ *
+ * @param $field
+ *   The field name to escape.
+ *
+ * @return
+ *   The escaped field name as a string.
+ */
+function db_escape_field($field) {
+  return Database::getConnection()->escapeField($field);
+}
+
 /**
  * Escapes characters that work as wildcard characters in a LIKE pattern.
  *
@@ -2900,17 +2922,3 @@ function db_ignore_slave() {
   }
 }
 
-/**
- * Redirects the user to the installation script.
- *
- * This will check if Drupal has not been installed yet (i.e., if no $databases
- * array has been defined in the settings.php file) and we are not already
- * installing. If both are true, the user is redirected to install.php.
- */
-function _db_check_install_needed() {
-  global $databases;
-  if (empty($databases) && !drupal_installation_attempted()) {
-    include_once DRUPAL_ROOT . '/includes/install.inc';
-    install_goto('install.php');
-  }
-}
diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc
index d868cec416d634251496dbf10aa7c0d96acdec4c..856e3120027adad4b86c03d02841987a68c1f158 100644
--- a/includes/database/mysql/database.inc
+++ b/includes/database/mysql/database.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.26 2010/03/07 08:03:44 webchick Exp $
+// $Id: database.inc,v 1.27 2010/05/05 06:28:39 webchick Exp $
 
 /**
  * @file
@@ -20,14 +20,17 @@ class DatabaseConnection_mysql extends DatabaseConnection {
     // MySQL never supports transactional DDL.
     $this->transactionalDDLSupport = FALSE;
 
-    // Default to TCP connection on port 3306.
-    if (empty($connection_options['port'])) {
-      $connection_options['port'] = 3306;
-    }
-
     $this->connectionOptions = $connection_options;
 
-    $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . $connection_options['port'] . ';dbname=' . $connection_options['database'];
+    // The DSN should use either a socket or a host/port.
+    if (isset($connection_options['unix_socket'])) {
+      $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
+    }
+    else {
+      // Default to TCP connection on port 3306.
+      $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
+    }
+    $dsn .= ';dbname=' . $connection_options['database'];
     parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
       // So we don't have to mess around with cursors and unbuffered queries by default.
       PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
diff --git a/includes/database/mysql/query.inc b/includes/database/mysql/query.inc
index cbf6dd074a15dacdc25f369ea982ed427016a3b1..70770f4a04f551977c12a5297eb10617b48a18e4 100644
--- a/includes/database/mysql/query.inc
+++ b/includes/database/mysql/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.15 2010/04/19 04:43:05 webchick Exp $
+// $Id: query.inc,v 1.17 2010/05/15 07:04:21 dries Exp $
 
 /**
  * @ingroup database
@@ -34,7 +34,7 @@ class InsertQuery_mysql extends InsertQuery {
       $values = $this->fromQuery->getArguments();
     }
 
-    $last_insert_id = $this->connection->query((string)$this, $values, $this->queryOptions);
+    $last_insert_id = $this->connection->query((string) $this, $values, $this->queryOptions);
 
     // Re-initialize the values array so that we can re-use this query.
     $this->insertValues = array();
@@ -43,6 +43,8 @@ class InsertQuery_mysql extends InsertQuery {
   }
 
   public function __toString() {
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
 
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
@@ -50,10 +52,10 @@ class InsertQuery_mysql extends InsertQuery {
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
     }
 
-    $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -138,11 +140,13 @@ class MergeQuery_mysql extends MergeQuery {
     //
     // @link http ://dev.mysql.com/doc/refman/5.0/en/mysql-affected-rows.html
     $this->queryOptions['return'] = Database::RETURN_AFFECTED;
-    return $this->connection->query((string)$this, $values, $this->queryOptions);
+    return $this->connection->query((string) $this, $values, $this->queryOptions);
   }
 
 
   public function __toString() {
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
 
     // Set defaults.
     if ($this->updateFields) {
@@ -164,7 +168,7 @@ class MergeQuery_mysql extends MergeQuery {
 
     $insert_fields = $this->insertFields + $this->keyFields;
 
-    $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES ';
+    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES ';
 
     $max_placeholder = 0;
     $values = array();
diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc
index 6c5cd9717c2386f689bfc5df132abba30dad647c..a4a2cc7b9cf60197600b992f4c606389007decb5 100644
--- a/includes/database/pgsql/database.inc
+++ b/includes/database/pgsql/database.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.36 2010/03/07 08:03:45 webchick Exp $
+// $Id: database.inc,v 1.37 2010/04/29 03:48:16 webchick Exp $
 
 /**
  * @file
@@ -90,7 +90,6 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
       }
     }
     catch (PDOException $e) {
-      _db_check_install_needed();
       if ($options['throw_exception']) {
         // Add additional debug information.
         if ($query instanceof DatabaseStatementInterface) {
diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc
index f7b323bb8aa43ef2fdcb0532f327418ce93058c6..f3b47b7ea36c0da73294d241bf51491da5f232e0 100644
--- a/includes/database/pgsql/install.inc
+++ b/includes/database/pgsql/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.6 2010/01/30 07:59:24 dries Exp $
+// $Id: install.inc,v 1.7 2010/05/13 08:23:56 dries Exp $
 
 /**
  * @file
@@ -84,14 +84,6 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
           LANGUAGE \'sql\''
         );
       }
-      db_query('CREATE OR REPLACE FUNCTION "if"(boolean, text, text) RETURNS text AS
-        \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
-        LANGUAGE \'sql\''
-      );
-      db_query('CREATE OR REPLACE FUNCTION "if"(boolean, integer, integer) RETURNS integer AS
-        \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
-        LANGUAGE \'sql\''
-      );
 
       db_query('CREATE OR REPLACE FUNCTION "substring_index"(text, text, integer) RETURNS text AS
         \'SELECT array_to_string((string_to_array($1, $2)) [1:$3], $2);\'
diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc
index 96f2122664b4fee903e9bd00469726525815df46..dd2d6345e5f6c44113f20aa80b426bafd4d60c21 100644
--- a/includes/database/pgsql/query.inc
+++ b/includes/database/pgsql/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.16 2009/09/11 02:47:11 webchick Exp $
+// $Id: query.inc,v 1.18 2010/05/15 07:04:21 dries Exp $
 
 /**
  * @ingroup database
@@ -19,7 +19,7 @@ class InsertQuery_pgsql extends InsertQuery {
       return NULL;
     }
 
-    $stmt = $this->connection->prepareQuery((string)$this);
+    $stmt = $this->connection->prepareQuery((string) $this);
 
     // Fetch the list of blobs and sequences used on that table.
     $table_information = $this->connection->schema()->queryTableInformation($this->table);
@@ -71,6 +71,8 @@ class InsertQuery_pgsql extends InsertQuery {
   }
 
   public function __toString() {
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
 
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
@@ -78,10 +80,10 @@ class InsertQuery_pgsql extends InsertQuery {
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
     }
 
-    $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -121,7 +123,7 @@ class UpdateQuery_pgsql extends UpdateQuery {
 
     // Because we filter $fields the same way here and in __toString(), the
     // placeholders will all match up properly.
-    $stmt = $this->connection->prepareQuery((string)$this);
+    $stmt = $this->connection->prepareQuery((string) $this);
 
     // Fetch the list of blobs and sequences used on that table.
     $table_information = $this->connection->schema()->queryTableInformation($this->table);
diff --git a/includes/database/prefetch.inc b/includes/database/prefetch.inc
index 4a07e784d604811ce00024e6ff8b973f7cf03b49..a314eacf0a24868a9cd5b9431e4b7a990535d54a 100644
--- a/includes/database/prefetch.inc
+++ b/includes/database/prefetch.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: prefetch.inc,v 1.8 2010/03/26 17:14:45 dries Exp $
+// $Id: prefetch.inc,v 1.10 2010/04/30 13:47:46 dries Exp $
 
 /**
  * @file
@@ -175,7 +175,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
     // as soon as possible.
     $this->rowCount = $statement->rowCount();
     $this->data = $statement->fetchAll(PDO::FETCH_ASSOC);
-    // Destroy the statement as soon as possible. See 
+    // Destroy the statement as soon as possible. See
     // DatabaseConnection_sqlite::PDOPrepare() for explanation.
     unset($statement);
 
@@ -475,8 +475,8 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
     return $result;
   }
 
-  public function fetchAllAssoc($key, $fetch_style = PDO::FETCH_OBJ) {
-    $this->fetchStyle = $fetch_style;
+  public function fetchAllAssoc($key, $fetch_style = NULL) {
+    $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
     $this->fetchOptions = $this->defaultFetchOptions;
 
     $result = array();
diff --git a/includes/database/query.inc b/includes/database/query.inc
index ead5318b6c4e7aca0cbf874587fde3ce3539048f..f8e5fdd0aee1112706bfed0cc11ec11ed39b8cf9 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.46 2010/04/19 04:43:05 webchick Exp $
+// $Id: query.inc,v 1.49 2010/05/15 07:04:21 dries Exp $
 
 /**
  * @ingroup database
@@ -21,10 +21,11 @@ interface QueryConditionInterface {
    *
    * This method can take a variable number of parameters. If called with two
    * parameters, they are taken as $field and $value with $operator having a value
-   * of =.
+   * of IN if $value is an array and = otherwise.
    *
    * @param $field
-   *   The name of the field to check.
+   *   The name of the field to check. If you would like to add a more complex
+   *   condition involving operators or functions, use where().
    * @param $value
    *   The value to test the field against. In most cases, this is a scalar. For more
    *   complex options, it is an array. The meaning of each element in the array is
@@ -239,6 +240,13 @@ abstract class Query implements QueryPlaceholderInterface {
    */
   protected $nextPlaceholder = 0;
 
+  /**
+   * An array of comments that can be prepended to a query.
+   *
+   * @var array
+   */
+  protected $comments = array();
+
   public function __construct(DatabaseConnection $connection, $options) {
     $this->connection = $connection;
     $this->queryOptions = $options;
@@ -262,6 +270,44 @@ abstract class Query implements QueryPlaceholderInterface {
   public function nextPlaceholder() {
     return $this->nextPlaceholder++;
   }
+
+  /**
+   * Adds a comment to the query.
+   *
+   * By adding a comment to a query, you can more easily find it in your
+   * query log or the list of active queries on an sql server. This allows
+   * for easier debugging and allows you to more easily find where a query
+   * with a performance problem is being generated.
+   *
+   * @param $comment
+   *   The comment string to be inserted into the query.
+   * @return Query
+   *   The called object.
+   */
+  public function comment($comment) {
+    $this->comments[] = $comment;
+    return $this;
+  }
+
+  /**
+   * Returns a reference to the comments array for the query.
+   *
+   * Because this method returns by reference, alter hooks may edit the comments
+   * array directly to make their changes. If just adding comments, however, the
+   * use of comment() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $comments =& $query->getComments();
+   * @endcode
+   *
+   * @return
+   *   A reference to the comments array structure.
+   */
+  public function &getComments() {
+    return $this->comments;
+  }
 }
 
 /**
@@ -441,7 +487,7 @@ class InsertQuery extends Query {
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      $sql = (string)$this;
+      $sql = (string) $this;
       // The SelectQuery may contain arguments, load and pass them through.
       return $this->connection->query($sql, $this->fromQuery->getArguments(), $this->queryOptions);
     }
@@ -452,7 +498,7 @@ class InsertQuery extends Query {
     // we wrap it in a transaction so that it is atomic where possible. On many
     // databases, such as SQLite, this is also a notable performance boost.
     $transaction = $this->connection->startTransaction();
-    $sql = (string)$this;
+    $sql = (string) $this;
     foreach ($this->insertValues as $insert_values) {
       $last_insert_id = $this->connection->query($sql, $insert_values, $this->queryOptions);
     }
@@ -467,11 +513,14 @@ class InsertQuery extends Query {
 
   public function __toString() {
 
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
     if (!empty($this->fromQuery)) {
-      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
     }
 
     // For simplicity, we will use the $placeholders array to inject
@@ -481,7 +530,7 @@ class InsertQuery extends Query {
     $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
     $placeholders = array_pad($placeholders, count($this->insertFields), '?');
 
-    return 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', $placeholders) . ')';
+    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', $placeholders) . ')';
   }
 
   /**
@@ -779,7 +828,7 @@ class MergeQuery extends Query {
     }
 
     $select = $select->countQuery();
-    $sql = (string)$select;
+    $sql = (string) $select;
     $arguments = $select->getArguments();
     $num_existing = $this->connection->query($sql, $arguments)->fetchField();
 
@@ -895,11 +944,15 @@ class DeleteQuery extends Query implements QueryConditionInterface {
       $values = $this->condition->arguments();
     }
 
-    return $this->connection->query((string)$this, $values, $this->queryOptions);
+    return $this->connection->query((string) $this, $values, $this->queryOptions);
   }
 
   public function __toString() {
-    $query = 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
+
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
+    $query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
 
     if (count($this->condition)) {
 
@@ -935,11 +988,14 @@ class TruncateQuery extends Query {
   }
 
   public function execute() {
-    return $this->connection->query((string)$this, array(), $this->queryOptions);
+    return $this->connection->query((string) $this, array(), $this->queryOptions);
   }
 
   public function __toString() {
-    return 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
+    return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
   }
 }
 
@@ -1095,10 +1151,14 @@ class UpdateQuery extends Query implements QueryConditionInterface {
       $update_values = array_merge($update_values, $this->condition->arguments());
     }
 
-    return $this->connection->query((string)$this, $update_values, $this->queryOptions);
+    return $this->connection->query((string) $this, $update_values, $this->queryOptions);
   }
 
   public function __toString() {
+
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
     // Expressions take priority over literal fields, so we process those first
     // and remove any literal fields that conflict.
     $fields = $this->fields;
@@ -1113,7 +1173,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
       $update_fields[] = $field . '=:db_update_placeholder_' . ($max_placeholder++);
     }
 
-    $query = 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
+    $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
 
     if (count($this->condition)) {
       $this->condition->compile($this->connection, $this);
@@ -1217,7 +1277,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
           if ($condition['field'] instanceof QueryConditionInterface) {
             // Compile the sub-condition recursively and add it to the list.
             $condition['field']->compile($connection, $queryPlaceholder);
-            $condition_fragments[] = '(' . (string)$condition['field'] . ')';
+            $condition_fragments[] = '(' . (string) $condition['field'] . ')';
             $arguments += $condition['field']->arguments();
           }
           else {
@@ -1239,7 +1299,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
             $placeholders = array();
             if ($condition['value'] instanceof SelectQueryInterface) {
               $condition['value']->compile($connection, $queryPlaceholder);
-              $placeholders[] = (string)$condition['value'];
+              $placeholders[] = (string) $condition['value'];
               $arguments += $condition['value']->arguments();
             }
             // We assume that if there is a delimiter, then the value is an
@@ -1255,7 +1315,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
                 $placeholders[] = $placeholder;
               }
             }
-            $condition_fragments[] = ' (' . $condition['field'] . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
+            $condition_fragments[] = ' (' . $connection->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
           }
         }
       }
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index 012b74afa4cf0c209d021fc863fda4327a534cce..8f3b80679f3af3071df8d712aba8c56e33e97a22 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.inc,v 1.34 2010/04/07 15:07:59 dries Exp $
+// $Id: schema.inc,v 1.35 2010/04/28 20:25:21 dries Exp $
 
 /**
  * @file
@@ -604,9 +604,9 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
     if ($this->tableExists($name)) {
       throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
     }
-  	$statements = $this->createTableSql($name, $table);
+    $statements = $this->createTableSql($name, $table);
     foreach ($statements as $statement) {
-    	$this->connection->query($statement);
+      $this->connection->query($statement);
     }
   }
 
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 61c85c68d0a2ea08f6c9bc9d611a2daa3bfc6000..6e2954175e06f9dc0d182b1995aaee78e7226361 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: select.inc,v 1.35 2010/04/11 18:33:43 dries Exp $
+// $Id: select.inc,v 1.41 2010/05/15 07:04:21 dries Exp $
 
 /**
  * @ingroup database
@@ -232,7 +232,9 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    *   this clause should use a named placeholder and the value or values to
    *   insert should be passed in the 4th parameter. For the first table joined
    *   on a query, this value is ignored as the first table is taken as the base
-   *   table.
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
    * @param $arguments
    *   An array of arguments to replace into the $condition of this join.
    * @return
@@ -253,7 +255,9 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    *   this clause should use a named placeholder and the value or values to
    *   insert should be passed in the 4th parameter. For the first table joined
    *   on a query, this value is ignored as the first table is taken as the base
-   *   table.
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
    * @param $arguments
    *   An array of arguments to replace into the $condition of this join.
    * @return
@@ -274,7 +278,9 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    *   this clause should use a named placeholder and the value or values to
    *   insert should be passed in the 4th parameter. For the first table joined
    *   on a query, this value is ignored as the first table is taken as the base
-   *   table.
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
    * @param $arguments
    *   An array of arguments to replace into the $condition of this join.
    * @return
@@ -295,7 +301,9 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    *   this clause should use a named placeholder and the value or values to
    *   insert should be passed in the 4th parameter. For the first table joined
    *   on a query, this value is ignored as the first table is taken as the base
-   *   table.
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
    * @param $arguments
    *   An array of arguments to replace into the $condition of this join.
    * @return
@@ -324,7 +332,9 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    *   this clause should use a named placeholder and the value or values to
    *   insert should be passed in the 4th parameter. For the first table joined
    *   on a query, this value is ignored as the first table is taken as the base
-   *   table.
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
    * @param $arguments
    *   An array of arguments to replace into the $condition of this join.
    * @return
@@ -444,6 +454,29 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
    */
   public function preExecute(SelectQueryInterface $query = NULL);
 
+  /**
+   * Helper function to build most common HAVING conditional clauses.
+   *
+   * This method can take a variable number of parameters. If called with two
+   * parameters, they are taken as $field and $value with $operator having a value
+   * of IN if $value is an array and = otherwise.
+   *
+   * @param $field
+   *   The name of the field to check. If you would like to add a more complex
+   *   condition involving operators or functions, use having().
+   * @param $value
+   *   The value to test the field against. In most cases, this is a scalar. For more
+   *   complex options, it is an array. The meaning of each element in the array is
+   *   dependent on the $operator.
+   * @param $operator
+   *   The comparison operator, such as =, <, or >=. It also accepts more complex
+   *   options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
+   *   = otherwise.
+   * @return QueryConditionInterface
+   *   The called object.
+   */
+  public function havingCondition($field, $value = NULL, $operator = NULL);
+
   /**
    * Clone magic method.
    *
@@ -727,7 +760,7 @@ class SelectQueryExtender implements SelectQueryInterface {
   }
 
   public function __toString() {
-    return (string)$this->query;
+    return (string) $this->query;
   }
 
   public function __clone() {
@@ -906,10 +939,7 @@ class SelectQuery extends Query implements SelectQueryInterface {
   /* Implementations of QueryConditionInterface for the WHERE clause. */
 
   public function condition($field, $value = NULL, $operator = NULL) {
-    if (!isset($num_args)) {
-      $num_args = func_num_args();
-    }
-    $this->where->condition($field, $value, $operator, $num_args);
+    $this->where->condition($field, $value, $operator);
     return $this;
   }
 
@@ -942,11 +972,8 @@ class SelectQuery extends Query implements SelectQueryInterface {
 
   /* Implementations of QueryConditionInterface for the HAVING clause. */
 
-  public function havingCondition($field, $value = NULL, $operator = '=') {
-    if (!isset($num_args)) {
-      $num_args = func_num_args();
-    }
-    $this->having->condition($field, $value, $operator, $num_args);
+  public function havingCondition($field, $value = NULL, $operator = NULL) {
+    $this->having->condition($field, $value, $operator);
     return $this;
   }
 
@@ -1069,10 +1096,11 @@ class SelectQuery extends Query implements SelectQueryInterface {
 
     // Modules may alter all queries or only those having a particular tag.
     if (isset($this->alterTags)) {
-      drupal_alter('query', $query);
+      $hooks = array('query');
       foreach ($this->alterTags as $tag => $value) {
-        drupal_alter("query_$tag", $query);
+        $hooks[] = 'query_' . $tag;
       }
+      drupal_alter($hooks, $query);
     }
     return $this->prepared = TRUE;
   }
@@ -1085,7 +1113,7 @@ class SelectQuery extends Query implements SelectQueryInterface {
     }
 
     $args = $this->getArguments();
-    return $this->connection->query((string)$this, $args, $this->queryOptions);
+    return $this->connection->query((string) $this, $args, $this->queryOptions);
   }
 
   public function distinct($distinct = TRUE) {
@@ -1192,6 +1220,10 @@ class SelectQuery extends Query implements SelectQueryInterface {
     }
     $alias = $alias_candidate;
 
+    if (is_string($condition)) {
+      $condition = str_replace('%alias', $alias, $condition);
+    }
+
     $this->tables[$alias] = array(
       'join type' => $type,
       'table' => $table,
@@ -1285,8 +1317,11 @@ class SelectQuery extends Query implements SelectQueryInterface {
 
   public function __toString() {
 
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
     // SELECT
-    $query = 'SELECT ';
+    $query = $comments . 'SELECT ';
     if ($this->distinct) {
       $query .= 'DISTINCT ';
     }
@@ -1295,13 +1330,13 @@ class SelectQuery extends Query implements SelectQueryInterface {
     $fields = array();
     foreach ($this->tables as $alias => $table) {
       if (!empty($table['all_fields'])) {
-        $fields[] = $alias . '.*';
+        $fields[] = $this->connection->escapeTable($alias) . '.*';
       }
     }
     foreach ($this->fields as $alias => $field) {
       // Always use the AS keyword for field aliases, as some
       // databases require it (e.g., PostgreSQL).
-      $fields[] = (isset($field['table']) ? $field['table'] . '.' : '') . $field['field'] . ' AS ' . $field['alias'];
+      $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeField($field['alias']);
     }
     foreach ($this->expressions as $alias => $expression) {
       $fields[] = $expression['expression'] . ' AS ' . $expression['alias'];
@@ -1319,7 +1354,10 @@ class SelectQuery extends Query implements SelectQueryInterface {
 
       // If the table is a subquery, compile it and integrate it into this query.
       if ($table['table'] instanceof SelectQueryInterface) {
-        $table_string = '(' . (string)$table['table'] . ')';
+        // Run preparation steps on this sub-query before converting to string.
+        $subquery = $table['table'];
+        $subquery->preExecute();
+        $table_string = '(' . (string) $subquery . ')';
       }
       else {
         $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
@@ -1327,7 +1365,7 @@ class SelectQuery extends Query implements SelectQueryInterface {
 
       // Don't use the AS keyword for table aliases, as some
       // databases don't support it (e.g., Oracle).
-      $query .=  $table_string . ' ' . $table['alias'];
+      $query .=  $table_string . ' ' . $this->connection->escapeTable($table['alias']);
 
       if (!empty($table['condition'])) {
         $query .= ' ON ' . $table['condition'];
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index d2ced9f625f3ad212b342a8d2952f6853e410edb..8be26c1487154595b8290ae074cd2476d0f88e1c 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.9 2009/11/02 00:19:27 webchick Exp $
+// $Id: query.inc,v 1.10 2010/05/15 07:04:21 dries Exp $
 
 /**
  * @file
@@ -33,16 +33,19 @@ class InsertQuery_sqlite extends InsertQuery {
   }
 
   public function __toString() {
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
     // Produce as many generic placeholders as necessary.
     $placeholders = array_fill(0, count($this->insertFields), '?');
 
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
     }
 
-    return 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
+    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
   }
 
 }
@@ -143,7 +146,10 @@ class DeleteQuery_sqlite extends DeleteQuery {
  */
 class TruncateQuery_sqlite extends TruncateQuery {
   public function __toString() {
-    return 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
+    return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
   }
 }
 
diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc
index 515fc6aff17efbff7054e5e2a6662418be23b2c9..432ebd1e7886e85bd369cf4f0a083f8571da75dd 100644
--- a/includes/database/sqlite/schema.inc
+++ b/includes/database/sqlite/schema.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.inc,v 1.16 2010/04/07 15:07:59 dries Exp $
+// $Id: schema.inc,v 1.17 2010/04/28 20:25:21 dries Exp $
 
 /**
  * @file
@@ -14,7 +14,7 @@
 
 class DatabaseSchema_sqlite extends DatabaseSchema {
 
-	/**
+  /**
    * Override DatabaseSchema::$defaultSchema
    */
   protected $defaultSchema = 'main';
diff --git a/includes/entity.inc b/includes/entity.inc
index 7c1ddf6738dcb2d8c7f269a4941c30a2d60a462e..159c04e012a82a5a21bce54e6e1a52628064bc9c 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: entity.inc,v 1.7 2010/03/27 05:52:49 webchick Exp $
+// $Id: entity.inc,v 1.8 2010/05/09 13:27:31 dries Exp $
 
 /**
  * Interface for entity controller classes.
@@ -188,14 +188,6 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
       // The id field is provided by entity, so remove it.
       unset($entity_revision_fields[$this->idKey]);
 
-      // Change timestamp to revision_timestamp, and revision uid to
-      // revision_uid before adding them to the query.
-      // TODO: This is node specific and has to be moved into NodeController.
-      unset($entity_revision_fields['timestamp']);
-      $query->addField('revision', 'timestamp', 'revision_timestamp');
-      unset($entity_revision_fields['uid']);
-      $query->addField('revision', 'uid', 'revision_uid');
-
       // Remove all fields from the base table that are also fields by the same
       // name in the revision table.
       $entity_field_keys = array_flip($entity_fields);
diff --git a/includes/file.inc b/includes/file.inc
index 3e4ec953a3f60bf9e16deb88abedb398d9e9f208..cef2b1500f99a1950b4b2cfcd04bfb3c910aecaa 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.inc,v 1.207 2010/04/10 17:30:15 dries Exp $
+// $Id: file.inc,v 1.209 2010/05/11 10:56:04 dries Exp $
 
 /**
  * @file
@@ -343,9 +343,21 @@ function file_create_url($uri) {
   $scheme = file_uri_scheme($uri);
 
   if (!$scheme) {
-    // If this is not a properly formatted stream, then it is a shipped file.
-    // Therefor, return the URI with the base URL prepended.
-    return $GLOBALS['base_url'] . '/' . $uri;
+    // Allow for:
+    // - root-relative URIs (e.g. /foo.jpg in http://example.com/foo.jpg)
+    // - protocol-relative URIs (e.g. //bar.jpg, which is expanded to
+    //   http://example.com/bar.jpg by the browser when viewing a page over
+    //   HTTP and to https://example.com/bar.jpg when viewing a HTTPS page)
+    // Both types of relative URIs are characterized by a leading slash, hence
+    // we can use a single check.
+    if (drupal_substr($uri, 0, 1) == '/') {
+      return $uri;
+    }
+    else {
+      // If this is not a properly formatted stream, then it is a shipped file.
+      // Therefor, return the URI with the base URL prepended.
+      return $GLOBALS['base_url'] . '/' . $uri;
+    }
   }
   elseif ($scheme == 'http' || $scheme == 'https') {
     // Check for http so that we don't have to implement getExternalUrl() for
@@ -409,7 +421,9 @@ function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS)
  */
 function file_ensure_htaccess() {
   file_create_htaccess('public://', FALSE);
-  file_create_htaccess('private://', TRUE);
+  if (variable_get('file_private_path', FALSE)) {
+    file_create_htaccess('private://', TRUE);
+  }
   file_create_htaccess('temporary://', TRUE);
 }
 
@@ -1586,8 +1600,7 @@ function file_download() {
   $scheme = array_shift($args);
   $target = implode('/', $args);
   $uri = $scheme . '://' . $target;
-
-  if (file_exists($uri)) {
+  if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
     // Let other modules provide headers and controls access to the file.
     $headers = module_invoke_all('file_download', $uri);
     if (in_array(-1, $headers)) {
diff --git a/includes/form.inc b/includes/form.inc
index a57d7ba873679933474bf0259825fcf7bfff1441..21008c0c9061c729b4aced3aa3c0d67d6e8c436c 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: form.inc,v 1.454 2010/04/24 14:49:13 dries Exp $
+// $Id: form.inc,v 1.464 2010/05/19 19:22:24 dries Exp $
 
 /**
  * @defgroup forms Form builder functions
@@ -203,7 +203,7 @@ function drupal_build_form($form_id, &$form_state) {
       }
 
       $form = drupal_retrieve_form($form_id, $form_state);
-      $form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
+      $form_build_id = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
       $form['#build_id'] = $form_build_id;
 
       // Fix the form method, if it is 'get' in $form_state, but not in $form.
@@ -331,7 +331,7 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
   // Otherwise, a new #build_id is generated, to not clobber the previous
   // build's data in the form cache; also allowing the user to go back to an
   // earlier build, make changes, and re-submit.
-  $form['#build_id'] = isset($old_form['#build_id']) ? $old_form['#build_id'] : 'form-' . md5(mt_rand());
+  $form['#build_id'] = isset($old_form['#build_id']) ? $old_form['#build_id'] : 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
 
   // #action defaults to request_uri(), but in case of AJAX and other partial
   // rebuilds, the form is submitted to an alternate URL, and the original
@@ -491,7 +491,7 @@ function form_state_keys_no_cache() {
  * $form_state['values']['body'] = 'This is the body text!';
  * $form_state['values']['name'] = 'robo-user';
  * $form_state['values']['op'] = t('Save');
- * drupal_form_submit('story_node_form', $form_state, (object)$node);
+ * drupal_form_submit('story_node_form', $form_state, (object) $node);
  * @endcode
  */
 function drupal_form_submit($form_id, &$form_state) {
@@ -651,7 +651,7 @@ function drupal_process_form($form_id, &$form, &$form_state) {
       // We'll clear out the cached copies of the form and its stored data
       // here, as we've finished with them. The in-memory copies are still
       // here, though.
-      if (variable_get('cache', CACHE_DISABLED) == CACHE_DISABLED && !empty($form_state['values']['form_build_id'])) {
+      if (!variable_get('cache', 0) && !empty($form_state['values']['form_build_id'])) {
         cache_clear_all('form_' . $form_state['values']['form_build_id'], 'cache_form');
         cache_clear_all('storage_' . $form_state['values']['form_build_id'], 'cache_form');
       }
@@ -774,11 +774,8 @@ function drupal_prepare_form($form_id, &$form, &$form_state) {
     }
   }
 
-  // Invoke hook_form_FORM_ID_alter() implementations.
-  drupal_alter('form_' . $form_id, $form, $form_state);
-
-  // Invoke hook_form_alter() implementations.
-  drupal_alter('form', $form, $form_state, $form_id);
+  // Invoke hook_form_alter() and hook_form_FORM_ID_alter() implementations.
+  drupal_alter(array('form', 'form_' . $form_id), $form, $form_state, $form_id);
 }
 
 
@@ -1294,6 +1291,13 @@ function form_builder($form_id, $element, &$form_state) {
   // Recurse through all child elements.
   $count = 0;
   foreach (element_children($element) as $key) {
+    // Prior to checking properties of child elements, their default properties
+    // need to be loaded.
+    if (isset($element[$key]['#type']) && empty($element[$key]['#defaults_loaded']) && ($info = element_info($element[$key]['#type']))) {
+      $element[$key] += $info;
+      $element[$key]['#defaults_loaded'] = TRUE;
+    }
+
     // Don't squash an existing tree value.
     if (!isset($element[$key]['#tree'])) {
       $element[$key]['#tree'] = $element['#tree'];
@@ -1315,12 +1319,6 @@ function form_builder($form_id, $element, &$form_state) {
     $array_parents[] = $key;
     $element[$key]['#array_parents'] = $array_parents;
 
-    // Prior to handling #weight, default element properties need to be applied.
-    if (isset($element[$key]['#type']) && empty($element[$key]['#defaults_loaded']) && ($info = element_info($element[$key]['#type']))) {
-      $element[$key] += $info;
-      $element[$key]['#defaults_loaded'] = TRUE;
-    }
-
     // Assign a decimal placeholder weight to preserve original array order.
     if (!isset($element[$key]['#weight'])) {
       $element[$key]['#weight'] = $count/1000;
@@ -1869,7 +1867,7 @@ function form_type_textfield_value($element, $input = FALSE) {
  */
 function form_type_token_value($element, $input = FALSE) {
   if ($input !== FALSE) {
-    return (string)$input;
+    return (string) $input;
   }
 }
 
@@ -2001,8 +1999,8 @@ function form_select_options($element, $choices = NULL) {
       $options .= form_select_options($element, $choice->option);
     }
     else {
-      $key = (string)$key;
-      if ($value_valid && (!$value_is_array && (string)$element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
+      $key = (string) $key;
+      if ($value_valid && (!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
         $selected = ' selected="selected"';
       }
       else {
@@ -2177,8 +2175,8 @@ function form_process_password_confirm($element) {
  */
 function password_confirm_validate($element, &$element_state) {
   $pass1 = trim($element['pass1']['#value']);
-  if (!empty($pass1)) {
-    $pass2 = trim($element['pass2']['#value']);
+  $pass2 = trim($element['pass2']['#value']);
+  if (!empty($pass1) || !empty($pass2)) {
     if (strcmp($pass1, $pass2)) {
       form_error($element, t('The specified passwords do not match.'));
     }
@@ -2544,8 +2542,10 @@ function theme_tableselect($variables) {
     }
     // Add an empty header or a "Select all" checkbox to provide room for the
     // checkboxes/radios in the first table column.
-    $first_col = $element['#js_select'] ? array(theme('table_select_header_cell')) : array('');
-    $header = array_merge($first_col, $header);
+    if ($element['#js_select']) {
+      drupal_add_js('misc/tableselect.js');
+      array_unshift($header, array('class' => array('select-all')));
+    }
   }
   return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => $element['#empty'], 'attributes' => $element['#attributes']));
 }
@@ -2652,13 +2652,16 @@ function form_process_fieldset(&$element, &$form_state) {
   // Contains form element summary functionalities.
   $element['#attached']['js']['misc/form.js'] = array('weight' => JS_LIBRARY + 1);
 
+  // The .form-wrapper class is required for #states to treat fieldsets like
+  // containers.
+  if (!isset($element['#attributes']['class'])) {
+    $element['#attributes']['class'] = array();
+  }
+  $element['#attributes']['class'][] = 'form-wrapper';
+
   // Collapsible fieldsets
   if (!empty($element['#collapsible'])) {
     $element['#attached']['js'][] = 'misc/collapse.js';
-    if (!isset($element['#attributes']['class'])) {
-      $element['#attributes']['class'] = array();
-    }
-    $element['#attributes']['class'][] = 'form-wrapper';
     $element['#attributes']['class'][] = 'collapsible';
     if (!empty($element['#collapsed'])) {
       $element['#attributes']['class'][] = 'collapsed';
@@ -3029,49 +3032,46 @@ function theme_form_element($variables) {
   // This is also used in the installer, pre-database setup.
   $t = get_t();
 
+  // Add element #id for #type 'item'.
+  if (isset($element['#markup']) && !empty($element['#id'])) {
+    $attributes['id'] = $element['#id'];
+  }
   // Add element's #type and #name as class to aid with JS/CSS selectors.
-  $class = array('form-item');
+  $attributes['class'] = array('form-item');
   if (!empty($element['#type'])) {
-    $class[] = 'form-type-' . strtr($element['#type'], '_', '-');
+    $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
   }
   if (!empty($element['#name'])) {
-    $class[] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
+    $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
   }
+  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";
 
   // If #title is not set, we don't display any label or required marker.
   if (!isset($element['#title'])) {
     $element['#title_display'] = 'none';
   }
-
-  $output = '<div class="' . implode(' ', $class) . '">' . "\n";
-
-  if (isset($element['#field_prefix'])) {
-    $output .= '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ';
-  }
+  $prefix = isset($element['#field_prefix']) ? '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ' : '';
+  $suffix = isset($element['#field_suffix']) ? ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>' : '';
 
   switch ($element['#title_display']) {
     case 'before':
       $output .= ' ' . theme('form_element_label', $variables);
-      $output .= ' ' . $element['#children'] . "\n";
+      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
       break;
 
     case 'invisible':
     case 'after':
-      $output .= ' ' . $element['#children'];
+      $output .= ' ' . $prefix . $element['#children'] . $suffix;
       $output .= ' ' . theme('form_element_label', $variables) . "\n";
       break;
 
     case 'none':
     case 'attribute':
       // Output no label and no required marker, only the children.
-      $output .= ' ' . $element['#children'] . "\n";
+      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
       break;
   }
 
-  if (isset($element['#field_suffix'])) {
-    $output .= ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>';
-  }
-
   if (!empty($element['#description'])) {
     $output .= ' <div class="description">' . $element['#description'] . "</div>\n";
   }
diff --git a/includes/install.core.inc b/includes/install.core.inc
index 6fed3728dc6b4dcc06b95e560350f75df2597ee2..5fb86f6673089eb46193272630288520fe4ea72d 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.core.inc,v 1.13 2010/04/24 14:49:13 dries Exp $
+// $Id: install.core.inc,v 1.19 2010/05/18 18:11:13 dries Exp $
 
 /**
  * @file
@@ -1011,7 +1011,7 @@ function install_settings_form_submit($form, &$form_state) {
     'required' => TRUE,
   );
   $settings['drupal_hash_salt'] = array(
-    'value'    => sha1(drupal_random_bytes(64)),
+    'value'    => drupal_hash_base64(drupal_random_bytes(55)),
     'required' => TRUE,
   );
   drupal_rewrite_settings($settings);
@@ -1082,7 +1082,7 @@ function _install_select_profile($profiles) {
   if (sizeof($profiles) == 1) {
     $profile = array_pop($profiles);
     // TODO: is this right?
-    require_once $profile->uri;
+    require_once DRUPAL_ROOT . '/' . $profile->uri;
     return $profile->name;
   }
   else {
@@ -1332,11 +1332,7 @@ function install_load_profile(&$install_state) {
  *   An array of information about the current installation state.
  */
 function install_bootstrap_full(&$install_state) {
-  // Bootstrap newly installed Drupal, while preserving existing messages.
-  $messages = isset($_SESSION['messages']) ? $_SESSION['messages'] : '';
-
   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-  $_SESSION['messages'] = $messages;
 }
 
 /**
@@ -1479,11 +1475,6 @@ function install_finished(&$install_state) {
   $output = '<p>' . st('Congratulations, you installed @drupal!', array('@drupal' => drupal_install_profile_distribution_name())) . '</p>';
   $output .= '<p>' . (isset($messages['error']) ? st('Review the messages above before visiting <a href="@url">your new site</a>.', array('@url' => url(''))) : st('<a href="@url">Visit your new site</a>.', array('@url' => url('')))) . '</p>';
 
-  // Rebuild the module and theme data, in case any newly-installed modules
-  // need to modify it via hook_system_info_alter().
-  system_rebuild_module_data();
-  system_rebuild_theme_data();
-
   // Flush all caches to ensure that any full bootstraps during the installer
   // do not leave stale cached data, and that any content types or other items
   // registered by the install profile are registered correctly.
@@ -1736,21 +1727,13 @@ function install_configure_form_submit($form, &$form_state) {
     }
   }
 
-  // Turn this off temporarily so that we can pass a password through.
-  variable_set('user_email_verification', FALSE);
-  $form_state['old_values'] = $form_state['values'];
-  $form_state['values'] = $form_state['values']['account'];
-
   // We precreated user 1 with placeholder values. Let's save the real values.
   $account = user_load(1);
-  $merge_data = array('init' => $form_state['values']['mail'], 'roles' => array(), 'status' => 1);
-  user_save($account, array_merge($form_state['values'], $merge_data));
+  $merge_data = array('init' => $form_state['values']['account']['mail'], 'roles' => !empty($account->roles) ? $account->roles : array(), 'status' => 1);
+  user_save($account, array_merge($form_state['values']['account'], $merge_data));
   // Load global $user and perform final login tasks.
   $user = user_load(1);
   user_login_finalize();
-  $form_state['values'] = $form_state['old_values'];
-  unset($form_state['old_values']);
-  variable_set('user_email_verification', TRUE);
 
   if (isset($form_state['values']['clean_url'])) {
     variable_set('clean_url', $form_state['values']['clean_url']);
diff --git a/includes/install.inc b/includes/install.inc
index a88d05c179314391b6fd53192030fb6108463abf..9095e8e76ba31fc3d30468430116620d7fc11279 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.132 2010/04/24 14:53:59 dries Exp $
+// $Id: install.inc,v 1.135 2010/05/18 18:11:13 dries Exp $
 
 /**
  * Indicates that a module has not been installed yet.
@@ -367,7 +367,7 @@ abstract class DatabaseTasks {
       }
     }
     if (!empty($message)) {
-      $message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
+      $message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
       throw new DatabaseTaskException($message);
     }
   }
@@ -384,7 +384,7 @@ abstract class DatabaseTasks {
       $this->pass('Drupal can CONNECT to the database ok.');
     }
     catch (Exception $e) {
-      $this->fail(st('Failed to connect to your %name database server. %name reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage(), '%name' => $this->name())));
+      $this->fail(st('Failed to connect to your %name database server. %name reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li></ul>For more help, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage(), '%name' => $this->name())));
       return FALSE;
     }
     return TRUE;
@@ -547,7 +547,7 @@ function drupal_verify_profile($install_state) {
  * functions can be made available while other modules are installed.
  */
 function drupal_install_system() {
-  $system_path = dirname(drupal_get_filename('module', 'system', NULL));
+  $system_path = drupal_get_path('module', 'system');
   require_once DRUPAL_ROOT . '/' . $system_path . '/system.install';
   module_invoke('system', 'install');
 
@@ -849,10 +849,14 @@ function install_goto($path) {
  * @see t()
  * @ingroup sanitization
  */
-function st($string, $args = array()) {
+function st($string, array $args = array(), array $options = array()) {
   static $locale_strings = NULL;
   global $install_state;
 
+  if (empty($options['context'])) {
+    $options['context'] = '';
+  }
+
   if (!isset($locale_strings)) {
     $locale_strings = array();
     if (isset($install_state['parameters']['profile']) && isset($install_state['parameters']['locale'])) {
@@ -883,7 +887,7 @@ function st($string, $args = array()) {
       case '!':
     }
   }
-  return strtr((!empty($locale_strings[$string]) ? $locale_strings[$string] : $string), $args);
+  return strtr((!empty($locale_strings[$options['context']][$string]) ? $locale_strings[$options['context']][$string] : $string), $args);
 }
 
 /**
diff --git a/includes/iso.inc b/includes/iso.inc
index 6b5baf0d75482b0de93d4816a41475c9d608e8cf..9af86391d5b49c6c568f69c401939823c50ada54 100644
--- a/includes/iso.inc
+++ b/includes/iso.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: iso.inc,v 1.9 2010/04/17 12:55:08 dries Exp $
+// $Id: iso.inc,v 1.10 2010/04/30 08:15:56 dries Exp $
 
 /**
  * @file
@@ -376,7 +376,7 @@ function _locale_get_predefined_list() {
     'ku' => array('Kurdish', 'Kurdî'),
     'kv' => array('Komi'),
     'kw' => array('Cornish'),
-    'ky' => array('Kyrgyz', 'Кыргыз тили'),
+    'ky' => array('Kyrgyz', 'Кыргызча'),
     'la' => array('Latin', 'Latina'),
     'lb' => array('Luxembourgish'),
     'lg' => array('Luganda'),
diff --git a/includes/language.inc b/includes/language.inc
index 1b55a18c6019f3c87c5749fababafef89182b539..61bbbd76c9261d9ae365fb9180885cc60f624b44 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: language.inc,v 1.29 2010/03/10 19:36:14 webchick Exp $
+// $Id: language.inc,v 1.30 2010/05/12 08:26:14 dries Exp $
 
 /**
  * @file
@@ -283,7 +283,7 @@ function language_provider_invoke($provider_id, $provider = NULL) {
 
     // If the language provider has no cache preference or this is satisfied
     // we can execute the callback.
-    $cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', CACHE_DISABLED);
+    $cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
     $callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
     $langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
     $results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
diff --git a/includes/locale.inc b/includes/locale.inc
index b5fe671de51ad191a2f9ae814a28744c774e0fd8..a9c8281b524cc91c6b467d2a13499131ada2bf65 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.inc,v 1.251 2010/04/09 12:14:25 dries Exp $
+// $Id: locale.inc,v 1.254 2010/05/01 08:12:22 dries Exp $
 
 /**
  * @file
@@ -683,7 +683,7 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
         $languages = language_list();
         if (($mode != LOCALE_IMPORT_KEEP) || empty($languages[$lang]->plurals)) {
           // Since we only need to parse the header if we ought to update the
-          // plural formula, only run this if we don't need to keep existing 
+          // plural formula, only run this if we don't need to keep existing
           // data untouched or if we don't have an existing plural formula.
           $header = _locale_import_parse_header($value['msgstr']);
 
@@ -1391,7 +1391,7 @@ function _locale_export_po($language = NULL, $output = NULL) {
   header("Content-Disposition: attachment; filename=$filename");
   header("Content-Type: text/plain; charset=utf-8");
   print $output;
-  exit();
+  drupal_exit();
 }
 
 /**
@@ -1680,7 +1680,7 @@ function _locale_rebuild_js($langcode = NULL) {
     }
 
     $data .= "'strings': " . drupal_json_encode($translations) . " };";
-    $data_hash = md5($data);
+    $data_hash = drupal_hash_base64($data);
   }
 
   // Construct the filepath where JS translation files are stored.
diff --git a/includes/lock.inc b/includes/lock.inc
index c927a97f2ecc2a2f72e2d780a06ca1718e38a94c..fe856e97f96477120d90a7a69facb15d80db4f3a 100644
--- a/includes/lock.inc
+++ b/includes/lock.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: lock.inc,v 1.3 2010/02/24 19:59:32 dries Exp $
+// $Id: lock.inc,v 1.4 2010/05/06 15:20:18 dries Exp $
 
 /**
  * @file
@@ -18,7 +18,7 @@
  *
  * This is a cooperative, advisory lock system. Any long-running operation
  * that could potentially be attempted in parallel by multiple requests should
- * try to acquire a lock before proceeding. By obtainng a lock, one request
+ * try to acquire a lock before proceeding. By obtaining a lock, one request
  * notifies any other requests that a specific operation is in progress which
  * must not be executed in parallel.
  *
diff --git a/includes/mail.inc b/includes/mail.inc
index 3fefa09fca58ae4a6c8f485826548da730adf79a..e10bee72f7e26164acff30373f9e898408919ebe 100644
--- a/includes/mail.inc
+++ b/includes/mail.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: mail.inc,v 1.30 2010/01/09 23:03:21 webchick Exp $
+// $Id: mail.inc,v 1.31 2010/05/04 15:11:21 dries Exp $
 
 /**
  * @file
@@ -575,7 +575,7 @@ function _drupal_html_to_text_pad($text, $pad, $prefix = '') {
   if (($p = strrpos($text, "\n")) === FALSE) {
     $p = -1;
   }
-  $n = max(0, 79 - (strlen($text) - $p));
+  $n = max(0, 79 - (strlen($text) - $p) - strlen($prefix));
   // Add prefix and padding, and restore linebreak.
-  return $text . $prefix . str_repeat($pad, $n - strlen($prefix)) . "\n";
+  return $text . $prefix . str_repeat($pad, $n) . "\n";
 }
diff --git a/includes/menu.inc b/includes/menu.inc
index 975a162e9ffef342c150ef6cf05d530bfd349e02..ce945481ce79d59a327895fe7a66bc3bee66589e 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.inc,v 1.387 2010/04/26 14:06:23 dries Exp $
+// $Id: menu.inc,v 1.392 2010/05/17 18:47:25 dries Exp $
 
 /**
  * @file
@@ -407,9 +407,9 @@ function menu_get_item($path = NULL, $router_item = NULL) {
     $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
     $ancestors = menu_get_ancestors($parts);
 
-    // Since there is no limit to the length of $path, but the cids are
-    // restricted to 255 characters, use md5() to keep it short yet unique.
-    $cid = 'menu_item:' . md5($path);
+    // Since there is no limit to the length of $path, use a hash to keep it
+    // short yet unique.
+    $cid = 'menu_item:' . hash('sha256', $path);
     if ($cached = cache_get($cid, 'cache_menu')) {
       $router_item = $cached->data;
     }
@@ -574,7 +574,7 @@ function _menu_check_access(&$item, $map) {
   $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
   // Check for a TRUE or FALSE value.
   if (is_numeric($callback)) {
-    $item['access'] = (bool)$callback;
+    $item['access'] = (bool) $callback;
   }
   else {
     $arguments = menu_unserialize($item['access_arguments'], $map);
@@ -978,7 +978,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
   // Use $mlid as a flag for whether the data being loaded is for the whole tree.
   $mlid = isset($link['mlid']) ? $link['mlid'] : 0;
   // Generate a cache ID (cid) specific for this $menu_name, $link, $language, and depth.
-  $cid = 'links:' . $menu_name . ':all-cid:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int)$max_depth;
+  $cid = 'links:' . $menu_name . ':all-cid:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int) $max_depth;
 
   if (!isset($tree[$cid])) {
     // If the static variable doesn't have the data, check {cache_menu}.
@@ -1090,7 +1090,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
       $max_depth = min($max_depth, MENU_MAX_DEPTH);
     }
     // Generate a cache ID (cid) specific for this page.
-    $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int)$item['access'] . ':' . (int)$max_depth;
+    $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth;
 
     if (!isset($tree[$cid])) {
       // If the static variable doesn't have the data, check {cache_menu}.
@@ -1238,7 +1238,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
  * Helper function - compute the real cache ID for menu tree data.
  */
 function _menu_tree_cid($menu_name, $data) {
-  return 'links:' . $menu_name . ':tree-data:' . $GLOBALS['language']->language . ':' . md5(serialize($data));
+  return 'links:' . $menu_name . ':tree-data:' . $GLOBALS['language']->language . ':' . hash('sha256', serialize($data));
 }
 
 /**
@@ -1438,7 +1438,7 @@ function theme_menu_local_task($variables) {
       $link['title'] = check_plain($link['title']);
     }
     $link['localized_options']['html'] = TRUE;
-    $link_text = t('!local-task-title !active', array('!local-task-title' => $link['title'], '!active' => $active));
+    $link_text = t('!local-task-title!active', array('!local-task-title' => $link['title'], '!active' => $active));
   }
 
   return '<li' . (!empty($variables['element']['#active']) ? ' class="active"' : '') . '>' . l($link_text, $link['href'], $link['localized_options']) . "</li>\n";
@@ -1685,9 +1685,19 @@ function menu_local_tasks($level = 0) {
     $tabs = array();
 
     $router_item = menu_get_item();
+
+    // If this router item points to its parent, start from the parents to
+    // compute tabs and actions.
+    if ($router_item && ($router_item['type'] & MENU_LINKS_TO_PARENT)) {
+      $router_item = menu_get_item($router_item['tab_parent']);
+    }
+
+    // If we failed to fetch a router item or the current user doesn't have
+    // access to it, don't bother computing the tabs.
     if (!$router_item || !$router_item['access']) {
       return $empty;
     }
+
     // Get all tabs and the root page.
     $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
       ->fields('menu_router')
@@ -1710,8 +1720,9 @@ function menu_local_tasks($level = 0) {
       // Store the translated item for later use.
       $tasks[$item['path']] = $item;
     }
+
     // Find all tabs below the current path.
-    $path = ($router_item['type'] == MENU_DEFAULT_LOCAL_TASK ? $router_item['tab_parent'] : $router_item['path']);
+    $path = $router_item['path'];
     // Tab parenting may skip levels, so the number of parts in the path may not
     // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort).
     $depth = 1001;
@@ -2130,7 +2141,7 @@ function menu_set_active_trail($new_trail = NULL) {
     // Make sure the current page is in the trail (needed for the page title),
     // but exclude tabs and the front page.
     $last = count($trail) - 1;
-    if ($trail[$last]['href'] != $item['href'] && !(bool)($item['type'] & MENU_IS_LOCAL_TASK) && !drupal_is_front_page()) {
+    if ($trail[$last]['href'] != $item['href'] && !(bool) ($item['type'] & MENU_IS_LOCAL_TASK) && !drupal_is_front_page()) {
       $trail[] = $item;
     }
   }
@@ -2181,7 +2192,7 @@ function menu_get_active_title() {
   $active_trail = menu_get_active_trail();
 
   foreach (array_reverse($active_trail) as $item) {
-    if (!(bool)($item['type'] & MENU_IS_LOCAL_TASK)) {
+    if (!(bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
       return $item['title'];
     }
   }
@@ -3096,8 +3107,8 @@ function _menu_router_build($callbacks) {
       '_fit' => $fit,
     );
     $item += array(
-      '_visible' => (bool)($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
-      '_tab' => (bool)($item['type'] & MENU_IS_LOCAL_TASK),
+      '_visible' => (bool) ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
+      '_tab' => (bool) ($item['type'] & MENU_IS_LOCAL_TASK),
     );
     if ($move) {
       $new_path = implode('/', $item['_parts']);
@@ -3134,7 +3145,7 @@ function _menu_router_build($callbacks) {
           // previous iteration assigned one already), try to find the menu name
           // of the parent item in the currently stored menu links.
           if (!isset($parent['menu_name'])) {
-            $menu_name = db_query("SELECT menu_name FROM {menu_links} WHERE router_path = :router_path", array(':router_path' => $parent_path))->fetchField();
+            $menu_name = db_query("SELECT menu_name FROM {menu_links} WHERE router_path = :router_path AND module = 'system'", array(':router_path' => $parent_path))->fetchField();
             if ($menu_name) {
               $parent['menu_name'] = $menu_name;
             }
diff --git a/includes/module.inc b/includes/module.inc
index 1733cff900bd1e5ef3dd8fabbf36b567dda0439c..380d4c8f5dbe5da47ff42f3a9d7fd641d49486f1 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: module.inc,v 1.190 2010/04/22 22:36:01 webchick Exp $
+// $Id: module.inc,v 1.192 2010/05/09 13:49:33 dries Exp $
 
 /**
  * @file
@@ -375,10 +375,10 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
       // Now install the module if necessary.
       if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
         drupal_install_schema($module);
-        // Allow the module to perform install tasks.
-        module_invoke($module, 'install');
         $versions = drupal_get_schema_versions($module);
         drupal_set_installed_schema_version($module, $versions ? max($versions) : SCHEMA_INSTALLED);
+        // Allow the module to perform install tasks.
+        module_invoke($module, 'install');
         // Record the fact that it was installed.
         $modules_installed[] = $module;
         watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
@@ -786,7 +786,12 @@ function drupal_required_modules() {
  *
  * @param $type
  *   A string describing the data type of the alterable $data. 'form', 'links',
- *   'node_content', and so on are several examples.
+ *   'node_content', and so on are several examples. Alternatively can be an
+ *   array, in which case hook_TYPE_alter() is invoked for each value in the
+ *   array, ordered first by module, and then for each module, in the order of
+ *   values in $type. For example, when Form API is using drupal_alter() to
+ *   execute both hook_form_alter() and hook_form_FORM_ID_alter()
+ *   implementations, it passes array('form', 'form_' . $form_id) for $type.
  * @param &$data
  *   The primary data to be altered.
  * @param &$context1
@@ -804,14 +809,69 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
   }
   $functions = &$drupal_static_fast['functions'];
 
+  // Most of the time, $type is passed as a string, so for performance,
+  // normalize it to that. When passed as an array, usually the first item in
+  // the array is a generic type, and additional items in the array are more
+  // specific variants of it, as in the case of array('form', 'form_FORM_ID').
+  if (is_array($type)) {
+    $cid = implode(',', $type);
+    $extra_types = $type;
+    $type = array_shift($extra_types);
+    // Allow if statements in this function to use the faster isset() rather
+    // than !empty() both when $type is passed as a string, or as an array with
+    // one item.
+    if (empty($extra_types)) {
+      unset($extra_types);
+    }
+  }
+  else {
+    $cid = $type;
+  }
+
   // Some alter hooks are invoked many times per page request, so statically
   // cache the list of functions to call, and on subsequent calls, iterate
   // through them quickly.
-  if (!isset($functions[$type])) {
-    $functions[$type] = array();
+  if (!isset($functions[$cid])) {
+    $functions[$cid] = array();
     $hook = $type . '_alter';
-    foreach (module_implements($hook) as $module) {
-      $functions[$type][] = $module . '_' . $hook;
+    $modules = module_implements($hook);
+    if (!isset($extra_types)) {
+      // For the more common case of a single hook, we do not need to call
+      // function_exists(), since module_implements() returns only modules with
+      // implementations.
+      foreach ($modules as $module) {
+        $functions[$cid][] = $module . '_' . $hook;
+      }
+    }
+    else {
+      // For multiple hooks, we need $modules to contain every module that
+      // implements at least one of them.
+      $extra_modules = array();
+      foreach ($extra_types as $extra_type) {
+        $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter'));
+      }
+      // If any modules implement one of the extra hooks that do not implement
+      // the primary hook, we need to add them to the $modules array in their
+      // appropriate order.
+      if (array_diff($extra_modules, $modules)) {
+        // Order the modules by the order returned by module_list().
+        $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
+      }
+      foreach ($modules as $module) {
+        // Since $modules is a merged array, for any given module, we do not
+        // know whether it has any particular implementation, so we need a
+        // function_exists().
+        $function = $module . '_' . $hook;
+        if (function_exists($function)) {
+          $functions[$cid][] = $function;
+        }
+        foreach ($extra_types as $extra_type) {
+          $function = $module . '_' . $extra_type . '_alter';
+          if (function_exists($function)) {
+            $functions[$cid][] = $function;
+          }
+        }
+      }
     }
     // Allow the theme to alter variables after the theme system has been
     // initialized.
@@ -825,12 +885,22 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
       foreach ($theme_keys as $theme_key) {
         $function = $theme_key . '_' . $hook;
         if (function_exists($function)) {
-          $functions[$type][] = $function;
+          $functions[$cid][] = $function;
+        }
+        if (isset($extra_types)) {
+          foreach ($extra_types as $extra_type) {
+            $function = $theme_key . '_' . $extra_type . '_alter';
+            if (function_exists($function)) {
+              $functions[$cid][] = $function;
+            }
+          }
         }
       }
     }
   }
-  foreach ($functions[$type] as $function) {
+
+  foreach ($functions[$cid] as $function) {
     $function($data, $context1, $context2);
   }
 }
+
diff --git a/includes/pager.inc b/includes/pager.inc
index af0065cfa2c801b3aff83f67edae7707834da84d..d8c82e6c63403f8d15e725131d36ca5145555c8c 100644
--- a/includes/pager.inc
+++ b/includes/pager.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: pager.inc,v 1.79 2010/04/13 15:23:02 dries Exp $
+// $Id: pager.inc,v 1.80 2010/05/06 05:59:30 webchick Exp $
 
 /**
  * @file
@@ -85,7 +85,7 @@ class PagerDefault extends SelectQueryExtender {
     // We calculate the total of pages as ceil(items / limit).
     $pager_total_items[$this->element] = $this->getCountQuery()->execute()->fetchField();
     $pager_total[$this->element] = ceil($pager_total_items[$this->element] / $this->limit);
-    $pager_page_array[$this->element] = max(0, min((int)$pager_page_array[$this->element], ((int)$pager_total[$this->element]) - 1));
+    $pager_page_array[$this->element] = max(0, min((int) $pager_page_array[$this->element], ((int) $pager_total[$this->element]) - 1));
     $pager_limits[$this->element] = $this->limit;
     $this->range($pager_page_array[$this->element] * $this->limit, $this->limit);
 
@@ -528,6 +528,6 @@ function pager_load_array($value, $element, $old_array) {
     }
   }
   // Update the changed element.
-  $new_array[$element] = (int)$value;
+  $new_array[$element] = (int) $value;
   return $new_array;
 }
diff --git a/includes/password.inc b/includes/password.inc
index 787f14b80f0f39e1f7c76af289a8a1d47cd1fdde..364729b9ab49e1ec6afaf4877c17d919ade56f36 100644
--- a/includes/password.inc
+++ b/includes/password.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: password.inc,v 1.6 2009/02/26 07:30:26 webchick Exp $
+// $Id: password.inc,v 1.8 2010/05/04 15:47:03 dries Exp $
 
 /**
  * @file
@@ -16,8 +16,8 @@
 
 /**
  * The standard log2 number of iterations for password stretching. This should
- * increase by 1 at least every other Drupal version in order to counteract
- * increases in the speed and power of computers available to crack the hashes.
+ * increase by 1 every Drupal version in order to counteract increases in the
+ * speed and power of computers available to crack the hashes.
  */
 define('DRUPAL_HASH_COUNT', 14);
 
@@ -31,6 +31,11 @@ define('DRUPAL_MIN_HASH_COUNT', 7);
  */
 define('DRUPAL_MAX_HASH_COUNT', 30);
 
+/**
+ * The expected (and maximum) number of characters in a hashed password.
+ */
+define('DRUPAL_HASH_LENGTH', 55);
+
 /**
  * Returns a string for mapping an int to the corresponding base 64 character.
  */
@@ -49,7 +54,7 @@ function _password_itoa64() {
  * @return
  *   Encoded string
  */
-function _password_base64_encode($input, $count)  {
+function _password_base64_encode($input, $count) {
   $output = '';
   $i = 0;
   $itoa64 = _password_itoa64();
@@ -93,7 +98,7 @@ function _password_base64_encode($input, $count)  {
  *   A 12 character string containing the iteration count and a random salt.
  */
 function _password_generate_salt($count_log2) {
-  $output = '$P$';
+  $output = '$S$';
   // Minimum log2 iterations is DRUPAL_MIN_HASH_COUNT.
   $count_log2 = max($count_log2, DRUPAL_MIN_HASH_COUNT);
   // Maximum log2 iterations is DRUPAL_MAX_HASH_COUNT.
@@ -113,19 +118,23 @@ function _password_generate_salt($count_log2) {
  * for an attacker to try to break the hash by brute-force computation of the
  * hashes of a large number of plain-text words or strings to find a match.
  *
+ * @param $algo
+ *   The string name of a hashing algorithm usable by hash(), like 'sha256'.
  * @param $password
  *   The plain-text password to hash.
  * @param $setting
- *   An existing hash or the output of _password_generate_salt().
+ *   An existing hash or the output of _password_generate_salt().  Must be
+ *   at least 12 characters (the settings and salt).
  *
  * @return
  *   A string containing the hashed password (and salt) or FALSE on failure.
+ *   The return string will be truncated at DRUPAL_HASH_LENGTH characters max.
  */
-function _password_crypt($password, $setting)  {
+function _password_crypt($algo, $password, $setting) {
   // The first 12 characters of an existing hash are its setting string.
   $setting = substr($setting, 0, 12);
 
-  if (substr($setting, 0, 3) != '$P$') {
+  if ($setting[0] != '$' || $setting[2] != '$') {
     return FALSE;
   }
   $count_log2 = _password_get_count_log2($setting);
@@ -139,22 +148,21 @@ function _password_crypt($password, $setting)  {
     return FALSE;
   }
 
-  // We must use md5() or sha1() here since they are the only cryptographic
-  // primitives always available in PHP 5. To implement our own low-level
-  // cryptographic function in PHP would result in much worse performance and
-  // consequently in lower iteration counts and hashes that are quicker to crack
-  // (by non-PHP code).
-
+  // Convert the base 2 logarithm into an integer.
   $count = 1 << $count_log2;
 
-  $hash = md5($salt . $password, TRUE);
+  // We rely on the hash() function being available in PHP 5.2+.
+  $hash = hash($algo, $salt . $password, TRUE);
   do {
-    $hash = md5($hash . $password, TRUE);
+    $hash = hash($algo, $hash . $password, TRUE);
   } while (--$count);
 
-  $output =  $setting . _password_base64_encode($hash, 16);
+  $len = strlen($hash);
+  $output =  $setting . _password_base64_encode($hash, $len);
   // _password_base64_encode() of a 16 byte MD5 will always be 22 characters.
-  return (strlen($output) == 34) ? $output : FALSE;
+  // _password_base64_encode() of a 64 byte sha512 will always be 86 characters.
+  $expected = 12 + ceil((8 * $len) / 6);
+  return (strlen($output) == $expected) ? substr($output, 0, DRUPAL_HASH_LENGTH) : FALSE;
 }
 
 /**
@@ -182,7 +190,7 @@ function user_hash_password($password, $count_log2 = 0) {
     // Use the standard iteration count.
     $count_log2 = variable_get('password_count_log2', DRUPAL_HASH_COUNT);
   }
-  return _password_crypt($password, _password_generate_salt($count_log2));
+  return _password_crypt('sha512', $password, _password_generate_salt($count_log2));
 }
 
 /**
@@ -201,7 +209,7 @@ function user_hash_password($password, $count_log2 = 0) {
  *   TRUE or FALSE.
  */
 function user_check_password($password, $account) {
-  if (substr($account->pass, 0, 3) == 'U$P') {
+  if (substr($account->pass, 0, 2) == 'U$') {
     // This may be an updated password from user_update_7000(). Such hashes
     // have 'U' added as the first character and need an extra md5().
     $stored_hash = substr($account->pass, 1);
@@ -210,7 +218,23 @@ function user_check_password($password, $account) {
   else {
     $stored_hash = $account->pass;
   }
-  $hash = _password_crypt($password, $stored_hash);
+
+  $type = substr($stored_hash, 0, 3);
+  switch ($type) {
+    case '$S$':
+      // A normal Drupal 7 password using sha512.
+      $hash = _password_crypt('sha512', $password, $stored_hash);
+      break;
+    case '$H$':
+      // phpBB3 uses "$H$" for the same thing as "$P$".
+    case '$P$':
+      // A phpass password generated using md5.  This is an
+      // imported password or from an earlier Drupal version.
+      $hash = _password_crypt('md5', $password, $stored_hash);
+      break;
+    default:
+      return FALSE;
+  }
   return ($hash && $stored_hash == $hash);
 }
 
@@ -234,7 +258,7 @@ function user_check_password($password, $account) {
  */
 function user_needs_new_hash($account) {
   // Check whether this was an updated password.
-  if ((substr($account->pass, 0, 3) != '$P$') || (strlen($account->pass) != 34)) {
+  if ((substr($account->pass, 0, 3) != '$S$') || (strlen($account->pass) != DRUPAL_HASH_LENGTH)) {
     return TRUE;
   }
   // Check whether the iteration count used differs from the standard number.
diff --git a/includes/path.inc b/includes/path.inc
index 1f4d3557ade83bee71e908756b4ef38fe0fe4494..98a5962628f44265e23c7acb63a0c493b5e59488 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.inc,v 1.62 2010/04/24 15:11:27 dries Exp $
+// $Id: path.inc,v 1.63 2010/05/18 18:26:30 dries Exp $
 
 /**
  * @file
@@ -234,96 +234,6 @@ function drupal_get_normal_path($path, $path_language = NULL) {
   return $path;
 }
 
-/**
- * Return a component of the current Drupal path.
- *
- * When viewing a page at the path "admin/structure/types", for example, arg(0)
- * returns "admin", arg(1) returns "structure", and arg(2) returns "types".
- *
- * Avoid use of this function where possible, as resulting code is hard to read.
- * In menu callback functions, attempt to use named arguments. See the explanation
- * in menu.inc for how to construct callbacks that take arguments. When attempting
- * to use this function to load an element from the current path, e.g. loading the
- * node on a node page, please use menu_get_object() instead.
- *
- * @param $index
- *   The index of the component, where each component is separated by a '/'
- *   (forward-slash), and where the first component has an index of 0 (zero).
- * @param $path
- *   A path to break into components. Defaults to the path of the current page.
- *
- * @return
- *   The component specified by $index, or NULL if the specified component was
- *   not found.
- */
-function arg($index = NULL, $path = NULL) {
-  // Even though $arguments doesn't need to be resettable for any functional
-  // reasons (the result of explode() does not depend on any run-time
-  // information), it should be resettable anyway in case a module needs to
-  // free up the memory used by it.
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['arguments'] = &drupal_static(__FUNCTION__);
-  }
-  $arguments = &$drupal_static_fast['arguments'];
-
-  if (!isset($path)) {
-    $path = $_GET['q'];
-  }
-  if (!isset($arguments[$path])) {
-    $arguments[$path] = explode('/', $path);
-  }
-  if (!isset($index)) {
-    return $arguments[$path];
-  }
-  if (isset($arguments[$path][$index])) {
-    return $arguments[$path][$index];
-  }
-}
-
-/**
- * Get the title of the current page, for display on the page and in the title bar.
- *
- * @return
- *   The current page's title.
- */
-function drupal_get_title() {
-  $title = drupal_set_title();
-
-  // During a bootstrap, menu.inc is not included and thus we cannot provide a title.
-  if (!isset($title) && function_exists('menu_get_active_title')) {
-    $title = check_plain(menu_get_active_title());
-  }
-
-  return $title;
-}
-
-/**
- * Set the title of the current page, for display on the page and in the title bar.
- *
- * @param $title
- *   Optional string value to assign to the page title; or if set to NULL
- *   (default), leaves the current title unchanged.
- * @param $output
- *   Optional flag - normally should be left as CHECK_PLAIN. Only set to
- *   PASS_THROUGH if you have already removed any possibly dangerous code
- *   from $title using a function like check_plain() or filter_xss(). With this
- *   flag the string will be passed through unchanged.
- *
- * @return
- *   The updated title of the current page.
- */
-function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
-  $stored_title = &drupal_static(__FUNCTION__);
-
-  if (isset($title)) {
-    $stored_title = ($output == PASS_THROUGH) ? $title : check_plain($title);
-  }
-
-  return $stored_title;
-}
-
 /**
  * Check if the current page is the front page.
  *
diff --git a/includes/session.inc b/includes/session.inc
index 542253e8604567603c0213139e34484b085d2d6e..07b208d76739357af174de110c2579442cb19a9b 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: session.inc,v 1.82 2010/04/13 15:13:40 dries Exp $
+// $Id: session.inc,v 1.83 2010/05/01 08:12:22 dries Exp $
 
 /**
  * @file
@@ -206,7 +206,10 @@ function drupal_session_initialize() {
     // processes (like drupal_get_token()) needs to know the future
     // session ID in advance.
     $user = drupal_anonymous_user();
-    session_id(md5(uniqid('', TRUE)));
+    // Less random sessions (which are much faster to generate) are used for
+    // anonymous users than are generated in drupal_session_regenerate() when
+    // a user becomes authenticated.
+    session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE)));
   }
   date_default_timezone_set(drupal_get_user_timezone());
 }
@@ -284,7 +287,7 @@ function drupal_session_regenerate() {
   if ($is_https && variable_get('https', FALSE)) {
     $insecure_session_name = substr(session_name(), 1);
     $params = session_get_cookie_params();
-    $session_id = md5(uniqid(mt_rand(), TRUE));
+    $session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
     setcookie($insecure_session_name, $session_id, REQUEST_TIME + $params['lifetime'], $params['path'], $params['domain'], FALSE, $params['httponly']);
     $_COOKIE[$insecure_session_name] = $session_id;
   }
diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc
index 971a58fc696a8df6f70cb2f7800034ab8fa845b4..61784fe8afc79f50e1fc974bb21d950de36896e4 100644
--- a/includes/stream_wrappers.inc
+++ b/includes/stream_wrappers.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: stream_wrappers.inc,v 1.13 2010/03/26 17:14:45 dries Exp $
+// $Id: stream_wrappers.inc,v 1.15 2010/05/06 05:59:30 webchick Exp $
 
 /**
  * @file
@@ -336,11 +336,11 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
     $path = $this->getLocalPath();
     $this->handle = ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode);
 
-    if ((bool)$this->handle && $options & STREAM_USE_PATH) {
+    if ((bool) $this->handle && $options & STREAM_USE_PATH) {
       $opened_url = $path;
     }
 
-    return (bool)$this->handle;
+    return (bool) $this->handle;
   }
 
   /**
@@ -506,7 +506,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
    */
   public function mkdir($uri, $mode, $options) {
     $this->uri = $uri;
-    $recursive = (bool)($options & STREAM_MKDIR_RECURSIVE);
+    $recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE);
     if ($recursive) {
       // $this->getLocalPath() fails if $uri has multiple levels of directories
       // that do not yet exist.
@@ -581,7 +581,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
     $this->uri = $uri;
     $this->handle = opendir($this->getLocalPath());
 
-    return (bool)$this->handle;
+    return (bool) $this->handle;
   }
 
   /**
@@ -657,7 +657,7 @@ class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
    * Implements abstract public function getDirectoryPath()
    */
   public function getDirectoryPath() {
-    return variable_get('file_private_path', conf_path() . '/private/files');
+    return variable_get('file_private_path', '');
   }
 
   /**
@@ -684,7 +684,7 @@ class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper {
    * Implements abstract public function getDirectoryPath()
    */
   public function getDirectoryPath() {
-    return variable_get('file_temporary_path', conf_path() . '/private/temp');
+    return variable_get('file_temporary_path', sys_get_temp_dir());
   }
 
   /**
diff --git a/includes/theme.inc b/includes/theme.inc
index a5d6aa1a26bc6062ec4fadebd20acabd5e3561ab..f27b9018707bbf027d3b6cd10c433d45f8edd39a 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.inc,v 1.593 2010/04/26 17:54:49 webchick Exp $
+// $Id: theme.inc,v 1.598 2010/05/19 19:22:24 dries Exp $
 
 /**
  * @file
@@ -621,130 +621,88 @@ function list_themes($refresh = FALSE) {
 }
 
 /**
- * Generate the themed output.
- *
- * All requests for theme hooks must go through this function. It examines
- * the request and routes it to the appropriate theme function. The theme
- * registry is checked to determine which implementation to use, which may
- * be a function or a template.
- *
- * If the implementation is a template, the following functions may be used to
- * modify the $variables array. They are processed in two distinct phases;
- * "preprocess" and "process" functions. The order listed here is the order in
- * which they execute.
- *
- * - template_preprocess(&$variables)
- *   This sets a default set of variables for all template implementations.
- *
- * - template_preprocess_HOOK(&$variables)
- *   This is the first preprocessor called specific to the hook; it should be
- *   implemented by the module that registers it.
- *
- * - MODULE_preprocess(&$variables)
- *   This will be called for all templates; it should only be used if there
- *   is a real need. It's purpose is similar to template_preprocess().
- *
- * - MODULE_preprocess_HOOK(&$variables)
- *   This is for modules that want to alter or provide extra variables for
- *   theming hooks not registered to itself. For example, if a module named
- *   "foo" wanted to alter the $classes_array variable for the hook "node" a
- *   preprocess function of foo_preprocess_node() can be created to intercept
- *   and alter the variable.
- *
- * - ENGINE_engine_preprocess(&$variables)
- *   This function should only be implemented by theme engines and exists
- *   so that it can set necessary variables for all hooks.
- *
- * - ENGINE_engine_preprocess_HOOK(&$variables)
- *   This is the same as the previous function, but it is called for a single
- *   theming hook.
- *
- * - THEME_preprocess(&$variables)
- *   This is for themes that want to alter or provide extra variables. For
- *   example, if a theme named "foo" wanted to alter the $classes_array variable
- *   for the hook "node" a preprocess function of foo_preprocess_node() can be
- *   created to intercept and alter the variable.
- *
- * - THEME_preprocess_HOOK(&$variables)
- *   The same applies from the previous function, but it is called for a
- *   specific hook.
- *
- * - template_process(&$variables)
- *   This sets a default set of variables for all template implementations.
- *
- * - template_process_HOOK(&$variables)
- *   This is the first processor called specific to the hook; it should be
- *   implemented by the module that registers it.
- *
- * - MODULE_process(&$variables)
- *   This will be called for all templates; it should only be used if there
- *   is a real need. It's purpose is similar to template_process().
- *
- * - MODULE_process_HOOK(&$variables)
- *   This is for modules that want to alter or provide extra variables for
- *   theming hooks not registered to itself. For example, if a module named
- *   "foo" wanted to alter the $classes_array variable for the hook "node" a
- *   process function of foo_process_node() can be created to intercept
- *   and alter the variable.
- *
- * - ENGINE_engine_process(&$variables)
- *   This function should only be implemented by theme engines and exists
- *   so that it can set necessary variables for all hooks.
- *
- * - ENGINE_engine_process_HOOK(&$variables)
- *   This is the same as the previous function, but it is called for a single
- *   theming hook.
- *
- * - ENGINE_process(&$variables)
- *   This is meant to be used by themes that utilize a theme engine. It is
- *   provided so that the processor is not locked into a specific theme.
- *   This makes it easy to share and transport code but theme authors must be
- *   careful to prevent fatal re-declaration errors when using sub-themes that
- *   have their own processor named exactly the same as its base theme. In
- *   the default theme engine (PHPTemplate), sub-themes will load their own
- *   template.php file in addition to the one used for its parent theme. This
- *   increases the risk for these errors. A good practice is to use the engine
- *   name for the base theme and the theme name for the sub-themes to minimize
- *   this possibility.
- *
- * - ENGINE_process_HOOK(&$variables)
- *   The same applies from the previous function, but it is called for a
- *   specific hook.
- *
- * - THEME_process(&$variables)
- *   These functions are based upon the raw theme; they should primarily be
- *   used by themes that do not use an engine or by sub-themes. It serves the
- *   same purpose as ENGINE_process().
- *
- * - THEME_process_HOOK(&$variables)
- *   The same applies from the previous function, but it is called for a
- *   specific hook.
- *
- * If the implementation is a function, only the hook-specific preprocess
+ * Generates themed output.
+ *
+ * All requests for themed output must go through this function. It examines
+ * the request and routes it to the appropriate theme function or template, by
+ * checking the theme registry.
+ *
+ * The first argument to this function is the name of the theme hook. For
+ * instance, to theme a table, the theme hook name is 'table'. By default, this
+ * theme hook could be implemented by a function called 'theme_table' or a
+ * template file called 'table.tpl.php', but hook_theme() can override the
+ * default function or template name.
+ *
+ * If the implementation is a template file, several functions are called
+ * before the template file is invoked, to modify the $variables array. These
+ * fall into the "preprocessing" phase and the "processing" phase, and are
+ * executed (if they exist), in the following order (note that in the following
+ * list, HOOK indicates the theme hook name, MODULE indicates a module name,
+ * THEME indicates a theme name, and ENGINE indicates a theme engine name):
+ * - template_preprocess(&$variables, $hook): Creates a default set of variables
+ *   for all theme hooks.
+ * - template_preprocess_HOOK(&$variables): Should be implemented by
+ *   the module that registers the theme hook, to set up default variables.
+ * - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
+ *   implementing modules.
+ * - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
+ *   all implementing modules, so that modules that didn't define the theme hook
+ *   can alter the variables.
+ * - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
+ *   set necessary variables for all theme hooks.
+ * - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
+ *   necessary variables for the particular theme hook.
+ * - THEME_preprocess(&$variables, $hook): Allows the theme to set necessary
+ *   variables for all theme hooks.
+ * - THEME_preprocess_HOOK(&$variables): Allows the theme to set necessary
+ *   variables specific to the particular theme hook.
+ * - template_process(&$variables, $hook): Creates a default set of variables
+ *   for all theme hooks.
+ * - template_process_HOOK(&$variables): This is the first processor specific
+ *   to the theme hook; it should be implemented by the module that registers
+ *   it.
+ * - MODULE_process(&$variables, $hook): hook_process() is invoked on all
+ *   implementing modules.
+ * - MODULE_process_HOOK(&$variables): hook_process_HOOK() is invoked on
+ *   on all implementing modules, so that modules that didn't define the theme
+ *   hook can alter the variables.
+ * - ENGINE_engine_process(&$variables, $hook): Allows the theme engine to set
+ *   necessary variables for all theme hooks.
+ * - ENGINE_engine_process_HOOK(&$variables): Allows the theme engine to set
+ *   necessary variables for the particular theme hook.
+ * - ENGINE_process(&$variables, $hook): Allows the theme engine to process the
+ *   variables.
+ * - ENGINE_process_HOOK(&$variables): Allows the theme engine to process the
+ *   variables specific to the theme hook.
+ * - THEME_process(&$variables, $hook):  Allows the theme to process the
+ *   variables.
+ * - THEME_process_HOOK(&$variables):  Allows the theme to process the
+ *   variables specific to the theme hook.
+ *
+ * If the implementation is a function, only the theme-hook-specific preprocess
  * and process functions (the ones ending in _HOOK) are called from the
- * above list. This is because theme hooks with function implementations
- * need to be fast, and calling the non-hook-specific preprocess and process
- * functions for them would incur a noticeable performance penalty.
+ * list above. This is because theme hooks with function implementations
+ * need to be fast, and calling the non-theme-hook-specific preprocess and
+ * process functions for them would incur a noticeable performance penalty.
  *
  * There are two special variables that these preprocess and process functions
- * can set:
- *   'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be merged
- *   together to form a list of 'suggested' alternate hooks to use, in
- *   reverse order of priority. theme_hook_suggestion will always be a higher
- *   priority than items in theme_hook_suggestions. theme() will use the
- *   highest priority implementation that exists. If none exists, theme() will
- *   use the implementation for the theme hook it was called with. These
- *   suggestions are similar to and are used for similar reasons as calling
- *   theme() with an array as the $hook parameter (see below). The difference
- *   is whether the suggestions are determined by the code that calls theme() or
- *   by a preprocess or process function.
+ * can set: 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be
+ * merged together to form a list of 'suggested' alternate theme hooks to use,
+ * in reverse order of priority. theme_hook_suggestion will always be a higher
+ * priority than items in theme_hook_suggestions. theme() will use the
+ * highest priority implementation that exists. If none exists, theme() will
+ * use the implementation for the theme hook it was called with. These
+ * suggestions are similar to and are used for similar reasons as calling
+ * theme() with an array as the $hook parameter (see below). The difference
+ * is whether the suggestions are determined by the code that calls theme() or
+ * by a preprocess or process function.
  *
  * @param $hook
  *   The name of the theme hook to call. If the name contains a
  *   double-underscore ('__') and there isn't an implementation for the full
  *   name, the part before the '__' is checked. This allows a fallback to a more
  *   generic implementation. For example, if theme('links__node', ...) is
- *   called, but there is no implementation of that hook, then the 'links'
+ *   called, but there is no implementation of that theme hook, then the 'links'
  *   implementation is used. This process is iterative, so if
  *   theme('links__contextual__node', ...) is called, theme() checks for the
  *   following implementations, and uses the first one that exists:
@@ -753,20 +711,20 @@ function list_themes($refresh = FALSE) {
  *   - links
  *   This allows themes to create specific theme implementations for named
  *   objects and contexts of otherwise generic theme hooks. The $hook parameter
- *   may also be an array, in which case the first hook that has an
+ *   may also be an array, in which case the first theme hook that has an
  *   implementation is used. This allows for the code that calls theme() to
  *   explicitly specify the fallback order in a situation where using the '__'
- *   convention is not desired or insufficient.
- *
+ *   convention is not desired or is insufficient.
  * @param $variables
  *   An associative array of variables to merge with defaults from the theme
  *   registry, pass to preprocess and process functions for modification, and
  *   finally, pass to the function or template implementing the theme hook.
- *   Alternatively, this can be a renderable array, in which case, its properties
- *   are mapped to variables expected by the theme hook implementations.
+ *   Alternatively, this can be a renderable array, in which case, its
+ *   properties are mapped to variables expected by the theme hook
+ *   implementations.
  *
  * @return
- *   An HTML string that generates the themed output.
+ *   An HTML string representing the themed output.
  */
 function theme($hook, $variables = array()) {
   static $hooks = NULL;
@@ -1512,7 +1470,16 @@ function theme_links($variables) {
  *   An associative array containing:
  *   - path: Either the path of the image file (relative to base_path()) or a
  *     full URL.
- *   - alt: The alternative text for text-based browsers.
+ *   - alt: The alternative text for text-based browsers. HTML 4 and XHTML 1.0
+ *     always require an alt attribute. The HTML 5 draft allows the alt
+ *     attribute to be omitted in some cases. Therefore, this variable defaults
+ *     to an empty string, but can be set to NULL for the attribute to be
+ *     omitted. Usually, neither omission nor an empty string satisfies
+ *     accessibility requirements, so it is strongly encouraged for code calling
+ *     theme('image') to pass a meaningful value for this variable.
+ *     - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
+ *     - http://www.w3.org/TR/xhtml1/dtds.html
+ *     - http://dev.w3.org/html5/spec/Overview.html#alt
  *   - title: The title text is displayed when the image is hovered in some
  *     popular browsers.
  *   - attributes: Associative array of attributes to be placed in the img tag.
@@ -1526,10 +1493,27 @@ function theme_image($variables) {
   $attributes = $variables['attributes'];
   $getsize = $variables['getsize'];
 
-  if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
-    $attributes = drupal_attributes($attributes);
-    $url = file_create_url($path);
-    return '<img src="' . check_url($url) . '" alt="' . check_plain($alt) . '" title="' . check_plain($title) . '" ' . (isset($image_attributes) ? $image_attributes : '') . $attributes . ' />';
+  if (!$getsize || (is_file($path) && (list($width, $height) = @getimagesize($path)))) {
+    // The src attribute can be omitted, by passing NULL for $path and FALSE for
+    // $getsize.
+    if (isset($path)) {
+      $attributes['src'] = file_create_url($path);
+    }
+    // The alt attribute defaults to an empty string. By passing NULL as value,
+    // it can be omitted.
+    if (isset($alt)) {
+      $attributes['alt'] = $alt;
+    }
+    if (isset($title)) {
+      $attributes['title'] = $title;
+    }
+    if (!isset($attributes['width']) && !empty($width)) {
+      $attributes['width'] = $width;
+    }
+    if (!isset($attributes['height']) && !empty($height)) {
+      $attributes['height'] = $height;
+    }
+    return '<img' . drupal_attributes($attributes) . ' />';
   }
 }
 
@@ -1759,18 +1743,6 @@ function theme_table($variables) {
   return $output;
 }
 
-/**
- * Returns attributes for a header cell of tables with select all functionality.
- *
- * @return
- *   An array of attributes.
- */
-function theme_table_select_header_cell() {
-  drupal_add_js('misc/tableselect.js');
-
-  return array('class' => array('select-all'));
-}
-
 /**
  * Returns HTML for a sort icon.
  *
@@ -2517,7 +2489,7 @@ function template_preprocess_username(&$variables) {
    }
   }
   else {
-    $variables['uid'] = (int)$account->uid;
+    $variables['uid'] = (int) $account->uid;
   }
 
   // Set the name to a formatted name that is safe for printing and
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index f2d416abcb7b0532b97b285db1a39cc84fac1d77..2544bc4e47eb98c23b2fa6b69855972a0ca0185a 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.maintenance.inc,v 1.58 2010/04/20 08:19:01 webchick Exp $
+// $Id: theme.maintenance.inc,v 1.59 2010/05/12 09:22:24 dries Exp $
 
 /**
  * @file
@@ -144,12 +144,6 @@ function theme_install_page($variables) {
 
   // Delay setting the message variable so it can be processed below.
   $variables['show_messages'] = FALSE;
-  // Variable processors invoked manually since this function and theme_update_page()
-  // are exceptions in how it works within the theme system.
-  template_preprocess($variables, 'install_page');
-  template_preprocess_maintenance_page($variables);
-  template_process($variables, 'install_page');
-  template_process_maintenance_page($variables);
 
   // Special handling of error messages
   $messages = drupal_set_message();
@@ -174,20 +168,7 @@ function theme_install_page($variables) {
     $variables['messages'] .= theme('status_messages', array('display' => 'status'));
   }
 
-  // This was called as a theme hook (not template), so we need to fix
-  // path_to_theme() for the template, to point at the actual theme rather than
-  // system module as owner of the hook. Additionally, figure out the
-  // maintenance page template to use.
-  global $theme_path, $theme_info, $base_theme_info;
-  $theme_path = dirname($theme_info->uri);
-  $base_themes = $base_theme_info;
-  // Make sure a maintenance-page.tpl.php is always found.
-  $base_themes[] = 'modules/system';
-  while (!file_exists($theme_path . '/maintenance-page.tpl.php') && $base_theme = array_shift($base_themes)) {
-    $theme_path = dirname($base_theme->uri);
-  }
-
-  return theme_render_template($theme_path . '/maintenance-page.tpl.php', $variables);
+  return theme('maintenance_page', $variables);
 }
 
 /**
@@ -205,13 +186,6 @@ function theme_update_page($variables) {
   // Set required headers.
   drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
 
-  // Variable processors invoked manually since this function and theme_install_page()
-  // are exceptions in how it works within the theme system.
-  template_preprocess($variables, 'update_page');
-  template_preprocess_maintenance_page($variables);
-  template_process($variables, 'update_page');
-  template_process_maintenance_page($variables);
-
   // Special handling of warning messages.
   $messages = drupal_set_message();
   if (isset($messages['warning'])) {
@@ -220,20 +194,7 @@ function theme_update_page($variables) {
     $variables['messages'] .= theme('status_messages', array('display' => 'warning'));
   }
 
-  // This was called as a theme hook (not template), so we need to fix
-  // path_to_theme() for the template, to point at the actual theme rather than
-  // system module as owner of the hook. Additionally, figure out the
-  // maintenance page template to use.
-  global $theme_path, $theme_info, $base_theme_info;
-  $theme_path = dirname($theme_info->uri);
-  $base_themes = $base_theme_info;
-  // Make sure a maintenance-page.tpl.php is always found.
-  $base_themes[] = 'modules/system';
-  while (!file_exists($theme_path . '/maintenance-page.tpl.php') && $base_theme = array_shift($base_themes)) {
-    $theme_path = dirname($base_theme->uri);
-  }
-
-  return theme_render_template($theme_path . '/maintenance-page.tpl.php', $variables);
+  return theme('maintenance_page', $variables);
 }
 
 /**
diff --git a/includes/update.inc b/includes/update.inc
index fe84dd5c2558d7662959740732cd449397e1fea9..0a238bb2099aa3ff3c68af3810e48ee87f20d48f 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.inc,v 1.44 2010/04/21 07:05:44 webchick Exp $
+// $Id: update.inc,v 1.50 2010/05/21 11:53:26 dries Exp $
 
 /**
  * @file
@@ -99,6 +99,23 @@ function update_prepare_d7_bootstrap() {
   // that occur by creating a static list.
   $GLOBALS['conf']['blocked_ips'] = array();
 
+  // Check that PDO is available and that the correct PDO database driver is
+  // loaded. Bootstrapping to DRUPAL_BOOTSTRAP_DATABASE will result in a fatal
+  // error otherwise.
+  $message = '';
+  // Check that PDO is loaded.
+  if (!extension_loaded('pdo')) {
+    $message = '<h2>PDO is required!</h2><p>Drupal 7 requires PHP ' . DRUPAL_MINIMUM_PHP . ' or higher with the PHP Data Objects (PDO) extension enabled.</p>';
+  }
+  // Check that the correct driver is loaded for the database being updated.
+  elseif (!in_array($databases['default']['default']['driver'], PDO::getAvailableDrivers())) {
+      $message = '<h2>A PDO database driver is required!</h2><p>You need to enable the PDO_' . strtoupper($databases['default']['default']['driver']) . ' database driver for PHP ' . DRUPAL_MINIMUM_PHP . ' or higher so that Drupal 7 can access the database.</p>';
+  }
+  if ($message) {
+    print $message . '<p>See the <a href="http://drupal.org/requirements">system requirements page</a> for more information.</p>';
+    exit();
+  }
+  
   // Allow the database system to work even if the registry has not been
   // created yet.
   drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
@@ -164,11 +181,6 @@ function update_prepare_d7_bootstrap() {
           'not null' => TRUE,
           'default' => 0,
         ),
-        'headers' => array(
-          'description' => 'Any custom HTTP headers to be added to cached data.',
-          'type' => 'text',
-          'not null' => FALSE,
-        ),
         'serialized' => array(
           'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
           'type' => 'int',
@@ -184,6 +196,12 @@ function update_prepare_d7_bootstrap() {
     );
     db_create_table('cache_bootstrap', $cache_bootstrap);
   }
+
+  // Set a valid timezone for 6 -> 7 upgrade process.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+  if (is_numeric(variable_get('date_default_timezone', 0))) {
+    $GLOBALS['conf']['date_default_timezone'] = 'UTC';
+  }
 }
 
 /**
@@ -223,11 +241,11 @@ function update_fix_d7_block_deltas(&$sandbox, $renamed_deltas) {
           ))
           ->fetchField();
           if ($block_exists) {
-          	db_update($table)
-          	  ->fields(array('delta' => $new_delta))
-          	  ->condition('module', $module)
-          	  ->condition('delta', $old_delta)
-          	  ->execute();
+            db_update($table)
+              ->fields(array('delta' => $new_delta))
+              ->condition('module', $module)
+              ->condition('delta', $old_delta)
+              ->execute();
           }
         }
       }
@@ -294,7 +312,7 @@ function update_fix_d7_requirements() {
   global $update_rewrite_settings, $db_url;
   if (!empty($update_rewrite_settings)) {
     $databases = update_parse_db_url($db_url);
-    $salt = sha1(drupal_random_bytes(64));
+    $salt = drupal_hash_base64(drupal_random_bytes(55));
     file_put_contents(conf_path() . '/settings.php', "\n" . '$databases = ' . var_export($databases, TRUE) . ";\n\$drupal_hash_salt = '$salt';", FILE_APPEND);
   }
   if (drupal_get_installed_schema_version('system') < 7000 && !variable_get('update_d7_requirements', FALSE)) {
@@ -1100,16 +1118,10 @@ function update_build_dependency_graph($update_functions) {
   }
 
   // Now add any explicit update dependencies declared by modules.
-  $update_dependencies = update_invoke_all('update_dependencies');
+  $update_dependencies = update_retrieve_dependencies();
   foreach ($graph as $function => $data) {
     if (!empty($update_dependencies[$data['module']][$data['number']])) {
       foreach ($update_dependencies[$data['module']][$data['number']] as $module => $number) {
-        // If we have an explicit dependency on more than one update from a
-        // particular module, choose the highest one, since that contains the
-        // actual direct dependency.
-        if (is_array($number)) {
-          $number = max($number);
-        }
         $dependency = $module . '_update_' . $number;
         $graph[$dependency]['edges'][$function] = TRUE;
         $graph[$dependency]['module'] = $module;
@@ -1158,39 +1170,66 @@ function update_already_performed($module, $number) {
 }
 
 /**
- * Invoke an update system hook in all installed modules.
- *
- * This function is similar to module_invoke_all(), except it does not require
- * that a module be enabled to invoke its hook, only that it be installed. This
- * allows the update system to properly perform updates even on modules that
- * are currently disabled.
+ * Invoke hook_update_dependencies() in all installed modules.
  *
- * @param $hook
- *   The name of the hook to invoke.
- * @param ...
- *   Arguments to pass to the hook.
+ * This function is similar to module_invoke_all(), with the main difference
+ * that it does not require that a module be enabled to invoke its hook, only
+ * that it be installed. This allows the update system to properly perform
+ * updates even on modules that are currently disabled.
  *
  * @return
- *   An array of return values of the hook implementations. If modules return
- *   arrays from their implementations, those are merged into one array.
+ *   An array of return values obtained by merging the results of the
+ *   hook_update_dependencies() implementations in all installed modules.
  *
  * @see module_invoke_all()
+ * @see hook_update_dependencies()
  */
-function update_invoke_all() {
-  $args = func_get_args();
-  $hook = $args[0];
-  unset($args[0]);
+function update_retrieve_dependencies() {
   $return = array();
-  $modules = db_query("SELECT name FROM {system} WHERE type = 'module' AND schema_version != :schema", array(':schema' => SCHEMA_UNINSTALLED))->fetchCol();
+  // Get a list of installed modules, arranged so that we invoke their hooks in
+  // the same order that module_invoke_all() does.
+  $modules = db_query("SELECT name FROM {system} WHERE type = 'module' AND schema_version != :schema ORDER BY weight ASC, name ASC", array(':schema' => SCHEMA_UNINSTALLED))->fetchCol();
   foreach ($modules as $module) {
-    $function = $module . '_' . $hook;
+    $function = $module . '_update_dependencies';
     if (function_exists($function)) {
-      $result = call_user_func_array($function, $args);
+      $result = $function();
+      // Each implementation of hook_update_dependencies() returns a
+      // multidimensional, associative array containing some keys that
+      // represent module names (which are strings) and other keys that
+      // represent update function numbers (which are integers). We cannot use
+      // array_merge_recursive() to properly merge these results, since it
+      // treats strings and integers differently. Therefore, we have to
+      // explicitly loop through the expected array structure here and perform
+      // the merge manually.
       if (isset($result) && is_array($result)) {
-        $return = array_merge_recursive($return, $result);
-      }
-      elseif (isset($result)) {
-        $return[] = $result;
+        foreach ($result as $module => $module_data) {
+          foreach ($module_data as $update => $update_data) {
+            foreach ($update_data as $module_dependency => $update_dependency) {
+              // If there are redundant dependencies declared for the same
+              // update function (so that it is declared to depend on more than
+              // one update from a particular module), record the dependency on
+              // the highest numbered update here, since that automatically
+              // implies the previous ones. For example, if one module's
+              // implementation of hook_update_dependencies() required this
+              // ordering:
+              //
+              // system_update_7001 ---> user_update_7000
+              //
+              // but another module's implementation of the hook required this
+              // one:
+              //
+              // system_update_7002 ---> user_update_7000
+              //
+              // we record the second one, since system_update_7001() is always
+              // guaranteed to run before system_update_7002() anyway (within
+              // an individual module, updates are always run in numerical
+              // order).
+              if (!isset($return[$module][$update][$module_dependency]) || $update_dependency > $return[$module][$update][$module_dependency]) {
+                $return[$module][$update][$module_dependency] = $update_dependency;
+              }
+            }
+          }
+        }
       }
     }
   }
diff --git a/includes/xmlrpc.inc b/includes/xmlrpc.inc
index 6edfe019df2dfb4959e3142b63a65f6c4b38beb5..334a8c3d7247e670b6c4c31f4b35a92c7c005a8f 100644
--- a/includes/xmlrpc.inc
+++ b/includes/xmlrpc.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: xmlrpc.inc,v 1.65 2010/03/31 15:56:53 dries Exp $
+// $Id: xmlrpc.inc,v 1.66 2010/05/06 05:59:30 webchick Exp $
 
 /**
  * @file
@@ -260,7 +260,7 @@ function xmlrpc_message_tag_close($parser, $tag) {
       // If no type is indicated, the type is string
       // We take special care for empty values
       if (trim($xmlrpc_message->current_tag_contents) != '' || (isset($xmlrpc_message->last_open) && ($xmlrpc_message->last_open == 'value'))) {
-        $value = (string)$xmlrpc_message->current_tag_contents;
+        $value = (string) $xmlrpc_message->current_tag_contents;
         $value_flag = TRUE;
       }
       unset($xmlrpc_message->last_open);
diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc
index 6055a19bb5115fa36b58ca9add9cbf434b04b075..a850eee48e3ddebe981646f5097598f0ba4c42f5 100644
--- a/includes/xmlrpcs.inc
+++ b/includes/xmlrpcs.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: xmlrpcs.inc,v 1.38 2010/03/31 15:33:08 dries Exp $
+// $Id: xmlrpcs.inc,v 1.39 2010/04/29 05:35:21 webchick Exp $
 
 /**
  * @file
@@ -60,7 +60,8 @@ function xmlrpc_server($callbacks) {
 
   $data = file_get_contents('php://input');
   if (!$data) {
-    exit('XML-RPC server accepts POST requests only.');
+    print 'XML-RPC server accepts POST requests only.';
+    drupal_exit();
   }
   $xmlrpc_server->message = xmlrpc_message($data);
   if (!xmlrpc_message_parse($xmlrpc_server->message)) {
diff --git a/misc/ajax.js b/misc/ajax.js
index 2ea89e65c31e7473360455945417dc47bda45d97..463481bf43f3b4d3e7ac4bc90c9120aea12da0ed 100644
--- a/misc/ajax.js
+++ b/misc/ajax.js
@@ -1,4 +1,4 @@
-// $Id: ajax.js,v 1.15 2010/04/07 17:30:43 dries Exp $
+// $Id: ajax.js,v 1.17 2010/05/16 19:08:08 dries Exp $
 (function ($) {
 
 /**
@@ -93,7 +93,7 @@ Drupal.ajax = function (base, element, element_settings) {
     selector: '#' + base,
     effect: 'none',
     speed: 'slow',
-    method: 'replace',
+    method: 'replaceWith',
     progress: {
       type: 'bar',
       message: 'Please wait...'
@@ -132,7 +132,7 @@ Drupal.ajax = function (base, element, element_settings) {
       // Sanity check for browser support (object expected).
       // When using iFrame uploads, responses must be returned as a string.
       if (typeof response == 'string') {
-        response = $.parseJson(response);
+        response = $.parseJSON(response);
       }
       return ajax.success(response, status);
     },
diff --git a/misc/autocomplete.js b/misc/autocomplete.js
index bb648d14ffcebfdaa448fd629c3c7418860936e5..bda022e4c7e22901db3e7add2681429c0cda2dcf 100644
--- a/misc/autocomplete.js
+++ b/misc/autocomplete.js
@@ -1,4 +1,4 @@
-// $Id: autocomplete.js,v 1.35 2010/01/29 22:40:41 dries Exp $
+// $Id: autocomplete.js,v 1.36 2010/04/30 05:23:43 webchick Exp $
 (function ($) {
 
 /**
@@ -72,23 +72,23 @@ Drupal.jsAC.prototype.onkeyup = function (input, e) {
     e = window.event;
   }
   switch (e.keyCode) {
-    case 16: // shift.
-    case 17: // ctrl.
-    case 18: // alt.
-    case 20: // caps lock.
-    case 33: // page up.
-    case 34: // page down.
-    case 35: // end.
-    case 36: // home.
-    case 37: // left arrow.
-    case 38: // up arrow.
-    case 39: // right arrow.
-    case 40: // down arrow.
+    case 16: // Shift.
+    case 17: // Ctrl.
+    case 18: // Alt.
+    case 20: // Caps lock.
+    case 33: // Page up.
+    case 34: // Page down.
+    case 35: // End.
+    case 36: // Home.
+    case 37: // Left arrow.
+    case 38: // Up arrow.
+    case 39: // Right arrow.
+    case 40: // Down arrow.
       return true;
 
-    case 9:  // tab.
-    case 13: // enter.
-    case 27: // esc.
+    case 9:  // Tab.
+    case 13: // Enter.
+    case 27: // Esc.
       this.hidePopup(e.keyCode);
       return true;
 
diff --git a/misc/collapse.js b/misc/collapse.js
index 8f7e7cbcadd3ab42415d34878e0c052d325aea66..c9cde7fd5203524e27ada72eb67d17b3acc324c1 100644
--- a/misc/collapse.js
+++ b/misc/collapse.js
@@ -1,4 +1,4 @@
-// $Id: collapse.js,v 1.30 2010/04/09 12:24:53 dries Exp $
+// $Id: collapse.js,v 1.32 2010/05/14 16:45:56 dries Exp $
 (function ($) {
 
 /**
@@ -58,8 +58,10 @@ Drupal.behaviors.collapse = {
   attach: function (context, settings) {
     $('fieldset.collapsible', context).once('collapse', function () {
       var $fieldset = $(this);
-      // Expand if there are errors inside.
-      if ($('.error', $fieldset).length) {
+      // Expand fieldset if there are errors inside, or if it contains an
+      // element that is targeted by the uri fragment identifier. 
+      var anchor = location.hash && location.hash != '#' ? ', ' + location.hash : '';
+      if ($('.error' + anchor, $fieldset).length) {
         $fieldset.removeClass('collapsed');
       }
 
diff --git a/misc/displace.js b/misc/displace.js
new file mode 100644
index 0000000000000000000000000000000000000000..57431742dcc3b826610f53090f10dc263bf95764
--- /dev/null
+++ b/misc/displace.js
@@ -0,0 +1,115 @@
+// $Id: displace.js,v 1.2 2010/05/14 16:44:37 dries Exp $
+(function ($) {
+
+/**
+ * Provides a generic method to position elements fixed to the viewport.
+ *
+ * Fixed positioning (CSS declaration position:fixed) is done relative to the
+ * viewport. This makes it hard to position multiple fixed positioned element
+ * relative to each other (e.g. multiple toolbars should come after each other,
+ * not on top of each other).
+ *
+ * To position an element fixed at the top of the viewport add the class
+ * "displace-top" to that element, and to position it to the bottom of the view-
+ * port add the class "displace-bottom".
+ *
+ * When a browser doesn't support position:fixed (like IE6) the element gets
+ * positioned absolutely by default, but this can be overridden by using the
+ * "displace-unsupported" class.
+ */
+
+/**
+ * Attaches the displace behavior.
+ */
+Drupal.behaviors.displace = {
+  attach: function (context, settings) {
+    // Test for position:fixed support.
+    if (!Drupal.positionFixedSupported()) {
+      $(document.documentElement).addClass('displace-unsupported');
+    }
+
+    $(document.body).once('displace', function () {
+      $(window).bind('resize.drupal-displace', function () {
+        Drupal.displace.clearCache();
+
+        $(document.body).css({
+          paddingTop: Drupal.displace.getDisplacement('top'),
+          paddingBottom: Drupal.displace.getDisplacement('bottom')
+        });
+      });
+    });
+
+    Drupal.displace.clearCache(true);
+    $(window).triggerHandler('resize');
+  }
+};
+
+/**
+ * The displace object.
+ */
+Drupal.displace = Drupal.displace || {};
+
+Drupal.displace.elements = [];
+Drupal.displace.displacement = [];
+
+/**
+ * Get all displaced elements of given region.
+ *
+ * @param region
+ *   Region name. Either "top" or "bottom".
+ *
+ * @return
+ *   jQuery object containing all displaced elements of given region.
+ */
+Drupal.displace.getDisplacedElements = function (region) {
+  if (!this.elements[region]) {
+    this.elements[region] = $('.displace-' + region);
+  }
+  return this.elements[region];
+};
+
+/**
+ * Get the total displacement of given region.
+ *
+ * @param region
+ *   Region name. Either "top" or "bottom".
+ *
+ * @return
+ *   The total displacement of given region in pixels.
+ */
+Drupal.displace.getDisplacement = function (region) {
+  if (!this.displacement[region]) {
+    var offset = 0;
+    var height = 0;
+    this.getDisplacedElements(region).each(function () {
+      offset = offset + height;
+      height = $(this).css(region, offset).outerHeight();
+
+      // In IE, Shadow filter adds some extra height, so we need to remove it
+      // from the returned height.
+      if (this.filters && this.filters.length && this.filters.item('DXImageTransform.Microsoft.Shadow')) {
+        height -= this.filters.item('DXImageTransform.Microsoft.Shadow').strength;
+      }
+    });
+
+    // Use offset of latest displaced element as the total displacement.
+    this.displacement[region] = offset + height;
+  }
+
+  return this.displacement[region];
+};
+
+/**
+ * Clear cache.
+ *
+ * @param selectorCache
+ *   Boolean whether to also clear the selector cache.
+ */
+Drupal.displace.clearCache = function (selectorCache) {
+  if (selectorCache) {
+    this.elements = [];
+  }
+  this.displacement = [];
+};
+
+})(jQuery);
diff --git a/misc/drupal.js b/misc/drupal.js
index e8f61dff247398e422ee7c2a993edee065954732..6980b980b04d3a295b664885321c3be373d9d3df 100644
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -1,4 +1,4 @@
-// $Id: drupal.js,v 1.65 2010/03/10 15:14:38 dries Exp $
+// $Id: drupal.js,v 1.66 2010/05/14 16:44:37 dries Exp $
 
 var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
 
@@ -299,6 +299,24 @@ Drupal.getSelection = function (element) {
   return { 'start': element.selectionStart, 'end': element.selectionEnd };
 };
 
+/**
+ * Checks if position:fixed is supported.
+ *
+ * @return
+ *   Boolean indicating whether or not position:fixed is supported.
+ *
+ * @see http://yura.thinkweb2.com/cft/#IS_POSITION_FIXED_SUPPORTED
+ */
+Drupal.positionFixedSupported = function () {
+  if (this._positionFixedSupported === undefined) {
+    var el = $('<div style="position:fixed; top:10px" />').appendTo(document.body);
+    this._positionFixedSupported = el[0].offsetTop === 10;
+    el.remove();
+  }
+
+  return this._positionFixedSupported;
+};
+
 /**
  * Build an error message from an AJAX response.
  */
diff --git a/misc/farbtastic/farbtastic.css b/misc/farbtastic/farbtastic.css
index cf86792580059cac095145c8ff05df1225a85263..675a5c072115111cae6fe6fb70987b7e3a1975f3 100644
--- a/misc/farbtastic/farbtastic.css
+++ b/misc/farbtastic/farbtastic.css
@@ -1,4 +1,4 @@
-/* $Id: farbtastic.css,v 1.3 2007/04/13 07:33:23 dries Exp $ */
+/* $Id: farbtastic.css,v 1.4 2010/04/28 20:08:38 dries Exp $ */
 
 .farbtastic {
   position: relative;
@@ -7,11 +7,13 @@
   position: absolute;
   cursor: crosshair;
 }
-.farbtastic, .farbtastic .wheel {
+.farbtastic,
+.farbtastic .wheel {
   width: 195px;
   height: 195px;
 }
-.farbtastic .color, .farbtastic .overlay {
+.farbtastic .color,
+.farbtastic .overlay {
   top: 47px;
   left: 47px;
   width: 101px;
diff --git a/misc/states.js b/misc/states.js
index cf2d1ae1d2bf815836cec920d53ab3de29233c26..25bc1d7b453c26967cb997f11f70935809e52a6b 100644
--- a/misc/states.js
+++ b/misc/states.js
@@ -1,4 +1,4 @@
-// $Id: states.js,v 1.2 2010/02/18 19:24:55 webchick Exp $
+// $Id: states.js,v 1.4 2010/04/30 19:30:44 webchick Exp $
 (function ($) {
 
 /**
@@ -19,7 +19,7 @@ Drupal.behaviors.states = {
   attach: function (context, settings) {
     for (var selector in settings.states) {
       for (var state in settings.states[selector]) {
-        new states.Dependant({
+        new states.Dependent({
           element: $(selector),
           state: states.State.sanitize(state),
           dependees: settings.states[selector][state]
@@ -39,12 +39,12 @@ Drupal.behaviors.states = {
  *
  * @param args
  *   Object with the following keys (all of which are required):
- *   - element: A jQuery object of the dependant element
- *   - state: A State object describing the state that is dependant
+ *   - element: A jQuery object of the dependent element
+ *   - state: A State object describing the state that is dependent
  *   - dependees: An object with dependency specifications. Lists all elements
  *     that this element depends on.
  */
-states.Dependant = function (args) {
+states.Dependent = function (args) {
   $.extend(this, { values: {}, oldValue: undefined }, args);
 
   for (var selector in this.dependees) {
@@ -57,7 +57,7 @@ states.Dependant = function (args) {
  * specification from the dependency settings. If the object type can't be
  * found in this list, the === operator is used by default.
  */
-states.Dependant.comparisons = {
+states.Dependent.comparisons = {
   'RegExp': function (reference, value) {
     return reference.test(value);
   },
@@ -67,9 +67,9 @@ states.Dependant.comparisons = {
   }
 };
 
-states.Dependant.prototype = {
+states.Dependent.prototype = {
   /**
-   * Initializes one of the elements this dependant depends on.
+   * Initializes one of the elements this dependent depends on.
    *
    * @param selector
    *   The CSS selector describing the dependee.
@@ -111,9 +111,9 @@ states.Dependant.prototype = {
    *   true, undefined or false.
    */
   compare: function (reference, value) {
-    if (reference.constructor.name in states.Dependant.comparisons) {
+    if (reference.constructor.name in states.Dependent.comparisons) {
       // Use a custom compare function for certain reference value types.
-      return states.Dependant.comparisons[reference.constructor.name](reference, value);
+      return states.Dependent.comparisons[reference.constructor.name](reference, value);
     }
     else {
       // Do a plain comparison otherwise.
@@ -228,7 +228,7 @@ states.Trigger.prototype = {
  * This list of states contains functions that are used to monitor the state
  * of an element. Whenever an element depends on the state of another element,
  * one of these trigger functions is added to the dependee so that the
- * dependant element can be updated.
+ * dependent element can be updated.
  */
 states.Trigger.states = {
   // 'empty' describes the state to be monitored
@@ -247,11 +247,22 @@ states.Trigger.states = {
     }
   },
 
+  // For radio buttons, only return the value if the radio button is selected.
   value: {
     'keyup': function () {
+      // Radio buttons share the same :input[name="key"] selector.
+      if (this.length > 1) {
+        // Initial checked value of radios is undefined, so we return false.
+        return this.filter(':checked').val() || false;
+      }
       return this.val();
     },
     'change': function () {
+      // Radio buttons share the same :input[name="key"] selector.
+      if (this.length > 1) {
+        // Initial checked value of radios is undefined, so we return false.
+        return this.filter(':checked').val() || false;
+      }
       return this.val();
     }
   },
diff --git a/misc/tabledrag.js b/misc/tabledrag.js
index 91585d632b37533d14e43d078f93d058b5baa8fd..7220b784ce403968d33eaaf787ed75ca3cf27e3b 100644
--- a/misc/tabledrag.js
+++ b/misc/tabledrag.js
@@ -1,4 +1,4 @@
-// $Id: tabledrag.js,v 1.36 2010/03/31 19:22:00 dries Exp $
+// $Id: tabledrag.js,v 1.38 2010/05/18 06:46:45 dries Exp $
 (function ($) {
 
 /**
@@ -516,7 +516,7 @@ Drupal.tableDrag.prototype.getMouseOffset = function (target, event) {
  *   The y coordinate of the mouse on the page (not the screen).
  */
 Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) {
-  var rows = this.table.tBodies[0].rows;
+  var rows = $(this.table.tBodies[0].rows).not(':hidden');
   for (var n = 0; n < rows.length; n++) {
     var row = rows[n];
     var indentDiff = 0;
@@ -998,7 +998,7 @@ Drupal.tableDrag.prototype.row.prototype.findSiblings = function (rowSettings) {
   var siblings = [];
   var directions = ['prev', 'next'];
   var rowIndentation = this.indents;
-  for (var d in directions) {
+  for (var d = 0; d < directions.length; d++) {
     var checkRow = $(this.element)[directions[d]]();
     while (checkRow.length) {
       // Check that the sibling contains a similar target field.
diff --git a/misc/tableheader.js b/misc/tableheader.js
index 642710546f0af51a5ecbd39e379ac1d86dbc799a..17fed66cdd272ba2a6f6e912acddf66654482097 100644
--- a/misc/tableheader.js
+++ b/misc/tableheader.js
@@ -1,4 +1,4 @@
-// $Id: tableheader.js,v 1.29 2009/12/18 08:17:26 dries Exp $
+// $Id: tableheader.js,v 1.30 2010/05/14 07:45:53 dries Exp $
 (function ($) {
 
 Drupal.tableHeaderDoScroll = function () {
@@ -42,7 +42,7 @@ Drupal.behaviors.tableHeader = {
     // Track positioning and visibility.
     function tracker(e) {
       // Reset top position of sticky table headers to the current top offset.
-      var topOffset = Drupal.settings.tableHeaderOffset ? eval(Drupal.settings.tableHeaderOffset + '()') : 0;
+      var topOffset = Drupal.displace ? Drupal.displace.getDisplacement('top') : 0;
       $('.sticky-header').css('top', topOffset + 'px');
       // Save positioning data.
       var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
diff --git a/misc/vertical-tabs.js b/misc/vertical-tabs.js
index 5fa13e5fedea12352b71f60f9ed314f966f921d2..a604c4b9fb02577fcc1ca05ebc5acdeba1291c81 100644
--- a/misc/vertical-tabs.js
+++ b/misc/vertical-tabs.js
@@ -1,4 +1,4 @@
-// $Id: vertical-tabs.js,v 1.12 2010/04/09 12:24:53 dries Exp $
+// $Id: vertical-tabs.js,v 1.13 2010/04/28 20:25:21 dries Exp $
 
 (function ($) {
 
@@ -129,7 +129,7 @@ Drupal.verticalTab.prototype = {
    * Updates the tab's summary.
    */
   updateSummary: function () {
-	  this.summary.html(this.fieldset.drupalGetSummary());
+    this.summary.html(this.fieldset.drupalGetSummary());
   },
 
   /**
diff --git a/modules/aggregator/aggregator.admin.inc b/modules/aggregator/aggregator.admin.inc
index 0ffa70b1e2d9997323e7999a45e46cb5458f3fbe..c6741695beba68d826e703cdcba888416b646139 100644
--- a/modules/aggregator/aggregator.admin.inc
+++ b/modules/aggregator/aggregator.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator.admin.inc,v 1.52 2010/04/24 14:49:13 dries Exp $
+// $Id: aggregator.admin.inc,v 1.53 2010/05/18 20:53:29 dries Exp $
 
 /**
  * @file
@@ -395,6 +395,16 @@ function aggregator_admin_refresh_feed($feed) {
  * @ingroup forms
  */
 function aggregator_admin_form($form, $form_state) {
+  // Global aggregator settings.
+  $form['aggregator_allowed_html_tags'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Allowed HTML tags'),
+    '#size' => 80,
+    '#maxlength' => 255,
+    '#default_value' => variable_get('aggregator_allowed_html_tags', '<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>'),
+    '#description' => t('A space-separated list of HTML tags allowed in the content of feed items. Disallowed tags are stripped from the content.'),
+  );
+
   // Make sure configuration is sane.
   aggregator_sanitize_configuration();
 
diff --git a/modules/aggregator/aggregator.css b/modules/aggregator/aggregator.css
index b289271a33a84973465bd8f0b97a76a84c4f9d91..b50fc8d4f4383732e1ca28f35a4fcd8d79e67568 100644
--- a/modules/aggregator/aggregator.css
+++ b/modules/aggregator/aggregator.css
@@ -1,4 +1,4 @@
-/* $Id: aggregator.css,v 1.2 2007/05/27 17:57:47 goba Exp $ */
+/* $Id: aggregator.css,v 1.3 2010/04/28 20:08:38 dries Exp $ */
 
 #aggregator .feed-source .feed-title {
   margin-top: 0;
@@ -17,7 +17,8 @@
   margin-bottom: 0;
   font-size: 1.3em;
 }
-#aggregator .feed-item-meta, #aggregator .feed-item-body {
+#aggregator .feed-item-meta,
+#aggregator .feed-item-body {
   margin-bottom: 0.5em;
 }
 #aggregator .feed-item-categories {
diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info
index 14e94d5b12f55b2c0db0f113db22503157a43b65..8d455f7861c2edb3ff25808c1eaf1a65a84dc8c7 100644
--- a/modules/aggregator/aggregator.info
+++ b/modules/aggregator/aggregator.info
@@ -14,8 +14,8 @@ files[] = aggregator.install
 files[] = aggregator.test
 configure = admin/config/services/aggregator/settings
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/aggregator/aggregator.install b/modules/aggregator/aggregator.install
index 402774e2da5381d97dc16357b7cfe0a5ced13b2b..a1c165955d058b2a5e842a031a2f7c0494a189fe 100644
--- a/modules/aggregator/aggregator.install
+++ b/modules/aggregator/aggregator.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator.install,v 1.29 2010/02/26 00:11:58 webchick Exp $
+// $Id: aggregator.install,v 1.30 2010/05/01 08:12:22 dries Exp $
 
 /**
  * @file
@@ -170,10 +170,10 @@ function aggregator_schema() {
       ),
       'hash' => array(
         'type' => 'varchar',
-        'length' => 32,
+        'length' => 64,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'Calculated md5 hash of the feed data, used for validating cache.',
+        'description' => 'Calculated hash of the feed data, used for validating cache.',
       ),
       'etag' => array(
         'type' => 'varchar',
@@ -275,7 +275,7 @@ function aggregator_schema() {
  * Add hash column to aggregator_feed table.
  */
 function aggregator_update_7000() {
-  db_add_field('aggregator_feed', 'hash', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''));
+  db_add_field('aggregator_feed', 'hash', array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''));
 }
 
 /**
@@ -297,3 +297,4 @@ function aggregator_update_7002() {
   ));
   db_add_index('aggregator_feed', 'queued', array('queued'));
 }
+
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index 467423adfff6ad20f77d5f141987bc619f4f9261..672d078f206e7f78b2e044dff3450b3a0d2f0e03 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator.module,v 1.438 2010/04/13 15:23:02 dries Exp $
+// $Id: aggregator.module,v 1.439 2010/05/01 08:12:22 dries Exp $
 
 /**
  * @file
@@ -614,12 +614,12 @@ function aggregator_refresh($feed) {
   list($fetcher, $parser, $processors) = _aggregator_get_variables();
   $success = module_invoke($fetcher, 'aggregator_fetch', $feed);
 
-  // We store the md5 hash of feed data in the database. When refreshing a
+  // We store the hash of feed data in the database. When refreshing a
   // feed we compare stored hash and new hash calculated from downloaded
   // data. If both are equal we say that feed is not updated.
-  $md5 = md5($feed->source_string);
+  $hash = hash('sha256', $feed->source_string);
 
-  if ($success && ($feed->hash != $md5)) {
+  if ($success && ($feed->hash != $hash)) {
     // Parse the feed.
     if (module_invoke($parser, 'aggregator_parse', $feed)) {
       // Update feed with parsed data.
@@ -630,7 +630,7 @@ function aggregator_refresh($feed) {
           'link' => empty($feed->link) ? $feed->url : $feed->link,
           'description' => empty($feed->description) ? '' : $feed->description,
           'image' => empty($feed->image) ? '' : $feed->image,
-          'hash' => $md5,
+          'hash' => $hash,
           'etag' => empty($feed->etag) ? '' : $feed->etag,
           'modified' => empty($feed->modified) ? 0 : $feed->modified,
         ))
diff --git a/modules/aggregator/aggregator.parser.inc b/modules/aggregator/aggregator.parser.inc
index 90618047850b9a65a72b87690bb5a546230f91d6..72842d5f5507aa9dbcc0ea488a74c8d9dad87522 100644
--- a/modules/aggregator/aggregator.parser.inc
+++ b/modules/aggregator/aggregator.parser.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator.parser.inc,v 1.8 2010/01/30 07:59:24 dries Exp $
+// $Id: aggregator.parser.inc,v 1.9 2010/05/20 08:51:24 dries Exp $
 
 /**
  * @file
@@ -24,7 +24,7 @@ function aggregator_aggregator_parse($feed) {
 
   // Filter the input data.
   if (aggregator_parse_feed($feed->source_string, $feed)) {
-    $modified = empty($feed->http_headers['Last-Modified']) ? 0 : strtotime($feed->http_headers['Last-Modified']);
+    $modified = empty($feed->http_headers['last-modified']) ? 0 : strtotime($feed->http_headers['last-modified']);
 
     // Prepare the channel data.
     foreach ($channel as $key => $value) {
@@ -43,7 +43,7 @@ function aggregator_aggregator_parse($feed) {
       $image = '';
     }
 
-    $etag = empty($feed->http_headers['ETag']) ? '' : $feed->http_headers['ETag'];
+    $etag = empty($feed->http_headers['etag']) ? '' : $feed->http_headers['etag'];
 
     // Add parsed data to the feed object.
     $feed->link = !empty($channel['LINK']) ? $channel['LINK'] : '';
diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info
index 6114806ac6b7bb1fe511fdeaa5de652b89e86947..9b75fc6530d03bc6775568870a4520dc4b9f4b92 100644
--- a/modules/aggregator/tests/aggregator_test.info
+++ b/modules/aggregator/tests/aggregator_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = aggregator_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/aggregator/tests/aggregator_test.module b/modules/aggregator/tests/aggregator_test.module
index 35d626aabf6491dd5834dfdcb2e20afaa5a9b909..f77e38af6e598c4d07a474be8b1f6c6d8c79671b 100644
--- a/modules/aggregator/tests/aggregator_test.module
+++ b/modules/aggregator/tests/aggregator_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator_test.module,v 1.7 2010/03/06 06:31:24 dries Exp $
+// $Id: aggregator_test.module,v 1.8 2010/05/01 08:12:22 dries Exp $
 
 /**
  * Implements hook_menu().
@@ -25,7 +25,7 @@ function aggregator_test_menu() {
  */
 function aggregator_test_feed($use_last_modified = FALSE, $use_etag = FALSE) {
   $last_modified = strtotime('Sun, 19 Nov 1978 05:00:00 GMT');
-  $etag = md5($last_modified);
+  $etag = drupal_hash_base64($last_modified);
 
   $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
   $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
diff --git a/modules/block/block.admin.inc b/modules/block/block.admin.inc
index 3fbbe75a75210820174222024a56a1f8d42be01d..d07f06e8ee142144e2fec3cb207deb72615abca7 100644
--- a/modules/block/block.admin.inc
+++ b/modules/block/block.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.admin.inc,v 1.78 2010/04/24 14:49:13 dries Exp $
+// $Id: block.admin.inc,v 1.80 2010/05/13 07:53:02 dries Exp $
 
 /**
  * @file
@@ -170,10 +170,12 @@ function _block_compare($a, $b) {
   if ((!empty($a['region']) && !empty($b['region'])) && ($place = ($regions[$a['region']] - $regions[$b['region']]))) {
     return $place;
   }
-  // Sort by weight.
-  $weight = $a['weight'] - $b['weight'];
-  if ($weight) {
-    return $weight;
+  // Sort by weight, unless disabled.
+  if ($a['region'] != BLOCK_REGION_NONE) {
+    $weight = $a['weight'] - $b['weight'];
+    if ($weight) {
+      return $weight;
+    }
   }
   // Sort by title.
   return strcmp($a['info'], $b['info']);
@@ -440,9 +442,9 @@ function block_add_block_form_validate($form, &$form_state) {
 function block_add_block_form_submit($form, &$form_state) {
   $delta = db_insert('block_custom')
     ->fields(array(
-      'body' => $form_state['values']['body'],
+      'body' => $form_state['values']['body']['value'],
       'info' => $form_state['values']['info'],
-      'format' => $form_state['values']['format'],
+      'format' => $form_state['values']['body']['format'],
     ))
     ->execute();
   // Store block delta to allow other modules to work with new block.
diff --git a/modules/block/block.api.php b/modules/block/block.api.php
index 8bdab9f7dd59bf0d0baf2c76e065de9fa2e52279..8fedbbc56d1a745ee693b9ae31209339c9c4c36d 100644
--- a/modules/block/block.api.php
+++ b/modules/block/block.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.api.php,v 1.11 2010/04/22 09:12:35 webchick Exp $
+// $Id: block.api.php,v 1.12 2010/04/28 12:36:26 dries Exp $
 
 /**
  * @file
@@ -192,7 +192,7 @@ function hook_block_view($delta = '') {
  *   - delta: The identifier for the block within that module, as defined within
  *     hook_block_info().
  *
- * @see hook_block_view_alter()
+ * @see hook_block_view_MODULE_DELTA_alter()
  * @see hook_block_view()
  */
 function hook_block_view_alter(&$data, $block) {
@@ -213,10 +213,6 @@ function hook_block_view_alter(&$data, $block) {
  * Modules can implement hook_block_view_MODULE_DELTA_alter() to modify a
  * specific block, rather than implementing hook_block_view_alter().
  *
- * Note that this hook fires before hook_block_view_alter(). Therefore, all
- * implementations of hook_block_view_MODULE_DELTA_alter() will run before all
- * implementations of hook_block_view_alter(), regardless of the module order.
- *
  * @param $data
  *   An array of data, as returned from the hook_block_view() implementation of
  *   the module that defined the block:
diff --git a/modules/block/block.info b/modules/block/block.info
index 5c23f4399572454fd64db43357f00dd632992dc2..037493e6a4e7e591aebc0d40a2872402b0b5c553 100644
--- a/modules/block/block.info
+++ b/modules/block/block.info
@@ -10,8 +10,8 @@ files[] = block.install
 files[] = block.test
 configure = admin/structure/block
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/block/block.install b/modules/block/block.install
index 1d1496243069dd62f7eaaf791f881d8a475977cc..fafc39ea10957d891453bc70f775e5645485692a 100644
--- a/modules/block/block.install
+++ b/modules/block/block.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.install,v 1.40 2010/03/28 11:16:29 dries Exp $
+// $Id: block.install,v 1.41 2010/05/19 19:14:43 dries Exp $
 
 /**
  * @file
@@ -387,3 +387,10 @@ function block_update_7004() {
   // Rebuild theme data, so the new 'help' region is identified.
   system_rebuild_theme_data();
 }
+
+/**
+ * Remove {cache_block}.headers column.
+ */
+function block_update_7005() {
+  db_drop_field('cache_block', 'headers');
+}
diff --git a/modules/block/block.js b/modules/block/block.js
index ccfb475424b591a7df146b57fae2228050d113be..290106919bd3b784d225cca901e85c8b09012cb5 100644
--- a/modules/block/block.js
+++ b/modules/block/block.js
@@ -1,4 +1,4 @@
-// $Id: block.js,v 1.15 2010/04/09 12:24:53 dries Exp $
+// $Id: block.js,v 1.16 2010/05/09 13:57:59 dries Exp $
 (function ($) {
 
 /**
@@ -64,8 +64,8 @@ Drupal.behaviors.blockSettingsSummary = {
  */
 Drupal.behaviors.blockDrag = {
   attach: function (context, settings) {
-    // tableDrag is required for this behavior.
-    if (typeof Drupal.tableDrag == 'undefined') {
+    // tableDrag is required and we should be on the blocks admin page.
+    if (typeof Drupal.tableDrag == 'undefined' || typeof Drupal.tableDrag.blocks == 'undefined') {
       return;
     }
 
diff --git a/modules/block/block.module b/modules/block/block.module
index b6abb66b02355d8861d35a5d8035f6ac8157a3aa..03ec5152a6905021b77ab71c2e68233d1c06d9bc 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.module,v 1.419 2010/04/26 14:10:40 dries Exp $
+// $Id: block.module,v 1.421 2010/05/13 07:53:02 dries Exp $
 
 /**
  * @file
@@ -469,8 +469,9 @@ function block_custom_block_form($edit = array()) {
  * @param $edit
  *   Associative array of fields to save. Array keys:
  *   - info: Block description.
- *   - body: Block contents.
- *   - format: Filter ID of the filter format for the body.
+ *   - body: Associative array of body value and format.  Array keys:
+ *     - value: Block contents.
+ *     - format: Filter ID of the filter format for the body.
  * @param $delta
  *   Block ID of the block to save.
  * @return
@@ -479,9 +480,9 @@ function block_custom_block_form($edit = array()) {
 function block_custom_block_save($edit, $delta) {
   db_update('block_custom')
     ->fields(array(
-      'body' => $edit['body'],
+      'body' => $edit['body']['value'],
       'info' => $edit['info'],
-      'format' => $edit['format'],
+      'format' => $edit['body']['format'],
     ))
     ->condition('bid', $delta)
     ->execute();
@@ -762,9 +763,8 @@ function _block_render_blocks($region_blocks) {
         $array = module_invoke($block->module, 'block_view', $block->delta);
 
         // Allow modules to modify the block before it is viewed, via either
-        // hook_block_view_MODULE_DELTA_alter() or hook_block_view_alter().
-        drupal_alter("block_view_{$block->module}_{$block->delta}", $array, $block);
-        drupal_alter('block_view', $array, $block);
+        // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
+        drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
 
         if (isset($cid)) {
           cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info
index 5deccb00c29d4ffed8c11224ef51274a1902fd18..6d4d48fa999f0f1142b926d1929f43602715921b 100644
--- a/modules/block/tests/block_test.info
+++ b/modules/block/tests/block_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = block_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/blog/blog.info b/modules/blog/blog.info
index a9f3bf2818671011ae0e20445aaf0783e78ac32b..bdb83120ed74354859c979d5cc032a86a527f9cc 100644
--- a/modules/blog/blog.info
+++ b/modules/blog/blog.info
@@ -9,8 +9,8 @@ files[] = blog.module
 files[] = blog.pages.inc
 files[] = blog.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/blog/blog.install b/modules/blog/blog.install
new file mode 100644
index 0000000000000000000000000000000000000000..322c21b91dc6bd6f50535aef701809bab45dffb5
--- /dev/null
+++ b/modules/blog/blog.install
@@ -0,0 +1,17 @@
+<?php
+// $Id: blog.install,v 1.1 2010/05/05 15:11:51 webchick Exp $
+
+/**
+ * @file
+ * Install, update and uninstall functions for the blog module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function blog_install() {
+  // Ensure the blog node type is available.
+  node_types_rebuild();
+  $types = node_type_get_types();
+  node_add_body_field($types['blog']);
+}
diff --git a/modules/book/book.admin.inc b/modules/book/book.admin.inc
index ffdcf881298dcc990de318ca77636311affd597f..819765d36e475232c780be3a6f7504c7438c906c 100644
--- a/modules/book/book.admin.inc
+++ b/modules/book/book.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.admin.inc,v 1.33 2010/04/13 15:23:02 dries Exp $
+// $Id: book.admin.inc,v 1.35 2010/05/01 08:12:22 dries Exp $
 
 /**
  * @file
@@ -154,7 +154,7 @@ function _book_admin_table($node, &$form) {
   $tree = book_menu_subtree_data($node->book);
   $tree = array_shift($tree); // Do not include the book item itself.
   if ($tree['below']) {
-    $hash = sha1(serialize($tree['below']));
+    $hash = drupal_hash_base64(serialize($tree['below']));
     // Store the hash value as a hidden form element so that we can detect
     // if another user changed the book hierarchy.
     $form['tree_hash'] = array(
@@ -246,8 +246,8 @@ function theme_book_admin_table($variables) {
       drupal_render($form[$key]['weight']),
       drupal_render($form[$key]['plid']) . drupal_render($form[$key]['mlid']),
       l(t('view'), $href),
-      $access ? l(t('edit'), 'node/' . $nid . '/edit', array('query' => $destination)) : '&nbsp',
-      $access ? l(t('delete'), 'node/' . $nid . '/delete', array('query' => $destination) )  : '&nbsp',
+      $access ? l(t('edit'), 'node/' . $nid . '/edit', array('query' => $destination)) : '&nbsp;',
+      $access ? l(t('delete'), 'node/' . $nid . '/delete', array('query' => $destination) )  : '&nbsp;',
     );
     $row = array('data' => $data);
     if (isset($form[$key]['#attributes'])) {
diff --git a/modules/book/book.info b/modules/book/book.info
index 72fd0f306a07c97ae6c98b63816e7441c3e34575..e13d43e5862f28cbc1c4cd2e98bc32059ca977fa 100644
--- a/modules/book/book.info
+++ b/modules/book/book.info
@@ -11,8 +11,8 @@ files[] = book.install
 files[] = book.test
 configure = admin/content/book/settings
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/book/book.install b/modules/book/book.install
index 4195442a2ae3a1e62ee558398bb6ecdfb4d1d6b8..3f0a14ebea9448cd69e08e060bccb91d32f4623c 100644
--- a/modules/book/book.install
+++ b/modules/book/book.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.install,v 1.34 2009/12/04 16:49:45 dries Exp $
+// $Id: book.install,v 1.35 2010/05/05 06:55:25 webchick Exp $
 
 /**
  * @file
@@ -37,6 +37,7 @@ function _book_install_type_create() {
 
   $book_node_type = node_type_set_defaults($book_node_type);
   node_type_save($book_node_type);
+  node_add_body_field($book_node_type);
   // Default to not promoted.
   variable_set('node_options_book', array('status'));
   // Use this default type for adding content to books.
diff --git a/modules/book/book.module b/modules/book/book.module
index 2f6dfc0ba85f44753edbd4fbe40da1d1533458a9..35529981b807fadc431888bb6363e8f1c2ed4e96 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.module,v 1.539 2010/04/13 15:23:02 dries Exp $
+// $Id: book.module,v 1.542 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -540,7 +540,7 @@ function _book_add_form_elements(&$form, &$form_state, $node) {
     '#title' => t('Book'),
     '#default_value' => $node->book['bid'],
     '#options' => $options,
-    '#access' => (bool)$options,
+    '#access' => (bool) $options,
     '#description' => t('Your page will be a part of the selected book.'),
     '#weight' => -5,
     '#attributes' => array('class' => array('book-title-select')),
@@ -1019,7 +1019,26 @@ function template_preprocess_book_navigation(&$variables) {
 }
 
 /**
- * A recursive helper function for book_toc().
+ * Recursively processes and formats menu items for book_toc().
+ *
+ * This helper function recursively modifies the $toc array for each item in
+ * $tree, ignoring items in the exclude array or at a depth greater than the
+ * limit.  Truncates titles over thirty characters and appends an indentation
+ * string incremented by depth.
+ *
+ * @param $tree
+ *   The data structure of the book's menu tree.  Includes hidden links.
+ * @param $indent
+ *   A string appended to each menu item title. Increments by '--' per depth
+ *   level.
+ * @param $toc
+ *   Reference to the table of contents array. This is modified in place, so the
+ *   function does not have a return value.
+ * @param $exclude
+ *   Optional array of mlid values. Any link whose mlid is in this array will be
+ *   excluded (along with its children).
+ * @param $depth_limit
+ *   Any link deeper than this value will be excluded (along with its children).
  */
 function _book_toc_recurse($tree, $indent, &$toc, $exclude, $depth_limit) {
   foreach ($tree as $data) {
@@ -1254,7 +1273,7 @@ function book_menu_subtree_data($link) {
       $data['node_links'] = array();
       menu_tree_collect_node_links($data['tree'], $data['node_links']);
       // Compute the real cid for book subtree data.
-      $tree_cid = 'links:' . $item['menu_name'] . ':subtree-data:' . md5(serialize($data));
+      $tree_cid = 'links:' . $item['menu_name'] . ':subtree-data:' . hash('sha256', serialize($data));
       // Cache the data, if it is not already in the cache.
 
       if (!cache_get($tree_cid, 'cache_menu')) {
diff --git a/modules/color/color-rtl.css b/modules/color/color-rtl.css
index daf4257d3d3636763f28b2cf7042bae3425c33b7..beb1b2cc248cd9afcf794b300793811f053bfda5 100644
--- a/modules/color/color-rtl.css
+++ b/modules/color/color-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: color-rtl.css,v 1.3 2008/05/19 19:36:41 dries Exp $ */
+/* $Id: color-rtl.css,v 1.4 2010/04/28 20:08:38 dries Exp $ */
 
 #placeholder {
   left: 0;
@@ -14,7 +14,8 @@
   float: right;
   clear: right;
 }
-.color-form .form-text, .color-form .form-select {
+.color-form .form-text,
+.color-form .form-select {
   float: right;
 }
 .color-form .form-text {
@@ -24,7 +25,9 @@
 #palette .hook {
   float: right;
 }
-#palette .down, #palette .up, #palette .both {
+#palette .down,
+#palette .up,
+#palette .both {
   background: url(images/hook-rtl.png) no-repeat 0 0;
 }
 #palette .up {
diff --git a/modules/color/color.css b/modules/color/color.css
index 745e7d4c2c22e68cf4b2dc653bbc08f05a41bd4e..c388d9f361ecb6d3bdab20fc80fe0a0a53011ad0 100644
--- a/modules/color/color.css
+++ b/modules/color/color.css
@@ -1,4 +1,4 @@
-/* $Id: color.css,v 1.4 2007/05/27 17:57:48 goba Exp $ */
+/* $Id: color.css,v 1.5 2010/04/28 20:08:38 dries Exp $ */
 
 /* Farbtastic placement */
 .color-form {
@@ -23,7 +23,8 @@
   clear: left; /* LTR */
   width: 10em;
 }
-.color-form .form-text, .color-form .form-select {
+.color-form .form-text,
+.color-form .form-select {
   float: left; /* LTR */
 }
 .color-form .form-text {
@@ -38,7 +39,9 @@
   width: 16px;
   height: 16px;
 }
-#palette .down, #palette .up, #palette .both {
+#palette .down,
+#palette .up,
+#palette .both {
   background: url(images/hook.png) no-repeat 100% 0; /* LTR */
 }
 #palette .up {
diff --git a/modules/color/color.info b/modules/color/color.info
index 0319923caca2ff7da3ddb6efddbefc54441a2b40..6c4cfa56c1cac13a58300375b77e831d5436b54a 100644
--- a/modules/color/color.info
+++ b/modules/color/color.info
@@ -9,8 +9,8 @@ files[] = color.module
 files[] = color.install
 files[] = color.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/color/color.module b/modules/color/color.module
index 8282c3a75189cb3410d07465a76fab714eedd23e..0b5a88984fa829c9c09f61f649de503db9ddbec1 100644
--- a/modules/color/color.module
+++ b/modules/color/color.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: color.module,v 1.85 2010/04/22 23:25:32 dries Exp $
+// $Id: color.module,v 1.86 2010/05/01 08:12:23 dries Exp $
 
 /**
  * Implements hook_help().
@@ -329,7 +329,7 @@ function color_scheme_form_submit($form, &$form_state) {
   }
 
   // Prepare target locations for generated files.
-  $id = $theme . '-' . substr(md5(serialize($palette) . microtime()), 0, 8);
+  $id = $theme . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8);
   $paths['color'] = 'public://color';
   $paths['target'] = $paths['color'] . '/' . $id;
   foreach ($paths as $path) {
diff --git a/modules/color/preview.js b/modules/color/preview.js
index f90181e646790f2c5bc9b027544b94fcb77f9c9e..c5e47a08da0ee71a80de1827609aa74a93fe01cc 100644
--- a/modules/color/preview.js
+++ b/modules/color/preview.js
@@ -1,15 +1,15 @@
-// $Id: preview.js,v 1.1 2010/04/22 05:18:21 webchick Exp $
+// $Id: preview.js,v 1.2 2010/04/28 20:25:21 dries Exp $
 
 (function ($) {
   Drupal.color = {
-    callback: function(context, settings, form, farb, height, width) {  
+    callback: function(context, settings, form, farb, height, width) {
       // Solid background.
       $('#preview', form).css('backgroundColor', $('#palette input[name="palette[base]"]', form).val());
-      
+
       // Text preview
       $('#text', form).css('color', $('#palette input[name="palette[text]"]', form).val());
       $('#text a, #text h2', form).css('color', $('#palette input[name="palette[link]"]', form).val());
-      
+
       // Set up gradients if there are some.
       var color_start, color_end;
       for (i in settings.gradients) {
@@ -32,4 +32,4 @@
       }
     }
   };
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/modules/comment/comment-wrapper.tpl.php b/modules/comment/comment-wrapper.tpl.php
index 7b9119e801c486de6c07e7eabcc9a2e29bff788e..d17205cae7ca994580d0e673b1a98779aa096cbe 100644
--- a/modules/comment/comment-wrapper.tpl.php
+++ b/modules/comment/comment-wrapper.tpl.php
@@ -1,9 +1,9 @@
 <?php
-// $Id: comment-wrapper.tpl.php,v 1.9 2010/02/23 09:51:21 dries Exp $
+// $Id: comment-wrapper.tpl.php,v 1.10 2010/05/05 06:41:22 webchick Exp $
 
 /**
  * @file
- * Default theme implementation to wrap comments.
+ * Default theme implementation to provide an HTML container for comments.
  *
  * Available variables:
  * - $content: The array of content-related elements for the node. Use
@@ -13,6 +13,12 @@
  *   CSS. It can be manipulated through the variable $classes_array from
  *   preprocess functions. The default value has the following:
  *   - comment-wrapper: The current template type, i.e., "theming hook".
+ * - $title_prefix (array): An array containing additional output populated by
+ *   modules, intended to be displayed in front of the main title tag that
+ *   appears in the template.
+ * - $title_suffix (array): An array containing additional output populated by
+ *   modules, intended to be displayed after the main title tag that appears in
+ *   the template.
  *
  * The following variables are provided for contextual information.
  * - $node: Node object the comments are attached to.
@@ -32,7 +38,9 @@
 ?>
 <div id="comments" class="<?php print $classes; ?>"<?php print $attributes; ?>>
   <?php if ($content['comments'] && $node->type != 'forum'): ?>
+    <?php print render($title_prefix); ?>
     <h2 class="title"><?php print t('Comments'); ?></h2>
+    <?php print render($title_suffix); ?>
   <?php endif; ?>
 
   <?php print render($content['comments']); ?>
diff --git a/modules/comment/comment.info b/modules/comment/comment.info
index e70dd7bf4c52753bacb3e2fb979a244a92b05c48..d646a442ec4f6f5df74deac62c5567638b686709 100644
--- a/modules/comment/comment.info
+++ b/modules/comment/comment.info
@@ -12,8 +12,8 @@ files[] = comment.test
 files[] = comment.tokens.inc
 configure = admin/content/comment
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index b761ce8051e168c16b98729361fbb6b6ea355f34..4ac23e9bac5ece3679b48752ef22154e50ff513f 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.module,v 1.871 2010/04/26 14:26:46 dries Exp $
+// $Id: comment.module,v 1.875 2010/05/10 20:12:21 webchick Exp $
 
 /**
  * @file
@@ -422,7 +422,7 @@ function comment_block_configure($delta = '') {
  * Implements hook_block_save().
  */
 function comment_block_save($delta = '', $edit = array()) {
-  variable_set('comment_block_count', (int)$edit['comment_block_count']);
+  variable_set('comment_block_count', (int) $edit['comment_block_count']);
 }
 
 /**
@@ -576,12 +576,15 @@ function theme_comment_block() {
   $items = array();
   $number = variable_get('comment_block_count', 10);
   foreach (comment_get_recent($number) as $comment) {
-    $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) . '<br />' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed)));
+    $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) .'<span>'. t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed))) .'</span>';
   }
 
   if ($items) {
     return theme('item_list', array('items' => $items));
   }
+  else {
+    return t('No comments available.');
+  }
 }
 
 /**
@@ -606,7 +609,7 @@ function comment_node_view($node, $view_mode) {
       // is open to new comments, and there currently are none.
       if (user_access('access comments')) {
         if (!empty($node->comment_count)) {
-          $links['comment_comments'] = array(
+          $links['comment-comments'] = array(
             'title' => format_plural($node->comment_count, '1 comment', '@count comments'),
             'href' => "node/$node->nid",
             'attributes' => array('title' => t('Jump to the first comment of this posting.')),
@@ -615,8 +618,8 @@ function comment_node_view($node, $view_mode) {
           );
 
           $new = comment_num_new($node->nid);
-          if ($new) {
-            $links['comment_new_comments'] = array(
+          if (!$new) {
+            $links['comment-new-comments'] = array(
               'title' => format_plural($new, '1 new comment', '@count new comments'),
               'href' => "node/$node->nid",
               'query' => comment_new_page_count($node->comment_count, $new, $node),
@@ -629,7 +632,7 @@ function comment_node_view($node, $view_mode) {
         else {
           if ($node->comment == COMMENT_NODE_OPEN) {
             if (user_access('post comments')) {
-              $links['comment_add'] = array(
+              $links['comment-add'] = array(
                 'title' => t('Add new comment'),
                 'href' => "comment/reply/$node->nid",
                 'attributes' => array('title' => t('Add a new comment to this page.')),
@@ -651,17 +654,17 @@ function comment_node_view($node, $view_mode) {
       // indexing.
       if ($node->comment == COMMENT_NODE_OPEN) {
         if (user_access('post comments')) {
-          $links['comment_add'] = array(
+          $links['comment-add'] = array(
             'title' => t('Add new comment'),
             'attributes' => array('title' => t('Share your thoughts and opinions related to this posting.')),
             'fragment' => 'comment-form',
             'html' => TRUE,
           );
           if (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_SEPARATE_PAGE) {
-            $links['comment_add']['href'] = "comment/reply/$node->nid";
+            $links['comment-add']['href'] = "comment/reply/$node->nid";
           }
           else {
-            $links['comment_add']['href'] = "node/$node->nid";
+            $links['comment-add']['href'] = "node/$node->nid";
           }
         }
         else {
@@ -984,23 +987,23 @@ function comment_links($comment, $node) {
   $links = array();
   if ($node->comment == COMMENT_NODE_OPEN) {
     if (user_access('administer comments') && user_access('post comments')) {
-      $links['comment_delete'] = array(
+      $links['comment-delete'] = array(
         'title' => t('delete'),
         'href' => "comment/$comment->cid/delete",
         'html' => TRUE,
       );
-      $links['comment_edit'] = array(
+      $links['comment-edit'] = array(
         'title' => t('edit'),
         'href' => "comment/$comment->cid/edit",
         'html' => TRUE,
       );
-      $links['comment_reply'] = array(
+      $links['comment-reply'] = array(
         'title' => t('reply'),
         'href' => "comment/reply/$comment->nid/$comment->cid",
         'html' => TRUE,
       );
       if ($comment->status == COMMENT_NOT_PUBLISHED) {
-        $links['comment_approve'] = array(
+        $links['comment-approve'] = array(
           'title' => t('approve'),
           'href' => "comment/$comment->cid/approve",
           'html' => TRUE,
@@ -1010,13 +1013,13 @@ function comment_links($comment, $node) {
     }
     elseif (user_access('post comments')) {
       if (comment_access('edit', $comment)) {
-        $links['comment_edit'] = array(
+        $links['comment-edit'] = array(
           'title' => t('edit'),
           'href' => "comment/$comment->cid/edit",
           'html' => TRUE,
         );
       }
-      $links['comment_reply'] = array(
+      $links['comment-reply'] = array(
         'title' => t('reply'),
         'href' => "comment/reply/$comment->nid/$comment->cid",
         'html' => TRUE,
@@ -2089,7 +2092,7 @@ function comment_submit($comment) {
       $comment['subject'] = t('(No subject)');
     }
   }
-  return (object)$comment;
+  return (object) $comment;
 }
 
 /**
@@ -2100,7 +2103,7 @@ function comment_form_submit_build_comment($form, &$form_state) {
 
   field_attach_submit('comment', $comment, $form, $form_state);
 
-  $form_state['comment'] = (array)$comment;
+  $form_state['comment'] = (array) $comment;
   $form_state['rebuild'] = TRUE;
   return $comment;
 }
@@ -2363,7 +2366,7 @@ function _comment_update_node_statistics($nid) {
  * 31000, 31001, ...
  */
 function int2vancode($i = 0) {
-  $num = base_convert((int)$i, 10, 36);
+  $num = base_convert((int) $i, 10, 36);
   $length = strlen($num);
 
   return chr($length + ord('0') - 1) . $num;
diff --git a/modules/comment/comment.test b/modules/comment/comment.test
index ecab2569dbdfa43046da261aff1dd97f00d6219a..5e036e734786650215782d19dbb4d80067ab1747 100644
--- a/modules/comment/comment.test
+++ b/modules/comment/comment.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.test,v 1.77 2010/04/22 10:12:25 webchick Exp $
+// $Id: comment.test,v 1.80 2010/05/06 05:59:31 webchick Exp $
 
 class CommentHelperCase extends DrupalWebTestCase {
   protected $admin_user;
@@ -879,6 +879,11 @@ class CommentApprovalTest extends CommentHelperCase {
     ));
     $this->drupalLogin($this->admin_user);
     $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info.
+
+    // Test that the comments page loads correctly when there are no comments
+    $this->drupalGet('admin/content/comment');
+    $this->assertText(t('No comments available.'));
+
     $this->drupalLogout();
 
     // Post anonymous comment without contact info.
@@ -1141,7 +1146,7 @@ class CommentRdfaTestCase extends CommentHelperCase {
 
     // Tests number of comments in teaser view.
     $this->drupalGet('node');
-    $comment_count_teaser = $this->xpath('//div[contains(@typeof, "sioc:Item")]//li[contains(@class, "comment_comments")]/a[contains(@property, "sioc:num_replies") and contains(@content, "2") and @datatype="xsd:integer"]');
+    $comment_count_teaser = $this->xpath('//div[contains(@typeof, "sioc:Item")]//li[contains(@class, "comment-comments")]/a[contains(@property, "sioc:num_replies") and contains(@content, "2") and @datatype="xsd:integer"]');
     $this->assertTrue(!empty($comment_count_teaser), t('RDFa markup for the number of comments found on teaser view.'));
 
     // Tests number of comments in full node view.
@@ -1243,15 +1248,15 @@ class CommentRdfaTestCase extends CommentHelperCase {
     $comment_container = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]');
     $this->assertTrue(!empty($comment_container), t("Comment RDF type for comment found."));
     $comment_title = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//h3[@property="dc:title"]');
-    $this->assertEqual((string)$comment_title[0]->a, $comment->subject, t("RDFa markup for the comment title found."));
+    $this->assertEqual((string) $comment_title[0]->a, $comment->subject, t("RDFa markup for the comment title found."));
     $comment_date = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//*[contains(@property, "dc:date") and contains(@property, "dc:created")]');
     $this->assertTrue(!empty($comment_date), t("RDFa markup for the date of the comment found."));
     // The author tag can be either a or span
     $comment_author = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/*[contains(@class, "username") and @typeof="sioc:UserAccount" and @property="foaf:name"]');
     $name = empty($account["name"]) ? $this->web_user->name : $account["name"] . " (not verified)";
-    $this->assertEqual((string)$comment_author[0], $name, t("RDFa markup for the comment author found."));
+    $this->assertEqual((string) $comment_author[0], $name, t("RDFa markup for the comment author found."));
     $comment_body = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//div[@class="content"]//div[contains(@class, "comment-body")]//div[@property="content:encoded"]');
-    $this->assertEqual((string)$comment_body[0]->p, $comment->comment, t("RDFa markup for the comment body found."));
+    $this->assertEqual((string) $comment_body[0]->p, $comment->comment, t("RDFa markup for the comment body found."));
   }
 }
 
diff --git a/modules/contact/contact.info b/modules/contact/contact.info
index ce836de9f462e647e5062c293b1f7664c2e67a5e..63e15e8dd9f301aa8128cb32a53821223f50423c 100644
--- a/modules/contact/contact.info
+++ b/modules/contact/contact.info
@@ -11,8 +11,8 @@ files[] = contact.install
 files[] = contact.test
 configure = admin/structure/contact
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/contextual/contextual.css b/modules/contextual/contextual.css
index 17249ddfb7fb41a13163e2bd7e2521d10ef1a334..b09bd3f2f26c02eff5a4fd307106df8c91923909 100644
--- a/modules/contextual/contextual.css
+++ b/modules/contextual/contextual.css
@@ -1,4 +1,4 @@
-/* $Id: contextual.css,v 1.4 2010/01/20 04:25:13 dries Exp $ */
+/* $Id: contextual.css,v 1.5 2010/05/05 06:38:57 webchick Exp $ */
 
 /**
  * Contextual links regions.
@@ -63,6 +63,7 @@ div.contextual-links-wrapper ul.contextual-links {
   padding: 0.25em 0;
   position: absolute;
   right: 0;
+  text-align: left;
   top: 19px;
   white-space: nowrap;
   -moz-border-radius: 4px;
diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info
index 09308f775fcd84822679616a04e057822d80b3ac..4fd93e074899feb5db29c52c2695d35c17b63b1a 100644
--- a/modules/contextual/contextual.info
+++ b/modules/contextual/contextual.info
@@ -6,8 +6,8 @@ version = VERSION
 core = 7.x
 files[] = contextual.module
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/dashboard/dashboard.css b/modules/dashboard/dashboard.css
index 07fdb00602302c91fc868ae5c028322c0737a126..80fde4c7301cce100dc91d2861789be9c349b4b6 100644
--- a/modules/dashboard/dashboard.css
+++ b/modules/dashboard/dashboard.css
@@ -1,4 +1,4 @@
-/* $Id: dashboard.css,v 1.12 2010/03/28 11:29:27 dries Exp $ */
+/* $Id: dashboard.css,v 1.13 2010/04/28 20:08:38 dries Exp $ */
 
 #dashboard div.dashboard-region {
   float: left;
@@ -26,7 +26,8 @@
   float: none;
 }
 
-#dashboard #disabled-blocks .block, #dashboard .block-placeholder {
+#dashboard #disabled-blocks .block,
+#dashboard .block-placeholder {
   background: #e2e1dc;
   padding: 6px 4px 6px 8px;
   margin: 3px 3px 3px 0;
@@ -92,7 +93,8 @@
   background: #0074BD;
 }
 
-#dashboard #disabled-blocks .block .content, #dashboard .ui-sortable-helper .content {
+#dashboard #disabled-blocks .block .content,
+#dashboard .ui-sortable-helper .content {
   display: none;
 }
 
diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info
index ac82e93228b307a7bc42e9e5750b364125c3a1c9..a92e8f279343181f7984e9ee8909cac0607faf64 100644
--- a/modules/dashboard/dashboard.info
+++ b/modules/dashboard/dashboard.info
@@ -8,8 +8,8 @@ files[] = dashboard.module
 dependencies[] = block
 configure = admin/dashboard/customize
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/dashboard/dashboard.js b/modules/dashboard/dashboard.js
index af41205a3b884874dbb1e21733109ee681cfcb72..f97218735fc353ccb800ddf5636dae78dee71626 100644
--- a/modules/dashboard/dashboard.js
+++ b/modules/dashboard/dashboard.js
@@ -1,4 +1,4 @@
-// $Id: dashboard.js,v 1.9 2010/03/28 11:29:27 dries Exp $
+// $Id: dashboard.js,v 1.11 2010/05/18 12:07:39 dries Exp $
 (function ($) {
 
 /**
@@ -8,9 +8,6 @@ Drupal.behaviors.dashboard = {
   attach: function () {
     $('#dashboard').prepend('<div class="customize"><ul class="action-links"><li><a href="#">' + Drupal.t('Customize dashboard') + '</a></li></ul><div class="canvas"></div></div>');
     $('#dashboard .customize .action-links a').click(Drupal.behaviors.dashboard.enterCustomizeMode);
-    if ($('#dashboard .region .block').length == 0) {
-      Drupal.settings.dashboard.launchCustomize = true;
-    }
     Drupal.behaviors.dashboard.addPlaceholders();
     if (Drupal.settings.dashboard.launchCustomize) {
       Drupal.behaviors.dashboard.enterCustomizeMode();
@@ -172,16 +169,15 @@ Drupal.behaviors.dashboard = {
       // Load the newly enabled block's content.
       $.get(Drupal.settings.dashboard.blockContent + '/' + module + '/' + delta, {},
         function (block) {
-          var blockContent = "";
           if (block) {
-            blockContent = $("div.content", $(block));
+            item.html(block);
           }
 
-          if (!blockContent) {
-            blockContent = $('<div class="content">' + Drupal.settings.dashboard.emptyBlockText + '</div>');
+          if (item.find('div.content').is(':empty')) {
+            item.find('div.content').html(Drupal.settings.dashboard.emptyBlockText);
           }
 
-          $("div.content", item).after(blockContent).remove();
+          Drupal.attachBehaviors(item);
         },
         'html'
       );
diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module
index 25318e1cceed62063bd36c77b3a752136316cd1d..ecd9fa5d9898350b021e82263ecd3f98d1a0d688 100644
--- a/modules/dashboard/dashboard.module
+++ b/modules/dashboard/dashboard.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: dashboard.module,v 1.27 2010/04/22 09:12:35 webchick Exp $
+// $Id: dashboard.module,v 1.29 2010/05/18 12:07:39 dries Exp $
 
 /**
  * Implements hook_help().
@@ -161,9 +161,10 @@ function dashboard_page_build(&$page) {
 function dashboard_system_info_alter(&$info, $file, $type) {
   if ($type == 'theme') {
     $info['regions'] += dashboard_region_descriptions();
-    if (module_exists('overlay')) {
-      $info['overlay_regions'] = !empty($info['overlay_regions']) ? array_merge($info['overlay_regions'], dashboard_regions()) : dashboard_regions();
-    }
+    // Indicate that these regions are intended to be displayed whenever the
+    // dashboard is displayed in an overlay. This information is provided for
+    // any module that might need to use it, not just the core Overlay module.
+    $info['overlay_regions'] = !empty($info['overlay_regions']) ? array_merge($info['overlay_regions'], dashboard_regions()) : dashboard_regions();
   }
 }
 
@@ -197,6 +198,14 @@ function dashboard_theme() {
  *   Whether to launch in customization mode right away. TRUE or FALSE.
  */
 function dashboard_admin($launch_customize = FALSE) {
+  // Only continue if provided arguments are expected. This function serves
+  // as the callback for the top-level admin/ page, so any unexpected arguments
+  // are likely the result of someone typing in the URL of an administrative
+  // page that doesn't actually exist; for example, admin/some/random/page.
+  if (!is_bool($launch_customize)) {
+    return MENU_NOT_FOUND;
+  }
+
   $js_settings = array(
     'dashboard' => array(
       'drawer' => url('admin/dashboard/drawer'),
diff --git a/modules/dblog/dblog-rtl.css b/modules/dblog/dblog-rtl.css
index 3e5ab2c676b97993793dfabf84f3f3e825ced54c..40415c7c62eefd90eb1c245b93c26c9ee7c43a48 100644
--- a/modules/dblog/dblog-rtl.css
+++ b/modules/dblog/dblog-rtl.css
@@ -1,6 +1,7 @@
-/* $Id: dblog-rtl.css,v 1.5 2009/08/24 03:11:34 webchick Exp $ */
+/* $Id: dblog-rtl.css,v 1.6 2010/04/28 20:08:38 dries Exp $ */
 
-.form-item-type, .form-item-severity {
+.form-item-type,
+.form-item-severity {
   float: right;
   padding-right: 0;
   padding-left: .8em;
diff --git a/modules/dblog/dblog.css b/modules/dblog/dblog.css
index d419ebfb2eea3a1becf0b62ff16f13cf7048d16b..954f28857166b2c92201e0e185404e30fd5e6109 100644
--- a/modules/dblog/dblog.css
+++ b/modules/dblog/dblog.css
@@ -1,6 +1,7 @@
-/* $Id: dblog.css,v 1.8 2010/01/03 21:01:04 webchick Exp $ */
+/* $Id: dblog.css,v 1.9 2010/04/28 20:08:38 dries Exp $ */
 
-.form-item-type, .form-item-severity {
+.form-item-type,
+.form-item-severity {
   float: left; /* LTR */
   padding-right: .8em; /* LTR */
   margin: 0.1em;
@@ -31,10 +32,12 @@ tr.dblog-content {
 tr.dblog-content .active {
   background: #cce;
 }
-tr.dblog-page-not-found, tr.dblog-access-denied {
+tr.dblog-page-not-found,
+tr.dblog-access-denied {
   background: #dfd;
 }
-tr.dblog-page-not-found .active, tr.dblog-access-denied .active {
+tr.dblog-page-not-found .active,
+tr.dblog-access-denied .active {
   background: #cec;
 }
 tr.dblog-error {
diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info
index be2bfd20e8a417e08d485455b6249e95ffbda347..3b61d593a05d0eab7aa7d9e0b62d607214d4cff2 100644
--- a/modules/dblog/dblog.info
+++ b/modules/dblog/dblog.info
@@ -9,8 +9,8 @@ files[] = dblog.admin.inc
 files[] = dblog.install
 files[] = dblog.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/dblog/dblog.install b/modules/dblog/dblog.install
index 2189b98ca6fae1345947e6021f8eb66bcde8d566..112d4412c59c762c04d7f06481876cf460b094df 100644
--- a/modules/dblog/dblog.install
+++ b/modules/dblog/dblog.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: dblog.install,v 1.20 2009/12/04 16:49:46 dries Exp $
+// $Id: dblog.install,v 1.21 2010/04/28 05:29:55 webchick Exp $
 
 /**
  * @file
@@ -92,24 +92,6 @@ function dblog_schema() {
   return $schema;
 }
 
-/**
- * @defgroup updates-6.x-extra Extra database logging updates for 6.x
- * @{
- */
-
-/**
- * Allow longer referrers.
- */
-function dblog_update_6000() {
-  db_change_field('watchdog', 'referer', 'referer', array('type' => 'text', 'not null' => FALSE));
-}
-
-/**
- * @} End of "defgroup updates-6.x-extra"
- * The next series of updates should start at 7000.
- */
-
-
 /**
  * @defgroup updates-6.x-to-7.x database logging updates from 6.x to 7.x
  * @{
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 382247e395129d3ebc9949285d9cb22c19fd143f..0f4078d9e0d6958cf30f4cf39f8d2e127b9c27cf 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.api.php,v 1.75 2010/04/24 07:19:09 dries Exp $
+// $Id: field.api.php,v 1.81 2010/05/18 18:30:49 dries Exp $
 
 /**
  * @ingroup field_fieldable_type
@@ -10,8 +10,8 @@
  * Expose "pseudo-field" components on fieldable entities.
  *
  * Field UI's 'Manage fields' page lets users re-order fields, but also
- * non-field components. For nodes, that would be title, menu settings, or
- * other elements exposed by contributed modules through hook_form() or
+ * non-field components. For nodes, these include the title, menu settings, and
+ * other elements exposed by contributed modules through hook_form() and
  * hook_form_alter().
  *
  * Fieldable entities or contributed modules that want to have their components
@@ -93,6 +93,7 @@ function hook_field_extra_fields_alter(&$info) {
  * can be attached to a fieldable entity. hook_field_info() defines the basic
  * properties of a field type, and a variety of other field hooks are called by
  * the Field Attach API to perform field-type-specific actions.
+ *
  * @see hook_field_info()
  * @see hook_field_info_alter()
  * @see hook_field_schema()
@@ -109,8 +110,9 @@ function hook_field_extra_fields_alter(&$info) {
  * The Field Types API also defines two kinds of pluggable handlers: widgets
  * and formatters, which specify how the field appears in edit forms and in
  * displayed entities. Widgets and formatters can be implemented by a field-type
- * module for it's own field types, or by a third-party module to extend the
+ * module for its own field types, or by a third-party module to extend the
  * behavior of existing field types.
+ *
  * @see hook_field_widget_info()
  * @see hook_field_formatter_info()
  *
@@ -131,13 +133,12 @@ function hook_field_extra_fields_alter(&$info) {
  *     settings.
  *   - instance_settings: An array whose keys are the names of the settings
  *     available for instances of the field type, and whose values are the
- *     default values for those settings.
- *     Instance-level settings can have different values on each field
- *     instance, and thus allow greater flexibility than field-level settings.
- *     It is recommended to put settings at the instance level whenever
- *     possible. Notable exceptions: settings acting on the schema definition,
- *     or settings that Views needs to use across field instances (e.g. list of
- *     allowed values).
+ *     default values for those settings. Instance-level settings can have
+ *     different values on each field instance, and thus allow greater
+ *     flexibility than field-level settings. It is recommended to put settings
+ *     at the instance level whenever possible. Notable exceptions: settings
+ *     acting on the schema definition, or settings that Views needs to use
+ *     across field instances (for example, the list of allowed values).
  *   - default_widget: The machine name of the default widget to be used by
  *     instances of this field type, when no widget is specified in the
  *     instance definition. This widget must be available whenever the field
@@ -148,6 +149,12 @@ function hook_field_extra_fields_alter(&$info) {
  *     instance definition. This formatter must be available whenever the field
  *     type is available (i.e. provided by the field type module, or by a module
  *     the field type module depends on).
+ *   - no_ui: (optional) A boolean specifying that users should not be allowed
+ *     to create fields and instances of this field type through the UI. Such
+ *     fields can only be created programmatically with field_create_field()
+ *     and field_create_instance(). Defaults to FALSE.
+ *
+ * @see hook_field_info_alter()
  */
 function hook_field_info() {
   return array(
@@ -182,7 +189,7 @@ function hook_field_info() {
  * Perform alterations on Field API field types.
  *
  * @param $info
- *   Array of informations on widget types exposed by hook_field_info()
+ *   Array of information on field types exposed by hook_field_info()
  *   implementations.
  */
 function hook_field_info_alter(&$info) {
@@ -204,23 +211,22 @@ function hook_field_info_alter(&$info) {
  *
  * @param $field
  *   A field structure.
+ *
  * @return
  *   An associative array with the following keys:
- *   - columns: An array of Schema API column specifications, keyed by column name.
- *     This specifies what comprises a value for a given field.
- *     For example, a value for a number field is simply 'value', while a
- *     value for a formatted text field is the combination of 'value' and
- *     'format'.
- *     It is recommended to avoid having the columns definitions depend on
- *     field settings when possible.
- *     No assumptions should be made on how storage engines internally use the
- *     original column name to structure their storage.
+ *   - columns: An array of Schema API column specifications, keyed by column
+ *     name. This specifies what comprises a value for a given field. For
+ *     example, a value for a number field is simply 'value', while a value for
+ *     a formatted text field is the combination of 'value' and 'format'. It is
+ *     recommended to avoid having the column definitions depend on field
+ *     settings when possible. No assumptions should be made on how storage
+ *     engines internally use the original column name to structure their
+ *     storage.
  *   - indexes: An array of Schema API indexes definitions. Only columns that
- *     appear in the 'columns' array are allowed.
- *     Those indexes will be used as default indexes. Callers of
- *     field_create_field() can specify additional indexes, or, at their own
- *     risk, modify the default indexes specified by the field-type module.
- *     Some storage engines might not support indexes.
+ *     appear in the 'columns' array are allowed. Those indexes will be used as
+ *     default indexes. Callers of field_create_field() can specify additional
+ *     indexes, or, at their own risk, modify the default indexes specified by
+ *     the field-type module. Some storage engines might not support indexes.
  */
 function hook_field_schema($field) {
   if ($field['type'] == 'text_long') {
@@ -257,10 +263,10 @@ function hook_field_schema($field) {
 }
 
 /**
- * Defines custom load behavior for this module's field types.
+ * Define custom load behavior for this module's field types.
  *
  * Unlike most other field hooks, this hook operates on multiple entities. The
- * $entities, $instances and $items parameters are arrays keyed by entity id.
+ * $entities, $instances and $items parameters are arrays keyed by entity ID.
  * For performance reasons, information for all available entity should be
  * loaded in a single query where possible.
  *
@@ -270,25 +276,26 @@ function hook_field_schema($field) {
  * hook_field_load() is run on those as well. Use
  * hook_field_formatter_prepare_view() instead.
  *
+ * Make changes or additions to field values by altering the $items parameter by
+ * reference. There is no return value.
+ *
  * @param $entity_type
  *   The type of $entity.
  * @param $entities
- *   Array of entities being loaded, keyed by entity id.
+ *   Array of entities being loaded, keyed by entity ID.
  * @param $field
  *   The field structure for the operation.
  * @param $instances
  *   Array of instance structures for $field for each entity, keyed by entity
- *   id.
+ *   ID.
  * @param $langcode
- *   The language associated to $items.
+ *   The language code associated with $items.
  * @param $items
- *   Array of field values already loaded for the entities, keyed by entity id.
+ *   Array of field values already loaded for the entities, keyed by entity ID.
+ *   Store your changes in this parameter (passed by reference).
  * @param $age
  *   FIELD_LOAD_CURRENT to load the most recent revision for all fields, or
  *   FIELD_LOAD_REVISION to load the version indicated by each entity.
- * @return
- *   Changes or additions to field values are done by altering the $items
- *   parameter by reference.
  */
 function hook_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
   // Sample code from text.module: precompute sanitized strings so they are
@@ -308,27 +315,29 @@ function hook_field_load($entity_type, $entities, $field, $instances, $langcode,
 }
 
 /**
- * Prepares field values prior to display.
+ * Prepare field values prior to display.
  *
  * This hook is invoked before the field values are handed to formatters
  * for display, and runs before the formatters' own
  * hook_field_formatter_prepare_view().
- * @see hook_field_formatter_prepare_view()
  *
  * Unlike most other field hooks, this hook operates on multiple entities. The
- * $entities, $instances and $items parameters are arrays keyed by entity id.
+ * $entities, $instances and $items parameters are arrays keyed by entity ID.
  * For performance reasons, information for all available entities should be
  * loaded in a single query where possible.
  *
+ * Make changes or additions to field values by altering the $items parameter by
+ * reference. There is no return value.
+ *
  * @param $entity_type
  *   The type of $entity.
  * @param $entities
- *   Array of entities being displayed, keyed by entity id.
+ *   Array of entities being displayed, keyed by entity ID.
  * @param $field
  *   The field structure for the operation.
  * @param $instances
  *   Array of instance structures for $field for each entity, keyed by entity
- *   id.
+ *   ID.
  * @param $langcode
  *   The language associated to $items.
  * @param $items
@@ -336,7 +345,7 @@ function hook_field_load($entity_type, $entities, $field, $instances, $langcode,
  */
 function hook_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
   // Sample code from image.module: if there are no images specified at all,
-  // use the default.
+  // use the default image.
   foreach ($entities as $id => $entity) {
     if (empty($items[$id]) && $field['settings']['default_image']) {
       if ($file = file_load($field['settings']['default_image'])) {
@@ -351,7 +360,10 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
 }
 
 /**
- * Define custom validate behavior for this module's field types.
+ * Validate this module's field data.
+ *
+ * If there are validation problems, add to the $errors array (passed by
+ * reference). There is no return value.
  *
  * @param $entity_type
  *   The type of $entity.
@@ -362,7 +374,7 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  * @param $errors
@@ -370,10 +382,11 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
  *   already been reported for the entity. The function should add its errors
  *   to this array. Each error is an associative array, with the following
  *   keys and values:
- *   - 'error': an error code (should be a string, prefixed with the module name)
- *   - 'message': the human readable message to be displayed.
+ *   - error: An error code (should be a string, prefixed with the module
+ *     name).
+ *   - message: The human readable message to be displayed.
  */
-function hook_field_validate($entity_type, $entity, $field, $instance, $langcode, &$items, &$errors) {
+function hook_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
   foreach ($items as $delta => $item) {
     if (!empty($item['value'])) {
       if (!empty($field['settings']['max_length']) && drupal_strlen($item['value']) > $field['settings']['max_length']) {
@@ -389,6 +402,9 @@ function hook_field_validate($entity_type, $entity, $field, $instance, $langcode
 /**
  * Define custom presave behavior for this module's field types.
  *
+ * Make changes or additions to field values by altering the $items parameter by
+ * reference. There is no return value.
+ *
  * @param $entity_type
  *   The type of $entity.
  * @param $entity
@@ -398,7 +414,7 @@ function hook_field_validate($entity_type, $entity, $field, $instance, $langcode
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  */
@@ -417,6 +433,8 @@ function hook_field_presave($entity_type, $entity, $field, $instance, $langcode,
 /**
  * Define custom insert behavior for this module's field types.
  *
+ * Invoked from field_attach_insert().
+ *
  * @param $entity_type
  *   The type of $entity.
  * @param $entity
@@ -426,16 +444,19 @@ function hook_field_presave($entity_type, $entity, $field, $instance, $langcode,
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  */
 function hook_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // @todo Needs function body.
 }
 
 /**
  * Define custom update behavior for this module's field types.
  *
+ * Invoked from field_attach_update().
+ *
  * @param $entity_type
  *   The type of $entity.
  * @param $entity
@@ -445,17 +466,55 @@ function hook_field_insert($entity_type, $entity, $field, $instance, $langcode,
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  */
 function hook_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // @todo Needs function body.
+}
+
+/**
+ * Update the storage information for a field.
+ *
+ * This is invoked on the field's storage module from field_update_field(),
+ * before the new field information is saved to the database. The field storage
+ * module should update its storage tables to agree with the new field
+ * information. If there is a problem, the field storage module should throw an
+ * exception.
+ *
+ * @param $field
+ *   The updated field structure to be saved.
+ * @param $prior_field
+ *   The previously-saved field structure.
+ * @param $has_data
+ *   TRUE if the field has data in storage currently.
+ */
+function hook_field_storage_update_field($field, $prior_field, $has_data) {
+  if (!$has_data) {
+    // There is no data. Re-create the tables completely.
+    $prior_schema = _field_sql_storage_schema($prior_field);
+    foreach ($prior_schema as $name => $table) {
+      db_drop_table($name, $table);
+    }
+    $schema = _field_sql_storage_schema($field);
+    foreach ($schema as $name => $table) {
+      db_create_table($name, $table);
+    }
+  }
+  else {
+    // There is data. See field_sql_storage_field_storage_update_field() for
+    // an example of what to do to modify the schema in place, preserving the
+    // old data as much as possible.
+  }
+  drupal_get_schema(NULL, TRUE);
 }
 
 /**
  * Define custom delete behavior for this module's field types.
  *
- * This hook is invoked just before the data is deleted from field storage.
+ * This hook is invoked just before the data is deleted from field storage
+ * in field_attach_delete().
  *
  * @param $entity_type
  *   The type of $entity.
@@ -466,18 +525,20 @@ function hook_field_update($entity_type, $entity, $field, $instance, $langcode,
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  */
 function hook_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // @todo Needs function body.
 }
 
 /**
- * Define custom delete_revision behavior for this module's field types.
+ * Define custom revision delete behavior for this module's field types.
  *
- * This hook is invoked just before the data is deleted from field storage,
- * and will only be called for fieldable types that are versioned.
+ * This hook is invoked just before the data is deleted from field storage
+ * in field_attach_delete_revision(), and will only be called for fieldable
+ * types that are versioned.
  *
  * @param $entity_type
  *   The type of $entity.
@@ -488,11 +549,12 @@ function hook_field_delete($entity_type, $entity, $field, $instance, $langcode,
  * @param $instance
  *   The instance structure for $field on $entity's bundle.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  */
 function hook_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // @todo Needs function body.
 }
 
 /**
@@ -523,12 +585,13 @@ function hook_field_prepare_translation($entity_type, $entity, $field, $instance
  *   An item that may or may not be empty.
  * @param $field
  *   The field to which $item belongs.
+ *
  * @return
  *   TRUE if $field's type considers $item not to contain any data;
  *   FALSE otherwise.
  */
 function hook_field_is_empty($item, $field) {
-  if (empty($item['value']) && (string)$item['value'] !== '0') {
+  if (empty($item['value']) && (string) $item['value'] !== '0') {
     return TRUE;
   }
   return FALSE;
@@ -540,16 +603,15 @@ function hook_field_is_empty($item, $field) {
  * Widgets are Form API elements with additional processing capabilities.
  * Widget hooks are typically called by the Field Attach API during the
  * creation of the field form structure with field_attach_form().
+ *
  * @see hook_field_widget_info_alter()
  * @see hook_field_widget_form()
  * @see hook_field_widget_error()
  *
  * @return
  *   An array describing the widget types implemented by the module.
- *
  *   The keys are widget type names. To avoid name clashes, widget type
  *   names should be prefixed with the name of the module that exposes them.
- *
  *   The values are arrays describing the widget type, with the following
  *   key/value pairs:
  *   - label: The human-readable name of the widget type.
@@ -558,17 +620,19 @@ function hook_field_is_empty($item, $field) {
  *   - settings: An array whose keys are the names of the settings available
  *     for the widget type, and whose values are the default values for those
  *     settings.
- *   - behaviors: (optional) An array describing behaviors of the widget.
- *     - multiple values:
- *       FIELD_BEHAVIOR_DEFAULT (default) if the widget allows the input of one
- *       single field value (most common case). The widget will be repeated for
- *       each value input.
- *       FIELD_BEHAVIOR_CUSTOM if one single copy of the widget can receive
- *       several field values. Examples: checkboxes, multiple select,
- *       comma-separated textfield...
- *     - default value:
- *       FIELD_BEHAVIOR_DEFAULT (default) if the widget accepts default values.
- *       FIELD_BEHAVIOR_NONE if the widget does not support default values.
+ *   - behaviors: (optional) An array describing behaviors of the widget, with
+ *     the following elements:
+ *     - multiple values: One of the following constants:
+ *       - FIELD_BEHAVIOR_DEFAULT: (default) If the widget allows the input of
+ *         one single field value (most common case). The widget will be
+ *         repeated for each value input.
+ *       - FIELD_BEHAVIOR_CUSTOM: If one single copy of the widget can receive
+ *         several field values. Examples: checkboxes, multiple select,
+ *         comma-separated textfield.
+ *     - default value: One of the following constants:
+ *       - FIELD_BEHAVIOR_DEFAULT: (default) If the widget accepts default
+ *         values.
+ *       - FIELD_BEHAVIOR_NONE: if the widget does not support default values.
  */
 function hook_field_widget_info() {
     return array(
@@ -602,7 +666,6 @@ function hook_field_widget_info() {
   );
 }
 
-
 /**
  * Perform alterations on Field API widget types.
  *
@@ -621,7 +684,7 @@ function hook_field_widget_info_alter(&$info) {
 }
 
 /**
- * Return a single form element for a field widget.
+ * Return the form for a single field widget.
  *
  * Field widget form elements should be based on the passed in $element, which
  * contains the base form element properties derived from the field
@@ -629,11 +692,11 @@ function hook_field_widget_info_alter(&$info) {
  *
  * Field API will set the weight, field name and delta values for each form
  * element. If there are multiple values for this field, the Field API will
- * call this function as many times as needed.
+ * invoke this hook as many times as needed.
  *
  * Note that, depending on the context in which the widget is being included
  * (regular entity edit form, 'default value' input in the field settings form,
- * etc...), the passed in values for $field and $instance might be different
+ * etc.), the passed in values for $field and $instance might be different
  * from the official definitions returned by field_info_field() and
  * field_info_instance(). If the widget uses Form API callbacks (like
  * #element_validate, #value_callback...) that need to access the $field or
@@ -651,7 +714,7 @@ function hook_field_widget_info_alter(&$info) {
  * @param $instance
  *   The field instance.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   Array of default values for this field.
  * @param $delta
@@ -672,6 +735,7 @@ function hook_field_widget_info_alter(&$info) {
  *     required.
  *   - #delta: The order of this item in the array of subelements; see $delta
  *     above.
+ *
  * @return
  *   The form elements for a single widget for this field.
  */
@@ -693,9 +757,9 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
  * @param $error
  *   An associative array with the following key-value pairs, as returned by
  *   hook_field_validate():
- *   - 'error': the error code. Complex widgets might need to report different
+ *   - error: the error code. Complex widgets might need to report different
  *     errors to different form elements inside the widget.
- *   - 'message': the human readable message to be displayed.
+ *   - message: the human readable message to be displayed.
  * @param $form
  *   The form array.
  * @param $form_state
@@ -712,17 +776,10 @@ function hook_field_widget_error($element, $error, $form, &$form_state) {
  * called by the Field Attach API field_attach_prepare_view() and
  * field_attach_view() functions.
  *
- * @see hook_field_formatter_info()
- * @see hook_field_formatter_info_alter()
- * @see hook_field_formatter_view()
- * @see hook_field_formatter_prepare_view()
- *
  * @return
  *   An array describing the formatter types implemented by the module.
- *
  *   The keys are formatter type names. To avoid name clashes, formatter type
  *   names should be prefixed with the name of the module that exposes them.
- *
  *   The values are arrays describing the formatter type, with the following
  *   key/value pairs:
  *   - label: The human-readable name of the formatter type.
@@ -731,6 +788,10 @@ function hook_field_widget_error($element, $error, $form, &$form_state) {
  *   - settings: An array whose keys are the names of the settings available
  *     for the formatter type, and whose values are the default values for
  *     those settings.
+ *
+ * @see hook_field_formatter_info_alter()
+ * @see hook_field_formatter_view()
+ * @see hook_field_formatter_prepare_view()
  */
 function hook_field_formatter_info() {
   return array(
@@ -764,7 +825,6 @@ function hook_field_formatter_info() {
   );
 }
 
-
 /**
  * Perform alterations on Field API formatter types.
  *
@@ -790,39 +850,39 @@ function hook_field_formatter_info_alter(&$info) {
  * which displays properties of the referenced entities such as name or type.
  *
  * This hook is called after the field type's own hook_field_prepare_view().
- * @see hook_field_prepare_view()
  *
  * Unlike most other field hooks, this hook operates on multiple entities. The
- * $entities, $instances and $items parameters are arrays keyed by entity id.
+ * $entities, $instances and $items parameters are arrays keyed by entity ID.
  * For performance reasons, information for all available entities should be
  * loaded in a single query where possible.
  *
  * @param $entity_type
  *   The type of $entity.
  * @param $entities
- *   Array of entities being displayed, keyed by entity id.
+ *   Array of entities being displayed, keyed by entity ID.
  * @param $field
  *   The field structure for the operation.
  * @param $instances
  *   Array of instance structures for $field for each entity, keyed by entity
- *   id.
+ *   ID.
  * @param $langcode
  *   The language the field values are to be shown in. If no language is
  *   provided the current language is used.
  * @param $items
- *   Array of field values for the entities, keyed by entity id.
+ *   Array of field values for the entities, keyed by entity ID.
  * @param $displays
- *   Array of display settings to use for each entity, keyed by entity id.
+ *   Array of display settings to use for each entity, keyed by entity ID.
+ *
  * @return
  *   Changes or additions to field values are done by altering the $items
  *   parameter by reference.
  */
 function hook_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
-
+  // @todo Needs function body.
 }
 
 /**
- * Builds a renderable array for a field value.
+ * Build a renderable array for a field value.
  *
  * @param $entity_type
  *   The type of $entity.
@@ -833,7 +893,7 @@ function hook_field_formatter_prepare_view($entity_type, $entities, $field, $ins
  * @param $instance
  *   The field instance.
  * @param $langcode
- *   The language associated to $items.
+ *   The language associated with $items.
  * @param $items
  *   Array of values for this field.
  * @param $display
@@ -903,8 +963,20 @@ function hook_field_formatter_view($entity_type, $entity, $field, $instance, $la
  * Act on field_attach_form.
  *
  * This hook is invoked after the field module has performed the operation.
+ * Implementing modules should alter the $form or $form_state parameters.
  *
- * See field_attach_form() for details and arguments.
+ * @param $entity_type
+ *   The type of $entity; for example, 'node' or 'user'.
+ * @param $entity
+ *   The entity for which to load form elements, used to initialize
+ *   default form values.
+ * @param $form
+ *   The form structure to fill in.
+ * @param $form_state
+ *   An associative array containing the current state of the form.
+ * @param $langcode
+ *   The language the field values are going to be entered in. If no language
+ *   is provided the default site language will be used.
  */
 function hook_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
   $tids = array();
@@ -945,13 +1017,13 @@ function hook_field_attach_form($entity_type, $entity, &$form, &$form_state, $la
 }
 
 /**
- * Act on field_attach_load.
+ * Act on field_attach_load().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * Unlike other field_attach hooks, this hook accounts for 'multiple loads'.
  * Instead of the usual $entity parameter, it accepts an array of entities,
- * indexed by entity id. For performance reasons, information for all available
+ * indexed by entity ID. For performance reasons, information for all available
  * entities should be loaded in a single query where possible.
  *
  * The changes made to the entities' field values get cached by the field cache
@@ -959,106 +1031,116 @@ function hook_field_attach_form($entity_type, $entity, &$form, &$form_state, $la
  *
  * See field_attach_load() for details and arguments.
  */
-function hook_field_attach_load($entity_type, $entities, $age) {
+function hook_field_attach_load($entity_type, &$entities, $age, $options) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_validate.
+ * Act on field_attach_validate().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_validate() for details and arguments.
  */
 function hook_field_attach_validate($entity_type, $entity, &$errors) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_submit.
+ * Act on field_attach_submit().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_submit() for details and arguments.
  */
 function hook_field_attach_submit($entity_type, $entity, $form, &$form_state) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_presave.
+ * Act on field_attach_presave().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_presave() for details and arguments.
  */
 function hook_field_attach_presave($entity_type, $entity) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_insert.
+ * Act on field_attach_insert().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_insert() for details and arguments.
  */
 function hook_field_attach_insert($entity_type, $entity) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_update.
+ * Act on field_attach_update().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_update() for details and arguments.
  */
 function hook_field_attach_update($entity_type, $entity) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_preprocess.
+ * Alter field_attach_preprocess() variables.
  *
- * This hook is invoked while preprocessing the field.tpl.php template file.
+ * This hook is invoked while preprocessing the field.tpl.php template file
+ * in field_attach_preprocess().
  *
  * @param $variables
  *   The variables array is passed by reference and will be populated with field
  *   values.
  * @param $context
  *   An associative array containing:
- *   - entity_type: The type of $entity; e.g. 'node' or 'user'.
- *   - object: The entity with fields to render.
+ *   - entity_type: The type of $entity; for example, 'node' or 'user'.
+ *   - entity: The entity with fields to render.
  *   - element: The structured array containing the values ready for rendering.
  */
 function hook_field_attach_preprocess_alter(&$variables, $context) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_delete.
+ * Act on field_attach_delete().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_delete() for details and arguments.
  */
 function hook_field_attach_delete($entity_type, $entity) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_delete_revision.
+ * Act on field_attach_delete_revision().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_delete_revision() for details and arguments.
  */
 function hook_field_attach_delete_revision($entity_type, $entity) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_purge_data.
+ * Act on field_purge_data().
  *
  * This hook is invoked in field_purge_data() and allows modules to act on
- * purging data from a single field pseudo-entity.  For example, if a module
+ * purging data from a single field pseudo-entity. For example, if a module
  * relates data in the field with its own data, it may purge its own data
  * during this process as well.
  *
  * @param $entity_type
- *   The type of $entity; e.g. 'node' or 'user'.
+ *   The type of $entity; for example, 'node' or 'user'.
  * @param $entity
  *   The pseudo-entity whose field data is being purged.
  * @param $field
@@ -1077,23 +1159,24 @@ function hook_field_attach_purge($entity_type, $entity, $field, $instance) {
 }
 
 /**
- * Act on field_attach_view.
+ * Perform alterations on field_attach_view().
  *
  * This hook is invoked after the field module has performed the operation.
  *
- * @param &$output
- *   The structured content array tree for all of $entity's fields.
+ * @param $output
+ *   The structured content array tree for all of the entity's fields.
  * @param $context
  *   An associative array containing:
- *   - entity_type: The type of $entity; e.g. 'node' or 'user'.
- *   - object: The entity with fields to render.
- *   - view_mode: View mode, e.g. 'full', 'teaser'...
+ *   - entity_type: The type of $entity; for example, 'node' or 'user'.
+ *   - entity: The entity with fields to render.
+ *   - view_mode: View mode, for example, 'full' or 'teaser'.
  */
 function hook_field_attach_view_alter(&$output, $context) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_language().
+ * Perform alterations on field_language() values.
  *
  * This hook is invoked to alter the array of display languages for the given
  * entity.
@@ -1107,13 +1190,14 @@ function hook_field_attach_view_alter(&$output, $context) {
  *   - langcode: The language code $entity has to be displayed in.
  */
 function hook_field_language_alter(&$display_language, $context) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_available_languages().
+ * Alter field_available_languages() values.
  *
- * This hook is invoked to alter the array of available languages for the given
- * field.
+ * This hook is invoked from field_available_languages() to allow modules to
+ * alter the array of available languages for the given field.
  *
  * @param &$languages
  *   A reference to an array of language codes to be made available.
@@ -1123,26 +1207,29 @@ function hook_field_language_alter(&$display_language, $context) {
  *   - field: A field data structure.
  */
 function hook_field_available_languages_alter(&$languages, $context) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_create_bundle.
+ * Act on field_attach_create_bundle().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_create_bundle() for details and arguments.
  */
 function hook_field_attach_create_bundle($entity_type, $bundle) {
+  // @todo Needs function body.
 }
 
 /**
- * Act on field_attach_rename_bundle.
+ * Act on field_attach_rename_bundle().
  *
  * This hook is invoked after the field module has performed the operation.
  *
  * See field_attach_rename_bundle() for details and arguments.
  */
 function hook_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1151,7 +1238,7 @@ function hook_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new)
  * This hook is invoked after the field module has performed the operation.
  *
  * @param $entity_type
- *   The type of entity; e.g. 'node' or 'user'.
+ *   The type of entity; for example, 'node' or 'user'.
  * @param $bundle
  *   The bundle that was just deleted.
  * @param $instances
@@ -1159,6 +1246,7 @@ function hook_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new)
  *   deleted.
  */
 function hook_field_attach_delete_bundle($entity_type, $bundle, $instances) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1225,14 +1313,18 @@ function hook_field_storage_info_alter(&$info) {
  *
  * @param $field
  *   A field structure.
+ *
  * @return
  *   An array of details.
  *    - The first dimension is a store type (sql, solr, etc).
  *    - The second dimension indicates the age of the values in the store
  *      FIELD_LOAD_CURRENT or FIELD_LOAD_REVISION.
  *    - Other dimensions are specific to the field storage module.
+ *
+ * @see hook_field_storage_details_alter()
  */
 function hook_field_storage_details($field) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1243,13 +1335,19 @@ function hook_field_storage_details($field) {
  *   hook_field_storage_details() implementations.
  * @param $field
  *   A field structure.
+ *
+ * @see hook_field_storage_details()
  */
 function hook_field_storage_details_alter(&$details, $field) {
+  // @todo Needs function body.
 }
 
 /**
  * Load field data for a set of entities.
  *
+ * This hook is invoked from field_attach_load() to ask the field storage
+ * module to load field data.
+ *
  * Modules implementing this hook should load field values and add them to
  * objects in $entities. Fields with no values should be added as empty
  * arrays.
@@ -1267,16 +1365,20 @@ function hook_field_storage_details_alter(&$details, $field) {
  *   depending on the $age parameter) to add each field to.
  * @param $options
  *   An associative array of additional options, with the following keys:
- *   - 'deleted': If TRUE, deleted fields should be loaded as well as
+ *   - deleted: If TRUE, deleted fields should be loaded as well as
  *     non-deleted fields. If unset or FALSE, only non-deleted fields should be
  *     loaded.
  */
-function hook_field_storage_load($entity_type, $entities, $age, $fields, $options) {
+function hook_field_storage_load($entity_type, &$entities, $age, $fields, $options) {
+  // @todo Needs function body.
 }
 
 /**
  * Write field data for an entity.
  *
+ * This hook is invoked from field_attach_insert() and field_attach_update(),
+ * to ask the field storage module to save field data.
+ *
  * @param $entity_type
  *   The entity type of entity, such as 'node' or 'user'.
  * @param $entity
@@ -1286,28 +1388,36 @@ function hook_field_storage_load($entity_type, $entities, $age, $fields, $option
  *   FIELD_STORAGE_INSERT when inserting a new entity.
  * @param $fields
  *   An array listing the fields to be written. The keys and values of the
- *   array are field ids.
+ *   array are field IDs.
  */
 function hook_field_storage_write($entity_type, $entity, $op, $fields) {
+  // @todo Needs function body.
 }
 
 /**
  * Delete all field data for an entity.
  *
+ * This hook is invoked from field_attach_delete() to ask the field storage
+ * module to delete field data.
+ *
  * @param $entity_type
  *   The entity type of entity, such as 'node' or 'user'.
  * @param $entity
  *   The entity on which to operate.
  * @param $fields
  *   An array listing the fields to delete. The keys and values of the
- *   array are field ids.
+ *   array are field IDs.
  */
 function hook_field_storage_delete($entity_type, $entity, $fields) {
+  // @todo Needs function body.
 }
 
 /**
  * Delete a single revision of field data for an entity.
  *
+ * This hook is invoked from field_attach_delete_revision() to ask the field
+ * storage module to delete field revision data.
+ *
  * Deleting the current (most recently written) revision is not
  * allowed as has undefined results.
  *
@@ -1315,58 +1425,76 @@ function hook_field_storage_delete($entity_type, $entity, $fields) {
  *   The entity type of entity, such as 'node' or 'user'.
  * @param $entity
  *   The entity on which to operate. The revision to delete is
- *   indicated by the entity's revision id property, as identified by
+ *   indicated by the entity's revision ID property, as identified by
  *   hook_fieldable_info() for $entity_type.
  * @param $fields
  *   An array listing the fields to delete. The keys and values of the
- *   array are field ids.
+ *   array are field IDs.
  */
 function hook_field_storage_delete_revision($entity_type, $entity, $fields) {
+  // @todo Needs function body.
 }
 
 /**
  * Handle a field query.
  *
+ * This hook is invoked from field_attach_query() to ask the field storage
+ * module to handle a field query.
+ *
  * @param $field_name
  *   The name of the field to query.
  * @param $conditions
- *   See field_attach_query().
- *   A storage module that doesn't support querying a given column should raise
- *   a FieldQueryException. Incompatibilities should be mentioned on the module
- *   project page.
+ *   See field_attach_query(). A storage module that doesn't support querying a
+ *   given column should raise a FieldQueryException. Incompatibilities should
+ *   be mentioned on the module project page.
  * @param $options
  *   See field_attach_query(). All option keys are guaranteed to be specified.
+ *
  * @return
  *   See field_attach_query().
  */
 function hook_field_storage_query($field_name, $conditions, $options) {
+  // @todo Needs function body
 }
 
 /**
  * Act on creation of a new field.
  *
+ * This hook is invoked from field_create_field() to ask the field storage
+ * module to save field information and prepare for storing field instances.
+ * If there is a problem, the field storage module should throw an exception.
+ *
  * @param $field
  *   The field structure being created.
  */
 function hook_field_storage_create_field($field) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on deletion of a field.
  *
+ * This hook is invoked from field_delete_field() to ask the field storage
+ * module to mark all information stored in the field for deletion.
+ *
  * @param $field
  *   The field being deleted.
  */
 function hook_field_storage_delete_field($field) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on deletion of a field instance.
  *
+ * This hook is invoked from field_delete_instance() to ask the field storage
+ * module to mark all information stored for the field instance for deletion.
+ *
  * @param $instance
  *   The instance being deleted.
  */
 function hook_field_storage_delete_instance($instance) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1396,13 +1524,14 @@ function hook_field_storage_delete_instance($instance) {
  *   that your module has already loaded a field.
  * @param $options
  *   An associative array of additional options, with the following keys:
- *   - 'field_id': The field ID that should be loaded. If unset, all fields
+ *   - field_id: The field ID that should be loaded. If unset, all fields
  *     should be loaded.
- *   - 'deleted': If TRUE, deleted fields should be loaded as well as
+ *   - deleted: If TRUE, deleted fields should be loaded as well as
  *     non-deleted fields. If unset or FALSE, only non-deleted fields should be
  *     loaded.
  */
 function hook_field_storage_pre_load($entity_type, $entities, $age, &$skip_fields, $options) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1412,15 +1541,15 @@ function hook_field_storage_pre_load($entity_type, $entities, $age, &$skip_field
  * optionally preventing the field storage module from doing so.
  *
  * @param $entity_type
- *   The type of $entity; e.g. 'node' or 'user'.
+ *   The type of $entity; for example, 'node' or 'user'.
  * @param $entity
  *   The entity with fields to save.
  * @param $skip_fields
- *   An array keyed by field ids whose data has already been written and
- *   therefore should not be written again. The values associated to these keys
- *   are not specified.
+ *   An array keyed by field IDs whose data has already been written and
+ *   therefore should not be written again. The values associated with these
+ *   keys are not specified.
  * @return
- *   Saved field ids are set set as keys in $skip_fields.
+ *   Saved field IDs are set set as keys in $skip_fields.
  */
 function hook_field_storage_pre_insert($entity_type, $entity, &$skip_fields) {
   if ($entity_type == 'node' && $entity->status && _forum_node_check_node_type($entity)) {
@@ -1449,15 +1578,15 @@ function hook_field_storage_pre_insert($entity_type, $entity, &$skip_fields) {
  * optionally preventing the field storage module from doing so.
  *
  * @param $entity_type
- *   The type of $entity; e.g. 'node' or 'user'.
+ *   The type of $entity; for example, 'node' or 'user'.
  * @param $entity
  *   The entity with fields to save.
  * @param $skip_fields
- *   An array keyed by field ids whose data has already been written and
- *   therefore should not be written again. The values associated to these keys
- *   are not specified.
+ *   An array keyed by field IDs whose data has already been written and
+ *   therefore should not be written again. The values associated with these
+ *   keys are not specified.
  * @return
- *   Saved field ids are set set as keys in $skip_fields.
+ *   Saved field IDs are set set as keys in $skip_fields.
  */
 function hook_field_storage_pre_update($entity_type, $entity, &$skip_fields) {
   $first_call = &drupal_static(__FUNCTION__, array());
@@ -1519,6 +1648,7 @@ function hook_field_storage_pre_update($entity_type, $entity, &$skip_fields) {
  *   handled.
  */
 function hook_field_storage_pre_query($field_name, $conditions, $options, &$skip_field) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1537,27 +1667,27 @@ function hook_field_storage_pre_query($field_name, $conditions, $options, &$skip
 /**
  * Act on a field being created.
  *
- * This hook is invoked after the field is created and so it cannot modify the
- * field itself.
- *
- * TODO: Not implemented.
+ * This hook is invoked from field_create_field() after the field is created, to
+ * allow modules to act on field creation.
  *
  * @param $field
  *   The field just created.
  */
 function hook_field_create_field($field) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on a field instance being created.
  *
- * This hook is invoked after the instance record is saved and so it cannot
- * modify the instance itself.
+ * This hook is invoked from field_create_instance() after the instance record
+ * is saved, so it cannot be used to modify the instance itself.
  *
  * @param $instance
  *   The instance just created.
  */
 function hook_field_create_instance($instance) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1570,16 +1700,16 @@ function hook_field_create_instance($instance) {
  * semantics, or if there are external dependencies on field settings
  * that cannot be updated.
  *
+ * To forbid the update from occurring, throw a FieldUpdateForbiddenException.
+ *
  * @param $field
  *   The field as it will be post-update.
  * @param $prior_field
  *   The field as it is pre-update.
  * @param $has_data
  *   Whether any data already exists for this field.
- * @return
- *   Throws a FieldUpdateForbiddenException to prevent the update from occurring.
  */
-function hook_field_update_field_forbid($field, $prior_field, $has_data) {
+function hook_field_update_forbid($field, $prior_field, $has_data) {
   // A 'list' field stores integer keys mapped to display values. If
   // the new field will have fewer values, and any data exists for the
   // abandoned keys, the field will have no way to display them. So,
@@ -1598,7 +1728,7 @@ function hook_field_update_field_forbid($field, $prior_field, $has_data) {
 /**
  * Act on a field being updated.
  *
- * This hook is invoked just after field is updated.
+ * This hook is invoked just after field is updated in field_update_field().
  *
  * @param $field
  *   The field as it is post-update.
@@ -1608,24 +1738,26 @@ function hook_field_update_field_forbid($field, $prior_field, $has_data) {
  *   Whether any data already exists for this field.
  */
 function hook_field_update_field($field, $prior_field, $has_data) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on a field being deleted.
  *
- * This hook is invoked just after field is deleted.
+ * This hook is invoked just after a field is deleted by field_delete_field().
  *
  * @param $field
  *   The field just deleted.
  */
 function hook_field_delete_field($field) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on a field instance being updated.
  *
- * This hook is invoked after the instance record is saved and so it cannot
- * modify the instance itself.
+ * This hook is invoked from field_update_instance() after the instance record
+ * is saved, so it cannot be used by a module to modify the instance itself.
  *
  * @param $instance
  *   The instance as it is post-update.
@@ -1633,35 +1765,44 @@ function hook_field_delete_field($field) {
  *   The instance as it was pre-update.
  */
 function hook_field_update_instance($instance, $prior_instance) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on a field instance being deleted.
  *
- * This hook is invoked just after the instance is deleted.
+ * This hook is invoked from field_delete_instance() after the instance is
+ * deleted.
  *
  * @param $instance
  *   The instance just deleted.
  */
 function hook_field_delete_instance($instance) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on field records being read from the database.
  *
+ * This hook is invoked from field_read_fields() on each field being read.
+ *
  * @param $field
  *   The field record just read from the database.
  */
-function hook_field_read_field($field) {
+function hook_field_read_field(&$field) {
+  // @todo Needs function body.
 }
 
 /**
  * Act on a field record being read from the database.
  *
+ * This hook is invoked from field_read_instances() on each instance being read.
+ *
  * @param $instance
  *   The instance record just read from the database.
  */
 function hook_field_read_instance($instance) {
+  // @todo Needs function body.
 }
 
 /**
@@ -1739,7 +1880,7 @@ function hook_field_storage_purge_field_instance($instance) {
  * module to delete field data information.
  *
  * @param $entity_type
- *   The type of $entity; e.g. 'node' or 'user'.
+ *   The type of $entity; for example, 'node' or 'user'.
  * @param $entity
  *   The pseudo-entity whose field data to delete.
  * @param $field
@@ -1774,21 +1915,23 @@ function hook_field_storage_purge($entity_type, $entity, $field, $instance) {
 /**
  * Determine whether the user has access to a given field.
  *
+ * This hook is invoked from field_access() to let modules block access to
+ * operations on fields. If no module returns FALSE, the operation is allowed.
+ *
  * @param $op
- *   The operation to be performed. Possible values:
- *   - "edit"
- *   - "view"
+ *   The operation to be performed. Possible values: 'edit', 'view'.
  * @param $field
  *   The field on which the operation is to be performed.
  * @param $entity_type
- *   The type of $entity; e.g. 'node' or 'user'.
+ *   The type of $entity; for example, 'node' or 'user'.
  * @param $entity
  *   (optional) The entity for the operation.
  * @param $account
- *   (optional) The account to check, if not given use currently logged in user.
+ *   (optional) The account to check; if not given use currently logged in user.
+ *
  * @return
- *   TRUE if the operation is allowed;
- *   FALSE if the operation is denied.
+ *   TRUE if the operation is allowed, and FALSE if the operation is denied.
  */
 function hook_field_access($op, $field, $entity_type, $entity, $account) {
+  // @todo Needs function body.
 }
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index ab4bf81d44063022015dfd169a6bd30219ddce3e..573c58bb80b7ff6dd5e9f50b80b88297f91cc81a 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.attach.inc,v 1.86 2010/04/04 12:48:18 dries Exp $
+// $Id: field.attach.inc,v 1.87 2010/05/23 07:30:56 dries Exp $
 
 /**
  * @file
@@ -555,6 +555,9 @@ function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcod
   $form['#pre_render'][] = '_field_extra_weights_pre_render';
   $form['#extra_fields'] = field_extra_fields($entity_type, $bundle);
 
+  // Save the original entity to allow later re-use.
+  $form_state['entity'] = $entity;
+
   // Let other modules make changes to the form.
   // Avoid module_invoke_all() to let parameters be taken by reference.
   foreach (module_implements('field_attach_form') as $module) {
diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc
index 071b58aa259c04bcd2c1236bda417b869f8d70b8..71aa31d11fcc569cf6bf7111f17a51d8f6a13a47 100644
--- a/modules/field/field.crud.inc
+++ b/modules/field/field.crud.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.crud.inc,v 1.57 2010/04/24 07:19:09 dries Exp $
+// $Id: field.crud.inc,v 1.59 2010/05/09 13:40:48 dries Exp $
 
 /**
  * @file
@@ -127,6 +127,8 @@
  *     field_attach_insert(), or field_attach_update().
  * - default_value_function (string)
  *     The name of the function, if any, that will provide a default value.
+ * - default_value (array)
+ *     If default_value_function is not set, then fixed values can be provided.
  * - deleted (integer, read-only)
  *     TRUE if this instance has been deleted, FALSE otherwise.
  *     Deleted instances are ignored by the Field Attach API.
@@ -225,6 +227,8 @@
  *   The $field array with the id property filled in.
  * @throw
  *   FieldException
+ *
+ * See: @link field_structs Field API data structures @endlink.
  */
 function field_create_field($field) {
   // Field name is required.
@@ -613,6 +617,8 @@ function field_delete_field($field_name) {
  *   The $instance array with the id property filled in.
  * @throw
  *   FieldException
+ *
+ * See: @link field_structs Field API data structures @endlink.
  */
 function field_create_instance($instance) {
   $field = field_read_field($instance['field_name']);
@@ -1099,7 +1105,7 @@ function field_purge_instance($instance) {
 function field_purge_field($field) {
   $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
   if (count($instances) > 0) {
-    throw new FieldException("Attempt to purge a field that still has instances.");
+    throw new FieldException("Attempt to purge a field, @field_name that still has instances.", array('@field_name' => $field['field_name']));
   }
 
   db_delete('field_config')
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index 3371ee833986d0204b98fa0b7b460ed8d4bf644c..b47f866dcde5f8a329a6af10e4706a6df7db1970 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.default.inc,v 1.34 2010/03/27 05:52:49 webchick Exp $
+// $Id: field.default.inc,v 1.35 2010/05/23 07:30:56 dries Exp $
 
 /**
  * @file
@@ -67,13 +67,23 @@ function field_default_validate($entity_type, $entity, $field, $instance, $langc
 function field_default_submit($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
   $field_name = $field['field_name'];
 
-  // Reorder items to account for drag-n-drop reordering.
-  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
-    $items = _field_sort_items($field, $items);
+  if (isset($form_state['values'][$field_name][$langcode])) {
+    // Reorder items to account for drag-n-drop reordering.
+    if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
+      $items = _field_sort_items($field, $items);
+    }
+    // Filter out empty values.
+    $items = _field_filter_items($field, $items);
+  }
+  elseif (!empty($entity->revision) && isset($form_state['entity']->{$field_name}[$langcode])) {
+    // To ensure new revisions are created with all field values in all
+    // languages, populate values not included in the form with the ones from
+    // the original object. This covers:
+    // - partial forms including only a subset of the fields,
+    // - fields for which the user has no edit access,
+    // - languages not involved in the form.
+    $items = $form_state['entity']->{$field_name}[$langcode];
   }
-
-  // Filter out empty values.
-  $items = _field_filter_items($field, $items);
 }
 
 /**
diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc
index cbc39e05d12d3f7bfd1a37d3927214c998e2e974..77bd86118f754e7e0ba9ab04a3e6c7b2ef70cdb1 100644
--- a/modules/field/field.form.inc
+++ b/modules/field/field.form.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.form.inc,v 1.47 2010/04/13 15:23:02 dries Exp $
+// $Id: field.form.inc,v 1.49 2010/05/23 07:30:56 dries Exp $
 
 /**
  * @file
@@ -16,19 +16,10 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
     list($id, , ) = entity_extract_ids($entity_type, $entity);
   }
 
+  $addition = array();
   $field_name = $field['field_name'];
   $addition[$field_name] = array();
 
-  // Store field information in $form_state['storage'].
-  $form_state['field'][$field_name][$langcode] = array(
-    'field' => $field,
-    'instance' => $instance,
-    // This entry will be populated at form build time.
-    'array_parents' => array(),
-    // This entry will be populated at form validation time.
-    'errors' => array(),
-  );
-
   // Populate widgets with default values when creating a new entity.
   if (empty($items) && empty($id)) {
     $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
@@ -79,6 +70,16 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
   }
 
   if ($elements) {
+    // Store field information in $form_state.
+    $form_state['field'][$field_name][$langcode] = array(
+      'field' => $field,
+      'instance' => $instance,
+      // This entry will be populated at form build time.
+      'array_parents' => array(),
+      // This entry will be populated at form validation time.
+      'errors' => array(),
+    );
+
     // Also aid in theming of field widgets by rendering a classified
     // container.
     $addition[$field_name] = array(
@@ -93,16 +94,6 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
       '#weight' => $instance['widget']['weight'],
     );
   }
-  else {
-    // The field is not accessible, or the widget did not return anything. Make
-    // sure the items are available in the submitted form values.
-    foreach ($items as $delta => $item) {
-      $elements[$delta] = array(
-        '#type' => 'value',
-        '#value' => $item,
-      );
-    }
-  }
 
   // Populate the 'array_parents' information in $form_state['field'] after
   // the form is built, so that we catch changes in the form structure performed
@@ -215,7 +206,6 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
           '#ajax' => array(
             'callback' => 'field_add_more_js',
             'wrapper' => $wrapper_id,
-            'method' => 'replace',
             'effect' => 'fade',
           ),
           // The field_add_more_submit() and field_add_more_js() handlers will
diff --git a/modules/field/field.info b/modules/field/field.info
index 9f3e2453cef6ef15df76d813e3fb7953bfefad28..c4178aef63f9a93291f1ea02e73ecd56a26f2763 100644
--- a/modules/field/field.info
+++ b/modules/field/field.info
@@ -16,8 +16,8 @@ files[] = tests/field.test
 dependencies[] = field_sql_storage
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info
index 60f6a00c2903ad4637a067b48a6cf6b3043095d6..34b1358a223fbd5d1b9240f4e8383f204aac0966 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.info
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.info
@@ -9,8 +9,8 @@ files[] = field_sql_storage.install
 files[] = field_sql_storage.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module b/modules/field/modules/field_sql_storage/field_sql_storage.module
index 4ce68ad922b4eba47f92142eef07d50d9ca69a27..a3c03d241e82ee1427af9273657e072d72ee6b24 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_sql_storage.module,v 1.44 2010/03/27 05:52:49 webchick Exp $
+// $Id: field_sql_storage.module,v 1.46 2010/05/06 15:29:51 dries Exp $
 
 /**
  * @file
@@ -40,7 +40,12 @@ function field_sql_storage_field_storage_info() {
  *   A string containing the generated name for the database table
  */
 function _field_sql_storage_tablename($field) {
-  return "field_data_{$field['field_name']}" . ($field['deleted'] ? "_{$field['id']}" : '');
+  if ($field['deleted']) {
+    return "field_deleted_data_{$field['id']}";
+  }
+  else {
+    return "field_data_{$field['field_name']}";
+  }
 }
 
 /**
@@ -52,7 +57,12 @@ function _field_sql_storage_tablename($field) {
  *   A string containing the generated name for the database table
  */
 function _field_sql_storage_revision_tablename($field) {
-  return "field_revision_{$field['field_name']}" . ($field['deleted'] ? "_{$field['id']}" : '');
+  if ($field['deleted']) {
+    return "field_deleted_revision_{$field['id']}";
+  }
+  else {
+    return "field_revision_{$field['field_name']}";
+  }
 }
 
 /**
@@ -218,7 +228,7 @@ function field_sql_storage_field_storage_create_field($field) {
 }
 
 /**
- * Implements hook_field_update_field_forbid().
+ * Implements hook_field_update_forbid().
  *
  * Forbid any field update that changes column definitions if there is
  * any data.
diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info
index 9f0b8adab24ee464b1934ebb38fc8c442ff14e27..ad0f9e8387ad84539962bc8c04c4f06c21292baa 100644
--- a/modules/field/modules/list/list.info
+++ b/modules/field/modules/list/list.info
@@ -8,8 +8,8 @@ files[]=list.module
 files[]=tests/list.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/list/list.module b/modules/field/modules/list/list.module
index 2a17b44f4ec7c1494a295126e904143120c8dca8..d3d7b75b7094518edb078a4a04418e52de102497 100644
--- a/modules/field/modules/list/list.module
+++ b/modules/field/modules/list/list.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: list.module,v 1.30 2010/03/27 12:49:32 dries Exp $
+// $Id: list.module,v 1.32 2010/05/12 08:55:47 dries Exp $
 
 /**
  * @file
@@ -73,7 +73,6 @@ function list_field_schema($field) {
       $columns = array(
         'value' => array(
           'type' => 'float',
-          'unsigned' => TRUE,
           'not null' => FALSE,
         ),
       );
@@ -82,7 +81,6 @@ function list_field_schema($field) {
       $columns = array(
         'value' => array(
           'type' => 'int',
-          'unsigned' => TRUE,
           'not null' => FALSE,
         ),
       );
@@ -310,7 +308,7 @@ function list_field_validate($entity_type, $entity, $field, $instance, $langcode
  * Implements hook_field_is_empty().
  */
 function list_field_is_empty($item, $field) {
-  if (empty($item['value']) && (string)$item['value'] !== '0') {
+  if (empty($item['value']) && (string) $item['value'] !== '0') {
     return TRUE;
   }
   return FALSE;
diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info
index cb448199ca64f6eca213bc0a20e5abccfd044496..afd5ddbf4c577514e5227ba3aaa961bc7787d7df 100644
--- a/modules/field/modules/list/tests/list_test.info
+++ b/modules/field/modules/list/tests/list_test.info
@@ -7,8 +7,8 @@ files[] = list_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info
index 65fee6a9428f3526c2a0b0a72a0f0ca7891692cc..20cf84eb24f1f17a994cfe8d3aab0143954e2f55 100644
--- a/modules/field/modules/number/number.info
+++ b/modules/field/modules/number/number.info
@@ -7,8 +7,8 @@ core = 7.x
 files[]=number.module
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/number/number.module b/modules/field/modules/number/number.module
index 454e2b5016e35b297492fe68578c0598933946dd..8a377e47535984c5a89c66c6c0619aff2cb041ac 100644
--- a/modules/field/modules/number/number.module
+++ b/modules/field/modules/number/number.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: number.module,v 1.38 2010/04/23 05:48:13 webchick Exp $
+// $Id: number.module,v 1.39 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -214,7 +214,7 @@ function number_field_presave($entity_type, $entity, $field, $instance, $langcod
  * Implements hook_field_is_empty().
  */
 function number_field_is_empty($item, $field) {
-  if (empty($item['value']) && (string)$item['value'] !== '0') {
+  if (empty($item['value']) && (string) $item['value'] !== '0') {
     return TRUE;
   }
   return FALSE;
diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info
index 423355b2b43c50ba612f765138cbf7a9c67ce273..64c9f8883c084af147a2423b342cc44de1bc7df0 100644
--- a/modules/field/modules/options/options.info
+++ b/modules/field/modules/options/options.info
@@ -8,8 +8,8 @@ files[]=options.module
 files[]=options.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info
index a6c4aea7f772b8ff52fe0539049e58c0e9283c50..c242cb79fcaa3699cdf7a16703cbf15af51b438e 100644
--- a/modules/field/modules/text/text.info
+++ b/modules/field/modules/text/text.info
@@ -8,8 +8,8 @@ files[] = text.module
 files[] = text.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module
index 3d41bffca93493448ba1b6ee5daf517849cecc58..83bee6df3434639f9311c4e14e39c77389deec51 100644
--- a/modules/field/modules/text/text.module
+++ b/modules/field/modules/text/text.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: text.module,v 1.53 2010/04/13 15:16:27 dries Exp $
+// $Id: text.module,v 1.54 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -221,7 +221,7 @@ function text_field_load($entity_type, $entities, $field, $instances, $langcode,
  * Implements hook_field_is_empty().
  */
 function text_field_is_empty($item, $field) {
-  if (empty($item['value']) && (string)$item['value'] !== '0') {
+  if (empty($item['value']) && (string) $item['value'] !== '0') {
     return TRUE;
   }
   return FALSE;
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index a9b4bd21f1a530dcb3f9a7459b3507f4dc9c1479..dbcdaaab24e9f99a6e3fc6fe3f0e2b0ee6899565 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.test,v 1.27 2010/04/11 18:33:43 dries Exp $
+// $Id: field.test,v 1.30 2010/05/23 07:30:56 dries Exp $
 
 /**
  * @file
@@ -1576,7 +1576,7 @@ class FieldFormTestCase extends FieldTestCase {
       // We'll need three slightly different formats to check the values.
       $values[$delta] = $value;
       $weights[$delta] = $weight;
-      $field_values[$weight]['value'] = (string)$value;
+      $field_values[$weight]['value'] = (string) $value;
       $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
     }
 
@@ -1644,7 +1644,7 @@ class FieldFormTestCase extends FieldTestCase {
       // We'll need three slightly different formats to check the values.
       $values[$delta] = $value;
       $weights[$delta] = $weight;
-      $field_values[$weight]['value'] = (string)$value;
+      $field_values[$weight]['value'] = (string) $value;
       $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
     }
     // Press 'add more' button through AJAX, and place the expected HTML result
@@ -2715,7 +2715,7 @@ class FieldTranslationsTestCase extends FieldTestCase {
 
     $results = _field_invoke('test_op', $entity_type, $entity);
     foreach ($results as $langcode => $result) {
-      $hash = md5(serialize(array($entity_type, $entity, $this->field_name, $langcode, $values[$langcode])));
+      $hash = hash('sha256', serialize(array($entity_type, $entity, $this->field_name, $langcode, $values[$langcode])));
       // Check whether the parameters passed to _field_invoke() were correctly
       // forwarded to the callback function.
       $this->assertEqual($hash, $result, t('The result for %language is correctly stored.', array('%language' => $langcode)));
@@ -2757,7 +2757,7 @@ class FieldTranslationsTestCase extends FieldTestCase {
     $grouped_results = _field_invoke_multiple('test_op_multiple', $entity_type, $entities);
     foreach ($grouped_results as $id => $results) {
       foreach ($results as $langcode => $result) {
-        $hash = md5(serialize(array($entity_type, $entities[$id], $this->field_name, $langcode, $values[$id][$langcode])));
+        $hash = hash('sha256', serialize(array($entity_type, $entities[$id], $this->field_name, $langcode, $values[$id][$langcode])));
         // Check whether the parameters passed to _field_invoke() were correctly
         // forwarded to the callback function.
         $this->assertEqual($hash, $result, t('The result for entity %id/%language is correctly stored.', array('%id' => $id, '%language' => $langcode)));
@@ -2878,6 +2878,51 @@ class FieldTranslationsTestCase extends FieldTestCase {
     $langcode = field_language($entity_type, $entity, $this->field_name, $requested_language);
     $this->assertTrue(isset($entity->{$this->field_name}[$langcode]) && $langcode != $requested_language, t('The display language for the (single) field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
   }
+
+  /**
+   * Tests field translations when creating a new revision.
+   */
+  function testFieldFormTranslationRevisions() {
+    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $this->drupalLogin($web_user);
+
+    // Prepare the field translations.
+    field_test_entity_info_translatable($this->entity_type, TRUE);
+    $eid = 1;
+    $entity = field_test_create_stub_entity($eid, $eid, $this->instance['bundle']);
+    $available_languages = array_flip(field_available_languages($this->entity_type, $this->field));
+    unset($available_languages[LANGUAGE_NONE]);
+    $field_name = $this->field['field_name'];
+
+    // Store the field translations.
+    $entity->is_new = TRUE;
+    foreach ($available_languages as $langcode => $value) {
+      $entity->{$field_name}[$langcode][0]['value'] = $value + 1;
+    }
+    field_test_entity_save($entity);
+
+    // Create a new revision.
+    $langcode = field_valid_language(NULL);
+    $edit = array("{$field_name}[$langcode][0][value]" => $entity->{$field_name}[$langcode][0]['value'], 'revision' => TRUE);
+    $this->drupalPost('test-entity/' . $eid . '/edit', $edit, t('Save'));
+
+    // Check translation revisions.
+    $this->checkTranslationRevisions($eid, $eid, $available_languages);
+    $this->checkTranslationRevisions($eid, $eid + 1, $available_languages);
+  }
+
+  /**
+   * Check if the field translation attached to the entity revision identified
+   * by the passed arguments were correctly stored.
+   */
+  private function checkTranslationRevisions($eid, $evid, $available_languages) {
+    $field_name = $this->field['field_name'];
+    $entity = field_test_entity_test_load($eid, $evid);
+    foreach ($available_languages as $langcode => $value) {
+      $passed = isset($entity->{$field_name}[$langcode]) && $entity->{$field_name}[$langcode][0]['value'] == $value + 1;
+      $this->assertTrue($passed, t('The @language translation for revision @revision was correctly stored', array('@language' => $langcode, '@revision' => $entity->ftvid)));
+    }
+  }
 }
 
 /**
diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc
index 77203a6deed5455392f27761fb2d21b3a5f81012..066e7e687fd579a6dc745f96955bd7aae175bd1d 100644
--- a/modules/field/tests/field_test.entity.inc
+++ b/modules/field/tests/field_test.entity.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_test.entity.inc,v 1.7 2010/03/27 18:41:14 dries Exp $
+// $Id: field_test.entity.inc,v 1.9 2010/05/23 07:30:56 dries Exp $
 
 /**
  * @file
@@ -164,11 +164,19 @@ function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = 'test_bundle
 function field_test_entity_test_load($ftid, $ftvid = NULL) {
   // Load basic strucure.
   $query = db_select('test_entity', 'fte', array())
-    ->fields('fte')
-    ->condition('ftid', $ftid);
+    ->condition('fte.ftid', $ftid);
+
   if ($ftvid) {
-    $query->condition('ftvid', $ftvid);
+    $query->join('test_entity_revision', 'fter', 'fte.ftid = fter.ftid');
+    $query->addField('fte', 'ftid');
+    $query->addField('fte', 'fttype');
+    $query->addField('fter', 'ftvid');
+    $query->condition('fter.ftvid', $ftvid);
+  }
+  else {
+    $query->fields('fte');
   }
+
   $entities = $query->execute()->fetchAllAssoc('ftid');
 
   // Attach fields.
@@ -255,9 +263,9 @@ function field_test_entity_edit($entity) {
  */
 function field_test_entity_form($form, &$form_state, $entity, $add = FALSE) {
   if (isset($form_state['test_entity'])) {
-    $entity = $form_state['test_entity'] + (array)$entity;
+    $entity = $form_state['test_entity'] + (array) $entity;
   }
-  $entity = (object)$entity;
+  $entity = (object) $entity;
 
   foreach (array('ftid', 'ftvid', 'fttype') as $key) {
     $form[$key] = array(
@@ -325,7 +333,7 @@ function field_test_entity_form_submit_builder($form, &$form_state) {
   $entity->revision = !empty($form_state['values']['revision']);
   field_attach_submit('test_entity', $entity, $form, $form_state);
 
-  $form_state['test_entity'] = (array)$entity;
+  $form_state['test_entity'] = (array) $entity;
   $form_state['rebuild'] = TRUE;
 
   return $entity;
diff --git a/modules/field/tests/field_test.field.inc b/modules/field/tests/field_test.field.inc
index 8bd55c2e1647f36b3e9f8a5af3aa95220662f3cb..50d96811e415843efb130526337ac612d50a4533 100644
--- a/modules/field/tests/field_test.field.inc
+++ b/modules/field/tests/field_test.field.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_test.field.inc,v 1.9 2010/03/12 19:51:40 dries Exp $
+// $Id: field_test.field.inc,v 1.10 2010/05/18 18:30:49 dries Exp $
 
 /**
  * @file
@@ -12,7 +12,7 @@
 function field_test_field_info() {
   return array(
     'test_field' => array(
-      'label' => t('Test Field'),
+      'label' => t('Test field'),
       'description' => t('Dummy field type used for tests.'),
       'settings' => array(
         'test_field_setting' => 'dummy test string',
@@ -26,6 +26,15 @@ function field_test_field_info() {
       'default_widget' => 'test_field_widget',
       'default_formatter' => 'field_test_default',
     ),
+    'hidden_test_field' => array(
+      'no_ui' => TRUE,
+      'label' => t('Hidden from UI test field'),
+      'description' => t('Dummy hidden field type used for tests.'),
+      'settings' => array(),
+      'instance_settings' => array(),
+      'default_widget' => 'test_field_widget',
+      'default_formatter' => 'field_test_default',
+    ),
   );
 }
 
@@ -139,7 +148,7 @@ function field_test_field_widget_info() {
   return array(
     'test_field_widget' => array(
       'label' => t('Test field'),
-      'field types' => array('test_field'),
+      'field types' => array('test_field', 'hidden_test_field'),
       'settings' => array('test_widget_setting' => 'dummy test string'),
     ),
     'test_field_widget_multiple' => array(
diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info
index 325e8abb49872266d42896cea80ca58ff4899ac8..09940f99cdb844637e6e2e0d1306d163c671c717 100644
--- a/modules/field/tests/field_test.info
+++ b/modules/field/tests/field_test.info
@@ -11,8 +11,8 @@ files[] = field_test.install
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module
index 7cd2e3266b907c25933a3d6c94534f5599e06d71..3900a0b7b3bf2dd0a2681348778faf0379e00459 100644
--- a/modules/field/tests/field_test.module
+++ b/modules/field/tests/field_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_test.module,v 1.6 2010/03/25 11:46:20 dries Exp $
+// $Id: field_test.module,v 1.7 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -69,7 +69,7 @@ function field_test_menu() {
  * This simulates a field operation callback to be invoked by _field_invoke().
  */
 function field_test_field_test_op($entity_type, $entity, $field, $instance, $langcode, &$items) {
-  return array($langcode => md5(serialize(array($entity_type, $entity, $field['field_name'], $langcode, $items))));
+  return array($langcode => hash('sha256', serialize(array($entity_type, $entity, $field['field_name'], $langcode, $items))));
 }
 
 /**
@@ -81,7 +81,7 @@ function field_test_field_test_op($entity_type, $entity, $field, $instance, $lan
 function field_test_field_test_op_multiple($entity_type, $entities, $field, $instances, $langcode, &$items) {
   $result = array();
   foreach ($entities as $id => $entity) {
-    $result[$id] = array($langcode => md5(serialize(array($entity_type, $entity, $field['field_name'], $langcode, $items[$id]))));
+    $result[$id] = array($langcode => hash('sha256', serialize(array($entity_type, $entity, $field['field_name'], $langcode, $items[$id]))));
   }
   return $result;
 }
diff --git a/modules/field/theme/field-rtl.css b/modules/field/theme/field-rtl.css
index 90bcc73e808d7bd298e742260f7362bef0aeb1ef..723eac49590a127db3b0cd9b149364cca9d12628 100644
--- a/modules/field/theme/field-rtl.css
+++ b/modules/field/theme/field-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: field-rtl.css,v 1.1 2009/03/30 05:28:41 webchick Exp $ */
+/* $Id: field-rtl.css,v 1.2 2010/05/22 20:23:01 dries Exp $ */
 
 form .field-multiple-table th.field-label {
   padding-right: 0;
@@ -9,3 +9,7 @@ form .field-multiple-table td.field-multiple-drag {
 form .field-multiple-table td.field-multiple-drag a.tabledrag-handle{
   padding-left: .5em;
 }
+.field-label-inline .field-label,
+.field-label-inline .field-items {
+  float: right;
+}
diff --git a/modules/field/theme/field.css b/modules/field/theme/field.css
index 44518619b0933e34a51f4b914eef86b8c32b2649..e23f50d21f23b6ad1dd6c7ffd142a7228b8eed59 100644
--- a/modules/field/theme/field.css
+++ b/modules/field/theme/field.css
@@ -1,4 +1,4 @@
-/* $Id: field.css,v 1.8 2009/11/11 08:32:35 dries Exp $ */
+/* $Id: field.css,v 1.9 2010/05/22 20:23:01 dries Exp $ */
 
 /* Field display */
 .field .field-label {
@@ -6,7 +6,7 @@
 }
 .field-label-inline .field-label,
 .field-label-inline .field-items {
-  float:left;
+  float:left; /*LTR*/
 }
 
 /* Form display */
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index f8070016a88b8188a9cb58203be8ad816f6957e8..629abcc340e4df38de738dce06f757afd658821a 100644
--- a/modules/field_ui/field_ui.admin.inc
+++ b/modules/field_ui/field_ui.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_ui.admin.inc,v 1.49 2010/04/24 14:49:13 dries Exp $
+// $Id: field_ui.admin.inc,v 1.50 2010/05/18 18:30:49 dries Exp $
 
 /**
  * @file
@@ -703,8 +703,9 @@ function field_ui_field_type_options() {
     $field_types = field_info_field_types();
     $field_type_options = array();
     foreach ($field_types as $name => $field_type) {
-      // Skip field types which have no widget types.
-      if (field_ui_widget_type_options($name)) {
+      // Skip field types which have no widget types, or should not be add via
+      // uesr interface.
+      if (field_ui_widget_type_options($name) && empty($field_type['no_ui'])) {
         $options[$name] = $field_type['label'];
       }
     }
@@ -793,10 +794,13 @@ function field_ui_existing_field_options($entity_type, $bundle) {
           // Don't show
           // - locked fields,
           // - fields already in the current bundle,
-          // - field that cannot be added to the entity type.
+          // - fields that cannot be added to the entity type,
+          // - fields that that shoud not be added via user interface.
+
           if (empty($field['locked'])
             && !field_info_instance($entity_type, $field['field_name'], $bundle)
-            && (empty($field['entity_types']) || in_array($entity_type, $field['entity_types']))) {
+            && (empty($field['entity_types']) || in_array($entity_type, $field['entity_types']))
+            && empty($field_types[$field['type']]['no_ui'])) {
             $text = t('@type: @field (@label)', array(
               '@type' => $field_types[$field['type']]['label'],
               '@label' => t($instance['label']), '@field' => $instance['field_name'],
diff --git a/modules/field_ui/field_ui.api.php b/modules/field_ui/field_ui.api.php
index 04eb99cc1f07df6ca1c992586f60ef3ad7e23f22..f5ed10256ad1d26fc3cb4cd1bc4224c5ecefe1dc 100644
--- a/modules/field_ui/field_ui.api.php
+++ b/modules/field_ui/field_ui.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_ui.api.php,v 1.5 2010/04/26 14:40:47 dries Exp $
+// $Id: field_ui.api.php,v 1.6 2010/05/04 16:11:08 dries Exp $
 
 /**
  * @file
@@ -12,11 +12,12 @@
  */
 
 /**
- * Field settings form.
+ * Add settings to a field settings form.
  *
- * The field type module is responsible for not returning form elements that
- * cannot be changed. It may not always be possible to tell in advance, but
- * modules should attempt to inform the user what is going/likely to work.
+ * Invoked from field_ui_field_settings_form() to allow the module defining the
+ * field to add global settings (i.e. settings that do not depend on the bundle
+ * or instance) to the field settings form. If the field already has data, only
+ * include settings that are safe to change.
  *
  * @todo: Only the field type module knows which settings will affect the
  * field's schema, but only the field storage module knows what schema
@@ -30,7 +31,8 @@
  * @param $instance
  *   The instance structure being configured.
  * @param $has_data
- *   Whether the field already has data.
+ *   TRUE if the field already has data, FALSE if not.
+ *
  * @return
  *   The form definition for the field settings.
  */
@@ -48,12 +50,16 @@ function hook_field_settings_form($field, $instance, $has_data) {
 }
 
 /**
- * Instance settings form.
+ * Add settings to an instance field settings form.
+ *
+ * Invoked from field_ui_field_edit_form() to allow the module defining the
+ * field to add settings for a field instance.
  *
  * @param $field
  *   The field structure being configured.
  * @param $instance
  *   The instance structure being configured.
+ *
  * @return
  *   The form definition for the field instance settings.
  */
@@ -86,12 +92,16 @@ function hook_field_instance_settings_form($field, $instance) {
 }
 
 /**
- * Widget settings form.
+ * Add settings to a widget settings form.
+ *
+ * Invoked from field_ui_field_edit_form() to allow the module defining the
+ * widget to add settings for a widget instance.
  *
  * @param $field
  *   The field structure being configured.
  * @param $instance
  *   The instance structure being configured.
+ *
  * @return
  *   The form definition for the widget settings.
  */
@@ -121,27 +131,6 @@ function hook_field_widget_settings_form($field, $instance) {
   return $form;
 }
 
-/**
- * Formatter settings form.
- *
- * @todo Not implemented yet. The signature below is only prospective, but
- * providing $instance is not enough, since one $instance holds several display
- * settings.
- *
- * @param $formatter
- *   The type of the formatter being configured.
- * @param $settings
- *   The current values of the formatter settings.
- * @param $field
- *   The field structure being configured.
- * @param $instance
- *   The instance structure being configured.
- * @return
- *   The form definition for the formatter settings.
- */
-function hook_field_formatter_settings_form($formatter, $settings, $field, $instance) {
-}
-
 /**
  * Provide information on view mode tabs for an entity type.
  *
diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info
index b2331b32a5f7c3729d908468d9bcfae8323ea7ee..989fcc6d37a9a88414f0b3d5356bf56ca06dc327 100644
--- a/modules/field_ui/field_ui.info
+++ b/modules/field_ui/field_ui.info
@@ -8,8 +8,8 @@ files[] = field_ui.module
 files[] = field_ui.admin.inc
 files[] = field_ui.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test
index d5601635241604ad5a6b92d6578994c55ce4e1d9..337dba1bc271ef6f10414cd47357c69c18df92a0 100644
--- a/modules/field_ui/field_ui.test
+++ b/modules/field_ui/field_ui.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_ui.test,v 1.15 2010/04/07 17:30:43 dries Exp $
+// $Id: field_ui.test,v 1.16 2010/05/18 18:30:49 dries Exp $
 
 /**
  * @file
@@ -125,7 +125,7 @@ class FieldUITestCase extends DrupalWebTestCase {
    */
   function addExistingField() {
     // Check "Add existing field" appears.
-    $this->drupalGet(('admin/structure/types/manage/page/fields'));
+    $this->drupalGet('admin/structure/types/manage/page/fields');
     $this->assertRaw(t('Add existing field'), t('"Add existing field" was found.'));
 
     // Check that the list of options respects entity type restrictions on
@@ -263,6 +263,41 @@ class FieldUITestCase extends DrupalWebTestCase {
     $this->assertNull(field_info_field($this->field_name), t('Field was deleted.'));
   }
 
+  /**
+   * Test that Field UI respects the 'no_ui' option in hook_field_info().
+   */
+  function testHiddenFields() {
+    $bundle_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/';
+
+    // Check that the field type is not available in the 'add new field' row.
+    $this->drupalGet($bundle_path);
+    $this->assertFalse($this->xpath('//select[@id="edit--add-new-field-type"]//option[@value="hidden_test_field"]'), t("The 'add new field' select respects field types 'no_ui' property."));
+
+    // Create a field and an instance programmatically.
+    $field_name = 'hidden_test_field';
+    field_create_field(array('field_name' => $field_name, 'type' => $field_name));
+    $instance = array(
+      'field_name' => $field_name,
+      'bundle' => $this->type,
+      'entity_type' => 'node',
+      'label' => t('Hidden field'),
+      'widget_type' => 'test_field_widget',
+    );
+    field_create_instance($instance);
+    $this->assertTrue(field_read_instance('node', $field_name, $this->type), t('An instance of the field %field was created programmatically.', array('%field' => $field_name)));
+
+    // Check that the newly added instance appears on the 'Manage Fields'
+    // screen.
+    $this->drupalGet($bundle_path);
+    $this->assertFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $instance['label'], t('Field was created and appears in the overview page.'));
+
+    // Check that the instance does not appear in the 'add existing field' row
+    // on other bundles.
+    $bundle_path = 'admin/structure/types/manage/article/fields/';
+    $this->drupalGet($bundle_path);
+    $this->assertFalse($this->xpath('//select[@id="edit--add-existing-field-field-name"]//option[@value=:field_name]', array(':field_name' => $field_name)), t("The 'add existing field' select respects field types 'no_ui' property."));
+  }
+
   /**
    * Create a new field through the Field UI.
    *
diff --git a/modules/file/file.info b/modules/file/file.info
index 5e8edc90e2b068257588814de83ad4b77d407856..8e37c4cab32e8508c35e934aacc369c3c6de2da5 100644
--- a/modules/file/file.info
+++ b/modules/file/file.info
@@ -9,8 +9,8 @@ files[] = file.field.inc
 files[] = file.install
 files[] = tests/file.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/file/file.js b/modules/file/file.js
index 837e15c4c67e8ea1a4aa1471b8dd2dd79d6df7e6..f89ab8a794c6d8ae984cf0c81e95abc4ca1b4416 100644
--- a/modules/file/file.js
+++ b/modules/file/file.js
@@ -1,4 +1,4 @@
-// $Id: file.js,v 1.2 2010/04/21 07:40:37 webchick Exp $
+// $Id: file.js,v 1.3 2010/05/01 21:55:13 dries Exp $
 
 /**
  * @file
@@ -31,7 +31,7 @@ Drupal.behaviors.fileButtons = {
     $('input.form-submit', context).bind('mousedown', Drupal.file.disableFields);
     $('div.form-managed-file input.form-submit', context).bind('mousedown', Drupal.file.progressBar);
   },
-  unattach: function (context) {
+  detach: function (context) {
     $('input.form-submit', context).unbind('mousedown', Drupal.file.disableFields);
     $('div.form-managed-file input.form-submit', context).unbind('mousedown', Drupal.file.progressBar);
   }
diff --git a/modules/file/file.module b/modules/file/file.module
index b8f78b7775c6fb476a957ca99ad6aa7bff3d7943..738aa5d9b2b783a124cc39ec31ce0e8783e63402 100644
--- a/modules/file/file.module
+++ b/modules/file/file.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.module,v 1.25 2010/04/13 15:23:03 dries Exp $
+// $Id: file.module,v 1.28 2010/05/09 19:34:26 dries Exp $
 
 /**
  * @file
@@ -351,7 +351,6 @@ function file_managed_file_process($element, &$form_state, $form) {
   $ajax_settings = array(
     'path' => 'file/ajax/' . implode('/', $element['#parents']) . '/' . $form['form_build_id']['#value'],
     'wrapper' => $element['#id'] . '-ajax-wrapper',
-    'method' => 'replace',
     'effect' => 'fade',
     'progress' => array(
       'type' => $element['#progress_indicator'],
@@ -411,7 +410,7 @@ function file_managed_file_process($element, &$form_state, $form) {
 
   // Add progress bar support to the upload if possible.
   if ($element['#progress_indicator'] == 'bar' && $implementation = file_progress_implementation()) {
-    $upload_progress_key = md5(mt_rand());
+    $upload_progress_key = mt_rand();
 
     if ($implementation == 'uploadprogress') {
       $element['UPLOAD_IDENTIFIER'] = array(
@@ -651,10 +650,10 @@ function theme_file_link($variables) {
 
   // Use the description as the link text if available.
   if (empty($file->description)) {
-    $link_text = check_plain($file->filename);
+    $link_text = $file->filename;
   }
   else {
-    $link_text = check_plain($file->description);
+    $link_text = $file->description;
     $options['attributes']['title'] = check_plain($file->filename);
   }
 
diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info
index 45a8f9930c6cb9f6be2ac7bc0694f43908cc9057..5a9f9fbdcea83d5062a9dfe42ec62852886e8917 100644
--- a/modules/file/tests/file_module_test.info
+++ b/modules/file/tests/file_module_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = file_module_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/filter/filter.info b/modules/filter/filter.info
index 067d223b93ed3574f9e1adf26b8362b8759c336c..960b0d53f80c98bda362b31cdd764d7db0c98952 100644
--- a/modules/filter/filter.info
+++ b/modules/filter/filter.info
@@ -12,8 +12,8 @@ files[] = filter.test
 required = TRUE
 configure = admin/config/content/formats
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/filter/filter.install b/modules/filter/filter.install
index c4cf99fd76066beda04d51a6989997901be61909..03e370d46be0e62a14c9964b3128dbf471da7722 100644
--- a/modules/filter/filter.install
+++ b/modules/filter/filter.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.install,v 1.36 2010/04/22 05:44:41 webchick Exp $
+// $Id: filter.install,v 1.37 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -98,7 +98,7 @@ function filter_schema() {
   );
 
   $schema['cache_filter'] = drupal_get_schema_unprocessed('system', 'cache');
-  $schema['cache_filter']['description'] = 'Cache table for the Filter module to store already filtered pieces of text, identified by text format and md5 hash of the text.';
+  $schema['cache_filter']['description'] = 'Cache table for the Filter module to store already filtered pieces of text, identified by text format and hash of the text.';
 
   return $schema;
 }
diff --git a/modules/filter/filter.js b/modules/filter/filter.js
index 6e3758318a99d41c02452a56796babae7b06dbd3..7c09fd46d29331c32766d4a0d3f3042709a68afc 100644
--- a/modules/filter/filter.js
+++ b/modules/filter/filter.js
@@ -1,4 +1,4 @@
-// $Id: filter.js,v 1.1 2010/03/07 23:59:20 webchick Exp $
+// $Id: filter.js,v 1.2 2010/04/30 07:48:07 dries Exp $
 (function ($) {
 
 /**
@@ -12,7 +12,7 @@ Drupal.behaviors.filterGuidelines = {
       .bind('change', function () {
         $(this).parents('.filter-wrapper')
           .find('.filter-guidelines-item').hide()
-          .siblings('#filter-guidelines-' + this.value).show();
+          .siblings('.filter-guidelines-' + this.value).show();
       })
       .change();
   }
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index bcd8605ae036a5486e25bfa7eecae45a450f68c8..16e13fa703336e060302a383c74300031d9259bf 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.module,v 1.328 2010/04/24 14:53:59 dries Exp $
+// $Id: filter.module,v 1.331 2010/05/13 07:53:02 dries Exp $
 
 /**
  * @file
@@ -681,7 +681,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
   $cache = $cache && !empty($format->cache);
   $cache_id = '';
   if ($cache) {
-    $cache_id = $format->format . ':' . $langcode . ':' . md5($text);
+    $cache_id = $format->format . ':' . $langcode . ':' . hash('sha256', $text);
     if ($cached = cache_get($cache_id, 'cache_filter')) {
       return $cached->data;
     }
@@ -730,29 +730,12 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
  *   the text format id specified in #format or the user's default format by
  *   default, if NULL.
  *
- * Since most modules expect the value of the new 'format' element *next* to the
- * original element, filter_process_format() utilizes an #after_build to move
- * the values of the children of the 'text_format' element so as to let the
- * submitted form values appear as if they were located on the same level.
- * For example, considering the input values:
+ * The resulting value for the element will be an array holding the value and the
+ * format.  For example, the value for the body element will be:
  * @code
- *   $form_state['input']['body']['value'] = 'foo';
- *   $form_state['input']['body']['format'] = 'foo';
+ *   $form_state['values']['body']['value'] = 'foo';
+ *   $form_state['values']['body']['format'] = 'foo';
  * @endcode
- * The #after_build will process them into:
- * @code
- *   $form_state['values']['body'] = 'foo';
- *   $form_state['values']['format'] = 'foo';
- * @endcode
- *
- * If multiple text format-enabled elements are required on the same level of
- * the form structure, modules can set custom #parents on the original element.
- * Alternatively, the #after_build may be unset through a subsequent #process
- * callback. If the default #after_build is not invoked and no custom processing
- * occurs, then the submitted form values will appear like in the
- * $form_state['input'] array above.
- *
- * @see filter_form_after_build()
  *
  * @param $element
  *   The form element to process. Properties used:
@@ -804,9 +787,6 @@ function filter_process_format($element) {
   $element['#attached']['js'][] = $path . '/filter.js';
   $element['#attached']['css'][] = $path . '/filter.css';
 
-  // Apply default #after_build behavior.
-  $element['#after_build'][] = 'filter_form_after_build';
-
   // Setup child container for the text format widget.
   $element['format'] = array(
     '#type' => 'fieldset',
@@ -886,38 +866,6 @@ function filter_process_format($element) {
   return $element;
 }
 
-/**
- * After build callback to move #type 'text_format' values up in $form_state.
- */
-function filter_form_after_build($element, &$form_state) {
-  // For text fields, the additional subkeys map 1:1 to field schema columns.
-  if (isset($element['#columns'])) {
-    return $element;
-  }
-
-  $parents = $element['#parents'];
-  array_pop($parents);
-
-  foreach (element_children($element) as $key) {
-    $current_parents = $parents;
-    switch ($key) {
-      case 'value':
-        form_set_value(array('#parents' => $element['#parents']), $element[$key]['#value'], $form_state);
-        break;
-
-      case 'format':
-        $current_parents[] = $key;
-        form_set_value(array('#parents' => $current_parents), $element['format']['format']['#value'], $form_state);
-        break;
-
-      default:
-        $current_parents[] = $key;
-        form_set_value(array('#parents' => $current_parents), $element[$key]['#value'], $form_state);
-    }
-  }
-  return $element;
-}
-
 /**
  * #pre_render callback for #type 'text_format' to hide field value from prying eyes.
  *
@@ -1122,7 +1070,9 @@ function theme_filter_guidelines($variables) {
   $format = $variables['format'];
 
   $name = isset($format->name) ? '<label>' . $format->name . ':</label>' : '';
-  return '<div id="filter-guidelines-' . $format->format . '" class="filter-guidelines-item">' . $name . theme('filter_tips', array('tips' => _filter_tips($format->format, FALSE))) . '</div>';
+  $attributes['class'][] = 'filter-guidelines-item';
+  $attributes['class'][] = 'filter-guidelines-' . $format->format;
+  return '<div' . drupal_attributes($attributes) . '>' . $name . theme('filter_tips', array('tips' => _filter_tips($format->format, FALSE))) . '</div>';
 }
 
 /**
diff --git a/modules/forum/forum-topic-list.tpl.php b/modules/forum/forum-topic-list.tpl.php
index 9c8ce3e4169d3c94e639edf1fbca9b2aa0bc96ed..89566c4685ff05b5f718d39a1d44560913dd58f3 100644
--- a/modules/forum/forum-topic-list.tpl.php
+++ b/modules/forum/forum-topic-list.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum-topic-list.tpl.php,v 1.9 2010/03/26 17:14:45 dries Exp $
+// $Id: forum-topic-list.tpl.php,v 1.10 2010/04/28 20:25:21 dries Exp $
 
 /**
  * @file
@@ -7,7 +7,7 @@
  *
  * Available variables:
  * - $header: The table header. This is pre-generated with click-sorting
- *   information. If you need to change this, see 
+ *   information. If you need to change this, see
  *   template_preprocess_forum_topic_list().
  * - $pager: The pager to display beneath the table.
  * - $topics: An array of topics to be displayed.
diff --git a/modules/forum/forum.css b/modules/forum/forum.css
index 530b6a39f77e61a6d752ef47cb71c24d56c83e7d..19d75ea5812689ee99a5f0b12fea670b649289e7 100644
--- a/modules/forum/forum.css
+++ b/modules/forum/forum.css
@@ -1,10 +1,15 @@
-/* $Id: forum.css,v 1.7 2009/08/22 15:26:04 dries Exp $ */
+/* $Id: forum.css,v 1.8 2010/04/28 20:08:38 dries Exp $ */
 
 #forum .description {
   font-size: 0.9em;
   margin: 0.5em;
 }
-#forum td.created, #forum td.posts, #forum td.topics, #forum td.last-reply, #forum td.replies, #forum td.pager {
+#forum td.created,
+#forum td.posts,
+#forum td.topics,
+#forum td.last-reply,
+#forum td.replies,
+#forum td.pager {
   white-space: nowrap;
 }
 #forum tr td.forum {
diff --git a/modules/forum/forum.info b/modules/forum/forum.info
index 7b7a88c570ee87945908060f6d7a8ea21c4ca56b..177f519ebc46d670ac7419855c83a77d21a88ff4 100644
--- a/modules/forum/forum.info
+++ b/modules/forum/forum.info
@@ -13,8 +13,8 @@ files[] = forum.install
 files[] = forum.test
 configure = admin/structure/forum
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/forum/forum.install b/modules/forum/forum.install
index 49aa336bb83b7f49bc3c809294876ff8cd275ae3..2931135e3f1648ac83204ba3fd7978092f7f2db6 100644
--- a/modules/forum/forum.install
+++ b/modules/forum/forum.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.install,v 1.45 2010/04/26 14:32:27 dries Exp $
+// $Id: forum.install,v 1.46 2010/05/05 06:55:25 webchick Exp $
 
 /**
  * @file
@@ -80,6 +80,10 @@ function forum_enable() {
     $term = (object) $edit;
     taxonomy_term_save($term);
   }
+  // Ensure the forum node type is available.
+  node_types_rebuild();
+  $types = node_type_get_types();
+  node_add_body_field($types['forum']);
 }
 
 /**
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index a9088ed08c26d1df2f5bce401dbb5f335b6bb986..d2c72b7967077f86ac6bd93ffc90c246ee18c81c 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.module,v 1.564 2010/04/26 14:32:27 dries Exp $
+// $Id: forum.module,v 1.565 2010/04/28 05:54:55 webchick Exp $
 
 /**
  * @file
@@ -94,6 +94,13 @@ function forum_menu() {
     'access arguments' => array('access content'),
     'file' => 'forum.pages.inc',
   );
+  $items['forum/%forum_forum'] = array(
+    'title' => 'Forums',
+    'page callback' => 'forum_page',
+    'page arguments' => array(1),
+    'access arguments' => array('access content'),
+    'file' => 'forum.pages.inc',
+  );
   $items['admin/structure/forum'] = array(
     'title' => 'Forums',
     'description' => 'Control forum hierarchy settings.',
@@ -163,9 +170,8 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
   // Add action link to 'node/add/forum' on 'forum' page.
   if ($root_path == 'forum') {
     $tid = (isset($router_item['page_arguments'][0]) ? $router_item['page_arguments'][0] : 0);
-    $forums = forum_get_forums($tid);
-    $parents = taxonomy_get_parents_all($tid);
-    if ($forums || $parents) {
+    $forum_term = forum_forum_load($tid);
+    if ($forum_term) {
       $vid = variable_get('forum_nav_vocabulary', 0);
       $vocabulary = taxonomy_vocabulary_load($vid);
 
@@ -178,7 +184,7 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
             '#theme' => 'menu_local_action',
             '#link' => array(
               'title' => t('Add new @node_type', array('@node_type' => node_type_get_name($type))),
-              'href' => 'node/add/' . str_replace('_', '-', $type) . '/' . $tid,
+              'href' => 'node/add/' . str_replace('_', '-', $type) . '/' . $forum_term->tid,
             ),
           );
         }
@@ -723,27 +729,54 @@ function forum_form($node, $form_state) {
 }
 
 /**
- * Returns a list of all forums for a given taxonomy id
- *
- * Forum objects contain the following fields
- * -num_topics Number of topics in the forum
- * -num_posts Total number of posts in all topics
- * -last_post Most recent post for the forum
+ * Returns a tree of all forums for a given taxonomy term ID.
  *
  * @param $tid
- *   Taxonomy ID of the vocabulary that holds the forum list.
+ *    (optional) Taxonomy ID of the forum, if not givin all forums will be returned.
  * @return
- *   Array of object containing the forum information.
+ *   A tree of taxonomy objects, with the following additional properties:
+ *    - 'num_topics': Number of topics in the forum
+ *    - 'num_posts': Total number of posts in all topics
+ *    - 'last_post': Most recent post for the forum
+ *    - 'forums': An array of child forums
  */
-function forum_get_forums($tid = 0) {
+function forum_forum_load($tid = NULL) {
   $cache = &drupal_static(__FUNCTION__, array());
 
+  // Return a cached forum tree if available.
+  if (!isset($tid)) {
+    $tid = 0;
+  }
   if (isset($cache[$tid])) {
     return $cache[$tid];
   }
 
-  $forums = array();
   $vid = variable_get('forum_nav_vocabulary', 0);
+
+  // Load and validate the parent term.
+  if ($tid) {
+    $forum_term = taxonomy_term_load($tid);
+    if (!$forum_term || ($forum_term->vid != $vid)) {
+      return $cache[$tid] = FALSE;
+    }
+  }
+  // If $tid is 0, create an empty object to hold the child terms.
+  else if ($tid === 0) {
+    $forum_term = (object) array(
+      'tid' => 0,
+    );
+  }
+
+  // Determine if the requested term is a container.
+  if (!$forum_term->tid || in_array($forum_term->tid, variable_get('forum_containers', array()))) {
+    $forum_term->container = 1;
+  }
+
+  // Load parent terms.
+  $forum_term->parents = taxonomy_get_parents_all($forum_term->tid);
+
+  // Load the tree below.
+  $forums = array();
   $_forums = taxonomy_get_tree($vid, $tid);
 
   if (count($_forums)) {
@@ -762,10 +795,12 @@ function forum_get_forums($tid = 0) {
   }
 
   foreach ($_forums as $forum) {
+    // Determine if the child term is a container.
     if (in_array($forum->tid, variable_get('forum_containers', array()))) {
       $forum->container = 1;
     }
 
+    // Merge in the topic and post counters.
     if (!empty($counts[$forum->tid])) {
       $forum->num_topics = $counts[$forum->tid]->topic_count;
       $forum->num_posts = $counts[$forum->tid]->topic_count + $counts[$forum->tid]->comment_count;
@@ -775,6 +810,7 @@ function forum_get_forums($tid = 0) {
       $forum->num_posts = 0;
     }
 
+    // Query "Last Post" information for this forum.
     $query = db_select('node', 'n');
     $query->join('users', 'u1', 'n.uid = u1.uid');
     $query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $forum->tid));
@@ -791,6 +827,7 @@ function forum_get_forums($tid = 0) {
       ->execute()
       ->fetchObject();
 
+    // Merge in the "Last Post" information.
     $last_post = new stdClass();
     if (!empty($topic->last_comment_timestamp)) {
       $last_post->created = $topic->last_comment_timestamp;
@@ -802,9 +839,10 @@ function forum_get_forums($tid = 0) {
     $forums[$forum->tid] = $forum;
   }
 
-  $cache[$tid] = $forums;
-
-  return $forums;
+  // Cache the result, and return the tree.
+  $forum_term->forums = $forums;
+  $cache[$tid] = $forum_term;
+  return $forum_term;
 }
 
 /**
diff --git a/modules/forum/forum.pages.inc b/modules/forum/forum.pages.inc
index 2dc002f9711fc23d4d5cd60ea36f2432c7859b58..6acdb23ae51a0475299f19e7d877b5c450eef183 100644
--- a/modules/forum/forum.pages.inc
+++ b/modules/forum/forum.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.pages.inc,v 1.3 2009/10/09 00:59:59 dries Exp $
+// $Id: forum.pages.inc,v 1.4 2010/04/28 05:54:55 webchick Exp $
 
 /**
  * @file
@@ -9,16 +9,21 @@
 /**
  * Menu callback; prints a forum listing.
  */
-function forum_page($tid = 0) {
-  $topics = '';
+function forum_page($forum_term = NULL) {
+  if (!isset($forum_term)) {
+    // On the main page, display all the top-level forums.
+    $forum_term = forum_forum_load(0);
+  }
+
   $forum_per_page = variable_get('forum_per_page', 25);
   $sortby = variable_get('forum_order', 1);
 
-  $forums = forum_get_forums($tid);
-  $parents = taxonomy_get_parents_all($tid);
-  if ($tid && !in_array($tid, variable_get('forum_containers', array()))) {
-    $topics = forum_get_topics($tid, $sortby, $forum_per_page);
+  if (empty($forum_term->container)) {
+    $topics = forum_get_topics($forum_term->tid, $sortby, $forum_per_page);
+  }
+  else {
+    $topics = '';
   }
 
-  return theme('forums', array('forums' => $forums, 'topics' => $topics, 'parents' => $parents, 'tid' => $tid, 'sortby' => $sortby, 'forums_per_page' => $forum_per_page));
+  return theme('forums', array('forums' => $forum_term->forums, 'topics' => $topics, 'parents' => $forum_term->parents, 'tid' => $forum_term->tid, 'sortby' => $sortby, 'forums_per_page' => $forum_per_page));
 }
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
index caaabb9501d9733530e0078b80c43fb9fc82b248..7860937eaa9b7b8a59d7d95721699cd78de2eced 100644
--- a/modules/forum/forum.test
+++ b/modules/forum/forum.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.test,v 1.55 2010/04/26 14:32:27 dries Exp $
+// $Id: forum.test,v 1.56 2010/04/28 05:54:55 webchick Exp $
 
 class ForumTestCase extends DrupalWebTestCase {
   protected $admin_user;
@@ -268,7 +268,7 @@ class ForumTestCase extends DrupalWebTestCase {
 
     // Assert that the forum no longer exists.
     $this->drupalGet('forum/' . $tid);
-    $this->assertRaw(t('No forums defined'), 'The forum was not found');
+    $this->assertResponse(404, 'The forum was not found');
   }
 
   /**
diff --git a/modules/help/help.info b/modules/help/help.info
index c73eda75d8c7070268d71ec8f79bab0ce7bb6eab..ce75a2da33e058c8233d689c165e827bf1fad493 100644
--- a/modules/help/help.info
+++ b/modules/help/help.info
@@ -8,8 +8,8 @@ files[] = help.module
 files[] = help.admin.inc
 files[] = help.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/image/image.effects.inc b/modules/image/image.effects.inc
index 94d92961e906c99e0fd363ef6f6f278ad41a36e8..401061f91b41e89d8b0b3af32ed18dbbb3f3a67c 100644
--- a/modules/image/image.effects.inc
+++ b/modules/image/image.effects.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.effects.inc,v 1.4 2010/03/26 17:14:45 dries Exp $
+// $Id: image.effects.inc,v 1.5 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -232,7 +232,7 @@ function image_rotate_effect(&$image, $data) {
   }
 
   if (!empty($data['random'])) {
-    $degrees = abs((float)$data['degrees']);
+    $degrees = abs((float) $data['degrees']);
     $data['degrees'] = rand(-1 * $degrees, $degrees);
   }
 
diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc
index 9c89707cad122e84ae6195d1e71bd85d96b1f424..43f5a2dbca59c07bdf130ab0b9a2775966536486 100644
--- a/modules/image/image.field.inc
+++ b/modules/image/image.field.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.field.inc,v 1.20 2010/04/13 15:23:03 dries Exp $
+// $Id: image.field.inc,v 1.21 2010/04/30 12:53:47 dries Exp $
 
 /**
  * @file
@@ -511,8 +511,11 @@ function theme_image_formatter($variables) {
   $image = array(
     'path' => $item['uri'],
     'alt' => $item['alt'],
-    'title' => $item['title'],
   );
+  // Do not output an empty 'title' attribute.
+  if (drupal_strlen($item['title']) > 0) {
+    $image['title'] = $item['title'];
+  }
 
   if ($variables['image_style']) {
     $image['style_name'] = $variables['image_style'];
diff --git a/modules/image/image.info b/modules/image/image.info
index 8e29c076d8dab3be3fbef63b17fe2e2736d3b90d..be5083cd688b21fecef2ddf7b925d7d71adf5a62 100644
--- a/modules/image/image.info
+++ b/modules/image/image.info
@@ -13,8 +13,8 @@ files[] = image.install
 files[] = image.test
 configure = admin/config/media/image-styles
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/image/image.module b/modules/image/image.module
index c21b1373028ec13c585923cb85edc00e2cd60007..e5bc1c62021e25657389b35160973b54e7a01cc1 100644
--- a/modules/image/image.module
+++ b/modules/image/image.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.module,v 1.40 2010/04/23 07:54:44 webchick Exp $
+// $Id: image.module,v 1.42 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -178,7 +178,7 @@ function image_theme() {
         'style_name' => NULL,
         'path' => NULL,
         'alt' => '',
-        'title' => '',
+        'title' => NULL,
         'attributes' => array(),
         'getsize' => TRUE,
       ),
@@ -632,19 +632,19 @@ function image_style_generate() {
   $path = implode('/', $args);
 
   $path = $scheme . '://' . $path;
-  $path_md5 = md5($path);
+  $path_hash = drupal_hash_base64($path);
   $destination = image_style_path($style['name'], $path);
 
   // Check that it's a defined style and that access was granted by
   // image_style_url().
-  if (!$style || !cache_get('access:' . $style_name . ':' . $path_md5, 'cache_image')) {
+  if (!$style || !cache_get('access:' . $style_name . ':' . $path_hash, 'cache_image')) {
     drupal_access_denied();
     drupal_exit();
   }
 
   // Don't start generating the image if the derivate already exists or if
   // generation is in progress in another thread.
-  $lock_name = 'image_style_generate:' . $style_name . ':' . $path_md5;
+  $lock_name = 'image_style_generate:' . $style_name . ':' . $path_hash;
   if (!file_exists($destination)) {
     $lock_acquired = lock_acquire($lock_name);
     if (!$lock_acquired) {
@@ -783,7 +783,7 @@ function image_style_url($style_name, $path) {
 
   // Set a cache entry to grant access to this style/image path. This will be
   // checked by image_style_generate().
-  cache_set('access:' . $style_name . ':' . md5($path), 1, 'cache_image', REQUEST_TIME + 600);
+  cache_set('access:' . $style_name . ':' . drupal_hash_base64($path), 1, 'cache_image', REQUEST_TIME + 600);
 
   $scheme = file_uri_scheme($path);
   $target = file_uri_target($path);
diff --git a/modules/image/image.test b/modules/image/image.test
index 340c65f8e5749a7d2110f837ef3bb8f32ab49259..625ba2b60ba109571324948d784f2cded7bcc913 100644
--- a/modules/image/image.test
+++ b/modules/image/image.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.test,v 1.20 2010/04/22 21:43:59 webchick Exp $
+// $Id: image.test,v 1.21 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -190,7 +190,7 @@ class ImageStylesPathAndUrlUnitTest extends DrupalWebTestCase {
 
     // Fetch the URL that generates the file while another process appears to
     // be generating the same file (this is signaled using a lock).
-    $lock_name = 'image_style_generate:' . $this->style_name . ':' . md5($original_uri);
+    $lock_name = 'image_style_generate:' . $this->style_name . ':' . drupal_hash_base64($original_uri);
     $this->assertTrue(lock_acquire($lock_name), t('Lock was acquired.'));
     $this->drupalGet($expected_generate_url);
     $this->assertResponse(503, t('Service Unavailable response received.'));
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index 437f31b4017337c1910bd3448ef63ca424b84d39..bd7b1b950bc69027d95bb2e8d1ac662615481cc7 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.admin.inc,v 1.12 2010/04/24 14:49:14 dries Exp $
+// $Id: locale.admin.inc,v 1.13 2010/05/11 10:49:37 dries Exp $
 
 /**
  * @file
@@ -337,13 +337,23 @@ function locale_languages_predefined_form_submit($form, &$form_state) {
   }
 
   $form_state['redirect'] = 'admin/config/regional/language';
-  return;
 }
 
 /**
  * Validate the language editing form. Reused for custom language addition too.
  */
 function locale_languages_edit_form_validate($form, &$form_state) {
+  // Ensure sane field values for langcode, name, and native.
+  if (!isset($form['langcode_view']) && preg_match('@[^a-zA-Z_-]@', $form_state['values']['langcode'])) {
+    form_set_error('langcode', t('%field may only contain characters a-z, underscores, or hyphens.', array('%field' => $form['langcode']['#title'])));
+  }
+  if ($form_state['values']['name'] != check_plain($form_state['values']['name'])) {
+    form_set_error('name', t('%field cannot contain any markup.', array('%field' => $form['name']['#title'])));
+  }
+  if ($form_state['values']['native'] != check_plain($form_state['values']['native'])) {
+    form_set_error('native', t('%field cannot contain any markup.', array('%field' => $form['native']['#title'])));
+  }
+
   if (!empty($form_state['values']['domain']) && !empty($form_state['values']['prefix'])) {
     form_set_error('prefix', t('Domain and path prefix values should not be set at the same time.'));
   }
diff --git a/modules/locale/locale.api.php b/modules/locale/locale.api.php
index d54b4b4d08396304f3c4020cff4a1525479084ff..a09535b01fa94477e9dc996e2bc03d40aca3f2df 100644
--- a/modules/locale/locale.api.php
+++ b/modules/locale/locale.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.api.php,v 1.10 2010/04/07 05:15:51 dries Exp $
+// $Id: locale.api.php,v 1.11 2010/05/12 08:26:14 dries Exp $
 
 /**
  * @file
@@ -151,7 +151,7 @@ function hook_language_negotiation_info() {
       'types' => array('custom_language_type'),
       'name' => t('Custom language provider'),
       'description' => t('This is a custom language provider.'),
-      'cache' => CACHE_DISABLED,
+      'cache' => 0,
     ),
   );
 }
diff --git a/modules/locale/locale.css b/modules/locale/locale.css
index be5746052942714854612696b0349715bdc3af6a..ea5676a0b6f563d0d52204547effa03c7bf03c5b 100644
--- a/modules/locale/locale.css
+++ b/modules/locale/locale.css
@@ -1,11 +1,13 @@
-/* $Id: locale.css,v 1.6 2010/01/03 21:01:04 webchick Exp $ */
+/* $Id: locale.css,v 1.7 2010/04/28 20:08:38 dries Exp $ */
 
 .locale-untranslated {
   font-style: normal;
   text-decoration: line-through;
 }
 
-.form-item-language, .form-item-translation, .form-item-group {
+.form-item-language,
+.form-item-translation,
+.form-item-group {
   float: left; /* LTR */
   padding-right: .8em; /* LTR */
   margin: 0.1em;
diff --git a/modules/locale/locale.datepicker.js b/modules/locale/locale.datepicker.js
new file mode 100644
index 0000000000000000000000000000000000000000..681a2cc0e067feadaec3dc62f5e8fbe07dbe9d86
--- /dev/null
+++ b/modules/locale/locale.datepicker.js
@@ -0,0 +1,70 @@
+// $Id: locale.datepicker.js,v 1.1 2010/04/29 05:15:43 webchick Exp $
+(function ($) {
+
+$.datepicker.regional['drupal-locale'] = {
+  closeText: Drupal.t('Done'),
+  prevText: Drupal.t('Prev'),
+  nextText: Drupal.t('Next'),
+  currentText: Drupal.t('Today'),
+  monthNames: [
+    Drupal.t('January'),
+    Drupal.t('February'),
+    Drupal.t('March'),
+    Drupal.t('April'),
+    Drupal.t('May'),
+    Drupal.t('June'),
+    Drupal.t('July'),
+    Drupal.t('August'),
+    Drupal.t('September'),
+    Drupal.t('October'),
+    Drupal.t('November'),
+    Drupal.t('December')
+  ],
+  monthNamesShort: [
+    Drupal.t('Jan'),
+    Drupal.t('Feb'),
+    Drupal.t('Mar'),
+    Drupal.t('Apr'),
+    Drupal.t('May'),
+    Drupal.t('Jun'),
+    Drupal.t('Jul'),
+    Drupal.t('Aug'),
+    Drupal.t('Sep'),
+    Drupal.t('Oct'),
+    Drupal.t('Nov'),
+    Drupal.t('Dec')
+  ],
+  dayNames: [
+    Drupal.t('Sunday'),
+    Drupal.t('Monday')
+    Drupal.t('Tuesday')
+    Drupal.t('Wednesday')
+    Drupal.t('Thursday')
+    Drupal.t('Friday')
+    Drupal.t('Saturday')
+  ],
+  dayNamesShort: [
+    Drupal.t('Sun')
+    Drupal.t('Mon')
+    Drupal.t('Tue')
+    Drupal.t('Wed')
+    Drupal.t('Thu')
+    Drupal.t('Fri')
+    Drupal.t('Sat')
+  ],
+  dayNamesMin: [
+    Drupal.t('Su')
+    Drupal.t('Mo')
+    Drupal.t('Tu')
+    Drupal.t('We')
+    Drupal.t('Th')
+    Drupal.t('Fr')
+    Drupal.t('Sa')
+  ],
+  dateFormat: Drupal.t('mm/dd/yy'),
+  firstDay: Drupal.settings.jqueryuidatepicker.firstDay,
+  isRTL: Drupal.settings.jqueryuidatepicker.rtl
+};
+$.datepicker.setDefaults($.datepicker.regional['drupal-locale']);
+
+})(jQuery);
diff --git a/modules/locale/locale.info b/modules/locale/locale.info
index 8b2b1a9d73e5445b042db189683b42f3775e0ed9..6558742d10a3faf108d48ae05292fb78f089ffaa 100644
--- a/modules/locale/locale.info
+++ b/modules/locale/locale.info
@@ -10,8 +10,8 @@ files[] = locale.admin.inc
 files[] = locale.test
 configure = admin/config/regional/language
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/locale/locale.install b/modules/locale/locale.install
index 93fb79349c66ab2049282437292025b0a256aa2b..73d35370a2fb6adf4dad00478b769004427ecf7c 100644
--- a/modules/locale/locale.install
+++ b/modules/locale/locale.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.install,v 1.57 2010/03/25 11:46:21 dries Exp $
+// $Id: locale.install,v 1.58 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -81,6 +81,13 @@ function locale_update_7001() {
   return array();
 }
 
+/**
+ * Allow longer javascript file names.
+ */
+function locale_update_7002() {
+  db_change_field('languages', 'javascript', 'javascript', array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''));
+}
+
 /**
  * @} End of "defgroup updates-6.x-to-7.x"
  */
@@ -207,7 +214,7 @@ function locale_schema() {
       ),
       'javascript' => array(
         'type' => 'varchar',
-        'length' => 32,
+        'length' => 64,
         'not null' => TRUE,
         'default' => '',
         'description' => 'Location of JavaScript translation file.',
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index b3cfac9b045a4f57125746a25cc2f61aaa9ba3c1..e396cefbe784ad942ac30ff20ae01949af4269ad 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.module,v 1.291 2010/04/08 18:16:43 dries Exp $
+// $Id: locale.module,v 1.293 2010/05/12 08:26:14 dries Exp $
 
 /**
  * @file
@@ -589,7 +589,7 @@ function locale_language_negotiation_info() {
     'callbacks' => array('language' => 'locale_language_from_browser'),
     'file' => $file,
     'weight' => -2,
-    'cache' => CACHE_DISABLED,
+    'cache' => 0,
     'name' => t('Browser'),
     'description' => t("Determine the language from the browser's language settings."),
   );
@@ -892,6 +892,28 @@ function locale_css_alter(&$css) {
   }
 }
 
+ /**
+ * Implement hook_library_alter().
+ *
+ * Provides the language support for the jQuery UI Date Picker.
+ */
+function locale_library_alter(&$libraries, $module) {
+  global $language;
+  if ($module == 'system' && isset($libraries['system']['ui.datepicker'])) {
+    $datepicker = drupal_get_path('module', 'locale') . '/locale.datepicker.js';
+    $libraries['system']['ui.datepicker']['js'][$datepicker] = array('weight' => JS_THEME);
+    $libraries['system']['ui.datepicker']['js'][] = array(
+      'data' => array(
+        'jqueryuidatepicker' => array(
+          'rtl' => $language->direction == LANGUAGE_RTL,
+          'firstDay' => variable_get('date_first_day', 0),
+        ),
+      ),
+      'type' => 'setting',
+    );
+  }
+}
+
 // ---------------------------------------------------------------------------------
 // Language switcher block
 
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 1f31b7f2532c80e9e6454ecdf3022cee43584d3c..5ef82f811a10c24e9faec1732be486874d8461fb 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.test,v 1.69 2010/03/31 20:05:06 dries Exp $
+// $Id: locale.test,v 1.70 2010/04/28 05:12:43 webchick Exp $
 
 /**
  * @file
@@ -957,6 +957,35 @@ EOF;
 
 }
 
+/**
+ * Tests for the st() function.
+ */
+class LocaleInstallTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'String translation using st()',
+      'description' => 'Tests that st() works like t().',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+
+    // st() lives in install.inc, so ensure that it is loaded for all tests.
+    require_once DRUPAL_ROOT . '/includes/install.inc';
+  }
+
+  /**
+   * Verify that function signatures of t() and st() are equal.
+   */
+  function testFunctionSignatures() {
+    $reflector_t = new ReflectionFunction('t');
+    $reflector_st = new ReflectionFunction('st');
+    $this->assertEqual($reflector_t->getParameters(), $reflector_st->getParameters(), t('Function signatures of t() and st() are equal.'));
+  }
+}
+
 /**
  * Locale uninstall with English UI functional test.
  */
@@ -1106,7 +1135,7 @@ class LocaleUninstallFrenchFunctionalTest extends LocaleUninstallFunctionalTest
 /**
  * Functional tests for the language switching feature.
  */
-class LanguageSwitchingFunctionalTest extends DrupalWebTestCase {
+class LocaleLanguageSwitchingFunctionalTest extends DrupalWebTestCase {
 
   public static function getInfo() {
     return array(
@@ -1280,7 +1309,7 @@ class LocaleUserLanguageFunctionalTest extends DrupalWebTestCase {
 /**
  * Functional test for language handling during user creation.
  */
-class LocalUserCreationTest extends DrupalWebTestCase {
+class LocaleUserCreationTest extends DrupalWebTestCase {
 
   public static function getInfo() {
     return array(
@@ -1606,7 +1635,7 @@ class LocaleContentFunctionalTest extends DrupalWebTestCase {
  *        http://example.cn/admin/config
  *          UI language in Chinese
  */
-class UILanguageNegotiationTest extends DrupalWebTestCase {
+class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
       'name' => 'UI language negotiation',
@@ -1904,7 +1933,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
 /**
  * Functional tests for localizing date formats.
  */
-class LocalizeDateFormatsFunctionalTest extends DrupalWebTestCase {
+class LocaleDateFormatsFunctionalTest extends DrupalWebTestCase {
 
   public static function getInfo() {
     return array(
@@ -1969,3 +1998,4 @@ class LocalizeDateFormatsFunctionalTest extends DrupalWebTestCase {
     $this->assertText($french_date, t('French date format appears'));
   }
 }
+
diff --git a/modules/locale/tests/locale_test.info b/modules/locale/tests/locale_test.info
index 395f532f20dc0bbbbce2f5a87de03ac24f588b3f..4cbb417e0a424bfd1fd5f70cc1ce915328e6cf4c 100644
--- a/modules/locale/tests/locale_test.info
+++ b/modules/locale/tests/locale_test.info
@@ -7,8 +7,8 @@ files[] = locale_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc
index 76bbc80f3e290698bc28753cbaf5168f863f63f0..5e391ae650240d16a71de39d16975289895351f5 100644
--- a/modules/menu/menu.admin.inc
+++ b/modules/menu/menu.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.admin.inc,v 1.78 2010/04/24 14:49:14 dries Exp $
+// $Id: menu.admin.inc,v 1.79 2010/05/04 20:31:53 dries Exp $
 
 /**
  * @file
@@ -181,6 +181,7 @@ function menu_overview_form_submit($form, &$form_state) {
     $item['customized'] = 1;
     menu_link_save($item);
   }
+  drupal_set_message(t('Your configuration has been saved.'));
 }
 
 /**
@@ -403,6 +404,9 @@ function menu_edit_item_submit($form, &$form_state) {
   if (!menu_link_save($item)) {
     drupal_set_message(t('There was an error saving the menu link.'), 'error');
   }
+  else {
+    drupal_set_message(t('Your configuration has been saved.'));
+  }
   $form_state['redirect'] = 'admin/structure/menu/manage/' . $item['menu_name'];
 }
 
@@ -605,6 +609,7 @@ function menu_edit_menu_submit($form, &$form_state) {
       menu_link_save($link);
     }
   }
+  drupal_set_message(t('Your configuration has been saved.'));
   $form_state['redirect'] = $path . $menu['menu_name'];
 }
 
diff --git a/modules/menu/menu.api.php b/modules/menu/menu.api.php
index 5f629f0e83daa399a01cd3f53498a88a0ef2e675..12ccabd61641c44d1cf03e1c54c2092176fc77c6 100644
--- a/modules/menu/menu.api.php
+++ b/modules/menu/menu.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.api.php,v 1.24 2010/01/30 07:59:25 dries Exp $
+// $Id: menu.api.php,v 1.25 2010/04/28 05:08:24 webchick Exp $
 
 /**
  * @file
@@ -11,393 +11,6 @@
  * @{
  */
 
-/**
- * Define menu items and page callbacks.
- *
- * This hook enables modules to register paths in order to define how URL
- * requests are handled. Paths may be registered for URL handling only, or they
- * can register a link to be placed in a menu (usually the Navigation menu). A
- * path and its associated information is commonly called a "menu router item".
- * This hook is rarely called (for example, when modules are enabled), and
- * its results are cached in the database.
- *
- * hook_menu() implementations return an associative array whose keys define
- * paths and whose values are an associative array of properties for each
- * path. (The complete list of properties is in the return value section below.)
- *
- * The definition for each path may include a page callback function, which is
- * invoked when the registered path is requested. If there is no other
- * registered path that fits the requested path better, any further path
- * components are passed to the callback function. For example, your module
- * could register path 'abc/def':
- * @code
- *   function mymodule_menu() {
- *     $items['abc/def'] = array(
- *       'page callback' => 'mymodule_abc_view',
- *     );
- *   }
- *
- *   function mymodule_abc_view($ghi = 0, $jkl = '') {
- *     // ...
- *   }
- * @endcode
- * When path 'abc/def' is requested, no further path components are in the
- * request, and no additional arguments are passed to the callback function (so
- * $ghi and $jkl would take the default values as defined in the function
- * signature). When 'abc/def/123/foo' is requested, $ghi will be '123' and
- * $jkl will be 'foo'. Note that this automatic passing of optional path
- * arguments applies only to page and theme callback functions.
- *
- * In addition to optional path arguments, the page callback and other callback
- * functions may specify argument lists as arrays. These argument lists may
- * contain both fixed/hard-coded argument values and integers that correspond
- * to path components. When integers are used and the callback function is
- * called, the corresponding path components will be substituted for the
- * integers. That is, the integer 0 in an argument list will be replaced with
- * the first path component, integer 1 with the second, and so on (path
- * components are numbered starting from zero). This substitution feature allows
- * you to re-use a callback function for several different paths. For example:
- * @code
- *   function mymodule_menu() {
- *     $items['abc/def'] = array(
- *       'page callback' => 'mymodule_abc_view',
- *       'page arguments' => array(1, 'foo'),
- *     );
- *   }
- * @endcode
- * When path 'abc/def' is requested, the page callback function will get 'def'
- * as the first argument and (always) 'foo' as the second argument.
- *
- * Note that if a page or theme callback function has an argument list array,
- * these arguments will be passed first to the function, followed by any
- * any arguments generated by optional path arguments as described above.
- *
- * Special care should be taken for the page callback drupal_get_form(), because
- * your specific form callback function will always receive $form and
- * &$form_state as the first function arguments:
- * @code
- *   function mymodule_abc_form($form, &$form_state) {
- *     // ...
- *     return $form;
- *   }
- * @endcode
- * See @link form_api Form API documentation @endlink for details.
- *
- * Wildcards within paths also work with integer substitution. For example,
- * your module could register path 'my-module/%/edit':
- * @code
- *   $items['my-module/%/edit'] = array(
- *     'page callback' => 'mymodule_abc_edit',
- *     'page arguments' => array(1),
- *   );
- * @endcode
- * When path 'my-module/foo/edit' is requested, integer 1 will be replaced
- * with 'foo' and passed to the callback function.
- *
- * Registered paths may also contain special "auto-loader" wildcard components
- * in the form of '%mymodule_abc', where the '%' part means that this path
- * component is a wildcard, and the 'mymodule_abc' part defines the prefix for a
- * load function, which here would be named mymodule_abc_load(). When a matching
- * path is requested, your load function will receive as its first argument the
- * path component in the position of the wildcard; load functions may also be
- * passed additional arguments (see "load arguments" in the return value
- * section below). For example, your module could register path
- * 'my-module/%mymodule_abc/edit':
- * @code
- *   $items['my-module/%mymodule_abc/edit'] = array(
- *     'page callback' => 'mymodule_abc_edit',
- *     'page arguments' => array(1),
- *   );
- * @endcode
- * When path 'my-module/123/edit' is requested, your load function
- * mymodule_abc_load() will be invoked with the argument '123', and should
- * load and return an "abc" object with internal id 123:
- * @code
- *   function mymodule_abc_load($abc_id) {
- *     return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject();
- *   }
- * @endcode
- * This 'abc' object will then be passed into the page callback function
- * mymodule_abc_edit() to replace the integer 1 in the page arguments.
- *
- * You can also make groups of menu items to be rendered (by default) as tabs
- * on a page. To do that, first create one menu item of type MENU_NORMAL_ITEM,
- * with your chosen path, such as 'foo'. Then duplicate that menu item, using a
- * subdirectory path, such as 'foo/tab1', and changing the type to
- * MENU_DEFAULT_LOCAL_TASK to make it the default tab for the group. Then add
- * the additional tab items, with paths such as "foo/tab2" etc., with type
- * MENU_LOCAL_TASK. Example:
- * @code
- * // Make "Foo settings" appear on the admin Config page
- * $items['admin/config/foo'] = array(
- *   'title' => 'Foo settings',
- *   'type' => MENU_NORMAL_ITEM,
- *   // page callback, etc. need to be added here
- * );
- * // Make "Global settings" the main tab on the "Foo settings" page
- * $items['admin/config/foo/global'] = array(
- *   'title' => 'Global settings',
- *   'type' => MENU_DEFAULT_LOCAL_TASK,
- *   // access callback, page callback, and theme callback will be inherited
- *   // from 'admin/config/foo', if not specified here to override
- * );
- * // Make an additional tab called "Node settings" on "Foo settings"
- * $items['admin/config/foo/node'] = array(
- *   'title' => 'Node settings',
- *   'type' => MENU_LOCAL_TASK,
- *   // access callback, page callback, and theme callback will be inherited
- *   // from 'admin/config/foo', if not specified here to override
- * );
- * @endcode
- *
- * @return
- *   An array of menu items. Each menu item has a key corresponding to the
- *   Drupal path being registered. The corresponding array value is an
- *   associative array that may contain the following key-value pairs:
- *   - "title": Required. The untranslated title of the menu item.
- *   - "title callback": Function to generate the title; defaults to t().
- *     If you require only the raw string to be output, set this to FALSE.
- *   - "title arguments": Arguments to send to t() or your custom callback,
- *     with path component substitution as described above.
- *   - "description": The untranslated description of the menu item.
- *   - "page callback": The function to call to display a web page when the user
- *     visits the path. If omitted, the parent menu item's callback will be used
- *     instead.
- *   - "page arguments": An array of arguments to pass to the page callback
- *     function, with path component substitution as described above.
- *   - "delivery callback": The function to call to package the result of the
- *     page callback function and send it to the browser. Defaults to
- *     drupal_deliver_html_page() unless a value is inherited from a parent menu
- *     item.
- *   - "access callback": A function returning a boolean value that determines
- *     whether the user has access rights to this menu item. Defaults to
- *     user_access() unless a value is inherited from a parent menu item.
- *   - "access arguments": An array of arguments to pass to the access callback
- *     function, with path component substitution as described above.
- *   - "theme callback": Optional. A function returning the machine-readable
- *     name of the default theme that will be used to render the page. If this
- *     function is provided, it is expected to return a currently-active theme
- *     on the site (otherwise, the main site theme will be used instead). If no
- *     function is provided, the main site theme will also be used, unless a
- *     value is inherited from a parent menu item. In all cases, the results of
- *     this function can be dynamically overridden for a particular page
- *     request by modules which implement hook_custom_theme().
- *   - "theme arguments": An array of arguments to pass to the theme callback
- *     function, with path component substitution as described above.
- *   - "file": A file that will be included before the page callback is called;
- *     this allows page callback functions to be in separate files. The file
- *     should be relative to the implementing module's directory unless
- *     otherwise specified by the "file path" option. Does not apply to other
- *     callbacks (only page callback).
- *   - "file path": The path to the directory containing the file specified in
- *     "file". This defaults to the path to the module implementing the hook.
- *   - "load arguments": An array of arguments to be passed to each of the
- *     wildcard object loaders in the path, after the path argument itself.
- *     For example, if a module registers path node/%node/revisions/%/view
- *     with load arguments set to array(3), the '%node' in the path indicates
- *     that the loader function node_load() will be called with the second
- *     path component as the first argument. The 3 in the load arguments
- *     indicates that the fourth path component will also be passed to
- *     node_load() (numbering of path components starts at zero). So, if path
- *     node/12/revisions/29/view is requested, node_load(12, 29) will be called.
- *     There are also two "magic" values that can be used in load arguments.
- *     "%index" indicates the index of the wildcard path component. "%map"
- *     indicates the path components as an array. For example, if a module
- *     registers for several paths of the form 'user/%user_category/edit/*', all
- *     of them can use the same load function user_category_load(), by setting
- *     the load arguments to array('%map', '%index'). For instance, if the user
- *     is editing category 'foo' by requesting path 'user/32/edit/foo', the load
- *     function user_category_load() will be called with 32 as its first
- *     argument, the array ('user', 32, 'edit', 'foo') as the map argument,
- *     and 1 as the index argument (because %user_category is the second path
- *     component and numbering starts at zero). user_category_load() can then
- *     use these values to extract the information that 'foo' is the category
- *     being requested.
- *   - "weight": An integer that determines the relative position of items in
- *     the menu; higher-weighted items sink. Defaults to 0. Menu items with the
- *     same weight are ordered alphabetically.
- *   - "menu_name": Optional. Set this to a custom menu if you don't want your
- *     item to be placed in Navigation.
- *   - "context": (optional) Defines the context a tab may appear in. By
- *     default, all tabs are only displayed as local tasks when being rendered
- *     in a page context. All tabs that should be accessible as contextual links
- *     in page region containers outside of the parent menu item's primary page
- *     context should be registered using one of the following contexts:
- *     - MENU_CONTEXT_PAGE: (default) The tab is displayed as local task for the
- *       page context only.
- *     - MENU_CONTEXT_INLINE: The tab is displayed as contextual link outside of
- *       the primary page context only.
- *     Contexts can be combined. For example, to display a tab both on a page
- *     and inline, a menu router item may specify:
- *     @code
- *       'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
- *     @endcode
- *   - "tab_parent": For local task menu items, the path of the task's parent
- *     item; defaults to the same path without the last component (e.g., the
- *     default parent for 'admin/people/create' is 'admin/people').
- *   - "tab_root": For local task menu items, the path of the closest non-tab
- *     item; same default as "tab_parent".
- *   - "block callback": Name of a function used to render the block on the
- *     system administration page for this item (called with no arguments).
- *     If not provided, system_admin_menu_block() is used to generate it.
- *   - "position": Position of the block ('left' or 'right') on the system
- *     administration page for this item.
- *   - "type": A bitmask of flags describing properties of the menu item.
- *     Many shortcut bitmasks are provided as constants in menu.inc:
- *     - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
- *       moved/hidden by the administrator.
- *     - MENU_CALLBACK: Callbacks simply register a path so that the correct
- *       information is generated when the path is accessed.
- *     - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
- *       administrator may enable.
- *     - MENU_LOCAL_ACTION: Local actions are menu items that describe actions
- *       on the parent item such as adding a new user or block, and are
- *       rendered in the action-links list in your theme.
- *     - MENU_LOCAL_TASK: Local tasks are menu items that describe different
- *       displays of data, and are generally rendered as tabs.
- *     - MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one
- *       "default" task, which should display the same page as the parent item.
- *     If the "type" element is omitted, MENU_NORMAL_ITEM is assumed.
- *
- * For a detailed usage example, see page_example.module.
- * For comprehensive documentation on the menu system, see
- * http://drupal.org/node/102338.
- */
-function hook_menu() {
-  $items['blog'] = array(
-    'title' => 'blogs',
-    'page callback' => 'blog_page',
-    'access arguments' => array('access content'),
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  $items['blog/feed'] = array(
-    'title' => 'RSS feed',
-    'page callback' => 'blog_feed',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
- * Alter the data being saved to the {menu_router} table after hook_menu is invoked.
- *
- * This hook is invoked by menu_router_build(). The menu definitions are passed
- * in by reference. Each element of the $items array is one item returned
- * by a module from hook_menu. Additional items may be added, or existing items
- * altered.
- *
- * @param $items
- *   Associative array of menu router definitions returned from hook_menu().
- */
-function hook_menu_alter(&$items) {
-  // Example - disable the page at node/add
-  $items['node/add']['access callback'] = FALSE;
-}
-
-/**
- * Alter the data being saved to the {menu_links} table by menu_link_save().
- *
- * @param $item
- *   Associative array defining a menu link as passed into menu_link_save().
- */
-function hook_menu_link_alter(&$item) {
-  // Example 1 - make all new admin links hidden (a.k.a disabled).
-  if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) {
-    $item['hidden'] = 1;
-  }
-  // Example 2  - flag a link to be altered by hook_translated_menu_link_alter()
-  if ($item['link_path'] == 'devel/cache/clear') {
-    $item['options']['alter'] = TRUE;
-  }
-}
-
-/**
- * Alter a menu link after it's translated, but before it's rendered.
- *
- * This hook may be used, for example, to add a page-specific query string.
- * For performance reasons, only links that have $item['options']['alter'] == TRUE
- * will be passed into this hook. The $item['options']['alter'] flag should
- * generally be set using hook_menu_link_alter().
- *
- * @param $item
- *   Associative array defining a menu link after _menu_link_translate()
- * @param $map
- *   Associative array containing the menu $map (path parts and/or objects).
- */
-function hook_translated_menu_link_alter(&$item, $map) {
-  if ($item['href'] == 'devel/cache/clear') {
-    $item['localized_options']['query'] = drupal_get_destination();
-  }
-}
-
-/**
- * Inform modules that a menu link has been created.
- *
- * This hook is used to notify modules that menu items have been
- * created. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param $link
- *   Associative array defining a menu link as passed into menu_link_save().
- *
- * @see hook_menu_link_update()
- * @see hook_menu_link_delete()
- */
-function hook_menu_link_insert($link) {
-  // In our sample case, we track menu items as editing sections
-  // of the site. These are stored in our table as 'disabled' items.
-  $record['mlid'] = $link['mlid'];
-  $record['menu_name'] = $link['menu_name'];
-  $record['status'] = 0;
-  drupal_write_record('menu_example', $record);
-}
-
-/**
- * Inform modules that a menu link has been updated.
- *
- * This hook is used to notify modules that menu items have been
- * updated. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param $link
- *   Associative array defining a menu link as passed into menu_link_save().
- *
- * @see hook_menu_link_insert()
- * @see hook_menu_link_delete()
- */
-function hook_menu_link_update($link) {
-  // If the parent menu has changed, update our record.
-  $menu_name = db_result(db_query("SELECT mlid, menu_name, status FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $link['mlid'])));
-  if ($menu_name != $link['menu_name']) {
-    db_update('menu_example')
-      ->fields(array('menu_name' => $link['menu_name']))
-      ->condition('mlid', $link['mlid'])
-      ->execute();
-  }
-}
-
-/**
- * Inform modules that a menu link has been deleted.
- *
- * This hook is used to notify modules that menu items have been
- * deleted. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param $link
- *   Associative array defining a menu link as passed into menu_link_save().
- *
- * @see hook_menu_link_insert()
- * @see hook_menu_link_update()
- */
-function hook_menu_link_delete($link) {
-  // Delete the record from our table.
-  db_delete('menu_example')
-    ->condition('mlid', $link['mlid'])
-    ->execute();
-}
-
 /**
  * Informs modules that a custom menu was created.
  *
@@ -470,112 +83,6 @@ function hook_menu_delete($menu) {
   variable_set('my_module_menus', $my_menus);
 }
 
-/**
- * Alter tabs and actions displayed on the page before they are rendered.
- *
- * This hook is invoked by menu_local_tasks(). The system-determined tabs and
- * actions are passed in by reference. Additional tabs or actions may be added,
- * or existing items altered.
- *
- * Each tab or action is an associative array containing:
- * - #theme: The theme function to use to render.
- * - #link: An associative array containing:
- *   - title: The localized title of the link.
- *   - href: The system path to link to.
- *   - localized_options: An array of options to pass to url().
- * - #active: Whether the link should be marked as 'active'.
- *
- * @param $data
- *   An associative array containing:
- *   - actions: An associative array containing:
- *     - count: The amount of actions determined by the menu system, which can
- *       be ignored.
- *     - output: A list of of actions, each one being an associative array
- *       as described above.
- *   - tabs: An indexed array (list) of tab levels (up to 2 levels), each
- *     containing an associative array:
- *     - count: The amount of tabs determined by the menu system. This value
- *       does not need to be altered if there is more than one tab.
- *     - output: A list of of tabs, each one being an associative array as
- *       described above.
- */
-function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
-  // Add an action linking to node/add to all pages.
-  $data['actions']['output'][] = array(
-    '#theme' => 'menu_local_task',
-    '#link' => array(
-      'title' => t('Add new content'),
-      'href' => 'node/add',
-      'localized_options' => array(
-        'attributes' => array(
-          'title' => t('Add new content'),
-        ),
-      ),
-    ),
-  );
-
-  // Add a tab linking to node/add to all pages.
-  $data['tabs'][0]['output'][] = array(
-    '#theme' => 'menu_local_task',
-    '#link' => array(
-      'title' => t('Example tab'),
-      'href' => 'node/add',
-      'localized_options' => array(
-        'attributes' => array(
-          'title' => t('Add new content'),
-        ),
-      ),
-    ),
-    // Define whether this link is active. This can be omitted for
-    // implementations that add links to pages outside of the current page
-    // context.
-    '#active' => ($router_item['path'] == $root_path),
-  );
-}
-
-/**
- * Alter contextual links before they are rendered.
- *
- * This hook is invoked by menu_contextual_links(). The system-determined
- * contextual links are passed in by reference. Additional links may be added
- * or existing links can be altered.
- *
- * Each contextual link must at least contain:
- * - title: The localized title of the link.
- * - href: The system path to link to.
- * - localized_options: An array of options to pass to url().
- *
- * @param $links
- *   An associative array containing contextual links for the given $root_path,
- *   as described above. The array keys are used to build CSS class names for
- *   contextual links and must therefore be unique for each set of contextual
- *   links.
- * @param $router_item
- *   The menu router item belonging to the $root_path being requested.
- * @param $root_path
- *   The (parent) path that has been requested to build contextual links for.
- *   This is a normalized path, which means that an originally passed path of
- *   'node/123' became 'node/%'.
- *
- * @see menu_contextual_links()
- * @see hook_menu()
- * @see system_preprocess()
- */
-function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) {
-  // Add a link to all contextual links for nodes.
-  if ($root_path == 'node/%') {
-    $links['foo'] = array(
-      'title' => t('Do fu'),
-      'href' => 'foo/do',
-      'localized_options' => array(
-        'query' => array(
-          'foo' => 'bar',
-        ),
-      ),
-    );
-  }
-}
-
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/modules/menu/menu.info b/modules/menu/menu.info
index a8d962634dd159282ae78d1c30e5fd56e8f475cf..46db58d34adab60f6a9405f034cf65c612fd6a94 100644
--- a/modules/menu/menu.info
+++ b/modules/menu/menu.info
@@ -10,8 +10,8 @@ files[] = menu.install
 files[] = menu.test
 configure = admin/structure/menu
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/menu/menu.test b/modules/menu/menu.test
index 3c99e2667dedf5f439cdfa1e71935d281baa1dfc..36ba1ab085160de65e5382b07b719bbe79a62bb7 100644
--- a/modules/menu/menu.test
+++ b/modules/menu/menu.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.test,v 1.34 2010/02/17 05:46:16 webchick Exp $
+// $Id: menu.test,v 1.36 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -100,7 +100,7 @@ class MenuTestCase extends DrupalWebTestCase {
    */
   function addCustomMenuCRUD() {
     // Add a new custom menu.
-    $menu_name = substr(md5($this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
+    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
     $title = $this->randomName(16);
 
     $menu = array(
@@ -130,7 +130,7 @@ class MenuTestCase extends DrupalWebTestCase {
 
     // Try adding a menu using a menu_name that is too long.
     $this->drupalGet('admin/structure/menu/add');
-    $menu_name = substr(md5($this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
+    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
     $title = $this->randomName(16);
     $edit = array(
       'menu_name' => $menu_name,
@@ -143,7 +143,7 @@ class MenuTestCase extends DrupalWebTestCase {
     $this->assertText(format_plural(MENU_MAX_MENU_NAME_LENGTH_UI, "The menu name can't be longer than 1 character.", "The menu name can't be longer than @count characters."), t('Validation failed when menu name is too long.'));
 
     // Change the menu_name so it no longer exceeds the maximum length.
-    $menu_name = substr(md5($this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
+    $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
     $edit['menu_name'] = $menu_name;
     $this->drupalPost('admin/structure/menu/add', $edit, t('Save'));
 
@@ -483,7 +483,7 @@ class MenuTestCase extends DrupalWebTestCase {
     // Load menu link.
     // Use api function so that link is translated for rendering.
     $item = menu_link_load($mlid);
-    $this->assertTrue((bool)$item, 'Standard menu link was loaded');
+    $this->assertTrue((bool) $item, 'Standard menu link was loaded');
     return $item;
   }
 
diff --git a/modules/node/content_types.inc b/modules/node/content_types.inc
index 03d199dcf88be8b0573ff49f400544e0f0db8df6..72e058eb5de3cedede953a057feda1d1c258dcbf 100644
--- a/modules/node/content_types.inc
+++ b/modules/node/content_types.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: content_types.inc,v 1.112 2010/04/24 14:49:14 dries Exp $
+// $Id: content_types.inc,v 1.114 2010/05/05 06:55:25 webchick Exp $
 
 /**
  * @file
@@ -94,7 +94,7 @@ function node_type_form($form, &$form_state, $type = NULL) {
     '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
     '#required' => TRUE,
     '#size' => 30,
-    '#field_suffix' => ' <small id="edit-name-suffix">' . ($type->locked ? t('Machine name: @name', array('@name' => $type->type)) : '&nbsp') . '</small>',
+    '#field_suffix' => ' <small id="edit-name-suffix">' . ($type->locked ? t('Machine name: @name', array('@name' => $type->type)) : '&nbsp;') . '</small>',
   );
 
   if (!$type->locked) {
@@ -160,12 +160,6 @@ function node_type_form($form, &$form_state, $type = NULL) {
     $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
     $form['submission']['title_label']['#required'] = FALSE;
   }
-  $form['submission']['body_label'] = array(
-    '#title' => t('Body field label'),
-    '#type' => 'textfield',
-    '#default_value' => isset($type->body_label) ? $type->body_label : '',
-    '#description' => t('To remove the body field, remove text and leave blank.'),
-  );
   $form['submission']['node_preview'] = array(
     '#type' => 'radios',
     '#title' => t('Preview before submitting'),
@@ -322,12 +316,9 @@ function node_type_form_submit($form, &$form_state) {
   $type->description = $form_state['values']['description'];
   $type->help = $form_state['values']['help'];
   $type->title_label = $form_state['values']['title_label'];
-  $type->body_label = $form_state['values']['body_label'];
-
   // title_label is required in core; has_title will always be true, unless a
   // module alters the title field.
   $type->has_title = ($type->title_label != '');
-  $type->has_body = ($type->body_label != '');
 
   $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
   $type->custom = $form_state['values']['custom'];
@@ -372,6 +363,7 @@ function node_type_form_submit($form, &$form_state) {
 
   node_types_rebuild();
   menu_rebuild();
+  node_add_body_field($type);
   $t_args = array('%name' => $type->name);
 
   if ($status == SAVED_UPDATED) {
diff --git a/modules/node/content_types.js b/modules/node/content_types.js
index 2fc099822780bba6a570d45acf5288cfe8d9a4a4..94fe1eb89507657ca2ceece6c20cf87738dabd9f 100644
--- a/modules/node/content_types.js
+++ b/modules/node/content_types.js
@@ -1,4 +1,4 @@
-// $Id: content_types.js,v 1.9 2010/04/09 12:24:53 dries Exp $
+// $Id: content_types.js,v 1.10 2010/05/05 06:55:25 webchick Exp $
 (function ($) {
 
 Drupal.behaviors.contentTypes = {
@@ -7,7 +7,6 @@ Drupal.behaviors.contentTypes = {
     $('fieldset#edit-submission', context).drupalSetSummary(function(context) {
       var vals = [];
       vals.push(Drupal.checkPlain($('#edit-title-label', context).val()) || Drupal.t('Requires a title'));
-      vals.push(Drupal.checkPlain($('#edit-body-label', context).val()) || Drupal.t('No body'));
       return vals.join(', ');
     });
     $('fieldset#edit-workflow', context).drupalSetSummary(function(context) {
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index a2d79354d00cf48c84820d78e3780a7a28038bad..81daab58b8193566d7c649862f422ef7e6edfcd8 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.api.php,v 1.66 2010/03/26 17:14:45 dries Exp $
+// $Id: node.api.php,v 1.67 2010/05/05 06:55:25 webchick Exp $
 
 /**
  * @file
@@ -771,10 +771,6 @@ function hook_node_view_alter(&$build) {
  *      field. Optional (defaults to TRUE).
  *   - "title_label": the label for the title field of this content type.
  *      Optional (defaults to 'Title').
- *   - "has_body": boolean indicating whether or not this node type has a body
- *      field. Optional (defaults to TRUE).
- *   - "body_label": the label for the body field of this content type. Optional
- *      (defaults to 'Body').
  *   - "locked": boolean indicating whether the administrator can change the
  *      machine name of this type. FALSE = changeable (not locked),
  *      TRUE = unchangeable (locked). Optional (defaults to TRUE).
@@ -986,17 +982,6 @@ function hook_prepare($node) {
 function hook_form($node, $form_state) {
   $type = node_type_get_type($node);
 
-  $form['title'] = array(
-    '#type' => 'textfield',
-    '#title' => check_plain($type->title_label),
-    '#required' => TRUE,
-  );
-  $form['body'] = array(
-    '#type' => 'textarea',
-    '#title' => check_plain($type->body_label),
-    '#rows' => 20,
-    '#required' => TRUE,
-  );
   $form['field1'] = array(
     '#type' => 'textfield',
     '#title' => t('Custom field'),
diff --git a/modules/node/node.css b/modules/node/node.css
index 53fcb5f00751e1d42e3825ae348ec3f8eb7abf06..5a725f0a4b35e6147dda382439d7f78cd3a093cf 100644
--- a/modules/node/node.css
+++ b/modules/node/node.css
@@ -1,4 +1,4 @@
-/* $Id: node.css,v 1.16 2010/04/08 18:26:42 dries Exp $ */
+/* $Id: node.css,v 1.17 2010/04/28 20:08:39 dries Exp $ */
 
 .node-unpublished {
   background-color: #fff4f4;
@@ -7,7 +7,8 @@
   background-color: #ffffea;
 }
 /* Override the default multiselect layout in system-behavior.css. */
-#node-admin-content dl.multiselect dd, dl.multiselect dd .form-item {
+#node-admin-content dl.multiselect dd,
+dl.multiselect dd .form-item {
   width: 20em; /* 6em label + 14em select */
 }
 #node-admin-content dl.multiselect dd .form-item label {
diff --git a/modules/node/node.info b/modules/node/node.info
index 3496f151808abd8e3ffd954ab1cd0c895d21a99c..928da46b2f433cb6b4026bd2b925c8fdaee21225 100644
--- a/modules/node/node.info
+++ b/modules/node/node.info
@@ -14,8 +14,8 @@ files[] = node.tokens.inc
 required = TRUE
 configure = admin/structure/types
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/node/node.install b/modules/node/node.install
index e7e75df84a3eb26d90d4692200e5b036834391ea..c6085f84c5f0b76cb30fb1f3b19e738d05b9fa6e 100644
--- a/modules/node/node.install
+++ b/modules/node/node.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.install,v 1.46 2010/03/28 11:16:29 dries Exp $
+// $Id: node.install,v 1.51 2010/05/14 04:37:53 webchick Exp $
 
 /**
  * @file
@@ -306,21 +306,6 @@ function node_schema() {
         'default' => '',
         'translatable' => TRUE,
       ),
-      'has_body' => array(
-        'description' => 'Boolean indicating whether this type has the body field attached.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'size' => 'tiny',
-      ),
-      'body_label' => array(
-        'description' => 'The label displayed for the body field on the edit form.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'translatable' => TRUE,
-      ),
       'custom' => array(
         'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE).',
         'type' => 'int',
@@ -496,30 +481,39 @@ function node_update_7005() {
 /**
  * Convert body and teaser from node properties to fields, and migrate status/comment/promote and sticky columns to the {node_revision} table.
  */
-function node_update_7006(&$context) {
-  $context['#finished'] = 0;
+function node_update_7006(&$sandbox) {
+  $sandbox['#finished'] = 0;
 
   // Get node type info for every invocation.
   drupal_static_reset('_node_types_build');
   $node_types = node_type_get_types();
 
-  if (!isset($context['total'])) {
+  if (!isset($sandbox['total'])) {
     // Initial invocation.
 
-    // Re-save node types to create body field instances.
-    foreach ($node_types as $type => $info) {
-      if ($info->has_body) {
-        node_type_save($info);
+    // Get node type info, specifically the body field settings.
+    $result = db_select('node_type', 'node_type')
+      ->fields('node_type')
+      ->execute();
+
+    // Add body field instances for existing node types.
+    foreach ($result as $node_type) {
+      if ($node_type->has_body) {
+        node_add_body_field($node_type, $node_type->body_label);
       }
+
+      $sandbox['node_types_info'][$node_type->type] = array(
+        'has_body' => $node_type->has_body,
+      );
     }
 
     // Initialize state for future calls.
-    $context['last'] = 0;
-    $context['count'] = 0;
+    $sandbox['last'] = 0;
+    $sandbox['count'] = 0;
 
     $query = db_select('node', 'n');
     $query->join('node_revision', 'nr', 'n.vid = nr.vid');
-    $context['total'] = $query->countQuery()->execute()->fetchField();
+    $sandbox['total'] = $query->countQuery()->execute()->fetchField();
   }
   else {
     // Subsequent invocations.
@@ -529,15 +523,15 @@ function node_update_7006(&$context) {
     $body_field_id = $body_field['id'];
 
     $found = FALSE;
-    if ($context['total']) {
+    if ($sandbox['total']) {
       // Operate on every revision of every node (whee!), in batches.
       $batch_size = 200;
       $query = db_select('node_revision', 'nr');
       $query->innerJoin('node', 'n', 'n.vid = nr.vid');
       $query
         ->fields('nr', array('nid', 'vid', 'body', 'teaser', 'format'))
-        ->fields('n', array('type', 'status', 'comment', 'promote', 'sticky'))
-        ->condition('nr.vid', $context['last'], '>')
+        ->fields('n', array('type', 'status', 'comment', 'promote', 'sticky', 'language'))
+        ->condition('nr.vid', $sandbox['last'], '>')
         ->orderBy('nr.vid', 'ASC')
         ->range(0, $batch_size);
       $revisions = $query->execute();
@@ -552,26 +546,30 @@ function node_update_7006(&$context) {
       foreach ($revisions as $revision) {
         $found = TRUE;
 
-        if ($node_types[$revision->type]->has_body) {
+        if ($sandbox['node_types_info'][$revision->type]['has_body']) {
           $node = (object) array(
             'nid' => $revision->nid,
             'vid' => $revision->vid,
             'type' => $revision->type,
           );
+          // After node_update_7009() we will always have LANGUAGE_NONE as
+          // language neutral language code, but here we still have empty
+          // strings.
+          $langcode = empty($revision->language) ? LANGUAGE_NONE : $revision->language;
           if (!empty($revision->teaser) && $revision->teaser != text_summary($revision->body)) {
-            $node->body[LANGUAGE_NONE][0]['summary'] = $revision->teaser;
+            $node->body[$langcode][0]['summary'] = $revision->teaser;
           }
           // Do this after text_summary() above.
           $break = '<!--break-->';
           if (substr($revision->body, 0, strlen($break)) == $break) {
             $revision->body = substr($revision->body, strlen($break));
           }
-          $node->body[LANGUAGE_NONE][0]['value'] = $revision->body;
+          $node->body[$langcode][0]['value'] = $revision->body;
           // Explicitly store the current default text format if the revision
           // did not have its own text format. Similar conversions for other
           // core modules are performed in filter_update_7005(), but we do this
           // one here since we are already migrating the data.
-          $node->body[LANGUAGE_NONE][0]['format'] = !empty($revision->format) ? $revision->format : variable_get('filter_default_format', 1);
+          $node->body[$langcode][0]['format'] = !empty($revision->format) ? $revision->format : variable_get('filter_default_format', 1);
           // This is a core update and no contrib modules are enabled yet, so
           // we can assume default field storage for a faster update.
           field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($body_field_id));
@@ -588,11 +586,11 @@ function node_update_7006(&$context) {
           ->condition('vid', $revision->vid)
           ->execute();
 
-        $context['last'] = $revision->vid;
-        $context['count'] += 1;
+        $sandbox['last'] = $revision->vid;
+        $sandbox['count'] += 1;
       }
 
-      $context['#finished'] = min(0.99, $context['count'] / $context['total']);
+      $sandbox['#finished'] = min(0.99, $sandbox['count'] / $sandbox['total']);
     }
 
     if (!$found) {
@@ -603,9 +601,12 @@ function node_update_7006(&$context) {
       db_drop_field('node_revision', 'teaser');
       db_drop_field('node_revision', 'format');
 
+      // Remove node_type properties related to the former 'body'.
+      db_drop_field('node_type', 'has_body');
+      db_drop_field('node_type', 'body_label');
+
       // We're done.
-      $context['#finished'] = 1;
-      return t("!number node body and teaser properties migrated to the 'body' field.", array('!number' => $context['total']));
+      $sandbox['#finished'] = 1;
     }
   }
 }
diff --git a/modules/node/node.js b/modules/node/node.js
index 76c98224402873dc34acba9c0b86af5a56c5c4ee..872729faeb658230e5d629f329d00d4d59c34f09 100644
--- a/modules/node/node.js
+++ b/modules/node/node.js
@@ -1,4 +1,4 @@
-// $Id: node.js,v 1.5 2010/04/09 12:24:53 dries Exp $
+// $Id: node.js,v 1.6 2010/05/04 16:03:34 dries Exp $
 
 (function ($) {
 
@@ -11,7 +11,8 @@ Drupal.behaviors.nodeFieldsetSummaries = {
     });
 
     $('fieldset#edit-author', context).drupalSetSummary(function (context) {
-      var name = $('#edit-name').val(), date = $('#edit-date').val();
+      var name = $('#edit-name').val() || Drupal.settings.anonymous,
+        date = $('#edit-date').val();
       return date ?
         Drupal.t('By @name on @date', { '@name': name, '@date': date }) :
         Drupal.t('By @name', { '@name': name });
diff --git a/modules/node/node.module b/modules/node/node.module
index dd759bb6d1f98c6eba30a0d774c6b0f24285bf02..04a4381104787f3e17c9ac47058cacd326a4110c 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.module,v 1.1264 2010/04/22 09:12:35 webchick Exp $
+// $Id: node.module,v 1.1273 2010/05/17 07:43:36 dries Exp $
 
 /**
  * @file
@@ -445,7 +445,7 @@ function node_type_get_name($node) {
  *
  * All new module-defined node types are saved to the database via a call to
  * node_type_save(), and obsolete ones are deleted via a call to
- * node_type_delete(). See _node_types_build() for an explanation of the new 
+ * node_type_delete(). See _node_types_build() for an explanation of the new
  * and obsolete types.
  */
 function node_types_rebuild() {
@@ -496,8 +496,6 @@ function node_type_save($info) {
     'base' => (string) $type->base,
     'has_title' => (int) $type->has_title,
     'title_label' => (string) $type->title_label,
-    'has_body' => (int) $type->has_body,
-    'body_label' => (string) $type->body_label,
     'description' => (string) $type->description,
     'help' => (string) $type->help,
     'custom' => (int) $type->custom,
@@ -514,7 +512,6 @@ function node_type_save($info) {
     if (!empty($type->old_type) && $type->old_type != $type->type) {
       field_attach_rename_bundle('node', $type->old_type, $type->type);
     }
-    node_configure_fields($type);
     module_invoke_all('node_type_update', $type);
     $status = SAVED_UPDATED;
   }
@@ -525,7 +522,7 @@ function node_type_save($info) {
       ->execute();
 
     field_attach_create_bundle('node', $type->type);
-    node_configure_fields($type);
+
     module_invoke_all('node_type_insert', $type);
     $status = SAVED_NEW;
   }
@@ -537,60 +534,48 @@ function node_type_save($info) {
 }
 
 /**
- * Manage the field(s) for a node type.
+ * Add default body field to a node type.
  *
- * Currently, the node module manages a single Field API field,
- * 'body'.  If $type->has_body is true, this function ensures the
- * 'body' field exists and creates an instance of it for the bundle
- * $type->type (e.g. 'page', 'story', ...).  If $type->has_body is
- * false, this function removes the instance (if it exists) for the
- * 'body' field on $type->type.
+ * @param $type
+ *   A node type object.
+ * @param $label
+ *   The label for the body instance.
  */
-function node_configure_fields($type) {
+function node_add_body_field($type, $label = 'Body') {
    // Add or remove the body field, as needed.
   $field = field_info_field('body');
   $instance = field_info_instance('node', 'body', $type->type);
-  if ($type->has_body) {
-    if (empty($field)) {
-      $field = array(
-        'field_name' => 'body',
-        'type' => 'text_with_summary',
-        'entity_types' => array('node'),
-        'translatable' => TRUE,
-      );
-      $field = field_create_field($field);
-    }
-    if (empty($instance)) {
-      $instance = array(
-        'field_name' => 'body',
-        'entity_type' => 'node',
-        'bundle' => $type->type,
-        'label' => $type->body_label,
-        'widget_type' => 'text_textarea_with_summary',
-        'settings' => array('display_summary' => TRUE),
-
-        // Define default formatters for the teaser and full view.
-        'display' => array(
-          'full' => array(
-            'label' => 'hidden',
-            'type' => 'text_default',
-          ),
-          'teaser' => array(
-            'label' => 'hidden',
-            'type' => 'text_summary_or_trimmed',
-          ),
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'body',
+      'type' => 'text_with_summary',
+      'entity_types' => array('node'),
+      'translatable' => TRUE,
+    );
+    $field = field_create_field($field);
+  }
+  if (empty($instance)) {
+    $instance = array(
+      'field_name' => 'body',
+      'entity_type' => 'node',
+      'bundle' => $type->type,
+      'label' => $label,
+      'widget_type' => 'text_textarea_with_summary',
+      'settings' => array('display_summary' => TRUE),
+
+      // Define default formatters for the teaser and full view.
+      'display' => array(
+        'full' => array(
+          'label' => 'hidden',
+          'type' => 'text_default',
         ),
-      );
-      field_create_instance($instance);
-    }
-    else {
-      $instance['label'] = $type->body_label;
-      $instance['settings']['display_summary'] = TRUE;
-      field_update_instance($instance);
-    }
-  }
-  elseif (!empty($instance)) {
-    field_delete_instance($instance);
+        'teaser' => array(
+          'label' => 'hidden',
+          'type' => 'text_summary_or_trimmed',
+        ),
+      ),
+    );
+    field_create_instance($instance);
   }
 }
 
@@ -626,6 +611,7 @@ function node_type_delete($type) {
   db_delete('node_type')
     ->condition('type', $type)
     ->execute();
+  field_attach_delete_bundle('node', $type);
   module_invoke_all('node_type_delete', $info);
 
   // Clear the node type cache.
@@ -737,14 +723,13 @@ function node_type_set_defaults($info = array()) {
     $type->base = '';
     $type->description = '';
     $type->help = '';
-    $type->has_title = 1;
-    $type->has_body = 1;
-    $type->title_label = t('Title');
-    $type->body_label = t('Body');
     $type->custom = 0;
     $type->modified = 0;
     $type->locked = 1;
     $type->is_new = 1;
+
+    $type->has_title = 1;
+    $type->title_label = 'Title';
   }
 
   $new_type = clone $type;
@@ -752,13 +737,10 @@ function node_type_set_defaults($info = array()) {
   foreach ($info as $key => $data) {
     $new_type->$key = $data;
   }
-  // If the type has no title or body, set an empty label.
+  // If the type has no title, set an empty label.
   if (!$new_type->has_title) {
     $new_type->title_label = '';
   }
-  if (!$new_type->has_body) {
-    $new_type->body_label = '';
-  }
   $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
 
   return $new_type;
@@ -1277,7 +1259,7 @@ function node_build_content($node, $view_mode = 'full') {
   // to know when a teaser view is different than a full view.
   $links = array();
   if ($view_mode == 'teaser') {
-    $links['node_readmore'] = array(
+    $links['node-readmore'] = array(
       'title' => t('Read more'),
       'href' => 'node/' . $node->nid,
       'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
@@ -1360,7 +1342,7 @@ function template_preprocess_node(&$variables) {
   }
 
   // Flatten the node object's member fields.
-  $variables = array_merge((array)$node, $variables);
+  $variables = array_merge((array) $node, $variables);
 
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
@@ -1560,16 +1542,10 @@ function node_search_execute($keys = NULL) {
   // 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')), NULL, array('target' => 'slave'));
-  $count_query->addExpression('COUNT(*)');
-  $query->setCountQuery($count_query);
+  // Load results.
   $find = $query
     ->limit(10)
     ->execute();
-
-  // Load results.
   $results = array();
   foreach ($find as $item) {
     // Render the node.
@@ -3314,6 +3290,7 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
 function node_content_form($node, $form_state) {
   // It is impossible to define a content type without implementing hook_form()
   // @todo: remove this requirement.
+  $form = array();
   $type = node_type_get_type($node);
 
   if ($type->has_title) {
@@ -3669,4 +3646,16 @@ class NodeController extends DrupalDefaultEntityController {
     $this->hookLoadArguments[] = array_keys($typed_nodes);
     parent::attachLoad($nodes, $revision_id);
   }
+
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    // Ensure that uid is taken from the {node} table,
+    // alias timestamp to revision_timestamp and add revision_uid.
+    $query = parent::buildQuery($ids, $conditions, $revision_id);
+    $fields =& $query->getFields();
+    unset($fields['timestamp']);
+    $query->addField('revision', 'timestamp', 'revision_timestamp');
+    $fields['uid']['table'] = 'base';
+    $query->addField('revision', 'uid', 'revision_uid');
+    return $query;
+  }
 }
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index c70c0eaf014e1baf9cbd87c8e2e0ce2320af7620..c39278cd4a054e430582deba3564790d30ec1d64 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.pages.inc,v 1.123 2010/04/24 14:49:14 dries Exp $
+// $Id: node.pages.inc,v 1.126 2010/05/10 06:34:39 dries Exp $
 
 /**
  * @file
@@ -66,7 +66,7 @@ function node_add($type) {
   // If a node type has been specified, validate its existence.
   if (isset($types[$type])) {
     // Initialize settings:
-    $node = (object)array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => LANGUAGE_NONE);
+    $node = (object) array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => LANGUAGE_NONE);
 
     drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
     $output = drupal_get_form($type . '_node_form', $node);
@@ -76,7 +76,7 @@ function node_add($type) {
 }
 
 function node_form_validate($form, &$form_state) {
-  $node = (object)$form_state['values'];
+  $node = (object) $form_state['values'];
   node_validate($node, $form);
 
   // Field validation. Requires access to $form_state, so this cannot be
@@ -95,7 +95,7 @@ function node_form($form, &$form_state, $node) {
   }
 
   if (isset($form_state['node'])) {
-    $node = (object)($form_state['node'] + (array)$node);
+    $node = (object) ($form_state['node'] + (array) $node);
   }
   if (isset($form_state['node_preview'])) {
     $form['#prefix'] = $form_state['node_preview'];
@@ -196,7 +196,13 @@ function node_form($form, &$form_state, $node) {
     '#collapsed' => TRUE,
     '#group' => 'additional_settings',
     '#attached' => array(
-      'js' => array(drupal_get_path('module', 'node') . '/node.js'),
+      'js' => array(
+        drupal_get_path('module', 'node') . '/node.js',
+        array(
+          'type' => 'setting',
+          'data' => array('anonymous' => variable_get('anonymous', t('Anonymous'))),
+        ),
+      ),
     ),
     '#weight' => 90,
   );
@@ -271,7 +277,6 @@ function node_form($form, &$form_state, $node) {
     );
   }
   $form['#validate'][] = 'node_form_validate';
-  $form['#theme'] = array($node->type . '_node_form', 'node_form');
 
   $form['#builder_function'] = 'node_form_submit_build_node';
   field_attach_form('node', $node, $form, $form_state, $node->language);
@@ -415,11 +420,11 @@ function node_form_submit_build_node($form, &$form_state) {
   // functions to process the form values into an updated node.
   unset($form_state['submit_handlers']);
   form_execute_handlers('submit', $form, $form_state);
-  $node = node_submit((object)$form_state['values']);
+  $node = node_submit((object) $form_state['values']);
 
   field_attach_submit('node', $node, $form, $form_state);
 
-  $form_state['node'] = (array)$node;
+  $form_state['node'] = (array) $node;
   $form_state['rebuild'] = TRUE;
   return $node;
 }
diff --git a/modules/node/node.test b/modules/node/node.test
index 73b57d5a36b58dc5e3ee32fc251a2cb0beb92176..ad2768dea37078e8eda97aba6c0b2013e6ae30f5 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.test,v 1.81 2010/04/20 09:48:06 webchick Exp $
+// $Id: node.test,v 1.85 2010/05/07 15:00:56 dries Exp $
 
 /**
  * Test the node_load_multiple() function.
@@ -260,7 +260,7 @@ class PageEditTestCase extends DrupalWebTestCase {
 
     // Check that the title and body fields are displayed with the correct values.
     $active = '<span class="element-invisible">' . t('(active tab)') . '</span>';
-    $link_text = t('!local-task-title !active', array('!local-task-title' => t('Edit'), '!active' => $active));
+    $link_text = t('!local-task-title!active', array('!local-task-title' => t('Edit'), '!active' => $active));
     $this->assertText(strip_tags($link_text), 0, t('Edit tab found and marked active.'));
     $this->assertFieldByName($title_key, $edit[$title_key], t('Title field displayed.'));
     $this->assertFieldByName($body_key, $edit[$body_key], t('Body field displayed.'));
@@ -1087,39 +1087,33 @@ class NodeTypeTestCase extends DrupalWebTestCase {
     $this->assertRaw('Title', t('Title field was found.'));
     $this->assertRaw('Body', t('Body field was found.'));
 
-    // Rename the title field and remove the body field.
+    // Rename the title field.
     $edit = array(
       'title_label' => 'Foo',
-      'body_label' => '',
     );
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    // Refresh the field information for the rest of the test.
     field_info_cache_clear();
 
-    $this->assertFalse(field_info_instance('node', 'body', 'page'), t('Body field was removed.'));
     $this->drupalGet('node/add/page');
     $this->assertRaw('Foo', t('New title label was displayed.'));
     $this->assertNoRaw('Title', t('Old title label was not displayed.'));
-    $this->assertNoRaw('Full text', t('Body field was not found.'));
 
-    // Add the body field again and change the name, machine name and description.
+    // Change the name, machine name and description.
     $edit = array(
       'name' => 'Bar',
       'type' => 'bar',
       'description' => 'Lorem ipsum.',
-      'body_label' => 'Baz',
     );
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
-    field_info_cache_clear();
 
-    $instance = field_info_instance('node', 'body', 'bar');
-    $this->assertEqual($instance['label'], 'Baz', t('Body field was added.'));
     $this->drupalGet('node/add');
     $this->assertRaw('Bar', t('New name was displayed.'));
     $this->assertRaw('Lorem ipsum', t('New description was displayed.'));
     $this->clickLink('Bar');
     $this->assertEqual(url('node/add/bar', array('absolute' => TRUE)), $this->getUrl(), t('New machine name was used in URL.'));
     $this->assertRaw('Foo', t('Title field was found.'));
-    $this->assertRaw('Baz', t('Body field was found.'));
+    $this->assertRaw('Body', t('Body field was found.'));
   }
 }
 
@@ -1297,9 +1291,11 @@ class NodeTitleTestCase extends DrupalWebTestCase {
    *  Create one node and test if the node title has the correct value.
    */
   function testNodeTitle() {
-    // Create "Basic page" content with title
+    // Create "Basic page" content with title.
+    // Add the node to the frontpage so we can test if teaser links are clickable.
     $settings = array(
       'title' => $this->randomName(8),
+      'promote' => 1,
     );
     $node = $this->drupalCreateNode($settings);
 
@@ -1315,11 +1311,15 @@ class NodeTitleTestCase extends DrupalWebTestCase {
 
     // Test node title in comment preview.
     $this->assertEqual(current($this->xpath('//div[@id=:id]/h2/a', array(':id' => 'node-' . $node->nid))), $node->title, 'Node preview title is equal to node title.', 'Node');
+
+    // Test node title is clickable on teaser list (/node).
+    $this->drupalGet('node');
+    $this->clickLink($node->title);
   }
 }
 
 /**
- * Test the node_feed() functionality
+ * Test the node_feed() functionality.
  */
 class NodeFeedTestCase extends DrupalWebTestCase {
   public static function getInfo() {
@@ -1661,7 +1661,7 @@ class NodeQueryAlter extends DrupalWebTestCase {
     }
     catch (Exception $e) {
       $this->fail($e->getMessage());
-      $this->fail((string)$query);
+      $this->fail((string) $query);
       $this->fail(t('Altered query is malformed'));
     }
   }
@@ -1699,7 +1699,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
     );
     $node = $this->drupalCreateNode($settings);
 
-    // Load node so that the body and summary fields are structured properly. 
+    // Load node so that the body and summary fields are structured properly.
     $node = node_load($node->nid);
     $instance = field_info_instance('node', 'body', $node->type);
 
diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info
index 98b5e2696a98561ea2848b694807ad1290b71e2e..e5777a6c6bce4082db19ca669db7496305273a31 100644
--- a/modules/node/tests/node_access_test.info
+++ b/modules/node/tests/node_access_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = node_access_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/node/tests/node_presave_test.info b/modules/node/tests/node_presave_test.info
index b72e325815c6afdb383892861d775a14f0512d28..57fcd8aea23f169a771e8887692abc7701e82f83 100644
--- a/modules/node/tests/node_presave_test.info
+++ b/modules/node/tests/node_presave_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = node_presave_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info
index 1d2bef874850f8b74c503faf8b396e69fbef748b..ec3291f318102de1c52ca79a982c93f3475fe74e 100644
--- a/modules/node/tests/node_test.info
+++ b/modules/node/tests/node_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = node_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info
index a0fa4462fa49e9679e16b84671ecd1206a1c3b39..da643046d30de07018aee80de1288fb3133081ae 100644
--- a/modules/node/tests/node_test_exception.info
+++ b/modules/node/tests/node_test_exception.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = node_test_exception.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/openid/openid.api.php b/modules/openid/openid.api.php
index d65ddb4cbe62c0b3eaaf02948c1b37930108d5f4..b797e807cf95d5a5d0b5450fc984866ff0d85d8d 100644
--- a/modules/openid/openid.api.php
+++ b/modules/openid/openid.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.api.php,v 1.4 2010/03/02 08:59:54 dries Exp $
+// $Id: openid.api.php,v 1.5 2010/05/13 17:37:24 dries Exp $
 
 /**
  * @file
@@ -71,8 +71,8 @@ function hook_openid_discovery_method_info() {
  * Allow modules to alter discovery methods.
  */
 function hook_openid_discovery_method_info_alter(&$methods) {
-  // Remove Google discovery scheme.
-  unset($methods['google']);
+  // Remove XRI discovery scheme.
+  unset($methods['xri']);
 }
 
 /**
diff --git a/modules/openid/openid.css b/modules/openid/openid.css
index 7a8b1bcb35603a1a49fbd08aa5cf7492ab7d34b4..dc587683c5ed6418a8c34eb0135638375bbe7c28 100644
--- a/modules/openid/openid.css
+++ b/modules/openid/openid.css
@@ -1,10 +1,10 @@
-/* $Id: openid.css,v 1.10 2010/01/30 07:59:25 dries Exp $ */
+/* $Id: openid.css,v 1.11 2010/05/05 16:28:06 dries Exp $ */
 
 #edit-openid-identifier {
   background-image: url("login-bg.png");
-  background-position: 0% 50%;
+  background-position: left 50%; /* LTR */
   background-repeat: no-repeat;
-  padding-left: 20px;
+  padding-left: 20px; /* LTR */
 }
 div.form-item-openid-identifier {
   display: block;
@@ -13,11 +13,6 @@ html.js #user-login-form div.form-item-openid-identifier,
 html.js #user-login div.form-item-openid-identifier {
   display: none;
 }
-html.js #user-login-form li.openid-link,
-html.js #user-login li.openid-link {
-  display : block;
-  list-style: none;
-}
 #user-login-form ul {
   margin-top: 0;
 }
@@ -27,14 +22,26 @@ html.js #user-login li.openid-link {
 #user-login ul li {
   margin: 0;
 }
-#user-login-form li.openid-link,
-#user-login-form li.user-link,
-#user-login li.openid-link,
-#user-login li.user-link {
+#user-login-form .openid-links {
+  padding-bottom: 0;
+}
+#user-login .openid-links {
+  padding-left: 0; /* LTR */
+}
+#user-login-form .openid-links li,
+#user-login .openid-links li {
   display: none;
+  list-style: none;
+}
+html.js #user-login-form li.openid-link,
+html.js #user-login li.openid-link {
+  display: block;
+  margin-left: 0; /* LTR */
 }
 #user-login-form li.openid-link a,
 #user-login li.openid-link a {
-  background: transparent url("login-bg.png") no-repeat 0 2px;
-  padding: 0 20px;
+  background-image: url("login-bg.png");
+  background-position: left top; /* LTR */
+  background-repeat: no-repeat;
+  padding: 0 0 0 1.5em; /* LTR */
 }
diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc
index 0a031856863ac10bdd8c069d203d9ac9e08166f0..aba6ed515280233e3d2fcea58282fda9686149ad 100644
--- a/modules/openid/openid.inc
+++ b/modules/openid/openid.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.inc,v 1.31 2010/04/24 14:49:14 dries Exp $
+// $Id: openid.inc,v 1.33 2010/05/13 17:37:24 dries Exp $
 
 /**
  * @file
@@ -65,11 +65,6 @@ define('OPENID_NS_AX', 'http://openid.net/srv/ax/1.0');
  */
 define('OPENID_NS_XRD', 'xri://$xrd*($v*2.0)');
 
-/**
- * OpenID IDP for Google hosted domains.
- */
-define('OPENID_NS_GOOGLE', 'http://namespace.google.com/openid/xmlns');
-
 /**
  * Performs an HTTP 302 redirect (for the 1.x protocol).
  */
@@ -89,11 +84,20 @@ function openid_redirect_http($url, $message) {
  * Creates a js auto-submit redirect for (for the 2.x protocol)
  */
 function openid_redirect($url, $message) {
-  $output = '<html><head><title>' . t('OpenID redirect') . "</title></head>\n<body>";
+  global $language;
+  
+  $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";
+  $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $language->language . '" lang="' . $language->language . '">' . "\n";
+  $output .= "<head>\n";
+  $output .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
+  $output .= "<title>" . t('OpenID redirect') . "</title>\n";
+  $output .= "</head>\n";
+  $output .= "<body>\n";
   $elements = drupal_get_form('openid_redirect_form', $url, $message);
   $output .= drupal_render($elements);
-  $output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>';
-  $output .= "</body></html>\n";
+  $output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>' . "\n";
+  $output .= "</body>\n";
+  $output .= "</html>\n";
   print $output;
 
   drupal_exit();
@@ -112,8 +116,8 @@ function openid_redirect_form($form, &$form_state, $url, $message) {
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
-    '#prefix' => '<noscript>',
-    '#suffix' => '</noscript>',
+    '#prefix' => '<noscript><div>',
+    '#suffix' => '</div></noscript>',
     '#value' => t('Send'),
   );
 
@@ -291,34 +295,6 @@ function _openid_url_normalize($url) {
   return $normalized_url;
 }
 
-/**
- * OpenID normalization method: Normalize Google identifiers.
- *
- * This transforms a Google identifier (user@domain) into an XRDS URL.
- *
- * @see http://sites.google.com/site/oauthgoog/fedlogininterp/openiddiscovery#TOC-IdP-Discovery
- */
-function _openid_google_idp_normalize($identifier) {
-  if (!valid_email_address($identifier)) {
-    return;
-  }
-
-  // If the identifier is a valid email address, try to discover the domain
-  // with Google Federated Login. We only use the generic URL, because the
-  // domain-specific URL (http://example.com/.well-known/host-meta) cannot
-  // be trusted.
-  list($name, $domain) = explode('@', $identifier, 2);
-  $response = drupal_http_request('https://www.google.com/accounts/o8/.well-known/host-meta?hd=' . rawurlencode($domain));
-  if (isset($response->error) || $response->code != 200) {
-    return;
-  }
-
-  if (preg_match('/Link: <(.*)>/', $response->data, $matches)) {
-    $xrds_url = $matches[1];
-    return $xrds_url;
-  }
-}
-
 /**
  * Create a serialized message packet as per spec: $key:$value\n .
  */
diff --git a/modules/openid/openid.info b/modules/openid/openid.info
index d682c5654734598a232d3248e359270fe06a22d5..46749768fc2a054919073fb38963ad5fffd65e23 100644
--- a/modules/openid/openid.info
+++ b/modules/openid/openid.info
@@ -11,8 +11,8 @@ files[] = xrds.inc
 files[] = openid.install
 files[] = openid.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index c1d6e58827f10b36a2837f4afae01cd31a742a67..3964e59f469f70054ca691b8974b74958f170ef8 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.module,v 1.84 2010/04/07 16:35:03 dries Exp $
+// $Id: openid.module,v 1.89 2010/05/20 08:51:24 dries Exp $
 
 /**
  * @file
@@ -136,7 +136,9 @@ function _openid_user_login_form_alter(&$form, &$form_state) {
   );
 
   $form['openid_links'] = array(
-    '#markup' => theme('item_list', array('items' => $items)),
+    '#theme' => 'item_list',
+    '#items' => $items,
+    '#attributes' => array('class' => array('openid-links')),
     '#weight' => 1,
   );
 
@@ -385,12 +387,10 @@ function openid_openid_discovery_method_info() {
   // The discovery process will stop as soon as one discovery method succeed.
   // We first attempt to discover XRI-based identifiers, then standard XRDS
   // identifiers via Yadis and HTML-based discovery, conforming to the OpenID 2.0
-  // specification. If those fail, we attempt to discover services based on
-  // the Google user discovery scheme.
+  // specification.
   return array(
     'xri' => '_openid_xri_discovery',
     'xrds' => '_openid_xrds_discovery',
-    'google' => '_openid_google_user_discovery',
   );
 }
 
@@ -437,14 +437,14 @@ function _openid_xrds_discovery($claimed_id) {
     $result = drupal_http_request($xrds_url, array('headers' => $headers));
 
     if (!isset($result->error)) {
-      if (isset($result->headers['Content-Type']) && preg_match("/application\/xrds\+xml/", $result->headers['Content-Type'])) {
+      if (isset($result->headers['content-type']) && preg_match("/application\/xrds\+xml/", $result->headers['content-type'])) {
         // Parse XML document to find URL
         $services = _openid_xrds_parse($result->data);
       }
       else {
         $xrds_url = NULL;
-        if (isset($result->headers['X-XRDS-Location'])) {
-          $xrds_url = $result->headers['X-XRDS-Location'];
+        if (isset($result->headers['x-xrds-location'])) {
+          $xrds_url = $result->headers['x-xrds-location'];
         }
         else {
           // Look for meta http-equiv link in HTML head
@@ -485,52 +485,16 @@ function _openid_xrds_discovery($claimed_id) {
   return $services;
 }
 
-/**
- * OpenID discovery method: Perform an user discovery using Google Discovery protocol.
- *
- * This transforms a OpenID identifier into an OpenID endpoint.
- *
- * @see http://sites.google.com/site/oauthgoog/fedlogininterp/openiddiscovery#TOC-User-Discovery
- * @see hook_openid_discovery_method_info()
- */
-function _openid_google_user_discovery($claimed_id) {
-  $xrds_url = $claimed_id;
-  $url = @parse_url($xrds_url);
-  if (empty($url['scheme']) || ($url['scheme'] != 'http' && $scheme['scheme'] != 'https') || empty($url['host'])) {
-    return;
-  }
-
-  $response = drupal_http_request('https://www.google.com/accounts/o8/.well-known/host-meta?hd=' . rawurlencode($url['host']));
-  if (isset($response->error) || $response->code != 200) {
-    return;
-  }
-
-  if (preg_match('/Link: <(.*)>/', $response->data, $matches)) {
-    $xrds_url = $matches[1];
-    $services = _openid_xrds_discovery($xrds_url);
-
-    foreach ($services as $i => $service) {
-      if (in_array('http://www.iana.org/assignments/relation/describedby', $service['types']) && $service['service']->children(OPENID_NS_GOOGLE)->URITemplate) {
-        $template = (string)$service['service']->children(OPENID_NS_GOOGLE)->URITemplate;
-        $xrds_url = str_replace('{%uri}', rawurlencode($claimed_id), $template);
-        return _openid_xrds_discovery($xrds_url);
-      }
-    }
-  }
-}
-
 /**
  * Implementation of hook_openid_normalization_method_info().
  *
  * Define standard normalization methods.
  */
 function openid_openid_normalization_method_info() {
-  // We first try to normalize Google Identifiers (user@domain) into their
-  // corresponding XRDS URL. If this fail, we proceed with standard OpenID
-  // normalization by normalizing XRI idenfiers. Finally, normalize the identifier
-  // into a canonical URL.
+  // OpenID Authentication 2.0, section 7.2:
+  // If the User-supplied Identifier looks like an XRI, treat it as such;
+  // otherwise treat it as an HTTP URL.
   return array(
-    'google_idp' => '_openid_google_idp_normalize',
     'xri' => '_openid_xri_normalize',
     'url' => '_openid_url_normalize',
   );
@@ -548,7 +512,7 @@ function openid_association($op_endpoint) {
 
   // Remove Old Associations:
   db_delete('openid_association')
-    ->condition('created + expires_in', REQUEST_TIME, '<')
+    ->where('created + expires_in < :request_time', array(':request_time' => REQUEST_TIME))
     ->execute();
 
   // Check to see if we have an association for this IdP already
@@ -687,6 +651,8 @@ function openid_association_request($public) {
 }
 
 function openid_authentication_request($claimed_id, $identity, $return_to = '', $assoc_handle = '', $service) {
+  global $base_url;
+
   module_load_include('inc', 'openid');
 
   $request =  array(
@@ -699,10 +665,10 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '',
   if ($service['version'] == 2) {
     $request['openid.ns'] = OPENID_NS_2_0;
     $request['openid.claimed_id'] = $claimed_id;
-    $request['openid.realm'] = url('', array('absolute' => TRUE));
+    $request['openid.realm'] = $base_url .'/';
   }
   else {
-    $request['openid.trust_root'] = url('', array('absolute' => TRUE));
+    $request['openid.trust_root'] = $base_url .'/';
   }
 
   // Always request Simple Registration. The specification doesn't mandate
diff --git a/modules/openid/openid.test b/modules/openid/openid.test
index 3a2ebec53cad58f9db137ce82840bbe0aa2edfbd..b167600926c2b24cab52c1260268127e0543a6da 100644
--- a/modules/openid/openid.test
+++ b/modules/openid/openid.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.test,v 1.22 2010/04/07 14:22:34 dries Exp $
+// $Id: openid.test,v 1.23 2010/05/13 17:37:24 dries Exp $
 
 /**
  * Base class for OpenID tests.
@@ -509,16 +509,4 @@ class OpenIDUnitTest extends DrupalWebTestCase {
 
     $this->assertEqual(openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', t('openid_normalize() correctly normalized a URL with a fragment.'));
   }
-
-  /**
-   * Test _openid_google_idp_normalize().
-   */
-  function testGoogleIdpNormalize() {
-    // We consider that Gmail will always be Gmail.
-    $this->assertTrue(valid_url(_openid_google_idp_normalize('testuser@gmail.com'), TRUE), t('_openid_google_idp_normalize() correctly normalized a Google Gmail identifier.'));
-    // This is a test domain documented on http://sites.google.com/site/oauthgoog/fedlogininterp/saml-idp.
-    $this->assertTrue(valid_url(_openid_google_idp_normalize('test@lso-test-domain.com'), TRUE), t('_openid_google_idp_normalize() correctly normalized a Google Apps for Domain identifier.'));
-    // We consider that microsoft.com will never be hosted by Google.
-    $this->assertFalse(valid_url(_openid_google_idp_normalize('test@microsoft.com'), TRUE), t("_openid_google_idp_normalize() didn't normalized an identifier for a domain that is not Google-enabled."));
-  }
 }
diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info
index bcf5457fcc71145c2f7dfb33d211153ec1d99632..724ada543e9080589c740a17bf5ba4105cad2d2a 100644
--- a/modules/openid/tests/openid_test.info
+++ b/modules/openid/tests/openid_test.info
@@ -9,8 +9,8 @@ files[] = openid_test.module
 dependencies[] = openid
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/overlay/overlay-parent.css b/modules/overlay/overlay-parent.css
index 6e184e538a764219bf394cfd25c88abf82276a87..a2005da3d51684dd37118f2af40ee73ae8bc2810 100644
--- a/modules/overlay/overlay-parent.css
+++ b/modules/overlay/overlay-parent.css
@@ -1,4 +1,4 @@
-/* $Id: overlay-parent.css,v 1.13 2010/03/20 14:45:05 dries Exp $ */
+/* $Id: overlay-parent.css,v 1.14 2010/04/28 20:08:39 dries Exp $ */
 
 /**
  * ui-dialog overlay.
@@ -38,7 +38,8 @@ body.overlay-autofit {
   min-height: 100px;
 }
 
-.overlay.ui-widget-content, .overlay .ui-widget-header {
+.overlay.ui-widget-content,
+.overlay .ui-widget-header {
   background: none;
   border: none;
 }
diff --git a/modules/overlay/overlay-parent.js b/modules/overlay/overlay-parent.js
index 232c4c2f82c10d26ef74e837c64e2b809b078282..5d16c407af49e4b13b51abe01d2150a676350e43 100644
--- a/modules/overlay/overlay-parent.js
+++ b/modules/overlay/overlay-parent.js
@@ -1,4 +1,4 @@
-// $Id: overlay-parent.js,v 1.38 2010/04/24 07:14:29 dries Exp $
+// $Id: overlay-parent.js,v 1.41 2010/05/14 07:45:54 dries Exp $
 
 (function ($) {
 
@@ -31,6 +31,17 @@ Drupal.behaviors.overlayParent = {
 
 /**
  * Overlay object for parent windows.
+ *
+ * Events
+ * Overlay triggers a number of events that can be used by other scripts.
+ * - drupalOverlayOpen: This event is triggered when the overlay is opened.
+ * - drupalOverlayBeforeClose: This event is triggered when the overlay attempts
+ *   to close. If an event handler returns false, the close will be prevented.
+ * - drupalOverlayClose: This event is triggered when the overlay is closed.
+ * - drupalOverlayBeforeLoad: This event is triggered right before a new URL
+ *   is loaded into the overlay.
+ * - drupalOverlayLoad: This event is triggered when the overlay is finished
+ *   loading.
  */
 Drupal.overlay = Drupal.overlay || {
   options: {},
@@ -66,10 +77,6 @@ Drupal.overlay = Drupal.overlay || {
  *   - height: height of the overlay in pixels.
  *   - autoFit: boolean indicating whether the overlay should be resized to
  *     fit the contents of the document loaded.
- *   - onOverlayOpen: callback to invoke when the overlay is opened.
- *   - onOverlayCanClose: callback to allow external scripts to decide if the
- *     overlay can be closed.
- *   - onOverlayClose: callback to invoke when the overlay is closed.
  *   - customDialogOptions: an object with custom jQuery UI Dialog options.
  *
  * @return
@@ -89,9 +96,6 @@ Drupal.overlay.open = function (options) {
     width: options.width,
     height: options.height,
     autoFit: (options.autoFit == undefined || options.autoFit),
-    onOverlayOpen: options.onOverlayOpen,
-    onOverlayCanClose: options.onOverlayCanClose,
-    onOverlayClose: options.onOverlayClose,
     customDialogOptions: options.customDialogOptions || {}
   };
 
@@ -103,6 +107,9 @@ Drupal.overlay.open = function (options) {
   // Open the dialog.
   self.$container.dialog('open');
 
+  // Allow other scripts to respond to this event.
+  $(document).trigger('drupalOverlayOpen');
+
   return true;
 };
 
@@ -182,10 +189,12 @@ Drupal.overlay.create = function () {
       return false;
     }
 
-    // Allow external scripts to decide if the overlay can be closed.
-    // The external script should call Drupal.overlay.close() again when it is
-    // ready for closing.
-    if ($.isFunction(self.options.onOverlayCanClose) && self.options.onOverlayCanClose(self) === false) {
+    // Allow other scripts to decide if the overlay can be closed. If an event-
+    // handler returns false the overlay won't be closed. The external script
+    // should call Drupal.overlay.close() again when it is ready for closing.
+    var event = $.Event('drupalOverlayBeforeClose');
+    $(document).trigger(event);
+    if (event.isDefaultPrevented()) {
       return false;
     }
 
@@ -216,9 +225,8 @@ Drupal.overlay.create = function () {
 
     self.lastHeight = 0;
 
-    if ($.isFunction(self.options.onOverlayClose)) {
-      self.options.onOverlayClose();
-    }
+    // Allow other scripts to respond to this event.
+    $(document).trigger('drupalOverlayClose');
   };
 
   // Default jQuery UI Dialog options.
@@ -319,18 +327,24 @@ Drupal.overlay.load = function (url) {
   // No need to resize while loading.
   clearTimeout(self.resizeTimeoutID);
 
+  // Allow other scripts to respond to this event.
+  $(document).trigger('drupalOverlayBeforeLoad');
+
   // While the overlay is loading, we remove the loaded class from the dialog.
   // After the loading is finished, the loaded class is added back. The loaded
   // class is being used to hide the iframe while loading.
   // See overlay-parent.css .overlay-loaded #overlay-element.
   self.$dialog.removeClass('overlay-loaded');
-  self.$iframe
+  self.$iframe.once('overlay-event-load')
     .bind('load.overlay-event', function () {
       self.isLoading = false;
 
       // Only continue when overlay is still open and not closing.
       if (self.isOpen && !self.isClosing) {
         self.$dialog.addClass('overlay-loaded');
+
+        // Allow other scripts to respond to this event.
+        $(document).trigger('drupalOverlayLoad');
       }
       else {
         self.destroy();
@@ -636,15 +650,9 @@ Drupal.overlay.outerResize = function () {
     return;
   }
 
-  // Consider any region that should be visible above the overlay (such as
-  // an admin toolbar).
-  var $displaceTop = $('.overlay-displace-top');
-  var displaceTopHeight = 0;
-  $displaceTop.each(function () {
-    displaceTopHeight += $(this).height();
-  });
+  var displaceTop = Drupal.displace ? Drupal.displace.getDisplacement('top') : 0;
 
-  self.$wrapper.css('top', displaceTopHeight);
+  self.$wrapper.css('top', displaceTop);
 
   // When the overlay has no height yet, make it fit exactly in the window,
   // or the configured height when autoFit is disabled.
@@ -652,7 +660,7 @@ Drupal.overlay.outerResize = function () {
     var titleBarHeight = self.$dialogTitlebar.outerHeight(true);
 
     if (self.options.autoFit || self.options.height == undefined ||!isNan(self.options.height)) {
-      self.lastHeight = parseInt($(window).height() - displaceTopHeight - titleBarHeight - 45);
+      self.lastHeight = parseInt($(window).height() - displaceTop - titleBarHeight - 45);
     }
     else {
       self.lastHeight = self.options.height;
@@ -689,11 +697,11 @@ Drupal.overlay.clickHandler = function (event) {
 
   var $target = $(event.target);
 
-  if (self.isOpen && $target.closest('.overlay-displace-top, .overlay-displace-bottom').length) {
+  if (self.isOpen && $target.closest('.displace-top, .displace-bottom').length) {
     // Click events in displaced regions could potentionally change the size of
     // that region (e.g. the toggle button of the toolbar module). Trigger the
     // resize event to force a recalculation of overlay's size/position.
-    $(window).triggerHandler('resize.overlay-event');
+    $(window).triggerHandler('resize');
   }
 
   // Only continue by left-click or right-click.
@@ -810,14 +818,13 @@ Drupal.overlay.hashchangeHandler = function (event) {
     else {
       // There is not an overlay opened yet; we should open a new one.
       var overlayOptions = {
-        url: linkURL,
-        onOverlayClose: function () {
-          // Clear the overlay URL fragment.
-          $.bbq.pushState();
-
-          self.resetActiveClass(self.getPath(window.location));
-        }
+        url: linkURL
       };
+      $(document).one('drupalOverlayClose', function () {
+        // Clear the overlay URL fragment.
+        $.bbq.pushState();
+        self.resetActiveClass(self.getPath(window.location));
+      });
       self.open(overlayOptions);
     }
   }
@@ -916,7 +923,7 @@ Drupal.overlay.resetActiveClass = function(activePath) {
   var self = this;
   var windowDomain = window.location.protocol + window.location.hostname;
 
-  $('.overlay-displace-top, .overlay-displace-bottom')
+  $('.displace-top, .displace-bottom')
   .find('a[href]')
   // Remove active class from all links in displaced regions.
   .removeClass('active')
diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info
index 23fcde2827ada83f0dd8d1007b90f2899974f579..47e7ff7e7a88ef63abacd5f919f27e5685a20aac 100644
--- a/modules/overlay/overlay.info
+++ b/modules/overlay/overlay.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = overlay.module
 files[] = overlay.install
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module
index e64400c57aae6fe9fbc71ed7a0bb904f67703e37..917f5bd0f731dc275c4bdbdea270b388aee5f6e3 100644
--- a/modules/overlay/overlay.module
+++ b/modules/overlay/overlay.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: overlay.module,v 1.17 2010/04/24 07:14:29 dries Exp $
+// $Id: overlay.module,v 1.18 2010/05/14 07:45:54 dries Exp $
 
 /**
  * @file
@@ -299,16 +299,6 @@ function overlay_preprocess_page(&$variables) {
   }
 }
 
-/**
- * Preprocess template variables for toolbar.tpl.php.
- *
- * Adding the 'overlay-displace-top' class to the toolbar pushes the overlay
- * down, so it appears below the toolbar.
- */
-function overlay_preprocess_toolbar(&$variables) {
-  $variables['classes_array'][] = "overlay-displace-top";
-}
-
 /**
  * Form after_build callback.
  *
diff --git a/modules/path/path.admin.inc b/modules/path/path.admin.inc
index e19048326855b877bc03b244f36caa4e3a719135..d6fd4c0b4607be33382d9634342e6fe3d6dfab8e 100644
--- a/modules/path/path.admin.inc
+++ b/modules/path/path.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.admin.inc,v 1.43 2010/04/24 14:49:14 dries Exp $
+// $Id: path.admin.inc,v 1.44 2010/05/14 04:57:59 webchick Exp $
 
 /**
  * @file
@@ -19,14 +19,13 @@ function path_admin_overview($keys = NULL) {
   $alias_exists = (bool) db_query_range('SELECT 1 FROM {url_alias} WHERE language <> :language', 0, 1, array(':language' => LANGUAGE_NONE))->fetchField();
   $multilanguage = (module_exists('locale') || $alias_exists);
 
-  $header = array(
-    array('data' => t('Alias'), 'field' => 'alias', 'sort' => 'asc'),
-    array('data' => t('System'), 'field' => 'source'),
-    array('data' => t('Operations'), 'colspan' => '2')
-  );
+  $header = array();
+  $header[] = array('data' => t('Alias'), 'field' => 'alias', 'sort' => 'asc');
+  $header[] = array('data' => t('System'), 'field' => 'source');
   if ($multilanguage) {
-    array_splice($header, 2, 0, array(array('data' => t('Language'), 'field' => 'language')));
+    $header[] = array('data' => t('Language'), 'field' => 'language');
   }
+  $header[] = array('data' => t('Operations'));
 
   $query = db_select('url_alias')->extend('PagerDefault')->extend('TableSort');
   if ($keys) {
@@ -42,22 +41,38 @@ function path_admin_overview($keys = NULL) {
   $rows = array();
   $destination = drupal_get_destination();
   foreach ($result as $data) {
-    $row = array(
+    $row = array();
+    $row['data']['alias'] = l($data->alias, $data->source);
+    $row['data']['source'] = l($data->source, $data->source, array('alias' => TRUE));
+    if ($multilanguage) {
+      $row['data']['language'] = module_invoke('locale', 'language_name', $data->language);
+    }
+
+    $operations = array();
+    $operations['edit'] = array(
+      'title' => t('edit'),
+      'href' => "admin/config/search/path/edit/$data->pid",
+      'query' => $destination,
+    );
+    $operations['delete'] = array(
+      'title' => t('delete'),
+      'href' => "admin/config/search/path/delete/$data->pid",
+      'query' => $destination,
+    );
+    $row['data']['operations'] = array(
       'data' => array(
-        l($data->alias, $data->source),
-        l($data->source, $data->source, array('alias' => TRUE)),
-        l(t('edit'), "admin/config/search/path/edit/$data->pid", array('query' => $destination)),
-        l(t('delete'), "admin/config/search/path/delete/$data->pid", array('query' => $destination)),
+        '#theme' => 'links',
+        '#links' => $operations,
+        '#attributes' => array('class' => array('links', 'inline', 'nowrap')),
       ),
     );
+
     // If the system path maps to a different URL alias, highlight this table
     // row to let the user know of old aliases.
     if ($data->alias != drupal_get_path_alias($data->source, $data->language)) {
       $row['class'] = array('warning');
     }
-    if ($multilanguage) {
-      array_splice($row['data'], 2, 0, module_invoke('locale', 'language_name', $data->language));
-    }
+
     $rows[] = $row;
   }
 
@@ -65,7 +80,7 @@ function path_admin_overview($keys = NULL) {
     '#theme' => 'table',
     '#header' => $header,
     '#rows' => $rows,
-    '#empty' => t('No URL aliases available. <a href="@link">Add alias</a>.', array('@link' => url('admin/config/search/path/add'))),
+    '#empty' => t('No URL aliases available. <a href="@link">Add URL alias</a>.', array('@link' => url('admin/config/search/path/add'))),
   );
   $build['path_pager'] = array('#theme' => 'pager');
 
diff --git a/modules/path/path.info b/modules/path/path.info
index f16c083ea3e5fd1c1c5c6824b048554e2212b149..6aa6b53907fe1d973c80183a48760c98ceae113d 100644
--- a/modules/path/path.info
+++ b/modules/path/path.info
@@ -9,8 +9,8 @@ files[] = path.admin.inc
 files[] = path.test
 configure = admin/config/search/path
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/php/php.info b/modules/php/php.info
index 16b501d42eb25b2a4583e47322d302f83a25132b..2af11cd9ac50dec8870d3e304a723eed0a126bd2 100644
--- a/modules/php/php.info
+++ b/modules/php/php.info
@@ -8,8 +8,8 @@ files[] = php.module
 files[] = php.install
 files[] = php.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/poll/poll.info b/modules/poll/poll.info
index 50f1c19fe2ce9c412208ceb03d9be061a57e963b..c3e1227795a4388168e5897304c767a74d357867 100644
--- a/modules/poll/poll.info
+++ b/modules/poll/poll.info
@@ -10,8 +10,8 @@ files[] = poll.install
 files[] = poll.test
 files[] = poll.tokens.inc
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 876f8b84400f952e8987384d8e2f578d806d100a..340fd7c11eb8137dd4274ecdd878f08198e25ccf 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.module,v 1.345 2010/04/24 14:49:14 dries Exp $
+// $Id: poll.module,v 1.348 2010/05/09 13:37:32 dries Exp $
 
 /**
  * @file
@@ -297,7 +297,6 @@ function poll_form($node, &$form_state) {
     '#ajax' => array(
       'callback' => 'poll_choice_js',
       'wrapper' => 'poll-choices',
-      'method' => 'replace',
       'effect' => 'fade',
     ),
   );
@@ -365,8 +364,6 @@ function poll_more_choices_submit($form, &$form_state) {
 }
 
 function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) {
-  $admin = user_access('administer nodes');
-
   $form = array(
     '#tree' => TRUE,
   );
@@ -422,7 +419,7 @@ function poll_choice_js($form, $form_state) {
 function poll_node_form_submit(&$form, &$form_state) {
   // Renumber fields
   $form_state['values']['choice'] = array_values($form_state['values']['choice']);
-  $form_state['values']['teaser'] = poll_teaser((object)$form_state['values']);
+  $form_state['values']['teaser'] = poll_teaser((object) $form_state['values']);
 }
 
 /**
diff --git a/modules/poll/poll.test b/modules/poll/poll.test
index 717a3d82bdb169c6fd97f9e21b217caf4f1dbdbc..51e3aff1329a1d434ac1b433f4ac569f848eb425 100644
--- a/modules/poll/poll.test
+++ b/modules/poll/poll.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.test,v 1.33 2010/04/22 23:59:04 dries Exp $
+// $Id: poll.test,v 1.34 2010/05/12 08:26:15 dries Exp $
 
 /**
  * @file
@@ -375,7 +375,7 @@ class PollVoteCheckHostname extends PollTestCase {
 
     // Enable page cache to verify that the result page is not saved in the
     // cache when anonymous voting is allowed.
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
 
     // Create poll.
     $title = $this->randomName();
diff --git a/modules/profile/profile.info b/modules/profile/profile.info
index 04be1fa375df1af604d14afd219ab32fbc29a966..6d7fc5022f6557fee7f5e9d681bea90919397bb4 100644
--- a/modules/profile/profile.info
+++ b/modules/profile/profile.info
@@ -11,8 +11,8 @@ files[] = profile.install
 files[] = profile.test
 configure = admin/config/people/profile
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info
index 867eda3901c596c4fdb144346e0e04ce2da12a93..4c6c1b5b5fb2d05df24339d4ae739b5d2b2076fa 100644
--- a/modules/rdf/rdf.info
+++ b/modules/rdf/rdf.info
@@ -8,8 +8,8 @@ files[] = rdf.install
 files[] = rdf.module
 files[] = rdf.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/rdf/rdf.module b/modules/rdf/rdf.module
index 15061512a3afe14968768b5e89eaeb71404e5cb2..37d47ffc84b3cf8c9c842530842766e4181ab588 100644
--- a/modules/rdf/rdf.module
+++ b/modules/rdf/rdf.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: rdf.module,v 1.39 2010/04/22 21:41:09 webchick Exp $
+// $Id: rdf.module,v 1.40 2010/05/05 15:49:04 dries Exp $
 
 /**
  * @file
@@ -502,7 +502,7 @@ function rdf_preprocess_node(&$variables) {
   // Adds RDFa markup annotating the number of comments a node has.
   if (isset($variables['node']->comment_count) && !empty($variables['node']->rdf_mapping['comment_count']['predicates'])) {
     // Annotates the 'x comments' link in teaser view.
-    if (isset($variables['content']['links']['comment']['#links']['comment_comments'])) {
+    if (isset($variables['content']['links']['comment']['#links']['comment-comments'])) {
       $comment_count_attributes['property'] = $variables['node']->rdf_mapping['comment_count']['predicates'];
       $comment_count_attributes['content'] = $variables['node']->comment_count;
       $comment_count_attributes['datatype'] = $variables['node']->rdf_mapping['comment_count']['datatype'];
@@ -512,7 +512,7 @@ function rdf_preprocess_node(&$variables) {
       // we set an empty rel attribute which triggers rule number 5. See
       // http://www.w3.org/TR/rdfa-syntax/#sec_5.5.
       $comment_count_attributes['rel'] = '';
-      $variables['content']['links']['comment']['#links']['comment_comments']['attributes'] += $comment_count_attributes;
+      $variables['content']['links']['comment']['#links']['comment-comments']['attributes'] += $comment_count_attributes;
     }
     // In full node view, the number of comments is not displayed by
     // node.tpl.php so it is expressed in RDFa in the <head> tag.
diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info
index 9f59ec3b63aced9811891d6127658ed7dbf19e19..416586d8485a12498bdd8752f43bf8fb6c29941e 100644
--- a/modules/rdf/tests/rdf_test.info
+++ b/modules/rdf/tests/rdf_test.info
@@ -8,8 +8,8 @@ files[] = rdf_test.install
 files[] = rdf_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/search/search.api.php b/modules/search/search.api.php
index 62418a582cda43553b38ab1fd3da79cc1649a49f..f366e6436cd07b8f080fcf581d69584e9c747068 100644
--- a/modules/search/search.api.php
+++ b/modules/search/search.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.api.php,v 1.25 2010/02/27 10:54:12 dries Exp $
+// $Id: search.api.php,v 1.26 2010/05/12 15:53:43 dries Exp $
 
 /**
  * @file
@@ -177,16 +177,10 @@ function hook_search_execute($keys = NULL) {
   // 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')));
-  $count_query->addExpression('COUNT(*)');
-  $query->setCountQuery($count_query);
+  // Load results.
   $find = $query
     ->limit(10)
     ->execute();
-
-  // Load results.
   $results = array();
   foreach ($find as $item) {
     // Build the node body.
diff --git a/modules/search/search.extender.inc b/modules/search/search.extender.inc
index 5c994aa1d5bfb90d18dfc9136951c4ce98042a1e..ebab18211e993b5601f5aba8981f454c8c9e8ee3 100644
--- a/modules/search/search.extender.inc
+++ b/modules/search/search.extender.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.extender.inc,v 1.4 2010/04/16 13:53:43 dries Exp $
+// $Id: search.extender.inc,v 1.5 2010/05/12 15:53:43 dries Exp $
 
 /**
  * @file
@@ -407,6 +407,7 @@ class SearchQuery extends SelectQueryExtender {
       return new DatabaseStatementEmpty();
     }
 
+    // Add conditions to query.
     $this->join('search_dataset', 'd', 'i.sid = d.sid AND i.type = d.type');
     $this->condition($this->conditions);
 
@@ -443,4 +444,35 @@ class SearchQuery extends SelectQueryExtender {
 
     return $this->query->execute();
   }
+
+  /**
+   * Build the default count query for SearchQuery.
+   *
+   * Since SearchQuery always uses GROUP BY, we can default to a subquery. Also
+   * adding the same conditions as execute() because countQuery() is called
+   * first.
+   */
+  public function countQuery() {
+    // Clone the inner query.
+    $inner = clone $this->query;
+
+    // Add conditions to query.
+    $inner->join('search_dataset', 'd', 'i.sid = d.sid AND i.type = d.type');
+    $inner->condition($this->conditions);
+
+    // Remove existing fields and expressions, they are not needed for a count
+    // query.
+    $fields =& $inner->getFields();
+    $fields = array();
+    $expressions =& $inner->getExpressions();
+    $expressions = array();
+
+    // Add the sid as the only field and count them as a subquery.
+    $count = db_select($inner->fields('i', array('sid')), NULL, array('target' => 'slave'));
+
+    // Add the COUNT() expression.
+    $count->addExpression('COUNT(*)');
+
+    return $count;
+  }
 }
diff --git a/modules/search/search.info b/modules/search/search.info
index 097adfc11f38c1971242d4370307343f33b92f8e..ab1e5798cca23de4dd4a6f3375d5a67cb3fda2c4 100644
--- a/modules/search/search.info
+++ b/modules/search/search.info
@@ -12,8 +12,8 @@ files[] = search.test
 files[] = search.extender.inc
 configure = admin/config/search/settings
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/search/search.module b/modules/search/search.module
index 3a511976a2cc1407b434027e31abaef1e507b452..910b2d20bdf5c7c1b145d7ae22fa031c0da2a6fd 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.module,v 1.345 2010/04/24 14:49:14 dries Exp $
+// $Id: search.module,v 1.348 2010/05/09 19:46:11 dries Exp $
 
 /**
  * @file
@@ -103,12 +103,25 @@ define('PREG_CLASS_PUNCTUATION',
   '\x{ff65}');
 
 /**
- * Matches all CJK characters that are candidates for auto-splitting
- * (Chinese, Japanese, Korean).
- * Contains kana and BMP ideographs.
+ * Matches CJK (Chinese, Japanese, Korean) letter-like characters.
+ *
+ * This list is derived from the "East Asian Scripts" section of
+ * http://www.unicode.org/charts/index.html, as well as a comment on
+ * http://unicode.org/reports/tr11/tr11-11.html listing some character
+ * ranges that are reserved for additional CJK ideographs.
+ *
+ * The character ranges do not include numbers, punctuation, or symbols, since
+ * these are handled separately in search. Note that radicals and strokes are
+ * considered symbols. (See
+ * http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt)
+ *
+ * @see search_expand_cjk()
  */
-define('PREG_CLASS_CJK', '\x{3041}-\x{30ff}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}' .
-'\x{4e00}-\x{9fbb}\x{f900}-\x{fad9}');
+define('PREG_CLASS_CJK', '\x{1100}-\x{11FF}\x{3040}-\x{309F}\x{30A1}-\x{318E}' .
+  '\x{31A0}-\x{31B7}\x{31F0}-\x{31FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FCF}' .
+  '\x{A000}-\x{A48F}\x{A4D0}-\x{A4FD}\x{A960}-\x{A97F}\x{AC00}-\x{D7FF}' .
+  '\x{F900}-\x{FAFF}\x{FF21}-\x{FF3A}\x{FF41}-\x{FF5A}\x{FF66}-\x{FFDC}' .
+  '\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}');
 
 /**
  * Implements hook_help().
@@ -124,7 +137,9 @@ function search_help($path, $arg) {
       $output .= '<dt>' . t('Searching content and users') . '</dt>';
       $output .= '<dd>' . t('Users with <em>Use search</em> permission can use the search block and <a href="@search">Search page</a>. Users with the <em>View published content</em> permission can search for content containing exact keywords. Users with the <em>View user profiles</em> permission can search for users containing the keyword anywhere in the user name, and users with the <em>Administer users</em> permission can search for users by email address. Additionally, users with <em>Use advanced search</em> permission can find content using more complex search methods and filtering by choosing the <em>Advanced search</em> option on the <a href="@search">Search page</a>.', array('@search' => url('search'))) . '</dd>';
       $output .= '<dt>' . t('Indexing content with cron') . '</dt>';
-      $output .= '<dd>' . t('To provide keyword searching, the search engine maintains an index of words found in the content. To build and maintain this index, a correctly configured <a href="@cron">cron maintenance task</a> is required. Users with <em>Administer search</em> permission can further configure the cron settings on the <a href="@searchsettings">Search settings page</a>.', array('@cron' => 'http://drupal.org/cron', '@searchsettings' => url('admin/config/search/settings'))) . '</dd>';
+      $output .= '<dd>' . t('To provide keyword searching, the search engine maintains an index of words found in the content and its fields, along with text added to your content by other modules (such as comments from the core Comment module, and taxonomy terms from the core Taxonomy module). To build and maintain this index, a correctly configured <a href="@cron">cron maintenance task</a> is required. Users with <em>Administer search</em> permission can further configure the cron settings on the <a href="@searchsettings">Search settings page</a>.', array('@cron' => 'http://drupal.org/cron', '@searchsettings' => url('admin/config/search/settings'))) . '</dd>';
+      $output .= '<dt>' . t('Content reindexing') . '</dt>';
+      $output .= '<dd>' . t('Content-related actions on your site (creating, editing, or deleting content and comments) automatically cause affected content items to be marked for indexing or reindexing at the next cron run. When content is marked for reindexing, the previous content remains in the index until cron runs, at which time it is replaced by the new content. Unlike content-related actions, actions related to the structure of your site do not cause affected content to be marked for reindexing. Examples of structure-related actions that affect content include deleting or editing taxonomy terms, enabling or disabling modules that add text to content (such as Taxonomy, Comment, and field-providing modules), and modifying the fields or display parameters of your content types. If you take one of these actions and you want to ensure that the search index is updated to reflect your changed site structure, you can mark all content for reindexing by clicking the "Re-index site" button on the <a href="@searchsettings">Search settings page</a>. If you have a lot of content on your site, it may take several cron runs for the content to be reindexed.', array('@searchsettings' => url('admin/config/search/settings'))) . '</dd>';
       $output .= '<dt>' . t('Configuring search settings') . '</dt>';
       $output .= '<dd>' . t('Indexing behavior can be adjusted using the <a href="@searchsettings">Search settings page</a>. Users with <em>Administer search</em> permission can control settings such as the <em>Number of items to index per cron run</em>, <em>Indexing settings</em> (word length), <em>Active search modules</em>, and <em>Content ranking</em>, which lets you adjust the priority in which indexed content is returned in results.', array('@searchsettings' => url('admin/config/search/settings'))) . '</dd>';
       $output .= '<dt>' . t('Search block') . '</dt>';
@@ -244,18 +259,43 @@ function search_menu() {
     'file path' => drupal_get_path('module', 'dblog'),
     'file' => 'dblog.admin.inc',
   );
+
+  // Add paths for searching. We add each module search path twice: once without
+  // and once with %menu_tail appended. The reason for this is that we want to
+  // preserve keywords when switching tabs, and also to have search tabs
+  // highlighted properly. The only way to do that within the Drupal menu
+  // system appears to be having two sets of tabs. See discussion on issue
+  // http://drupal.org/node/245103 for details.
+
   drupal_static_reset('search_get_info');
-  $search_hooks = search_get_info();
-  foreach(variable_get('search_active_modules', array('node', 'user')) as $module) {
-    if (isset($search_hooks[$module])) {
-      $items['search/' . $search_hooks[$module]['path'] . '/%menu_tail'] = array(
-        'title' => $search_hooks[$module]['title'],
+  if ($active = variable_get('search_active_modules', array('node', 'user'))) {
+    foreach (array_intersect_key(search_get_info(), array_flip($active)) as $module => $search_info) {
+      $path = 'search/' . $search_info['path'];
+      $items[$path] = array(
+        'title' => $search_info['title'],
+        'page callback' => 'search_view',
+        'page arguments' => array($module),
+        'access callback' => '_search_menu_access',
+        'access arguments' => array($module),
+        'type' => $module == 'node' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
+        'file' => 'search.pages.inc',
+        'weight' => $module == 'node' ? -10 : 0,
+      );
+      $items["$path/%menu_tail"] = array(
+        'title' => $search_info['title'],
         'page callback' => 'search_view',
         'page arguments' => array($module),
         'access callback' => '_search_menu_access',
         'access arguments' => array($module),
+        // The default local task points to its parent, but this item points to
+        // where it should so it should not be changed.
         'type' => MENU_LOCAL_TASK,
         'file' => 'search.pages.inc',
+        'weight' => 0,
+        // These tabs are not subtabs.
+        'tab_root' => 'search/node/%',
+        // These tabs need to display at the same level.
+        'tab_parent' => 'search',
       );
     }
   }
@@ -420,28 +460,45 @@ function search_simplify($text) {
 }
 
 /**
- * Basic CJK tokenizer. Simply splits a string into consecutive, overlapping
- * sequences of characters ('minimum_word_size' long).
+ * Splits CJK (Chinese, Japanese, Korean) text into tokens.
+ *
+ * The Search module matches exact words, where a word is defined to be a
+ * sequence of characters delimited by spaces or punctuation. CJK languages are
+ * written in long strings of characters, though, not split up into words. So
+ * in order to allow search matching, we split up CJK text into tokens
+ * consisting of consecutive, overlapping sequences of characters whose length
+ * is equal to the 'minimum_word_size' variable. This tokenizing is only done if
+ * the 'overlap_cjk' variable is TRUE.
+ *
+ * @param $matches
+ *   This function is a callback for preg_replace_callback(), which is called
+ *   from search_simplify(). So, $matches is an array of regular expression
+ *   matches, which means that $matches[0] contains the matched text -- a string
+ *   of CJK characters to tokenize.
+ *
+ * @return
+ *   Tokenized text, starting and ending with a space character.
  */
 function search_expand_cjk($matches) {
   $min = variable_get('minimum_word_size', 3);
   $str = $matches[0];
-  $l = drupal_strlen($str);
-  // Passthrough short words
-  if ($l <= $min) {
+  $length = drupal_strlen($str);
+  // If the text is shorter than the minimum word size, don't tokenize it.
+  if ($length <= $min) {
     return ' ' . $str . ' ';
   }
   $tokens = ' ';
-  // FIFO queue of characters
+  // Build a FIFO queue of characters.
   $chars = array();
-  // Begin loop
-  for ($i = 0; $i < $l; ++$i) {
-    // Grab next character
+  for ($i = 0; $i < $length; $i++) {
+    // Add the next character off the beginning of the string to the queue.
     $current = drupal_substr($str, 0, 1);
     $str = substr($str, strlen($current));
     $chars[] = $current;
     if ($i >= $min - 1) {
+      // Make a token of $min characters, and add it to the token string.
       $tokens .= implode('', $chars) . ' ';
+      // Shift out the first character in the queue.
       array_shift($chars);
     }
   }
diff --git a/modules/search/search.pages.inc b/modules/search/search.pages.inc
index 6e56723634139e5c9956e5487dddf73b1ced3e9c..f6058b60b119f0d0206d12244a4a2b6d2ba907b4 100644
--- a/modules/search/search.pages.inc
+++ b/modules/search/search.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.pages.inc,v 1.18 2010/04/13 15:23:03 dries Exp $
+// $Id: search.pages.inc,v 1.19 2010/05/01 01:04:24 webchick Exp $
 
 /**
  * @file
@@ -14,14 +14,14 @@ function search_view($type = 'node') {
   // the search query URL clean as a whistle:
   // search/type/keyword+keyword
   if (!isset($_POST['form_id'])) {
-    if ($type == '') {
-      // Note: search/node can not be a default tab because it would take on the
-      // path of its parent (search). It would prevent remembering keywords when
-      // switching tabs. This is why we drupal_goto to it from the parent instead.
-      drupal_goto('search/node');
+    $keys = search_get_keys();
+    if ($_GET['q'] != 'search' && $type == 'node' && !$keys) {
+      // Due to how search_menu() sets up the tabs, path search/node would
+      // display two sets of tabs. So instead, if there are no keywords and
+      // we're on the node tab, just redirect to the bare 'search' path.
+      drupal_goto('search');
     }
 
-    $keys = search_get_keys();
     // Only perform search if there is non-whitespace search term:
     $results = '';
     if (trim($keys)) {
diff --git a/modules/search/search.test b/modules/search/search.test
index c2402360e9a4fac2ab1b2aa6d70108aaef1b6e36..f129e03d51ce3c2150309f95a0b53d6ac2946732 100644
--- a/modules/search/search.test
+++ b/modules/search/search.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.test,v 1.60 2010/04/26 14:26:46 dries Exp $
+// $Id: search.test,v 1.63 2010/05/12 15:53:43 dries Exp $
 
 // The search index can contain different types of content. Typically the type is 'node'.
 // Here we test with _test_ and _test2_ as the type.
@@ -413,6 +413,88 @@ class SearchRankingTestCase extends DrupalWebTestCase {
     }
   }
 
+  /**
+   * Test rankings of HTML tags.
+   */
+  function testHTMLRankings() {
+    // Login with sufficient privileges.
+    $this->drupalLogin($this->drupalCreateUser(array('create page content')));
+    
+    // Test HTML tags with different weights.
+    $sorted_tags = array('h1', 'h2', 'h3', 'h4', 'a', 'h5', 'h6', 'notag');
+    $shuffled_tags = $sorted_tags;
+
+    // Shuffle tags to ensure HTML tags are ranked properly.
+    shuffle($shuffled_tags);
+    $settings = array(
+      'type' => 'page',
+      'title' => array(LANGUAGE_NONE => array(array('value' => 'Simple node'))),
+    );
+    foreach ($shuffled_tags as $tag) {
+      switch ($tag) {
+        case 'a':
+          $settings['body'] = array(LANGUAGE_NONE => array(array('value' => l('Drupal Rocks', 'node'), 'format' => 3)));
+          break;
+        case 'notag':
+          $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'Drupal Rocks')));
+          break;
+        default:
+          $settings['body'] = array(LANGUAGE_NONE => array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 3)));
+          break;
+      }
+      $nodes[$tag] = $this->drupalCreateNode($settings);
+    }
+
+    // Update the search index.
+    module_invoke_all('update_index');
+    search_update_totals();
+
+    // Refresh variables after the treatment.
+    $this->refreshVariables();
+    
+    // Disable all other rankings.
+    $node_ranks = array('sticky', 'promote', 'recent', 'comments', 'views');
+    foreach ($node_ranks as $node_rank) {
+      variable_set('node_rank_' . $node_rank, 0);
+    }
+    $set = node_search_execute('rocks');
+
+    // Test the ranking of each tag.
+    foreach ($sorted_tags as $tag_rank => $tag) {
+      // Assert the results.
+      if ($tag == 'notag') {
+        $this->assertEqual($set[$tag_rank]['node']->nid, $nodes[$tag]->nid, 'Search tag ranking for plain text order.');
+      } else {
+        $this->assertEqual($set[$tag_rank]['node']->nid, $nodes[$tag]->nid, 'Search tag ranking for "&lt;' . $sorted_tags[$tag_rank] . '&gt;" order.');
+      }
+    }
+
+    // Test tags with the same weight against the sorted tags.
+    $unsorted_tags = array('u', 'b', 'i', 'strong', 'em');
+    foreach ($unsorted_tags as $tag) {
+      $settings['body'] = array(LANGUAGE_NONE => array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 3)));
+      $node = $this->drupalCreateNode($settings);
+
+      // Update the search index.
+      module_invoke_all('update_index');
+      search_update_totals();
+
+      // Refresh variables after the treatment.
+      $this->refreshVariables();
+
+      $set = node_search_execute('rocks');
+
+      // Ranking should always be second to last.
+      $set = array_slice($set, -2, 1);
+
+      // Assert the results.
+      $this->assertEqual($set[0]['node']->nid, $node->nid, 'Search tag ranking for "&lt;' . $tag . '&gt;" order.');
+      
+      // Delete node so it doesn't show up in subsequent search results.
+      node_delete($node->nid);
+    }
+  }
+
   /**
    * Verifies that if we combine two rankings, search still works.
    *
@@ -511,6 +593,66 @@ class SearchBlockTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests that searching for a phrase gets the correct page count.
+ */
+class SearchExactTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Search engine phrase queries',
+      'description' => 'Tests that searching for a phrase gets the correct page count.',
+      'group' => 'Search',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('search');
+  }
+
+  /**
+   * Tests that the correct number of pager links are found for both keywords and phrases.
+   */
+  function testExactQuery() {
+    // Login with sufficient privileges.
+    $this->drupalLogin($this->drupalCreateUser(array('create page content', 'search content')));
+
+    $settings = array(
+      'type' => 'page',
+      'title' => 'Simple Node',
+    );
+    // Create nodes with exact phrase.
+    for ($i = 0; $i <= 17; $i++) {
+      $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'love pizza')));
+      $this->drupalCreateNode($settings);
+    }
+    // Create nodes containing keywords.
+    for ($i = 0; $i <= 17; $i++) {
+      $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'love cheesy pizza')));
+      $this->drupalCreateNode($settings);
+    }
+
+    // Update the search index.
+    module_invoke_all('update_index');
+    search_update_totals();
+
+    // Refresh variables after the treatment.
+    $this->refreshVariables();
+
+    // Test that the correct number of pager links are found for keyword search.
+    $edit = array('keys' => 'love pizza');
+    $this->drupalPost('search/node', $edit, t('Search'));
+    $this->assertLinkByHref('page=1', 0, '2nd page link is found for keyword search.');
+    $this->assertLinkByHref('page=2', 0, '3rd page link is found for keyword search.');
+    $this->assertLinkByHref('page=3', 0, '4th page link is found for keyword search.');
+    $this->assertNoLinkByHref('page=4', '5th page link is not found for keyword search.');
+
+    // Test that the correct number of pager links are found for exact phrase search.
+    $edit = array('keys' => '"love pizza"');
+    $this->drupalPost('search/node', $edit, t('Search'));
+    $this->assertLinkByHref('page=1', 0, '2nd page link is found for exact phrase search.');
+    $this->assertNoLinkByHref('page=2', '3rd page link is not found for exact phrase search.');
+  }
+}
 
 /**
  * Test integration searching comments.
@@ -790,3 +932,153 @@ class SearchConfigSettingsForm extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Test the CJK tokenizer.
+ */
+class SearchTokenizerTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'CJK tokenizer',
+      'description' => 'Check that CJK tokenizer works as intended.',
+      'group' => 'Search',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('search');
+  }
+
+  /**
+   * Verifies that strings of CJK characters are tokenized.
+   *
+   * The search_simplify() function does special things with numbers, symbols,
+   * and punctuation. So we only test that CJK characters that are not in these
+   * character classes are tokenized properly. See PREG_CLASS_CKJ for more
+   * information.
+   */
+  function testTokenizer() {
+    // Set the minimum word size to 1 (to split all CJK characters) and make
+    // sure CJK tokenizing is turned on.
+    variable_set('minimum_word_size', 1);
+    variable_set('overlap_cjk', TRUE);
+    $this->refreshVariables();
+
+    // Create a string of CJK characters from various character ranges in
+    // the Unicode tables.
+
+    // Beginnings of the character ranges.
+    $starts = array(
+      'CJK unified' => 0x4e00,
+      'CJK Ext A' => 0x3400,
+      'CJK Compat' => 0xf900,
+      'Hangul Jamo' => 0x1100,
+      'Hangul Ext A' => 0xa960,
+      'Hangul Ext B' => 0xd7b0,
+      'Hangul Compat' => 0x3131,
+      'Half non-punct 1' => 0xff21,
+      'Half non-punct 2' => 0xff41,
+      'Half non-punct 3' => 0xff66,
+      'Hangul Syllables' => 0xac00,
+      'Hiragana' => 0x3040,
+      'Katakana' => 0x30a1,
+      'Katakana Ext' => 0x31f0,
+      'CJK Reserve 1' => 0x20000,
+      'CJK Reserve 2' => 0x30000,
+      'Bomofo' => 0x3100,
+      'Bomofo Ext' => 0x31a0,
+      'Lisu' => 0xa4d0,
+      'Yi' => 0xa000,
+    );
+
+    // Ends of the character ranges.
+    $ends = array(
+      'CJK unified' => 0x9fcf,
+      'CJK Ext A' => 0x4dbf,
+      'CJK Compat' => 0xfaff,
+      'Hangul Jamo' => 0x11ff,
+      'Hangul Ext A' => 0xa97f,
+      'Hangul Ext B' => 0xd7ff,
+      'Hangul Compat' => 0x318e,
+      'Half non-punct 1' => 0xff3a,
+      'Half non-punct 2' => 0xff5a,
+      'Half non-punct 3' => 0xffdc,
+      'Hangul Syllables' => 0xd7af,
+      'Hiragana' => 0x309f,
+      'Katakana' => 0x30ff,
+      'Katakana Ext' => 0x31ff,
+      'CJK Reserve 1' => 0x2fffd,
+      'CJK Reserve 2' => 0x3fffd,
+      'Bomofo' => 0x312f,
+      'Bomofo Ext' => 0x31b7,
+      'Lisu' => 0xa4fd,
+      'Yi' => 0xa48f,
+    );
+
+    // Generate characters consisting of starts, midpoints, and ends.
+    $chars = array();
+    $charcodes = array();
+    foreach ($starts as $key => $value) {
+      $charcodes[] = $starts[$key];
+      $chars[] = $this->code2utf($starts[$key]);
+      $mid = round(0.5 * ($starts[$key] + $ends[$key]));
+      $charcodes[] = $mid;
+      $chars[] = $this->code2utf($mid);
+      $charcodes[] = $ends[$key];
+      $chars[] = $this->code2utf($ends[$key]);
+    }
+
+    // Merge into a string and tokenize.
+    $string = implode('', $chars);
+    $out = trim(search_simplify($string));
+    $expected = drupal_strtolower(implode(' ', $chars));
+
+    // Verify that the output matches what we expect.
+    $this->assertEqual($out, $expected, 'CJK tokenizer worked on all supplied CJK characters');
+  }
+
+  /**
+   * Verifies that strings of non-CJK characters are not tokenized.
+   *
+   * This is just a sanity check - it verifies that strings of letters are
+   * not tokenized.
+   */
+  function testNoTokenizer() {
+    // Set the minimum word size to 1 (to split all CJK characters) and make
+    // sure CJK tokenizing is turned on.
+    variable_set('minimum_word_size', 1);
+    variable_set('overlap_cjk', TRUE);
+    $this->refreshVariables();
+
+    $letters = 'abcdefghijklmnopqrstuvwxyz';
+    $out = trim(search_simplify($letters));
+
+    $this->assertEqual($letters, $out, 'Letters are not CJK tokenized');
+  }
+
+  /**
+   * Like PHP chr() function, but for unicode characters.
+   *
+   * chr() only works for ASCII characters up to character 255. This function
+   * converts a number to the corresponding unicode character. Adapted from
+   * functions supplied in comments on several functions on php.net.
+   */
+  function code2utf($num) {
+    if ($num < 128) {
+      return chr($num);
+    }
+
+    if ($num < 2048) {
+      return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
+    }
+
+    if ($num < 65536) {
+      return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
+    }
+
+    if ($num < 2097152) {
+      return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
+    }
+
+    return '';
+  }
+}
diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info
index ffe1d04e998c4d5a8578ba5207b717315698e1f9..d93bd4182d2c2aab3ae8b912f8b6907908fa9f37 100644
--- a/modules/shortcut/shortcut.info
+++ b/modules/shortcut/shortcut.info
@@ -10,8 +10,8 @@ files[] = shortcut.install
 files[] = shortcut.test
 configure = admin/config/user-interface/shortcut
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 702eb191344cfb73e9b05b7cb10571dae900668d..a781958e2f925158411c5224fcd9216a030342d2 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: drupal_web_test_case.php,v 1.211 2010/04/23 05:46:01 webchick Exp $
+// $Id: drupal_web_test_case.php,v 1.217 2010/05/10 06:38:23 dries Exp $
 
 /**
  * Base class for Drupal tests.
@@ -837,11 +837,12 @@ class DrupalWebTestCase extends DrupalTestCase {
       'locked' => 0,
     );
     $type = $forced + $settings + $defaults;
-    $type = (object)$type;
+    $type = (object) $type;
 
     $saved_type = node_type_save($type);
     node_types_rebuild();
     menu_rebuild();
+    node_add_body_field($type);
 
     $this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
 
@@ -1075,7 +1076,7 @@ class DrupalWebTestCase extends DrupalTestCase {
    */
   protected function drupalGetToken($value = '') {
     $private_key = drupal_get_private_key();
-    return md5($this->session_id . $value . $private_key);
+    return drupal_hmac_base64($value, $this->session_id . $private_key);
   }
 
   /*
@@ -1158,6 +1159,11 @@ class DrupalWebTestCase extends DrupalTestCase {
 
     $this->preloadRegistry();
 
+    // Set path variables.
+    variable_set('file_public_path', $public_files_directory);
+    variable_set('file_private_path', $private_files_directory);
+    variable_set('file_temporary_path', $temp_files_directory);
+
     // Include the default profile.
     variable_set('install_profile', 'standard');
     $profile_details = install_profile_info('standard', 'en');
@@ -1212,11 +1218,6 @@ class DrupalWebTestCase extends DrupalTestCase {
     unset($GLOBALS['conf']['language_default']);
     $language = language_default();
 
-    // Set path variables
-    variable_set('file_public_path', $public_files_directory);
-    variable_set('file_private_path', $private_files_directory);
-    variable_set('file_temporary_path', $temp_files_directory);
-
     // Use the test mail class instead of the default mail handler class.
     variable_set('mail_system', array('default-system' => 'TestingMailSystem'));
 
@@ -1359,15 +1360,20 @@ class DrupalWebTestCase extends DrupalTestCase {
   }
 
   /**
-   * Performs a cURL exec with the specified options after calling curlConnect().
+   * Initializes and executes a cURL request.
    *
    * @param $curl_options
-   *   Custom cURL options.
+   *   An associative array of cURL options to set, where the keys are constants
+   *   defined by the cURL library. For a list of valid options, see
+   *   http://www.php.net/manual/function.curl-setopt.php
    * @param $redirect
-   *   FALSE if this is an initial request, TRUE if this request is the result of
-   *   a redirect.
+   *   FALSE if this is an initial request, TRUE if this request is the result
+   *   of a redirect.
+   *
    * @return
-   *   Content returned from the exec.
+   *   The content returned from the call to curl_exec().
+   *
+   * @see curlInitialize()
    */
   protected function curlExec($curl_options, $redirect = FALSE) {
     $this->curlInitialize();
@@ -1860,8 +1866,8 @@ class DrupalWebTestCase extends DrupalTestCase {
       $name = (string) $element['name'];
       // This can either be the type of <input> or the name of the tag itself
       // for <select> or <textarea>.
-      $type = isset($element['type']) ? (string)$element['type'] : $element->getName();
-      $value = isset($element['value']) ? (string)$element['value'] : '';
+      $type = isset($element['type']) ? (string) $element['type'] : $element->getName();
+      $value = isset($element['value']) ? (string) $element['value'] : '';
       $done = FALSE;
       if (isset($edit[$name])) {
         switch ($type) {
@@ -1900,7 +1906,7 @@ class DrupalWebTestCase extends DrupalTestCase {
                 $index = 0;
                 $key = preg_replace('/\[\]$/', '', $name);
                 foreach ($options as $option) {
-                  $option_value = (string)$option['value'];
+                  $option_value = (string) $option['value'];
                   if (in_array($option_value, $new_value)) {
                     $post[$key . '[' . $index++ . ']'] = $option_value;
                     $done = TRUE;
@@ -1936,7 +1942,7 @@ class DrupalWebTestCase extends DrupalTestCase {
       if (!isset($post[$name]) && !$done) {
         switch ($type) {
           case 'textarea':
-            $post[$name] = (string)$element;
+            $post[$name] = (string) $element;
             break;
           case 'select':
             $single = empty($element['multiple']);
@@ -1950,10 +1956,10 @@ class DrupalWebTestCase extends DrupalTestCase {
               if ($option['selected'] || ($first && $single)) {
                 $first = FALSE;
                 if ($single) {
-                  $post[$name] = (string)$option['value'];
+                  $post[$name] = (string) $option['value'];
                 }
                 else {
-                  $post[$key . '[' . $index++ . ']'] = (string)$option['value'];
+                  $post[$key . '[' . $index++ . ']'] = (string) $option['value'];
                 }
               }
             }
@@ -3003,7 +3009,7 @@ function simpletest_verbose($message, $original_file_directory = NULL, $test_cla
   if ($original_file_directory) {
     $file_directory = $original_file_directory;
     $class = $test_class;
-    $verbose = variable_get('simpletest_verbose', FALSE);
+    $verbose = variable_get('simpletest_verbose', TRUE);
     $directory = $file_directory . '/simpletest/verbose';
     $writable = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
     if ($writable && !file_exists($directory . '/.htaccess')) {
diff --git a/modules/simpletest/files/README.txt b/modules/simpletest/files/README.txt
index 63ae5c3104f274c96d047e167699fe84da07d1fe..ddfce559c22450221d6ee8f62a5a741e3507d5f3 100644
--- a/modules/simpletest/files/README.txt
+++ b/modules/simpletest/files/README.txt
@@ -1,5 +1,5 @@
-$Id: README.txt,v 1.1 2008/04/20 18:23:30 dries Exp $
+$Id: README.txt,v 1.2 2010/04/28 20:25:21 dries Exp $
 
 These files are use in some tests that upload files or other operations were
 a file is useful. These files are copied to the files directory as specified
-in the site settings. Other tests files are generated in order to save space.
\ No newline at end of file
+in the site settings. Other tests files are generated in order to save space.
diff --git a/modules/simpletest/files/javascript-1.txt b/modules/simpletest/files/javascript-1.txt
index e0206ba8319b0db6cc237a16010a78b5a279280a..efd44fd9360ad1865cc4a31ca2a2f64b4977be29 100644
--- a/modules/simpletest/files/javascript-1.txt
+++ b/modules/simpletest/files/javascript-1.txt
@@ -1,3 +1,3 @@
 <script>
 alert('SimpleTest PHP was executed!');
-</script>
\ No newline at end of file
+</script>
diff --git a/modules/simpletest/files/php-1.txt b/modules/simpletest/files/php-1.txt
index dc8e64213f09a797039d8797a8d7c6bf0ca93eb9..52788b6feac0266e42e90d00f61e2689768edf69 100644
--- a/modules/simpletest/files/php-1.txt
+++ b/modules/simpletest/files/php-1.txt
@@ -1,3 +1,3 @@
 <?php
 print 'SimpleTest PHP was executed!';
-?>
\ No newline at end of file
+?>
diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info
index c2d617be202dca3dc1631b337439e9c52655030b..c44669271d98748dd80f78fff31c736744e35b39 100644
--- a/modules/simpletest/simpletest.info
+++ b/modules/simpletest/simpletest.info
@@ -38,8 +38,8 @@ files[] = tests/unicode.test
 files[] = tests/update.test
 files[] = tests/xmlrpc.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/simpletest.pages.inc b/modules/simpletest/simpletest.pages.inc
index 8e46e964ffae0c0909959d293afbe6ed28cfc67b..2a0844a9e07f1e5f3f2a06df7a6865056a1196f1 100644
--- a/modules/simpletest/simpletest.pages.inc
+++ b/modules/simpletest/simpletest.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: simpletest.pages.inc,v 1.28 2010/04/13 15:23:03 dries Exp $
+// $Id: simpletest.pages.inc,v 1.30 2010/05/19 19:22:24 dries Exp $
 
 /**
  * @file
@@ -71,10 +71,11 @@ function theme_simpletest_test_table($variables) {
 
   drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
   drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js');
+  drupal_add_js('misc/tableselect.js');
 
   // Create header for test selection table.
   $header = array(
-    theme('table_select_header_cell'),
+    array('class' => array('select-all')),
     array('data' => t('Test'), 'class' => array('simpletest_test')),
     array('data' => t('Description'), 'class' => array('simpletest_description')),
   );
@@ -276,7 +277,7 @@ function simpletest_result_form($form, &$form_state, $test_id) {
 
     // Set summary information.
     $group_summary['#ok'] = $group_summary['#fail'] + $group_summary['#exception'] == 0;
-    $form['result']['results'][$group]['#collapsed'] = $group_summary['#ok'] && !$group_summary['#debug'];
+    $form['result']['results'][$group]['#collapsed'] = $group_summary['#ok'];
 
     // Store test group (class) as for use in filter.
     $filter[$group_summary['#ok'] ? 'pass' : 'fail'][] = $group;
@@ -444,7 +445,7 @@ function simpletest_settings_form($form, &$form_state) {
     '#type' => 'checkbox',
     '#title' => t('Provide verbose information when running tests'),
     '#description' => t('The verbose data will be printed along with the standard assertions and is useful for debugging. The verbose data will be erased between each test suite run. The verbose data output is very detailed and should only be used when debugging.'),
-    '#default_value' => variable_get('simpletest_verbose', FALSE),
+    '#default_value' => variable_get('simpletest_verbose', TRUE),
   );
 
   $form['httpauth'] = array(
diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test
index e528595e9280d8b87b3a3977a4822ba9086d02e2..6525ae391fb4ec68f86d0d0c887fa8b32ceadc34 100644
--- a/modules/simpletest/simpletest.test
+++ b/modules/simpletest/simpletest.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: simpletest.test,v 1.40 2010/03/31 20:05:06 dries Exp $
+// $Id: simpletest.test,v 1.41 2010/05/10 06:38:23 dries Exp $
 
 class SimpleTestFunctionalTest extends DrupalWebTestCase {
   /**
@@ -415,6 +415,26 @@ class SimpleTestMailCaptureTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Test Folder creation
+ */
+class SimpleTestFolderTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Testing SimpleTest setUp',
+      'description' => "This test will check SimpleTest's treatment of hook_install during setUp.  Image module is used for test.",
+      'group' => 'SimpleTest',
+    );
+  }
+
+  function testFolderSetup() {
+    if (module_exists('image')) {
+      $path = file_directory_path() . '/styles';
+      $this->assertTrue(file_prepare_directory($path, FALSE), "Directory created.");
+    }
+  }
+}
+
 /**
  * Test required modules for tests.
  */
diff --git a/modules/simpletest/tests/actions.test b/modules/simpletest/tests/actions.test
index 3a098a89435d76e2f2c9d4d0d20a6cfa001d0e88..1dee630e460c7f0fd2d409c93150488dabf2fa6e 100644
--- a/modules/simpletest/tests/actions.test
+++ b/modules/simpletest/tests/actions.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: actions.test,v 1.14 2010/03/26 17:14:45 dries Exp $
+// $Id: actions.test,v 1.15 2010/05/01 08:12:23 dries Exp $
 
 class ActionsConfigurationTestCase extends DrupalWebTestCase {
   public static function getInfo() {
@@ -21,7 +21,7 @@ class ActionsConfigurationTestCase extends DrupalWebTestCase {
 
     // Make a POST request to admin/config/system/actions/manage.
     $edit = array();
-    $edit['action'] = md5('system_goto_action');
+    $edit['action'] = drupal_hash_base64('system_goto_action');
     $this->drupalPost('admin/config/system/actions/manage', $edit, t('Create'));
 
     // Make a POST request to the individual action configuration page.
@@ -29,7 +29,7 @@ class ActionsConfigurationTestCase extends DrupalWebTestCase {
     $action_label = $this->randomName();
     $edit['actions_label'] = $action_label;
     $edit['url'] = 'admin';
-    $this->drupalPost('admin/config/system/actions/configure/' . md5('system_goto_action'), $edit, t('Save'));
+    $this->drupalPost('admin/config/system/actions/configure/' . drupal_hash_base64('system_goto_action'), $edit, t('Save'));
 
     // Make sure that the new complex action was saved properly.
     $this->assertText(t('The action has been successfully saved.'), t("Make sure we get a confirmation that we've successfully saved the complex action."));
@@ -87,7 +87,7 @@ class ActionLoopTestCase extends DrupalWebTestCase {
     $user = $this->drupalCreateUser(array('administer actions'));
     $this->drupalLogin($user);
 
-    $hash = md5('actions_loop_test_log');
+    $hash = drupal_hash_base64('actions_loop_test_log');
     $edit = array('aid' => $hash);
     $this->drupalPost('admin/structure/trigger/actions_loop_test', $edit, t('Assign'));
 
diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info
index a24f5132d9ba79178f23451b54aac11234faeb47..dbf7b16a92f37398976a4df83b87a8c41f1bc26a 100644
--- a/modules/simpletest/tests/actions_loop_test.info
+++ b/modules/simpletest/tests/actions_loop_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = actions_loop_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test
index 3fc93e38772c249254150829c986fef16fbd0cec..2e10b80f18a53044271439bddaa853f434377ea5 100644
--- a/modules/simpletest/tests/ajax.test
+++ b/modules/simpletest/tests/ajax.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: ajax.test,v 1.9 2010/04/11 18:33:44 dries Exp $
+// $Id: ajax.test,v 1.11 2010/04/30 08:07:55 dries Exp $
 
 class AJAXTestCase extends DrupalWebTestCase {
   function setUp() {
@@ -146,6 +146,11 @@ class AJAXCommandsTestCase extends AJAXTestCase {
     $command = $commands[0];
     $this->assertTrue($command['command'] == 'insert' && $command['method'] == 'html' && $command['data'] == 'replacement text', "'html' AJAX command issued with correct data");
 
+    // Tests the 'insert' command.
+    $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX insert: Let client insert based on #ajax['method']."))));
+    $command = $commands[0];
+    $this->assertTrue($command['command'] == 'insert' && $command['method'] == NULL && $command['data'] == 'insert replacement text', "'insert' AJAX command issued with correct data");
+
     // Tests the 'prepend' command.
     $commands = $this->discardSettings($this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'prepend': Click to prepend something"))));
     $command = $commands[0];
@@ -268,9 +273,7 @@ class AJAXMultiFormTestCase extends AJAXTestCase {
       $this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == 1, t('Found the correct number of field items on the initial page.'));
       $this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button on the initial page.'));
     }
-    // @todo Legacy bug of duplicate ids for filter-guidelines-FORMAT. See
-    //   http://drupal.org/node/755566.
-    $this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other', array('filter-guidelines-1', 'filter-guidelines-2', 'filter-guidelines-3'));
+    $this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
 
     // Submit the "add more" button of each form twice. After each corresponding
     // page update, ensure the same as above. To successfully implement
@@ -286,9 +289,7 @@ class AJAXMultiFormTestCase extends AJAXTestCase {
         $settings = array_merge_recursive($settings, $commands[0]['settings']);
         $this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == $i+2, t('Found the correct number of field items after an AJAX submission.'));
         $this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button after an AJAX submission.'));
-        // @todo Legacy bug of duplicate ids for filter-guidelines-FORMAT. See
-        //   http://drupal.org/node/755566.
-        $this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other', array('filter-guidelines-1', 'filter-guidelines-2', 'filter-guidelines-3'));
+        $this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
       }
     }
   }
diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info
index 0b357f5a296714f0c3e21ee701edec583874ed9b..9d20ddc0ce11b871d743149489c8685172933933 100644
--- a/modules/simpletest/tests/ajax_forms_test.info
+++ b/modules/simpletest/tests/ajax_forms_test.info
@@ -7,8 +7,8 @@ files[] = ajax_forms_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/ajax_forms_test.module b/modules/simpletest/tests/ajax_forms_test.module
index acd9226c221ad2c44b6b25acd995ea26001a8f02..3f7c765b7350c75deacc7d46c7fc46b528c6fa7e 100644
--- a/modules/simpletest/tests/ajax_forms_test.module
+++ b/modules/simpletest/tests/ajax_forms_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: ajax_forms_test.module,v 1.5 2010/03/26 18:58:12 dries Exp $
+// $Id: ajax_forms_test.module,v 1.7 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -81,8 +81,8 @@ function ajax_forms_test_simple_form_select_callback($form, $form_state) {
  */
 function ajax_forms_test_simple_form_checkbox_callback($form, $form_state) {
   $commands = array();
-  $commands[] = ajax_command_html('#ajax_checkbox_value', (int)$form_state['values']['checkbox']);
-  $commands[] = ajax_command_data('#ajax_checkbox_value', 'form_state_value_select', (int)$form_state['values']['checkbox']);
+  $commands[] = ajax_command_html('#ajax_checkbox_value', (int) $form_state['values']['checkbox']);
+  $commands[] = ajax_command_data('#ajax_checkbox_value', 'form_state_value_select', (int) $form_state['values']['checkbox']);
   return array('#type' => 'ajax', '#commands' => $commands);
 }
 
@@ -186,6 +186,17 @@ function ajax_forms_test_ajax_commands_form($form, &$form_state) {
     '#suffix' => '<div id="html_div">Original contents</div>',
   );
 
+  // Shows the AJAX 'insert' command.
+  $form['insert_command_example'] = array(
+    '#value' => t("AJAX insert: Let client insert based on #ajax['method']."),
+    '#type' => 'submit',
+    '#ajax' => array(
+      'callback' => 'ajax_forms_test_advanced_commands_insert_callback',
+      'method' => 'prepend',
+    ),
+    '#suffix' => '<div id="insert_div">Original contents</div>',
+  );
+
   // Shows the AJAX 'prepend' command.
   $form['prepend_command_example'] = array(
     '#value' => t("AJAX 'prepend': Click to prepend something"),
@@ -320,6 +331,15 @@ function ajax_forms_test_advanced_commands_html_callback($form, $form_state) {
   return array('#type' => 'ajax', '#commands' => $commands);
 }
 
+/**
+ * AJAX callback for 'insert'.
+ */
+function ajax_forms_test_advanced_commands_insert_callback($form, $form_state) {
+  $commands = array();
+  $commands[] = ajax_command_insert('#insert_div', 'insert replacement text');
+  return array('#type' => 'ajax', '#commands' => $commands);
+}
+
 /**
  * AJAX callback for 'prepend'.
  */
diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info
index 98b94a798788456809ea5d48f760cfa3b8bf41a7..042a198a8406fc0f311048ff0abec35a141120cc 100644
--- a/modules/simpletest/tests/ajax_test.info
+++ b/modules/simpletest/tests/ajax_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = ajax_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/batch.test b/modules/simpletest/tests/batch.test
index f9aa936c2bf06d51b8eba24fc96edc65060b0172..5c11f7269c457174ae93414e167253b6ad50f7db 100644
--- a/modules/simpletest/tests/batch.test
+++ b/modules/simpletest/tests/batch.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: batch.test,v 1.8 2010/01/08 06:36:34 webchick Exp $
+// $Id: batch.test,v 1.9 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -352,7 +352,7 @@ class BatchPercentagesUnitTestCase extends DrupalUnitTestCase {
     foreach ($this->testCases as $expected_result => $arguments) {
       // PHP sometimes casts numeric strings that are array keys to integers,
       // cast them back here.
-      $expected_result = (string)$expected_result;
+      $expected_result = (string) $expected_result;
       $total = $arguments['total'];
       $current = $arguments['current'];
       $actual_result = _batch_api_percentage($total, $current);
diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info
index 6e0a4adbd9ee015a3db6b89c6062e93699c9a778..aad88e7b34d6707fea1c491bf0e50aef4703517e 100644
--- a/modules/simpletest/tests/batch_test.info
+++ b/modules/simpletest/tests/batch_test.info
@@ -8,8 +8,8 @@ files[] = batch_test.module
 files[] = batch_test.callbacks.inc
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test
index 10c434c0db6a16ef00eee050d5769a245c32a509..9bbe1378b7e7fc93de9eac3e467f0c351c250ee9 100644
--- a/modules/simpletest/tests/bootstrap.test
+++ b/modules/simpletest/tests/bootstrap.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: bootstrap.test,v 1.29 2010/03/17 13:58:45 dries Exp $
+// $Id: bootstrap.test,v 1.30 2010/05/12 08:26:15 dries Exp $
 
 class BootstrapIPAddressTestCase extends DrupalWebTestCase {
 
@@ -105,7 +105,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
    * Test support for requests containing If-Modified-Since and If-None-Match headers.
    */
   function testConditionalRequests() {
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
 
     // Fill the cache.
     $this->drupalGet('');
@@ -143,7 +143,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
    * Test cache headers.
    */
   function testPageCache() {
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
 
     // Fill the cache.
     $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
@@ -187,7 +187,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
    * mod_deflate Apache module.
    */
   function testPageCompression() {
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
 
     // Fill the cache and verify that output is compressed.
     $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
@@ -280,14 +280,14 @@ class HookBootExitTestCase extends DrupalWebTestCase {
    */
   function testHookBootExit() {
     // Test with cache disabled. Boot and exit should always fire.
-    variable_set('cache', CACHE_DISABLED);
+    variable_set('cache', 0);
     $this->drupalGet('');
     $calls = 1;
     $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with disabled cache.'));
     $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with disabled cache.'));
 
     // Test with normal cache. Boot and exit should be called.
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
     $this->drupalGet('');
     $calls++;
     $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.'));
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index 8c277567395c88af62497b30be3ebeec0a12e40b..3e8d9d6956af487fdd1fd53b17aa01f7088812ba 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: common.test,v 1.110 2010/04/22 21:41:09 webchick Exp $
+// $Id: common.test,v 1.112 2010/05/18 06:59:46 dries Exp $
 
 /**
  * @file
@@ -86,6 +86,28 @@ class CommonURLUnitTest extends DrupalWebTestCase {
     $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, t('XSS attack @path was filtered', array('@path' => $path)));
   }
 
+  /*
+   * Tests for active class in l() function.
+   */
+  function testLActiveClass() {
+    $link = l($this->randomName(), $_GET['q']);
+    $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));
+  }
+
+  /**
+   * Tests for custom class in l() function.
+   */
+  function testLCustomClass() {
+    $class = $this->randomName();
+    $link = l($this->randomName(), $_GET['q'], array('attributes' => array('class' => array($class))));
+    $this->assertTrue($this->hasClass($link, $class), t('Custom class @class is present on link when requested', array('@class' => $class)));
+    $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));    
+  }
+
+  private function hasClass($link, $class) {
+    return preg_match('|class="([^\"\s]+\s+)*' . $class . '|', $link);
+  }
+  
   /**
    * Test drupal_get_query_parameters().
    */
@@ -907,19 +929,6 @@ class DrupalHTTPRequestTestCase extends DrupalWebTestCase {
     $redirect_307 = drupal_http_request(url('system-test/redirect/307', array('absolute' => TRUE)), array('max_redirects' => 0));
     $this->assertFalse(isset($redirect_307->redirect_code), t('drupal_http_request does not follow 307 redirect if max_redirects = 0.'));
   }
-
-  function testDrupalGetDestination() {
-    $query = $this->randomName(10);
-
-    // Verify that a 'destination' query string is used as destination.
-    $this->drupalGet('system-test/destination', array('query' => array('destination' => $query)));
-    $this->assertText('The destination: ' . $query, t('The given query string destination is determined as destination.'));
-
-    // Verify that the current path is used as destination.
-    $this->drupalGet('system-test/destination', array('query' => array($query => NULL)));
-    $url = 'system-test/destination?' . $query;
-    $this->assertText('The destination: ' . $url, t('The current path is determined as destination.'));
-  }
 }
 
 /**
@@ -985,17 +994,33 @@ class DrupalGotoTest extends DrupalWebTestCase {
   }
 
   /**
-   * Test setting and retrieving content for theme regions.
+   * Test drupal_goto().
    */
   function testDrupalGoto() {
     $this->drupalGet('common-test/drupal_goto/redirect');
+    $headers = $this->drupalGetHeaders(TRUE);
+    list(, $status) = explode(' ', $headers[0][':status'], 3);
+    $this->assertEqual($status, 302, t('Expected response code was sent.'));
+    $this->assertText('drupal_goto', t('Drupal goto redirect succeeded.'));
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), t('Drupal goto redirected to expected URL.'));
 
-    $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program."));
-    $this->assertText('drupal_goto', t("Drupal goto redirect failed."));
+    $this->drupalGet('common-test/drupal_goto/redirect_advanced');
+    $headers = $this->drupalGetHeaders(TRUE);
+    list(, $status) = explode(' ', $headers[0][':status'], 3);
+    $this->assertEqual($status, 301, t('Expected response code was sent.'));
+    $this->assertText('drupal_goto', t('Drupal goto redirect succeeded.'));
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), t('Drupal goto redirected to expected URL.'));
+
+    // Test that drupal_goto() respects ?destination=xxx. Use an complicated URL
+    // to test that the path is encoded and decoded properly.
+    $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123';
+    $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination)));
+    $this->assertText('drupal_goto', t('Drupal goto redirect with destination succeeded.'));
+    $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), t('Drupal goto redirected to given query string destination. '));
   }
 
   /**
-   * Test setting and retrieving content for theme regions.
+   * Test hook_drupal_goto_alter().
    */
   function testDrupalGotoAlter() {
     $this->drupalGet('common-test/drupal_goto/redirect_fail');
@@ -1003,6 +1028,22 @@ class DrupalGotoTest extends DrupalWebTestCase {
     $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program."));
     $this->assertNoText('drupal_goto_fail', t("Drupal goto redirect failed."));
   }
+
+  /**
+   * Test drupal_get_destination().
+   */
+  function testDrupalGetDestination() {
+    $query = $this->randomName(10);
+
+    // Verify that a 'destination' query string is used as destination.
+    $this->drupalGet('common-test/destination', array('query' => array('destination' => $query)));
+    $this->assertText('The destination: ' . $query, t('The given query string destination is determined as destination.'));
+
+    // Verify that the current path is used as destination.
+    $this->drupalGet('common-test/destination', array('query' => array($query => NULL)));
+    $url = 'common-test/destination?' . $query;
+    $this->assertText('The destination: ' . $url, t('The current path is determined as destination.'));
+  }
 }
 
 /**
diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info
index 987cd5af7b9998c051b55b99f44541042c5f014b..0249090e85306be04b539ebc909c075bc4965d43 100644
--- a/modules/simpletest/tests/common_test.info
+++ b/modules/simpletest/tests/common_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = common_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module
index de2e32b61fb582eaec96061996b7cea3a01189ad..4dc29b1c84eb06e5712f5fec12a0a32bef1b10f3 100644
--- a/modules/simpletest/tests/common_test.module
+++ b/modules/simpletest/tests/common_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: common_test.module,v 1.10 2010/03/02 08:47:41 dries Exp $
+// $Id: common_test.module,v 1.11 2010/05/18 06:59:46 dries Exp $
 
 /**
  * @file
@@ -28,6 +28,12 @@ function common_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['common-test/drupal_goto/redirect_advanced'] = array(
+    'title' => 'Drupal Goto',
+    'page callback' => 'common_test_drupal_goto_redirect_advanced',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['common-test/drupal_goto/redirect_fail'] = array(
     'title' => 'Drupal Goto Failure',
     'page callback' => 'drupal_goto',
@@ -35,6 +41,12 @@ function common_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['common-test/destination'] = array(
+    'title' => 'Drupal Get Destination',
+    'page callback' => 'common_test_destination',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['common-test/query-string'] = array(
     'title' => 'Test querystring',
     'page callback' => 'common_test_js_and_css_querystring',
@@ -45,11 +57,17 @@ function common_test_menu() {
 }
 
 /**
- * Check that drupal_goto() exits once called.
+ * Redirect using drupal_goto().
  */
 function common_test_drupal_goto_redirect() {
   drupal_goto('common-test/drupal_goto');
-  print t("Drupal goto failed to stop program");
+}
+
+/**
+ * Redirect using drupal_goto().
+ */
+function common_test_drupal_goto_redirect_advanced() {
+  drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
 }
 
 /**
@@ -75,6 +93,14 @@ function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code)
   }
 }
 
+/**
+ * Print destination query parameter.
+ */
+function common_test_destination() {
+  $destination = drupal_get_destination();
+  print "The destination: " . check_plain($destination['destination']);
+}
+
 /**
  * Implements hook_TYPE_alter().
  */
diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info
index ca0f2275d154695017fc0765c0d572f732b03f95..ef98079f336e9dcdcf44d363d78695e638bc753e 100644
--- a/modules/simpletest/tests/database_test.info
+++ b/modules/simpletest/tests/database_test.info
@@ -8,8 +8,8 @@ files[] = database_test.install
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test
index 018e7fec844f1874870cec3eb01255ed173ce218..492f3b7294f7d45ffe3bb0c10cc8183fffeed0c8 100644
--- a/modules/simpletest/tests/database_test.test
+++ b/modules/simpletest/tests/database_test.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: database_test.test,v 1.87 2010/04/11 18:33:44 dries Exp $
+// $Id: database_test.test,v 1.92 2010/05/15 07:04:21 dries Exp $
 
 /**
  * Dummy class for fetching into a class.
@@ -456,7 +456,7 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
     $query->execute();
 
     $num_records_after = db_query('SELECT COUNT(*) FROM {test}')->fetchField();
-    $this->assertIdentical($num_records_before + 1, (int)$num_records_after, t('Record inserts correctly.'));
+    $this->assertIdentical($num_records_before + 1, (int) $num_records_after, t('Record inserts correctly.'));
     $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Yoko'))->fetchField();
     $this->assertIdentical($saved_age, '29', t('Can retrieve after inserting.'));
   }
@@ -1015,7 +1015,6 @@ class DatabaseDeleteTruncateTestCase extends DatabaseTestCase {
     $this->assertEqual($num_records_before, $num_records_after + $num_deleted, t('Deletion adds up.'));
   }
 
-
   /**
    * Confirm that we can truncate a whole table successfully.
    */
@@ -1274,6 +1273,27 @@ class DatabaseSelectTestCase extends DatabaseTestCase {
     $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
   }
 
+  /**
+   * Test rudimentary SELECT statement with a COMMENT.
+   */
+  function testSimpleComment() {
+    $query = db_select('test')->comment('Testing query comments');
+    $name_field = $query->addField('test', 'name');
+    $age_field = $query->addField('test', 'age', 'age');
+    $result = $query->execute();
+
+    $num_records = 0;
+    foreach ($result as $record) {
+      $num_records++;
+    }
+
+    $query = (string)$query;
+    $expected = "/* Testing query comments */ SELECT test.name AS name, test.age AS age\nFROM \n{test} test";
+
+    $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
+    $this->assertEqual($query, $expected, t('The flattened query contains the comment string.'));
+  }
+
   /**
    * Test basic conditionals on SELECT statements.
    */
@@ -1835,7 +1855,7 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
     $task_field = $query->addField('t', 'task');
     $query->orderBy($count_field);
     $query->groupBy($task_field);
-    $query->havingCondition('COUNT(task)', 2, '>=');
+    $query->having('COUNT(task) >= 2');
     $result = $query->execute();
 
     $num_records = 0;
@@ -1972,6 +1992,20 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
     $job = $query->execute()->fetchField();
     $this->assertEqual($job, 'Songwriter', t('Correct data retrieved.'));
   }
+
+  /**
+   * Confirm we can join on a single table twice with a dynamic alias.
+   */
+  function testJoinTwice() {
+    $query = db_select('test')->fields('test');
+    $alias = $query->join('test', 'test', 'test.job = %alias.job');
+    $query->addField($alias, 'name', 'othername');
+    $query->addField($alias, 'job', 'otherjob');
+    $query->where("$alias.name <> test.name");
+    $crowded_job = $query->execute()->fetch();
+    $this->assertEqual($crowded_job->job, $crowded_job->otherjob, t('Correctly joined same table twice.'));
+    $this->assertNotEqual($crowded_job->name, $crowded_job->othername, t('Correctly joined same table twice.'));
+  }
 }
 
 class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase {
@@ -2326,22 +2360,6 @@ class DatabaseAlterTestCase extends DatabaseTestCase {
     $this->assertEqual($records[0]->$pid_field, 1, t('Correct data retrieved.'));
     $this->assertEqual($records[0]->$task_field, 'sleep', t('Correct data retrieved.'));
   }
-}
-
-/**
- * Select alter tests, part 2.
- *
- * @see database_test_query_alter()
- */
-class DatabaseAlter2TestCase extends DatabaseTestCase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Query altering tests, part 2',
-      'description' => 'Test the hook_query_alter capabilities of the Select builder.',
-      'group' => 'Database',
-    );
-  }
 
   /**
    * Test that we can alter the fields of a query.
@@ -2390,6 +2408,31 @@ class DatabaseAlter2TestCase extends DatabaseTestCase {
 
     $this->assertEqual($num_records, 4, t('Returned the correct number of rows.'));
   }
+
+  /**
+   * Test that we can do basic alters on subqueries.
+   */
+  function testSimpleAlterSubquery() {
+    // Create a sub-query with an alter tag.
+    $subquery = db_select('test', 'p');
+    $subquery->addField('p', 'name');
+    $subquery->addField('p', 'id');
+    // Pick out George.
+    $subquery->condition('age', 27);
+    $subquery->addExpression("age*2", 'double_age');
+    // This query alter should change it to age * 3.
+    $subquery->addTag('database_test_alter_change_expressions');
+
+    // Create a main query and join to sub-query.
+    $query = db_select('test_task', 'tt');
+    $query->join($subquery, 'pq', 'pq.id = tt.pid');
+    $age_field = $query->addField('pq', 'double_age');
+    $name_field = $query->addField('pq', 'name');
+
+    $record = $query->execute()->fetch();
+    $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.'));
+    $this->assertEqual($record->$age_field, 27*3, t('Fetched age expression is correct.'));
+  }
 }
 
 /**
@@ -3227,5 +3270,4 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
 
     $this->assertEqual($result->fetchAll(), array(), t('Empty array returned from empty result set.'));
   }
-
 }
diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info
index c0b8b31c53f60b3a963c862db7430ec5c84bbff6..d0f2be50ca49f18829ba002fd73feeaee644af9d 100644
--- a/modules/simpletest/tests/entity_cache_test.info
+++ b/modules/simpletest/tests/entity_cache_test.info
@@ -8,8 +8,8 @@ files[] = entity_cache_test.module
 dependencies[] = entity_cache_test_dependency
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info
index 0888277d55f6b10c39db81ee86bd6055b9a015cd..3300857f6d836d67a2b1da4128449c3036b01164 100644
--- a/modules/simpletest/tests/entity_cache_test_dependency.info
+++ b/modules/simpletest/tests/entity_cache_test_dependency.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = entity_cache_test_dependency.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info
index 324a296e1473afb66aa4fa68a70ab731d99d487a..438f3b65543f423a00e26e45dc5f11fb8e73a292 100644
--- a/modules/simpletest/tests/error_test.info
+++ b/modules/simpletest/tests/error_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = error_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test
index 971aa2522e4f82e2691d38bffd444408996cb2f1..dd4270b9b151e3cf5f65bc5db5c4122d91f452a9 100644
--- a/modules/simpletest/tests/file.test
+++ b/modules/simpletest/tests/file.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.test,v 1.53 2010/04/11 18:33:44 dries Exp $
+// $Id: file.test,v 1.54 2010/05/11 10:56:04 dries Exp $
 
 /**
  *  @file
@@ -2022,7 +2022,6 @@ class FileURLRewritingTest extends FileTestCase {
 
   function setUp() {
     parent::setUp('file_test');
-    variable_set('file_test_hook_file_url_alter', TRUE);
   }
 
   /**
@@ -2031,12 +2030,33 @@ class FileURLRewritingTest extends FileTestCase {
   function testShippedFileURL()  {
     // Test generating an URL to a shipped file (i.e. a file that is part of
     // Drupal core, a module or a theme, for example a JavaScript file).
+
+    // Test alteration of file URLs to use a CDN.
+    variable_set('file_test_hook_file_url_alter', 'cdn');
+    $filepath = 'misc/jquery.js';
+    $url = file_create_url($filepath);
+    $this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $filepath, $url, t('Correctly generated a CDN URL for a shipped file.'));
+    $filepath = 'misc/favicon.ico';
+    $url = file_create_url($filepath);
+    $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $filepath, $url, t('Correctly generated a CDN URL for a shipped file.'));
+
+    // Test alteration of file URLs to use root-relative URLs.
+    variable_set('file_test_hook_file_url_alter', 'root-relative');
+    $filepath = 'misc/jquery.js';
+    $url = file_create_url($filepath);
+    $this->assertEqual(base_path() . '/' . $filepath, $url, t('Correctly generated a root-relative URL for a shipped file.'));
+    $filepath = 'misc/favicon.ico';
+    $url = file_create_url($filepath);
+    $this->assertEqual(base_path() . '/' . $filepath, $url, t('Correctly generated a root-relative URL for a shipped file.'));
+
+    // Test alteration of file URLs to use protocol-relative URLs.
+    variable_set('file_test_hook_file_url_alter', 'protocol-relative');
     $filepath = 'misc/jquery.js';
     $url = file_create_url($filepath);
-    $this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $filepath, $url, t('Correctly generated a URL for a shipped file.'));
+    $this->assertEqual('/' . base_path() . '/' . $filepath, $url, t('Correctly generated a protocol-relative URL for a shipped file.'));
     $filepath = 'misc/favicon.ico';
     $url = file_create_url($filepath);
-    $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $filepath, $url, t('Correctly generated a URL for a shipped file.'));
+    $this->assertEqual('/' . base_path() . '/' . $filepath, $url, t('Correctly generated a protocol-relative URL for a shipped file.'));
   }
 
   /**
@@ -2044,9 +2064,24 @@ class FileURLRewritingTest extends FileTestCase {
    */
   function testPublicCreatedFileURL() {
     // Test generating an URL to a created file.
+
+    // Test alteration of file URLs to use a CDN.
+    variable_set('file_test_hook_file_url_alter', 'cdn');
+    $file = $this->createFile();
+    $url = file_create_url($file->uri);
+    $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . file_directory_path() . '/' . $file->filename, $url, t('Correctly generated a CDN URL for a created file.'));
+
+    // Test alteration of file URLs to use root-relative URLs.
+    variable_set('file_test_hook_file_url_alter', 'root-relative');
+    $file = $this->createFile();
+    $url = file_create_url($file->uri);
+    $this->assertEqual(base_path() . '/' . file_directory_path() . '/' . $file->filename, $url, t('Correctly generated a root-relative URL for a created file.'));
+
+    // Test alteration of file URLs to use a protocol-relative URLs.
+    variable_set('file_test_hook_file_url_alter', 'protocol-relative');
     $file = $this->createFile();
     $url = file_create_url($file->uri);
-    $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . file_directory_path() . '/' . $file->filename, $url, t('Correctly generated a URL for a created file.'));
+    $this->assertEqual('/' . base_path() . '/' . file_directory_path() . '/' . $file->filename, $url, t('Correctly generated a protocol-relative URL for a created file.'));
   }
 }
 
diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info
index 53fa3ce897b8051982db7281c4399ebd289eb95d..1280ef9e2d7a3b198d4bbee21bf04f68c8b269f2 100644
--- a/modules/simpletest/tests/file_test.info
+++ b/modules/simpletest/tests/file_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = file_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/file_test.module b/modules/simpletest/tests/file_test.module
index 8c531f2d0f20508cfd86bf3d849c49f68933bb90..d7624e55eef75b6554bdc2739224f9f742e49bb1 100644
--- a/modules/simpletest/tests/file_test.module
+++ b/modules/simpletest/tests/file_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: file_test.module,v 1.21 2010/03/26 17:14:45 dries Exp $
+// $Id: file_test.module,v 1.22 2010/05/11 10:56:04 dries Exp $
 
 /**
  * @file
@@ -286,41 +286,90 @@ function file_test_file_delete($file) {
 function file_test_file_url_alter(&$uri) {
   // Only run this hook when this variable is set. Otherwise, we'd have to add
   // another hidden test module just for this hook.
-  if (!variable_get('file_test_hook_file_url_alter', FALSE)) {
+  $alter_mode = variable_get('file_test_hook_file_url_alter', FALSE);
+  if (!$alter_mode) {
     return;
   }
-
-  $cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png');
-
-  // Most CDNs don't support private file transfers without a lot of hassle,
-  // so don't support this in the common case.
-  $schemes = array('public');
-
-  $scheme = file_uri_scheme($uri);
-
-  // Only serve shipped files and public created files from the CDN.
-  if (!$scheme || in_array($scheme, $schemes)) {
-    // Shipped files.
-    if (!$scheme) {
-      $path = $uri;
-    }
-    // Public created files.
-    else {
-      $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
-      $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
+  // Test alteration of file URLs to use a CDN.
+  elseif ($alter_mode == 'cdn') {
+    $cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png');
+
+    // Most CDNs don't support private file transfers without a lot of hassle,
+    // so don't support this in the common case.
+    $schemes = array('public');
+
+    $scheme = file_uri_scheme($uri);
+
+    // Only serve shipped files and public created files from the CDN.
+    if (!$scheme || in_array($scheme, $schemes)) {
+      // Shipped files.
+      if (!$scheme) {
+        $path = $uri;
+      }
+      // Public created files.
+      else {
+        $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
+        $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
+      }
+
+      // Clean up Windows paths.
+      $path = str_replace('\\', '/', $path);
+
+      // Serve files with one of the CDN extensions from CDN 1, all others from
+      // CDN 2.
+      $pathinfo = pathinfo($path);
+      if (array_key_exists('extension', $pathinfo) && in_array($pathinfo['extension'], $cdn_extensions)) {
+        $uri = FILE_URL_TEST_CDN_1 . '/' . $path;
+      }
+      else {
+        $uri = FILE_URL_TEST_CDN_2 . '/' . $path;
+      }
     }
-
-    // Clean up Windows paths.
-    $path = str_replace('\\', '/', $path);
-
-    // Serve files with one of the CDN extensions from CDN 1, all others from
-    // CDN 2.
-    $pathinfo = pathinfo($path);
-    if (array_key_exists('extension', $pathinfo) && in_array($pathinfo['extension'], $cdn_extensions)) {
-      $uri = FILE_URL_TEST_CDN_1 . '/' . $path;
+  }
+  // Test alteration of file URLs to use root-relative URLs.
+  elseif ($alter_mode == 'root-relative') {
+    // Only serve shipped files and public created files with root-relative
+    // URLs.
+    $scheme = file_uri_scheme($uri);
+    if (!$scheme || $scheme == 'public') {
+      // Shipped files.
+      if (!$scheme) {
+        $path = $uri;
+      }
+      // Public created files.
+      else {
+        $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
+        $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
+      }
+
+      // Clean up Windows paths.
+      $path = str_replace('\\', '/', $path);
+
+      // Generate a root-relative URL.
+      $uri = base_path() . '/' . $path;
     }
-    else {
-      $uri = FILE_URL_TEST_CDN_2 . '/' . $path;
+  }
+  // Test alteration of file URLs to use protocol-relative URLs.
+  elseif ($alter_mode == 'protocol-relative') {
+    // Only serve shipped files and public created files with protocol-relative
+    // URLs.
+    $scheme = file_uri_scheme($uri);
+    if (!$scheme || $scheme == 'public') {
+      // Shipped files.
+      if (!$scheme) {
+        $path = $uri;
+      }
+      // Public created files.
+      else {
+        $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
+        $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
+      }
+
+      // Clean up Windows paths.
+      $path = str_replace('\\', '/', $path);
+
+      // Generate a protocol-relative URL.
+      $uri = '/' . base_path() . '/' . $path;
     }
   }
 }
diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info
index 965c1eb8124229a4741598f7dc809ad839be9fbd..921282e867b38693a4f66a94c3ddaef933110a9a 100644
--- a/modules/simpletest/tests/filter_test.info
+++ b/modules/simpletest/tests/filter_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = filter_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index cf4765fdb980f4a4c424d21fd443621023f5273e..b413f19c943b435d740dff0d4d8b73426417eeb1 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: form.test,v 1.48 2010/04/11 19:00:27 dries Exp $
+// $Id: form.test,v 1.50 2010/04/28 16:11:22 dries Exp $
 
 /**
  * @file
@@ -209,6 +209,40 @@ class FormsTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Test form alter hooks.
+ */
+class FormAlterTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Form alter hooks',
+      'description' => 'Tests hook_form_alter() and hook_form_FORM_ID_alter().',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Tests execution order of hook_form_alter() and hook_form_FORM_ID_alter().
+   */
+  function testExecutionOrder() {
+    $this->drupalGet('form-test/alter');
+    // Ensure that the order is first by module, then for a given module, the
+    // id-specific one after the generic one.
+    $expected = array(
+      'block_form_form_test_alter_form_alter() executed.',
+      'form_test_form_alter() executed.',
+      'form_test_form_form_test_alter_form_alter() executed.',
+      'system_form_form_test_alter_form_alter() executed.',
+    );
+    $content = preg_replace('/\s+/', ' ', filter_xss($this->content, array()));
+    $this->assert(strpos($content, implode(' ', $expected)) !== FALSE, t('Form alter hooks executed in the expected order.'));
+  }
+}
+
 /**
  * Test form validation handlers.
  */
@@ -341,6 +375,20 @@ class FormsElementsLabelsTestCase extends DrupalWebTestCase {
 
     $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-no-show"]');
     $this->assertFalse(isset($elements[0]), t("No label tag when title set not to display."));
+
+    // Check #field_prefix and #field_suffix placement.
+    $elements = $this->xpath('//span[@class="field-prefix"]/following-sibling::div[@id="edit-form-radios-test"]');
+    $this->assertTrue(isset($elements[0]), t("Properly placed the #field_prefix element after the label and before the field."));
+
+    $elements = $this->xpath('//span[@class="field-suffix"]/preceding-sibling::div[@id="edit-form-radios-test"]');
+    $this->assertTrue(isset($elements[0]), t("Properly places the #field_suffix element immediately after the form field."));
+
+    // Check #prefix and #suffix placement.
+    $elements = $this->xpath('//div[@id="form-test-textfield-title-prefix"]/following-sibling::div[contains(@class, \'form-item-form-textfield-test-title\')]');
+    $this->assertTrue(isset($elements[0]), t("Properly places the #prefix element before the form item."));
+
+    $elements = $this->xpath('//div[@id="form-test-textfield-title-suffix"]/preceding-sibling::div[contains(@class, \'form-item-form-textfield-test-title\')]');
+    $this->assertTrue(isset($elements[0]), t("Properly places the #suffix element before the form item."));
   }
 }
 
diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info
index 3c81f8f8dde586f465d1a7c7e7ae44c8723d5d4a..4a88f76571baac645ddf9972c53d0033618a14a2 100644
--- a/modules/simpletest/tests/form_test.info
+++ b/modules/simpletest/tests/form_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = form_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module
index 9f8094c4aefb0c389920dbfeb3457637ec520579..354d436c03edd198a0c9658d21b4d1a4eaa4b926 100644
--- a/modules/simpletest/tests/form_test.module
+++ b/modules/simpletest/tests/form_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: form_test.module,v 1.37 2010/04/11 19:00:27 dries Exp $
+// $Id: form_test.module,v 1.39 2010/04/28 16:11:22 dries Exp $
 
 /**
  * @file
@@ -10,6 +10,13 @@
  * Implements hook_menu().
  */
 function form_test_menu() {
+  $items['form-test/alter'] = array(
+    'title' => 'Form altering test',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_alter_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['form-test/validate'] = array(
     'title' => 'Form validation handlers test',
     'page callback' => 'drupal_get_form',
@@ -141,6 +148,46 @@ function form_test_menu() {
   return $items;
 }
 
+/**
+ * Form builder for testing hook_form_alter() and hook_form_FORM_ID_alter().
+ */
+function form_test_alter_form($form, &$form_state) {
+  // Elements can be added as needed for future testing needs, but for now,
+  // we're only testing alter hooks that do not require any elements added by
+  // this function.
+  return $form;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() on behalf of block.module.
+ */
+function block_form_form_test_alter_form_alter(&$form, &$form_state) {
+  drupal_set_message('block_form_form_test_alter_form_alter() executed.');
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function form_test_form_alter(&$form, &$form_state, $form_id) {
+  if ($form_id == 'form_test_alter_form') {
+    drupal_set_message('form_test_form_alter() executed.');
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function form_test_form_form_test_alter_form_alter(&$form, &$form_state) {
+  drupal_set_message('form_test_form_form_test_alter_form_alter() executed.');
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() on behalf of system.module.
+ */
+function system_form_form_test_alter_form_alter(&$form, &$form_state) {
+  drupal_set_message('system_form_form_test_alter_form_alter() executed.');
+}
+
 /**
  * Form builder for testing drupal_validate_form().
  *
@@ -529,6 +576,9 @@ function form_label_test_form() {
       'second-radio' => t('Second radio'),
       'third-radio' => t('Third radio'),
     ),
+    // Test #field_prefix and #field_suffix placement.
+    '#field_prefix' => '<span id="form-test-radios-field-prefix">' . t('Radios #field_prefix element') . '</span>',
+    '#field_suffix' => '<span id="form-test-radios-field-suffix">' . t('Radios #field_suffix element') . '</span>',
   );
   $form['form_checkbox_test'] = array(
     '#type' => 'checkbox',
@@ -550,6 +600,9 @@ function form_label_test_form() {
     '#type' => 'textfield',
     '#title' => t('Textfield test for title only'),
     // Not required.
+    // Test #prefix and #suffix placement.
+    '#prefix' => '<div id="form-test-textfield-title-prefix">' . t('Textfield #prefix element') . '</div>',
+    '#suffix' => '<div id="form-test-textfield-title-suffix">' . t('Textfield #suffix element') . '</div>',
   );
   $form['form_textfield_test_title_after'] = array(
     '#type' => 'textfield',
diff --git a/modules/simpletest/tests/graph.test b/modules/simpletest/tests/graph.test
index ce92ca98536cbc1d86363071f5ca83130f276cd9..1751fe2ca554ad74d5b88d434047c6519c326b3b 100644
--- a/modules/simpletest/tests/graph.test
+++ b/modules/simpletest/tests/graph.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: graph.test,v 1.6 2009/07/13 21:51:41 webchick Exp $
+// $Id: graph.test,v 1.7 2010/05/18 18:11:13 dries Exp $
 
 /**
  * @file
@@ -23,7 +23,7 @@ class GraphUnitTest extends DrupalUnitTestCase {
    */
   function testDepthFirstSearch() {
     // Provoke the inclusion of graph.inc.
-    require_once 'includes/graph.inc';
+    require_once DRUPAL_ROOT . '/includes/graph.inc';
 
     // The sample graph used is:
     // 1 --> 2 --> 3     5 ---> 6
diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info
index 99aeaff517b2ae0ac5e7456ce623084c6946e769..4fe62cb55839cec4a31b59167f32714eec3de4dc 100644
--- a/modules/simpletest/tests/image_test.info
+++ b/modules/simpletest/tests/image_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = image_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info
index 9a39315f8a4a4ef7e69a79d4e35ea41f3277f01f..967193987d17ebe3e56b524969b94f2ee5a308ae 100644
--- a/modules/simpletest/tests/menu_test.info
+++ b/modules/simpletest/tests/menu_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = menu_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info
index 482d10f071193009986e44ffff1c1ca1b8fe876d..1572971fc66f8f627671eb6b9864339754178ee4 100644
--- a/modules/simpletest/tests/module_test.info
+++ b/modules/simpletest/tests/module_test.info
@@ -8,8 +8,8 @@ files[] = module_test.module
 files[] = module_test.file.inc
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/registry.test b/modules/simpletest/tests/registry.test
index f77db6d3d6e36106c51f1ab190e73c024d5fd22a..e822768972916a80ffe9c63a55d772626249fc8c 100644
--- a/modules/simpletest/tests/registry.test
+++ b/modules/simpletest/tests/registry.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: registry.test,v 1.16 2009/08/24 00:14:21 webchick Exp $
+// $Id: registry.test,v 1.17 2010/05/01 08:12:23 dries Exp $
 
 class RegistryParseFileTestCase extends DrupalWebTestCase {
   public static function getInfo() {
@@ -11,9 +11,10 @@ class RegistryParseFileTestCase extends DrupalWebTestCase {
   }
 
   function setUp() {
-    $this->fileName = 'registry_test_' . md5(rand());
-    $this->className = 'registry_test_class' . md5(rand());
-    $this->interfaceName = 'registry_test_interface' . md5(rand());
+    $chrs = hash('sha256', microtime() . mt_rand());
+    $this->fileName = 'registry_test_' . substr($chrs, 0, 16);
+    $this->className = 'registry_test_class' . substr($chrs, 16, 16);
+    $this->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
     parent::setUp();
   }
 
@@ -61,18 +62,19 @@ class RegistryParseFilesTestCase extends DrupalWebTestCase {
     // Create files with some php to parse - one 'new', one 'existing' so
     // we test all the important code paths in _registry_parse_files.
     foreach ($this->fileTypes as $fileType) {
+      $chrs = hash('sha256', microtime() . mt_rand());
       $this->$fileType = new stdClass();
-      $this->$fileType->fileName = file_directory_path() . '/registry_test_' . md5(rand());
-      $this->$fileType->className = 'registry_test_class' . md5(rand());
-      $this->$fileType->interfaceName = 'registry_test_interface' . md5(rand());
+      $this->$fileType->fileName = file_directory_path() . '/registry_test_' . substr($chrs, 0, 16);
+      $this->$fileType->className = 'registry_test_class' . substr($chrs, 16, 16);
+      $this->$fileType->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
       $this->$fileType->contents = $this->getFileContents($fileType);
       file_save_data($this->$fileType->contents, $this->$fileType->fileName);
 
       if ($fileType == 'existing_changed') {
         db_insert('registry_file')
           ->fields(array(
-            'filectime' => rand(1, 1000000),
-            'filemtime' => rand(1, 1000000),
+            'filectime' => mt_rand(1, 1000000),
+            'filemtime' => mt_rand(1, 1000000),
             'filename' => $this->$fileType->fileName,
           ))
           ->execute();
@@ -81,7 +83,7 @@ class RegistryParseFilesTestCase extends DrupalWebTestCase {
         foreach (array('class', 'interface') as $type) {
           db_insert('registry')
             ->fields(array(
-              'name' => $type . md5(rand()),
+              'name' => $type . hash('sha256', microtime() . mt_rand()),
               'type' => $type,
               'filename' => $this->$fileType->fileName,
             ))
@@ -117,8 +119,8 @@ class RegistryParseFilesTestCase extends DrupalWebTestCase {
     foreach ($this->fileTypes as $fileType) {
       $files[$this->$fileType->fileName] = array('module' => '', 'weight' => 0);
       if ($fileType == 'existing_changed') {
-        $files[$this->$fileType->fileName]['filectime'] = rand(1, 1000000);
-        $files[$this->$fileType->fileName]['filemtime'] = rand(1, 1000000);
+        $files[$this->$fileType->fileName]['filectime'] = mt_rand(1, 1000000);
+        $files[$this->$fileType->fileName]['filemtime'] = mt_rand(1, 1000000);
       }
     }
     return $files;
diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test
index 74ffab94467e5c598c1760de74731f2d3107af00..b1aa396fb90d02c40a65381ce8b96d81c7168a75 100644
--- a/modules/simpletest/tests/session.test
+++ b/modules/simpletest/tests/session.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: session.test,v 1.27 2010/02/17 08:56:48 dries Exp $
+// $Id: session.test,v 1.28 2010/05/12 08:26:15 dries Exp $
 
 /**
  * @file
@@ -140,7 +140,7 @@ class SessionTestCase extends DrupalWebTestCase {
     $this->assertSessionEmpty(TRUE);
 
     // The same behavior is expected when caching is enabled.
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
     $this->drupalGet('');
     $this->assertSessionCookie(FALSE);
     $this->assertSessionEmpty(TRUE);
diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info
index d095ad61670e0687a7553d636f6e98137893a5b4..5ddbc7597c03e88cd8febfb33043bad534129790 100644
--- a/modules/simpletest/tests/session_test.info
+++ b/modules/simpletest/tests/session_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = session_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info
index abbb29d6b31f2b1e1ab65bf21c062150fe648aa1..0fa2904365bf98d7ec1d9d1e6345c57502d66ee1 100644
--- a/modules/simpletest/tests/system_dependencies_test.info
+++ b/modules/simpletest/tests/system_dependencies_test.info
@@ -8,8 +8,8 @@ files[] = system_dependencies_test.module
 hidden = TRUE
 dependencies[] = _missing_dependency
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/system_test.info b/modules/simpletest/tests/system_test.info
index a48c86a3278ca52365aae66442bffff55abac451..32f3e6ae26ad695a3b4960fad38edf811e24d475 100644
--- a/modules/simpletest/tests/system_test.info
+++ b/modules/simpletest/tests/system_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = system_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/system_test.module b/modules/simpletest/tests/system_test.module
index df17b73dcdd0eb6cc8ff513b8add199fc7401cc4..613b57a5438de52dc385c57ae303a31e711f5f8f 100644
--- a/modules/simpletest/tests/system_test.module
+++ b/modules/simpletest/tests/system_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: system_test.module,v 1.25 2010/02/17 22:44:52 webchick Exp $
+// $Id: system_test.module,v 1.28 2010/05/20 08:51:24 dries Exp $
 
 /**
  * Implements hook_menu().
@@ -43,13 +43,6 @@ function system_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
-  $items['system-test/destination'] = array(
-    'title' => 'Redirect',
-    'page callback' => 'system_test_destination',
-    'page arguments' => array(2),
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
 
   $items['system-test/variable-get'] = array(
     'title' => 'Variable Get',
@@ -115,9 +108,10 @@ function system_test_basic_auth_page() {
 }
 
 function system_test_redirect($code) {
-  $code = (int)$code;
+  $code = (int) $code;
   if ($code != 200) {
-    header("Location: " . url('system-test/redirect/200', array('absolute' => TRUE)), TRUE, $code);
+    // Header names are case-insensitive.
+    header("locaTION: " . url('system-test/redirect/200', array('absolute' => TRUE)), TRUE, $code);
     exit;
   }
   return '';
@@ -143,11 +137,6 @@ function system_test_redirect_invalid_scheme() {
   exit;
 }
 
-function system_test_destination() {
-  $destination = drupal_get_destination();
-  return 'The destination: ' . $destination['destination'];
-}
-
 /**
  * Implements hook_modules_installed().
  */
diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info
index 4a252be84965314f70ba21956b594066b6a123ad..2ecdb6b806dc8d0ac5bc0e1f512b6e3bc5a0fee4 100644
--- a/modules/simpletest/tests/taxonomy_test.info
+++ b/modules/simpletest/tests/taxonomy_test.info
@@ -8,8 +8,8 @@ files[] = taxonomy_test.module
 hidden = TRUE
 dependencies[] = taxonomy
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index f69c2af419443c3c9cbe4521c13449fb0da044db..2d27c260b93fb410febd16bb7d1b339a58d1ea09 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.test,v 1.15 2010/04/22 22:33:29 dries Exp $
+// $Id: theme.test,v 1.16 2010/04/29 05:22:06 webchick Exp $
 
 /**
  * @file
@@ -44,7 +44,7 @@ class ThemeUnitTest extends DrupalWebTestCase {
     $suggestions = theme_get_suggestions($args, 'page');
     $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), t('Removed invalid \\0 from suggestions'));
   }
-  
+
   /**
   * Preprocess functions for the base hook should run even for suggestion implementations.
   */
@@ -155,3 +155,30 @@ class ThemeItemListUnitTest extends DrupalWebTestCase {
     $this->assertIdentical($expected, $output, 'Nested list is rendered correctly.');
   }
 }
+
+/**
+ * Functional test for initialization of the theme system in hook_init().
+ */
+class ThemeHookInitUnitTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Theme initialization in hook_init()',
+      'description' => 'Tests that the theme system can be correctly initialized in hook_init().',
+      'group' => 'Theme',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('theme_test');
+    variable_set('theme_default', 'garland');
+  }
+
+  /**
+   * Test that the theme system can generate output when called by hook_init().
+   */
+  function testThemeInitializationHookInit() {
+    $this->drupalGet('theme-test/hook-init');
+    $this->assertRaw('Themed output generated in hook_init()', t('Themed output generated in hook_init() correctly appears on the page.'));
+    $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page when the theme system is initialized in hook_init()."));
+  }
+}
diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info
index b08461b67e9e079a3b3f9fb0072c1b6e28e764c4..da7a96bcacb8786d8f3edffbb275684697215551 100644
--- a/modules/simpletest/tests/theme_test.info
+++ b/modules/simpletest/tests/theme_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = theme_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module
index 6265cbbd4d66c2182f9c981062dd5f51dcd818a3..6815a1cfd696ae06b7d8796c22d751cd755b2bac 100644
--- a/modules/simpletest/tests/theme_test.module
+++ b/modules/simpletest/tests/theme_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme_test.module,v 1.1 2010/03/21 04:05:24 webchick Exp $
+// $Id: theme_test.module,v 1.2 2010/04/29 05:22:06 webchick Exp $
 
 /**
  * Implements hook_menu().
@@ -12,10 +12,36 @@ function theme_test_menu() {
     'theme callback' => '_theme_custom_theme',
     'type' => MENU_CALLBACK,
   );
-
+  $items['theme-test/hook-init'] = array(
+    'page callback' => 'theme_test_hook_init_page_callback',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
+/**
+ * Implements hook_init().
+ */
+function theme_test_init() {
+  // First, force the theme registry to be rebuilt on this page request. This
+  // allows us to test a full initialization of the theme system in the code
+  // below.
+  drupal_theme_rebuild();
+  // Next, initialize the theme system by storing themed text in a global
+  // variable. We will use this later in theme_test_hook_init_page_callback()
+  // to test that even when the theme system is initialized this early, it is
+  // still capable of returning output and theming the page as a whole.
+  $GLOBALS['theme_test_output'] = theme('more_link', array('url' => url('user'), 'title' => 'Themed output generated in hook_init()'));
+}
+
+/**
+ * Menu callback for testing themed output generated in hook_init().
+ */
+function theme_test_hook_init_page_callback() {
+  return $GLOBALS['theme_test_output'];
+}
+
 /**
  * Custom theme callback.
  */
diff --git a/modules/simpletest/tests/update.test b/modules/simpletest/tests/update.test
index ea86bdf1f215e549a2c1b5e92f0848fbe87805b5..944dba7f6c2b9244fae2866a5e58ff5a3de703e7 100644
--- a/modules/simpletest/tests/update.test
+++ b/modules/simpletest/tests/update.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.test,v 1.1 2010/02/03 18:16:23 webchick Exp $
+// $Id: update.test,v 1.2 2010/04/28 05:28:22 webchick Exp $
 
 /**
  * @file
@@ -86,3 +86,31 @@ class UpdateDependencyMissingTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests for the invocation of hook_update_dependencies().
+ */
+class UpdateDependencyHookInvocationTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Update dependency hook invocation',
+      'description' => 'Test that the hook invocation for determining update dependencies works correctly.',
+      'group' => 'Update API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('update_test_1', 'update_test_2');
+    require_once DRUPAL_ROOT . '/includes/update.inc';
+  }
+
+  /**
+   * Test the structure of the array returned by hook_update_dependencies().
+   */
+  function testHookUpdateDependencies() {
+    $update_dependencies = update_retrieve_dependencies();
+    $this->assertTrue($update_dependencies['system'][7000]['update_test_1'] == 7000, t('An update function that has a dependency on two separate modules has the first dependency recorded correctly.'));
+    $this->assertTrue($update_dependencies['system'][7000]['update_test_2'] == 7001, t('An update function that has a dependency on two separate modules has the second dependency recorded correctly.'));
+    $this->assertTrue($update_dependencies['system'][7001]['update_test_1'] == 7002, t('An update function that depends on more than one update from the same module only has the dependency on the higher-numbered update function recorded.'));
+  }
+}
+
diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info
index 3a8d9c3254c3be83d194bfcb16e078bbd6a63637..696344a913d8359c471948a0b242cb98d34ef1a9 100644
--- a/modules/simpletest/tests/update_test_1.info
+++ b/modules/simpletest/tests/update_test_1.info
@@ -8,8 +8,8 @@ files[] = update_test_1.module
 files[] = update_test_1.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/update_test_1.install b/modules/simpletest/tests/update_test_1.install
index 3bb71bde7c01b0880c0da6da02be324117bd63d3..814a74a8d2a39988c356be766ec08e343bda5da9 100644
--- a/modules/simpletest/tests/update_test_1.install
+++ b/modules/simpletest/tests/update_test_1.install
@@ -1,11 +1,40 @@
 <?php
-// $Id: update_test_1.install,v 1.1 2010/02/03 18:16:23 webchick Exp $
+// $Id: update_test_1.install,v 1.2 2010/04/28 05:28:22 webchick Exp $
 
 /**
  * @file
  * Install, update and uninstall functions for the update_test_1 module.
  */
 
+/**
+ * Implements hook_update_dependencies().
+ *
+ * @see update_test_2_update_dependencies()
+ */
+function update_test_1_update_dependencies() {
+  // These dependencies are used in combination with those declared in
+  // update_test_2_update_dependencies() for the sole purpose of testing that
+  // the results of hook_update_dependencies() are collected correctly and have
+  // the correct array structure. Therefore, we use updates from System module
+  // (which have already run), so that they will not get in the way of other
+  // tests.
+  $dependencies['system'][7000] = array(
+    // Compare to update_test_2_update_dependencies(), where the same System
+    // module update function is forced to depend on an update function from a
+    // different module. This allows us to test that both dependencies are
+    // correctly recorded.
+    'update_test_1' => 7000,
+  );
+  $dependencies['system'][7001] = array(
+    // Compare to update_test_2_update_dependencies(), where the same System
+    // module update function is forced to depend on a different update
+    // function within the same module. This allows us to test that only the
+    // dependency on the higher-numbered update function is recorded.
+    'update_test_1' => 7002,
+  );
+  return $dependencies;
+}
+
 /**
  * Dummy update_test_1 update 7000.
  */
diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info
index c1c6c4d4c4c6a7db70e91f4d351871cbfb51061a..6cd8bc12f040b740df966afcfd86a974fddc365d 100644
--- a/modules/simpletest/tests/update_test_2.info
+++ b/modules/simpletest/tests/update_test_2.info
@@ -8,8 +8,8 @@ files[] = update_test_2.module
 files[] = update_test_2.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/update_test_2.install b/modules/simpletest/tests/update_test_2.install
index 585c1d6d009f3668ed62b5134bcf03c41825a64b..6e094ac48d3ec9ee17891829548aebe3d821bc49 100644
--- a/modules/simpletest/tests/update_test_2.install
+++ b/modules/simpletest/tests/update_test_2.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: update_test_2.install,v 1.1 2010/02/03 18:16:23 webchick Exp $
+// $Id: update_test_2.install,v 1.2 2010/04/28 05:28:22 webchick Exp $
 
 /**
  * @file
@@ -8,11 +8,30 @@
 
 /**
  * Implements hook_update_dependencies().
+ *
+ * @see update_test_1_update_dependencies()
+ * @see update_test_3_update_dependencies()
  */
 function update_test_2_update_dependencies() {
+  // Combined with update_test_3_update_dependencies(), we are declaring here
+  // that these two modules run updates in the following order:
+  // 1. update_test_2_update_7000()
+  // 2. update_test_3_update_7000()
+  // 3. update_test_2_update_7001()
+  // 4. update_test_2_update_7002()
   $dependencies['update_test_2'][7001] = array(
     'update_test_3' => 7000,
   );
+
+  // These are coordinated with the corresponding dependencies declared in
+  // update_test_1_update_dependencies().
+  $dependencies['system'][7000] = array(
+    'update_test_2' => 7001,
+  );
+  $dependencies['system'][7001] = array(
+    'update_test_1' => 7001,
+  );
+
   return $dependencies;
 }
 
diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info
index a95f31dad36a7c16d5530fe5126947c7ad996184..d10794a64cf605e98679ae4cf95d02309dbdb12b 100644
--- a/modules/simpletest/tests/update_test_3.info
+++ b/modules/simpletest/tests/update_test_3.info
@@ -8,8 +8,8 @@ files[] = update_test_3.module
 files[] = update_test_3.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/update_test_3.install b/modules/simpletest/tests/update_test_3.install
index 3030296fa8fad7750dec563130d642b2feafc79d..4a86e79b3e2170491453757f5c309cfb0acac2b0 100644
--- a/modules/simpletest/tests/update_test_3.install
+++ b/modules/simpletest/tests/update_test_3.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: update_test_3.install,v 1.1 2010/02/03 18:16:23 webchick Exp $
+// $Id: update_test_3.install,v 1.2 2010/04/28 05:28:22 webchick Exp $
 
 /**
  * @file
@@ -8,6 +8,8 @@
 
 /**
  * Implements hook_update_dependencies().
+ *
+ * @see update_test_2_update_dependencies()
  */
 function update_test_3_update_dependencies() {
   $dependencies['update_test_3'][7000] = array(
diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info
index f24af5268a4c76d8a39e925186c9da8449145bf7..a171d908bed6e956611159e3856814da6ffb3c55 100644
--- a/modules/simpletest/tests/url_alter_test.info
+++ b/modules/simpletest/tests/url_alter_test.info
@@ -8,8 +8,8 @@ files[] = url_alter_test.module
 files[] = url_alter_test.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/simpletest/tests/xmlrpc.test b/modules/simpletest/tests/xmlrpc.test
index 42288250ce8e793a5eba42bb68893581f6757af4..7625a8ffcc0fed9b0361958facffd32feaa8392d 100644
--- a/modules/simpletest/tests/xmlrpc.test
+++ b/modules/simpletest/tests/xmlrpc.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: xmlrpc.test,v 1.16 2010/03/31 15:56:53 dries Exp $
+// $Id: xmlrpc.test,v 1.17 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * Perform basic XML-RPC tests that do not require addition callbacks.
@@ -155,7 +155,7 @@ class XMLRPCValidator1IncTestCase extends DrupalWebTestCase {
     for ($y = 2000; $y < 2002; $y++) {
       for ($m = 3; $m < 5; $m++) {
         for ($d = 1; $d < 6; $d++) {
-          $ys = (string)$y;
+          $ys = (string) $y;
           $ms = sprintf('%02d', $m);
           $ds = sprintf('%02d', $d);
           $struct_7[$ys][$ms][$ds]['moe']   = mt_rand(-100, 100);
diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info
index 4537cb49369b1644b3e3a0845bc1925e4581c1cd..244b58f6fbf03dbdb9fdd1e162a1728639070501 100644
--- a/modules/simpletest/tests/xmlrpc_test.info
+++ b/modules/simpletest/tests/xmlrpc_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = xmlrpc_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info
index 8329f376c37b55fcbd2b80eb7ff37ec216b8760b..5922dd3796c081aa8414b65903861fba5a0324d2 100644
--- a/modules/statistics/statistics.info
+++ b/modules/statistics/statistics.info
@@ -12,8 +12,8 @@ files[] = statistics.test
 files[] = statistics.tokens.inc
 configure = admin/config/system/statistics
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/statistics/statistics.install b/modules/statistics/statistics.install
index 1c18ef467f154dcbcf2cb4c5cc0f9a440e153f9b..02765039d79c15a5106c643144ae87c1be0f0197 100644
--- a/modules/statistics/statistics.install
+++ b/modules/statistics/statistics.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.install,v 1.25 2009/12/04 16:49:47 dries Exp $
+// $Id: statistics.install,v 1.26 2010/04/28 05:29:55 webchick Exp $
 
 /**
  * @file
@@ -133,24 +133,6 @@ function statistics_schema() {
   return $schema;
 }
 
-/**
- * @defgroup updates-6.x-extra Extra statistics updates for 6.x
- * @{
- */
-
-/**
- * Allow longer referrers.
- */
-function statistics_update_6000() {
-  db_change_field('accesslog', 'url', 'url', array('type' => 'text', 'not null' => FALSE));
-}
-
-/**
- * @} End of "defgroup updates-6.x-extra"
- * The next series of updates should start at 7000.
- */
-
-
 /**
  * @defgroup updates-6.x-to-7.x statistics updates from 6.x to 7.x
  * @{
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index 16b14fdd4e0a95f73a410a918a89746812ea5f71..08d8612cd3da9b3f673d905f363c34938f01c0e1 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.module,v 1.333 2010/03/30 07:17:19 webchick Exp $
+// $Id: statistics.module,v 1.335 2010/05/18 18:26:30 dries Exp $
 
 /**
  * @file
@@ -51,7 +51,12 @@ function statistics_help($path, $arg) {
 function statistics_exit() {
   global $user;
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+  // When serving cached pages with the 'page_cache_without_database'
+  // configuration, system variables need to be loaded. This is a major
+  // performance decrease for non-database page caches, but with Statistics
+  // module, it is likely to also have 'statistics_enable_access_log' enabled,
+  // in which case we need to bootstrap to the session phase anyway.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
 
   if (variable_get('statistics_count_content_views', 0)) {
     // We are counting content views.
@@ -70,6 +75,7 @@ function statistics_exit() {
     }
   }
   if (variable_get('statistics_enable_access_log', 0)) {
+    drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
     // Log this page access.
     db_insert('accesslog')
       ->fields(array(
@@ -304,12 +310,14 @@ function statistics_get($nid) {
  * Implements hook_block_info().
  */
 function statistics_block_info() {
+  $blocks = array();
+
   if (variable_get('statistics_count_content_views', 0)) {
     $blocks['popular']['info'] = t('Popular content');
     // Too dynamic to cache.
     $blocks['popular']['cache'] = DRUPAL_NO_CACHE;
-    return $blocks;
   }
+  return $blocks;
 }
 
 /**
diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test
index 1b25a33ac68e1921bf3fedb6b9d017b556314d2a..e35c6ada1923569eb3ba0ed7cc7d29a9329d46bd 100644
--- a/modules/statistics/statistics.test
+++ b/modules/statistics/statistics.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.test,v 1.17 2010/04/20 09:48:06 webchick Exp $
+// $Id: statistics.test,v 1.18 2010/05/18 18:26:30 dries Exp $
 
 /**
  * Sets up a base class for the Statistics module.
@@ -33,6 +33,69 @@ class StatisticsTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests that logging via statistics_exit() works for cached and uncached pages.
+ *
+ * Subclass DrupalWebTestCase rather than StatisticsTestCase, because we want
+ * to test requests from an anonymous user.
+ */
+class StatisticsLoggingTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Statistics logging tests',
+      'description' => 'Tests request logging for cached and uncached pages.',
+      'group' => 'Statistics'
+    );
+  }
+
+  function setUp() {
+    parent::setUp('statistics');
+
+    // Ensure we have a node page to access.
+    $this->node = $this->drupalCreateNode();
+
+    // Enable page caching.
+    variable_set('cache', TRUE);
+
+    // Enable access logging.
+    variable_set('statistics_enable_access_log', 1);
+    variable_set('statistics_count_content_views', 1);
+
+    // Clear the logs.
+    db_truncate('accesslog');
+    db_truncate('node_counter');
+  }
+
+  /**
+   * Verifies request logging for cached and uncached pages.
+   */
+  function testLogging() {
+    $path = 'node/' . $this->node->nid;
+    $expected = array(
+      'title' => $this->node->title,
+      'path' => $path,
+    );
+
+    // Verify logging of an uncached page.
+    $this->drupalGet($path);
+    $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Testing an uncached page.'));
+    $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
+    $this->assertTrue(is_array($log) && count($log) == 1, t('Page request was logged.'));
+    $this->assertEqual(array_intersect_key($log[0], $expected), $expected);
+    $node_counter = statistics_get($this->node->nid);
+    $this->assertIdentical($node_counter['totalcount'], '1');
+
+    // Verify logging of a cached page.
+    $this->drupalGet($path);
+    $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Testing a cached page.'));
+    $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
+    $this->assertTrue(is_array($log) && count($log) == 2, t('Page request was logged.'));
+    $this->assertEqual(array_intersect_key($log[1], $expected), $expected);
+    $node_counter = statistics_get($this->node->nid);
+    $this->assertIdentical($node_counter['totalcount'], '2');
+  }
+}
+
 /**
  * Tests that report pages render properly, and that access logging works.
  */
diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info
index f5891b8f764582610d44f8f229f8b5004a824443..40efff403736e09b2db1992e10d6d60273d2b178 100644
--- a/modules/syslog/syslog.info
+++ b/modules/syslog/syslog.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = syslog.module
 files[] = syslog.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/system/admin-rtl.css b/modules/system/admin-rtl.css
index e5a8801b6a39416e1d50ebbb63f750ce694e8443..cbf6195c8b7f291e1ce89338bbe969a0a03a4d9e 100644
--- a/modules/system/admin-rtl.css
+++ b/modules/system/admin-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: admin-rtl.css,v 1.6 2009/08/03 03:04:33 webchick Exp $ */
+/* $Id: admin-rtl.css,v 1.7 2010/04/28 20:08:39 dries Exp $ */
 
 div.admin-panel .body {
   padding: 0 8px 2px 4px;
@@ -23,7 +23,8 @@ div.admin .expert-link {
   padding-left: 4px;
 }
 
-table.system-status-report th, table.system-status-report tr.merge-up td {
+table.system-status-report th,
+table.system-status-report tr.merge-up td {
   padding-right: 30px;
 }
 
@@ -38,7 +39,8 @@ table.screenshot {
 .date-container {
   clear: right;
 }
-.date-container .select-container, .date-container .custom-container {
+.date-container .select-container,
+.date-container .custom-container {
   float: right;
 }
 .date-container .custom-container {
diff --git a/modules/system/admin.css b/modules/system/admin.css
index e4f6847cc0cdb4fb56124cb9183944324437024b..54df5af5ee07172c6dccbb03f336a02d2466258e 100644
--- a/modules/system/admin.css
+++ b/modules/system/admin.css
@@ -1,4 +1,4 @@
-/* $Id: admin.css,v 1.21 2009/08/03 03:04:33 webchick Exp $ */
+/* $Id: admin.css,v 1.22 2010/04/28 20:08:39 dries Exp $ */
 
 /*
 ** Formatting for administration page
@@ -47,7 +47,8 @@ table.package .description {
 table.package .version {
   direction: ltr;
 }
-div.admin-requirements, div.admin-required {
+div.admin-requirements,
+div.admin-required {
   font-size: 0.9em;
   color: #444;
 }
@@ -67,7 +68,8 @@ span.admin-missing {
 table.system-status-report th {
   border-bottom: 1px solid #ccc;
 }
-table.system-status-report th, table.system-status-report tr.merge-up td {
+table.system-status-report th,
+table.system-status-report tr.merge-up td {
   padding-left: 30px; /* LTR */
 }
 table.system-status-report th {
@@ -125,7 +127,8 @@ table.screenshot {
 .date-container .form-item {
   margin-top: 0;
 }
-.date-container .select-container, .date-container .custom-container {
+.date-container .select-container,
+.date-container .custom-container {
   float: left; /* LTR */
 }
 .date-container .custom-container {
diff --git a/modules/system/system-behavior-rtl.css b/modules/system/system-behavior-rtl.css
index ee9cb9d3954a5f5605cbf9040aae4e2cb2208773..06c03fb1e6d3c39ff4f10d65ef815f41af7dcbea 100644
--- a/modules/system/system-behavior-rtl.css
+++ b/modules/system/system-behavior-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: system-behavior-rtl.css,v 1.2 2010/03/03 19:46:26 dries Exp $ */
+/* $Id: system-behavior-rtl.css,v 1.3 2010/04/28 20:08:39 dries Exp $ */
 
 /**
  * Autocomplete
@@ -71,14 +71,16 @@ div.indentation {
   padding: 0.42em 0.6em 0.42em 0;
   float: right;
 }
-div.tree-child, div.tree-child-last {
+div.tree-child,
+div.tree-child-last {
   background-position: -65px center;
 }
 
 /**
  * Multiselect form
  */
-dl.multiselect dt, dl.multiselect dd {
+dl.multiselect dt,
+dl.multiselect dd {
   float: right;
   margin: 0 0 0 1em;
 }
diff --git a/modules/system/system-behavior.css b/modules/system/system-behavior.css
index 66e71a89baebb934e76ab327ec5ffedc876196dd..14ed433f0ede0339b2d74a2cb0d7b1daca90b2e2 100644
--- a/modules/system/system-behavior.css
+++ b/modules/system/system-behavior.css
@@ -1,4 +1,4 @@
-/* $Id: system-behavior.css,v 1.8 2010/04/11 18:45:47 dries Exp $ */
+/* $Id: system-behavior.css,v 1.9 2010/04/28 20:08:39 dries Exp $ */
 
 /**
  * Autocomplete
@@ -176,12 +176,15 @@ tr .ajax-progress .throbber {
 /**
  * Multiselect form
  */
-dl.multiselect dd, dl.multiselect dd .form-item, dl.multiselect dd select {
+dl.multiselect dd,
+dl.multiselect dd .form-item,
+dl.multiselect dd select {
   font-family: inherit;
   font-size: inherit;
   width: 14em;
 }
-dl.multiselect dt, dl.multiselect dd {
+dl.multiselect dt,
+dl.multiselect dd {
   float: left; /* LTR */
   line-height: 1.75em;
   padding: 0;
@@ -217,7 +220,8 @@ dl.multiselect .form-item {
   width: 0%;
   background-color: #47C965;
 }
-input.password-confirm, input.password-field {
+input.password-confirm,
+input.password-field {
   width: 16em;
   margin-bottom: 0.4em;
 }
diff --git a/modules/system/system-menus-rtl.css b/modules/system/system-menus-rtl.css
index 36dedabec160fb00d5cbe3da17582fccf48cb3f4..f1449afc382e62970bf91abe6488cade63df2949 100644
--- a/modules/system/system-menus-rtl.css
+++ b/modules/system/system-menus-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: system-menus-rtl.css,v 1.2 2010/03/07 08:13:43 webchick Exp $ */
+/* $Id: system-menus-rtl.css,v 1.3 2010/04/28 20:08:39 dries Exp $ */
 
 ul.menu {
   text-align:right;
@@ -9,6 +9,8 @@ ul.menu li {
 ul li.collapsed {
   list-style-image: url(../../misc/menu-collapsed-rtl.png);
 }
-li.expanded, li.collapsed, li.leaf {
+li.expanded,
+li.collapsed,
+li.leaf {
   padding: 0.2em 0 0 0.5em;
 }
diff --git a/modules/system/system-menus.css b/modules/system/system-menus.css
index 87abccf59ce36acae98eaf8a850c4070f06ad2c7..dd7a243df6872b129ba7aa82bc3625d72c1d57c7 100644
--- a/modules/system/system-menus.css
+++ b/modules/system/system-menus.css
@@ -1,4 +1,4 @@
-/* $Id: system-menus.css,v 1.2 2010/03/07 08:13:43 webchick Exp $ */
+/* $Id: system-menus.css,v 1.4 2010/05/18 11:56:59 dries Exp $ */
 
 ul.menu {
   list-style: none;
@@ -10,7 +10,7 @@ ul.menu li {
 }
 ul li.expanded {
   list-style-type: circle;
-  list-style-image: url(../../misc/menu-expanded.png); 
+  list-style-image: url(../../misc/menu-expanded.png);
 }
 ul li.collapsed {
   list-style-type: disc;
@@ -20,7 +20,9 @@ ul li.leaf {
   list-style-type: square;
   list-style-image: url(../../misc/menu-leaf.png);
 }
-li.expanded, li.collapsed, li.leaf {
+li.expanded,
+li.collapsed,
+li.leaf {
   padding: 0.2em 0.5em 0 0; /* LTR */
   margin: 0;
 }
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index cf6fd312dfb8ae8da5a7c3d3fc252a5cda80978a..263b0630156a68c7a29ee069788cb106d49f2398 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.admin.inc,v 1.270 2010/04/24 14:49:14 dries Exp $
+// $Id: system.admin.inc,v 1.284 2010/05/21 11:37:55 dries Exp $
 
 /**
  * @file
@@ -10,11 +10,12 @@
  * Menu callback; Provide the administration overview page.
  */
 function system_main_admin_page($arg = NULL) {
-  // If we received an argument, they probably meant some other page.
-  // Let's 404 them since the menu system cannot be told we do not
-  // accept arguments.
+  // Only continue if provided arguments are expected. This function serves
+  // as the callback for the top-level admin/ page, so any unexpected arguments
+  // are likely the result of someone typing in the URL of an administrative
+  // page that doesn't actually exist; for example, admin/some/random/page.
   if (isset($arg) && substr($arg, 0, 3) != 'by-') {
-    return drupal_not_found();
+    return MENU_NOT_FOUND;
   }
 
   // Check for status report errors.
@@ -96,12 +97,15 @@ function system_admin_config_page() {
       }
       $block = $item;
       $block['content'] = '';
-      $block['show'] = TRUE;
       if ($item['block_callback'] && function_exists($item['block_callback'])) {
         $function = $item['block_callback'];
         $block['content'] .= $function();
       }
       $block['content'] .= theme('admin_block_content', array('content' => system_admin_menu_block($item)));
+      if (!empty($block['content'])) {
+        $block['show'] = TRUE;
+      }
+
       // Prepare for sorting as in function _menu_tree_check_access().
       // The weight is offset so it is always positive, with a uniform 5-digits.
       $blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block;
@@ -141,8 +145,12 @@ function system_admin_menu_block_page() {
  * Menu callback; prints a listing of admin tasks for each installed module.
  */
 function system_admin_by_module() {
-
   $module_info = system_get_info('module');
+  foreach ($module_info as $module => $info) {
+    $module_info[$module] = new StdClass();
+    $module_info[$module]->info = $info;
+  }
+  uasort($module_info, 'system_sort_modules_by_info_name');
   $menu_items = array();
   $help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
 
@@ -164,7 +172,7 @@ function system_admin_by_module() {
       // Sort.
       ksort($admin_tasks);
 
-      $menu_items[$info['name']] = array($info['description'], $admin_tasks);
+      $menu_items[$info->info['name']] = array($info->info['description'], $admin_tasks);
     }
   }
   return theme('system_admin_by_module', array('menu_items' => $menu_items));
@@ -187,35 +195,21 @@ function system_settings_overview() {
   return $output;
 }
 
-/**
- * Retrieve the list of themes that are not hidden.
- */
-function _system_theme_list() {
-  // Get current list of themes.
-  $themes = system_rebuild_theme_data();
-
-  // Remove hidden themes from the display list.
-  foreach ($themes as $theme_key => $theme) {
-    if (!empty($theme->info['hidden'])) {
-      unset($themes[$theme_key]);
-    }
-  }
-
-  uasort($themes, 'system_sort_modules_by_info_name');
-  return $themes;
-}
-
 /**
  * Menu callback; displays a listing of all themes.
  */
 function system_themes_page() {
   // Get current list of themes.
-  $themes = _system_theme_list();
+  $themes = list_themes();
+  uasort($themes, 'system_sort_modules_by_info_name');
 
   $theme_default = variable_get('theme_default', 'garland');
   $theme_groups  = array();
 
   foreach ($themes as &$theme) {
+    if (!empty($theme->info['hidden'])) {
+      continue;
+    }
     $admin_theme_options[$theme->name] = $theme->info['name'];
     $theme->is_default = ($theme->name == $theme_default);
 
@@ -369,7 +363,7 @@ function system_theme_enable() {
   if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) {
     $theme = $_REQUEST['theme'];
     // Get current list of themes.
-    $themes = _system_theme_list();
+    $themes = list_themes();
 
     // Check if the specified theme is one recognized by the system.
     if (!empty($themes[$theme])) {
@@ -391,7 +385,7 @@ function system_theme_disable() {
   if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) {
     $theme = $_REQUEST['theme'];
     // Get current list of themes.
-    $themes = _system_theme_list();
+    $themes = list_themes();
 
     // Check if the specified theme is one recognized by the system.
     if (!empty($themes[$theme])) {
@@ -419,7 +413,7 @@ function system_theme_default() {
   if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) {
     $theme = $_REQUEST['theme'];
     // Get current list of themes.
-    $themes = _system_theme_list();
+    $themes = list_themes();
 
     // Check if the specified theme is one recognized by the system.
     if (!empty($themes[$theme])) {
@@ -832,20 +826,21 @@ function system_modules($form, $form_state = array()) {
   $files = system_rebuild_module_data();
 
   // Remove hidden modules from display list.
-  foreach ($files as $filename => $file) {
+  $visible_files = $files;
+  foreach ($visible_files as $filename => $file) {
     if (!empty($file->info['hidden']) || !empty($file->info['required'])) {
-      unset($files[$filename]);
+      unset($visible_files[$filename]);
     }
   }
 
-  uasort($files, 'system_sort_modules_by_info_name');
+  uasort($visible_files, 'system_sort_modules_by_info_name');
 
   // If the modules form was submitted, then system_modules_submit() runs first
   // and if there are unfilled required modules, then $form_state['storage'] is
   // filled, triggering a rebuild. In this case we need to display a
   // confirmation form.
   if (!empty($form_state['storage'])) {
-    return system_modules_confirm_form($files, $form_state['storage']);
+    return system_modules_confirm_form($visible_files, $form_state['storage']);
   }
 
   $modules = array();
@@ -855,7 +850,7 @@ function system_modules($form, $form_state = array()) {
   $help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
 
   // Iterate through each of the modules.
-  foreach ($files as $filename => $module) {
+  foreach ($visible_files as $filename => $module) {
     $extra = array();
     $extra['enabled'] = (bool) $module->status;
     // If this module requires other modules, add them to the array.
@@ -864,7 +859,8 @@ function system_modules($form, $form_state = array()) {
         $extra['requires'][$requires] = t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst($requires)));
         $extra['disabled'] = TRUE;
       }
-      else {
+      // Only display visible modules.
+      elseif (isset($visible_files[$requires])) {
         $requires_name = $files[$requires]->info['name'];
         if ($incompatible_version = drupal_check_incompatibility($v, str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $files[$requires]->info['version']))) {
           $extra['requires'][$requires] = t('@module (<span class="admin-missing">incompatible with</span> version @version)', array(
@@ -921,8 +917,8 @@ function system_modules($form, $form_state = array()) {
     // impossible to disable this one.
     foreach ($module->required_by as $required_by => $v) {
       // Hidden modules are unset already.
-      if (isset($files[$required_by])) {
-        if ($files[$required_by]->status == 1) {
+      if (isset($visible_files[$required_by])) {
+        if ($files[$required_by]->status == 1 && $module->status == 1) {
           $extra['required_by'][] = t('@module (<span class="admin-enabled">enabled</span>)', array('@module' => $files[$required_by]->info['name']));
           $extra['disabled'] = TRUE;
         }
@@ -1240,7 +1236,6 @@ function system_modules_submit($form, &$form_state) {
   registry_rebuild();
   system_rebuild_theme_data();
   drupal_theme_rebuild();
-  cache_clear_all('system_list', 'cache_bootstrap');
   node_types_rebuild();
   menu_rebuild();
   cache_clear_all('schema', 'cache');
@@ -1338,7 +1333,7 @@ function system_modules_uninstall_confirm_form($storage) {
 
   // Construct the hidden form elements and list items.
   foreach (array_filter($storage['uninstall']) as $module => $value) {
-    $info = drupal_parse_info_file(dirname(drupal_get_filename('module', $module)) . '/' . $module . '.info');
+    $info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info');
     $uninstall[] = $info['name'];
     $form['uninstall'][$module] = array('#type' => 'hidden',
       '#value' => 1,
@@ -1631,12 +1626,12 @@ function system_performance_settings() {
     '#title' => t('Caching'),
   );
 
-  $cache = variable_get('cache', CACHE_DISABLED);
+  $cache = variable_get('cache', 0);
   $form['caching']['cache'] = array(
-    '#type' => 'radios',
-    '#title' => t('Page cache for anonymous users'),
+    '#type' => 'checkbox',
+    '#title' => t('Cache pages for anonymous users'),
     '#default_value' => $cache,
-    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended)')),
+    '#weight' => -2,
   );
   $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval');
   $period[0] = '<' . t('none') . '>';
@@ -1645,7 +1640,14 @@ function system_performance_settings() {
     '#title' => t('Minimum cache lifetime'),
     '#default_value' => variable_get('cache_lifetime', 0),
     '#options' => $period,
-    '#description' => t('The minimum amount of time that will elapse before the caches are recreated.')
+    '#description' => t('Cached pages will not be re-created until at least this much time has elapsed.')
+  );
+  $form['caching']['page_cache_maximum_age'] = array(
+    '#type' => 'select',
+    '#title' => t('Expiration of cached pages'),
+    '#default_value' => variable_get('page_cache_maximum_age', 0),
+    '#options' => $period,
+    '#description' => t('The maximum time an external cache can use an old version of a page.')
   );
 
   $directory = 'public://';
@@ -1662,7 +1664,7 @@ function system_performance_settings() {
     '#description' => t('External resources can be optimized automatically, which can reduce both the size and number of requests made to your website.') . $disabled_message,
   );
 
-  $js_hide = $cache == CACHE_DISABLED ? ' class="js-hide"' : '';
+  $js_hide = $cache ? '' : ' class="js-hide"';
   $form['bandwidth_optimization']['page_compression'] = array(
     '#type' => 'checkbox',
     '#title' => t('Compress cached pages.'),
@@ -1736,15 +1738,18 @@ function system_file_system_settings() {
   // Any visible, writeable wrapper can potentially be used for the files
   // directory, including a remote file system that integrates with a CDN.
   foreach(file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $info) {
-    $options[$scheme] = $info['description'];
+    $options[$scheme] = check_plain($info['description']);
+  }
+
+  if (!empty($options)) {
+    $form['file_default_scheme'] = array(
+      '#type' => 'radios',
+      '#title' => t('Default download method'),
+      '#default_value' => isset($options['public']) ? 'public' : key($options),
+      '#options' => $options,
+      '#description' => t('This setting is used as the preferred download method. The use of public files is more efficient, but does not provide any access control.'),
+    );
   }
-  $form['file_default_scheme'] = array(
-    '#type' => 'radios',
-    '#title' => t('Default download method'),
-    '#default_value' => 'public',
-    '#options' => $options,
-    '#description' => t('This setting is used as the preferred download method. The use of public files is more efficient, but does not provide any access control.'),
-  );
 
   return system_settings_form($form, TRUE);
 }
@@ -2028,7 +2033,7 @@ function system_add_date_format_type_form($form, &$form_state) {
     '#title' => t('Date type'),
     '#type' => 'textfield',
     '#required' => TRUE,
-    '#field_suffix' => ' <small id="edit-date-type-suffix">&nbsp</small>',
+    '#field_suffix' => ' <small id="edit-date-type-suffix">&nbsp;</small>',
   );
   $js_settings = array(
     'type' => 'setting',
@@ -2474,15 +2479,15 @@ function theme_status_report($variables) {
         REQUIREMENT_WARNING => 'warning',
         REQUIREMENT_ERROR => 'error',
       );
-      $class = $classes[isset($requirement['severity']) ? (int)$requirement['severity'] : 0] . ' ' . $class;
+      $class = $classes[isset($requirement['severity']) ? (int) $requirement['severity'] : 0] . ' ' . $class;
 
       // Output table row(s)
       if (!empty($requirement['description'])) {
-        $output .= '<tr class="' . $class . ' merge-down"><th>' . $requirement['title'] . '</th><td>' . $requirement['value'] . '</td></tr>';
+        $output .= '<tr class="' . $class . ' merge-down"><td>' . $requirement['title'] . '</td><td>' . $requirement['value'] . '</td></tr>';
         $output .= '<tr class="' . $class . ' merge-up"><td colspan="2">' . $requirement['description'] . '</td></tr>';
       }
       else {
-        $output .= '<tr class="' . $class . '"><th>' . $requirement['title'] . '</th><td>' . $requirement['value'] . '</td></tr>';
+        $output .= '<tr class="' . $class . '"><td>' . $requirement['title'] . '</td><td>' . $requirement['value'] . '</td></tr>';
       }
     }
   }
@@ -2936,7 +2941,7 @@ function system_actions_manage_form_submit($form, &$form_state) {
  * on our elements.
  *
  * @param $action
- *   md5 hash of an action ID or an integer. If it is an md5 hash, we are
+ *   Hash of an action ID or an integer. If it is a hash, we are
  *   creating a new instance. If it is an integer, we are editing an existing
  *   instance.
  * @return
@@ -2961,7 +2966,7 @@ function system_actions_configure($form, &$form_state, $action = NULL) {
     $edit['actions_label'] = $data->label;
     $edit['actions_type'] = $data->type;
     $function = $data->callback;
-    $action = md5($data->callback);
+    $action = drupal_hash_base64($data->callback);
     $params = unserialize($data->parameters);
     if ($params) {
       foreach ($params as $name => $val) {
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index 3bb8824ea6e7bbdb7e033fd1f0fb2a7b10f94f04..9ab122284f4ba828f7083e70b2c86696e4bd955c 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.api.php,v 1.157 2010/04/26 14:33:54 dries Exp $
+// $Id: system.api.php,v 1.167 2010/05/07 12:59:07 dries Exp $
 
 /**
  * @file
@@ -32,6 +32,8 @@
  *     exists, and automatically load it when required.
  *
  * See system_hook_info() for all hook groups defined by Drupal core.
+ *
+ * @see hook_hook_info_alter().
  */
 function hook_hook_info() {
   $hooks['token_info'] = array(
@@ -43,6 +45,21 @@ function hook_hook_info() {
   return $hooks;
 }
 
+/**
+ * Alter information from hook_hook_info().
+ *
+ * @param $hooks
+ *   Information gathered by module_hook_info() from other modules'
+ *   implementations of hook_hook_info(). Alter this array directly.
+ *   See hook_hook_info() for information on what this may contain.
+ */
+function hook_hook_info_alter(&$hooks) {
+  // Our module wants to completely override the core tokens, so make
+  // sure the core token hooks are not found.
+  $hooks['token_info']['group'] = 'mytokens';
+  $hooks['tokens']['group'] = 'mytokens';
+}
+
 /**
  * Inform the base system and the Field API about one or more entity types.
  *
@@ -405,8 +422,8 @@ function hook_cron_queue_info() {
  * @param array $queues
  *   An array of cron queue information.
  *
- *  @see hook_cron_queue_info()
- *  @see drupal_cron_run()
+ * @see hook_cron_queue_info()
+ * @see drupal_cron_run()
  */
 function hook_cron_queue_info_alter(&$queues) {
   // This site has many feeds so let's spend 90 seconds on each cron run
@@ -537,9 +554,9 @@ function hook_js_alter(&$javascript) {
  *   element of the value.
  * - 'css': Like 'js', an array of CSS elements passed to drupal_add_css().
  * - 'dependencies': An array of libraries that are required for a library. Each
- *   element is an array containing the module and name of the registered
- *   library. Note that all dependencies for each dependent library will be
- *   added when this library is added.
+ *   element is an array listing the module and name of another library. Note
+ *   that all dependencies for each dependent library will also be added when
+ *   this library is added.
  *
  * Registered information for a library should contain re-usable data only.
  * Module- or implementation-specific data and integration logic should be added
@@ -582,7 +599,7 @@ function hook_library() {
     ),
     'dependencies' => array(
       // Require jQuery UI core by System module.
-      array('system' => 'ui'),
+      array('system', 'ui'),
       // Require our other library.
       array('my_module', 'library-1'),
       // Require another library.
@@ -682,6 +699,499 @@ function hook_page_build(&$page) {
   }
 }
 
+/**
+ * Define menu items and page callbacks.
+ *
+ * This hook enables modules to register paths in order to define how URL
+ * requests are handled. Paths may be registered for URL handling only, or they
+ * can register a link to be placed in a menu (usually the Navigation menu). A
+ * path and its associated information is commonly called a "menu router item".
+ * This hook is rarely called (for example, when modules are enabled), and
+ * its results are cached in the database.
+ *
+ * hook_menu() implementations return an associative array whose keys define
+ * paths and whose values are an associative array of properties for each
+ * path. (The complete list of properties is in the return value section below.)
+ *
+ * The definition for each path may include a page callback function, which is
+ * invoked when the registered path is requested. If there is no other
+ * registered path that fits the requested path better, any further path
+ * components are passed to the callback function. For example, your module
+ * could register path 'abc/def':
+ * @code
+ *   function mymodule_menu() {
+ *     $items['abc/def'] = array(
+ *       'page callback' => 'mymodule_abc_view',
+ *     );
+ *   }
+ *
+ *   function mymodule_abc_view($ghi = 0, $jkl = '') {
+ *     // ...
+ *   }
+ * @endcode
+ * When path 'abc/def' is requested, no further path components are in the
+ * request, and no additional arguments are passed to the callback function (so
+ * $ghi and $jkl would take the default values as defined in the function
+ * signature). When 'abc/def/123/foo' is requested, $ghi will be '123' and
+ * $jkl will be 'foo'. Note that this automatic passing of optional path
+ * arguments applies only to page and theme callback functions.
+ *
+ * In addition to optional path arguments, the page callback and other callback
+ * functions may specify argument lists as arrays. These argument lists may
+ * contain both fixed/hard-coded argument values and integers that correspond
+ * to path components. When integers are used and the callback function is
+ * called, the corresponding path components will be substituted for the
+ * integers. That is, the integer 0 in an argument list will be replaced with
+ * the first path component, integer 1 with the second, and so on (path
+ * components are numbered starting from zero). This substitution feature allows
+ * you to re-use a callback function for several different paths. For example:
+ * @code
+ *   function mymodule_menu() {
+ *     $items['abc/def'] = array(
+ *       'page callback' => 'mymodule_abc_view',
+ *       'page arguments' => array(1, 'foo'),
+ *     );
+ *   }
+ * @endcode
+ * When path 'abc/def' is requested, the page callback function will get 'def'
+ * as the first argument and (always) 'foo' as the second argument.
+ *
+ * Note that if a page or theme callback function has an argument list array,
+ * these arguments will be passed first to the function, followed by any
+ * any arguments generated by optional path arguments as described above.
+ *
+ * Special care should be taken for the page callback drupal_get_form(), because
+ * your specific form callback function will always receive $form and
+ * &$form_state as the first function arguments:
+ * @code
+ *   function mymodule_abc_form($form, &$form_state) {
+ *     // ...
+ *     return $form;
+ *   }
+ * @endcode
+ * See @link form_api Form API documentation @endlink for details.
+ *
+ * Wildcards within paths also work with integer substitution. For example,
+ * your module could register path 'my-module/%/edit':
+ * @code
+ *   $items['my-module/%/edit'] = array(
+ *     'page callback' => 'mymodule_abc_edit',
+ *     'page arguments' => array(1),
+ *   );
+ * @endcode
+ * When path 'my-module/foo/edit' is requested, integer 1 will be replaced
+ * with 'foo' and passed to the callback function.
+ *
+ * Registered paths may also contain special "auto-loader" wildcard components
+ * in the form of '%mymodule_abc', where the '%' part means that this path
+ * component is a wildcard, and the 'mymodule_abc' part defines the prefix for a
+ * load function, which here would be named mymodule_abc_load(). When a matching
+ * path is requested, your load function will receive as its first argument the
+ * path component in the position of the wildcard; load functions may also be
+ * passed additional arguments (see "load arguments" in the return value
+ * section below). For example, your module could register path
+ * 'my-module/%mymodule_abc/edit':
+ * @code
+ *   $items['my-module/%mymodule_abc/edit'] = array(
+ *     'page callback' => 'mymodule_abc_edit',
+ *     'page arguments' => array(1),
+ *   );
+ * @endcode
+ * When path 'my-module/123/edit' is requested, your load function
+ * mymodule_abc_load() will be invoked with the argument '123', and should
+ * load and return an "abc" object with internal id 123:
+ * @code
+ *   function mymodule_abc_load($abc_id) {
+ *     return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject();
+ *   }
+ * @endcode
+ * This 'abc' object will then be passed into the page callback function
+ * mymodule_abc_edit() to replace the integer 1 in the page arguments.
+ *
+ * You can also make groups of menu items to be rendered (by default) as tabs
+ * on a page. To do that, first create one menu item of type MENU_NORMAL_ITEM,
+ * with your chosen path, such as 'foo'. Then duplicate that menu item, using a
+ * subdirectory path, such as 'foo/tab1', and changing the type to
+ * MENU_DEFAULT_LOCAL_TASK to make it the default tab for the group. Then add
+ * the additional tab items, with paths such as "foo/tab2" etc., with type
+ * MENU_LOCAL_TASK. Example:
+ * @code
+ * // Make "Foo settings" appear on the admin Config page
+ * $items['admin/config/foo'] = array(
+ *   'title' => 'Foo settings',
+ *   'type' => MENU_NORMAL_ITEM,
+ *   // page callback, etc. need to be added here
+ * );
+ * // Make "Global settings" the main tab on the "Foo settings" page
+ * $items['admin/config/foo/global'] = array(
+ *   'title' => 'Global settings',
+ *   'type' => MENU_DEFAULT_LOCAL_TASK,
+ *   // access callback, page callback, and theme callback will be inherited
+ *   // from 'admin/config/foo', if not specified here to override
+ * );
+ * // Make an additional tab called "Node settings" on "Foo settings"
+ * $items['admin/config/foo/node'] = array(
+ *   'title' => 'Node settings',
+ *   'type' => MENU_LOCAL_TASK,
+ *   // access callback, page callback, and theme callback will be inherited
+ *   // from 'admin/config/foo', if not specified here to override
+ * );
+ * @endcode
+ *
+ * @return
+ *   An array of menu items. Each menu item has a key corresponding to the
+ *   Drupal path being registered. The corresponding array value is an
+ *   associative array that may contain the following key-value pairs:
+ *   - "title": Required. The untranslated title of the menu item.
+ *   - "title callback": Function to generate the title; defaults to t().
+ *     If you require only the raw string to be output, set this to FALSE.
+ *   - "title arguments": Arguments to send to t() or your custom callback,
+ *     with path component substitution as described above.
+ *   - "description": The untranslated description of the menu item.
+ *   - "page callback": The function to call to display a web page when the user
+ *     visits the path. If omitted, the parent menu item's callback will be used
+ *     instead.
+ *   - "page arguments": An array of arguments to pass to the page callback
+ *     function, with path component substitution as described above.
+ *   - "delivery callback": The function to call to package the result of the
+ *     page callback function and send it to the browser. Defaults to
+ *     drupal_deliver_html_page() unless a value is inherited from a parent menu
+ *     item.
+ *   - "access callback": A function returning a boolean value that determines
+ *     whether the user has access rights to this menu item. Defaults to
+ *     user_access() unless a value is inherited from a parent menu item.
+ *   - "access arguments": An array of arguments to pass to the access callback
+ *     function, with path component substitution as described above.
+ *   - "theme callback": Optional. A function returning the machine-readable
+ *     name of the default theme that will be used to render the page. If this
+ *     function is provided, it is expected to return a currently-active theme
+ *     on the site (otherwise, the main site theme will be used instead). If no
+ *     function is provided, the main site theme will also be used, unless a
+ *     value is inherited from a parent menu item. In all cases, the results of
+ *     this function can be dynamically overridden for a particular page
+ *     request by modules which implement hook_custom_theme().
+ *   - "theme arguments": An array of arguments to pass to the theme callback
+ *     function, with path component substitution as described above.
+ *   - "file": A file that will be included before the page callback is called;
+ *     this allows page callback functions to be in separate files. The file
+ *     should be relative to the implementing module's directory unless
+ *     otherwise specified by the "file path" option. Does not apply to other
+ *     callbacks (only page callback).
+ *   - "file path": The path to the directory containing the file specified in
+ *     "file". This defaults to the path to the module implementing the hook.
+ *   - "load arguments": An array of arguments to be passed to each of the
+ *     wildcard object loaders in the path, after the path argument itself.
+ *     For example, if a module registers path node/%node/revisions/%/view
+ *     with load arguments set to array(3), the '%node' in the path indicates
+ *     that the loader function node_load() will be called with the second
+ *     path component as the first argument. The 3 in the load arguments
+ *     indicates that the fourth path component will also be passed to
+ *     node_load() (numbering of path components starts at zero). So, if path
+ *     node/12/revisions/29/view is requested, node_load(12, 29) will be called.
+ *     There are also two "magic" values that can be used in load arguments.
+ *     "%index" indicates the index of the wildcard path component. "%map"
+ *     indicates the path components as an array. For example, if a module
+ *     registers for several paths of the form 'user/%user_category/edit/*', all
+ *     of them can use the same load function user_category_load(), by setting
+ *     the load arguments to array('%map', '%index'). For instance, if the user
+ *     is editing category 'foo' by requesting path 'user/32/edit/foo', the load
+ *     function user_category_load() will be called with 32 as its first
+ *     argument, the array ('user', 32, 'edit', 'foo') as the map argument,
+ *     and 1 as the index argument (because %user_category is the second path
+ *     component and numbering starts at zero). user_category_load() can then
+ *     use these values to extract the information that 'foo' is the category
+ *     being requested.
+ *   - "weight": An integer that determines the relative position of items in
+ *     the menu; higher-weighted items sink. Defaults to 0. Menu items with the
+ *     same weight are ordered alphabetically.
+ *   - "menu_name": Optional. Set this to a custom menu if you don't want your
+ *     item to be placed in Navigation.
+ *   - "context": (optional) Defines the context a tab may appear in. By
+ *     default, all tabs are only displayed as local tasks when being rendered
+ *     in a page context. All tabs that should be accessible as contextual links
+ *     in page region containers outside of the parent menu item's primary page
+ *     context should be registered using one of the following contexts:
+ *     - MENU_CONTEXT_PAGE: (default) The tab is displayed as local task for the
+ *       page context only.
+ *     - MENU_CONTEXT_INLINE: The tab is displayed as contextual link outside of
+ *       the primary page context only.
+ *     Contexts can be combined. For example, to display a tab both on a page
+ *     and inline, a menu router item may specify:
+ *     @code
+ *       'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ *     @endcode
+ *   - "tab_parent": For local task menu items, the path of the task's parent
+ *     item; defaults to the same path without the last component (e.g., the
+ *     default parent for 'admin/people/create' is 'admin/people').
+ *   - "tab_root": For local task menu items, the path of the closest non-tab
+ *     item; same default as "tab_parent".
+ *   - "block callback": Name of a function used to render the block on the
+ *     system administration page for this item (called with no arguments).
+ *     If not provided, system_admin_menu_block() is used to generate it.
+ *   - "position": Position of the block ('left' or 'right') on the system
+ *     administration page for this item.
+ *   - "type": A bitmask of flags describing properties of the menu item.
+ *     Many shortcut bitmasks are provided as constants in menu.inc:
+ *     - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
+ *       moved/hidden by the administrator.
+ *     - MENU_CALLBACK: Callbacks simply register a path so that the correct
+ *       information is generated when the path is accessed.
+ *     - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
+ *       administrator may enable.
+ *     - MENU_LOCAL_ACTION: Local actions are menu items that describe actions
+ *       on the parent item such as adding a new user or block, and are
+ *       rendered in the action-links list in your theme.
+ *     - MENU_LOCAL_TASK: Local tasks are menu items that describe different
+ *       displays of data, and are generally rendered as tabs.
+ *     - MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one
+ *       "default" task, which should display the same page as the parent item.
+ *     If the "type" element is omitted, MENU_NORMAL_ITEM is assumed.
+ *
+ * For a detailed usage example, see page_example.module.
+ * For comprehensive documentation on the menu system, see
+ * http://drupal.org/node/102338.
+ */
+function hook_menu() {
+  $items['blog'] = array(
+    'title' => 'blogs',
+    'page callback' => 'blog_page',
+    'access arguments' => array('access content'),
+    'type' => MENU_SUGGESTED_ITEM,
+  );
+  $items['blog/feed'] = array(
+    'title' => 'RSS feed',
+    'page callback' => 'blog_feed',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Alter the data being saved to the {menu_router} table after hook_menu is invoked.
+ *
+ * This hook is invoked by menu_router_build(). The menu definitions are passed
+ * in by reference. Each element of the $items array is one item returned
+ * by a module from hook_menu. Additional items may be added, or existing items
+ * altered.
+ *
+ * @param $items
+ *   Associative array of menu router definitions returned from hook_menu().
+ */
+function hook_menu_alter(&$items) {
+  // Example - disable the page at node/add
+  $items['node/add']['access callback'] = FALSE;
+}
+
+/**
+ * Alter the data being saved to the {menu_links} table by menu_link_save().
+ *
+ * @param $item
+ *   Associative array defining a menu link as passed into menu_link_save().
+ */
+function hook_menu_link_alter(&$item) {
+  // Example 1 - make all new admin links hidden (a.k.a disabled).
+  if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) {
+    $item['hidden'] = 1;
+  }
+  // Example 2  - flag a link to be altered by hook_translated_menu_link_alter()
+  if ($item['link_path'] == 'devel/cache/clear') {
+    $item['options']['alter'] = TRUE;
+  }
+}
+
+/**
+ * Alter a menu link after it's translated, but before it's rendered.
+ *
+ * This hook may be used, for example, to add a page-specific query string.
+ * For performance reasons, only links that have $item['options']['alter'] == TRUE
+ * will be passed into this hook. The $item['options']['alter'] flag should
+ * generally be set using hook_menu_link_alter().
+ *
+ * @param $item
+ *   Associative array defining a menu link after _menu_link_translate()
+ * @param $map
+ *   Associative array containing the menu $map (path parts and/or objects).
+ */
+function hook_translated_menu_link_alter(&$item, $map) {
+  if ($item['href'] == 'devel/cache/clear') {
+    $item['localized_options']['query'] = drupal_get_destination();
+  }
+}
+
+/**
+ * Inform modules that a menu link has been created.
+ *
+ * This hook is used to notify modules that menu items have been
+ * created. Contributed modules may use the information to perform
+ * actions based on the information entered into the menu system.
+ *
+ * @param $link
+ *   Associative array defining a menu link as passed into menu_link_save().
+ *
+ * @see hook_menu_link_update()
+ * @see hook_menu_link_delete()
+ */
+function hook_menu_link_insert($link) {
+  // In our sample case, we track menu items as editing sections
+  // of the site. These are stored in our table as 'disabled' items.
+  $record['mlid'] = $link['mlid'];
+  $record['menu_name'] = $link['menu_name'];
+  $record['status'] = 0;
+  drupal_write_record('menu_example', $record);
+}
+
+/**
+ * Inform modules that a menu link has been updated.
+ *
+ * This hook is used to notify modules that menu items have been
+ * updated. Contributed modules may use the information to perform
+ * actions based on the information entered into the menu system.
+ *
+ * @param $link
+ *   Associative array defining a menu link as passed into menu_link_save().
+ *
+ * @see hook_menu_link_insert()
+ * @see hook_menu_link_delete()
+ */
+function hook_menu_link_update($link) {
+  // If the parent menu has changed, update our record.
+  $menu_name = db_result(db_query("SELECT mlid, menu_name, status FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $link['mlid'])));
+  if ($menu_name != $link['menu_name']) {
+    db_update('menu_example')
+      ->fields(array('menu_name' => $link['menu_name']))
+      ->condition('mlid', $link['mlid'])
+      ->execute();
+  }
+}
+
+/**
+ * Inform modules that a menu link has been deleted.
+ *
+ * This hook is used to notify modules that menu items have been
+ * deleted. Contributed modules may use the information to perform
+ * actions based on the information entered into the menu system.
+ *
+ * @param $link
+ *   Associative array defining a menu link as passed into menu_link_save().
+ *
+ * @see hook_menu_link_insert()
+ * @see hook_menu_link_update()
+ */
+function hook_menu_link_delete($link) {
+  // Delete the record from our table.
+  db_delete('menu_example')
+    ->condition('mlid', $link['mlid'])
+    ->execute();
+}
+
+/**
+ * Alter tabs and actions displayed on the page before they are rendered.
+ *
+ * This hook is invoked by menu_local_tasks(). The system-determined tabs and
+ * actions are passed in by reference. Additional tabs or actions may be added,
+ * or existing items altered.
+ *
+ * Each tab or action is an associative array containing:
+ * - #theme: The theme function to use to render.
+ * - #link: An associative array containing:
+ *   - title: The localized title of the link.
+ *   - href: The system path to link to.
+ *   - localized_options: An array of options to pass to url().
+ * - #active: Whether the link should be marked as 'active'.
+ *
+ * @param $data
+ *   An associative array containing:
+ *   - actions: An associative array containing:
+ *     - count: The amount of actions determined by the menu system, which can
+ *       be ignored.
+ *     - output: A list of of actions, each one being an associative array
+ *       as described above.
+ *   - tabs: An indexed array (list) of tab levels (up to 2 levels), each
+ *     containing an associative array:
+ *     - count: The amount of tabs determined by the menu system. This value
+ *       does not need to be altered if there is more than one tab.
+ *     - output: A list of of tabs, each one being an associative array as
+ *       described above.
+ */
+function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
+  // Add an action linking to node/add to all pages.
+  $data['actions']['output'][] = array(
+    '#theme' => 'menu_local_task',
+    '#link' => array(
+      'title' => t('Add new content'),
+      'href' => 'node/add',
+      'localized_options' => array(
+        'attributes' => array(
+          'title' => t('Add new content'),
+        ),
+      ),
+    ),
+  );
+
+  // Add a tab linking to node/add to all pages.
+  $data['tabs'][0]['output'][] = array(
+    '#theme' => 'menu_local_task',
+    '#link' => array(
+      'title' => t('Example tab'),
+      'href' => 'node/add',
+      'localized_options' => array(
+        'attributes' => array(
+          'title' => t('Add new content'),
+        ),
+      ),
+    ),
+    // Define whether this link is active. This can be omitted for
+    // implementations that add links to pages outside of the current page
+    // context.
+    '#active' => ($router_item['path'] == $root_path),
+  );
+}
+
+/**
+ * Alter contextual links before they are rendered.
+ *
+ * This hook is invoked by menu_contextual_links(). The system-determined
+ * contextual links are passed in by reference. Additional links may be added
+ * or existing links can be altered.
+ *
+ * Each contextual link must at least contain:
+ * - title: The localized title of the link.
+ * - href: The system path to link to.
+ * - localized_options: An array of options to pass to url().
+ *
+ * @param $links
+ *   An associative array containing contextual links for the given $root_path,
+ *   as described above. The array keys are used to build CSS class names for
+ *   contextual links and must therefore be unique for each set of contextual
+ *   links.
+ * @param $router_item
+ *   The menu router item belonging to the $root_path being requested.
+ * @param $root_path
+ *   The (parent) path that has been requested to build contextual links for.
+ *   This is a normalized path, which means that an originally passed path of
+ *   'node/123' became 'node/%'.
+ *
+ * @see menu_contextual_links()
+ * @see hook_menu()
+ * @see system_preprocess()
+ */
+function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) {
+  // Add a link to all contextual links for nodes.
+  if ($root_path == 'node/%') {
+    $links['foo'] = array(
+      'title' => t('Do fu'),
+      'href' => 'foo/do',
+      'localized_options' => array(
+        'query' => array(
+          'foo' => 'bar',
+        ),
+      ),
+    );
+  }
+}
+
 /**
  * Perform alterations before a page is rendered.
  *
@@ -745,10 +1255,14 @@ function hook_page_alter(&$page) {
  * Perform alterations before a form is rendered.
  *
  * One popular use of this hook is to add form elements to the node form. When
- * altering a node form, the node object retrieved at from $form['#node'].
+ * altering a node form, the node object can be accessed at $form['#node'].
  *
  * Note that instead of hook_form_alter(), which is called for all forms, you
- * can also use hook_form_FORM_ID_alter() to alter a specific form.
+ * can also use hook_form_FORM_ID_alter() to alter a specific form. For each
+ * module (in system weight order) the general form alter hook implementation
+ * is invoked first, then the form ID specific alter implementation is called.
+ * After all module hook implementations are invoked, the hook_form_alter()
+ * implementations from themes are invoked in the same manner.
  *
  * @param $form
  *   Nested array of form elements that comprise the form.
@@ -757,6 +1271,8 @@ function hook_page_alter(&$page) {
  * @param $form_id
  *   String representing the name of the form itself. Typically this is the
  *   name of the function that generated the form.
+ *
+ * @see hook_form_FORM_ID_alter()
  */
 function hook_form_alter(&$form, &$form_state, $form_id) {
   if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
@@ -776,15 +1292,12 @@ function hook_form_alter(&$form, &$form_state, $form_id) {
  * rather than implementing hook_form_alter() and checking the form ID, or
  * using long switch statements to alter multiple forms.
  *
- * Note that this hook fires before hook_form_alter(). Therefore all
- * implementations of hook_form_FORM_ID_alter() will run before all implementations
- * of hook_form_alter(), regardless of the module order.
- *
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
  *   A keyed array containing the current state of the form.
  *
+ * @see hook_form_alter()
  * @see drupal_prepare_form()
  */
 function hook_form_FORM_ID_alter(&$form, &$form_state) {
@@ -1074,91 +1587,92 @@ function hook_permission() {
 /**
  * Register a module (or theme's) theme implementations.
  *
- * Modules and themes implementing this return an array of arrays. The key
- * to each sub-array is the internal name of the hook, and the array contains
- * info about the hook. Each array may contain the following items:
- *
- * - variables: (required if "render element" not present) An array of
- *   variables that this theme hook uses. This value allows the theme layer to
- *   properly utilize templates. Each array key represents the name of the
- *   variable and the value will be used as the default value if it is not given
- *   when theme() is called. Template implementations receive these arguments as
- *   variables in the template file. Function implementations are passed this
- *   array data in the $variables parameter.
- * - render element: (required if "variables" not present) A string that is the
- *   name of the sole renderable element to pass to the theme function. The
- *   string represents the name of the "variable" that will hold the renderable
- *   array inside any optional preprocess or process functions. Cannot be used
- *   with the "variables" item; only one or the other, not both, can be present
- *   in a hook's info array.
- * - file: The file the implementation resides in. This file will be included
- *   prior to the theme being rendered, to make sure that the function or
- *   preprocess function (as needed) is actually loaded; this makes it possible
- *   to split theme functions out into separate files quite easily.
- * - path: Override the path of the file to be used. Ordinarily the module or
- *   theme path will be used, but if the file will not be in the default path,
- *   include it here. This path should be relative to the Drupal root
- *   directory.
- * - template: If specified, this theme implementation is a template, and this
- *   is the template file <b>without an extension</b>. Do not put .tpl.php
- *   on this file; that extension will be added automatically by the default
- *   rendering engine (which is PHPTemplate). If 'path', above, is specified,
- *   the template should also be in this path.
- * - function: If specified, this will be the function name to invoke for this
- *   implementation. If neither file nor function is specified, a default
- *   function name will be assumed. For example, if a module registers
- *   the 'node' theme hook, 'theme_node' will be assigned to its function.
- *   If the chameleon theme registers the node hook, it will be assigned
- *   'chameleon_node' as its function.
- * - pattern: A regular expression pattern to be used to allow this theme
- *   implementation to have a dynamic name. The convention is to use __ to
- *   differentiate the dynamic portion of the theme. For example, to allow
- *   forums to be themed individually, the pattern might be: 'forum__'. Then,
- *   when the forum is themed, call: <code>theme(array('forum__' . $tid, 'forum'),
- *   $forum)</code>.
- * - preprocess functions: A list of functions used to preprocess this data.
- *   Ordinarily this won't be used; it's automatically filled in. By default,
- *   for a module this will be filled in as template_preprocess_HOOK. For
- *   a theme this will be filled in as phptemplate_preprocess and
- *   phptemplate_preprocess_HOOK as well as themename_preprocess and
- *   themename_preprocess_HOOK.
- * - override preprocess functions: Set to TRUE when a theme does NOT want the
- *   standard preprocess functions to run. This can be used to give a theme
- *   FULL control over how variables are set. For example, if a theme wants
- *   total control over how certain variables in the page.tpl.php are set,
- *   this can be set to true. Please keep in mind that when this is used
- *   by a theme, that theme becomes responsible for making sure necessary
- *   variables are set.
- * - type: (automatically derived) Where the theme hook is defined:
- *   'module', 'theme_engine', or 'theme'.
- * - theme path: (automatically derived) The directory path of the theme or
- *   module, so that it doesn't need to be looked up.
- *
  * The following parameters are all optional.
  *
- * @param $existing
+ * @param array $existing
  *   An array of existing implementations that may be used for override
  *   purposes. This is primarily useful for themes that may wish to examine
  *   existing implementations to extract data (such as arguments) so that
  *   it may properly register its own, higher priority implementations.
  * @param $type
- *   What 'type' is being processed. This is primarily useful so that themes
- *   tell if they are the actual theme being called or a parent theme.
- *   May be one of:
- *     - module: A module is being checked for theme implementations.
- *     - base_theme_engine: A theme engine is being checked for a theme which is a parent of the actual theme being used.
- *     - theme_engine: A theme engine is being checked for the actual theme being used.
- *     - base_theme: A base theme is being checked for theme implementations.
- *     - theme: The actual theme in use is being checked.
+ *   Whether a theme, module, etc. is being processed. This is primarily useful
+ *   so that themes tell if they are the actual theme being called or a parent
+ *   theme. May be one of:
+ *   - 'module': A module is being checked for theme implementations.
+ *   - 'base_theme_engine': A theme engine is being checked for a theme that is
+ *     a parent of the actual theme being used.
+ *   - 'theme_engine': A theme engine is being checked for the actual theme
+ *     being used.
+ *   - 'base_theme': A base theme is being checked for theme implementations.
+ *   - 'theme': The actual theme in use is being checked.
  * @param $theme
- *   The actual name of theme that is being being checked (mostly only useful for
- *   theme engine).
+ *   The actual name of theme, module, etc. that is being being processed.
  * @param $path
  *   The directory path of the theme or module, so that it doesn't need to be
  *   looked up.
  *
- * @return
- *   A keyed array of theme hooks.
+ * @return array
+ *   An associative array of theme hook information. The keys on the outer
+ *   array are the internal names of the hooks, and the values are arrays
+ *   containing information about the hook. Each array may contain the
+ *   following elements:
+ *   - variables: (required if "render element" not present) An array of
+ *     variables that this theme hook uses. This value allows the theme layer to
+ *     properly utilize templates. Each array key represents the name of the
+ *     variable and the value will be used as the default value if it is not
+ *     given when theme() is called. Template implementations receive these
+ *     arguments as variables in the template file. Function implementations
+ *     are passed this array data in the $variables parameter.
+ *   - render element: (required if "variables" not present) A string that is
+ *     the name of the sole renderable element to pass to the theme function.
+ *     The string represents the name of the "variable" that will hold the
+ *     renderable array inside any optional preprocess or process functions.
+ *     Cannot be used with the "variables" item; only one or the other, not
+ *     both, can be present in a hook's info array.
+ *   - file: The file the implementation resides in. This file will be included
+ *     prior to the theme being rendered, to make sure that the function or
+ *     preprocess function (as needed) is actually loaded; this makes it
+ *     possible to split theme functions out into separate files quite easily.
+ *   - path: Override the path of the file to be used. Ordinarily the module or
+ *     theme path will be used, but if the file will not be in the default path,
+ *     include it here. This path should be relative to the Drupal root
+ *     directory.
+ *   - template: If specified, this theme implementation is a template, and this
+ *     is the template file without an extension. Do not put .tpl.php on this
+ *     file; that extension will be added automatically by the default rendering
+ *     engine (which is PHPTemplate). If 'path', above, is specified, the
+ *     template should also be in this path.
+ *   - function: If specified, this will be the function name to invoke for this
+ *     implementation. If neither file nor function is specified, a default
+ *     function name will be assumed. For example, if a module registers
+ *     the 'node' theme hook, 'theme_node' will be assigned to its function.
+ *     If the chameleon theme registers the node hook, it will be assigned
+ *     'chameleon_node' as its function.
+ *   - pattern: A regular expression pattern to be used to allow this theme
+ *     implementation to have a dynamic name. The convention is to use __ to
+ *     differentiate the dynamic portion of the theme. For example, to allow
+ *     forums to be themed individually, the pattern might be: 'forum__'. Then,
+ *     when the forum is themed, call:
+ *     @code
+ *     theme(array('forum__' . $tid, 'forum'), $forum)
+ *     @endcode
+ *   - preprocess functions: A list of functions used to preprocess this data.
+ *     Ordinarily this won't be used; it's automatically filled in. By default,
+ *     for a module this will be filled in as template_preprocess_HOOK. For
+ *     a theme this will be filled in as phptemplate_preprocess and
+ *     phptemplate_preprocess_HOOK as well as themename_preprocess and
+ *     themename_preprocess_HOOK.
+ *   - override preprocess functions: Set to TRUE when a theme does NOT want the
+ *     standard preprocess functions to run. This can be used to give a theme
+ *     FULL control over how variables are set. For example, if a theme wants
+ *     total control over how certain variables in the page.tpl.php are set,
+ *     this can be set to true. Please keep in mind that when this is used
+ *     by a theme, that theme becomes responsible for making sure necessary
+ *     variables are set.
+ *   - type: (automatically derived) Where the theme hook is defined:
+ *     'module', 'theme_engine', or 'theme'.
+ *   - theme path: (automatically derived) The directory path of the theme or
+ *     module, so that it doesn't need to be looked up.
  */
 function hook_theme($existing, $type, $theme, $path) {
   return array(
@@ -1703,7 +2217,7 @@ function hook_file_validate(&$file) {
  *
  * @see file_save()
  */
-function hook_file_insert(&$file) {
+function hook_file_insert($file) {
 
 }
 
@@ -1717,7 +2231,7 @@ function hook_file_insert(&$file) {
  *
  * @see file_save()
  */
-function hook_file_update(&$file) {
+function hook_file_update($file) {
 
 }
 
@@ -2844,6 +3358,30 @@ function hook_date_format_types() {
   );
 }
 
+/**
+ * Modify existing date format types.
+ *
+ * Allows other modules to modify existing date types like 'long'. Called
+ * by _system_date_format_types_build(). For instance, A module may use this
+ * hook to apply settings across all date format types, such as locking all
+ * date format types so they appear to be provided by the system.
+ *
+ * @param $types
+ *   An associative array of date format types containing:
+ *   - types:  An array of date format types including configuration settings
+ *     for each type:
+ *     - is_new: Set to FALSE to override previous settings.
+ *     - module: The name of the module that created the date format type.
+ *     - type: The date type name.
+ *     - title: The title of the date type.
+ *     - locked: Specifies that the date type is system-provided.
+ */
+function hook_date_format_types_alter(&$types) {
+  foreach ($types as $type_name => $type) {
+    $types[$type_name]['locked'] = 1;
+  }
+}
+
 /**
  * Defines additional date formats.
  *
@@ -3275,6 +3813,66 @@ function hook_token_info_alter(&$data) {
   );
 }
 
+
+/**
+ * Provide information on Updaters (classes that can update Drupal).
+ *
+ * An Updater is a class that knows how to update various parts of the Drupal
+ * file system, for example to update modules that have newer releases, or to
+ * install a new theme.
+ *
+ * @return
+ *   An associative array of information about the updater(s) being provided.
+ *   This array is keyed by a unique identifier for each updater, and the
+ *   values are subarrays that can contain the following keys:
+ *   - class: The name of the PHP class which implements this updater.
+ *   - name: Human-readable name of this updater.
+ *   - weight: Controls what order the Updater classes are consulted to decide
+ *     which one should handle a given task. When an update task is being run,
+ *     the system will loop through all the Updater classes defined in this
+ *     registry in weight order and let each class respond to the task and
+ *     decide if each Updater wants to handle the task. In general, this
+ *     doesn't matter, but if you need to override an existing Updater, make
+ *     sure your Updater has a lighter weight so that it comes first.
+ *
+ * @see drupal_get_updaters()
+ * @see hook_updater_info_alter()
+ */
+function hook_updater_info() {
+  return array(
+    'module' => array(
+      'class' => 'ModuleUpdater',
+      'name' => t('Update modules'),
+      'weight' => 0,
+    ),
+    'theme' => array(
+      'class' => 'ThemeUpdater',
+      'name' => t('Update themes'),
+      'weight' => 0,
+    ),
+  );
+}
+
+/**
+ * Alter the Updater information array.
+ *
+ * An Updater is a class that knows how to update various parts of the Drupal
+ * file system, for example to update modules that have newer releases, or to
+ * install a new theme.
+ *
+ * @param array $updaters
+ *   Associative array of updaters as defined through hook_updater_info().
+ *   Alter this array directly.
+ *
+ * @see drupal_get_updaters()
+ * @see hook_updater_info()
+ */
+function hook_updater_info_alter(&$updaters) {
+  // Adjust weight so that the theme Updater gets a chance to handle a given
+  // update task before module updaters.
+  $updaters['theme']['weight'] = -1;
+}
+
 /**
  * Alter the default country list.
  *
diff --git a/modules/system/system.css b/modules/system/system.css
index a426d80b49d2a73b231a10e8d99e89e7b169bbe6..bdf9017de4a890f599c7dc21c7f2f7a4014f4650 100644
--- a/modules/system/system.css
+++ b/modules/system/system.css
@@ -1,4 +1,4 @@
-/* $Id: system.css,v 1.74 2010/04/01 14:47:16 dries Exp $ */
+/* $Id: system.css,v 1.76 2010/05/14 07:45:54 dries Exp $ */
 
 /*
 ** HTML elements
@@ -29,7 +29,8 @@ th {
 th.active img {
   display: inline;
 }
-tr.even, tr.odd {
+tr.even,
+tr.odd {
   background-color: #eee;
   border-bottom: 1px solid #ccc;
   padding: 0.1em 0.6em;
@@ -43,7 +44,8 @@ tr.drag-previous {
 td.active {
   background-color: #ddd;
 }
-td.checkbox, th.checkbox {
+td.checkbox,
+th.checkbox {
   text-align: center;
 }
 tbody {
@@ -86,18 +88,25 @@ thead th {
   margin-top: 1em;
   margin-bottom: 1em;
 }
-tr.odd .form-item, tr.even .form-item {
+tr.odd .form-item,
+tr.even .form-item {
   margin-top: 0;
   margin-bottom: 0;
   white-space: nowrap;
 }
-tr.merge-down, tr.merge-down td, tr.merge-down th {
+tr.merge-down,
+tr.merge-down td,
+tr.merge-down th {
   border-bottom-width: 0 !important;
 }
-tr.merge-up, tr.merge-up td, tr.merge-up th {
+tr.merge-up,
+tr.merge-up td,
+tr.merge-up th {
   border-top-width: 0 !important;
 }
-.form-item input.error, .form-item textarea.error, .form-item select.error {
+.form-item input.error,
+.form-item textarea.error,
+.form-item select.error {
   border: 2px solid red;
 }
 .form-item .description {
@@ -111,33 +120,40 @@ tr.merge-up, tr.merge-up td, tr.merge-up th {
   display: inline;
   font-weight: normal;
 }
-.form-checkboxes, .form-radios {
+.form-checkboxes,
+.form-radios {
   margin: 1em 0;
 }
-.form-checkboxes .form-item, .form-radios .form-item {
+.form-checkboxes .form-item,
+.form-radios .form-item {
   margin-top: 0.4em;
   margin-bottom: 0.4em;
 }
-.form-type-radio .description, .form-type-checkbox .description {
+.form-type-radio .description,
+.form-type-checkbox .description {
   margin-left: 2.4em;
 }
-input.form-checkbox, input.form-radio {
+input.form-checkbox,
+input.form-radio {
   vertical-align: middle;
 }
-.marker, .form-required {
+.marker,
+.form-required {
   color: #f00;
 }
 .more-help-link {
   text-align: right; /* LTR */
 }
-.more-help-link a, a.module-link {
+.more-help-link a,
+a.module-link {
   padding: 1px 0 1px 20px; /* LTR */
 }
 a.module-link {
   display: block;
   white-space: nowrap;
 }
-.more-help-link a, a.module-link-help {
+.more-help-link a,
+a.module-link-help {
   background: url(../../misc/help.png) 0 50% no-repeat; /* LTR */
 }
 a.module-link-permissions {
@@ -238,6 +254,26 @@ tr.selected td {
   background: #ffc;
 }
 
+/*
+** To be used with displace.js
+*/
+.displace-top,
+.displace-bottom {
+  position: relative;
+  width: 100%;
+}
+.displace-processed .displace-top,
+.displace-processed .displace-bottom {
+  position: fixed;
+  width: auto;
+  left: 0;
+  right: 0;
+}
+.displace-unsupported .displace-top,
+.displace-unsupported .displace-bottom {
+  position: absolute;
+}
+
 /*
 ** Floating header for tableheader.js
 */
diff --git a/modules/system/system.info b/modules/system/system.info
index 96ccc8132a0e5f7ff2891c1ed8babe038d6d6524..b15f30f060897f8ff871f237fbe82802799bcd10 100644
--- a/modules/system/system.info
+++ b/modules/system/system.info
@@ -18,8 +18,8 @@ files[] = system.mail.inc
 required = TRUE
 configure = admin/config/system
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/system/system.install b/modules/system/system.install
index 42922102c3021d7b9e04906c456ecf8fa4298238..923be4e9cdb30d7304ab4660652dec33640048b1 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.install,v 1.461 2010/04/10 17:30:15 dries Exp $
+// $Id: system.install,v 1.469 2010/05/19 19:14:43 dries Exp $
 
 /**
  * @file
@@ -264,8 +264,10 @@ function system_requirements($phase) {
   // Test files directories.
   $directories = array(
     variable_get('file_public_path', conf_path() . '/files'),
-    variable_get('file_private_path', conf_path() . '/private/files'),
-    variable_get('file_temporary_path', conf_path() . '/private/temp'),
+    // By default no private files directory is configured. For private files
+    // to be secure the admin needs to provide a path outside the webroot.
+    variable_get('file_private_path', FALSE),
+    variable_get('file_temporary_path', sys_get_temp_dir()),
   );
   $requirements['file system'] = array(
     'title' => $t('File system'),
@@ -274,6 +276,9 @@ function system_requirements($phase) {
   $error = '';
   // For installer, create the directories if possible.
   foreach ($directories as $directory) {
+    if (!$directory) {
+      continue;
+    }
     if ($phase == 'install') {
       file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
     }
@@ -353,6 +358,62 @@ function system_requirements($phase) {
     $requirements['update access']['title'] = $t('Access to update.php');
   }
 
+  // Display an error if a newly introduced dependency in a module is not resolved.
+  if ($phase == 'update') {
+    $files = system_rebuild_module_data();
+    foreach ($files as $module => $file) {
+      // Ignore disabled modules.
+      if (!$file->status) {
+        continue;
+      }
+      // Check the module's PHP version.
+      $name = $file->info['name'];
+      $php = $file->info['php'];
+      if (version_compare($php, PHP_VERSION, '>')) {
+        $requirements['php']['description'] .= $t('@name requires at least PHP @version.', array('@name' => $name, '@version' => $php));
+        $requirements['php']['severity'] = REQUIREMENT_ERROR;
+      }
+      // Check the module's required modules.
+      foreach ($file->requires as $requirement) {
+        $required_module = $requirement['name'];
+        // Check if the module exists.
+        if (!isset($files[$required_module])) {
+          $requirements["$module-$required_module"] = array(
+            'title' => $t('Unresolved dependency'),
+            'description' => $t('@name requires this module.', array('@name' => $name)),
+            'value' => t('@required_name (Missing)', array('@required_name' => $required_module)),
+            'severity' => REQUIREMENT_ERROR,
+          );
+          continue;
+        }
+        // Check for an incompatible version.
+        $required_file = $files[$required_module];
+        $required_name = $required_file->info['name'];
+        $version = str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $required_file->info['version']);
+        $compatibility = drupal_check_incompatibility($requirement, $version);
+        if ($compatibility) {
+          $compatibility = rtrim(substr($compatibility, 2), ')');
+          $requirements["$module-$required_module"] = array(
+            'title' => $t('Unresolved dependency'),
+            'description' => $t('@name requires this module and version. Currently using @required_name version @version', array('@name' => $name, '@required_name' => $required_name, '@version' => $version)),
+            'value' => t('@required_name (Version @compatibility required)', array('@required_name' => $required_name, '@compatibility' => $compatibility)),
+            'severity' => REQUIREMENT_ERROR,
+          );
+          continue;
+        }
+        // Check for a disabled dependency.
+        if (!$required_file->status) {
+          $requirements["$module-$required_module"] = array(
+            'title' => $t('Unresolved dependency'),
+            'description' => $t('@name requires this module.', array('@name' => $name)),
+            'value' => $t('@required_name (Disabled)', array('@required_name' => $required_name)),
+            'severity' => REQUIREMENT_ERROR,
+          );
+        }
+      }
+    }
+  }
+
   // Test Unicode library
   include_once DRUPAL_ROOT . '/includes/unicode.inc';
   $requirements = array_merge($requirements, unicode_requirements());
@@ -414,7 +475,7 @@ function system_install() {
     ->execute();
 
   // Populate the cron key variable.
-  $cron_key = md5(mt_rand());
+  $cron_key = drupal_hash_base64(drupal_random_bytes(55));
   variable_set('cron_key', $cron_key);
 }
 
@@ -573,11 +634,6 @@ function system_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
-      'headers' => array(
-        'description' => 'Any custom HTTP headers to be added to cached data.',
-        'type' => 'text',
-        'not null' => FALSE,
-      ),
       'serialized' => array(
         'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
         'type' => 'int',
@@ -1513,107 +1569,9 @@ function system_schema() {
 // Updates for core.
 
 function system_update_last_removed() {
-  return 6047;
-}
-
-/**
- * @defgroup updates-6.x-extra Extra system updates for 6.x
- * @{
- */
-
-/**
-* Increase the size of the 'load_functions' and 'to_arg_functions' fields in table 'menu_router'.
-*/
-function system_update_6048() {
-  db_change_field('menu_router', 'load_functions', 'load_functions', array('type' => 'text', 'not null' => TRUE,));
-  db_change_field('menu_router', 'to_arg_functions', 'to_arg_functions', array('type' => 'text', 'not null' => TRUE,));
-}
-
-/**
- * Replace src index on the {url_alias} table with src, language.
- */
-function system_update_6049() {
-  db_drop_index('url_alias', 'src');
-  db_add_index('url_alias', 'src_language', array('src', 'language'));
+  return 6055;
 }
 
-/**
- * Clear any menu router blobs stored in the cache table.
- */
-function system_update_6050() {
-  cache_clear_all('router:', 'cache_menu', TRUE);
-}
-
-/**
- * Create a signature_format column.
- */
-function system_update_6051() {
-
-  if (!db_field_exists('users', 'signature_format')) {
-
-    // Set future text formats to FILTER_FORMAT_DEFAULT to ensure a safe default
-    // when incompatible modules insert into the users table. An actual format
-    // will be assigned when users save their signature.
-
-    $schema = array(
-      'type' => 'int',
-      'size' => 'small',
-      'not null' => TRUE,
-      'default' => FILTER_FORMAT_DEFAULT,
-      'description' => 'The {filter_formats}.format of the signature.',
-    );
-
-    db_add_field('users', 'signature_format', $schema);
-
-    // Set the format of existing signatures to the current default text format.
-    if ($current_default_filter = variable_get('filter_default_format', 0)) {
-      db_update('users')
-        ->fields(array(
-          'signature_format' => $current_default_filter,
-        ))
-        ->execute();
-    }
-
-    drupal_set_message("User signatures no longer inherit comment text formats. Each user's signature now has its own associated format that can be selected on the user's account page. Existing signatures have been set to your site's default text format.");
-  }
-}
-
-/**
- * Add a missing index on the {menu_router} table.
- */
-function system_update_6052() {
-  db_add_index('menu_router', 'tab_root_weight_title', array(array('tab_root', 64), 'weight', 'title'));
-}
-
-/**
- * Add a {system} index on type and name.
- */
-function system_update_6053() {
-  db_add_index('system', 'type_name', array(array('type', 12), 'name'));
-}
-
-/**
- * Improve indexes on the {url_alias} table.
- */
-function system_update_6055() {
-  db_drop_index('url_alias', 'src_language');
-  db_drop_unique_key('url_alias', 'dst_language');
-  db_add_index('url_alias', 'src_language_pid', array('src', 'language', 'pid'));
-  db_add_unique_key('url_alias', 'dst_language_pid', array('dst', 'language', 'pid'));
-}
-
-/**
- * Add semaphore table.
- */
-function system_update_6054() {
-  // Lives in update_fix_d7_requirements()
-}
-
-/**
- * @} End of "defgroup updates-6.x-extra"
- * The next series of updates should start at 7000.
- */
-
 /**
  * @defgroup updates-6.x-to-7.x System updates from 6.x to 7.x
  * @{
@@ -1650,7 +1608,7 @@ function system_update_7000() {
  * Generate a cron key and save it in the variables table.
  */
 function system_update_7001() {
-  variable_set('cron_key', md5(mt_rand()));
+  variable_set('cron_key', drupal_hash_base64(drupal_random_bytes(55)));
 }
 
 /**
@@ -2088,7 +2046,7 @@ function system_update_7032() {
  */
 function system_update_7033() {
   if (variable_get('cache') == 2) {
-    variable_set('cache', CACHE_NORMAL);
+    variable_set('cache', 1);
     return t('Aggressive caching was disabled and replaced with normal caching. Read the page caching section in default.settings.php for more information on how to enable similar functionality.');
   }
 }
@@ -2397,6 +2355,37 @@ function system_update_7052() {
   db_change_field('menu_router', 'file', 'include_file', array('type' => 'text', 'size' => 'medium'));
 }
 
+/**
+ * Upgrade standard blocks and menus.
+ */
+function system_update_7053() {
+  // Navigation block is now defined in system module.
+  db_update('block')
+    ->fields(array('module' => 'system'))
+    ->condition('module', 'user')
+    ->condition('delta', 'navigation')
+    ->execute();
+
+  // Create the same menus as in menu_install().
+  db_insert('menu_custom')
+    ->fields(array('menu_name' => 'user-menu', 'title' => 'User Menu', 'description' => "The <em>User</em> menu contains links related to the user's account, as well as the 'Log out' link."))
+    ->execute();
+
+  db_insert('menu_custom')
+    ->fields(array('menu_name' => 'management', 'title' => 'Management', 'description' => "The <em>Management</em> menu contains links for administrative tasks."))
+    ->execute();
+}
+
+/**
+ * Remove {cache_*}.headers columns.
+ */
+function system_update_7054() {
+  $cache_tables = array('cache', 'cache_filter', 'cache_form', 'cache_menu', 'cache_page', 'cache_path');
+  foreach ($cache_tables as $table) {
+    db_drop_field($table, 'headers');
+  }
+}
+
 /**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
diff --git a/modules/system/system.module b/modules/system/system.module
index 0819e63ef217248d240e48ab7ac4c537c2405566..0317810232cce12b92a7d6dc2aebd7be65e8b84d 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.module,v 1.923 2010/04/24 14:49:14 dries Exp $
+// $Id: system.module,v 1.933 2010/05/20 08:47:00 dries Exp $
 
 /**
  * @file
@@ -93,9 +93,9 @@ function system_help($path, $arg) {
       $output = '<p>' . t('Set and configure the default theme for your website.  Alternative <a href="@themes">themes</a> are available.', array('@themes' => 'http://drupal.org/project/themes')) . '</p>';
       return $output;
     case 'admin/appearance/settings/' . $arg[3]:
-      $reference = explode('.', $arg[3], 2);
-      $theme = array_pop($reference);
-      return '<p>' . t('These options control the display settings for the <code>%template</code> theme. When your site is displayed using this theme, these settings will be used.', array('%template' => $theme)) . '</p>';
+      $theme_list = list_themes();
+      $theme = $theme_list[$arg[3]];
+      return '<p>' . t('These options control the display settings for the %name theme. When your site is displayed using this theme, these settings will be used.', array('%name' => $theme->info['name'])) . '</p>';
     case 'admin/appearance/settings':
       return '<p>' . t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') . '</p>';
     case 'admin/modules':
@@ -217,7 +217,8 @@ function system_permission() {
       'title' => t('Administer themes'),
     ),
     'administer software updates' => array(
-      'title' => t('Run software updates'),
+      'title' => t('Administer software updates'),
+      'restrict access' => TRUE,
     ),
     'administer actions' => array(
       'title' => t('Administer actions'),
@@ -383,7 +384,6 @@ function system_element_info() {
   );
   $types['checkboxes'] = array(
     '#input' => TRUE,
-    '#tree' => TRUE,
     '#process' => array('form_process_checkboxes'),
     '#theme_wrappers' => array('checkboxes'),
     '#pre_render' => array('form_pre_render_conditional_form_element'),
@@ -957,7 +957,7 @@ function system_menu() {
   );
   $items['admin/config/system/site-information'] = array(
     'title' => 'Site information',
-    'description' => 'Change basic site name, e-mail address, slogan, default front page, number of posts per page, error pages and cron.',
+    'description' => 'Change site name, e-mail address, slogan, default front page, number of posts per page, error pages and cron.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_site_information_settings'),
     'access arguments' => array('administer site configuration'),
@@ -1008,7 +1008,7 @@ function system_menu() {
     'title' => 'Status report',
     'description' => "Get a status report about your site's operation and any detected problems.",
     'page callback' => 'system_status',
-    'weight' => 10,
+    'weight' => -60,
     'access arguments' => array('administer site configuration'),
     'file' => 'system.admin.inc',
   );
@@ -1517,24 +1517,30 @@ function system_library() {
  * Implements hook_stream_wrappers().
  */
 function system_stream_wrappers() {
-  return array(
+  $wrappers = array(
     'public' => array(
       'name' => t('Public files'),
       'class' => 'DrupalPublicStreamWrapper',
       'description' => t('Public local files served by the webserver.'),
     ),
-    'private' => array(
-      'name' => t('Private files'),
-      'class' => 'DrupalPrivateStreamWrapper',
-      'description' => t('Private local files served by Drupal.'),
-    ),
     'temporary' => array(
       'name' => t('Temporary files'),
       'class' => 'DrupalTemporaryStreamWrapper',
       'description' => t('Temporary local files for upload and previews.'),
       'type' => STREAM_WRAPPERS_HIDDEN,
-    )
+    ),
   );
+
+  // Only register the private file stream wrapper if a file path has been set.
+  if (variable_get('file_private_path', FALSE)) {
+    $wrappers['private'] = array(
+      'name' => t('Private files'),
+      'class' => 'DrupalPrivateStreamWrapper',
+      'description' => t('Private local files served by Drupal.'),
+    );
+  }
+
+  return $wrappers;
 }
 
 /**
@@ -2046,6 +2052,9 @@ function system_admin_menu_block($item) {
  */
 function system_check_directory($form_element) {
   $directory = $form_element['#value'];
+  if (strlen($directory) == 0) {
+    return $form_element;
+  }
 
   if (!is_dir($directory) && !drupal_mkdir($directory, NULL, TRUE)) {
     // If the directory does not exists and cannot be created.
@@ -2058,7 +2067,7 @@ function system_check_directory($form_element) {
     form_set_error($form_element['#parents'][0], t('The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory)));
     watchdog('file system', 'The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory), WATCHDOG_ERROR);
   }
-  else {
+  elseif (is_dir($directory)) {
     if ($form_element['#name'] == 'file_public_path') {
       // Create public .htaccess file.
       file_create_htaccess($directory, FALSE);
@@ -2173,6 +2182,11 @@ function system_update_files_database(&$files, $type) {
     }
   }
   $query->execute();
+
+  // If any module or theme was moved to a new location, we need to reset the
+  // system_list() cache or we will continue to load the old copy, look for
+  // schema updates in the wrong place, etc.
+  system_list_reset();
 }
 
 /**
@@ -2542,7 +2556,7 @@ function system_system_info_alter(&$info, $file, $type) {
  *   A string that is the region name.
  */
 function system_default_region($theme) {
-  $regions = array_keys(system_region_list($theme));
+  $regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
   return isset($regions[0]) ? $regions[0] : '';
 }
 
@@ -2635,41 +2649,46 @@ function _system_sort_requirements($a, $b) {
 }
 
 /**
- * Output a confirmation form
+ * Generates a form array for a confirmation form.
  *
- * This function returns a complete form for confirming an action. A link is
- * offered to go back to the item that is being changed in case the user changes
- * his/her mind.
+ * This function returns a complete form array for confirming an action. The
+ * form contains a confirm button as well as a cancellation link that allows a
+ * user to abort the action.
  *
- * If the submit handler for this form is invoked, the user successfully
- * confirmed the action. You should never directly inspect $_POST to see if an
- * action was confirmed.
+ * If the submit handler for a form that implements confirm_form() is invoked,
+ * the user successfully confirmed the action. You should never directly
+ * inspect $_POST to see if an action was confirmed.
  *
  * Note - if the parameters $question, $description, $yes, or $no could contain
  * any user input (such as node titles or taxonomy terms), it is the
  * responsibility of the code calling confirm_form() to sanitize them first with
  * a function like check_plain() or filter_xss().
  *
- * @ingroup forms
  * @param $form
- *   Additional elements to inject into the form, for example hidden elements.
+ *   Additional elements to add to the form; for example, hidden elements.
  * @param $question
  *   The question to ask the user (e.g. "Are you sure you want to delete the
- *   block <em>foo</em>?").
+ *   block <em>foo</em>?"). The page title will be set to this value.
  * @param $path
- *   The page to go to if the user denies the action.
- *   Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'.
+ *   The page to go to if the user cancels the action. This can be either:
+ *   - A string containing a Drupal path.
+ *   - An associative array with a 'path' key. Additional array values are
+ *     passed as the $options parameter to l().
+ *   If the 'destination' query parameter is set in the URL when viewing a
+ *   confirmation form, that value will be used instead of $path.
  * @param $description
- *   Additional text to display (defaults to "This action cannot be undone.").
+ *   Additional text to display. Defaults to t('This action cannot be undone.').
  * @param $yes
- *   A caption for the button which confirms the action (e.g. "Delete",
- *   "Replace", ...).
+ *   A caption for the button that confirms the action (e.g. "Delete",
+ *   "Replace", ...). Defaults to t('Confirm').
  * @param $no
- *   A caption for the link which denies the action (e.g. "Cancel").
+ *   A caption for the link which cancels the action (e.g. "Cancel"). Defaults
+ *   to t('Cancel').
  * @param $name
  *   The internal name used to refer to the confirmation item.
+ *
  * @return
- *   The form.
+ *   The form array.
  */
 function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
   $description = isset($description) ? $description : t('This action cannot be undone.');
@@ -2918,9 +2937,9 @@ function system_send_email_action_form($context) {
 function system_send_email_action_validate($form, $form_state) {
   $form_values = $form_state['values'];
   // Validate the configuration form.
-  if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != '%author') {
+  if (!valid_email_address($form_values['recipient']) && strpos($form_values['recipient'], ':mail') === FALSE) {
     // We want the literal %author placeholder to be emphasized in the error message.
-    form_set_error('recipient', t('Enter a valid email address or %author.', array('%author' => '%author')));
+    form_set_error('recipient', t('Enter a valid email address or use a token e-mail address such as %author.', array('%author' => '[node:author:mail]')));
   }
 }
 
diff --git a/modules/system/system.updater.inc b/modules/system/system.updater.inc
index 4e5b3f227219bac963c5c3d143ee5c5bea952941..60b8be89078f8da7a52d5ffcdc72905f84518060 100644
--- a/modules/system/system.updater.inc
+++ b/modules/system/system.updater.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.updater.inc,v 1.7 2010/04/10 09:49:49 dries Exp $
+// $Id: system.updater.inc,v 1.8 2010/05/18 18:11:13 dries Exp $
 
 /**
  * @file
@@ -53,8 +53,8 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
    * Return available database schema updates one a new version is installed.
    */
   public function getSchemaUpdates() {
-    require_once './includes/install.inc';
-    require_once './includes/update.inc';
+    require_once DRUPAL_ROOT . '/includes/install.inc';
+    require_once DRUPAL_ROOT . '/includes/update.inc';
 
     if (_update_get_project_type($project) != 'module') {
       return array();
diff --git a/modules/system/theme.api.php b/modules/system/theme.api.php
index 14b9ffe73d5d846aef6087545afc097a742b257d..9943e858b95e9c357502dee023474bc32ed20626 100644
--- a/modules/system/theme.api.php
+++ b/modules/system/theme.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.api.php,v 1.2 2010/04/24 07:11:07 dries Exp $
+// $Id: theme.api.php,v 1.3 2010/04/28 20:00:34 dries Exp $
 
 /**
  * @defgroup themeable Default theme implementations
@@ -94,6 +94,108 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) {
   );
 }
 
+/**
+ * Preprocess theme variables.
+ *
+ * This hook allows modules to preprocess theme variables for theme templates.
+ * It is called for all invocations of theme(), to allow modules to add to
+ * or override variables for all theme hooks.
+ *
+ * @param $variables
+ *   The variables array (modify in place).
+ * @param $hook
+ *   The name of the theme hook.
+ */
+function hook_preprocess(&$variables, $hook) {
+ static $hooks;
+
+  // Add contextual links to the variables, if the user has permission.
+
+  if (!user_access('access contextual links')) {
+    return;
+  }
+
+  if (!isset($hooks)) {
+    $hooks = theme_get_registry();
+  }
+
+  // Determine the primary theme function argument.
+  if (isset($hooks[$hook]['variables'])) {
+    $keys = array_keys($hooks[$hook]['variables']);
+    $key = $keys[0];
+  }
+  else {
+    $key = $hooks[$hook]['render element'];
+  }
+
+  if (isset($variables[$key])) {
+    $element = $variables[$key];
+  }
+
+  if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {
+    $variables['title_suffix']['contextual_links'] = contextual_links_view($element);
+    if (!empty($variables['title_suffix']['contextual_links'])) {
+      $variables['classes_array'][] = 'contextual-links-region';
+    }
+  }
+}
+
+/**
+ * Preprocess theme variables for a specific theme hook.
+ *
+ * This hook allows modules to preprocess theme variables for a specific theme
+ * hook. It should only be used if a module needs to override or add to the
+ * theme preprocessing for a theme hook it didn't define.
+ *
+ * @param $variables
+ *   The variables array (modify in place).
+ */
+function hook_preprocess_HOOK(&$variables) {
+  // This example is from rdf_preprocess_image(). It adds an RDF attribute
+  // to the image hook's variables.
+  $variables['attributes']['typeof'] = array('foaf:Image');
+}
+
+/**
+ * Process theme variables.
+ *
+ * This hook allows modules to process theme variables for theme templates.
+ * It is called for all invocations of theme(), to allow modules to add to
+ * or override variables for all theme hooks.
+ *
+ * @param $variables
+ *   The variables array (modify in place).
+ * @param $hook
+ *   The name of the theme hook.
+ */
+function hook_process(&$variables, $hook) {
+  // Wraps variables in RDF wrappers.
+  if (!empty($variables['rdf_template_variable_attributes_array'])) {
+    foreach ($variables['rdf_template_variable_attributes_array'] as $variable_name => $attributes) {
+      $context = array(
+        'hook' => $hook,
+        'variable_name' => $variable_name,
+        'variables' => $variables,
+      );
+      $variables[$variable_name] = theme('rdf_template_variable_wrapper', array('content' => $variables[$variable_name], 'attributes' => $attributes, 'context' => $context));
+    }
+  }
+}
+
+/**
+ * Process theme variables for a specific theme hook.
+ *
+ * This hook allows modules to process theme variables for a specific theme
+ * hook. It should only be used if a module needs to override or add to the
+ * theme processing for a theme hook it didn't define.
+ *
+ * @param $variables
+ *   The variables array (modify in place).
+ */
+function hook_process_HOOK(&$variables) {
+  $variables['classes'] .= ' my_added_class';
+}
+
 /**
  * Respond to themes being enabled.
  *
diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc
index 2a218661d0be884512831dd0d7b5a119383ba476..bba7f8593604a799353032ae9f3e47da5b8d15ef 100644
--- a/modules/taxonomy/taxonomy.admin.inc
+++ b/modules/taxonomy/taxonomy.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.admin.inc,v 1.102 2010/04/24 14:49:14 dries Exp $
+// $Id: taxonomy.admin.inc,v 1.105 2010/05/13 07:53:02 dries Exp $
 
 /**
  * @file
@@ -101,7 +101,7 @@ function theme_taxonomy_overview_vocabularies($variables) {
  */
 function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) {
   if (!is_array($edit)) {
-    $edit = (array)$edit;
+    $edit = (array) $edit;
   }
   $edit += array(
     'name' => '',
@@ -121,7 +121,7 @@ function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) {
     '#default_value' => $edit['name'],
     '#maxlength' => 255,
     '#required' => TRUE,
-    '#field_suffix' => ' <small id="edit-name-suffix">&nbsp</small>',
+    '#field_suffix' => ' <small id="edit-name-suffix">&nbsp;</small>',
   );
   $js_settings = array(
     'type' => 'setting',
@@ -352,7 +352,7 @@ function taxonomy_overview_terms($form, &$form_state, $vocabulary) {
   // Build the actual form.
   foreach ($current_page as $key => $term) {
     // Save the term for the current page so we don't have to load it a second time.
-    $form[$key]['#term'] = (array)$term;
+    $form[$key]['#term'] = (array) $term;
     if (isset($term->parents)) {
       $form[$key]['#term']['parent'] = $term->parent = $term->parents[0];
       unset($form[$key]['#term']['parents'], $term->parents);
@@ -444,7 +444,7 @@ function taxonomy_overview_terms_submit($form, &$form_state) {
 
   // Build a list of all terms that need to be updated on previous pages.
   $weight = 0;
-  $term = (array)$tree[0];
+  $term = (array) $tree[0];
   while ($term['tid'] != $form['#first_tid']) {
     if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
       $term['parent'] = $term['parents'][0];
@@ -453,7 +453,7 @@ function taxonomy_overview_terms_submit($form, &$form_state) {
     }
     $weight++;
     $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
-    $term = (array)$tree[$weight];
+    $term = (array) $tree[$weight];
   }
 
   // Renumber the current page weights and assign any new parents.
@@ -486,7 +486,7 @@ function taxonomy_overview_terms_submit($form, &$form_state) {
 
   // Build a list of all terms that need to be updated on following pages.
   for ($weight; $weight < count($tree); $weight++) {
-    $term = (array)$tree[$weight];
+    $term = (array) $tree[$weight];
     if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
       $term['parent'] = $term['parents'][0];
       $term['weight'] = $weight;
@@ -497,7 +497,7 @@ function taxonomy_overview_terms_submit($form, &$form_state) {
 
   // Save all updated terms.
   foreach ($changed_terms as $changed) {
-    $term = (object)$changed;
+    $term = (object) $changed;
     // Update term_hierachy and term_data directly since we don't have a
     // fully populated term object to save.
     db_update('taxonomy_term_hierarchy')
@@ -619,7 +619,7 @@ function theme_taxonomy_overview_terms($variables) {
 function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary = NULL) {
   if (!isset($vocabulary) && is_object($edit)) {
     $vocabulary = taxonomy_vocabulary_load($edit->vid);
-    $edit = (array)$edit;
+    $edit = (array) $edit;
   }
   $edit += array(
     'name' => '',
@@ -837,9 +837,15 @@ function taxonomy_form_term_submit($form, &$form_state) {
  */
 function taxonomy_form_term_submit_builder($form, &$form_state) {
   $term = (object) $form_state['values'];
+
+  // Convert text_format field into values expected by taxonomy_term_save().
+  $description = $form_state['values']['description'];
+  $term->description = $description['value'];
+  $term->format = $description['format'];
+
   field_attach_submit('taxonomy_term', $term, $form, $form_state);
 
-  $form_state['term'] = (array)$term;
+  $form_state['term'] = (array) $term;
   $form_state['rebuild'] = TRUE;
 
   return $term;
diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php
index b0b2437fe379542be5c9a8205131a42b639b48f1..11f45d59b8e1e12c7c847dc6c15cbff2c3cc0857 100644
--- a/modules/taxonomy/taxonomy.api.php
+++ b/modules/taxonomy/taxonomy.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.api.php,v 1.8 2009/12/04 15:54:37 dries Exp $
+// $Id: taxonomy.api.php,v 1.9 2010/05/14 04:41:54 webchick Exp $
 
 /**
  * @file
@@ -94,6 +94,19 @@ function hook_taxonomy_term_load($terms) {
   }
 }
 
+/**
+ * Act on taxonomy terms before they are saved.
+ *
+ * Modules implementing this hook can act on the term object before it is
+ * inserted or updated.
+ *
+ * @param $term
+ *   A term object.
+ */
+function hook_taxonomy_term_presave($term) {
+  $term->foo = 'bar';
+}
+
 /**
  * Act on taxonomy terms when inserted.
  *
diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info
index 6941518b5a8e50bba27b22c837cbb452e7604c29..4c44580700089116a895acf659d9ba691c646cba 100644
--- a/modules/taxonomy/taxonomy.info
+++ b/modules/taxonomy/taxonomy.info
@@ -12,8 +12,8 @@ files[] = taxonomy.test
 files[] = taxonomy.tokens.inc
 configure = admin/structure/taxonomy
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install
index 62a2bc34e46ebc447248209cc25ec7d22f94b548..31a1d5514aa2323afcca0ff9d54c61f007f2caf1 100644
--- a/modules/taxonomy/taxonomy.install
+++ b/modules/taxonomy/taxonomy.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.install,v 1.41 2010/04/20 07:47:55 webchick Exp $
+// $Id: taxonomy.install,v 1.42 2010/05/06 06:08:28 webchick Exp $
 
 /**
  * @file
@@ -260,7 +260,10 @@ function taxonomy_update_7002() {
 
   db_add_field('taxonomy_vocabulary', 'machine_name', $field);
 
-  foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
+  // Do a direct query here, rather than calling taxonomy_get_vocabularies(),
+  // in case Taxonomy module is disabled.
+  $vids = db_query('SELECT vid FROM {taxonomy_vocabulary}')->fetchCol();
+  foreach ($vids as $vid) {
     $machine_name = 'vocabulary_' . $vid;
     db_update('taxonomy_vocabulary')
       ->fields(array('machine_name' => $machine_name))
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index d16d2aa142ce764bb981151f402a5b1d2ff38007..7762e7e99304e5d4d384f38f7a8760a4a81ec092 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.module,v 1.587 2010/04/23 07:54:44 webchick Exp $
+// $Id: taxonomy.module,v 1.591 2010/05/21 20:27:45 dries Exp $
 
 /**
  * @file
@@ -143,9 +143,9 @@ function taxonomy_term_uri($term) {
  */
 function taxonomy_field_extra_fields() {
   $return = array();
-
-  foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
-    $return['taxonomy_term'][$machine_name] = array(
+  $info = entity_get_info('taxonomy_term');
+  foreach (array_keys($info['bundles']) as $bundle) {
+    $return['taxonomy_term'][$bundle] = array(
       'name' => array(
         'label' => t('Name'),
         'description' => t('Term name textfield'),
@@ -432,7 +432,7 @@ function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
   foreach ($tree as $term) {
     // Update the changed term with the new parent value before comparison.
     if ($term->tid == $changed_term['tid']) {
-      $term = (object)$changed_term;
+      $term = (object) $changed_term;
       $term->parents = $term->parent;
     }
     // Check this term's parent count.
@@ -469,6 +469,7 @@ function taxonomy_term_save($term) {
   }
 
   field_attach_presave('taxonomy_term', $term);
+  module_invoke_all('taxonomy_term_presave', $term);
 
   if (empty($term->tid)) {
     $status = drupal_write_record('taxonomy_term_data', $term);
@@ -565,7 +566,6 @@ function taxonomy_term_delete($tid) {
   return SAVED_DELETED;
 }
 
-
 /**
  * Generate an array for rendering the given term.
  *
@@ -615,7 +615,7 @@ function template_preprocess_taxonomy_term(&$variables) {
   $variables['page']      = taxonomy_term_is_page($term);
 
   // Flatten the term object's member fields.
-  $variables = array_merge((array)$term, $variables);
+  $variables = array_merge((array) $term, $variables);
 
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
@@ -1018,13 +1018,15 @@ function taxonomy_implode_tags($tags, $vid = NULL) {
   foreach ($tags as $tag) {
     // Extract terms belonging to the vocabulary in question.
     if (is_null($vid) || $tag->vid == $vid) {
+      // Make sure we have a completed loaded taxonomy term.
+      if (isset($tag->name)) {
+        // Commas and quotes in tag names are special cases, so encode 'em.
+        if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
+          $tag->name = '"' . str_replace('"', '""', $tag->name) . '"';
+        }
 
-      // Commas and quotes in tag names are special cases, so encode 'em.
-      if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
-        $tag->name = '"' . str_replace('"', '""', $tag->name) . '"';
+        $typed_tags[] = $tag->name;
       }
-
-      $typed_tags[] = $tag->name;
     }
   }
   return implode(', ', $typed_tags);
@@ -1273,6 +1275,8 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field,
 
     // Iterate through the fieldable entities again to attach the loaded term data.
     foreach ($entities as $id => $entity) {
+      $rekey = FALSE;
+
       foreach ($items[$id] as $delta => $item) {
         // Check whether the taxonomy term field instance value could be loaded.
         if (isset($terms[$item['tid']])) {
@@ -1282,8 +1286,14 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field,
         // Otherwise, unset the instance value, since the term does not exist.
         else {
           unset($items[$id][$delta]);
+          $rekey = TRUE;
         }
       }
+
+      if ($rekey) {
+        // Rekey the items array.
+        $items[$id] = array_values($items[$id]);
+      }
     }
   }
 }
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index ac8ef0d1bcc6b5bae2452180497d6cde25df19c5..cbd659ee011194c91c7c6409920b595e20031786 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.test,v 1.77 2010/04/20 09:48:06 webchick Exp $
+// $Id: taxonomy.test,v 1.78 2010/04/30 12:52:10 dries Exp $
 
 /**
  * @file
@@ -422,7 +422,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
   /**
    * Test term creation with a free-tagging vocabulary from the node form.
    */
-  function testNodeTermCreation() {
+  function testNodeTermCreationAndDeletion() {
     // Enable tags in the vocabulary.
     $instance = $this->instance;
     $instance['widget'] = array('type' => 'taxonomy_autocomplete');
@@ -446,6 +446,23 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
     foreach ($terms as $term) {
       $this->assertText($term, t('The term was saved and appears on the node page'));
     }
+
+    // Get the created terms.
+    list($term1, $term2, $term3) = taxonomy_get_tree($this->vocabulary->vid);
+
+    // Delete one term.
+    $this->drupalPost('taxonomy/term/' . $term1->tid . '/edit', array(), t('Delete'));
+    $this->drupalPost(NULL, NULL, t('Delete'));
+    $term_names = array($term2->name, $term3->name);
+
+    // Get the node.
+    $node = $this->drupalGetNodeByTitle($edit["title"]);
+    $this->drupalGet('node/' . $node->nid);
+
+    foreach ($term_names as $term_name) {
+      $this->assertText($term_name, t('The term %name appears on the node page after one term %deleted was deleted', array('%name' => $term_name, '%deleted' => $term1->name)));
+    }
+    $this->assertNoText($term1->name, t('The deleted term %name does not appear on the node page.', array('%name' => $term1->name)));
   }
 
   /**
diff --git a/modules/toolbar/toolbar.css b/modules/toolbar/toolbar.css
index 8ccfef2d7ad53b24c15fdbdcf9d14728627c0e9b..f276c59c0c5752341ed5028f6343750d7888aa77 100644
--- a/modules/toolbar/toolbar.css
+++ b/modules/toolbar/toolbar.css
@@ -1,12 +1,6 @@
-/* $Id: toolbar.css,v 1.20 2010/04/04 17:11:20 dries Exp $ */
+/* $Id: toolbar.css,v 1.21 2010/05/14 07:45:54 dries Exp $ */
 
-body.toolbar {
-  padding-top: 2.2em;
-}
 
-body.toolbar-drawer {
-  padding-top: 5.3em;
-}
 
 /**
  * Aggressive resets so we can achieve a consistent look in hostile CSS
@@ -32,10 +26,8 @@ body.toolbar-drawer {
   font: normal 0.9em "Lucida Grande", Verdana, sans-serif;
   background: #666;
   color: #ccc;
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
+}
+.displace-processed #toolbar {
   margin: 0 -20px;
   padding: 0 20px;
   z-index: 600;
@@ -45,6 +37,14 @@ body.toolbar-drawer {
   filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
   -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
 }
+.displace-unsupported #toolbar {
+  margin: 0;
+  padding-right: 0;
+  left: -20px;
+  right: 0;
+  width: 100%;
+}
+
 
 #toolbar div.collapsed {
   display: none;
@@ -132,18 +132,3 @@ body.toolbar-drawer {
   position: relative;
   padding: 0 10px;
 }
-
-/**
- * IE 6 Fix.
- *
- * IE 6 shows elements with position:fixed as position:static so we replace
- * it with position:absolute; toolbar needs it's z-index to stay above overlay.
- */
-* html #toolbar {
-  position: absolute;
-  margin: 0;
-  padding-right: 0;
-  left: -20px;
-  right: 0;
-  width: 100%;
-}
diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info
index b3560833ba61c26e3ea8769374eb6c6e4a8ea873..a14c5153668b90c050c457c28041458c0e13014e 100644
--- a/modules/toolbar/toolbar.info
+++ b/modules/toolbar/toolbar.info
@@ -6,8 +6,8 @@ package = Core
 version = VERSION
 files[] = toolbar.module
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/toolbar/toolbar.js b/modules/toolbar/toolbar.js
index 09fd86537794714968e28c9611cc5925e04861ea..5fb9ad6c1a10fabac16f43808dfc87e19a05b1d5 100644
--- a/modules/toolbar/toolbar.js
+++ b/modules/toolbar/toolbar.js
@@ -1,4 +1,4 @@
-// $Id: toolbar.js,v 1.16 2010/04/04 20:27:08 dries Exp $
+// $Id: toolbar.js,v 1.17 2010/05/14 07:45:54 dries Exp $
 (function ($) {
 
 Drupal.toolbar = Drupal.toolbar || {};
@@ -15,9 +15,8 @@ Drupal.behaviors.toolbar = {
     // Toggling toolbar drawer.
     $('#toolbar a.toggle', context).once('toolbar-toggle').click(function(e) {
       Drupal.toolbar.toggle();
-      // As the toolbar is an overlay displaced region, overlay should be
-      // notified of it's height change to adapt its position.
-      $(window).triggerHandler('resize.overlay-event');
+      // Allow resize event handlers to recalculate sizes/positions.
+      $(window).triggerHandler('resize');
       return false;
     });
   }
@@ -49,7 +48,6 @@ Drupal.toolbar.collapse = function() {
     .removeClass('toggle-active')
     .attr('title',  toggle_text)
     .html(toggle_text);
-  $('body').removeClass('toolbar-drawer').css('paddingTop', Drupal.toolbar.height());
   $.cookie(
     'Drupal.toolbar.collapsed',
     1,
@@ -71,7 +69,6 @@ Drupal.toolbar.expand = function() {
     .addClass('toggle-active')
     .attr('title',  toggle_text)
     .html(toggle_text);
-  $('body').addClass('toolbar-drawer').css('paddingTop', Drupal.toolbar.height());
   $.cookie(
     'Drupal.toolbar.collapsed',
     0,
@@ -95,14 +92,4 @@ Drupal.toolbar.toggle = function() {
   }
 };
 
-Drupal.toolbar.height = function() {
-  var height = $('#toolbar').outerHeight();
-  // In IE, Shadow filter adds some extra height, so we need to remove it from
-  // the returned height.
-  if ($('#toolbar').css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) {
-    height -= $('#toolbar').get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength;
-  }
-  return height;
-};
-
 })(jQuery);
diff --git a/modules/toolbar/toolbar.module b/modules/toolbar/toolbar.module
index 588eac8fd2a7c5c278d3b4f7d52a463454f6ccc8..3f978a539e36a36d2b88b0c4747d005071aadb47 100644
--- a/modules/toolbar/toolbar.module
+++ b/modules/toolbar/toolbar.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: toolbar.module,v 1.36 2010/04/04 17:11:20 dries Exp $
+// $Id: toolbar.module,v 1.39 2010/05/14 16:52:27 dries Exp $
 
 /**
  * @file
@@ -153,12 +153,15 @@ function toolbar_preprocess_html(&$vars) {
 /**
  * Implements hook_system_info_alter().
  *
- * If the overlay module is enabled, indicate that the 'page_top' region (in
- * which the toolbar will be displayed) is one of the overlay supplemental
- * regions that should be refreshed whenever its content is updated.
+ * Indicate that the 'page_top' region (in which the toolbar will be displayed)
+ * is an overlay supplemental region that should be refreshed whenever its
+ * content is updated.
+ *
+ * This information is provided for any module that might need to use it, not
+ * just the core Overlay module.
  */
 function toolbar_system_info_alter(&$info, $file, $type) {
-  if (module_exists('overlay') && $type == 'theme') {
+  if ($type == 'theme') {
     $info['overlay_supplemental_regions'][] = 'page_top';
   }
 }
@@ -174,12 +177,9 @@ function toolbar_view() {
     '#theme' => 'toolbar',
     '#attached'=> array(
       'js' => array(
-        $module_path . '/toolbar.js',
+        array('data' => 'misc/displace.js', 'weight' => JS_LIBRARY - 1),
         array('data' => 'misc/jquery.cookie.js', 'weight' => JS_LIBRARY + 2),
-        array(
-          'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'),
-          'type' => 'setting'
-        ),
+        $module_path . '/toolbar.js',
       ),
       'css' => array(
         $module_path . '/toolbar.css',
@@ -282,14 +282,13 @@ function toolbar_get_menu_tree() {
 /**
  * Generate a links array from a menu tree array.
  *
- * Based on menu_navigation_links(). Adds in path based IDs, icon placeholders
- * and overlay classes for the links.
+ * Based on menu_navigation_links(). Adds path based IDs and icon placeholders
+ * to the links.
  */
 function toolbar_menu_navigation_links($tree) {
   $links = array();
   foreach ($tree as $item) {
     if (!$item['link']['hidden'] && $item['link']['access']) {
-      $class = '';
       // Make sure we have a path specific ID in place, so we can attach icons
       // and behaviors to the items.
       $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['href']);
@@ -298,8 +297,8 @@ function toolbar_menu_navigation_links($tree) {
       $link['href'] = $item['link']['href'];
       // Add icon placeholder.
       $link['title'] = '<span class="icon"></span>' . $item['link']['title'];
-      // Add admin link ID and to-overlay class for the overlay.
-      $link['attributes'] = array('id' => 'toolbar-link-' . $id, 'class' => array('to-overlay'));
+      // Add admin link ID.
+      $link['attributes'] = array('id' => 'toolbar-link-' . $id);
       if (!empty($item['link']['description'])) {
         $link['title'] .= ' <span class="element-invisible">(' . $item['link']['description'] . ')</span>';
         $link['attributes']['title'] = $item['link']['description'];
diff --git a/modules/toolbar/toolbar.tpl.php b/modules/toolbar/toolbar.tpl.php
index 951a5f00b83b2add38f54a7f3128dfeec967c6ab..8f96bbd657784d430afb8b939ffa8196699fcaf0 100644
--- a/modules/toolbar/toolbar.tpl.php
+++ b/modules/toolbar/toolbar.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: toolbar.tpl.php,v 1.9 2010/02/10 10:54:12 dries Exp $
+// $Id: toolbar.tpl.php,v 1.10 2010/05/14 07:45:54 dries Exp $
 
 /**
  * @file
@@ -22,7 +22,7 @@
  * @see template_preprocess_toolbar()
  */
 ?>
-<div id="toolbar" class="<?php print $classes; ?> clearfix">
+<div id="toolbar" class="<?php print $classes; ?> displace-top clearfix">
   <div class="toolbar-menu clearfix">
     <?php print render($toolbar['toolbar_home']); ?>
     <?php print render($toolbar['toolbar_user']); ?>
diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info
index 76bea25c34809bb753602d9b3646bb50581b1e30..2e11e659f6bd795d2acd8587835e28f0aeb837fe 100644
--- a/modules/tracker/tracker.info
+++ b/modules/tracker/tracker.info
@@ -9,8 +9,8 @@ files[] = tracker.module
 files[] = tracker.pages.inc
 files[] = tracker.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/translation/translation.info b/modules/translation/translation.info
index d52de0610930ca168e7e3ff451c6562459b334ba..706d1e7354cd2c73fc3a716dd366a235101bf3ce 100644
--- a/modules/translation/translation.info
+++ b/modules/translation/translation.info
@@ -9,8 +9,8 @@ files[] = translation.module
 files[] = translation.pages.inc
 files[] = translation.test
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info
index 5c870488e1f6508f4fe18074e30d589061b13c3a..dde61ad2b950a61da43dc00cf7aaeceadbef3d95 100644
--- a/modules/trigger/tests/trigger_test.info
+++ b/modules/trigger/tests/trigger_test.info
@@ -6,8 +6,8 @@ core = 7.x
 files[] = trigger_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/trigger/trigger.admin.inc b/modules/trigger/trigger.admin.inc
index fa87afc12cd657863219ef8698076a2f897cb3bb..c9c02115a39f7557954c3d23783aae72d4052604 100644
--- a/modules/trigger/trigger.admin.inc
+++ b/modules/trigger/trigger.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: trigger.admin.inc,v 1.25 2010/04/21 08:23:42 webchick Exp $
+// $Id: trigger.admin.inc,v 1.26 2010/05/01 08:12:23 dries Exp $
 
 /**
  * @file
@@ -155,10 +155,11 @@ function trigger_assign_form($form, $form_state, $module, $hook, $label) {
   foreach ($actions as $aid => $info) {
     // If action is defined unassign it, otherwise offer to delete all orphaned
     // actions.
-    if (actions_function_lookup(md5($aid))) {
+    $hash = drupal_hash_base64($aid, TRUE);
+    if (actions_function_lookup($hash)) {
       $form[$hook]['assigned']['#value'][$aid] = array(
         'label' => $info['label'],
-        'link' => l(t('unassign'), "admin/structure/trigger/unassign/$module/$hook/" . md5($aid)),
+        'link' => l(t('unassign'), "admin/structure/trigger/unassign/$module/$hook/$hash"),
       );
     }
     else {
diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info
index da4cada482d17b255d5101be3bc47a83521a2363..19bc329a25a4e3ac84175a5f16cae2c4f2efec34 100644
--- a/modules/trigger/trigger.info
+++ b/modules/trigger/trigger.info
@@ -10,8 +10,8 @@ files[] = trigger.install
 files[] = trigger.test
 configure = admin/structure/trigger
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test
index 408eb2b3e75036ed3c0d176f2d86bdbd083f652e..d9af9c363d0ce19852d9733edf9f1e9ce94366be 100644
--- a/modules/trigger/trigger.test
+++ b/modules/trigger/trigger.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: trigger.test,v 1.31 2010/04/10 10:49:15 dries Exp $
+// $Id: trigger.test,v 1.32 2010/05/01 08:12:23 dries Exp $
 
 /**
  * Class with common helper methods.
@@ -19,7 +19,7 @@ class TriggerWebTestCase extends DrupalWebTestCase {
    */
   protected function configureAdvancedAction($action, $edit) {
     // Create an advanced action.
-    $hash = md5($action);
+    $hash = drupal_hash_base64($action);
     $this->drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
     $this->assertText(t('The action has been successfully saved.'));
 
@@ -58,7 +58,7 @@ class TriggerContentTestCase extends TriggerWebTestCase {
     $test_user = $this->drupalCreateUser(array('administer actions'));
     $web_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer nodes'));
     foreach ($content_actions as $action) {
-      $hash = md5($action);
+      $hash = drupal_hash_base64($action);
       $info = $this->actionInfo($action);
 
       // Assign an action to a trigger, then pull the trigger, and make sure
@@ -112,7 +112,7 @@ class TriggerContentTestCase extends TriggerWebTestCase {
     }
 
     $action_id = 'trigger_test_generic_any_action';
-    $hash = md5($action_id);
+    $hash = drupal_hash_base64($action_id);
     $edit = array('aid' => $hash);
     $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-update-assign-form');
 
@@ -200,7 +200,7 @@ class TriggerCronTestCase extends TriggerWebTestCase {
     $this->drupalLogin($test_user);
 
     // Assign a non-configurable action to the cron run trigger.
-    $edit = array('aid' => md5('trigger_test_system_cron_action'));
+    $edit = array('aid' => drupal_hash_base64('trigger_test_system_cron_action'));
     $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
 
     // Assign a configurable action to the cron trigger.
@@ -212,7 +212,7 @@ class TriggerCronTestCase extends TriggerWebTestCase {
     $aid = $this->configureAdvancedAction('trigger_test_system_cron_conf_action', $edit);
     // $aid is likely 3 but if we add more uses for the sequences table in
     // core it might break, so it is easier to get the value from the database.
-    $edit = array('aid' => md5($aid));
+    $edit = array('aid' => drupal_hash_base64($aid));
     $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
 
     // Add a second configurable action to the cron trigger.
@@ -222,7 +222,7 @@ class TriggerCronTestCase extends TriggerWebTestCase {
       'subject' => $action_label,
     );
     $aid = $this->configureAdvancedAction('trigger_test_system_cron_conf_action', $edit);
-    $edit = array('aid' => md5($aid));
+    $edit = array('aid' => drupal_hash_base64($aid));
     $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
 
     // Force a cron run.
@@ -265,7 +265,7 @@ class TriggerOtherTestCase extends TriggerWebTestCase {
     $test_user = $this->drupalCreateUser(array('administer actions'));
     $this->drupalLogin($test_user);
     $action_id = 'trigger_test_generic_action';
-    $hash = md5($action_id);
+    $hash = drupal_hash_base64($action_id);
     $edit = array('aid' => $hash);
     $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-insert-assign-form');
 
@@ -300,7 +300,7 @@ class TriggerOtherTestCase extends TriggerWebTestCase {
 
     // Configure an advanced action that we can assign.
     $aid = $this->configureAdvancedAction('system_message_action', $action_edit);
-    $edit = array('aid' => md5($aid));
+    $edit = array('aid' => drupal_hash_base64($aid));
     $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-login-assign-form');
 
     // Verify that the action has been assigned to the correct hook.
@@ -322,7 +322,7 @@ class TriggerOtherTestCase extends TriggerWebTestCase {
     $test_user = $this->drupalCreateUser(array('administer actions'));
     $this->drupalLogin($test_user);
     $action_id = 'trigger_test_generic_action';
-    $hash = md5($action_id);
+    $hash = drupal_hash_base64($action_id);
     $edit = array('aid' => $hash);
     $this->drupalPost('admin/structure/trigger/comment', $edit, t('Assign'), array(), array(), 'trigger-comment-insert-assign-form');
 
@@ -351,7 +351,7 @@ class TriggerOtherTestCase extends TriggerWebTestCase {
     $test_user = $this->drupalCreateUser(array('administer actions'));
     $this->drupalLogin($test_user);
     $action_id = 'trigger_test_generic_action';
-    $hash = md5($action_id);
+    $hash = drupal_hash_base64($action_id);
     $edit = array('aid' => $hash);
     $this->drupalPost('admin/structure/trigger/taxonomy', $edit, t('Assign'), array(), array(), 'trigger-taxonomy-term-insert-assign-form');
 
@@ -403,7 +403,7 @@ class TriggerOrphanedActionsTestCase extends DrupalWebTestCase {
    */
   function testActionsOrphaned() {
     $action = 'trigger_test_generic_any_action';
-    $hash = md5($action);
+    $hash = drupal_hash_base64($action);
 
     // Assign an action from a disable-able module to a trigger, then pull the
     // trigger, and make sure the actions fire.
diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info
index 590e88c63b1f5a277355f7f8efa12945ce4b83de..3446b3c83762f2b7fa86b5a9958d3603671baa4f 100644
--- a/modules/update/tests/aaa_update_test.info
+++ b/modules/update/tests/aaa_update_test.info
@@ -6,8 +6,8 @@ core = 7.x
 files[] = aaa_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info
index 6c3f6a5e7a12028c0038ffed6ecbfe452b62bedb..9506f04d6c2296599fd48ee921665314159bef51 100644
--- a/modules/update/tests/bbb_update_test.info
+++ b/modules/update/tests/bbb_update_test.info
@@ -6,8 +6,8 @@ core = 7.x
 files[] = bbb_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info
index b6f29dd43dfb2bc95021d7d6fe557e5a46430bc2..5627ee6b8ec3b58a18ea3c8d4de489a4a01d5913 100644
--- a/modules/update/tests/ccc_update_test.info
+++ b/modules/update/tests/ccc_update_test.info
@@ -6,8 +6,8 @@ core = 7.x
 files[] = ccc_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info
index 87b4cf889d360df24900d5b9fbd8e691ada2fa20..fde942338e552589e3602a441d441e5ab93862b9 100644
--- a/modules/update/tests/update_test.info
+++ b/modules/update/tests/update_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/update/update.api.php b/modules/update/update.api.php
index d8ee6e2b6bc01f40c0f6b8ef796d590343fbc1f9..c1b2515785bcc5e17b0e052edab12c5cf2435e5b 100644
--- a/modules/update/update.api.php
+++ b/modules/update/update.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.api.php,v 1.4 2009/08/22 14:34:23 webchick Exp $
+// $Id: update.api.php,v 1.5 2010/04/30 16:27:02 webchick Exp $
 
 /**
  * @file
@@ -104,6 +104,29 @@ function hook_update_status_alter(&$projects) {
   }
 }
 
+/**
+ * Verify an archive after it has been downloaded and extracted.
+ *
+ * @param string $project
+ *   The short name of the project that has been downloaded.
+ * @param string $archive_file
+ *   The filename of the unextracted archive.
+ * @param string $directory
+ *   The directory that the archive was extracted into.
+ *
+ * @return
+ *   If there is a problem, return any non-null value. If there is no problem,
+ *   don't return anything (null).
+ *
+ * @see update_manager_archive_verify()
+ */
+function hook_verify_update_archive($project, $archive_file, $directory) {
+  if (!file_exists($directory)) {
+    return TRUE;
+  }
+  // Add other checks on the archive integrity here.
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/modules/update/update.css b/modules/update/update.css
index a6011ca261000e3168d799a132c330cc373edfd3..f19db9b640a657aa4cdde515e5ba22c516d38be5 100644
--- a/modules/update/update.css
+++ b/modules/update/update.css
@@ -1,4 +1,4 @@
-/* $Id: update.css,v 1.6 2009/10/15 21:19:31 webchick Exp $ */
+/* $Id: update.css,v 1.7 2010/04/28 20:08:39 dries Exp $ */
 
 .update .project {
   font-weight: bold;
@@ -52,7 +52,8 @@
   background: #ffe;
 }
 
-.current-version, .new-version {
+.current-version,
+.new-version {
   direction: ltr; /* Note: version numbers should always be LTR. */
 }
 
diff --git a/modules/update/update.fetch.inc b/modules/update/update.fetch.inc
index 7944828aeeb2d5cccb710183376300df9da7b358..63847d26d83b1830fec0db20ce31b3324064ca84 100644
--- a/modules/update/update.fetch.inc
+++ b/modules/update/update.fetch.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.fetch.inc,v 1.26 2009/12/29 07:21:34 webchick Exp $
+// $Id: update.fetch.inc,v 1.28 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -137,7 +137,7 @@ function _update_process_fetch_task($project) {
 
   $success = FALSE;
   $available = array();
-  $site_key = md5($base_url . drupal_get_private_key());
+  $site_key = drupal_hmac_base64($base_url, drupal_get_private_key());
   $url = _update_build_fetch_url($project, $site_key);
   $fetch_url_base = _update_get_fetch_url_base($project);
   $project_name = $project['name'];
@@ -361,26 +361,26 @@ function update_parse_xml($raw_xml) {
   if (!isset($xml->short_name)) {
     return;
   }
-  $short_name = (string)$xml->short_name;
+  $short_name = (string) $xml->short_name;
   $data = array();
   foreach ($xml as $k => $v) {
-    $data[$k] = (string)$v;
+    $data[$k] = (string) $v;
   }
   $data['releases'] = array();
   if (isset($xml->releases)) {
     foreach ($xml->releases->children() as $release) {
-      $version = (string)$release->version;
+      $version = (string) $release->version;
       $data['releases'][$version] = array();
       foreach ($release->children() as $k => $v) {
-        $data['releases'][$version][$k] = (string)$v;
+        $data['releases'][$version][$k] = (string) $v;
       }
       $data['releases'][$version]['terms'] = array();
       if ($release->terms) {
         foreach ($release->terms->children() as $term) {
-          if (!isset($data['releases'][$version]['terms'][(string)$term->name])) {
-            $data['releases'][$version]['terms'][(string)$term->name] = array();
+          if (!isset($data['releases'][$version]['terms'][(string) $term->name])) {
+            $data['releases'][$version]['terms'][(string) $term->name] = array();
           }
-          $data['releases'][$version]['terms'][(string)$term->name][] = (string)$term->value;
+          $data['releases'][$version]['terms'][(string) $term->name][] = (string) $term->value;
         }
       }
     }
diff --git a/modules/update/update.info b/modules/update/update.info
index 0ff0012b340eb826804f9c679465dd523a91d657..171fa18a6dbb905a6a16c93e368f349498c5d5d7 100644
--- a/modules/update/update.info
+++ b/modules/update/update.info
@@ -15,8 +15,8 @@ files[] = update.settings.inc
 files[] = update.test
 configure = admin/reports/updates/settings
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/update/update.install b/modules/update/update.install
index 50a68ebe78acf288ffe30735f31d4aa78f309deb..242b04d3cdda8a5b8d4c492c87131b16e77e7afb 100644
--- a/modules/update/update.install
+++ b/modules/update/update.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.install,v 1.16 2010/01/15 10:12:36 dries Exp $
+// $Id: update.install,v 1.18 2010/05/19 19:14:43 dries Exp $
 
 /**
  * @file
@@ -167,3 +167,10 @@ function update_update_7000() {
   $queue = DrupalQueue::get('update_fetch_tasks');
   $queue->createQueue();
 }
+
+/**
+ * Remove {cache_update}.headers column.
+ */
+function update_update_7001() {
+  db_drop_field('cache_update', 'headers');
+}
diff --git a/modules/update/update.manager.inc b/modules/update/update.manager.inc
index c9517fceb4e80cb85725989d5524a74db467ac1c..8dbef154537468eea9e0a4416077f5ca845cebdc 100644
--- a/modules/update/update.manager.inc
+++ b/modules/update/update.manager.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.manager.inc,v 1.21 2010/04/24 14:49:14 dries Exp $
+// $Id: update.manager.inc,v 1.22 2010/05/14 04:50:18 webchick Exp $
 
 /**
  * @file
@@ -635,7 +635,7 @@ function update_manager_install_form_submit($form, &$form_state) {
 function _update_manager_extract_directory() {
   $directory = &drupal_static(__FUNCTION__, '');
   if (empty($directory)) {
-    $directory = DRUPAL_ROOT . '/' . file_directory_path('temporary') . '/update-extraction';
+    $directory = 'temporary://update-extraction';
     if (!file_exists($directory)) {
       mkdir($directory);
     }
@@ -708,8 +708,8 @@ function update_manager_file_get($url) {
   }
 
   // Check the cache and download the file if needed.
-  $local = 'temporary://update-cache/' . basename($parsed_url['path']);
-  $cache_directory = DRUPAL_ROOT . '/' . file_directory_path('temporary') . '/update-cache/';
+  $cache_directory = 'temporary://update-cache';
+  $local = $cache_directory . '/' . basename($parsed_url['path']);
 
   if (!file_exists($cache_directory)) {
     mkdir($cache_directory);
diff --git a/modules/update/update.module b/modules/update/update.module
index 6920bc9423c87493a21edd04d40fe95aab060faa..746ec24a5ff5454191145dd52ed40a2fdf5d83ef 100644
--- a/modules/update/update.module
+++ b/modules/update/update.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.module,v 1.65 2010/04/13 15:23:03 dries Exp $
+// $Id: update.module,v 1.67 2010/05/18 18:26:30 dries Exp $
 
 /**
  * @file
@@ -159,7 +159,7 @@ function update_menu() {
     'description' => 'Get a status report about available updates for your installed modules and themes.',
     'page callback' => 'update_status',
     'access arguments' => array('administer site configuration'),
-    'weight' => 10,
+    'weight' => -50,
     'file' => 'update.report.inc',
   );
   $items['admin/reports/updates/list'] = array(
@@ -653,9 +653,6 @@ function theme_update_last_check($variables) {
 /**
  * Store data in the private update status cache table.
  *
- * Note: this function completely ignores the {cache_update}.headers field
- * since that is meaningless for the kinds of data we're caching.
- *
  * @param $cid
  *   The cache ID to save the data with.
  * @param $data
@@ -671,7 +668,6 @@ function _update_cache_set($cid, $data, $expire) {
   $fields = array(
     'created' => REQUEST_TIME,
     'expire' => $expire,
-    'headers' => NULL,
   );
   if (!is_string($data)) {
     $fields['data'] = serialize($data);
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index 4fef3274c278d5f1393a3cb73ca282e6170f6c6d..dedfd1d55568b120295e8049c76906b93edde80e 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.admin.inc,v 1.108 2010/04/24 14:49:14 dries Exp $
+// $Id: user.admin.inc,v 1.109 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -975,7 +975,7 @@ function user_admin_role_validate($form, &$form_state) {
  * Form submit handler for the user_admin_role() form.
  */
 function user_admin_role_submit($form, &$form_state) {
-  $role = (object)$form_state['values'];
+  $role = (object) $form_state['values'];
   if ($form_state['values']['op'] == t('Save role')) {
     user_role_save($role);
     drupal_set_message(t('The role has been renamed.'));
diff --git a/modules/user/user.css b/modules/user/user.css
index 81c76c612df5d71208399f901fca7388835df7fb..ecf6870a1e0bfbac58804e7d778ae6608e295dc3 100644
--- a/modules/user/user.css
+++ b/modules/user/user.css
@@ -1,4 +1,4 @@
-/* $Id: user.css,v 1.20 2010/03/24 07:34:10 dries Exp $ */
+/* $Id: user.css,v 1.21 2010/04/28 20:08:39 dries Exp $ */
 
 #permissions td.module {
   font-weight: bold;
@@ -6,11 +6,13 @@
 #permissions td.permission {
   padding-left: 1.5em; /* LTR */
 }
-#permissions tr.odd .form-item, #permissions tr.even .form-item {
+#permissions tr.odd .form-item,
+#permissions tr.even .form-item {
   white-space: normal;
 }
 /* Override the default multiselect layout in system-behavior.css. */
-#user-filter-form dl.multiselect dd, dl.multiselect dd .form-item {
+#user-filter-form dl.multiselect dd,
+dl.multiselect dd .form-item {
   width: 20em; /* 6em label + 14em select */
 }
 #user-filter-form dl.multiselect dd .form-item label {
diff --git a/modules/user/user.info b/modules/user/user.info
index 8294107ad823fc0f4dae0c37db5ad2153c31a9d4..5e3139cca4f1071af5d1ddd55921662742a666cd 100644
--- a/modules/user/user.info
+++ b/modules/user/user.info
@@ -13,8 +13,8 @@ files[] = user.tokens.inc
 required = TRUE
 configure = admin/config/people
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/modules/user/user.install b/modules/user/user.install
index f4866f7556b9dcb8f4147ad2bfe5180d0bf96752..21f1da02ef0d76eb6292ad31546fca1ca9a080af 100644
--- a/modules/user/user.install
+++ b/modules/user/user.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.install,v 1.45 2010/04/13 15:15:07 dries Exp $
+// $Id: user.install,v 1.46 2010/05/05 06:55:25 webchick Exp $
 
 /**
  * @file
@@ -483,7 +483,7 @@ function user_update_7004(&$sandbox) {
     'type' => 'int',
     'not null' => TRUE,
     'default' => 0,
-    'description' => t("Foreign key: {file_managed}.fid of user's picture."),
+    'description' => "Foreign key: {file_managed}.fid of user's picture.",
   );
 
   if (!isset($sandbox['progress'])) {
diff --git a/modules/user/user.module b/modules/user/user.module
index 4cb5a7a3c5d2effe4a09b541b767c98a537cea72..505fe687dd666dbd28115f376efb0ab7d21940a9 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.module,v 1.1163 2010/04/24 14:51:49 dries Exp $
+// $Id: user.module,v 1.1170 2010/05/12 08:35:39 dries Exp $
 
 /**
  * @file
@@ -187,6 +187,15 @@ function user_field_extra_fields() {
   return $return;
 }
 
+/**
+ * Fetches a user object based on an external authentication source.
+ *
+ * @param string $authname
+ *   The external authentication username.
+ *
+ * @return
+ *   A fully-loaded user object if the user is found or FALSE if not found.
+ */
 function user_external_load($authname) {
   $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField();
 
@@ -273,14 +282,24 @@ class UserController extends DrupalDefaultEntityController {
 }
 
 /**
- * Fetch a user object.
+ * Loads a user object.
+ *
+ * Drupal has a global $user object, which represents the currently-logged-in
+ * user. So to avoid confusion and to avoid clobbering the global $user object,
+ * it is a good idea to assign the result of this function to a different local
+ * variable, generally $account. If you actually do want to act as the user you
+ * are loading, it is essential to call @code session_save_session(FALSE);
+ * @endcode first. See @link http://drupal.org/node/218104 Safely impersonating
+ * another user @endlink for more information.
  *
  * @param $uid
- *   Integer specifying the user id.
+ *   Integer specifying the user ID to load.
  * @param $reset
- *   A boolean indicating that the internal cache should be reset.
+ *   TRUE to reset the internal cache and load from the database; FALSE
+ *   (default) to load from the internal cache, if set.
+ *
  * @return
- *   A fully-loaded $user object upon successful user load or FALSE if user
+ *   A fully-loaded user object upon successful user load, or FALSE if the user
  *   cannot be loaded.
  *
  * @see user_load_multiple()
@@ -565,6 +584,19 @@ function user_validate_name($name) {
   }
 }
 
+/**
+ * Validates a user's email address.
+ *
+ * Checks that a user's email address exists and follows all standard
+ * validation rules. Returns error messages when the address is invalid.
+ *
+ * @param $mail
+ *   A user's email address.
+ *
+ * @return
+ *   If the address is invalid, a human-readable error message is returned.
+ *   If the address is valid, nothing is returned.
+ */
 function user_validate_mail($mail) {
   $mail = trim($mail);
   if (!$mail) {
@@ -575,6 +607,11 @@ function user_validate_mail($mail) {
   }
 }
 
+/**
+ * Validates an image uploaded by a user.
+ *
+ * @see user_account_form()
+ */
 function user_validate_picture(&$form, &$form_state) {
   // If required, validate the uploaded picture.
   $validators = array(
@@ -817,9 +854,10 @@ function user_search_execute($keys = NULL) {
   // Replace wildcards with MySQL/PostgreSQL wildcards.
   $keys = preg_replace('!\*+!', '%', $keys);
   $query = db_select('users')->extend('PagerDefault');
-  $query->fields('users', array('name', 'uid', 'mail'));
+  $query->fields('users', array('name', 'uid'));
   if (user_access('administer users')) {
     // Administrators can also search in the otherwise private email field.
+    $query->fields('users', array('mail'));
     $query->condition(db_or()->
       condition('name', '%' . db_like($keys) . '%', 'LIKE')->
       condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
@@ -830,8 +868,15 @@ function user_search_execute($keys = NULL) {
   $result = $query
     ->limit(15)
     ->execute();
-  foreach ($result as $account) {
-    $find[] = array('title' => $account->name . ' (' . $account->mail . ')', 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
+  if (user_access('administer users')) {
+    foreach ($result as $account) {
+      $find[] = array('title' => $account->name . ' (' . $account->mail . ')', 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
+    }
+  }
+  else {
+    foreach ($result as $account) {
+      $find[] = array('title' => $account->name, 'link' => url('user/' . $account->uid, array('absolute' => TRUE)));
+    }
   }
   return $find;
 }
@@ -875,6 +920,11 @@ function user_user_view($account) {
 
 /**
  * Helper function to add default user account fields to user registration and edit form.
+ * 
+ * @see user_account_form_validate()
+ * @see user_validate_current_pass()
+ * @see user_validate_picture()
+ * @see user_validate_email()
  */
 function user_account_form(&$form, &$form_state) {
   global $user;
@@ -1048,6 +1098,8 @@ function user_account_form(&$form, &$form_state) {
 
 /**
  * Form validation handler for the current password on the user_account_form().
+ * 
+ * @see user_account_form()
  */
 function user_validate_current_pass(&$form, &$form_state) {
   global $user;
@@ -1072,6 +1124,8 @@ function user_validate_current_pass(&$form, &$form_state) {
 
 /**
  * Form validation handler for user_account_form().
+ * 
+ * @see user_account_form()
  */
 function user_account_form_validate($form, &$form_state) {
   if ($form['#user_category'] == 'account' || $form['#user_category'] == 'register') {
@@ -1368,7 +1422,7 @@ function user_is_anonymous() {
 }
 
 function user_is_logged_in() {
-  return (bool)$GLOBALS['user']->uid;
+  return (bool) $GLOBALS['user']->uid;
 }
 
 function user_register_access() {
@@ -2082,8 +2136,7 @@ function user_cancel_url($account) {
 }
 
 function user_pass_rehash($password, $timestamp, $login) {
-  // A single md5() is vulnerable to length-extension attacks, so use it twice.
-  return md5(drupal_get_hash_salt() . md5($timestamp . $password . $login));
+  return drupal_hmac_base64($timestamp . $login, drupal_get_hash_salt() . $password);
 }
 
 /**
@@ -3001,8 +3054,8 @@ function _user_categories() {
 }
 
 function _user_sort($a, $b) {
-  $a = (array)$a + array('weight' => 0, 'title' => '');
-  $b = (array)$b + array('weight' => 0, 'title' => '');
+  $a = (array) $a + array('weight' => 0, 'title' => '');
+  $b = (array) $b + array('weight' => 0, 'title' => '');
   return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
 }
 
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
index 643d5b852780bf9d8a48956c244100a9ebd886fa..9bbf4908779fdd4cef5370676bbad2a71f5c832f 100644
--- a/modules/user/user.pages.inc
+++ b/modules/user/user.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.pages.inc,v 1.70 2010/04/24 14:49:14 dries Exp $
+// $Id: user.pages.inc,v 1.72 2010/05/06 05:59:31 webchick Exp $
 
 /**
  * @file
@@ -134,7 +134,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
           user_login_finalize();
           drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
           // Let the user's password be changed without the current password check.
-          $token = md5(drupal_random_bytes(55));
+          $token = drupal_hash_base64(drupal_random_bytes(55));
           $_SESSION['pass_reset_' . $user->uid] = $token;
           drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
         }
@@ -278,7 +278,7 @@ function user_profile_form($form, &$form_state, $account, $category = 'account')
  * Validation function for the user account and profile editing form.
  */
 function user_profile_form_validate($form, &$form_state) {
-  $edit = (object)$form_state['values'];
+  $edit = (object) $form_state['values'];
   field_attach_form_validate('user', $edit, $form, $form_state);
 }
 
@@ -291,9 +291,9 @@ function user_profile_form_submit($form, &$form_state) {
   // Remove unneeded values.
   form_state_values_clean($form_state);
 
-  $edit = (object)$form_state['values'];
+  $edit = (object) $form_state['values'];
   field_attach_submit('user', $edit, $form, $form_state);
-  $edit = (array)$edit;
+  $edit = (array) $edit;
 
   user_save($account, $edit, $category);
   $form_state['values']['uid'] = $account->uid;
diff --git a/modules/user/user.test b/modules/user/user.test
index 30572cba95f802c3fa5e419f56ae47dde47febed..560ca7a8c049619a6b13ee60e34bd2cd3cde424d 100644
--- a/modules/user/user.test
+++ b/modules/user/user.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.test,v 1.89 2010/04/20 09:48:06 webchick Exp $
+// $Id: user.test,v 1.92 2010/05/07 14:48:10 dries Exp $
 
 class UserRegistrationTestCase extends DrupalWebTestCase {
   public static function getInfo() {
@@ -55,7 +55,7 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
     $edit['pass[pass1]'] = '99999.0';
     $edit['pass[pass2]'] = '99999';
     $this->drupalPost('user/register', $edit, t('Create new account'));
-    $this->assertText(t('The specified passwords do not match.'), t('Type mismatched passwords display an error message.'));
+    $this->assertText(t('The specified passwords do not match.'), t('Typing mismatched passwords displays an error message.'));
 
     // Enter a correct password.
     $edit['pass[pass1]'] = $new_pass = $this->randomName();
@@ -1259,7 +1259,7 @@ class UserBlocksUnitTests extends DrupalWebTestCase {
   private function insertSession(array $fields = array()) {
     $fields += array(
       'uid' => 0,
-      'sid' => md5(uniqid(mt_rand(), TRUE)),
+      'sid' => drupal_hash_base64(uniqid(mt_rand(), TRUE)),
       'timestamp' => REQUEST_TIME,
     );
     db_insert('sessions')
@@ -1391,6 +1391,18 @@ class UserEditTestCase extends DrupalWebTestCase {
     $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
     $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
 
+    // Check that filling out a single password field does not validate.
+    $edit = array();
+    $edit['pass[pass1]'] = '';
+    $edit['pass[pass2]'] = $this->randomName();
+    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
+    $this->assertText(t("The specified passwords do not match."), t('Typing mismatched passwords displays an error message.'));
+
+    $edit['pass[pass1]'] = $this->randomName();
+    $edit['pass[pass2]'] = '';
+    $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
+    $this->assertText(t("The specified passwords do not match."), t('Typing mismatched passwords displays an error message.'));
+
     // Test that the error message appears when attempting to change the mail or
     // pass without the current password.
     $edit = array();
@@ -1585,3 +1597,36 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
     }
   }
 }
+
+/**
+ * Test user search.
+ */
+class UserUserSearchTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'User search',
+      'description' => 'Testing that only user with the right permission can see the email address in the user search.',
+      'group' => 'User',
+    );
+  }
+
+  function testUserSearch() {
+    $user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search'));
+    $this->drupalLogin($user1);
+    $keys = $user1->mail;
+    $edit = array('keys' => $keys);
+    $this->drupalPost('search/user/', $edit, t('Search'));
+    $this->assertNoText($keys);
+    $this->drupalLogout();
+
+    $user2 = $this->drupalCreateUser(array('administer users', 'access user profiles', 'search content', 'use advanced search'));
+    $this->drupalLogin($user2);
+    $keys = $user2->mail;
+    $edit = array('keys' => $keys);
+    $this->drupalPost('search/user/', $edit, t('Search'));
+    $this->assertText($keys);
+    $this->drupalLogout();
+  }
+}
+
+
diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info
index 8d5880db910fc68df079537c2f22023a627f3457..190e4b49e13b0e2c16511b407109876de1ee7172 100644
--- a/profiles/minimal/minimal.info
+++ b/profiles/minimal/minimal.info
@@ -7,8 +7,8 @@ dependencies[] = block
 dependencies[] = dblog
 files[] = minimal.profile
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info
index 334742c2c0694b759740ca6b0deb60d82507a2f9..9612125236e5314d80ed1cbb3c3dd085fed34677 100644
--- a/profiles/standard/standard.info
+++ b/profiles/standard/standard.info
@@ -23,8 +23,8 @@ dependencies[] = file
 dependencies[] = rdf
 files[] = standard.profile
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install
index a9de9dc5de8c33ea30e5e86bf78c1426637c3b6b..fe43d5b73c1d372b13e5109af8dc8d3cfb8283f7 100644
--- a/profiles/standard/standard.install
+++ b/profiles/standard/standard.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: standard.install,v 1.13 2010/04/22 09:55:32 webchick Exp $
+// $Id: standard.install,v 1.15 2010/05/16 10:41:04 dries Exp $
 
 /**
  * Implements hook_install().
@@ -227,6 +227,7 @@ function standard_install() {
   foreach ($types as $type) {
     $type = node_type_set_defaults($type);
     node_type_save($type);
+    node_add_body_field($type);
   }
 
   // Insert default pre-defined RDF mapping into the database.
@@ -414,6 +415,11 @@ function standard_install() {
   // Set this as the administrator role.
   variable_set('user_admin_role', $admin_role->rid);
 
+  // Assign user 1 the "administrator" role.
+  db_insert('users_roles')
+    ->fields(array('uid' => 1, 'rid' => $admin_role->rid))
+    ->execute();
+
   // Update the menu router information.
   menu_rebuild();
 
diff --git a/scripts/password-hash.sh b/scripts/password-hash.sh
index a7660fbd92b3b26e2be153ec652ecf6a0cdce881..3a7243e9b69519aac27c766e1f49ec869caf20d3 100755
--- a/scripts/password-hash.sh
+++ b/scripts/password-hash.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/php
 <?php
-// $Id: password-hash.sh,v 1.6 2009/02/26 07:30:29 webchick Exp $
+// $Id: password-hash.sh,v 1.7 2010/05/01 08:12:23 dries Exp $
 
 /**
  * Drupal hash script - to generate a hash from a plaintext password
@@ -13,10 +13,6 @@
  *  Plain-text passwords in quotes (or with spaces backslash escaped).
  */
 
-function variable_get($x, $default) {
-  return $default;
-}
-
 if (version_compare(PHP_VERSION, "5.2.0", "<")) {
   $version  = PHP_VERSION;
   echo <<<EOF
@@ -86,7 +82,7 @@ while ($param = array_shift($_SERVER['argv'])) {
 define('DRUPAL_ROOT', getcwd());
 
 include_once DRUPAL_ROOT . '/includes/password.inc';
-include_once DRUPAL_ROOT . '/includes/common.inc';
+include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
 
 foreach ($passwords as $password) {
   print("\npassword: $password \t\thash: ". user_hash_password($password) ."\n");
diff --git a/themes/garland/color/preview.css b/themes/garland/color/preview.css
index 314391e9f0cc2ec5a410ec9bfd3bbcf591364a6d..b63c078c23388319e2925e82df897c1ceb508472 100644
--- a/themes/garland/color/preview.css
+++ b/themes/garland/color/preview.css
@@ -1,11 +1,12 @@
-/* $Id: preview.css,v 1.4 2010/04/22 05:18:21 webchick Exp $ */
+/* $Id: preview.css,v 1.5 2010/04/28 20:08:39 dries Exp $ */
 
 /* Positioning */
 #preview {
   overflow: hidden;
   max-width: 100%;
 }
-#preview, #preview #img {
+#preview,
+#preview #img {
   width: 600px;
   height: 371px;
 }
@@ -50,7 +51,8 @@
 #preview p {
   margin: .5em 0;
 }
-#preview a:link, #preview a:visited {
+#preview a:link,
+#preview a:visited {
   text-decoration: none;
   font-weight: normal;
 }
diff --git a/themes/garland/fix-ie-rtl.css b/themes/garland/fix-ie-rtl.css
index 665af8e99c90512e23ffab81cd4e59cd6b79f679..4816254831fc46529d6b74b72d3cefefb1a01189 100644
--- a/themes/garland/fix-ie-rtl.css
+++ b/themes/garland/fix-ie-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: fix-ie-rtl.css,v 1.5 2010/03/31 20:24:13 dries Exp $ */
+/* $Id: fix-ie-rtl.css,v 1.6 2010/04/28 20:08:39 dries Exp $ */
 
 body {
   /* Center layout */
@@ -10,11 +10,12 @@ body {
   direction: ltr;
 }
 
-#squeeze .left-corner{
+#squeeze .left-corner {
   direction: rtl
 }
 
-#header-region, #wrapper #container {
+#header-region,
+#wrapper #container {
   /* Reset text alignment */
   text-align: right;
 }
@@ -54,7 +55,8 @@ tr.menu-disabled {
   height: 1em;
 }
 
-#attach-hide label, #uploadprogress div.message {
+#attach-hide label,
+#uploadprogress div.message {
   /* Fading elements in IE causes the text to bleed unless they have a background. */
   background-color: #ffffff;
 }
diff --git a/themes/garland/fix-ie.css b/themes/garland/fix-ie.css
index 865efed6faae6f92dad99b7dcef160e95f32d2ab..8753da1defed85f376582d04808783675be35b66 100644
--- a/themes/garland/fix-ie.css
+++ b/themes/garland/fix-ie.css
@@ -1,11 +1,12 @@
-/* $Id: fix-ie.css,v 1.12 2010/03/31 20:24:13 dries Exp $ */
+/* $Id: fix-ie.css,v 1.13 2010/04/28 20:08:39 dries Exp $ */
 
 body {
   /* Center layout */
   text-align: center;
 }
 
-#header-region, #wrapper #container {
+#header-region,
+#wrapper #container {
   /* Reset text alignment */
   text-align: left; /* LTR */
 }
@@ -58,7 +59,8 @@ tr.taxonomy-term-preview {
   filter: alpha(opacity=50);
 }
 
-#attach-hide label, #uploadprogress div.message {
+#attach-hide label,
+#uploadprogress div.message {
   /* Fading elements in IE causes the text to bleed unless they have a background. */
   background-color: #ffffff;
 }
diff --git a/themes/garland/garland.info b/themes/garland/garland.info
index 85de5721ab13a1b4565b6491d3cfc79ab4f1c316..381dd6f3e16cb62b0240c4e2f446631cacd28d2c 100644
--- a/themes/garland/garland.info
+++ b/themes/garland/garland.info
@@ -9,8 +9,8 @@ stylesheets[all][] = style.css
 stylesheets[print][] = print.css
 settings[garland_width] = fluid
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/themes/garland/print.css b/themes/garland/print.css
index 6f75653806cd1ab14b5a7d5502d19254ca264ae2..2b74d16773c7bc6f03a11d419e57a7e72e718c94 100644
--- a/themes/garland/print.css
+++ b/themes/garland/print.css
@@ -1,23 +1,35 @@
-/* $Id: print.css,v 1.8 2009/08/03 03:04:34 webchick Exp $ */
+/* $Id: print.css,v 1.9 2010/04/28 20:08:39 dries Exp $ */
 
-body, input, textarea, select {
+body,
+input,
+textarea,
+select {
   color: #000;
   background: none;
   font-family: Verdana, sans-serif;
   font-size: 11pt;
 }
 
-ul.main-menu, ul.secondary-menu,
-#header-region, .sidebar {
+ul.main-menu,
+ul.secondary-menu,
+#header-region,
+.sidebar {
   display: none;
 }
 
-body.two-sidebars, body.sidebar-first, body.sidebar-second, body {
+body.two-sidebars,
+body.sidebar-first,
+body.sidebar-second,
+body {
   width: 640px;
 }
 
-body.sidebar-first #center, body.sidebar-second #center, body.two-sidebars #center,
-body.sidebar-first #squeeze, body.sidebar-second #squeeze, body.two-sidebars #squeeze {
+body.sidebar-first #center,
+body.sidebar-second #center,
+body.two-sidebars #center,
+body.sidebar-first #squeeze,
+body.sidebar-second #squeeze,
+body.two-sidebars #squeeze {
   margin: 0;
 }
 
@@ -42,7 +54,9 @@ body.sidebar-first #squeeze, body.sidebar-second #squeeze, body.two-sidebars #sq
   height: 130px;
 }
 
-#wrapper #container #header h1, #wrapper #container #header h1 a:link, #wrapper #container #header h1 a:visited {
+#wrapper #container #header h1,
+#wrapper #container #header h1 a:link,
+#wrapper #container #header h1 a:visited {
   text-shadow: none;
   color: #000;
 }
diff --git a/themes/garland/style-rtl.css b/themes/garland/style-rtl.css
index 9d1e8dff679d581fe9781c48800f9d5791170944..657b8b45dd2b2d60fc1384e3a672ae6b0f6e5ed2 100644
--- a/themes/garland/style-rtl.css
+++ b/themes/garland/style-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: style-rtl.css,v 1.19 2010/04/08 18:26:42 dries Exp $ */
+/* $Id: style-rtl.css,v 1.22 2010/05/05 16:28:06 dries Exp $ */
 
 html {
   direction: rtl;
@@ -11,15 +11,22 @@ body {
   direction: rtl;
 }
 
-ul, .block ul, ol {
+ul,
+.block ul,
+ol {
   padding: 0 1.5em 0 0;
 }
 
-ul.menu, .item-list ul {
+ul.menu,
+.item-list ul {
   margin: 0.35em -0.5em 0 0;
 }
 
-ol li, ul li, ul.menu li, .item-list ul li, li.leaf {
+ol li,
+ul li,
+ul.menu li,
+.item-list ul li,
+li.leaf {
   margin: 0.15em .5em 0.15em 0;
 }
 
@@ -68,7 +75,8 @@ dl dd {
   padding: 0 1.3 0 0;
 }
 
-.form-button, .form-submit {
+.form-button,
+.form-submit {
   margin: 2em 0 1em 0.5em;
 }
 
@@ -181,8 +189,14 @@ h1.with-tabs {
   margin: 0 0 0 2em;
 }
 
-ul.primary li a, ul.primary li.active a, ul.primary li a:hover, ul.primary li a:visited,
-ul.secondary li a, ul.secondary li.active a, ul.secondary li a:hover, ul.secondary li a:visited {
+ul.primary li a,
+ul.primary li.active a,
+ul.primary li a:hover,
+ul.primary li a:visited,
+ul.secondary li a,
+ul.secondary li.active a,
+ul.secondary li a:hover,
+ul.secondary li a:visited {
   margin: 0 1px 0 0;
 
 }
@@ -196,8 +210,10 @@ ul.links li, ul.inline li {
   padding-right: 0;
 }
 
-.node .links, .comment .links {
+.node .links,
+.comment .links {
   text-align: right;
+  padding-right: 0;
 }
 
 .user-picture,
@@ -258,6 +274,14 @@ div.vertical-tabs {
 #user-login-form ul {
   text-align: right;
 }
+#user-login-form .openid-links {
+  padding-left: 0;
+  padding-right: 0.5em;
+}
+#user-login-form .openid-links li.user-link {
+  padding-left: 0;
+  padding-right: 1em;
+}
 
 div.admin .left {
   float: right;
@@ -284,8 +308,14 @@ div.admin .right {
  */
 
 /* Position:relative on these breaks IE7. */
-ul.primary li a, ul.primary li.active a, ul.primary li a:hover, ul.primary li a:visited,
-ul.secondary li a, ul.secondary li.active a, ul.secondary li a:hover, ul.secondary li a:visited {
+ul.primary li a,
+ul.primary li.active a,
+ul.primary li a:hover,
+ul.primary li a:visited,
+ul.secondary li a,
+ul.secondary li.active a,
+ul.secondary li a:hover,
+ul.secondary li a:visited {
   position: static;
 }
 
diff --git a/themes/garland/style.css b/themes/garland/style.css
index 4b7c79badb5456510f55311deda1d38da5ca2c93..49d856137378cbc95dec31a4564648c68951f39e 100644
--- a/themes/garland/style.css
+++ b/themes/garland/style.css
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.78 2010/04/08 18:26:42 dries Exp $ */
+/* $Id: style.css,v 1.82 2010/05/18 11:56:59 dries Exp $ */
 
 /**
  * Generic elements
@@ -16,12 +16,18 @@ input {
   color: #494949;
 }
 
-textarea, select {
+textarea,
+select {
   font: 1em/160% Verdana, sans-serif;
   color: #494949;
 }
 
-h1, h2, h3, h4, h5, h6 {
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
   margin: 0;
   padding: 0;
   font-weight: normal;
@@ -32,7 +38,8 @@ h1 {
   font-size: 170%;
 }
 
-h2, #center h1 {
+h2,
+#center h1 {
   font-size: 160%;
   line-height: 130%;
 }
@@ -53,11 +60,15 @@ h6 {
   font-size: 110%;
 }
 
-quote, code, fieldset {
+quote,
+code,
+fieldset {
   margin: .5em 0;
 }
 
-code, pre, kbd {
+code,
+pre,
+kbd {
   font-size: 115%;
 }
 
@@ -66,7 +77,8 @@ p {
   padding: 0;
 }
 
-a:link, a:visited {
+a:link,
+a:visited {
   color: #027AC6;
   text-decoration: none;
 }
@@ -76,7 +88,8 @@ a:hover {
   text-decoration: underline;
 }
 
-a:active, a.active {
+a:active,
+a.active {
   color: #5895be;
 }
 
@@ -88,13 +101,16 @@ hr {
   background: #5294c1;
 }
 
-ul, .block ul, ol {
+ul,
+.block ul,
+ol {
   margin: 0.5em 0 1em;
   padding: 0 0 0 1.5em; /* LTR */
 }
 
 /* Default to menu leaf bullet for unordered list items. "ul" used here so it can cascade to list items and "li.leaf" to override the system leaf image. */
-ul, li.leaf {
+ul,
+ul li.leaf {
   list-style-image: url(images/menu-leaf.gif);
 }
 
@@ -103,11 +119,16 @@ ol {
   list-style-image: none;
 }
 
-ul.menu, .item-list ul {
+ul.menu,
+.item-list ul {
   margin: 0.35em 0 0 -0.5em; /* LTR */
 }
 
-ol li, ul li, ul.menu li, .item-list ul li, li.leaf {
+ol li,
+ul li,
+ul.menu li,
+.item-list ul li,
+li.leaf {
   margin: 0.15em 0 0.15em .5em; /* LTR */
   padding-bottom: .1em;
 }
@@ -120,7 +141,9 @@ ul li.collapsed {
   list-style-image: url(images/menu-collapsed.gif); /* LTR */
 }
 
-ul li.leaf a, ul li.expanded a, ul li.collapsed a {
+ul li.leaf a,
+ul li.expanded a,
+ul li.collapsed a {
   display: block;
 }
 
@@ -166,7 +189,8 @@ dl dd {
   margin: 0 0 .5em 1.5em; /* LTR */
 }
 
-img, a img {
+img,
+a img {
   border: none;
 }
 
@@ -181,20 +205,25 @@ thead th {
   font-weight: bold;
 }
 
-th a:link, th a:visited {
+th a:link,
+th a:visited {
   color: #6f9dbd;
 }
 
-td, th {
+td,
+th {
   padding: .3em .5em;
 }
 
-tr.even, tr.odd, tbody th {
+tr.even,
+tr.odd,
+tbody th {
   border: solid #d3e7f4;
   border-width: 1px 0;
 }
 
-tr.odd, tr.info {
+tr.odd,
+tr.info {
   background-color: #edf5fa;
 }
 
@@ -218,7 +247,10 @@ tr.even td.active {
   background-color: #e6f1f7;
 }
 
-td.region-title, td.module, td.container, td.category {
+td.region-title,
+td.module,
+td.container,
+td.category {
   border-top: 1.5em solid #fff;
   border-bottom: 1px solid #b4d7f0;
   background-color: #d4e7f3;
@@ -226,7 +258,10 @@ td.region-title, td.module, td.container, td.category {
   font-weight: bold;
 }
 
-tr:first-child td.region-title, tr:first-child td.module, tr:first-child td.container, tr:first-child td.category {
+tr:first-child td.region-title,
+tr:first-child td.module,
+tr:first-child td.container,
+tr:first-child td.category {
   border-top-width: 0;
 }
 
@@ -234,7 +269,8 @@ span.form-required {
   color: #ffae00;
 }
 
-.submitted, .description, .vertical-tab-button .summary {
+.submitted, .description,
+.vertical-tab-button .summary {
   font-size: 0.92em;
   color: #898989;
 }
@@ -268,7 +304,10 @@ div.messages {
   padding: 0 0 0 1.3em; /* LTR */
 }
 
-.form-checkboxes, .form-radios, .form-checkboxes .form-item, .form-radios .form-item {
+.form-checkboxes,
+.form-radios,
+.form-checkboxes .form-item,
+.form-radios .form-item {
   margin: 0.25em 0;
 }
 
@@ -276,7 +315,8 @@ div.messages {
   margin-bottom: 2em;
 }
 
-.form-button, .form-submit {
+.form-button,
+.form-submit {
   margin: 2em 0.5em 1em 0; /* LTR */
 }
 
@@ -284,16 +324,20 @@ div.messages {
 .confirmation .form-submit,
 .search-form .form-submit,
 .poll .form-submit,
-fieldset .form-button, fieldset .form-submit,
-.sidebar .form-button, .sidebar .form-submit,
-table .form-button, table .form-submit {
+fieldset .form-button,
+fieldset .form-submit,
+.sidebar .form-button,
+.sidebar .form-submit,
+table .form-button,
+table .form-submit {
   margin: 0;
 }
 
 /**
  * Skip link
  */
-#skip-link a:link, #skip-link a:visited {
+#skip-link a:link,
+#skip-link a:visited {
   font-weight: bold;
   background: #fff;
   padding: 0px 5px;
@@ -305,7 +349,9 @@ table .form-button, table .form-submit {
   position: absolute;
 }
 
-#skip-link a:hover, #skip-link a:focus, #skip-link a:active  {
+#skip-link a:hover,
+#skip-link a:focus,
+#skip-link a:active  {
   height: auto;
   width: auto;
   overflow: visible;
@@ -348,7 +394,8 @@ table .form-button, table .form-submit {
   display: none;
 }
 
-.region-header p, .region-header img {
+.region-header p,
+.region-header img {
   margin-top: 0.5em;
 }
 
@@ -356,7 +403,9 @@ table .form-button, table .form-submit {
   margin: 0 1em 0 0; /* LTR */
 }
 
-.region-header h3, .region-header label, .region-header li {
+.region-header h3,
+.region-header label,
+.region-header li {
   margin: 0 1em;
   padding: 0;
   background: none;
@@ -395,7 +444,9 @@ body.fluid-width #wrapper #container {
   position: absolute;
 }
 
-#branding, #branding a:link, #branding a:visited {
+#branding,
+#branding a:link,
+#branding a:visited {
   line-height: 120px;
   position: relative;
   z-index: 2;
@@ -417,7 +468,8 @@ body.two-sidebars {
   min-width: 980px;
 }
 /* With 2 columns, require a minimum width of 800px. */
-body.sidebar-first, body.sidebar-second {
+body.sidebar-first,
+body.sidebar-second {
   min-width: 780px;
 }
 
@@ -549,7 +601,9 @@ div#branding strong {
    font-weight: normal;
 }
 
-#branding, #branding a:link, #branding a:visited {
+#branding,
+#branding a:link,
+#branding a:visited {
   color: #fff;
   text-shadow: #1659ac 0px 1px 3px;
   font-size: 1.5em;
@@ -563,7 +617,8 @@ div#branding strong {
   font-size: 0.92em;
 }
 
-#wrapper #container .breadcrumb, #wrapper #container .breadcrumb a {
+#wrapper #container .breadcrumb,
+#wrapper #container .breadcrumb a {
   color: #529ad6;
 }
 
@@ -602,7 +657,9 @@ ul.main-menu li {
   background-image: none;
 }
 
-ul.main-menu li a, ul.main-menu li a:link, ul.main-menu li a:visited {
+ul.main-menu li a,
+ul.main-menu li a:link,
+ul.main-menu li a:visited {
   display: block;
   margin: 0 1em;
   padding: .75em 0 0;
@@ -610,7 +667,8 @@ ul.main-menu li a, ul.main-menu li a:link, ul.main-menu li a:visited {
   background: transparent url(images/bg-navigation-item.png) no-repeat 50% 0;
 }
 
-ul.main-menu li a:hover, ul.main-menu li a.active {
+ul.main-menu li a:hover,
+ul.main-menu li a.active {
   color: #fff;
   background: transparent url(images/bg-navigation-item-hover.png) no-repeat 50% 0;
 }
@@ -634,7 +692,9 @@ ul.secondary-menu li {
   background-image: none;
 }
 
-ul.secondary-menu li a, ul.secondary-menu li a:link, ul.secondary-menu li a:visited {
+ul.secondary-menu li a,
+ul.secondary-menu li a:link,
+ul.secondary-menu li a:visited {
   display: block;
   margin: 0 1em;
   padding: .75em 0 0;
@@ -642,7 +702,8 @@ ul.secondary-menu li a, ul.secondary-menu li a:link, ul.secondary-menu li a:visi
   background: transparent;
 }
 
-ul.secondary-menu li a:hover, ul.secondary-menu li a.active {
+ul.secondary-menu li a:hover,
+ul.secondary-menu li a.active {
   color: #cde3f1;
   background: transparent;
 }
@@ -650,7 +711,10 @@ ul.secondary-menu li a:hover, ul.secondary-menu li a.active {
 /**
  * Local tasks
  */
-ul.primary, ul.primary li, ul.secondary, ul.secondary li {
+ul.primary,
+ul.primary li,
+ul.secondary,
+ul.secondary li {
   border: 0;
   background: none;
   margin: 0;
@@ -680,8 +744,14 @@ h1.with-tabs {
   padding: 0;
 }
 
-ul.primary li a, ul.primary li.active a, ul.primary li a:hover, ul.primary li a:visited,
-ul.secondary li a, ul.secondary li.active a, ul.secondary li a:hover, ul.secondary li a:visited {
+ul.primary li a,
+ul.primary li.active a,
+ul.primary li a:hover,
+ul.primary li a:visited,
+ul.secondary li a,
+ul.secondary li.active a,
+ul.secondary li a:hover,
+ul.secondary li a:visited {
   border: 0;
   background: transparent;
   padding: 4px 1em;
@@ -692,8 +762,14 @@ ul.secondary li a, ul.secondary li.active a, ul.secondary li a:hover, ul.seconda
   top: -1px;
   display: inline-block;
 }
-ul.primary li.active a, ul.primary li.active a:link, ul.primary li.active a:visited, ul.primary li a:hover,
-ul.secondary li.active a, ul.secondary li.active a:link, ul.secondary li.active a:visited, ul.secondary li a:hover {
+ul.primary li.active a,
+ul.primary li.active a:link,
+ul.primary li.active a:visited,
+ul.primary li a:hover,
+ul.secondary li.active a,
+ul.secondary li.active a:link,
+ul.secondary li.active a:visited,
+ul.secondary li a:hover {
   background: url(images/bg-tab.png) repeat-x 0 50%;
   color: #fff;
 }
@@ -711,7 +787,8 @@ ul.secondary li.active a {
   padding: 1.5em 16px;
 }
 
-ul.links li, ul.inline li {
+ul.links li,
+ul.inline li {
   margin-left: 0;
   margin-right: 0;
   padding-left: 0; /* LTR */
@@ -719,8 +796,10 @@ ul.links li, ul.inline li {
   background-image: none;
 }
 
-.node .links, .comment .links {
+.node .links,
+.comment .links {
   text-align: left; /* LTR */
+  padding-left: 0; /* LTR */
 }
 
 .user-picture,
@@ -737,7 +816,9 @@ ul.links li, ul.inline li {
   float: right; /* LTR */
 }
 
-.preview .node, .preview .comment, .node-sticky {
+.preview .node,
+.preview .comment,
+.node-sticky {
   margin: 0;
   padding: 0.5em 0;
   border: 0;
@@ -779,7 +860,8 @@ ul.links li, ul.inline li {
   color: #494949;
 }
 
-.node .content, .comment .content {
+.node .content,
+.comment .content {
   margin: 0.6em 0;
 }
 
@@ -954,7 +1036,8 @@ div.vertical-tabs ul.vertical-tabs-list li.selected a strong {
   padding-right: 20px; /* LTR */
 }
 
-#block-node-syndicate img, .feed-icon {
+#block-node-syndicate img,
+.feed-icon {
   float: right; /* LTR */
   padding-top: 4px;
 }
@@ -972,6 +1055,15 @@ div.vertical-tabs ul.vertical-tabs-list li.selected a strong {
 #user-login-form ul {
   text-align: left; /* LTR */
 }
+#user-login .openid-links {
+  padding: 0;
+}
+#user-login-form .openid-links {
+  padding-left: 0.5em; /* LTR */
+}
+#user-login-form .openid-links li.user-link {
+  padding-left: 1em; /* LTR */
+}
 
 /**
  * User profiles.
@@ -1045,12 +1137,16 @@ table.system-status-report th {
   border-color: #d3e7f4;
 }
 
-#autocomplete li.selected, tr.selected td, tr.selected td.active {
+#autocomplete li.selected,
+tr.selected td,
+tr.selected td.active {
   background: #027ac6;
   color: #fff;
 }
 
-tr.selected td a:link, tr.selected td a:visited, tr.selected td a:active {
+tr.selected td a:link,
+tr.selected td a:visited,
+tr.selected td a:active {
   color: #d3e7f4;
 }
 
@@ -1104,7 +1200,8 @@ div.error {
   border: 1px solid #d77;
 }
 
-div.error, tr.error {
+div.error,
+tr.error {
   color: #a30000;
   background-color: #FFCCCC;
 }
@@ -1115,7 +1212,8 @@ div.warning {
   color: #220;
 }
 
-.form-item input.error, .form-item textarea.error {
+.form-item input.error,
+.form-item textarea.error {
   border: 1px solid #c52020;
   color: #363636;
 }
@@ -1154,26 +1252,31 @@ tr.dblog-error {
 tr.dblog-error td.active {
   background-color: #fbdbdb;
 }
-tr.dblog-page-not-found, tr.dblog-access-denied {
+tr.dblog-page-not-found,
+tr.dblog-access-denied {
   background: #d7ffd7;
 }
-tr.dblog-page-not-found td.active, tr.dblog-access-denied td.active {
+tr.dblog-page-not-found td.active,
+tr.dblog-access-denied td.active {
   background: #c7eec7;
 }
 
 /**
  * Status report colors.
  */
-table.system-status-report tr.error, table.system-status-report tr.error th {
+table.system-status-report tr.error,
+table.system-status-report tr.error th {
   background-color: #fcc;
   border-color: #ebb;
   color: #200;
 }
-table.system-status-report tr.warning, table.system-status-report tr.warning th {
+table.system-status-report tr.warning,
+table.system-status-report tr.warning th {
   background-color: #ffd;
   border-color: #eeb;
 }
-table.system-status-report tr.ok, table.system-status-report tr.ok th {
+table.system-status-report tr.ok,
+table.system-status-report tr.ok th {
   background-color: #dfd;
   border-color: #beb;
 }
diff --git a/themes/seven/ie6.css b/themes/seven/ie6.css
index 6133fe7d204c95eb7df0d447a8645f127dffcbba..0e7d7483e40f18d9083e54585af12701ec104382 100644
--- a/themes/seven/ie6.css
+++ b/themes/seven/ie6.css
@@ -1,4 +1,4 @@
-/* $Id: ie6.css,v 1.5 2010/03/05 15:23:25 dries Exp $ */
+/* $Id: ie6.css,v 1.6 2010/04/28 20:08:39 dries Exp $ */
 
 ul.menu li,
 ul.menu li a,
@@ -8,11 +8,13 @@ ul.links li a,
 #page {
   height: 1%;
 }
-#block-system-main ul.node-type-list li a, #block-system-main ul.admin-list li a {
+#block-system-main ul.node-type-list li a,
+#block-system-main ul.admin-list li a {
   height: 1px;
   position: relative;
   display: block;
 }
-#block-system-main ul.node-type-list li div.description a, #block-system-main ul.admin-list li div.description a {
+#block-system-main ul.node-type-list li div.description a,
+#block-system-main ul.admin-list li div.description a {
   display: inline;
 }
diff --git a/themes/seven/reset.css b/themes/seven/reset.css
index c2d04a47d7989ca244aa3bbac9e14983bc050940..aa9c8044abc0cd5f68f67d207b938703ef461673 100644
--- a/themes/seven/reset.css
+++ b/themes/seven/reset.css
@@ -1,4 +1,4 @@
-/* $Id: reset.css,v 1.8 2010/04/12 17:33:35 webchick Exp $ */
+/* $Id: reset.css,v 1.9 2010/04/28 20:08:39 dries Exp $ */
 
 /**
  * Reset CSS styles.
@@ -150,7 +150,8 @@ q {
 }
 blockquote:before,
 blockquote:after,
-q:before, q:after {
+q:before,
+q:after {
   content: '';
   content: none;
 }
diff --git a/themes/seven/seven.info b/themes/seven/seven.info
index 81afb59956cd09375ac42556b116b880874ecd46..b719a4355cc886914681cdcbf4e09495b83affb6 100644
--- a/themes/seven/seven.info
+++ b/themes/seven/seven.info
@@ -15,8 +15,8 @@ regions[page_bottom] = Page bottom
 regions[sidebar_first] = First sidebar
 regions_hidden[] = sidebar_first
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/themes/seven/style.css b/themes/seven/style.css
index 709c8ed454235cc995903db5a6e35cecadddcd8b..fcf02f78831e2c09ce51834030034295c0da4653 100644
--- a/themes/seven/style.css
+++ b/themes/seven/style.css
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.52 2010/04/26 13:33:43 dries Exp $ */
+/* $Id: style.css,v 1.57 2010/05/05 16:41:57 dries Exp $ */
 
 /**
  * Generic elements.
@@ -28,7 +28,12 @@ hr {
 legend {
   font-weight: bold;
 }
-h1, h2, h3, h4, h5, h6 {
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
   font-weight: bold;
   margin: 10px 0;
 }
@@ -67,10 +72,13 @@ blockquote {
 address {
   font-style: italic;
 }
-u, ins {
+u,
+ins {
   text-decoration: underline;
 }
-s, strike, del {
+s,
+strike,
+del {
   text-decoration: line-through;
 }
 big {
@@ -92,15 +100,21 @@ sup {
 nobr {
   white-space: nowrap;
 }
-abbr, acronym {
+abbr,
+acronym {
   border-bottom: dotted 1px;
 }
-ul, .block ul, .item-list ul, .item-list ul {
+ul,
+.block ul,
+.item-list ul,
+.item-list ul {
   list-style-type: disc;
   list-style-image: none;
-  margin: 0.25em 0 0.25em 1.5em;
+  margin: 0.25em 0 0.25em 1.5em; /* LTR */
 }
-.item-list ul li, li.leaf, ul.menu li {
+.item-list ul li,
+li.leaf,
+ul.menu li {
   list-style-type: disc;
   list-style-image: none;
 }
@@ -111,18 +125,23 @@ ol {
   list-style-type: decimal;
   margin: 0.25em 0 0.25em 2em;
 }
-.item-list ul li.collapsed, ul.menu li.collapsed {
+.item-list ul li.collapsed,
+ul.menu li.collapsed {
   list-style-image:url(../../misc/menu-collapsed.png);
   list-style-type:disc;
 }
-.item-list ul li.expanded, ul.menu li.expanded {
+.item-list ul li.expanded,
+ul.menu li.expanded {
   list-style-image:url(../../misc/menu-expanded.png);
   list-style-type:circle;
 }
-quote, code {
+quote,
+code {
   margin: .5em 0;
 }
-code, pre, kbd {
+code,
+pre,
+kbd {
   font-size: 1.25em;
 }
 
@@ -325,27 +344,28 @@ ul.secondary {
   clear: both;
   font-size: 12px;
   text-align: right;
-  padding: 5px 10px 4px;
-  line-height: 20px;
+  padding: 4px 10px 10px;
+  line-height: 18px;
   overflow: hidden;
-  border-bottom: 1px solid #ccc;
-  background: #fff;
+  background-color: #fff;
 }
 ul.secondary li {
   padding-left: 10px;
 }
 ul.secondary li a {
-  color: #05a;
+  background-color: #ddd;
+  color: #000;
 }
 ul.secondary li a,
 ul.secondary li a:hover,
 ul.secondary li.active a,
 ul.secondary li.active a.active {
-  padding: 0 10px;
+  padding: 2px 10px;
   border-radius: 7px;
-  -moz-border-radius: 10px;
+  -moz-border-radius: 7px;
   -webkit-border-radius: 7px;
 }
+ul.secondary li a:hover,
 ul.secondary li.active a,
 ul.secondary li.active a.active {
   color: #fff;
@@ -430,7 +450,8 @@ ul.admin-list li:last-child {
 ul.node-type-list .label {
   font-size: 15px;
 }
-ul.node-type-list li a, ul.admin-list li a {
+ul.node-type-list li a,
+ul.admin-list li a {
   margin-left: -30px;
   padding: 0px 0 4px 30px;
   min-height: 0;
@@ -439,7 +460,8 @@ ul.admin-list.compact li a {
   margin-left: 0;
   padding: 0;
 }
-ul.node-type-list li div.description a, ul.admin-list li div.description a {
+ul.node-type-list li div.description a,
+ul.admin-list li div.description a {
   margin-left: 0px;
   padding: 0px;
   min-height: inherit;
@@ -454,28 +476,15 @@ table {
   margin: 0 0 10px;
   border: 1px solid #bebfb9;
 }
-table.system-status-report th,
 table td,
 table th {
   vertical-align: middle;
   padding: 8px 10px;
+  border: 0;
+  color: #000;
 }
-table.system-status-report th {
-  padding-left: 30px;
-}
-table.system-status-report tr.ok > * {
-  background-color: #dfd;
-}
-table.system-status-report tr.info > * {
-  background-color: #bdf;
-}
-table.system-status-report tr.warning > * {
-  background-color: #ffd;
-}
-table.system-status-report tr.error > * {
-  background-color: #fdd;
-}
-tr.even, tr.odd {
+tr.even,
+tr.odd {
   border-width: 0 1px 0 1px;
   border-style: solid;
   border-color: #bebfb9;
@@ -500,7 +509,6 @@ table th {
   border-color: #bebfb9;
   padding: 3px 10px;
 }
-
 table th.active {
   background: #bdbeb9;
 }
@@ -524,7 +532,21 @@ table tr.selected td {
   background: #ffc;
   border-color: #eeb;
 }
-
+table.system-status-report tr {
+ border-bottom: 1px solid #bebfb9;
+}
+table.system-status-report tr.ok td {
+  background-color: #dfd;
+}
+table.system-status-report tr.info td {
+  background-color: #bdf;
+}
+table.system-status-report tr.warning td {
+  background-color: #ffd;
+}
+table.system-status-report tr.error td {
+  background-color: #fdd;
+}
 /**
  * Fieldsets.
  *
@@ -632,10 +654,12 @@ div.description,
 ul.tips li {
   margin: 0.25em 0 0.25em 1.5em;
 }
-body div.form-type-radio div.description, body div.form-type-checkbox div.description {
+body div.form-type-radio div.description,
+body div.form-type-checkbox div.description {
   margin-left: 1.5em;
 }
-input.form-submit, a.button {
+input.form-submit,
+a.button {
   cursor: pointer;
   padding: 4px 17px;
   margin-bottom: 1em;
@@ -653,7 +677,10 @@ input.form-submit, a.button {
   -moz-border-radius: 20px;
   -webkit-border-radius: 15px;
 }
-a.button:link, a.button:visited, a.button:hover, a.button:active {
+a.button:link,
+a.button:visited,
+a.button:hover,
+a.button:active {
   text-decoration: none;
   color: #5a5a5a;
 }
@@ -881,8 +908,7 @@ ol.task-list li.done {
 }
 .overlay ul.secondary {
   background: transparent none;
-  margin: -2.4em 0 0.5em 0;
-  padding: 3px 10px;
+  margin: -2.4em 0 0.3em 0;
 }
 .overlay #content {
   padding: 0;
@@ -925,3 +951,11 @@ div.add-or-remove-shortcuts {
 #block-node-recent .more-link {
   padding: 0 5px 5px 0;
 }
+
+/* User login block */
+#user-login-form .openid-links {
+  margin-left: 0; /* LTR */
+}
+#user-login-form .openid-links .user-link {
+  margin-left: 1.5em; /* LTR */
+}
diff --git a/themes/seven/template.php b/themes/seven/template.php
index 1b86efdf418dbd86c1f047e551748ac919a6ea9e..09773e2aee8fec61b08cf84019e2586ed0e8c725 100644
--- a/themes/seven/template.php
+++ b/themes/seven/template.php
@@ -1,5 +1,17 @@
 <?php
-// $Id: template.php,v 1.16 2010/04/21 06:55:23 webchick Exp $
+// $Id: template.php,v 1.17 2010/05/12 09:22:24 dries Exp $
+
+/**
+ * Override or insert variables into the maintenance page template.
+ */
+function seven_preprocess_maintenance_page(&$vars) {
+  // While markup for normal pages is split into page.tpl.php and html.tpl.php,
+  // the markup for the maintenance page is all in the single
+  // maintenance-page.tpl.php template. So, to have what's done in
+  // seven_preprocess_html() also happen on the maintenance page, it has to be
+  // called here.
+  seven_preprocess_html($vars);
+}
 
 /**
  * Override or insert variables into the html template.
diff --git a/themes/stark/stark.info b/themes/stark/stark.info
index fe6b2a0433247472f802a5c6f881f46de4a9a66e..62661c61319582f2d84abd261e208cd19bb0f770 100644
--- a/themes/stark/stark.info
+++ b/themes/stark/stark.info
@@ -7,8 +7,8 @@ core = 7.x
 engine = phptemplate
 stylesheets[all][] = layout.css
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/themes/tests/test_theme/test_theme.info b/themes/tests/test_theme/test_theme.info
index 78a9ddcb8a4dd25cb96d382aa4bf1967fedc0747..d1d76d73e51c6ca8e646cb0861e20ec3d2ddd284 100644
--- a/themes/tests/test_theme/test_theme.info
+++ b/themes/tests/test_theme/test_theme.info
@@ -4,8 +4,8 @@ description = Theme for testing the theme system
 core = 7.x
 engine = phptemplate
 hidden = TRUE
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/themes/tests/update_test_basetheme/update_test_basetheme.info b/themes/tests/update_test_basetheme/update_test_basetheme.info
index 6ce7e183b651d6b06774b5b75c20d7550e31ac92..86fcb269f82e5b33881c15898864d6b592e98181 100644
--- a/themes/tests/update_test_basetheme/update_test_basetheme.info
+++ b/themes/tests/update_test_basetheme/update_test_basetheme.info
@@ -5,8 +5,8 @@ core = 7.x
 engine = phptemplate
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/themes/tests/update_test_subtheme/update_test_subtheme.info b/themes/tests/update_test_subtheme/update_test_subtheme.info
index 636987892579d7f5b0a122cc5702f9a11a1e4198..00a72491d0a57d347ddb52300d07fbebd7acb5a8 100644
--- a/themes/tests/update_test_subtheme/update_test_subtheme.info
+++ b/themes/tests/update_test_subtheme/update_test_subtheme.info
@@ -6,8 +6,8 @@ engine = phptemplate
 base theme = update_test_basetheme
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-04-26
-version = "7.0-alpha4"
+; Information added by drupal.org packaging script on 2010-05-23
+version = "7.0-alpha5"
 project = "drupal"
-datestamp = "1272318008"
+datestamp = "1274628610"
 
diff --git a/update.php b/update.php
index 5277061427e4e9232095b3bb4f11e97d7e5d51a2..1554e05e194e04651074ae11a1a7e645e89b862a 100644
--- a/update.php
+++ b/update.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.php,v 1.320 2010/04/24 14:49:13 dries Exp $
+// $Id: update.php,v 1.323 2010/05/18 18:11:12 dries Exp $
 
 /**
  * Root directory of Drupal installation.
@@ -226,7 +226,7 @@ function update_info_page() {
   update_task_list('info');
   drupal_set_title('Drupal database update');
   $token = drupal_get_token('update');
-  $output = '<p>Use this utility to update your database whenever a new release of Drupal or a module is installed.</p><p>For more detailed information, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>';
+  $output = '<p>Use this utility to update your database whenever a new release of Drupal or a module is installed.</p><p>For more detailed information, see the <a href="http://drupal.org/upgrade">upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>';
   $output .= "<ol>\n";
   $output .= "<li><strong>Back up your database</strong>. This process will change your database values and in case of emergency you may need to revert to a backup.</li>\n";
   $output .= "<li><strong>Back up your code</strong>. Hint: when backing up module code, do not leave that backup in the 'modules' or 'sites/*/modules' directories as this may confuse Drupal's auto-discovery mechanism.</li>\n";
@@ -268,7 +268,7 @@ function update_access_allowed() {
   // Calls to user_access() might fail during the Drupal 6 to 7 update process,
   // so we fall back on requiring that the user be logged in as user #1.
   try {
-    require_once drupal_get_path('module', 'user') . '/user.module';
+    require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'user') . '/user.module';
     return user_access('administer software updates');
   }
   catch (Exception $e) {
@@ -333,6 +333,7 @@ ini_set('display_errors', FALSE);
 require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
 require_once DRUPAL_ROOT . '/includes/update.inc';
 require_once DRUPAL_ROOT . '/includes/common.inc';
+require_once DRUPAL_ROOT . '/includes/file.inc';
 require_once DRUPAL_ROOT . '/includes/entity.inc';
 require_once DRUPAL_ROOT . '/includes/unicode.inc';
 update_prepare_d7_bootstrap();
@@ -346,7 +347,6 @@ drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
 $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
 if (empty($op) && update_access_allowed()) {
   require_once DRUPAL_ROOT . '/includes/install.inc';
-  require_once DRUPAL_ROOT . '/includes/file.inc';
   require_once DRUPAL_ROOT . '/modules/system/system.install';
 
   // Load module basics.