diff --git a/.htaccess.sample b/.htaccess.sample
index 0ac673e08ebd3ae3329d7117d7c3f4a36f3d3461..9cd0e98f20a39d4dc745705af278cc8525d47f3a 100644
--- a/.htaccess.sample
+++ b/.htaccess.sample
@@ -13,6 +13,9 @@ Options -Indexes
 # Follow symbolic links in this directory.
 Options +FollowSymLinks
 
+# Multiviews creates problems with aliased URLs and is not needed for Drupal.
+Options -Multiviews
+
 # Make Drupal handle any 404 errors.
 ErrorDocument 404 /index.php
 
@@ -146,4 +149,4 @@ DirectoryIndex index.php index.html index.htm
   </IfModule>
 </IfModule>
 
-# $Id: .htaccess,v 1.110 2010/10/11 23:49:48 dries Exp $
+# $Id: .htaccess,v 1.111 2010/11/23 02:59:05 dries Exp $
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 3ba64860ce22940ea233cb35ed876f9b1b0235bd..9807f2eb407c98f59d3c1baa97ef310b36b2d3e3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,6 +1,6 @@
-// $Id: CHANGELOG.txt,v 1.375 2010/10/23 05:30:57 webchick Exp $
+// $Id: CHANGELOG.txt,v 1.396 2011/01/05 06:17:58 webchick Exp $
 
-Drupal 7.0 beta 2, 2010-10-22 (development version)
+Drupal 7.0, 2011-01-05
 ----------------------
 - Database:
     * Fully rewritten database layer utilizing PHP 5's PDO abstraction layer.
@@ -114,13 +114,14 @@ Drupal 7.0 beta 2, 2010-10-22 (development version)
       on as contributed themes (http://drupal.org/project/bluemarine,
       http://drupal.org/project/chameleon and http://drupal.org/project/pushbutton).
     * Added Stark theme to make analyzing Drupal's default HTML and CSS easier.
-    * Added Seven theme as the default administration interface theme.
+    * Added Seven as the default administration theme.
     * Variable preprocessing of theme hooks prior to template rendering now goes
       through two phases: a 'preprocess' phase and a new 'process' phase. See
       http://api.drupal.org/api/function/theme/7 for details.
     * Theme hooks implemented as functions (rather than as templates) can now
       also have preprocess (and process) functions. See
       http://api.drupal.org/api/function/theme/7 for details.
+    * Added Bartik as the default theme.
 - File handling:
     * Files are now first class Drupal objects with file_load(), file_save(),
       and file_validate() functions and corresponding hooks.
@@ -189,9 +190,9 @@ Drupal 7.0 beta 2, 2010-10-22 (development version)
     * The translation system now supports message context (msgctxt).
     * Added support for translatable fields to Field API.
 - JavaScript changes
-    * Upgraded the core JavaScript library to jQuery version 1.4.2.
-    * Upgraded the jQuery Forms library to 2.36.
-    * Added jQuery UI 1.8, which allows improvements to Drupal's user
+    * Upgraded the core JavaScript library to jQuery version 1.4.4.
+    * Upgraded the jQuery Forms library to 2.52.
+    * Added jQuery UI 1.8.7, which allows improvements to Drupal's user
       experience.
 - Better module version support
     * Modules now can specify which version of another module they depend on.
diff --git a/INSTALL.sqlite.txt b/INSTALL.sqlite.txt
index 92ccb1129633a8b7e562e9a3498d92a80594c316..9c4f754a8c65d7732eeebf3bbd63766f109bcbc5 100644
--- a/INSTALL.sqlite.txt
+++ b/INSTALL.sqlite.txt
@@ -1,4 +1,4 @@
-// $Id: INSTALL.sqlite.txt,v 1.3 2010/09/01 02:39:57 dries Exp $
+// $Id: INSTALL.sqlite.txt,v 1.4 2010/11/29 02:55:57 webchick Exp $
 
 SQLITE REQUIREMENTS
 -------------------
@@ -16,13 +16,13 @@ the database file resides. This directory (not just the database file) also has
 to remain writeable by the web server going forward for SQLite to continue to be
 able to operate.
 
-On the "Database configuration" form in the "Database name" field, you must
+On the "Database configuration" form in the "Database file" field, you must
 supply the exact path to where you wish your database file to reside. It is
 strongly suggested that you choose a path that is outside of the webroot, yet
 ensure that the directory is writeable by the web server.
 
 If you must place your database file in your webroot, you could try using the
-following in your "Database name" field:
+following in your "Database file" field:
 
   sites/default/files/.ht.sqlite
 
@@ -30,8 +30,3 @@ Note: The .ht in the name will tell Apache to prevent the database from being
 downloaded. Please check that the file is, indeed, protected by your webserver.
 If not, please consult the documentation of your webserver on how to protect a
 file from downloading.
-
-USERNAME, PASSWORD, and ADVANCED OPTIONS
-----------------------------------------
-No username, password, or advanced options are necessary, and they should not be
-used.
diff --git a/INSTALL.txt b/INSTALL.txt
index 09931ed3e9dc0d2fa7388c5efd88925b4049f078..95fa415604dc4959fed1d47507017b959afb72a4 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -1,23 +1,23 @@
-// $Id: INSTALL.txt,v 1.84 2010/10/11 23:49:48 dries Exp $
+// $Id: INSTALL.txt,v 1.87 2011/01/01 22:41:24 webchick Exp $
 
 CONTENTS OF THIS FILE
 ---------------------
 
- * Requirements
- * Optional tasks
+ * Requirements and notes
+ * Optional server requirements
  * Installation
- * Drupal administration
- * Customizing your theme(s)
+ * Building and customizing your site
  * Multisite configuration
  * More information
 
-REQUIREMENTS
-------------
+
+REQUIREMENTS AND NOTES
+----------------------
 
 Drupal requires:
 
 - A web server. Apache (version 2.0 or greater) is recommended.
-- PHP 5.2.0 (or greater) (http://www.php.net/).
+- PHP 5.2.4 (or greater) (http://www.php.net/).
 - One of the following databases:
   - MySQL 5.0.15 (or greater) (http://www.mysql.com/).
   - MariaDB 5.1.44 (or greater) (http://mariadb.org/). MariaDB is a fully
@@ -29,296 +29,298 @@ For more detailed information about Drupal requirements, including a list of
 PHP extensions and configurations that are required, see "System requirements"
 (http://drupal.org/requirements) in the Drupal handbook.
 
-For detailed information on how to configure a test server environment using
-a variety of operating systems and web servers, see "Local server setup"
+For detailed information on how to configure a test server environment using a
+variety of operating systems and web servers, see "Local server setup"
 (http://drupal.org/node/157602) in the Drupal handbook.
 
-OPTIONAL TASKS
---------------
+Note that all directories mentioned in this document are always relative to the
+directory of your Drupal installation, and commands are meant to be run from
+this directory (except for the initial commands that create that directory).
+
 
-- To use XML-based services such as the Blogger API and RSS syndication,
-  you will need PHP's XML extension. This extension is enabled by default.
+OPTIONAL SERVER REQUIREMENTS
+----------------------------
 
-- To use Drupal's "Clean URLs" feature on an Apache web server, you will need
-  the mod_rewrite module and the ability to use local .htaccess files. For
-  Clean URLs support on IIS, see "Using Clean URLs with IIS"
+- If you want to use Drupal's "Clean URLs" feature on an Apache web server, you
+  will need the mod_rewrite module and the ability to use local .htaccess
+  files. For Clean URLs support on IIS, see "Using Clean URLs with IIS"
   (http://drupal.org/node/3854) in the Drupal handbook.
 
+- If you plan to use XML-based services such as RSS aggregation, you will need
+  PHP's XML extension. This extension is enabled by default on most PHP
+  installations.
+
 - To serve gzip compressed CSS and JS files on an Apache web server, you will
   need the mod_headers module and the ability to use local .htaccess files.
 
-- Various Drupal features require that the web server process (for
-  example, httpd) be able to initiate outbound connections. This is usually
-  possible, but some hosting providers or server configurations forbid such
-  connections. The features that depend on this functionality include the
-  integrated "Update status" module (which downloads information about
-  available updates of Drupal core and any installed contributed modules and
-  themes), the ability to log in via OpenID, fetching aggregator feeds, or
-  other network-dependent services.
+- Some Drupal functionality (e.g., checking whether Drupal and contributed
+  modules need updates, RSS aggregation, etc.) require that the web server be
+  able to go out to the web and download information. If you want to use this
+  functionality, you need to verify that your hosting provider or server
+  configuration allows the web server to initiate outbound connections. Most web
+  hosting setups allow this.
 
 
 INSTALLATION
 ------------
 
-1. DOWNLOAD DRUPAL AND OPTIONALLY A TRANSLATION
+1. Download and extract Drupal.
+
+   You can obtain the latest Drupal release from http://drupal.org -- the files
+   are in .tar.gz format and can be extracted using most compression tools.
+
+   To download and extract the files, on a typical Unix/Linux command line, use
+   the following commands (assuming you want version x.y of Drupal):
 
-   You can obtain the latest Drupal release from http://drupal.org/. The files
-   are in .tar.gz format and can be extracted using most compression tools. On a
-   typical Unix command line, use:
+     wget http://drupal.org/files/projects/drupal-x.y.tar.gz
+     tar -zxvf drupal-x.y.tar.gz
 
-     wget http://drupal.org/files/projects/drupal-x.x.tar.gz
-     tar -zxvf drupal-x.x.tar.gz
+   This will create a new directory drupal-x.y/ containing all Drupal files and
+   directories. Then, to move the contents of that directory into a directory
+   within your web server's document root or your public HTML directory,
+   continue with this command:
 
-   This will create a new directory drupal-x.x/ containing all Drupal files
-   and directories. Move the contents of that directory into a directory within
-   your web server's document root or your public HTML directory:
+     mv drupal-x.y/* drupal-x.y/.htaccess /path/to/your/installation
 
-     mv drupal-x.x/* drupal-x.x/.htaccess /var/www/html
+2. Optionally, download a translation.
 
    By default, Drupal is installed in English, and further languages may be
-   installed later. Follow these steps to translate Drupal into your language
-   during installation:
+   installed later. If you prefer to install Drupal in another language
+   initially:
 
-   - Download a translation file for this Drupal version from the translation
-     server:
-     http://localize.drupal.org/download
+   - Download a translation file for the correct Drupal version and language
+     from the translation server: http://localize.drupal.org/download
 
-   - Rename the downloaded file to your language's ISO code (e.g., de.po or
-     fr.po) and place it into the directory /translations right below
-     the installation profile's directory that you want to use for your
-     installation (usually "standard"):
+   - Place the file into your installation profile's translations
+     directory. For instance, if you are using the Standard install profile,
+     move the .po file into the directory:
 
-       /profiles/standard/translations/
+       profiles/standard/translations/
 
-   - Reload the language selection page after adding translations.
+   For detailed instructions, visit http://drupal.org/localize
 
-   For detailed instructions, visit http://drupal.org/localize.
+3. Create the Drupal database.
 
-2. IF NECESSARY, CREATE THE CONFIGURATION FILE AND GRANT WRITE PERMISSIONS
+   Because Drupal stores all site information in a database, you must create
+   this database in order to install Drupal, and grant Drupal certain database
+   privileges (such as the ability to create tables). For details, consult
+   INSTALL.mysql.txt, INSTALL.pgsql.txt, or INSTALL.sqlite.txt. You may also
+   need to consult your web hosting provider for instructions specific to your
+   web host.
 
-   Drupal comes with a default.settings.php file in the sites/default
-   directory. The installer uses this file as a template to create your
-   settings file using the details you provide through the install process.
-   To avoid problems when upgrading, Drupal is not packaged with an actual
-   settings file. During installation, Drupal will try to create this settings
-   file automatically. If this fails (which it can due to different server
-   setups), you must create a file named settings.php yourself. You may do so
-   by making a copy of default.settings.php (or create an empty file with
-   this name in the same directory). For example, (from the installation
-   directory) make a copy of the default.settings.php file with the command:
+   Take note of the username, password, database name, and hostname as you
+   create the database. You will enter this information during the install.
 
-     cp sites/default/default.settings.php sites/default/settings.php
+4. Run the install script.
 
-   Next, give the web server write privileges to the sites/default/settings.php
-   file with the command (from the installation directory):
+   To run the install script, point your browser to the base URL of your
+   website (e.g., http://www.example.com).
 
-     chmod o+w sites/default/settings.php
+   You will be guided through several screens to set up the database, add the
+   site maintenance account (the first user, also known as user/1), and provide
+   basic web site settings.
 
-  So that the files directory can be created automatically, give the web server
-  write privileges to the sites/default directory with the command (from the
-  installation directory):
+   During installation, several files and directories need to be created, which
+   the install script will try to do automatically. However, on some hosting
+   environments, manual steps are required, and the install script will tell
+   you that it cannot proceed until you fix certain issues. This is normal and
+   does not indicate a problem with your server.
 
-     chmod o+w sites/default
+   The most common steps you may need to perform are:
 
-3. CREATE THE DRUPAL DATABASE
+   a. Missing files directory.
 
-   Drupal requires access to a database in order to be installed. Your database
-   user will need sufficient privileges to run Drupal. Additional information
-   about privileges, and instructions to create a database using the command
-   line are available in INSTALL.mysql.txt (for MySQL) or INSTALL.pgsql.txt
-   (for PostgreSQL).
+      The install script will attempt to create a file storage directory in
+      the default location at sites/default/files (the location of the files
+      directory may be changed after Drupal is installed).
 
-   To create a database using PHPMyAdmin or a web-based control panel consult
-   the documentation or ask your webhost service provider.
+      If auto-creation fails, you can make it work by changing permissions on
+      the sites/default directory so that the web server can create the files
+      directory within it for you. (If you are creating a multisite
+      installation, substitute the correct sites directory for sites/default;
+      see the Multisite Configuration section of this file, below.)
 
-   Take note of the username, password, database name and hostname as you
-   create the database. You will enter these items in the install script.
+      For example, on a Unix/Linux command line, you can grant everyone
+      (including the web server) permission to write to the sites/default
+      directory with this command:
 
-4. RUN THE INSTALL SCRIPT
+        chmod a+w sites/default
 
-   To run the install script point your browser to the base URL of your website
-   (e.g., http://www.example.com).
+      Be sure to set the permissions back after the installation is finished!
+      Sample command:
 
-   You will be guided through several screens to set up the database,
-   create tables, add the site maintenance account (the first user, also known
-   as user/1), and provide basic web site settings.
+        chmod go-w sites/default
 
-   The install script will attempt to create a files storage directory
-   in the default location at sites/default/files (the location of the
-   files directory may be changed after Drupal is installed). In some
-   cases, you may need to create the directory and modify its permissions
-   manually. Use the following commands (from the installation directory)
-   to create the public and private files directories and grant the web server
-   write privileges to them:
+      Alternatively, instead of allowing the web server to create the files
+      directory for you as described above, you can create it yourself. Sample
+      commands from a Unix/Linux command line:
 
-     mkdir sites/default/files
-     chmod o+w sites/default/files
-     mkdir sites/default/private
-     chmod o+w sites/default/private
+        mkdir sites/default/files
+        chmod a+w sites/default/files
 
-   The install script will attempt to write-protect the settings.php file and
-   the sites/default directory after saving your configuration. However, you
-   may need to manually write-protect them using the commands (from the
-   installation directory):
+   b. Missing settings file.
 
-     chmod a-w sites/default/settings.php
-     chmod a-w sites/default
+      Drupal will try to automatically create a settings.php configuration file,
+      which is normally in the directory sites/default (to avoid problems when
+      upgrading, Drupal is not packaged with this file). If auto-creation fails,
+      you will need to create this file yourself, using the file
+      sites/default/default.settings.php as a template.
 
-   If you make manual changes to the file later, be sure to protect it again
-   after making your modifications. Failure to remove write permissions to that
-   file is a security risk. Although the default location for the settings.php
-   file is at sites/default/settings.php, it may be in another location
-   if you use the multi-site setup, as explained below.
+      For example, on a Unix/Linux command line, you can make a copy of the
+      default.settings.php file with the command:
 
-5. CONFIGURE DRUPAL
+        cp sites/default/default.settings.php sites/default/settings.php
 
-   When the install script succeeds, you will be directed to the "Welcome"
-   page logged in with the site maintenance account. Proceed with the initial
-   configuration steps suggested on the "Welcome" page.
+      Next, grant write privileges to the file to everyone (including the web
+      server) with the command:
 
-   If the default Drupal theme is not displaying properly and links on the page
-   result in "Page Not Found" errors, try manually setting the $base_url variable
-   in the settings.php file if not already set. It's currently known that servers
-   running FastCGI can run into problems if the $base_url variable is left
-   commented out (see http://bugs.php.net/bug.php?id=19656).
+        chmod a+w sites/default/settings.php
 
-6. REVIEW FILE SYSTEM STORAGE SETTINGS AND FILE PERMISSIONS
+      Be sure to set the permissions back after the installation is finished!
+      Sample command:
 
-   The files directory created in step 4 is the default file system path used
-   to store all uploaded files, as well as some temporary files created by Drupal.
-   After installation, the settings for the file system path may be modified
-   to store uploaded files in a different location.
+        chmod go-w sites/default/settings.php
 
-   It is not necessary to modify this path, but you may wish to change it if:
+   c. Write permissions after install.
 
-     * your site runs multiple Drupal installations from a single codebase
-       (modify the file system path of each installation to a different
-       directory so that uploads do not overlap between installations); or,
+      The install script will attempt to write-protect the settings.php file and
+      the sites/default directory after saving your configuration. If this
+      fails, you will be notified, and you can do it manually. Sample commands
+      from a Unix/Linux command line:
 
-     * your site runs a number of web server front-ends behind a load
-       balancer or reverse proxy (modify the file system path on each
-       server to point to a shared file repository).
+        chmod go-w sites/default/settings.php
+        chmod go-w sites/default
 
-   To modify the file system path:
+5. Verify that the site is working.
+
+   When the install script finishes, you will be logged in with the site
+   maintenance account on a "Welcome" page. If the default Drupal theme is not
+   displaying properly and links on the page result in "Page Not Found" errors,
+   you may be experiencing problems with clean URLs. Visit
+   http://drupal.org/getting-started/clean-urls to troubleshoot.
+
+6. Change file system storage settings (optional).
+
+   The files directory created in step 4 is the default file system path used to
+   store all uploaded files, as well as some temporary files created by
+   Drupal. After installation, you can modify the file system path to store
+   uploaded files in a different location.
 
-     * Ensure that the new location for the path exists or create it if
-       necessary. To create a new directory named uploads, for example,
-       use the following command from a shell or system prompt (while in
-       the installation directory):
+   It is not necessary to modify this path, but you may wish to change it if:
+
+   - Your site runs multiple Drupal installations from a single codebase (modify
+     the file system path of each installation to a different directory so that
+     uploads do not overlap between installations).
 
-           mkdir uploads
+   - Your site runs on a number of web servers behind a load balancer or reverse
+     proxy (modify the file system path on each server to point to a shared file
+     repository).
 
-     * Ensure that the new location for the path is writable by the web
-       server process. To grant write permissions for a directory named
-       uploads, you may need to use the following command from a shell
-       or system prompt (while in the installation directory):
+   - You want to restrict access to uploaded files.
 
-           chmod o+w uploads
+   To modify the file system path:
 
-     * Access the file system path settings in Drupal by selecting these
-       menu items from the Navigation menu:
+   a. Ensure that the new location for the path exists and is writable by the
+      web server. For example, to create a new directory named uploads and grant
+      write permissions, use the following commands on a Unix/Linux command
+      line:
 
-           Administer > Site configuration > File system
+        mkdir uploads
+        chmod a+w uploads
 
-       Enter the path to the new location (e.g.: uploads) at the File
-       System Path prompt.
+   b. Navigate to Administration > Configuration > Media > File system, and
+      enter the desired path. Note that if you want to use private file storage,
+      you need to first enter the path for private files and save the
+      configuration, and then change the "Default download method" setting and
+      save again.
 
    Changing the file system path after files have been uploaded may cause
    unexpected problems on an existing site. If you modify the file system path
    on an existing site, remember to copy all files from the original location
    to the new location.
 
+7. Revoke documentation file permissions (optional).
+
    Some administrators suggest making the documentation files, especially
    CHANGELOG.txt, non-readable so that the exact version of Drupal you are
    running is slightly more difficult to determine. If you wish to implement
-   this optional security measure, use the following command from a shell or
-   system prompt (while in the installation directory):
+   this optional security measure, from a Unix/Linux command line you can use
+   the following command:
 
-          chmod a-r CHANGELOG.txt
+     chmod a-r CHANGELOG.txt
 
-   Note that the example only affects CHANGELOG.txt. To completely hide
-   all documentation files from public view, repeat this command for each of
-   the Drupal documentation files in the installation directory, substituting the
+   Note that the example only affects CHANGELOG.txt. To completely hide all
+   documentation files from public view, repeat this command for each of the
+   Drupal documentation files in the installation directory, substituting the
    name of each file for CHANGELOG.txt in the example.
 
-   For more information on setting file permissions, see "Modifying Linux, Unix,
-   and Mac file permissions" (http://drupal.org/node/202483) or "Modifying
-   Windows file permissions" (http://drupal.org/node/202491) in the online
-   handbook.
-
-7. CRON MAINTENANCE TASKS
+   For more information on setting file permissions, see "Modifying Linux,
+   Unix, and Mac file permissions" (http://drupal.org/node/202483) or
+   "Modifying Windows file permissions" (http://drupal.org/node/202491) in the
+   online handbook.
 
-   Many Drupal modules have periodic tasks that must be triggered by a cron
-   maintenance task, including search module (to build and update the index
-   used for keyword searching), aggregator module (to retrieve feeds from other
-   sites), and system module (to perform routine maintenance and pruning on
-   system tables).
+8. Set up independent "cron" maintenance jobs.
 
-   For most sites, the built-in, automated cron feature should be sufficient.
-   Note, however, that cron tasks will only be executed when there are site
-   visitors. You can enable the built-in cron feature at:
+   Many Drupal modules have tasks that must be run periodically, including the
+   Search module (building and updating the index used for keyword searching),
+   the Aggregator module (retrieving feeds from other sites), and the System
+   module (performing routine maintenance and pruning of database tables). These
+   tasks are known as "cron maintenance tasks", named after the Unix/Linux
+   "cron" utility.
 
-          Administer > Configuration > System > Site information
+   When you install Drupal, its built-in cron feature is enabled, which
+   automatically runs the cron tasks periodically, triggered by people visiting
+   pages of your site. You can configure the built-in cron feature by navigating
+   to Administration > Configuration > System > Cron.
 
-   Advanced users may want to ensure that cron tasks are executed periodically.
-   To do this, visit the page "cron.php", which executes maintenance tasks on
-   behalf of installed modules. The URL of the cron.php page requires a "cron
-   key" to protect against unauthorized access.
-   Each cron key is automatically generated during installation and is specific
-   to your site. The full URL of the page, with cron key, is available in the
-   "Cron maintenance tasks" section of the "Status report page" at:
+   It is also possible to run the cron tasks independent of site visits; this is
+   recommended for most sites. To do this, you will need to set up an automated
+   process to visit the page cron.php on your site, which executes the cron
+   tasks.
 
-          Administer > Reports > Status report
+   The URL of the cron.php page requires a "cron key" to protect against
+   unauthorized access. Your site's cron key is automatically generated during
+   installation and is specific to your site. The full URL of the page, with the
+   cron key, is available in the "Cron maintenance tasks" section of the Status
+   report page at Administration > Reports > Status report.
 
-   Most systems support using a crontab utility for automatically executing
-   tasks like visiting the cron.php page. The following example crontab line
-   uses wget to automatically visit the cron.php page each hour, on the hour:
+   As an example for how to set up this automated process, you can use the
+   crontab utility on Unix/Linux systems. The following crontab line uses the
+   wget command to visit the cron.php page, and runs each hour, on the hour:
 
-   0   *   *   *   *   wget -O - -q -t 1 http://www.example.com/cron.php?cron_key=RANDOMTEXT
+   0 * * * * wget -O - -q -t 1 http://example.com/cron.php?cron_key=YOURKEY
 
-   Replace the text "http://www.example.com/cron.php?cron_key=RANDOMTEXT" in the
+   Replace the text "http://example.com/cron.php?cron_key=YOURKEY" in the
    example with the full URL displayed under "Cron maintenance tasks" on the
    "Status report" page.
 
-   More information about cron maintenance tasks are available in the help pages
-   and in Drupal's online handbook at http://drupal.org/cron. Example cron scripts
-   can be found in the scripts/ directory. (Note that these scripts must be
-   customized similar to the above example, to add your site-specific cron key
-   and domain name.)
+   More information about cron maintenance tasks is available at
+   http://drupal.org/cron, and sample cron shell scripts can be found in the
+   scripts/ directory. (Note that these scripts must be customized like the
+   above example, to add your site-specific cron key and domain name.)
 
 
 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. 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:
+A new installation of Drupal defaults to a very basic configuration. To extend
+your site, you use "modules" and "themes". A module is a plugin that adds
+functionality to Drupal, while a theme changes the look of your site. The core
+of Drupal provides several optional modules and themes, and you can download
+more at http://drupal.org/project/modules and http://drupal.org/project/themes
 
-Modules:
-  sites/all/modules/example_module
+Do not mix downloaded or custom modules and themes with Drupal's core modules
+and themes. Drupal's modules and themes are located in the top-level modules and
+themes directories, while the modules and themes you add to Drupal are normally
+placed in the sites/all/modules and sites/all/themes directories. If you run a
+multisite installation, you can also place modules and themes in the
+site-specific directories -- see the Multisite Configuration section, below.
 
-Themes:
-  sites/all/themes/example_theme
-
-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.
-
-Contributed modules can be found at:
-http://drupal.org/project/Modules
-
-Contributed themes can be found at:
-http://drupal.org/project/Themes
-
-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
+Never edit Drupal's core modules and themes; instead, use the hooks available in
+the Drupal API. To modify the behavior of Drupal, develope a module as described
+at http://drupal.org/developing/modules. To modify the look of Drupal, create a
+subtheme as described at http://drupal.org/node/225125, or a completely new
+theme as described at http://drupal.org/documentation/theme
 
 
 MULTISITE CONFIGURATION
@@ -328,12 +330,13 @@ A single Drupal installation can host several Drupal-powered sites, each with
 its own individual configuration.
 
 Additional site configurations are created in subdirectories within the 'sites'
-directory. Each subdirectory must have a 'settings.php' file which specifies the
-configuration settings. The easiest way to create additional sites is to copy
-the 'default' directory and modify the 'settings.php' file as appropriate. The
-new directory name is constructed from the site's URL. The configuration for
-www.example.com could be in 'sites/example.com/settings.php' (note that 'www.'
-should be omitted if users can access your site at http://example.com/).
+directory. Each subdirectory must have a 'settings.php' file, which specifies
+the configuration settings. The easiest way to create additional sites is to
+copy the 'default' directory and modify the 'settings.php' file as
+appropriate. The new directory name is constructed from the site's URL. The
+configuration for www.example.com could be in 'sites/example.com/settings.php'
+(note that 'www.' should be omitted if users can access your site at
+http://example.com/).
 
 Sites do not have to have a different domain. You can also use subdomains and
 subdirectories for Drupal sites. For example, example.com, sub.example.com,
@@ -370,30 +373,32 @@ directory within the site configuration directory. For example, if
 sub.example.com has a custom theme and a custom module that should not be
 accessible to other sites, the setup would look like this:
 
-  sites/sub.example.com/:
-  settings.php
-  themes/custom_theme
-  modules/custom_module
+  sites/sub.example.com/
+    settings.php
+    themes/custom_theme
+    modules/custom_module
 
 NOTE: for more information about multiple virtual hosts or the configuration
-settings, consult the Drupal handbook at drupal.org.
+settings, consult http://drupal.org/getting-started/6/install/multi-site
 
-For more information on configuring Drupal's file system path in a multi-site
+For more information on configuring Drupal's file system path in a multisite
 configuration, see step 6 above.
 
+
 MORE INFORMATION
 ----------------
 
-- For additional documentation, see the online Drupal handbook at
-  http://drupal.org/handbook.
+- For additional documentation, see the online Drupal handbook:
+  http://drupal.org/handbook
 
 - For a list of security announcements, see the "Security announcements" page
   at http://drupal.org/security (available as an RSS feed). This page also
   describes how to subscribe to these announcements via e-mail.
 
-- For information about the Drupal security process, or to find out how to report
-  a potential security issue to the Drupal security team, see the "Security team"
-  page at http://drupal.org/security-team.
+- For information about the Drupal security process, or to find out how to
+  report a potential security issue to the Drupal security team, see the
+  "Security team" page at http://drupal.org/security-team
 
-- For information about the wide range of available support options, see the
-  "Support" page at http://drupal.org/support.
+- For information about the wide range of available support options, visit
+  http://drupal.org and click on Community and Support in the top or bottom
+  navigation.
diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt
index 69c63031521f7fcc3a0c448153e521f7a58bb0d4..d01cc4cbba6fdfa248a60a5cdec5bb01f8dea040 100644
--- a/MAINTAINERS.txt
+++ b/MAINTAINERS.txt
@@ -1,4 +1,4 @@
-// $Id: MAINTAINERS.txt,v 1.48 2010/09/30 13:28:08 dries Exp $
+// $Id: MAINTAINERS.txt,v 1.53 2011/01/04 01:03:23 webchick Exp $
 
 Drupal core is maintained by the community.  To participate, go to
 
@@ -54,6 +54,9 @@ Database system
     - Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
     - Károly Négyesi 'chx' <http://drupal.org/user/9446>
 
+Database update system
+- ?
+
 Entity system
 - Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
 - Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
@@ -90,7 +93,7 @@ Mail system
 - ?
 
 Markup
-- Jacine Rodriguez 'Jacine' <http://drupal.org/user/88931>
+- Jacine Luisi 'Jacine' <http://drupal.org/user/88931>
 - Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
 
 Menu system
@@ -110,13 +113,11 @@ Theme system
 - Earl Miles 'merlinofchaos' <http://drupal.org/user/26979>
 - Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
 - Joon Park 'dvessel' <http://drupal.org/user/56782>
+- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
 
 Token system
 - Dave Reid 'davereid' <http://drupal.org/user/53892>
 
-Update system
-- ?
-
 XML-RPC system
 - Frederic G. Marand 'fgm' <http://drupal.org/user/27985>
 
@@ -129,7 +130,7 @@ Accessibility
 - Brandon Bowersox 'brandonojc' <http://drupal.org/user/186415> 
 
 Documentation
-- Addison Berry 'add1sun' <http://drupal.org/user/65088>
+- Ariane Khachatourians 'arianek' <http://drupal.org/user/158886>
 - Jennifer Hodgdon 'jhodgdon' <http://drupal.org/user/155601>
 
 Security
@@ -150,7 +151,7 @@ Aggregator module
 - ?
 
 Block module
-- ?
+- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
 
 Blog module
 - ?
@@ -268,7 +269,6 @@ Trigger module
 
 Update module
 - Derek Wright 'dww' <http://drupal.org/user/46549>
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
 
 User module
 - Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
@@ -283,11 +283,10 @@ Bartik theme
 - Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
 
 Garland theme
-- ?
+- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
 
 Seven theme
 - Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
 
 Stark theme
-- John Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
-
+- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4cc75b3abf64968627a270d5732fa6c30cff6fe1
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,89 @@
+// $Id: README.txt,v 1.1 2010/12/02 00:20:18 webchick Exp $
+
+CONTENTS OF THIS FILE
+---------------------
+
+ * About Drupal
+ * Configuration and features
+ * Appearance
+ * Developing for Drupal
+
+ABOUT DRUPAL
+------------
+
+Drupal is an open source content management platform supporting a variety of
+websites ranging from personal weblogs to large community-driven websites. For
+more information, see the Drupal website at http://drupal.org/, and join the
+Drupal community at http://drupal.org/community.
+
+Legal information about Drupal:
+ * Know your rights when using Drupal:
+   See LICENSE.txt in the same directory as this document.
+ * Learn about the Drupal trademark and logo policy:
+   http://drupal.com/trademark
+
+CONFIGURATION AND FEATURES
+--------------------------
+
+Drupal core (what you get when you download and unzip a drupal-x.y.tar.gz file
+from http://drupal.org/project/drupal) has what you need to get started with
+your website. It includes several modules (extensions that add functionality)
+for common website features, such as managing content, user accounts, image
+uploading, and search. Core comes with many options that allow site-specific
+configuration. In addition to the core modules, there are thousands of
+contributed modules (for functionality not included with Drupal core)
+available for download.
+
+More about configuration:
+ * Install, upgrade, and maintain Drupal:
+   See INSTALL.txt and UPGRADE.txt in the same directory as this document.
+ * Learn about how to use Drupal to create your site:
+   http://drupal.org/documentation
+ * Download contributed modules to sites/all/modules to extend Drupal's
+   functionality:
+   http://drupal.org/project/modules
+ * See also: "Developing for Drupal" for writing your own modules, below.
+
+APPEARANCE
+----------
+
+In Drupal, the appearance of your site is set by the theme (themes are
+extensions that set fonts, colors, and layout). Drupal core comes with several
+themes. More themes are available for download, and you can also create your
+own custom theme.
+
+More about themes:
+ * Download contributed themes to sites/all/themes to modify Drupal's
+   appearance:
+   http://drupal.org/project/themes
+ * Develop your own theme:
+   http://drupal.org/documentation/theme
+
+DEVELOPING FOR DRUPAL
+---------------------
+
+Drupal contains an extensive API that allows you to add to and modify the
+functionality of your site. The API consists of "hooks", which allow modules to
+react to system events and customize Drupal's behavior, and functions that
+standardize common operations such as database queries and form generation. The
+flexible hook architecture means that you should never need to directly modify
+the files that come with Drupal core to achieve the functionality you want;
+instead, functionality modifications take the form of modules.
+
+When you need new functionality for your Drupal site, search for existing
+contributed modules. If you find a module that matches except for a bug or an
+additional needed feature, change the module and contribute your improvements
+back to the project in the form of a "patch". Create new custom modules only
+when nothing existing comes close to what you need.
+
+More about developing:
+ * Search for existing contributed modules:
+   http://drupal.org/project/modules
+ * Contribute a patch:
+   http://drupal.org/patch/submit
+ * Develop your own module:
+   http://drupal.org/developing/modules
+ * Follow best practices:
+   http://drupal.org/best-practices
+ * Refer to the API documentation:
+   http://api.drupal.org/api/drupal/7
diff --git a/UPGRADE.txt b/UPGRADE.txt
index fb87a70ee98ab8f7a596d1ba8f7f15988c1169d9..b84844c05827025b061f62cc1dfa9c9a75fa2478 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -1,11 +1,11 @@
-// $Id: UPGRADE.txt,v 1.26 2010/10/22 00:31:59 dries Exp $
+// $Id: UPGRADE.txt,v 1.27 2010/10/27 18:32:54 dries Exp $
 
 INTRODUCTION
 ------------
 This document describes how to:
 
   * Update your Drupal site from one minor 7.x version to another minor 7.x
-    version; for example, from 7.9 to 7.10.
+    version; for example, from 7.8 to 7.9, or from 7.6 to 7.10.
 
   * Upgrade your Drupal site's major version from 6.x to 7.x.
 
@@ -15,15 +15,16 @@ First steps and definitions:
     version number, and y is known as the minor version number. The download
     file will be named drupal-x.y.tar.gz.
 
-  * The "Don't hack core" principle is respected. If you modified core files
-    outside of the 'sites' directory, see http://drupal.org/node/144376.
-
-  * All directories mentioned in this document are always relative to the
-    directory of your Drupal installation.
+  * All directories mentioned in this document are relative to the directory of
+    your Drupal installation.
 
   * Make a full backup of all files, directories, and your database(s) before
-    starting. Instructions may be found at
-    http://drupal.org/upgrade/backing-up-the-db
+    starting, and save it outside your Drupal installation directory.
+    Instructions may be found at http://drupal.org/upgrade/backing-up-the-db
+
+  * It is wise to try an update or upgrade on a test copy of your site before
+    applying it to your live site. Even minor updates can cause your site's
+    behavior to change.
 
 
 UPGRADE PROBLEMS
@@ -36,29 +37,34 @@ If you encounter errors during this process,
     you created before you started the upgrade process. Do not attempt to do
     further upgrades on a site that had update problems.
 
-  * Consult one of the support options listed on http://drupal.org/support.
+  * Consult one of the support options listed on http://drupal.org/support
 
 More in-depth information on upgrading can be found at http://drupal.org/upgrade
 
 
 MINOR VERSION UPDATES
 ---------------------
-To update from one minor 7.x version of Drupal to another 7.x version, after
+To update from one minor 7.x version of Drupal to any later 7.x version, after
 following the instructions in the INTRODUCTION section at the top of this file:
 
 1. Log in as a user with the permission "Administer software updates".
-   IMPORTANT! Do not close your browser until the final step is complete.
 
-2. Go to Administer » Configuration » Development » Maintenance mode.
+2. Go to Administration > Configuration > Development > Maintenance mode.
    Enable the "Put site into maintenance mode" checkbox and save the
    configuration.
 
-3. Remove all old core files and directories, EXCEPT for the 'sites' directory
+3. Remove all old core files and directories, except for the 'sites' directory
    and any custom files you added elsewhere.
 
    If you made modifications to files like .htaccess or robots.txt, you will
    need to re-apply them from your backup, after the new files are in place.
 
+   Sometimes an update includes changes to settings.php (this will be noted in
+   the release announcement). If that's the case, replace your old settings.php
+   with the new one, and copy the site-specific entries (especially the lines
+   giving the database name, user, and password) from the old settings.php to
+   the new settings.php.
+
 4. Download the latest Drupal 7.x release from http://drupal.org to a
    directory outside of your web root. Extract the archive and copy the files
    into your Drupal directory.
@@ -88,7 +94,7 @@ following the instructions in the INTRODUCTION section at the top of this file:
 
    - Open settings.php with a text editor.
 
-   - There is a line that says:
+   - Find the line that says:
      $update_free_access = FALSE;
 
    - Change it into:
@@ -96,12 +102,12 @@ following the instructions in the INTRODUCTION section at the top of this file:
 
    - Once the upgrade is done, $update_free_access must be reverted to FALSE.
 
-7. Go to Administration » Reports » Status report. Verify that everything is
-   is working as expected.
+7. Go to Administration > Reports > Status report. Verify that everything is
+   working as expected.
 
 8. Ensure that $update_free_access is FALSE in settings.php.
 
-9. Go to Administration » Configuration » Development » Maintenance mode.
+9. Go to Administration > Configuration > Development > Maintenance mode.
    Disable the "Put site into maintenance mode" checkbox and save the
    configuration.
 
@@ -111,38 +117,44 @@ MAJOR VERSION UPGRADE
 To upgrade from a previous major version of Drupal to Drupal 7.x, after
 following the instructions in the INTRODUCTION section at the top of this file:
 
-1. Update to the latest available version of Drupal 6.x.
+1. Check on the Drupal 7 status of your contributed and custom modules and
+   themes. See http://drupal.org/node/948216 for information on upgrading
+   contributed modules and themes. See http://drupal.org/node/895314 for a list
+   of modules that have been moved into core for Drupal 7, and instructions on
+   how to update them. See http://drupal.org/update/modules for information on
+   how to update your custom modules, and http://drupal.org/update/theme for
+   custom themes.
 
-   If your current version is Drupal 5.x, you have to upgrade to 6.x first.
-   Download Drupal 6.x and follow the instructions in UPGRADE.txt instead.
-   This document only applies for upgrades from 6.x to 7.x.
+   You may decide at this point that you cannot upgrade your site, because
+   needed modules or themes are not ready for Drupal 7.
 
-2. Check the availability of your modules and themes for Drupal 7.x. See
-   http://drupal.org/node/948216
+2. Update to the latest available version of Drupal 6.x (if your current version
+   is Drupal 5.x, you have to upgrade to 6.x first). If you need to update,
+   download Drupal 6.x and follow the instructions in its UPGRADE.txt. This
+   document only applies for upgrades from 6.x to 7.x.
 
 3. Log in as user ID 1 (the site maintenance user).
 
-4. Go to Administer » Site configuration » Site maintenance. Select "Off-line"
-   and save the configuration.
+4. Go to Administer > Site configuration > Site maintenance. Select
+   "Off-line" and save the configuration.
 
-5. Go to Administer » Site building » Themes. Enable "Garland" and select it as
-   default theme.
+5. Go to Administer > Site building > Themes. Enable "Garland" and select it as
+   the default theme.
 
-6. Go to Administer » Site building » Modules. Disable all modules that are not
+6. Go to Administer > Site building > Modules. Disable all modules that are not
    listed under "Core - required" or "Core - optional". It is possible that some
    modules cannot be disabled, because others depend on them. Repeat this step
    until all non-core modules are disabled.
 
-   In case you already know that you will not re-enable some modules for Drupal
-   7.x and you no longer need their data, then you can uninstall them under the
-   Uninstall tab afterwards. See http://drupal.org/node/895314 for a list of
-   modules whose functionality has been moved into core for Drupal 7.x.
+   If you know that you will not re-enable some modules for Drupal 7.x and you
+   no longer need their data, then you can uninstall them under the Uninstall
+   tab after disabling them.
 
 7. On the command line or in your FTP client, remove the file
 
      sites/default/default.settings.php
 
-8. Remove all old core files and directories, EXCEPT for the 'sites' directory
+8. Remove all old core files and directories, except for the 'sites' directory
    and any custom files you added elsewhere.
 
    If you made modifications to files like .htaccess or robots.txt, you will
@@ -186,7 +198,7 @@ following the instructions in the INTRODUCTION section at the top of this file:
 
    - Open settings.php with a text editor.
 
-   - There is a line that says:
+   - Find the line that says:
      $update_free_access = FALSE;
 
    - Change it into:
@@ -196,25 +208,15 @@ following the instructions in the INTRODUCTION section at the top of this file:
 
 14. Backup your database after the core upgrade has run.
 
-15. Replace your non-core modules, following this procedure:
-
-   - Check your notes for any special upgrade instructions.
-   - Entirely delete the old module directory in sites/all/modules/.
-   - Download, extract, and move the new module directory to sites/all/modules/.
-
-16. Go to Administration » Modules. Re-enable your non-core modules.
-
-17. Re-run update.php.
-
-18. If applicable, return the site to its original theme following the same
-   procedure as in 15., but putting the theme in sites/all/themes/.
+15. Replace and update your non-core modules and themes, following the
+   procedures at http://drupal.org/node/948216
 
-19. Go to Administration » Reports » Status report. Verify that everything is
-   is working as expected.
+16. Go to Administration > Reports > Status report. Verify that everything is
+   working as expected.
 
-20. Ensure that $update_free_access is FALSE in settings.php.
+17. Ensure that $update_free_access is FALSE in settings.php.
 
-21. Go to Administration » Configuration » Development » Maintenance mode.
+18. Go to Administration > Configuration > Development > Maintenance mode.
    Disable the "Put site into maintenance mode" checkbox and save the
    configuration.
 
diff --git a/authorize.php b/authorize.php
index 02cf32ff642ebdba773c01d7bc8b5be95e1dda85..8eeccdd7b10c112d35e5e36fc9f59fddc831114c 100644
--- a/authorize.php
+++ b/authorize.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: authorize.php,v 1.8 2010/04/22 10:16:24 webchick Exp $
+// $Id: authorize.php,v 1.12 2010/12/29 04:07:52 webchick Exp $
 
 /**
  * @file
@@ -113,7 +113,7 @@ if (authorize_access_allowed()) {
   }
 
   if (isset($_SESSION['authorize_operation']['page_title'])) {
-    drupal_set_title(check_plain($_SESSION['authorize_operation']['page_title']));
+    drupal_set_title($_SESSION['authorize_operation']['page_title']);
   }
   else {
     drupal_set_title(t('Authorize file system changes'));
@@ -125,10 +125,10 @@ if (authorize_access_allowed()) {
     // Clear the session out.
     unset($_SESSION['authorize_results']);
     unset($_SESSION['authorize_operation']);
-    unset($_SESSION['authorize_filetransfer_backends']);
+    unset($_SESSION['authorize_filetransfer_info']);
 
     if (!empty($results['page_title'])) {
-      drupal_set_title(check_plain($results['page_title']));
+      drupal_set_title($results['page_title']);
     }
     if (!empty($results['page_message'])) {
       drupal_set_message($results['page_message']['message'], $results['page_message']['type']);
@@ -140,20 +140,21 @@ if (authorize_access_allowed()) {
     if (is_array($results['tasks'])) {
       $links += $results['tasks'];
     }
-
-    $links = array_merge($links, array(
-      l(t('Administration pages'), 'admin'),
-      l(t('Front page'), '<front>'),
-    ));
-
-    $output .= theme('item_list', array('items' => $links));
+    else {
+      $links = array_merge($links, array(
+        l(t('Administration pages'), 'admin'),
+        l(t('Front page'), '<front>'),
+      ));
+    }
+	
+    $output .= theme('item_list', array('items' => $links, 'title' => t('Next steps')));
   }
   // If a batch is running, let it run.
   elseif (isset($_GET['batch'])) {
     $output = _batch_page();
   }
   else {
-    if (empty($_SESSION['authorize_operation']) || empty($_SESSION['authorize_filetransfer_backends'])) {
+    if (empty($_SESSION['authorize_operation']) || empty($_SESSION['authorize_filetransfer_info'])) {
       $output = t('It appears you have reached this page in error.');
     }
     elseif (!$batch = batch_get()) {
diff --git a/includes/actions.inc b/includes/actions.inc
index 82c51662cf13a85efaadd012b0e02a1686ee5e0e..9331422b9cb5aad7e1ceea16c74387b240a9239e 100644
--- a/includes/actions.inc
+++ b/includes/actions.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: actions.inc,v 1.39 2010/08/22 11:04:09 dries Exp $
+// $Id: actions.inc,v 1.41 2010/12/11 02:09:00 dries Exp $
 
 /**
  * @file
@@ -278,7 +278,7 @@ function actions_synchronize($delete_orphans = FALSE) {
     // user adds the action.
     if (!$array['configurable']) {
       // If we already have an action ID for this action, no need to assign aid.
-      if (array_key_exists($callback, $actions_in_db)) {
+      if (isset($actions_in_db[$callback])) {
         unset($actions_in_db[$callback]);
       }
       else {
@@ -312,7 +312,7 @@ function actions_synchronize($delete_orphans = FALSE) {
       $link = l(t('Remove orphaned actions'), 'admin/config/system/actions/orphan');
       $count = count($actions_in_db);
       $orphans = implode(', ', $orphaned);
-      watchdog('actions', format_plural($count, 'One orphaned action (%orphans) exists in the actions table. !link', '@count orphaned actions (%orphans) exist in the actions table. !link'), array('@count' => $count, '%orphans' => $orphans, '!link' => $link), WATCHDOG_WARNING);
+      watchdog('actions', '@count orphaned actions (%orphans) exist in the actions table. !link', array('@count' => $count, '%orphans' => $orphans, '!link' => $link), WATCHDOG_WARNING);
     }
   }
 }
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 8ad3bc36e9767bd4ae6b2f5abc47bdc6516967dd..cfb71febb0d003bbbb610cb896d46f0a369e1cc6 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: ajax.inc,v 1.37 2010/10/21 19:31:39 dries Exp $
+// $Id: ajax.inc,v 1.42 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -9,6 +9,8 @@
 /**
  * @defgroup ajax AJAX framework
  * @{
+ * Functions for Drupal's AJAX framework.
+ *
  * Drupal's AJAX framework is used to dynamically update parts of a page's HTML
  * based on data from the server. Upon a specified event, such as a button
  * click, a callback function is triggered which performs server-side logic and
@@ -407,19 +409,49 @@ function ajax_base_page_theme() {
 /**
  * Package and send the result of a page callback to the browser as an AJAX response.
  *
+ * This function is the equivalent of drupal_deliver_html_page(), but for AJAX
+ * requests. Like that function, it:
+ * - Adds needed HTTP headers.
+ * - Prints rendered output.
+ * - Performs end-of-request tasks.
+ *
  * @param $page_callback_result
  *   The result of a page callback. Can be one of:
  *   - NULL: to indicate no content.
  *   - An integer menu status constant: to indicate an error condition.
  *   - A string of HTML content.
  *   - A renderable array of content.
+ *
+ * @see drupal_deliver_html_page()
  */
 function ajax_deliver($page_callback_result) {
-  $commands = array();
-  $header = TRUE;
+  // Emit a Content-Type HTTP header if none has been added by the page callback
+  // or by a wrapping delivery callback.
+  if (is_null(drupal_get_http_header('Content-Type'))) {
+    // The standard header for JSON is application/json.
+    // @see http://www.ietf.org/rfc/rfc4627.txt?number=4627
+    // However, browsers do not allow JavaScript to read the contents of a
+    // user's local files. To work around that, jQuery submits forms containing
+    // a file input element to an IFRAME, instead of using XHR.
+    // @see http://malsup.com/jquery/form/#file-upload
+    // When Internet Explorer receives application/json content in an IFRAME, it
+    // treats it as a file download and prompts the user to save it. To prevent
+    // that, we return the content as text/plain. But only for POST requests,
+    // since jQuery should always use XHR for GET requests and the incorrect
+    // mime type should not end up in page or proxy server caches.
+    // @see http://drupal.org/node/995854
+    $iframe_upload = !isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest';
+    if ($iframe_upload && $_SERVER['REQUEST_METHOD'] == 'POST') {
+      drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+    }
+    else {
+      drupal_add_http_header('Content-Type', 'application/json; charset=utf-8');
+    }
+  }
 
   // Normalize whatever was returned by the page callback to an AJAX commands
   // array.
+  $commands = array();
   if (!isset($page_callback_result)) {
     // Simply delivering an empty commands array is sufficient. This results
     // in the AJAX request being completed, but nothing being done to the page.
@@ -444,7 +476,6 @@ function ajax_deliver($page_callback_result) {
     // Complex AJAX callbacks can return a result that contains an error message
     // or a specific set of commands to send to the browser.
     $page_callback_result += element_info('ajax');
-    $header = $page_callback_result['#header'];
     $error = $page_callback_result['#error'];
     if (isset($error) && $error !== FALSE) {
       if ((empty($error) || $error === TRUE)) {
@@ -470,24 +501,10 @@ function ajax_deliver($page_callback_result) {
     $commands[] = ajax_command_prepend(NULL, theme('status_messages'));
   }
 
-  // This function needs to do the same thing that drupal_deliver_html_page()
-  // does: add any needed http headers, print rendered output, and perform
-  // end-of-request tasks. By default, $header=TRUE, and we add a
-  // 'text/javascript' header. The page callback can override $header by
-  // returning an 'ajax' element with a #header property. This can be set to
-  // FALSE to prevent the 'text/javascript' header from being output, necessary
-  // when outputting to an IFRAME. This can also be set to 'multipart', in which
-  // case, we don't output JSON, but JSON content wrapped in a textarea, making
-  // a 'text/javascript' header incorrect.
-  if ($header && $header !== 'multipart') {
-    drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
-  }
-  $output = ajax_render($commands);
-  if ($header === 'multipart') {
-    // jQuery file uploads: http://malsup.com/jquery/form/#code-samples
-    $output = '<textarea>' . $output . '</textarea>';
-  }
-  print $output;
+  // Unlike the recommendation in http://malsup.com/jquery/form/#file-upload,
+  // we do not have to wrap the JSON string in a TEXTAREA, because
+  // drupal_json_encode() returns an HTML-safe JSON string.
+  print ajax_render($commands);
   ajax_footer();
 }
 
@@ -604,8 +621,8 @@ function ajax_pre_render_element($element) {
 
   // Attach JavaScript settings to the element.
   if (isset($element['#ajax']['event'])) {
-    $element['#attached']['library'][] = array('system', 'form');
-    $element['#attached']['js']['misc/ajax.js'] = array('group' => JS_LIBRARY, 'weight' => 2);
+    $element['#attached']['library'][] = array('system', 'jquery.form');
+    $element['#attached']['library'][] = array('system', 'drupal.ajax');
 
     $settings = $element['#ajax'];
 
@@ -613,15 +630,10 @@ function ajax_pre_render_element($element) {
     $settings += array(
       'path' => 'system/ajax',
       'options' => array(),
-      'selector' => '#' . $element['#id'],
-      'effect' => 'none',
-      'speed' => 'none',
-      'method' => 'replaceWith',
-      'progress' => array('type' => 'throbber'),
     );
 
     // @todo Legacy support. Remove in Drupal 8.
-    if ($settings['method'] == 'replace') {
+    if (isset($settings['method']) && $settings['method'] == 'replace') {
       $settings['method'] = 'replaceWith';
     }
 
@@ -659,7 +671,7 @@ function ajax_pre_render_element($element) {
     }
 
     // Convert a simple #ajax['progress'] string into an array.
-    if (is_string($settings['progress'])) {
+    if (isset($settings['progress']) && is_string($settings['progress'])) {
       $settings['progress'] = array('type' => $settings['progress']);
     }
     // Change progress path to a full URL.
@@ -667,10 +679,6 @@ function ajax_pre_render_element($element) {
       $settings['progress']['url'] = url($settings['progress']['path']);
       unset($settings['progress']['path']);
     }
-    // Add progress.js if we're doing a bar display.
-    if ($settings['progress']['type'] == 'bar') {
-      $element['#attached']['js']['misc/progress.js'] = array('cache' => FALSE);
-    }
 
     $element['#attached']['js'][] = array(
       'type' => 'setting',
@@ -690,6 +698,10 @@ function ajax_pre_render_element($element) {
 /**
  * @defgroup ajax_commands AJAX framework commands
  * @{
+ * Functions to create various AJAX commands.
+ *
+ * These functions can be used to create arrays for use with the
+ * ajax_render() function.
  */
 
 /**
@@ -1002,7 +1014,7 @@ function ajax_command_changed($selector, $asterisk = '') {
  * The 'css' command will instruct the client to use the jQuery css() method
  * to apply the CSS arguments to elements matched by the given selector.
  *
- * This command is implemented by Drupal.ajax.prototype.commands.insert()
+ * This command is implemented by Drupal.ajax.prototype.commands.css()
  * defined in misc/ajax.js.
  *
  * @param $selector
@@ -1087,6 +1099,37 @@ function ajax_command_data($selector, $name, $value) {
   );
 }
 
+/**
+ * Creates a Drupal AJAX 'invoke' command.
+ *
+ * The 'invoke' command will instruct the client to invoke the given jQuery
+ * method with the supplied arguments on the elements matched by the given
+ * selector. Intended for simple jQuery commands, such as attr(), addClass(),
+ * removeClass(), toggleClass(), etc.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.invoke()
+ * 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 $method
+ *   The jQuery method to invoke.
+ * @param $arguments
+ *   (optional) A list of arguments to the jQuery $method, if any.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_invoke($selector, $method, array $arguments = array()) {
+  return array(
+    'command' => 'invoke',
+    'selector' => $selector,
+    'method' => $method,
+    'arguments' => $arguments,
+  );
+}
+
 /**
  * Creates a Drupal AJAX 'restripe' command.
  *
diff --git a/includes/authorize.inc b/includes/authorize.inc
index c5ba6916f357dd7d8807fcb2ebf31f121a3b79fc..b8f2cce554670ac8276ed33c9f296a163db5c398 100644
--- a/includes/authorize.inc
+++ b/includes/authorize.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: authorize.inc,v 1.11 2010/05/14 04:50:18 webchick Exp $
+// $Id: authorize.inc,v 1.15 2011/01/04 04:37:27 webchick Exp $
 
 /**
  * @file
@@ -9,7 +9,7 @@
 /**
  * Build the form for choosing a FileTransfer type and supplying credentials.
  */
-function authorize_filetransfer_form($form_state) {
+function authorize_filetransfer_form($form, &$form_state) {
   global $base_url, $is_https;
   $form = array();
 
@@ -21,15 +21,18 @@ function authorize_filetransfer_form($form_state) {
   $form['#attached']['js'][] = $base_url . '/misc/authorize.js';
 
   // Get all the available ways to transfer files.
-  if (empty($_SESSION['authorize_filetransfer_backends'])) {
+  if (empty($_SESSION['authorize_filetransfer_info'])) {
     drupal_set_message(t('Unable to continue, no available methods of file transfer'), 'error');
     return array();
   }
-  $available_backends = $_SESSION['authorize_filetransfer_backends'];
-  uasort($available_backends, 'drupal_sort_weight');
+  $available_backends = $_SESSION['authorize_filetransfer_info'];
 
   if (!$is_https) {
-    drupal_set_message(t('WARNING: You are not using an encrypted connection, so your password will be sent in plain text. <a href="@https-link">Learn more</a>.', array('@https-link' => 'http://drupal.org/https-information')), 'error');
+    $form['information']['https_warning'] = array(
+      '#prefix' => '<div class="messages error">',
+      '#markup' => t('WARNING: You are not using an encrypted connection, so your password will be sent in plain text. <a href="@https-link">Learn more</a>.', array('@https-link' => 'http://drupal.org/https-information')),
+      '#suffix' => '</div>',
+    );
   }
 
   // Decide on a default backend.
@@ -78,17 +81,20 @@ function authorize_filetransfer_form($form_state) {
     '#attributes' => array('style' => 'display:none'),
   );
 
-  // Build a hidden fieldset for each one.
+  // Build a container for each connection type.
   foreach ($available_backends as $name => $backend) {
     $form['connection_settings']['authorize_filetransfer_default']['#options'][$name] = $backend['title'];
     $form['connection_settings'][$name] = array(
-      '#type' => 'fieldset',
+      '#type' => 'container',
       '#attributes' => array('class' => array("filetransfer-$name", 'filetransfer')),
-      '#title' => t('@backend connection settings', array('@backend' => $backend['title'])),
+    );
+    // We can't use #prefix on the container itself since then the header won't
+    // be hidden and shown when the containers are being manipulated via JS.
+    $form['connection_settings'][$name]['header'] = array(
+      '#markup' => '<h4>' . t('@backend connection settings', array('@backend' => $backend['title'])) . '</h4>',
     );
 
-    $current_settings = variable_get('authorize_filetransfer_connection_settings_' . $name, array());
-    $form['connection_settings'][$name] += system_get_filetransfer_settings_form($name, $current_settings);
+    $form['connection_settings'][$name] += _authorize_filetransfer_connection_settings($name);
 
     // Start non-JS code.
     if (isset($form_state['values']['connection_settings']['authorize_filetransfer_default']) && $form_state['values']['connection_settings']['authorize_filetransfer_default'] == $name) {
@@ -113,7 +119,7 @@ function authorize_filetransfer_form($form_state) {
         '#type' => 'submit',
         '#value' => t('Change connection type'),
         '#weight' => -5,
-        '#attributes' => array('class' => 'filetransfer-change-connection-type'),
+        '#attributes' => array('class' => array('filetransfer-change-connection-type')),
       );
     }
     // End non-JS code.
@@ -121,12 +127,77 @@ function authorize_filetransfer_form($form_state) {
   return $form;
 }
 
+/**
+ * Generate the Form API array for the settings for a given connection backend.
+ *
+ * @param $backend
+ *   The name of the backend (e.g. 'ftp', 'ssh', etc).
+ * @return
+ *   Form API array of connection settings for the given backend.
+ *
+ * @see hook_filetransfer_backends()
+ */
+function _authorize_filetransfer_connection_settings($backend) {
+  $defaults = variable_get('authorize_filetransfer_connection_settings_' . $backend, array());
+  $form = array();
+
+  // Create an instance of the file transfer class to get its settings form.
+  $filetransfer = authorize_get_filetransfer($backend);
+  if ($filetransfer) {
+    $form = $filetransfer->getSettingsForm();
+  }
+  // Fill in the defaults based on the saved settings, if any.
+  _authorize_filetransfer_connection_settings_set_defaults($form, NULL, $defaults);
+  return $form;
+}
+
+/**
+ * Recursively fill in the default settings on a file transfer connection form.
+ *
+ * The default settings for the file transfer connection forms are saved in
+ * the database. The settings are stored as a nested array in the case of a
+ * settings form that has fieldsets or otherwise uses a nested structure.
+ * Therefore, to properly add defaults, we need to walk through all the
+ * children form elements and process those defaults recursively.
+ *
+ * @param &$element
+ *   Reference to the Form API form element we're operating on.
+ * @param $key
+ *   The key for our current form element, if any.
+ * @param array $defaults
+ *   The default settings for the file transfer backend we're operating on.
+ * @return
+ *   Nothing, this function just sets $element['#default_value'] if needed.
+ */
+function _authorize_filetransfer_connection_settings_set_defaults(&$element, $key, array $defaults) {
+  // If we're operating on a form element which isn't a fieldset, and we have
+  // a default setting saved, stash it in #default_value.
+  if (!empty($key) && isset($defaults[$key]) && isset($element['#type']) && $element['#type'] != 'fieldset') {
+    $element['#default_value'] = $defaults[$key];
+  }
+  // Now, we walk through all the child elements, and recursively invoke
+  // ourself on each one. Since the $defaults settings array can be nested
+  // (because of #tree, any values inside fieldsets will be nested), if
+  // there's a subarray of settings for the form key we're currently
+  // processing, pass in that subarray to the recursive call. Otherwise, just
+  // pass on the whole $defaults array.
+  foreach (element_children($element) as $child_key) {
+    _authorize_filetransfer_connection_settings_set_defaults($element[$child_key], $child_key, ((isset($defaults[$key]) && is_array($defaults[$key])) ? $defaults[$key] : $defaults));
+  }
+}
+
 /**
  * Validate callback for the filetransfer authorization form.
  *
  * @see authorize_filetransfer_form()
  */
 function authorize_filetransfer_form_validate($form, &$form_state) {
+  // Only validate the form if we have collected all of the user input and are
+  // ready to proceed with updating or installing.
+  if ($form_state['clicked_button']['#name'] != 'process_updates') {
+    return;
+  }
+
   if (isset($form_state['values']['connection_settings'])) {
     $backend = $form_state['values']['connection_settings']['authorize_filetransfer_default'];
     $filetransfer = authorize_get_filetransfer($backend, $form_state['values']['connection_settings'][$backend]);
@@ -137,7 +208,12 @@ function authorize_filetransfer_form_validate($form, &$form_state) {
       $filetransfer->connect();
     }
     catch (Exception $e) {
-      form_set_error('connection_settings', $e->getMessage());
+      // The format of this error message is similar to that used on the
+      // database connection form in the installer.
+      form_set_error('connection_settings', t('Failed to connect to the server. The server reports the following message: !message For more help installing or updating code on your server, see the <a href="@handbook_url">handbook</a>.', array(
+        '!message' => '<p class="error">' . $e->getMessage()  . '</p>',
+        '@handbook_url' => 'http://drupal.org/documentation/install/modules-themes',
+      )));
     }
   }
 }
@@ -215,7 +291,7 @@ function authorize_run_operation($filetransfer) {
   unset($_SESSION['authorize_operation']);
 
   if (!empty($operation['page_title'])) {
-    drupal_set_title(check_plain($operation['page_title']));
+    drupal_set_title($operation['page_title']);
   }
 
   require_once DRUPAL_ROOT . '/' . $operation['file'];
@@ -235,9 +311,17 @@ function authorize_run_operation($filetransfer) {
  */
 function authorize_get_filetransfer($backend, $settings = array()) {
   $filetransfer = FALSE;
-  if (!empty($_SESSION['authorize_filetransfer_backends'][$backend])) {
-    $filetransfer = call_user_func_array(array($_SESSION['authorize_filetransfer_backends'][$backend]['class'], 'factory'), array(DRUPAL_ROOT, $settings));
+  if (!empty($_SESSION['authorize_filetransfer_info'][$backend])) {
+    $backend_info = $_SESSION['authorize_filetransfer_info'][$backend];
+    if (!empty($backend_info['file'])) {
+      $file = $backend_info['file path'] . '/' . $backend_info['file'];
+      require_once $file;
+    }
+    if (class_exists($backend_info['class'])) {
+      // PHP 5.2 doesn't support $class::factory() syntax, so we have to
+      // use call_user_func_array() until we can require PHP 5.3.
+      $filetransfer = call_user_func_array(array($backend_info['class'], 'factory'), array(DRUPAL_ROOT, $settings));
+    }
   }
   return $filetransfer;
 }
-
diff --git a/includes/batch.inc b/includes/batch.inc
index 0f30bc4305ddb30ee98d0798d537c7782a02154a..c84df765a9e265e9257b52726f0d94d6f1d9a20b 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: batch.inc,v 1.53 2010/10/04 07:34:26 webchick Exp $
+// $Id: batch.inc,v 1.54 2010/11/30 17:16:37 dries Exp $
 
 
 /**
@@ -139,8 +139,7 @@ function _batch_progress_page_js() {
     ),
   );
   drupal_add_js($js_setting, 'setting');
-  drupal_add_js('misc/progress.js', array('cache' => FALSE));
-  drupal_add_js('misc/batch.js', array('cache' => FALSE));
+  drupal_add_library('system', 'drupal.batch');
 
   return '<div id="progress"></div>';
 }
diff --git a/includes/batch.queue.inc b/includes/batch.queue.inc
index 7ff4b413473e33afaa83fa7eae55629d6d78c581..ee2665dcead51726ea009798599aac71eb8004c3 100644
--- a/includes/batch.queue.inc
+++ b/includes/batch.queue.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: batch.queue.inc,v 1.1 2010/01/08 06:36:34 webchick Exp $
+// $Id: batch.queue.inc,v 1.2 2010/12/01 00:21:02 webchick Exp $
 
 
 /**
@@ -21,7 +21,7 @@
 class BatchQueue extends SystemQueue {
 
   public function claimItem($lease_time = 0) {
-    $item = db_query('SELECT data, item_id FROM {queue} q WHERE name = :name ORDER BY item_id ASC', array(':name' => $this->name))->fetchObject();
+    $item = db_query_range('SELECT data, item_id FROM {queue} q WHERE name = :name ORDER BY item_id ASC', 0, 1, array(':name' => $this->name))->fetchObject();
     if ($item) {
       $item->data = unserialize($item->data);
       return $item;
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 06bfddbbb649d82518f8b63d742e88d64cdfe798..2d68c8175eae858a19f5cf9ce70154aa70139206 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: bootstrap.inc,v 1.430 2010/10/23 05:30:57 webchick Exp $
+// $Id: bootstrap.inc,v 1.462 2011/01/05 06:17:58 webchick Exp $
 
 /**
  * @file
@@ -9,7 +9,7 @@
 /**
  * The current system version.
  */
-define('VERSION', '7.0-beta2');
+define('VERSION', '7.0');
 
 /**
  * Core API compatibility.
@@ -19,22 +19,12 @@ define('DRUPAL_CORE_COMPATIBILITY', '7.x');
 /**
  * Minimum supported version of PHP.
  */
-define('DRUPAL_MINIMUM_PHP',    '5.2.4');
+define('DRUPAL_MINIMUM_PHP', '5.2.4');
 
 /**
  * Minimum recommended value of PHP memory_limit.
  */
-define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT',    '32M');
-
-/**
- * Minimum supported version of MySQL, if it is used.
- */
-define('DRUPAL_MINIMUM_MYSQL',  '5.0.15');
-
-/**
- * Minimum supported version of PostgreSQL, if it is used.
- */
-define('DRUPAL_MINIMUM_PGSQL',  '8.3');
+define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
 
 /**
  * Indicates that the item should never be removed unless explicitly selected.
@@ -250,6 +240,13 @@ define('REGISTRY_RESET_LOOKUP_CACHE', 1);
  */
 define('REGISTRY_WRITE_LOOKUP_CACHE', 2);
 
+/**
+ * Regular expression to match PHP function names.
+ *
+ * @see http://php.net/manual/en/language.functions.php
+ */
+define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*');
+
 /**
  * Start the timer with the specified name. If you start and stop the same
  * timer multiple times, the measured intervals will be accumulated.
@@ -446,21 +443,23 @@ function conf_path($require_settings = TRUE, $reset = FALSE) {
  * @see ip_address()
  */
 function drupal_override_server_variables($variables = array()) {
-  // Set defaults based on the provided URL.
+  // Allow the provided URL to override any existing values in $_SERVER.
   if (isset($variables['url'])) {
     $url = parse_url($variables['url']);
+    if (isset($url['host'])) {
+      $_SERVER['HTTP_HOST'] = $url['host'];
+    }
+    if (isset($url['path'])) {
+      $_SERVER['SCRIPT_NAME'] = $url['path'];
+    }
     unset($variables['url']);
   }
-  else {
-    $url = array();
-  }
-  $url += array(
-    'path' => '',
-    'host' => 'localhost',
-  );
+  // Define default values for $_SERVER keys. These will be used if $_SERVER
+  // does not already define them and no other values are passed in to this
+  // function.
   $defaults = array(
-    'HTTP_HOST' => $url['host'],
-    'SCRIPT_NAME' => $url['path'],
+    'HTTP_HOST' => 'localhost',
+    'SCRIPT_NAME' => NULL,
     'REMOTE_ADDR' => '127.0.0.1',
     'REQUEST_METHOD' => 'GET',
     'SERVER_NAME' => NULL,
@@ -513,8 +512,6 @@ function drupal_environment_initialize() {
   // sites/default/default.settings.php contains more runtime settings.
   // The .htaccess file contains settings that cannot be changed at runtime.
 
-  // Prevent PHP from generating HTML error messages.
-  ini_set('html_errors', 0);
   // Don't escape quotes when reading files from the database, disk, etc.
   ini_set('magic_quotes_runtime', '0');
   // Use session cookies, not transparent sessions that puts the session id in
@@ -713,7 +710,7 @@ function drupal_get_filename($type, $name, $filename = NULL) {
       // extension, not just the file we are currently looking for. This
       // prevents unnecessary scans from being repeated when this function is
       // called more than once in the same page request.
-      $matches = drupal_system_listing("/\.$extension$/", $dir, 'name', 0);
+      $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
       foreach ($matches as $matched_name => $file) {
         $files[$type][$matched_name] = $file->uri;
       }
@@ -897,7 +894,12 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
  */
 function bootstrap_invoke_all($hook) {
   // Bootstrap modules should have been loaded when this function is called, so
-  // we don't need to tell module_list() to reset its bootstrap list.
+  // we don't need to tell module_list() to reset its internal list (and we
+  // therefore leave the first parameter at its default value of FALSE). We
+  // still pass in TRUE for the second parameter, though; in case this is the
+  // first time during the bootstrap that module_list() is called, we want to
+  // make sure that its internal cache is primed with the bootstrap modules
+  // only.
   foreach (module_list(FALSE, TRUE) as $module) {
     drupal_load('module', $module);
     module_invoke($module, $hook);
@@ -1252,7 +1254,7 @@ function drupal_unpack($obj, $field = 'data') {
  *     drupal_set_title($title = t("@name's blog", array('@name' => format_username($account))), PASS_THROUGH);
  *   @endcode
  * - %variable: Indicates that the string should be HTML-escaped and highlighted
- *   with theme_placeholder(), which shows up by default as <em>emphasized</em>.
+ *   with drupal_placeholder(), which shows up 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
@@ -1388,7 +1390,7 @@ function drupal_unpack($obj, $field = 'data') {
  *    - !variable: inserted as is
  *    - @variable: escape plain text to HTML (using check_plain())
  *    - %variable: escape text and theme as a placeholder for user-submitted
- *      content (using check_plain() + theme_placeholder())
+ *      content (using check_plain() + drupal_placeholder())
  * @param $options
  *   An associative array of additional options, with the following keys:
  *     - 'langcode' (defaults to the current language) The language code to
@@ -1425,7 +1427,7 @@ function t($string, array $args = array(), array $options = array()) {
     $string = $custom_strings[$options['langcode']][$options['context']][$string];
   }
   // Translate with locale module if enabled.
-  elseif (function_exists('locale') && $options['langcode'] != 'en') {
+  elseif ($options['langcode'] != 'en' && function_exists('locale')) {
     $string = locale($string, $options['context'], $options['langcode']);
   }
   if (empty($args)) {
@@ -1561,7 +1563,8 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia
 
    // Use a default value if $message is not set.
    if (empty($message)) {
-     $message = '%type: %message in %function (line %line of %file).';
+     // The exception message is run through check_plain() by _drupal_decode_exception().
+     $message = '%type: !message in %function (line %line of %file).';
    }
    // $variables must be an array so that we can add the exception information.
    if (!is_array($variables)) {
@@ -1878,6 +1881,79 @@ function drupal_hash_base64($data) {
   return strtr($hash, array('+' => '-', '/' => '_', '=' => ''));
 }
 
+/**
+ * Merges multiple arrays, recursively, and returns the merged array.
+ *
+ * This function is similar to PHP's array_merge_recursive() function, but it
+ * handles non-array values differently. When merging values that are not both
+ * arrays, the latter value replaces the former rather than merging with it.
+ *
+ * Example:
+ * @code
+ * $link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => t('X'), 'class' => array('a', 'b')));
+ * $link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => t('Y'), 'class' => array('c', 'd')));
+ *
+ * // This results in array('fragment' => array('x', 'y'), 'attributes' => array('title' => array(t('X'), t('Y')), 'class' => array('a', 'b', 'c', 'd'))).
+ * $incorrect = array_merge_recursive($link_options_1, $link_options_2);
+ *
+ * // This results in array('fragment' => 'y', 'attributes' => array('title' => t('Y'), 'class' => array('a', 'b', 'c', 'd'))).
+ * $correct = drupal_array_merge_deep($link_options_1, $link_options_2);
+ * @endcode
+ *
+ * @param ...
+ *   Arrays to merge.
+ *
+ * @return
+ *   The merged array.
+ *
+ * @see drupal_array_merge_deep_array()
+ */
+function drupal_array_merge_deep() {
+  return drupal_array_merge_deep_array(func_get_args());
+}
+
+/**
+ * Merges multiple arrays, recursively, and returns the merged array.
+ *
+ * This function is equivalent to drupal_array_merge_deep(), except the
+ * input arrays are passed as a single array parameter rather than a variable
+ * parameter list.
+ *
+ * The following are equivalent:
+ * - drupal_array_merge_deep($a, $b);
+ * - drupal_array_merge_deep_array(array($a, $b));
+ *
+ * The following are also equivalent:
+ * - call_user_func_array('drupal_array_merge_deep', $arrays_to_merge);
+ * - drupal_array_merge_deep_array($arrays_to_merge);
+ *
+ * @see drupal_array_merge_deep()
+ */
+function drupal_array_merge_deep_array($arrays) {
+  $result = array();
+
+  foreach ($arrays as $array) {
+    foreach ($array as $key => $value) {
+      // Renumber integer keys as array_merge_recursive() does. Note that PHP
+      // automatically converts array keys that are integer strings (e.g., '1')
+      // to integers.
+      if (is_integer($key)) {
+        $result[] = $value;
+      }
+      // Recurse when both values are arrays.
+      elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
+        $result[$key] = drupal_array_merge_deep_array(array($result[$key], $value));
+      }
+      // Otherwise, use the latter value, overriding any previous value.
+      else {
+        $result[$key] = $value;
+      }
+    }
+  }
+
+  return $result;
+}
+
 /**
  * Generates a default anonymous $user object.
  *
@@ -2133,15 +2209,7 @@ function _drupal_bootstrap_database() {
   // The user agent header is used to pass a database prefix in the request when
   // running tests. However, for security reasons, it is imperative that we
   // validate we ourselves made the request.
-  if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
-    if (!drupal_valid_test_ua($_SERVER['HTTP_USER_AGENT'])) {
-      header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-      exit;
-    }
-
-    // The first part of the user agent is the prefix itself.
-    $test_prefix = $matches[1];
-
+  if ($test_prefix = drupal_valid_test_ua()) {
     // Set the test run id for use in other parts of Drupal.
     $test_info = &$GLOBALS['drupal_test_info'];
     $test_info['test_run_id'] = $test_prefix;
@@ -2174,7 +2242,6 @@ function _drupal_bootstrap_database() {
   // The database autoload routine comes first so that we can load the database
   // system without hitting the database. That is especially important during
   // the install or upgrade process.
-  spl_autoload_register('db_autoload');
   spl_autoload_register('drupal_autoload_class');
   spl_autoload_register('drupal_autoload_interface');
 }
@@ -2220,22 +2287,40 @@ function drupal_get_bootstrap_phase() {
 }
 
 /**
- * Validate the HMAC and timestamp of a user agent header from simpletest.
+ * Checks the current User-Agent string to see if this is an internal request
+ * from SimpleTest. If so, returns the test prefix for this test.
+ *
+ * @return
+ *   Either the simpletest prefix (the string "simpletest" followed by any
+ *   number of digits) or FALSE if the user agent does not contain a valid
+ *   HMAC and timestamp.
  */
-function drupal_valid_test_ua($user_agent) {
+function drupal_valid_test_ua() {
   global $drupal_hash_salt;
+  // No reason to reset this.
+  static $test_prefix;
+
+  if (isset($test_prefix)) {
+    return $test_prefix;
+  }
 
-  list($prefix, $time, $salt, $hmac) = explode(';', $user_agent);
-  $check_string =  $prefix . ';' . $time . ';' . $salt;
-  // We use the salt from settings.php to make the HMAC key, since
-  // 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 = $drupal_hash_salt . filectime($filepath) . fileinode($filepath);
-  $time_diff = REQUEST_TIME - $time;
-  // Since we are making a local request a 5 second time window is allowed,
-  // and the HMAC must match.
-  return ($time_diff >= 0) && ($time_diff <= 5) && ($hmac == drupal_hmac_base64($check_string, $key));
+  if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
+    list(, $prefix, $time, $salt, $hmac) = $matches;
+    $check_string =  $prefix . ';' . $time . ';' . $salt;
+    // We use the salt from settings.php to make the HMAC key, since
+    // 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.
+    $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
+    $time_diff = REQUEST_TIME - $time;
+    // Since we are making a local request a 5 second time window is allowed,
+    // and the HMAC must match.
+    if ($time_diff >= 0 && $time_diff <= 5 && $hmac == drupal_hmac_base64($check_string, $key)) {
+      $test_prefix = $prefix;
+      return $test_prefix;
+    }
+  }
+
+  return FALSE;
 }
 
 /**
@@ -2249,13 +2334,12 @@ function drupal_generate_test_ua($prefix) {
     // We use the salt from settings.php to make the HMAC key, since
     // 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 = $drupal_hash_salt . filectime($filepath) . fileinode($filepath);
+    $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
   }
-   // Generate a moderately secure HMAC based on the database credentials.
-   $salt = uniqid('', TRUE);
-   $check_string = $prefix . ';' . time() . ';' . $salt;
-   return  $check_string . ';' . drupal_hmac_base64($check_string, $key);
+  // Generate a moderately secure HMAC based on the database credentials.
+  $salt = uniqid('', TRUE);
+  $check_string = $prefix . ';' . time() . ';' . $salt;
+  return $check_string . ';' . drupal_hmac_base64($check_string, $key);
 }
 
 /**
@@ -2467,7 +2551,8 @@ function request_path() {
  *
  * @return
  *   The component specified by $index, or NULL if the specified component was
- *   not found.
+ *   not found. If called without arguments, it returns an array containing all
+ *   the components of the current path.
  */
 function arg($index = NULL, $path = NULL) {
   // Even though $arguments doesn't need to be resettable for any functional
@@ -2570,15 +2655,11 @@ function drupal_get_schema($table = NULL, $rebuild = FALSE) {
       // On some databases this function may be called before bootstrap has
       // been completed, so we force the functions we need to load just in case.
       if (function_exists('module_load_all_includes')) {
-        // There is currently a bug in module_list() where it caches what it
-        // was last called with, which is not always what you want.
-        // module_load_all_includes() calls module_list(), but if this function
-        // is called very early in the bootstrap process then it will be
-        // uninitialized and therefore return no modules. Instead, we have to
-        // "prime" module_list() here to to values we want, specifically
-        // "yes rebuild the list and don't limit to bootstrap".
-        // @todo Remove this call after http://drupal.org/node/222109 is fixed.
-        module_list(TRUE, FALSE);
+        // This function can be called very early in the bootstrap process, so
+        // we force the module_list() cache to be refreshed to ensure that it
+        // contains the complete list of modules before we go on to call
+        // module_load_all_includes().
+        module_list(TRUE);
         module_load_all_includes('install');
       }
 
@@ -2976,7 +3057,7 @@ function &drupal_register_shutdown_function($callback = NULL) {
     $args = func_get_args();
     array_shift($args);
     // Save callback and arguments
-    $callbacks[] = array('callback' => $callback, 'arguments' => $args, 'cwd' => getcwd());
+    $callbacks[] = array('callback' => $callback, 'arguments' => $args);
   }
   return $callbacks;
 }
@@ -2987,9 +3068,12 @@ function &drupal_register_shutdown_function($callback = NULL) {
 function _drupal_shutdown_function() {
   $callbacks = &drupal_register_shutdown_function();
 
+  // Set the CWD to DRUPAL_ROOT as it is not guaranteed to be the same as it
+  // was in the normal context of execution.
+  chdir(DRUPAL_ROOT);
+
   try {
     while (list($key, $callback) = each($callbacks)) {
-      chdir($callback['cwd']);
       call_user_func_array($callback['callback'], $callback['arguments']);
     }
   }
diff --git a/includes/cache.inc b/includes/cache.inc
index cab2e9f14b89cd5a33e6e5a2828542e4b698b301..e5d0c4978f1c0e024897191beacf7ae05a516fbd 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: cache.inc,v 1.49 2010/10/07 17:44:53 dries Exp $
+// $Id: cache.inc,v 1.51 2010/12/01 00:26:03 webchick Exp $
 
 /**
  * Get the cache object for a cache bin.
@@ -198,7 +198,7 @@ function cache_is_empty($bin) {
  * DrupalCacheInterface was called MyCustomCache, the following line would make
  * Drupal use it for the 'cache_page' bin:
  * @code
- *  variable_set('cache_page', 'MyCustomCache');
+ *  variable_set('cache_class_cache_page', 'MyCustomCache');
  * @endcode
  *
  * Additionally, you can register your cache implementation to be used by
@@ -208,6 +208,17 @@ function cache_is_empty($bin) {
  *  variable_set('cache_default_class', 'MyCustomCache');
  * @endcode
  *
+ * To implement a completely custom cache bin, use the same variable format:
+ * @code
+ *  variable_set('cache_class_custom_bin', 'MyCustomCache');
+ * @endcode
+ * To access your custom cache bin, specify the name of the bin when storing
+ * or retrieving cached data:
+ * @code
+ *  cache_set($cid, $data, 'custom_bin', $expire);
+ *  cache_get($cid, 'custom_bin');
+ * @endcode
+ *
  * @see _cache_get_object()
  * @see DrupalDatabaseCache
  */
@@ -305,17 +316,9 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
   }
 
   function get($cid) {
-    try {
-      // Garbage collection necessary when enforcing a minimum cache lifetime.
-      $this->garbageCollection($this->bin);
-      $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) {
-      // If the database is never going to be available, cache requests should
-      // return FALSE in order to allow exception handling to occur.
-      return FALSE;
-    }
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids);
+    return reset($cache);
   }
 
   function getMultiple(&$cids) {
diff --git a/includes/common.inc b/includes/common.inc
index cd5e6706e72b443f0642eed1b42eb51312beee51..216f1be4d99ec2cea0fd0780ffa115efb3ec85fd 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: common.inc,v 1.1244 2010/10/21 19:31:39 dries Exp $
+// $Id: common.inc,v 1.1283 2011/01/03 06:51:00 webchick Exp $
 
 /**
  * @file
@@ -37,7 +37,7 @@
  *   $my_substring = drupal_substr($original_string, 0, 5);
  * @endcode
  *
- * @} End of "defgroup php_wrappers".
+ * @}
  */
 
 /**
@@ -348,7 +348,7 @@ function drupal_get_html_head() {
  * This function can be called as long the HTML header hasn't been sent.
  *
  * @param $url
- *   A url for the feed.
+ *   An internal system path or a fully qualified external URL of the feed.
  * @param $title
  *   The title of the feed.
  */
@@ -358,10 +358,14 @@ function drupal_add_feed($url = NULL, $title = '') {
   if (isset($url)) {
     $stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title));
 
-    drupal_add_html_head_link(array('rel' => 'alternate',
-                          'type' => 'application/rss+xml',
-                          'title' => $title,
-                          'href' => $url));
+    drupal_add_html_head_link(array(
+      'rel' => 'alternate',
+      'type' => 'application/rss+xml',
+      'title' => $title,
+      // Force the URL to be absolute, for consistency with other <link> tags
+      // output by Drupal.
+      'href' => url($url, array('absolute' => TRUE)),
+    ));
   }
   return $stored_feed_links;
 }
@@ -726,46 +730,35 @@ function drupal_access_denied() {
  *
  * @param $url
  *   A string containing a fully qualified URI.
- * @param $options
- *   (optional) An array which can have one or more of following keys:
- *   - headers
- *       An array containing request headers to send as name/value pairs.
- *   - method
- *       A string containing the request method. Defaults to 'GET'.
- *   - data
- *       A string containing the request body. Defaults to NULL.
- *   - max_redirects
- *       An integer representing how many times a redirect may be followed.
- *       Defaults to 3.
- *   - timeout
- *       A float representing the maximum number of seconds the function call
- *       may take. The default is 30 seconds. If a timeout occurs, the error
- *       code is set to the HTTP_REQUEST_TIMEOUT constant.
- *   - context
- *       A context resource created with stream_context_create().
- * @return
- *   An object which can have one or more of the following parameters:
- *   - request
- *       A string containing the request body that was sent.
- *   - code
- *       An integer containing the response status code, or the error code if
- *       an error occurred.
- *   - protocol
- *       The response protocol (e.g. HTTP/1.1 or HTTP/1.0).
- *   - status_message
- *       The status message from the response, if a response was received.
- *   - redirect_code
- *       If redirected, an integer containing the initial response status code.
- *   - redirect_url
- *       If redirected, a string containing the redirection location.
- *   - error
- *       If an error occurred, the error message. Otherwise not set.
- *   - headers
- *       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.
+ * @param array $options
+ *   (optional) An array that can have one or more of the following elements:
+ *   - headers: An array containing request headers to send as name/value pairs.
+ *   - method: A string containing the request method. Defaults to 'GET'.
+ *   - data: A string containing the request body, formatted as
+ *     'param=value&param=value&...'. Defaults to NULL.
+ *   - max_redirects: An integer representing how many times a redirect
+ *     may be followed. Defaults to 3.
+ *   - timeout: A float representing the maximum number of seconds the function
+ *     call may take. The default is 30 seconds. If a timeout occurs, the error
+ *     code is set to the HTTP_REQUEST_TIMEOUT constant.
+ *   - context: A context resource created with stream_context_create().
+ *
+ * @return object
+ *   An object that can have one or more of the following components:
+ *   - request: A string containing the request body that was sent.
+ *   - code: An integer containing the response status code, or the error code
+ *     if an error occurred.
+ *   - protocol: The response protocol (e.g. HTTP/1.1 or HTTP/1.0).
+ *   - status_message: The status message from the response, if a response was
+ *     received.
+ *   - redirect_code: If redirected, an integer containing the initial response
+ *     status code.
+ *   - redirect_url: If redirected, a string containing the redirection location.
+ *   - error: If an error occurred, the error message. Otherwise not set.
+ *   - headers: 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.
  */
 function drupal_http_request($url, array $options = array()) {
   $result = new stdClass();
@@ -1556,6 +1549,10 @@ function filter_xss_bad_protocol($string, $decode = TRUE) {
   // @todo Remove the $decode parameter in Drupal 8, and always assume an HTML
   //   string that needs decoding.
   if ($decode) {
+    if (!function_exists('decode_entities')) {
+      require_once DRUPAL_ROOT . '/includes/unicode.inc';
+    }
+
     $string = decode_entities($string);
   }
   return check_plain(drupal_strip_dangerous_protocols($string));
@@ -1688,7 +1685,7 @@ function format_xml_elements($array) {
  *    - !variable: inserted as is
  *    - @variable: escape plain text to HTML (check_plain)
  *    - %variable: escape text and theme as a placeholder for user-submitted
- *      content (check_plain + theme_placeholder)
+ *      content (check_plain + drupal_placeholder)
  *   Note that you do not need to include @count in this array.
  *   This replacement is done automatically for the plural case.
  * @param $options
@@ -1826,26 +1823,30 @@ function format_interval($timestamp, $granularity = 2, $langcode = NULL) {
 }
 
 /**
- * Format a date with the given configured format or a custom format string.
- *
- * Drupal allows administrators to select formatting strings for 'short',
- * 'medium' and 'long' date formats. This function can handle these formats,
- * as well as any custom format.
+ * Formats a date, using a date type or a custom date format string.
  *
  * @param $timestamp
- *   The exact date to format, as a UNIX timestamp.
+ *   A UNIX timestamp to format.
  * @param $type
- *   The format to use. Can be "short", "medium" or "long" for the preconfigured
- *   date formats. If "custom" is specified, then $format is required as well.
+ *   (optional) The format to use, one of:
+ *   - 'short', 'medium', or 'long' (the corresponding built-in date formats).
+ *   - The name of a date type defined by a module in hook_date_format_types(),
+ *     if it's been assigned a format.
+ *   - The machine name of an administrator-defined date format.
+ *   - 'custom', to use $format.
+ *   Defaults to 'medium'.
  * @param $format
- *   A PHP date format string as required by date(). A backslash should be used
- *   before a character to avoid interpreting the character as part of a date
- *   format.
+ *   (optional) If $type is 'custom', a PHP date format string suitable for
+ *   input to date(). Use a backslash to escape ordinary text, so it does not
+ *   get interpreted as date format characters.
  * @param $timezone
- *   Time zone identifier; if omitted, the user's time zone is used.
+ *   (optional) Time zone identifier, as described at
+ *   http://php.net/manual/en/timezones.php Defaults to the time zone used to
+ *   display the page.
  * @param $langcode
- *   Optional language code to translate to a language other than what is used
- *   to display the page.
+ *   (optional) Language code to translate to. Defaults to the language used to
+ *   display the page.
+ *
  * @return
  *   A translated date string in the requested format.
  */
@@ -1876,15 +1877,26 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL
     case 'short':
       $format = variable_get('date_format_short', 'm/d/Y - H:i');
       break;
+
     case 'long':
       $format = variable_get('date_format_long', 'l, F j, Y - H:i');
       break;
+
     case 'custom':
       // No change to format.
       break;
+
     case 'medium':
     default:
-      $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+      // Retrieve the format of the custom $type passed.
+      if ($type != 'medium') {
+        $format = variable_get('date_format_' . $type, '');
+      }
+      // Fall back to 'medium'.
+      if ($format === '') {
+        $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+      }
+      break;
   }
 
   // Create a DateTime object from the timestamp.
@@ -2211,22 +2223,44 @@ function drupal_http_header_attributes(array $attributes = array()) {
 }
 
 /**
- * Format an attribute string to insert in a tag.
+ * Converts an associative array to an attribute string for use in XML/HTML tags.
+ *
+ * Each array key and its value will be formatted into an attribute string.
+ * If a value is itself an array, then its elements are concatenated to a single
+ * space-delimited string (for example, a class attribute with multiple values).
+ *
+ * Attribute values are sanitized by running them through check_plain().
+ * Attribute names are not automatically sanitized. When using user-supplied
+ * attribute names, it is strongly recommended to allow only white-listed names,
+ * since certain attributes carry security risks and can be abused.
  *
- * Each array key and its value will be formatted into an HTML attribute string.
- * If a value is itself an array, then each array element is concatenated with a
- * space between each value (e.g. a multi-value class attribute).
+ * Examples of security aspects when using drupal_attributes:
+ * @code
+ *   // By running the value in the following statement through check_plain,
+ *   // the malicious script is neutralized.
+ *   drupal_attributes(array('title' => t('<script>steal_cookie();</script>')));
+ *
+ *   // The statement below demonstrates dangerous use of drupal_attributes, and
+ *   // will return an onmouseout attribute with javascript code that, when used
+ *   // as attribute in a tag, will cause users to be redirected to another site.
+ *   //
+ *   // In this case, the 'onmouseout' attribute should not be whitelisted --
+ *   // you don't want users to have the ability to add this attribute or others
+ *   // that take JavaScript commands.
+ *   drupal_attributes(array('onmouseout' => 'window.location="http://malicious.com/";')));
+ * @endcode
  *
  * @param $attributes
- *   An associative array of HTML attributes.
+ *   An associative array of key-value pairs to be converted to attributes.
+ *
  * @return
- *   An HTML string ready for insertion in a tag.
+ *   A string ready for insertion in a tag.
+ *
+ * @ingroup sanitization
  */
 function drupal_attributes(array $attributes = array()) {
   foreach ($attributes as $attribute => &$data) {
-    if (is_array($data)) {
-      $data = implode(' ', $data);
-    }
+    $data = implode(' ', (array) $data);
     $data = $attribute . '="' . check_plain($data) . '"';
   }
   return $attributes ? ' ' . implode(' ', $attributes) : '';
@@ -2251,7 +2285,9 @@ function drupal_attributes(array $attributes = array()) {
  * @param array $options
  *   An associative array of additional options, with the following elements:
  *   - 'attributes': An associative array of HTML attributes to apply to the
- *     anchor tag.
+ *     anchor tag. If element 'class' is included, it must be an array; 'title'
+ *     must be a string; other elements are more flexible, as they just need
+ *     to work in a call to drupal_attributes($options['attributes']).
  *   - 'html' (default FALSE): Whether $text is HTML or just plain-text. For
  *     example, to make an image tag into a link, this must be set to TRUE, or
  *     you will see the escaped HTML image tag.
@@ -2920,7 +2956,7 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
  */
 function drupal_sort_css_js($a, $b) {
   // First order by group, so that, for example, all items in the CSS_SYSTEM
-  // group appear before items in the CSS_DEFAULT_GROUP, which appear before
+  // group appear before items in the CSS_DEFAULT group, which appear before
   // all items in the CSS_THEME group. Modules may create additional groups by
   // defining their own constants.
   if ($a['group'] < $b['group']) {
@@ -3166,6 +3202,12 @@ function drupal_pre_render_styles($elements) {
   // URL changed.
   $query_string = variable_get('css_js_query_string', '0');
 
+  // For inline CSS to validate as XHTML, all CSS containing XHTML needs to be
+  // wrapped in CDATA. To make that backwards compatible with HTML 4, we need to
+  // comment out the CDATA-tag.
+  $embed_prefix = "\n<!--/*--><![CDATA[/*><!--*/\n";
+  $embed_suffix = "\n/*]]>*/-->\n";
+
   // Defaults for LINK and STYLE elements.
   $link_element_defaults = array(
     '#type' => 'html_tag',
@@ -3273,6 +3315,8 @@ function drupal_pre_render_styles($elements) {
         if (isset($group['data'])) {
           $element = $style_element_defaults;
           $element['#value'] = $group['data'];
+          $element['#value_prefix'] = $embed_prefix;
+          $element['#value_suffix'] = $embed_suffix;
           $element['#attributes']['media'] = $group['media'];
           $element['#browsers'] = $group['browsers'];
           $elements[] = $element;
@@ -3281,6 +3325,8 @@ function drupal_pre_render_styles($elements) {
           foreach ($group['items'] as $item) {
             $element = $style_element_defaults;
             $element['#value'] = $item['data'];
+            $element['#value_prefix'] = $embed_prefix;
+            $element['#value_suffix'] = $embed_suffix;
             $element['#attributes']['media'] = $item['media'];
             $element['#browsers'] = $group['browsers'];
             $elements[] = $element;
@@ -3343,10 +3389,19 @@ function drupal_build_css_cache($css) {
       // Only 'file' stylesheets can be aggregated.
       if ($stylesheet['type'] == 'file') {
         $contents = drupal_load_stylesheet($stylesheet['data'], TRUE);
-        // Return the path to where this CSS file originated from.
-        $base = base_path() . dirname($stylesheet['data']) . '/';
-        _drupal_build_css_path(NULL, $base);
-        // Prefix all paths within this CSS file, ignoring external and absolute paths.
+
+        // Build the base URL of this CSS file: start with the full URL.
+        $css_base_url = file_create_url($stylesheet['data']);
+        // Move to the parent.
+        $css_base_url = substr($css_base_url, 0, strrpos($css_base_url, '/'));
+        // Simplify to a relative URL if the stylesheet URL starts with the
+        // base URL of the website.
+        if (substr($css_base_url, 0, strlen($GLOBALS['base_root'])) == $GLOBALS['base_root']) {
+          $css_base_url = substr($css_base_url, strlen($GLOBALS['base_root']));
+        }
+
+        _drupal_build_css_path(NULL, $css_base_url . '/');
+        // Anchor all paths in the CSS with its base URL, ignoring external and absolute paths.
         $data .= preg_replace_callback('/url\(\s*[\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\s*\)/i', '_drupal_build_css_path', $contents);
       }
     }
@@ -3422,34 +3477,40 @@ function _drupal_build_css_path($matches, $base = NULL) {
  *   Name of the stylesheet to be processed.
  * @param $optimize
  *   Defines if CSS contents should be compressed or not.
+ * @param $reset_basepath
+ *   Used internally to facilitate recursive resolution of @import commands.
+ *
  * @return
  *   Contents of the stylesheet, including any resolved @import commands.
  */
-function drupal_load_stylesheet($file, $optimize = NULL) {
-  // $_optimize does not use drupal_static as it is set by $optimize.
-  static $_optimize;
-  // Store optimization parameter for preg_replace_callback with nested @import loops.
+function drupal_load_stylesheet($file, $optimize = NULL, $reset_basepath = TRUE) {
+  // These statics are not cache variables, so we don't use drupal_static().
+  static $_optimize, $basepath;
+  if ($reset_basepath) {
+    $basepath = '';
+  }
+  // Store the value of $optimize for preg_replace_callback with nested
+  // @import loops.
   if (isset($optimize)) {
     $_optimize = $optimize;
   }
 
-  $contents = '';
-  if (file_exists($file)) {
-    // Load the local CSS stylesheet.
-    $contents = file_get_contents($file);
-
-    // Change to the current stylesheet's directory.
-    $cwd = getcwd();
-    chdir(dirname($file));
-
-    // Process the stylesheet.
-    $contents = drupal_load_stylesheet_content($contents, $_optimize);
+  // Stylesheets are relative one to each other. Start by adding a base path
+  // prefix provided by the parent stylesheet (if necessary).
+  if ($basepath && !file_uri_scheme($file)) {
+    $file = $basepath . '/' . $file;
+  }
+  $basepath = dirname($file);
 
-    // Change back directory.
-    chdir($cwd);
+  // Load the CSS stylesheet. We suppress errors because themes may specify
+  // stylesheets in their .info file that don't exist in the theme's path,
+  // but are merely there to disable certain module CSS files.
+  if ($contents = @file_get_contents($file)) {
+    // Return the processed stylesheet.
+    return drupal_load_stylesheet_content($contents, $_optimize);
   }
 
-  return $contents;
+  return '';
 }
 
 /**
@@ -3483,12 +3544,9 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
     );
     // Remove certain whitespace.
     // There are different conditions for removing leading and trailing
-    // whitespace. To be able to use a single backreference in the replacement
-    // string, the outer pattern uses the ?| modifier, which makes all contained
-    // subpatterns appear in \1.
+    // whitespace.
     // @see http://php.net/manual/en/regexp.reference.subpatterns.php
-    $contents = preg_replace('<
-      (?|
+    $contents = preg_replace_callback('<
       # Strip leading and trailing whitespace.
         \s*([@{};,])\s*
       # Strip only leading whitespace from:
@@ -3498,12 +3556,12 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
       # - Opening parenthesis: Retain "@media (bar) and foo".
       # - Colon: Retain :pseudo-selectors.
       | ([\(:])\s+
-      )
     >xS',
-      '\1',
+      '_drupal_load_stylesheet_content',
       $contents
     );
     // End the file with a new line.
+    $contents = trim($contents);
     $contents .= "\n";
   }
 
@@ -3513,6 +3571,16 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
   return $contents;
 }
 
+/**
+ * Helper for drupal_load_stylesheet_content().
+ */
+function _drupal_load_stylesheet_content($matches) {
+  // Discard the full match.
+  unset($matches[0]);
+  // Use the non-empty match.
+  return current(array_filter($matches));
+}
+
 /**
  * Loads stylesheets recursively and returns contents with corrected paths.
  *
@@ -3522,7 +3590,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
 function _drupal_load_stylesheet($matches) {
   $filename = $matches[1];
   // Load the imported stylesheet and replace @import commands in there as well.
-  $file = drupal_load_stylesheet($filename);
+  $file = drupal_load_stylesheet($filename, NULL, FALSE);
 
   // Determine the file's directory.
   $directory = dirname($filename);
@@ -3751,6 +3819,7 @@ function drupal_region_class($region) {
  *     array('type' => 'inline', 'scope' => 'footer', 'weight' => 5)
  *   );
  *   drupal_add_js('http://example.com/example.js', 'external');
+ *   drupal_add_js(array('myModule' => array('key' => 'value')), 'setting');
  * @endcode
  *
  * Calling drupal_static_reset('drupal_add_js') will clear all JavaScript added
@@ -3770,7 +3839,7 @@ function drupal_region_class($region) {
  * all typical visitors and most pages of a site. It is critical that all
  * preprocessed files are added unconditionally on every page, even if the
  * files are not needed on a page. This is normally done by calling
- * drupal_add_css() in a hook_init() implementation.
+ * drupal_add_js() in a hook_init() implementation.
  *
  * Non-preprocessed files should only be added to the page when they are
  * actually needed.
@@ -3783,9 +3852,11 @@ function drupal_region_class($region) {
  *     hosted on the local server. These files will not be aggregated if
  *     JavaScript aggregation is enabled.
  *   - 'setting': An associative array with configuration options. The array is
- *     directly placed in Drupal.settings. All modules should wrap their actual
- *     configuration settings in another variable to prevent conflicts in the
- *     Drupal.settings namespace.
+ *     merged directly into Drupal.settings. All modules should wrap their
+ *     actual configuration settings in another variable to prevent conflicts in
+ *     the Drupal.settings namespace. Items added with a string key will replace
+ *     existing settings with that key; items with numeric array keys will be
+ *     added to the existing settings array.
  * @param $options
  *   (optional) A string defining the type of JavaScript that is being added in
  *   the $data parameter ('file'/'setting'/'inline'/'external'), or an
@@ -3912,7 +3983,7 @@ function drupal_add_js($data = NULL, $options = NULL) {
       );
       // Register all required libraries.
       drupal_add_library('system', 'jquery', TRUE);
-      drupal_add_library('system', 'once', TRUE);
+      drupal_add_library('system', 'jquery.once', TRUE);
     }
 
     switch ($options['type']) {
@@ -4070,7 +4141,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
       case 'setting':
         $js_element = $element;
         $js_element['#value_prefix'] = $embed_prefix;
-        $js_element['#value'] = 'jQuery.extend(Drupal.settings, ' . drupal_json_encode(call_user_func_array('array_merge_recursive', $item['data'])) . ");";
+        $js_element['#value'] = 'jQuery.extend(Drupal.settings, ' . drupal_json_encode(drupal_array_merge_deep_array($item['data'])) . ");";
         $js_element['#value_suffix'] = $embed_suffix;
         $output .= theme('html_tag', array('element' => $js_element));
         break;
@@ -4143,12 +4214,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
 }
 
 /**
- * Add to the page all structures attached to a render() structure.
+ * Adds attachments to a render() structure.
  *
  * Libraries, JavaScript, CSS and other types of custom structures are attached
- * to elements using the #attached property. The #attached property contains an
- * associative array, where the keys are the the types of the structure, and
- * the value the attached data. For example:
+ * to elements using the #attached property. The #attached property is an
+ * associative array, where the keys are the the attachment types and the values
+ * are the attached data. For example:
  * @code
  * $build['#attached'] = array(
  *   'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
@@ -4159,13 +4230,21 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
  * 'js', 'css', and 'library' are types that get special handling.  For any
  * other kind of attached data, the array key must be the full name of the
  * callback function and each value an array of arguments. For example:
- *
  * @code
  * $build['#attached']['drupal_add_http_header'] = array(
  *   array('Content-Type', 'application/rss+xml; charset=utf-8'),
  * );
  * @endcode
  *
+ * External 'js' and 'css' files can also be loaded. For example:
+ * @code
+ * $build['#attached']['js'] = array(
+ *   'http://code.jquery.com/jquery-1.4.2.min.js' => array(
+ *     'type' => 'external',
+ *   ),
+ * );
+ * @endcode
+ *
  * @param $elements
  *   The structured array describing the data being rendered.
  * @param $group
@@ -4174,12 +4253,16 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
  *   assigned to them.
  * @param $dependency_check
  *   When TRUE, will exit if a given library's dependencies are missing. When
- *   set to FALSE, will continue to add the libraries, even though one of the
+ *   set to FALSE, will continue to add the libraries, even though one or more
  *   dependencies are missing. Defaults to FALSE.
+ * @param $every_page
+ *   Set to TRUE to indicate that the attachments are added to every page on the
+ *   site. Only attachments with the every_page flag set to TRUE can participate
+ *   in JavaScript/CSS aggregation.
  *
  * @return
- *   Will return FALSE if there were any missing library dependencies. TRUE will
- *   be returned if all library dependencies were met.
+ *   FALSE if there were any missing library dependencies; TRUE if all library
+ *   dependencies were met.
  *
  * @see drupal_add_library()
  * @see drupal_add_js()
@@ -4377,7 +4460,7 @@ function drupal_process_attached($elements, $group = JS_DEFAULT, $dependency_che
  * @see form_example_states_form()
  */
 function drupal_process_states(&$elements) {
-  $elements['#attached']['js']['misc/states.js'] = array('group' => JS_LIBRARY, 'weight' => 1);
+  $elements['#attached']['library'][] = array('system', 'drupal.states');
   $elements['#attached']['js'][] = array(
     'type' => 'setting',
     'data' => array('states' => array('#' . $elements['#id'] => $elements['#states'])),
@@ -4391,16 +4474,20 @@ function drupal_process_states(&$elements) {
  * settings, and optionally requiring another library. For example, a library
  * can be a jQuery plugin, a JavaScript framework, or a CSS framework. This
  * function allows modules to load a library defined/shipped by itself or a
- * depending module; without having to add all files of the library separately.
+ * depending module, without having to add all files of the library separately.
  * Each library is only loaded once.
  *
  * @param $module
  *   The name of the module that registered the library.
  * @param $name
  *   The name of the library to add.
+ * @param $every_page
+ *   Set to TRUE if this library is added to every page on the site. Only items
+ *   with the every_page flag set to TRUE can participate in aggregation.
+ *
  * @return
- *   TRUE when the library was successfully added or FALSE if the library or one
- *   of its dependencies could not be added.
+ *   TRUE if the library was successfully added; FALSE if the library or one of
+ *   its dependencies could not be added.
  *
  * @see drupal_get_library()
  * @see hook_library()
@@ -4444,10 +4531,14 @@ function drupal_add_library($module, $name, $every_page = NULL) {
  *
  * @param $module
  *   The name of a module that registered a library.
- * @param $library
- *   The name of a registered library.
+ * @param $name
+ *   (optional) The name of a registered library to retrieve. By default, all
+ *   libraries registered by $module are returned.
+ *
  * @return
- *   The definition of the requested library, if existent, or FALSE.
+ *   The definition of the requested library, if $name was passed and it exists,
+ *   or FALSE if it does not exist. If no $name was passed, an associative array
+ *   of libraries registered by $module is returned (which may be empty).
  *
  * @see drupal_add_library()
  * @see hook_library()
@@ -4456,7 +4547,7 @@ function drupal_add_library($module, $name, $every_page = NULL) {
  * @todo The purpose of drupal_get_*() is completely different to other page
  *   requisite API functions; find and use a different name.
  */
-function drupal_get_library($module, $name) {
+function drupal_get_library($module, $name = NULL) {
   $libraries = &drupal_static(__FUNCTION__, array());
 
   if (!isset($libraries[$module])) {
@@ -4479,11 +4570,13 @@ function drupal_get_library($module, $name) {
     }
     $libraries[$module] = $module_libraries;
   }
-  if (empty($libraries[$module][$name])) {
-    $libraries[$module][$name] = FALSE;
+  if (isset($name)) {
+    if (!isset($libraries[$module][$name])) {
+      $libraries[$module][$name] = FALSE;
+    }
+    return $libraries[$module][$name];
   }
-
-  return $libraries[$module][$name];
+  return $libraries[$module];
 }
 
 /**
@@ -4599,7 +4692,7 @@ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgro
     // Add the table drag JavaScript to the page before the module JavaScript
     // to ensure that table drag behaviors are registered before any module
     // uses it.
-    drupal_add_js('misc/jquery.cookie.js', array('weight' => -2));
+    drupal_add_library('system', 'jquery.cookie');
     drupal_add_js('misc/tabledrag.js', array('weight' => -1));
     $js_added = TRUE;
   }
@@ -5068,7 +5161,7 @@ function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1)
     // compatible with Drupal core. This may occur during upgrades of Drupal
     // core when new modules exist in core while older contrib modules with the
     // same name exist in a directory such as sites/all/modules/.
-    foreach (array_intersect_key($files_to_add, $files) as $key => $file) {
+    foreach (array_intersect_key($files_to_add, $files) as $file_key => $file) {
       // If it has no info file, then we just behave liberally and accept the
       // new resource on the list for merging.
       if (file_exists($info_file = dirname($file->uri) . '/' . $file->name . '.info')) {
@@ -5079,7 +5172,7 @@ function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1)
         // from the array for the current search directory, so it is not
         // overwritten when merged with the $files array.
         if (isset($info['core']) && $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
-          unset($files_to_add[$key]);
+          unset($files_to_add[$file_key]);
         }
       }
     }
@@ -5249,6 +5342,97 @@ function drupal_pre_render_link($element) {
   return $element;
 }
 
+/**
+ * #pre_render callback that collects child links into a single array.
+ *
+ * This function can be added as a pre_render callback for a renderable array,
+ * usually one which will be themed by theme_links(). It iterates through all
+ * unrendered children of the element, collects any #links properties it finds,
+ * merges them into the parent element's #links array, and prevents those
+ * children from being rendered separately.
+ *
+ * The purpose of this is to allow links to be logically grouped into related
+ * categories, so that each child group can be rendered as its own list of
+ * links if drupal_render() is called on it, but calling drupal_render() on the
+ * parent element will still produce a single list containing all the remaining
+ * links, regardless of what group they were in.
+ *
+ * A typical example comes from node links, which are stored in a renderable
+ * array similar to this:
+ * @code
+ * $node->content['links'] = array(
+ *   '#theme' => 'links__node',
+ *   '#pre_render' = array('drupal_pre_render_links'),
+ *   'comment' => array(
+ *     '#theme' => 'links__node__comment',
+ *     '#links' => array(
+ *       // An array of links associated with node comments, suitable for
+ *       // passing in to theme_links().
+ *     ),
+ *   ),
+ *   'statistics' => array(
+ *     '#theme' => 'links__node__statistics',
+ *     '#links' => array(
+ *       // An array of links associated with node statistics, suitable for
+ *       // passing in to theme_links().
+ *     ),
+ *   ),
+ *   'translation' => array(
+ *     '#theme' => 'links__node__translation',
+ *     '#links' => array(
+ *       // An array of links associated with node translation, suitable for
+ *       // passing in to theme_links().
+ *     ),
+ *   ),
+ * );
+ * @endcode
+ *
+ * In this example, the links are grouped by functionality, which can be
+ * helpful to themers who want to display certain kinds of links independently.
+ * For example, adding this code to node.tpl.php will result in the comment
+ * links being rendered as a single list:
+ * @code
+ * print render($content['links']['comment']);
+ * @endcode
+ *
+ * (where $node->content has been transformed into $content before handing
+ * control to the node.tpl.php template).
+ *
+ * The pre_render function defined here allows the above flexibility, but also
+ * allows the following code to be used to render all remaining links into a
+ * single list, regardless of their group:
+ * @code
+ * print render($content['links']);
+ * @endcode
+ *
+ * In the above example, this will result in the statistics and translation
+ * links being rendered together in a single list (but not the comment links,
+ * which were rendered previously on their own).
+ *
+ * Because of the way this function works, the individual properties of each
+ * group (for example, a group-specific #theme property such as
+ * 'links__node__comment' in the example above, or any other property such as
+ * #attributes or #pre_render that is attached to it) are only used when that
+ * group is rendered on its own. When the group is rendered together with other
+ * children, these child-specific properties are ignored, and only the overall
+ * properties of the parent are used.
+ */
+function drupal_pre_render_links($element) {
+  $element += array('#links' => array());
+  foreach (element_children($element) as $key) {
+    $child = &$element[$key];
+    // If the child has links which have not been printed yet and the user has
+    // access to it, merge its links in to the parent.
+    if (isset($child['#links']) && empty($child['#printed']) && (!isset($child['#access']) || $child['#access'])) {
+      $element['#links'] += $child['#links'];
+      // Mark the child as having been printed already (so that its links
+      // cannot be mistakenly rendered twice).
+      $child['#printed'] = TRUE;
+    }
+  }
+  return $element;
+}
+
 /**
  * #pre_render callback to append contents in #markup to #children.
  *
@@ -5667,9 +5851,6 @@ function drupal_render_cache_by_query($query, $function, $expire = CACHE_TEMPORA
   );
 }
 
-/**
-
-
 /**
  * Helper function for building cache ids.
  *
@@ -5763,6 +5944,9 @@ function element_sort_by_title($a, $b) {
 
 /**
  * Retrieve the default properties for the defined element type.
+ *
+ * @param $type
+ *   An element type as defined by hook_element_info().
  */
 function element_info($type) {
   // Use the advanced drupal_static() pattern, since this is called very often.
@@ -5784,6 +5968,21 @@ function element_info($type) {
   return isset($cache[$type]) ? $cache[$type] : array();
 }
 
+/**
+ * Retrieve a single property for the defined element type.
+ *
+ * @param $type
+ *   An element type as defined by hook_element_info().
+ * @param $property_name
+ *   The property within the element type that should be returned.
+ * @param $default
+ *   (Optional) The value to return if the element type does not specify a
+ *   value for the property. Defaults to NULL.
+ */
+function element_info_property($type, $property_name, $default = NULL) {
+  return (($info = element_info($type)) && array_key_exists($property_name, $info)) ? $info[$property_name] : $default;
+}
+
 /**
  * Function used by uasort to sort structured arrays by weight, without the property weight prefix.
  */
@@ -5796,6 +5995,19 @@ function drupal_sort_weight($a, $b) {
   return ($a_weight < $b_weight) ? -1 : 1;
 }
 
+/**
+ * Array sorting callback; sorts elements by 'title' key.
+ */
+function drupal_sort_title($a, $b) {
+  if (!isset($b['title'])) {
+    return -1;
+  }
+  if (!isset($a['title'])) {
+    return 1;
+  }
+  return strcasecmp($a['title'], $b['title']);
+}
+
 /**
  * Check if the key is a property.
  */
@@ -5965,14 +6177,22 @@ function element_set_attributes(array &$element, array $map) {
  *   An array of parent keys, starting with the outermost key.
  * @param $value
  *   The value to set.
+ * @param $force
+ *   (Optional) If TRUE, the value is forced into the structure even if it
+ *   requires the deletion of an already existing non-array parent value. If
+ *   FALSE, PHP throws an error if trying to add into a value that is not an
+ *   array. Defaults to FALSE.
  *
  * @see drupal_array_get_nested_value()
  */
-function drupal_array_set_nested_value(array &$array, array $parents, $value) {
+function drupal_array_set_nested_value(array &$array, array $parents, $value, $force = FALSE) {
   $ref = &$array;
   foreach ($parents as $parent) {
-    // Note that PHP is fine with referencing a not existing array key - in this
-    // case it just creates an entry with NULL as value.
+    // PHP auto-creates container arrays and NULL entries without error if $ref
+    // is NULL, but throws an error if $ref is set, but not an array.
+    if ($force && isset($ref) && !is_array($ref)) {
+      $ref = array();
+    }
     $ref = &$ref[$parent];
   }
   $ref = $value;
@@ -6036,10 +6256,7 @@ function drupal_array_set_nested_value(array &$array, array $parents, $value) {
 function drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
   $ref = &$array;
   foreach ($parents as $parent) {
-    // array_key_exists() is slower than isset() and triggers notices if the
-    // second argument is not an array, so only call it when absolutely
-    // necessary.
-    if (isset($ref[$parent]) || (is_array($ref) && array_key_exists($parent, $ref))) {
+    if (is_array($ref) && array_key_exists($parent, $ref)) {
       $ref = &$ref[$parent];
     }
     else {
@@ -6093,9 +6310,6 @@ function drupal_array_nested_key_exists(array $array, array $parents) {
 function drupal_common_theme() {
   return array(
     // theme.inc
-    'placeholder' => array(
-      'variables' => array('text' => NULL)
-    ),
     'html' => array(
       'render element' => 'page',
       'template' => 'html',
@@ -6210,10 +6424,6 @@ function drupal_common_theme() {
     'pager_link' => array(
       'variables' => array('text' => NULL, 'page_new' => NULL, 'element' => NULL, 'parameters' => array(), 'attributes' => array()),
     ),
-    // from locale.inc
-    'locale_admin_manage_screen' => array(
-      'render element' => 'form',
-    ),
     // from menu.inc
     'menu_link' => array(
       'render element' => 'element',
@@ -6228,7 +6438,7 @@ function drupal_common_theme() {
       'render element' => 'element',
     ),
     'menu_local_tasks' => array(
-      'variables' => array(),
+      'variables' => array('primary' => array(), 'secondary' => array()),
     ),
     // from form.inc
     'select' => array(
@@ -6286,7 +6496,7 @@ function drupal_common_theme() {
       'render element' => 'element',
     ),
     'form_required_marker' => array(
-      'arguments' => array('element' => NULL),
+      'render element' => 'element',
     ),
     'form_element_label' => array(
       'render element' => 'element',
@@ -6625,7 +6835,7 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
  * - name: The real name of the theme for display purposes
  * - description: Brief description
  * - screenshot: Path to screenshot relative to the theme's .info file.
- * - engine: Theme engine, typically: engine = phptemplate
+ * - engine: Theme engine; typically phptemplate.
  * - base: Name of a base theme, if applicable, eg: base = zen
  * - regions: Listed regions eg: region[left] = Left sidebar
  * - features: Features available eg: features[] = logo
@@ -7128,18 +7338,24 @@ function entity_create_stub_entity($entity_type, $ids) {
  * @see hook_entity_info()
  * @see DrupalEntityControllerInterface
  * @see DrupalDefaultEntityController
+ * @see EntityFieldQuery
  *
  * @param $entity_type
  *   The entity type to load, e.g. node or user.
  * @param $ids
  *   An array of entity IDs, or FALSE to load all entities.
  * @param $conditions
- *   An array of conditions in the form 'field' => $value.
+ *   (deprecated) An associative array of conditions on the base table, where
+ *   the keys are the database fields and the values are the values those
+ *   fields must have. Instead, it is preferable to use EntityFieldQuery to
+ *   retrieve a list of entity IDs loadable by this function.
  * @param $reset
  *   Whether to reset the internal cache for the requested entity type.
  *
  * @return
  *   An array of entity objects indexed by their ids.
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
   if ($reset) {
@@ -7148,6 +7364,28 @@ function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset =
   return entity_get_controller($entity_type)->load($ids, $conditions);
 }
 
+/**
+ * Loads the unchanged, i.e. not modified, entity from the database.
+ *
+ * Unlike entity_load() this function ensures the entity is directly loaded from
+ * the database, thus bypassing any static cache. In particular, this function
+ * is useful to determine changes by comparing the entity being saved to the
+ * stored entity.
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $id
+ *   The id of the entity to load.
+ *
+ * @return
+ *   The unchanged entity, or FALSE if the entity cannot be loaded.
+ */
+function entity_load_unchanged($entity_type, $id) {
+  entity_get_controller($entity_type)->resetCache(array($id));
+  $result = entity_get_controller($entity_type)->load(array($id));
+  return reset($result);
+}
+
 /**
  * Get the entity controller class for an entity type.
  */
@@ -7257,13 +7495,16 @@ function entity_uri($entity_type, $entity) {
 /**
  * Returns the label of an entity.
  *
+ * See the 'label callback' component of the hook_entity_info() return value
+ * for more information.
+ *
  * @param $entity_type
- *   The entity type; e.g. 'node' or 'user'.
+ *   The entity type; e.g., 'node' or 'user'.
  * @param $entity
- *   The entity for which to generate a path.
+ *   The entity for which to generate the label.
  *
  * @return
- *   A string with the entity label (e.g. node title), or FALSE if not found.
+ *   The entity label, or FALSE if not found.
  */
 function entity_label($entity_type, $entity) {
   $label = FALSE;
@@ -7296,16 +7537,20 @@ function entity_form_field_validate($entity_type, $form, &$form_state) {
  *
  * During the submission handling of an entity form's "Save", "Preview", and
  * possibly other buttons, the form state's entity needs to be updated with the
- * submitted form values. Each entity form implements its own
- * $form['#builder_function'] for doing this, appropriate for the particular
- * entity and form. Many of these entity builder functions can call this helper
- * function to re-use its logic of copying $form_state['values'][PROPERTY]
- * values to $entity->PROPERTY for all entries in $form_state['values'] that are
- * not field data, and calling field_attach_submit() to copy field data.
+ * submitted form values. Each entity form implements its own builder function
+ * for doing this, appropriate for the particular entity and form, whereas
+ * modules may specify additional builder functions in $form['#entity_builders']
+ * for copying the form values of added form elements to entity properties.
+ * Many of the main entity builder functions can call this helper function to
+ * re-use its logic of copying $form_state['values'][PROPERTY] values to
+ * $entity->PROPERTY for all entries in $form_state['values'] that are not field
+ * data, and calling field_attach_submit() to copy field data. Apart from that
+ * this helper invokes any additional builder functions that have been specified
+ * in $form['#entity_builders'].
  *
  * For some entity forms (e.g., forms with complex non-field data and forms that
  * simultaneously edit multiple entities), this behavior may be inappropriate,
- * so the #builder_function for such forms needs to implement the required
+ * so the builder function for such forms needs to implement the required
  * functionality instead of calling this function.
  */
 function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) {
@@ -7320,6 +7565,13 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st
     $entity->$key = $value;
   }
 
+  // Invoke all specified builders for copying form values to entity properties.
+  if (isset($form['#entity_builders'])) {
+    foreach ($form['#entity_builders'] as $function) {
+      $function($entity_type, $entity, $form, $form_state);
+    }
+  }
+
   // Copy field values to the entity.
   if ($info['fieldable']) {
     field_attach_submit($entity_type, $entity, $form, $form_state);
@@ -7461,3 +7713,39 @@ function drupal_get_updaters() {
   }
   return $updaters;
 }
+
+/**
+ * Drupal FileTransfer registry.
+ *
+ * @return
+ *   Returns the Drupal FileTransfer class registry.
+ *
+ * @see FileTransfer
+ * @see hook_filetransfer_info()
+ * @see hook_filetransfer_info_alter()
+ */
+function drupal_get_filetransfer_info() {
+  $info = &drupal_static(__FUNCTION__);
+  if (!isset($info)) {
+    // Since we have to manually set the 'file path' default for each
+    // module separately, we can't use module_invoke_all().
+    $info = array();
+    foreach (module_implements('filetransfer_info') as $module) {
+      $function = $module . '_filetransfer_info';
+      if (function_exists($function)) {
+        $result = $function();
+        if (isset($result) && is_array($result)) {
+          foreach ($result as &$values) {
+            if (empty($values['file path'])) {
+              $values['file path'] = drupal_get_path('module', $module);
+            }
+          }
+          $info = array_merge_recursive($info, $result);
+        }
+      }
+    }
+    drupal_alter('filetransfer_info', $info);
+    uasort($info, 'drupal_sort_weight');
+  }
+  return $info;
+}
diff --git a/includes/database/database.inc b/includes/database/database.inc
index 104d76f77c8075b09bf213084fc84a2132ee5a0c..e6cf0d5c3384966849961a140f7481b8c998b369 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.141 2010/10/15 18:03:43 webchick Exp $
+// $Id: database.inc,v 1.147 2010/12/22 07:48:56 webchick Exp $
 
 /**
  * @file
@@ -193,6 +193,17 @@ abstract class DatabaseConnection extends PDO {
    */
   protected $target = NULL;
 
+  /**
+   * The key representing this connection.
+   * 
+   * The key is a unique string which identifies a database connection. A
+   * connection can be a single server or a cluster of master and slaves (use
+   * target to pick between master and slave).
+   *
+   * @var string
+   */
+  protected $key = NULL;
+
   /**
    * The current database logging object for this connection.
    *
@@ -469,6 +480,28 @@ abstract class DatabaseConnection extends PDO {
     return $this->target;
   }
 
+  /**
+   * Tells this connection object what its key is.
+   *
+   * @param $target
+   *   The key this connection is for.
+   */
+  public function setKey($key) {
+    if (!isset($this->key)) {
+      $this->key = $key;
+    }
+  }
+
+  /**
+   * Returns the key this connection is associated with.
+   *
+   * @return
+   *   The key of this connection.
+   */
+  public function getKey() {
+    return $this->key;
+  }
+
   /**
    * Associates a logging object with this connection.
    *
@@ -648,13 +681,20 @@ abstract class DatabaseConnection extends PDO {
    *
    * @param string $class
    *   The class for which we want the potentially driver-specific class.
+   * @param array $files
+   *   The name of the files in which the driver-specific class can be.
+   * @param $use_autoload
+   *   If TRUE, attempt to load classes using PHP's autoload capability
+   *   as well as the manual approach here.
    * @return string
    *   The name of the class that should be used for this driver.
    */
-  public function getDriverClass($class) {
+  public function getDriverClass($class, array $files = array(), $use_autoload = FALSE) {
     if (empty($this->driverClasses[$class])) {
-      $this->driverClasses[$class] = $class . '_' . $this->driver();
-      if (!class_exists($this->driverClasses[$class])) {
+      $driver = $this->driver();
+      $this->driverClasses[$class] = $class . '_' . $driver;
+      Database::loadDriverFile($driver, $files);
+      if (!class_exists($this->driverClasses[$class], $use_autoload)) {
         $this->driverClasses[$class] = $class;
       }
     }
@@ -662,7 +702,7 @@ abstract class DatabaseConnection extends PDO {
   }
 
   /**
-   * Prepares and returns a SELECT query object with the specified ID.
+   * Prepares and returns a SELECT query object.
    *
    * @param $table
    *   The base table for this query, that is, the first table in the FROM
@@ -681,12 +721,12 @@ abstract class DatabaseConnection extends PDO {
    * @see SelectQuery
    */
   public function select($table, $alias = NULL, array $options = array()) {
-    $class = $this->getDriverClass('SelectQuery');
+    $class = $this->getDriverClass('SelectQuery', array('query.inc', 'select.inc'));
     return new $class($table, $alias, $this, $options);
   }
 
   /**
-   * Prepares and returns an INSERT query object with the specified ID.
+   * Prepares and returns an INSERT query object.
    *
    * @param $options
    *   An array of options on the query.
@@ -697,12 +737,12 @@ abstract class DatabaseConnection extends PDO {
    * @see InsertQuery
    */
   public function insert($table, array $options = array()) {
-    $class = $this->getDriverClass('InsertQuery');
+    $class = $this->getDriverClass('InsertQuery', array('query.inc'));
     return new $class($this, $table, $options);
   }
 
   /**
-   * Prepares and returns a MERGE query object with the specified ID.
+   * Prepares and returns a MERGE query object.
    *
    * @param $options
    *   An array of options on the query.
@@ -713,13 +753,13 @@ abstract class DatabaseConnection extends PDO {
    * @see MergeQuery
    */
   public function merge($table, array $options = array()) {
-    $class = $this->getDriverClass('MergeQuery');
+    $class = $this->getDriverClass('MergeQuery', array('query.inc'));
     return new $class($this, $table, $options);
   }
 
 
   /**
-   * Prepares and returns an UPDATE query object with the specified ID.
+   * Prepares and returns an UPDATE query object.
    *
    * @param $options
    *   An array of options on the query.
@@ -730,12 +770,12 @@ abstract class DatabaseConnection extends PDO {
    * @see UpdateQuery
    */
   public function update($table, array $options = array()) {
-    $class = $this->getDriverClass('UpdateQuery');
+    $class = $this->getDriverClass('UpdateQuery', array('query.inc'));
     return new $class($this, $table, $options);
   }
 
   /**
-   * Prepares and returns a DELETE query object with the specified ID.
+   * Prepares and returns a DELETE query object.
    *
    * @param $options
    *   An array of options on the query.
@@ -746,7 +786,7 @@ abstract class DatabaseConnection extends PDO {
    * @see DeleteQuery
    */
   public function delete($table, array $options = array()) {
-    $class = $this->getDriverClass('DeleteQuery');
+    $class = $this->getDriverClass('DeleteQuery', array('query.inc'));
     return new $class($this, $table, $options);
   }
 
@@ -762,7 +802,7 @@ abstract class DatabaseConnection extends PDO {
    * @see TruncateQuery
    */
   public function truncate($table, array $options = array()) {
-    $class = $this->getDriverClass('TruncateQuery');
+    $class = $this->getDriverClass('TruncateQuery', array('query.inc'));
     return new $class($this, $table, $options);
   }
 
@@ -776,7 +816,7 @@ abstract class DatabaseConnection extends PDO {
    */
   public function schema() {
     if (empty($this->schema)) {
-      $class = $this->getDriverClass('DatabaseSchema');
+      $class = $this->getDriverClass('DatabaseSchema', array('schema.inc'));
       if (class_exists($class)) {
         $this->schema = new $class($this);
       }
@@ -1097,7 +1137,7 @@ abstract class DatabaseConnection extends PDO {
   }
 
   /**
-   * Returns the type of the database being accessed.
+   * Returns the name of the PDO driver for this connection.
    */
   abstract public function databaseType();
 
@@ -1532,6 +1572,7 @@ abstract class Database {
     require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc';
     $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
     $new_connection->setTarget($target);
+    $new_connection->setKey($key);
 
     // If we have any active logging objects for this connection key, we need
     // to associate them with the connection we just opened.
@@ -1581,6 +1622,34 @@ abstract class Database {
     self::$ignoreTargets[$key][$target] = TRUE;
   }
 
+  /**
+   * Load a file for the database that might hold a class.
+   *
+   * @param $driver
+   *   The name of the driver.
+   * @param array $files
+   *   The name of the files the driver specific class can be.
+   */
+  public static function loadDriverFile($driver, array $files = array()) {
+    static $base_path;
+
+    if (empty($base_path)) {
+      $base_path = dirname(realpath(__FILE__));
+    }
+
+    $driver_base_path = "$base_path/$driver";
+    foreach ($files as $file) {
+      // Load the base file first so that classes extending base classes will
+      // have the base class loaded.
+      foreach (array("$base_path/$file", "$driver_base_path/$file") as $filename) {
+        // The OS caches file_exists() and PHP caches require_once(), so
+        // we'll let both of those take care of performance here.
+        if (file_exists($filename)) {
+          require_once $filename;
+        }
+      }
+    }
+  }
 }
 
 /**
@@ -2108,82 +2177,6 @@ class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface {
   }
 }
 
-/**
- * Autoload callback for the database system.
- */
-function db_autoload($class) {
-  static $base_path = '';
-  static $checked = array();
-
-  static $files = array(
-    'query.inc' => array(
-      'QueryPlaceholderInterface',
-      'QueryConditionInterface', 'DatabaseCondition',
-      'Query', 'DeleteQuery', 'InsertQuery', 'UpdateQuery', 'MergeQuery', 'TruncateQuery',
-      'QueryAlterableInterface',
-    ),
-    'select.inc' => array('QueryAlterableInterface', 'SelectQueryInterface', 'SelectQuery', 'SelectQueryExtender'),
-    'database.inc' => array('DatabaseConnection'),
-    'log.inc' => array('DatabaseLog'),
-    'prefetch.inc' => array('DatabaseStatementPrefetch'),
-    'schema.inc' => array('DatabaseSchema'),
-  );
-
-  // If a class doesn't exist, it may get checked a second time
-  // by class_exists().  If so, just bail out now.
-  if (isset($checked[$class])) {
-    return;
-  }
-  $checked[$class] = TRUE;
-
-  if (empty($base_path)) {
-    $base_path = dirname(realpath(__FILE__));
-  }
-
-  // If there is an underscore in the class name, we know it's a
-  // driver-specific file so check for those.  If not, it's a generic.
-  // Note that we use require_once here instead of require because of a
-  // quirk in class_exists().  By default, class_exists() will try to
-  // autoload a class if it's not found.  However, we cannot tell
-  // at this point whether or not the class is going to exist, only
-  // the file that it would be in if it does exist.  That means we may
-  // try to include a file that was already included by another
-  // autoload call, which would break.  Using require_once() neatly
-  // avoids that issue.
-  if (strpos($class, '_') !== FALSE) {
-    list($base, $driver) = explode('_', $class);
-
-    // Drivers have an extra file, and may put their SelectQuery implementation
-    // in the main query file since it's so small.
-    $driver_files = $files;
-    $driver_files['query.inc'][] = 'SelectQuery';
-    $driver_files['install.inc'] = array('DatabaseTasks');
-
-    foreach ($driver_files as $file => $classes) {
-      if (in_array($base, $classes)) {
-        $filename = "{$base_path}/{$driver}/{$file}";
-        // We might end up looking in a file that doesn't exist, so check that.
-        if (file_exists($filename)) {
-          require_once $filename;
-          // If the class now exists, we're done. Otherwise keep searching in
-          // additional files.
-          if (class_exists($class, FALSE) || interface_exists($class, FALSE)) {
-            return;
-          }
-        }
-      }
-    }
-  }
-  else {
-    foreach ($files as $file => $classes) {
-      if (in_array($class, $classes)) {
-        require_once $base_path . '/' . $file;
-        return;
-      }
-    }
-  }
-}
-
 /**
  * The following utility functions are simply convenience wrappers.
  *
@@ -2915,4 +2908,3 @@ function db_ignore_slave() {
     $_SESSION['ignore_slave_server'] = REQUEST_TIME + $duration;
   }
 }
-
diff --git a/includes/database/mysql/install.inc b/includes/database/mysql/install.inc
index 64bf8a1a024d5a87b4030b1f40e7157fbd971de5..e6075b63ecc1efe15eacaa8e7d992f0012a798d0 100644
--- a/includes/database/mysql/install.inc
+++ b/includes/database/mysql/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.4 2010/07/30 01:59:14 dries Exp $
+// $Id: install.inc,v 1.7 2010/11/26 21:36:43 webchick Exp $
 
 /**
  * @file
@@ -10,7 +10,6 @@
  * Specifies installation tasks for MySQL and equivalent databases.
  */
 class DatabaseTasks_mysql extends DatabaseTasks {
-
   /**
    * The PDO driver name for MySQL and equivalent databases.
    *
@@ -22,7 +21,14 @@ class DatabaseTasks_mysql extends DatabaseTasks {
    * Returns a human-readable name string for MySQL and equivalent databases.
    */
   public function name() {
-    return 'MySQL, MariaDB, or equivalent';
+    return st('MySQL, MariaDB, or equivalent');
+  }
+
+  /**
+   * Returns the minimum version for MySQL.
+   */
+  public function minimumVersion() {
+    return '5.0.15';
   }
 }
 
diff --git a/includes/database/mysql/schema.inc b/includes/database/mysql/schema.inc
index 05fe2d5209aa60798cb64abd8bdb1e11de86d386..94fcb821de316aee3f4c92674872ab5cf539723c 100644
--- a/includes/database/mysql/schema.inc
+++ b/includes/database/mysql/schema.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.inc,v 1.43 2010/10/22 15:18:56 webchick Exp $
+// $Id: schema.inc,v 1.44 2010/12/08 06:38:59 webchick Exp $
 
 /**
  * @file
@@ -337,7 +337,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
     $this->connection->query($query);
     if (isset($spec['initial'])) {
       $this->connection->update($table)
-        ->fields(array($field, $spec['initial']))
+        ->fields(array($field => $spec['initial']))
         ->execute();
     }
     if ($fixnull) {
diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc
index 72322ef794f08a97b1adaa7495298dba1f7cc862..beb7f53e9bf5492c2b88fbdabb8a99c6ffbf5431 100644
--- a/includes/database/pgsql/install.inc
+++ b/includes/database/pgsql/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.10 2010/08/16 21:01:23 dries Exp $
+// $Id: install.inc,v 1.14 2010/12/21 21:20:04 webchick Exp $
 
 /**
  * @file
@@ -21,6 +21,10 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
       'function' => 'checkPHPVersion',
       'arguments' => array(),
     );
+    $this->tasks[] = array(
+      'function' => 'checkBinaryOutput',
+      'arguments' => array(),
+    );
     $this->tasks[] = array(
       'function' => 'initializeDatabase',
       'arguments' => array(),
@@ -28,7 +32,11 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
   }
 
   public function name() {
-    return 'PostgreSQL';
+    return st('PostgreSQL');
+  }
+
+  public function minimumVersion() {
+    return '8.3';
   }
 
   /**
@@ -49,7 +57,8 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
         $text .= 'Recreate the database with %encoding encoding. See !link for more details.';
         $this->fail(st($text, $replacements));
       }
-    } catch (Exception $e) {
+    }
+    catch (Exception $e) {
       $this->fail(st('Drupal could not determine the encoding of the database was set to UTF-8'));
     }
   }
@@ -71,6 +80,60 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
     };
   }
 
+  /**
+   * Check Binary Output.
+   *
+   * Unserializing does not work on Postgresql 9 when bytea_output is 'hex'.
+   */
+  function checkBinaryOutput() {
+    // PostgreSQL < 9 doesn't support bytea_output, so verify we are running
+    // at least PostgreSQL 9.
+    $database_connection = Database::getConnection();
+    if (version_compare($database_connection->version(), '9') >= 0) {
+      if (!$this->checkBinaryOutputSuccess()) {
+        // First try to alter the database. If it fails, raise an error telling
+        // the user to do it themselves.
+        $connection_options = $database_connection->getConnectionOptions();
+        // It is safe to include the database name directly here, because this
+        // code is only called when a connection to the database is already
+        // established, thus the database name is guaranteed to be a correct
+        // value.
+        $query = "ALTER DATABASE \"" . $connection_options['database'] . "\" SET bytea_output = 'escape';";
+        try {
+          db_query($query);
+        }
+        catch (Exception $e) {
+          // Ignore possible errors when the user doesn't have the necessary
+          // privileges to ALTER the database.
+        }
+
+        // Close the database connection so that the configuration parameter
+        // is applied to the current connection.
+        db_close();
+
+        // Recheck, if it fails, finally just rely on the end user to do the
+        // right thing.
+        if (!$this->checkBinaryOutputSuccess()) {
+          $replacements = array(
+            '%setting' => 'bytea_output',
+            '%current_value' => 'hex',
+            '%needed_value' => 'escape',
+            '!query' => "<code>" . $query . "</code>",
+          );
+          $this->fail(st("The %setting setting is currently set to '%current_value', but needs to be '%needed_value'. Change this by running the following query: !query", $replacements));
+        }
+      }
+    }
+  }
+
+  /**
+   * Verify that a binary data roundtrip returns the original string.
+   */
+  protected function checkBinaryOutputSuccess() {
+    $bytea_output = db_query("SELECT 'encoding'::bytea AS output")->fetchField();
+    return ($bytea_output == 'encoding');
+  }
+
   /**
    * Make PostgreSQL Drupal friendly.
    */
diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc
index dcd753eea2887d04b2c9cc87f42634b45b122cae..b18b570051e0d90304bab441b30b33d271700453 100644
--- a/includes/database/pgsql/query.inc
+++ b/includes/database/pgsql/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.23 2010/09/24 21:24:13 webchick Exp $
+// $Id: query.inc,v 1.24 2010/11/29 04:45:10 webchick Exp $
 
 /**
  * @ingroup database
@@ -208,95 +208,3 @@ class UpdateQuery_pgsql extends UpdateQuery {
     return $stmt->rowCount();
   }
 }
-
-class SelectQuery_pgsql extends SelectQuery {
-
-  public function orderRandom() {
-    $alias = $this->addExpression('RANDOM()', 'random_field');
-    $this->orderBy($alias);
-    return $this;
-  }
-
-  /**
-   * Overrides SelectQuery::orderBy().
-   *
-   * PostgreSQL adheres strictly to the SQL-92 standard and requires that when
-   * using DISTINCT or GROUP BY conditions, fields and expressions that are
-   * ordered on also need to be selected. This is a best effort implementation
-   * to handle the cases that can be automated by adding the field if it is not
-   * yet selected.
-   *
-   * @code
-   *   $query = db_select('node', 'n');
-   *   $query->join('node_revision', 'nr', 'n.vid = nr.vid');
-   *   $query
-   *     ->distinct()
-   *     ->fields('n')
-   *     ->orderBy('timestamp');
-   * @endcode
-   *
-   * In this query, it is not possible (without relying on the schema) to know
-   * whether timestamp belongs to node_revisions and needs to be added or
-   * belongs to node and is already selected. Queries like this will need to be
-   * corrected in the original query by adding an explicit call to
-   * SelectQuery::addField() or SelectQuery::fields().
-   *
-   * Since this has a small performance impact, both by the additional
-   * processing in this function and in the database that needs to return the
-   * additional fields, this is done as an override instead of implementing it
-   * directly in SelectQuery::orderBy().
-   */
-  public function orderBy($field, $direction = 'ASC') {
-    // Call parent function to order on this.
-    $return = parent::orderBy($field, $direction);
-
-    // If there is a table alias specified, split it up.
-    if (strpos($field, '.') !== FALSE) {
-      list($table, $table_field) = explode('.', $field);
-    }
-    // Figure out if the field has already been added.
-    foreach ($this->fields as $existing_field) {
-      if (!empty($table)) {
-        // If table alias is given, check if field and table exists.
-        if ($existing_field['table'] == $table && $existing_field['field'] == $table_field) {
-          return $return;
-        }
-      }
-      else {
-        // If there is no table, simply check if the field exists as a field or
-        // an aliased field.
-        if ($existing_field['alias'] == $field) {
-          return $return;
-        }
-      }
-    }
-
-    // Also check expression aliases.
-    foreach ($this->expressions as $expression) {
-      if ($expression['alias'] == $field) {
-        return $return;
-      }
-    }
-
-    // If a table loads all fields, it can not be added again. It would
-    // result in an ambigious alias error because that field would be loaded
-    // twice: Once through table_alias.* and once directly. If the field
-    // actually belongs to a different table, it must be added manually.
-    foreach ($this->tables as $table) {
-      if (!empty($table['all_fields'])) {
-        return $return;
-      }
-    }
-
-    // If $field contains an characters which are not allowed in a field name
-    // it is considered an expression, these can't be handeld automatically
-    // either.
-    if ($this->connection->escapeField($field) != $field) {
-      return $return;
-    }
-
-    // This is a case that can be handled automatically, add the field.
-    $this->addField(NULL, $field);
-    return $return;
-  }
-}
diff --git a/includes/database/pgsql/schema.inc b/includes/database/pgsql/schema.inc
index 0cfd8a4b1b739b627c219f74a581c77751e70239..4ceddcb074616193684030a259424b33d92ce203 100644
--- a/includes/database/pgsql/schema.inc
+++ b/includes/database/pgsql/schema.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.inc,v 1.39 2010/10/22 15:18:56 webchick Exp $
+// $Id: schema.inc,v 1.43 2010/12/29 04:03:42 webchick Exp $
 
 /**
  * @file
@@ -74,6 +74,39 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
     return $this->tableInformation[$key];
   }
 
+  /**
+   * Fetch the list of CHECK constraints used on a field.
+   *
+   * We introspect the database to collect the information required by field
+   * alteration.
+   *
+   * @param $table
+   *   The non-prefixed name of the table.
+   * @param $field
+   *   The name of the field.
+   * @return
+   *   An array of all the checks for the field.
+   */
+  public function queryFieldInformation($table, $field) {
+    $prefixInfo = $this->getPrefixInfo($table, TRUE);
+
+    // Split the key into schema and table for querying.
+    $schema = $prefixInfo['schema'];
+    $table_name = $prefixInfo['table'];
+
+    $field_information = (object) array(
+        'checks' => array(),
+    );
+    $checks = $this->connection->query("SELECT conname FROM pg_class cl INNER JOIN pg_constraint co ON co.conrelid = cl.oid INNER JOIN pg_attribute attr ON attr.attrelid = cl.oid AND attr.attnum = ANY (co.conkey) INNER JOIN pg_namespace ns ON cl.relnamespace = ns.oid WHERE co.contype = 'c' AND ns.nspname = :schema AND cl.relname = :table AND attr.attname = :column", array(
+      ':schema' => $schema,
+      ':table' => $table_name,
+      ':column' => $field,
+    ));
+    $field_information = $checks->fetchCol();
+
+    return $field_information;
+  }
+
   /**
    * Generate SQL to create a new table from a Drupal schema definition.
    *
@@ -335,7 +368,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
     $this->connection->query($query);
     if (isset($spec['initial'])) {
       $this->connection->update($table)
-        ->fields(array($field, $spec['initial']))
+        ->fields(array($field => $spec['initial']))
         ->execute();
     }
     if ($fixnull) {
@@ -469,15 +502,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
     }
 
-    if (!array_key_exists('size', $spec)) {
-      $spec['size'] = 'normal';
-    }
-
-    // Map type definition to the PostgreSQL type.
-    if (!isset($spec['pgsql_type'])) {
-      $map = $this->getFieldTypeMap();
-      $spec['pgsql_type'] = $map[$spec['type'] . ':' . $spec['size']];
-    }
+    $spec = $this->processField($spec);
 
     // We need to typecast the new column to best be able to transfer the data
     // Schema_pgsql::getFieldTypeMap() will return possibilities that are not
@@ -489,8 +514,32 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       $typecast = $spec['pgsql_type'];
     }
 
+    if (in_array($spec['pgsql_type'], array('varchar', 'character', 'text')) && isset($spec['length'])) {
+      $typecast .= '(' . $spec['length'] . ')';
+    }
+    elseif (isset($spec['precision']) && isset($spec['scale'])) {
+      $typecast .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
+    }
+
+    // Remove old check constraints.
+    $field_info = $this->queryFieldInformation($table, $field);
+
+    foreach ($field_info as $check) {
+      $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"');
+    }
+
     $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast);
 
+    if (isset($spec['not null'])) {
+      if ($spec['not null']) {
+        $nullaction = 'SET NOT NULL';
+      }
+      else {
+        $nullaction = 'DROP NOT NULL';
+      }
+      $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" ' . $nullaction);
+    }
+
     if (in_array($spec['pgsql_type'], array('serial', 'bigserial'))) {
       // Type "serial" is known to PostgreSQL, but *only* during table creation,
       // not when altering. Because of that, the sequence needs to be created
@@ -508,6 +557,11 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '"');
     }
 
+    // Add unsigned check if necessary.
+    if (!empty($spec['unsigned'])) {
+      $this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)');
+    }
+
     // Change description if necessary.
     if (!empty($spec['description'])) {
       $this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));
diff --git a/includes/database/pgsql/select.inc b/includes/database/pgsql/select.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f61ccad0c62f9aa840b6e1a26cb0dd900762211d
--- /dev/null
+++ b/includes/database/pgsql/select.inc
@@ -0,0 +1,109 @@
+<?php
+// $Id: select.inc,v 1.1 2010/11/29 19:57:57 webchick Exp $
+
+/**
+ * @file
+ * Select builder for PostgreSQL database engine.
+ */
+
+/**
+ * @ingroup database
+ * @{
+ */
+
+class SelectQuery_pgsql extends SelectQuery {
+
+  public function orderRandom() {
+    $alias = $this->addExpression('RANDOM()', 'random_field');
+    $this->orderBy($alias);
+    return $this;
+  }
+
+  /**
+   * Overrides SelectQuery::orderBy().
+   *
+   * PostgreSQL adheres strictly to the SQL-92 standard and requires that when
+   * using DISTINCT or GROUP BY conditions, fields and expressions that are
+   * ordered on also need to be selected. This is a best effort implementation
+   * to handle the cases that can be automated by adding the field if it is not
+   * yet selected.
+   *
+   * @code
+   *   $query = db_select('node', 'n');
+   *   $query->join('node_revision', 'nr', 'n.vid = nr.vid');
+   *   $query
+   *     ->distinct()
+   *     ->fields('n')
+   *     ->orderBy('timestamp');
+   * @endcode
+   *
+   * In this query, it is not possible (without relying on the schema) to know
+   * whether timestamp belongs to node_revisions and needs to be added or
+   * belongs to node and is already selected. Queries like this will need to be
+   * corrected in the original query by adding an explicit call to
+   * SelectQuery::addField() or SelectQuery::fields().
+   *
+   * Since this has a small performance impact, both by the additional
+   * processing in this function and in the database that needs to return the
+   * additional fields, this is done as an override instead of implementing it
+   * directly in SelectQuery::orderBy().
+   */
+  public function orderBy($field, $direction = 'ASC') {
+    // Call parent function to order on this.
+    $return = parent::orderBy($field, $direction);
+
+    // If there is a table alias specified, split it up.
+    if (strpos($field, '.') !== FALSE) {
+      list($table, $table_field) = explode('.', $field);
+    }
+    // Figure out if the field has already been added.
+    foreach ($this->fields as $existing_field) {
+      if (!empty($table)) {
+        // If table alias is given, check if field and table exists.
+        if ($existing_field['table'] == $table && $existing_field['field'] == $table_field) {
+          return $return;
+        }
+      }
+      else {
+        // If there is no table, simply check if the field exists as a field or
+        // an aliased field.
+        if ($existing_field['alias'] == $field) {
+          return $return;
+        }
+      }
+    }
+
+    // Also check expression aliases.
+    foreach ($this->expressions as $expression) {
+      if ($expression['alias'] == $field) {
+        return $return;
+      }
+    }
+
+    // If a table loads all fields, it can not be added again. It would
+    // result in an ambigious alias error because that field would be loaded
+    // twice: Once through table_alias.* and once directly. If the field
+    // actually belongs to a different table, it must be added manually.
+    foreach ($this->tables as $table) {
+      if (!empty($table['all_fields'])) {
+        return $return;
+      }
+    }
+
+    // If $field contains an characters which are not allowed in a field name
+    // it is considered an expression, these can't be handeld automatically
+    // either.
+    if ($this->connection->escapeField($field) != $field) {
+      return $return;
+    }
+
+    // This is a case that can be handled automatically, add the field.
+    $this->addField(NULL, $field);
+    return $return;
+  }
+}
+
+/**
+ * @} End of "ingroup database".
+ */
+
diff --git a/includes/database/query.inc b/includes/database/query.inc
index e6d2830e49ec319c09a03d513867c6f3204ae745..f2cfc6c33ffc4ea4b4fcbadbb945ce8f09c63fea 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.57 2010/10/18 00:50:36 dries Exp $
+// $Id: query.inc,v 1.60 2010/12/31 20:43:43 webchick Exp $
 
 /**
  * @ingroup database
@@ -17,61 +17,87 @@
 interface QueryConditionInterface {
 
   /**
-   * Helper function to build most common conditional clauses.
+   * Helper function: builds the most common 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.
+   * 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 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
-   *   dependent on the $operator.
+   *   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.
+   *   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, and = otherwise.
+   *
    * @return QueryConditionInterface
    *   The called object.
    */
   public function condition($field, $value = NULL, $operator = NULL);
 
   /**
-   * Add an arbitrary WHERE clause to the query.
+   * Adds an arbitrary WHERE clause to the query.
    *
    * @param $snippet
-   *   A portion of a WHERE clause as a prepared statement. It must use named placeholders,
-   *   not ? placeholders.
+   *   A portion of a WHERE clause as a prepared statement. It must use named
+   *   placeholders, not ? placeholders.
    * @param $args
    *   An associative array of arguments.
+   *
    * @return QueryConditionInterface
    *   The called object.
    */
   public function where($snippet, $args = array());
 
   /**
-   * Set a condition that the specified field be NULL.
+   * Sets a condition that the specified field be NULL.
    *
    * @param $field
    *   The name of the field to check.
+   *
    * @return QueryConditionInterface
    *   The called object.
    */
   public function isNull($field);
 
   /**
-   * Set a condition that the specified field be NOT NULL.
+   * Sets a condition that the specified field be NOT NULL.
    *
    * @param $field
    *   The name of the field to check.
+   *
    * @return QueryConditionInterface
    *   The called object.
    */
   public function isNotNull($field);
 
+  /**
+   * Sets a condition that the specified subquery returns values.
+   * 
+   * @param SelectQueryInterface $select
+   *   The subquery that must contain results.
+   *
+   * @return QueryConditionInterface
+   *   The called object.
+   */
+  public function exists(SelectQueryInterface $select);
+  
+  /**
+   * Sets a condition that the specified subquery returns no values.
+   * 
+   * @param SelectQueryInterface $select
+   *   The subquery that must not contain results.
+   *
+   * @return QueryConditionInterface
+   *   The called object.
+   */
+  public function notExists(SelectQueryInterface $select);
+  
   /**
    * Gets a complete list of all conditions in this conditional clause.
    *
@@ -80,12 +106,13 @@ interface QueryConditionInterface {
    *
    * The data structure that is returned is an indexed array of entries, where
    * each entry looks like the following:
-   *
+   * @code
    * array(
    *   'field' => $field,
    *   'value' => $value,
    *   'operator' => $operator,
    * );
+   * @endcode
    *
    * In the special case that $operator is NULL, the $field is taken as a raw
    * SQL snippet (possibly containing a function) and $value is an associative
@@ -112,7 +139,7 @@ interface QueryConditionInterface {
    *
    * @param $connection
    *   The database connection for which to compile the conditionals.
-   * @param $query
+   * @param $queryPlaceholder
    *   The query this condition belongs to. If not given, the current query is
    *   used.
    */
@@ -130,12 +157,13 @@ interface QueryAlterableInterface {
    *
    * Tags are strings that identify a query. A query may have any number of
    * tags. Tags are used to mark a query so that alter hooks may decide if they
-   * wish to take action. Tags should be all lower-case and contain only letters,
-   * numbers, and underscore, and start with a letter. That is, they should
-   * follow the same rules as PHP identifiers in general.
+   * wish to take action. Tags should be all lower-case and contain only
+   * letters, numbers, and underscore, and start with a letter. That is, they
+   * should follow the same rules as PHP identifiers in general.
    *
    * @param $tag
    *   The tag to add.
+   *
    * @return QueryAlterableInterface
    *   The called object.
    */
@@ -146,6 +174,7 @@ interface QueryAlterableInterface {
    *
    * @param $tag
    *   The tag to check.
+   *
    * @return
    *   TRUE if this query has been marked with this tag, FALSE otherwise.
    */
@@ -156,8 +185,10 @@ interface QueryAlterableInterface {
    *
    * @param $tags
    *   A variable number of arguments, one for each tag to check.
+   *
    * @return
-   *   TRUE if this query has been marked with all specified tags, FALSE otherwise.
+   *   TRUE if this query has been marked with all specified tags, FALSE
+   *   otherwise.
    */
   public function hasAllTags();
 
@@ -166,6 +197,7 @@ interface QueryAlterableInterface {
    *
    * @param $tags
    *   A variable number of arguments, one for each tag to check.
+   *
    * @return
    *   TRUE if this query has been marked with at least one of the specified
    *   tags, FALSE otherwise.
@@ -184,6 +216,7 @@ interface QueryAlterableInterface {
    *   follows the same rules as any other PHP identifier.
    * @param $object
    *   The additional data to add to the query. May be any valid PHP variable.
+   *
    * @return QueryAlterableInterface
    *   The called object.
    */
@@ -194,6 +227,7 @@ interface QueryAlterableInterface {
    *
    * @param $key
    *   The unique identifier for the piece of metadata to retrieve.
+   *
    * @return
    *   The previously attached metadata object, or NULL if one doesn't exist.
    */
@@ -215,9 +249,10 @@ interface QueryPlaceholderInterface {
 }
 
 /**
- * Base class for the query builders.
+ * Base class for query builders.
  *
- * All query builders inherit from a common base class.
+ * Note that query builders use PHP's magic __toString() method to compile the
+ * query object into a prepared statement.
  */
 abstract class Query implements QueryPlaceholderInterface {
 
@@ -228,6 +263,20 @@ abstract class Query implements QueryPlaceholderInterface {
    */
   protected $connection;
 
+  /**
+   * The target of the connection object.
+   * 
+   * @var string
+   */
+  protected $connectionTarget;
+
+  /**
+   * The key of the connection object.
+   * 
+   * @var string
+   */
+  protected $connectionKey;
+
   /**
    * The query options to pass on to the connection object.
    *
@@ -247,26 +296,60 @@ abstract class Query implements QueryPlaceholderInterface {
    */
   protected $comments = array();
 
+  /**
+   * Constructs a Query object.
+   *
+   * @param DatabaseConnection $connection
+   *   Database connection object.
+   * @param array $options
+   *   Array of query options.
+   */
   public function __construct(DatabaseConnection $connection, $options) {
     $this->connection = $connection;
+    $this->connectionKey = $this->connection->getKey();
+    $this->connectionTarget = $this->connection->getTarget();
+
     $this->queryOptions = $options;
   }
 
   /**
-   * Run the query against the database.
+   * Implements the magic __sleep function to disconnect from the database.
+   */
+  public function __sleep() {
+    $keys = get_object_vars($this);
+    unset($keys['connection']);
+    return array_keys($keys);
+  }
+
+  /**
+  * Implements the magic __wakeup function to reconnect to the database.
+   */
+  public function __wakeup() {
+    $this->connection = Database::getConnection($this->connectionTarget, $this->connectionKey);
+  }
+
+  /**
+   * Runs the query against the database.
    */
   abstract protected function execute();
 
   /**
-   * __toString() magic method.
+   * Implements PHP magic __toString method to convert the query to a string.
    *
-   * The toString operation is how we compile a query object to a prepared statement.
+   * The toString operation is how we compile a query object to a prepared
+   * statement.
    *
    * @return
    *   A prepared statement query string for this object.
    */
   abstract public function __toString();
 
+  /**
+   * Gets the next placeholder value for this query object.
+   *
+   * @return int
+   *   Next placeholder value.
+   */
   public function nextPlaceholder() {
     return $this->nextPlaceholder++;
   }
@@ -275,12 +358,13 @@ abstract class Query implements QueryPlaceholderInterface {
    * 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
+   * 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.
    */
@@ -297,7 +381,6 @@ abstract class Query implements QueryPlaceholderInterface {
    * use of comment() is preferred.
    *
    * Note that this method must be called by reference as well:
-   *
    * @code
    * $comments =& $query->getComments();
    * @endcode
@@ -311,7 +394,7 @@ abstract class Query implements QueryPlaceholderInterface {
 }
 
 /**
- * General class for an abstracted INSERT operation.
+ * General class for an abstracted INSERT query.
  */
 class InsertQuery extends Query {
 
@@ -330,7 +413,7 @@ class InsertQuery extends Query {
   protected $insertFields = array();
 
   /**
-   * An array of fields which should be set to their database-defined defaults.
+   * An array of fields that should be set to their database-defined defaults.
    *
    * @var array
    */
@@ -339,13 +422,17 @@ class InsertQuery extends Query {
   /**
    * A nested array of values to insert.
    *
-   * $insertValues itself is an array of arrays. Each sub-array is an array of
-   * field names to values to insert. Whether multiple insert sets
-   * will be run in a single query or multiple queries is left to individual drivers
-   * to implement in whatever manner is most efficient. The order of values in each
-   * sub-array must match the order of fields in $insertFields.
+   * $insertValues is an array of arrays. Each sub-array is either an
+   * associative array whose keys are field names and whose values are field
+   * values to insert, or a non-associative array of values in the same order
+   * as $insertFields.
    *
-   * @var string
+   * Whether multiple insert sets will be run in a single query or multiple
+   * queries is left to individual drivers to implement in whatever manner is
+   * most appropriate. The order of values in each sub-array must match the
+   * order of fields in $insertFields.
+   *
+   * @var array
    */
   protected $insertValues = array();
 
@@ -356,6 +443,16 @@ class InsertQuery extends Query {
    */
   protected $fromQuery;
 
+  /**
+   * Constructs an InsertQuery object.
+   *
+   * @param DatabaseConnection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
   public function __construct($connection, $table, array $options = array()) {
     if (!isset($options['return'])) {
       $options['return'] = Database::RETURN_INSERT_ID;
@@ -365,7 +462,7 @@ class InsertQuery extends Query {
   }
 
   /**
-   * Add a set of field->value pairs to be inserted.
+   * Adds a set of field->value pairs to be inserted.
    *
    * This method may only be called once. Calling it a second time will be
    * ignored. To queue up multiple sets of values to be inserted at once,
@@ -380,6 +477,7 @@ class InsertQuery extends Query {
    * @param $values
    *   An array of fields to insert into the database. The values must be
    *   specified in the same order as the $fields array.
+   *
    * @return InsertQuery
    *   The called object.
    */
@@ -401,15 +499,16 @@ class InsertQuery extends Query {
   }
 
   /**
-   * Add another set of values to the query to be inserted.
+   * Adds another set of values to the query to be inserted.
    *
-   * If $values is a numeric array, it will be assumed to be in the same
+   * If $values is a numeric-keyed array, it will be assumed to be in the same
    * order as the original fields() call. If it is associative, it may be
    * in any order as long as the keys of the array match the names of the
    * fields.
    *
    * @param $values
    *   An array of values to add to the query.
+   *
    * @return InsertQuery
    *   The called object.
    */
@@ -429,7 +528,7 @@ class InsertQuery extends Query {
   }
 
   /**
-   * Specify fields for which the database-defaults should be used.
+   * Specifies fields for which the database defaults should be used.
    *
    * If you want to force a given field to use the database-defined default,
    * not NULL or undefined, use this method to instruct the database to use
@@ -443,6 +542,7 @@ class InsertQuery extends Query {
    * @param $fields
    *   An array of values for which to use the default values
    *   specified in the table definition.
+   *
    * @return InsertQuery
    *   The called object.
    */
@@ -451,6 +551,15 @@ class InsertQuery extends Query {
     return $this;
   }
 
+  /**
+   * Sets the fromQuery on this InsertQuery object.
+   *
+   * @param SelectQueryInterface $query
+   *   The query to fetch the rows that should be inserted.
+   *
+   * @return InsertQuery
+   *   The called object.
+   */
   public function from(SelectQueryInterface $query) {
     $this->fromQuery = $query;
     return $this;
@@ -466,8 +575,8 @@ class InsertQuery extends Query {
    *   return NULL. That makes it safe to use in multi-insert loops.
    */
   public function execute() {
-    // If validation fails, simply return NULL.
-    // Note that validation routines in preExecute() may throw exceptions instead.
+    // If validation fails, simply return NULL. Note that validation routines
+    // in preExecute() may throw exceptions instead.
     if (!$this->preExecute()) {
       return NULL;
     }
@@ -508,6 +617,12 @@ class InsertQuery extends Query {
     return $last_insert_id;
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
   public function __toString() {
 
     // Create a comments string to prepend to the query.
@@ -531,7 +646,7 @@ class InsertQuery extends Query {
   }
 
   /**
-   * Generic preparation and validation for an INSERT query.
+   * Preprocesses and validates the query.
    *
    * @return
    *   TRUE if the validation was successful, FALSE if not.
@@ -583,13 +698,24 @@ class DeleteQuery extends Query implements QueryConditionInterface {
   protected $table;
 
   /**
-   * The condition object for this query. Condition handling is handled via
-   * composition.
+   * The condition object for this query.
+   *
+   * Condition handling is handled via composition.
    *
    * @var DatabaseCondition
    */
   protected $condition;
 
+  /**
+   * Constructs a DeleteQuery object.
+   *
+   * @param DatabaseConnection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
     parent::__construct($connection, $options);
@@ -598,38 +724,81 @@ class DeleteQuery extends Query implements QueryConditionInterface {
     $this->condition = new DatabaseCondition('AND');
   }
 
+  /**
+   * Implements QueryConditionInterface::condition().
+   */
   public function condition($field, $value = NULL, $operator = NULL) {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNull().
+   */
   public function isNull($field) {
     $this->condition->isNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNotNull().
+   */
   public function isNotNull($field) {
     $this->condition->isNotNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::exists().
+   */
+  public function exists(SelectQueryInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectQueryInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+  
+  /**
+   * Implements QueryConditionInterface::conditions().
+   */
   public function &conditions() {
     return $this->condition->conditions();
   }
 
+  /**
+   * Implements QueryConditionInterface::arguments().
+   */
   public function arguments() {
     return $this->condition->arguments();
   }
 
+  /**
+   * Implements QueryConditionInterface::where().
+   */
   public function where($snippet, $args = array()) {
     $this->condition->where($snippet, $args);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
   }
 
+  /**
+   * Executes the DELETE query.
+   *
+   * @return
+   *   The return value is dependant on the database connection.
+   */
   public function execute() {
     $values = array();
     if (count($this->condition)) {
@@ -640,6 +809,12 @@ class DeleteQuery extends Query implements QueryConditionInterface {
     return $this->connection->query((string) $this, $values, $this->queryOptions);
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
   public function __toString() {
 
     // Create a comments string to prepend to the query.
@@ -664,26 +839,51 @@ class DeleteQuery extends Query implements QueryConditionInterface {
 class TruncateQuery extends Query {
 
   /**
-   * The table from which to delete.
+   * The table to truncate.
    *
    * @var string
    */
   protected $table;
 
+  /**
+   * Constructs a TruncateQuery object.
+   *
+   * @param DatabaseConnection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
     parent::__construct($connection, $options);
     $this->table = $table;
   }
 
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
   }
 
+  /**
+   * Executes the TRUNCATE query.
+   *
+   * @return
+   *   Return value is dependent on the database type.
+   */
   public function execute() {
     return $this->connection->query((string) $this, array(), $this->queryOptions);
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
   public function __toString() {
     // Create a comments string to prepend to the query.
     $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
@@ -719,26 +919,39 @@ class UpdateQuery extends Query implements QueryConditionInterface {
   protected $arguments = array();
 
   /**
-   * The condition object for this query. Condition handling is handled via
-   * composition.
+   * The condition object for this query.
+   *
+   * Condition handling is handled via composition.
    *
    * @var DatabaseCondition
    */
   protected $condition;
 
   /**
-   * An array of fields to update to an expression in case of a duplicate record.
+   * Array of fields to update to an expression in case of a duplicate record.
    *
    * This variable is a nested array in the following format:
+   * @code
    * <some field> => array(
-   *  'condition' => <condition to execute, as a string>
-   *  'arguments' => <array of arguments for condition, or NULL for none>
+   *  'condition' => <condition to execute, as a string>,
+   *  'arguments' => <array of arguments for condition, or NULL for none>,
    * );
+   * @endcode
    *
    * @var array
    */
   protected $expressionFields = array();
 
+  /**
+   * Constructs an UpdateQuery object.
+   *
+   * @param DatabaseConnection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
     parent::__construct($connection, $options);
@@ -747,44 +960,82 @@ class UpdateQuery extends Query implements QueryConditionInterface {
     $this->condition = new DatabaseCondition('AND');
   }
 
+  /**
+   * Implements QueryConditionInterface::condition().
+   */
   public function condition($field, $value = NULL, $operator = NULL) {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNull().
+   */
   public function isNull($field) {
     $this->condition->isNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNotNull().
+   */
   public function isNotNull($field) {
     $this->condition->isNotNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::exists().
+   */
+  public function exists(SelectQueryInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectQueryInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+  
+  /**
+   * Implements QueryConditionInterface::conditions().
+   */
   public function &conditions() {
     return $this->condition->conditions();
   }
 
+  /**
+   * Implements QueryConditionInterface::arguments().
+   */
   public function arguments() {
     return $this->condition->arguments();
   }
 
+  /**
+   * Implements QueryConditionInterface::where().
+   */
   public function where($snippet, $args = array()) {
     $this->condition->where($snippet, $args);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
   }
 
   /**
-   * Add a set of field->value pairs to be updated.
+   * Adds a set of field->value pairs to be updated.
    *
    * @param $fields
    *   An associative array of fields to write into the database. The array keys
-   *   are the field names while the values are the values to which to set them.
+   *   are the field names and the values are the values to which to set them.
+   *
    * @return UpdateQuery
    *   The called object.
    */
@@ -794,7 +1045,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
   }
 
   /**
-   * Specify fields to be updated as an expression.
+   * Specifies fields to be updated as an expression.
    *
    * Expression fields are cases such as counter=counter+1. This method takes
    * precedence over fields().
@@ -807,6 +1058,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
    * @param $arguments
    *   If specified, this is an array of key/value pairs for named placeholders
    *   corresponding to the expression.
+   *
    * @return UpdateQuery
    *   The called object.
    */
@@ -819,6 +1071,12 @@ class UpdateQuery extends Query implements QueryConditionInterface {
     return $this;
   }
 
+  /**
+   * Executes the UPDATE query.
+   *
+   * @return
+   *   The number of rows affected by the update.
+   */
   public function execute() {
 
     // Expressions take priority over literal fields, so we process those first
@@ -847,6 +1105,12 @@ class UpdateQuery extends Query implements QueryConditionInterface {
     return $this->connection->query((string) $this, $update_values, $this->queryOptions);
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
   public function __toString() {
 
     // Create a comments string to prepend to the query.
@@ -880,7 +1144,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
 }
 
 /**
- * General class for an abstracted MERGE operation.
+ * General class for an abstracted MERGE query operation.
  *
  * An ANSI SQL:2003 compatible database would run the following query:
  *
@@ -970,25 +1234,37 @@ class MergeQuery extends Query implements QueryConditionInterface {
   protected $updateFields = array();
 
   /**
-   * An array of fields to update to an expression in case of a duplicate record.
+   * Array of fields to update to an expression in case of a duplicate record.
    *
    * This variable is a nested array in the following format:
+   * @code
    * <some field> => array(
-   *  'condition' => <condition to execute, as a string>
-   *  'arguments' => <array of arguments for condition, or NULL for none>
+   *  'condition' => <condition to execute, as a string>,
+   *  'arguments' => <array of arguments for condition, or NULL for none>,
    * );
+   * @endcode
    *
    * @var array
    */
   protected $expressionFields = array();
 
   /**
-   * Flag indicated whether an UPDATE is necessary.
+   * Flag indicating whether an UPDATE is necessary.
    *
    * @var boolean
    */
   protected $needsUpdate = FALSE;
 
+  /**
+  * Constructs a MergeQuery object.
+  *
+  * @param DatabaseConnection $connection
+  *   A DatabaseConnection object.
+  * @param string $table
+  *   Name of the table to associate with this query.
+  * @param array $options
+  *   Array of database options.
+  */
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
     parent::__construct($connection, $options);
@@ -998,7 +1274,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
   }
 
   /**
-   * Set the table or subquery to be used for the condition.
+   * Sets the table or subquery to be used for the condition.
    *
    * @param $table
    *   The table name or the subquery to be used. Use a SelectQuery object to
@@ -1017,7 +1293,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
    *
    * @param $fields
    *   An associative array of fields to write into the database. The array keys
-   *   are the field names while the values are the values to which to set them.
+   *   are the field names and the values are the values to which to set them.
    *
    * @return MergeQuery
    *   The called object.
@@ -1029,7 +1305,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
   }
 
   /**
-   * Specify fields to be updated as an expression.
+   * Specifies fields to be updated as an expression.
    *
    * Expression fields are cases such as counter = counter + 1. This method
    * takes precedence over MergeQuery::updateFields() and it's wrappers,
@@ -1043,6 +1319,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
    * @param $arguments
    *   If specified, this is an array of key/value pairs for named placeholders
    *   corresponding to the expression.
+   *
    * @return MergeQuery
    *   The called object.
    */
@@ -1104,7 +1381,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
   }
 
   /**
-   * Set common field-value pairs in the INSERT and UPDATE query parts.
+   * Sets common field-value pairs in the INSERT and UPDATE query parts.
    *
    * This method should only be called once. It may be called either
    * with a single associative array or two indexed arrays. If called
@@ -1114,11 +1391,11 @@ class MergeQuery extends Query implements QueryConditionInterface {
    * and the second array is taken as the corresponding values.
    *
    * @param $fields
-   *   An associative array of fields on which to insert. The keys of the
-   *   array are taken to be the fields and the values are taken to be
-   *   corresponding values to insert.
+   *   An array of fields to insert, or an associative array of fields and
+   *   values. The keys of the array are taken to be the fields and the values
+   *   are taken to be corresponding values to insert.
    * @param $values
-   *   An array of fields to set into the database. The values must be
+   *   An array of values to set into the database. The values must be
    *   specified in the same order as the $fields array.
    *
    * @return MergeQuery
@@ -1137,7 +1414,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
   }
 
   /**
-   * Set the key field(s) to be used as conditions for this query.
+   * Sets the key field(s) to be used as conditions for this query.
    *
    * This method should only be called once. It may be called either
    * with a single associative array or two indexed arrays. If called
@@ -1150,10 +1427,11 @@ class MergeQuery extends Query implements QueryConditionInterface {
    * If no other method is called, the UPDATE will become a no-op.
    *
    * @param $fields
-   *   An array of fields to set.
+   *   An array of fields to set, or an associative array of fields and values.
    * @param $values
-   *   An array of fields to set into the database. The values must be
+   *   An array of values to set into the database. The values must be
    *   specified in the same order as the $fields array.
+   *
    * @return MergeQuery
    *   The called object.
    */
@@ -1168,38 +1446,84 @@ class MergeQuery extends Query implements QueryConditionInterface {
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::condition().
+   */
   public function condition($field, $value = NULL, $operator = NULL) {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNull().
+   */
   public function isNull($field) {
     $this->condition->isNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNotNull().
+   */
   public function isNotNull($field) {
     $this->condition->isNotNull($field);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::exists().
+   */
+  public function exists(SelectQueryInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectQueryInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+  
+  /**
+   * Implements QueryConditionInterface::conditions().
+   */
   public function &conditions() {
     return $this->condition->conditions();
   }
 
+  /**
+   * Implements QueryConditionInterface::arguments().
+   */
   public function arguments() {
     return $this->condition->arguments();
   }
 
+  /**
+   * Implements QueryConditionInterface::where().
+   */
   public function where($snippet, $args = array()) {
     $this->condition->where($snippet, $args);
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * In the degenerate case, there is no string-able query as this operation
+   * is potentially two queries.
+   *
+   * @return string
+   *   The prepared query statement.
+   */
   public function __toString() {
   }
 
@@ -1261,25 +1585,54 @@ class MergeQuery extends Query implements QueryConditionInterface {
  */
 class DatabaseCondition implements QueryConditionInterface, Countable {
 
+  /**
+   * Array of conditions.
+   *
+   * @var array
+   */
   protected $conditions = array();
+
+  /**
+   * Array of arguments.
+   *
+   * @var array
+   */
   protected $arguments = array();
 
+  /**
+   * Whether the conditions have been changed.
+   *
+   * TRUE if the condition has been changed since the last compile.
+   * FALSE if the condition has been compiled and not changed.
+   *
+   * @var bool
+   */
   protected $changed = TRUE;
 
+  /**
+   * Constructs a DataBaseCondition object.
+   *
+   * @param string $conjunction
+   *   The operator to use to combine conditions: 'AND' or 'OR'.
+   */
   public function __construct($conjunction) {
     $this->conditions['#conjunction'] = $conjunction;
   }
 
   /**
-   * Return the size of this conditional. This is part of the Countable interface.
+   * Implements Countable::count().
    *
-   * The size of the conditional is the size of its conditional array minus
-   * one, because one element is the the conjunction.
+   * Returns the size of this conditional. The size of the conditional is the
+   * size of its conditional array minus one, because one element is the the
+   * conjunction.
    */
   public function count() {
     return count($this->conditions) - 1;
   }
 
+  /**
+   * Implements QueryConditionInterface::condition().
+   */
   public function condition($field, $value = NULL, $operator = NULL) {
     if (!isset($operator)) {
       if (is_array($value)) {
@@ -1303,6 +1656,9 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::where().
+   */
   public function where($snippet, $args = array()) {
     $this->conditions[] = array(
       'field' => $snippet,
@@ -1314,18 +1670,44 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     return $this;
   }
 
+  /**
+   * Implements QueryConditionInterface::isNull().
+   */
   public function isNull($field) {
     return $this->condition($field);
   }
 
+  /**
+   * Implements QueryConditionInterface::isNotNull().
+   */
   public function isNotNull($field) {
     return $this->condition($field, NULL, 'IS NOT NULL');
   }
 
+  /**
+   * Implements QueryConditionInterface::exists().
+   */
+  public function exists(SelectQueryInterface $select) {
+    return $this->condition('', $select, 'EXISTS');
+  }
+  
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectQueryInterface $select) {
+    return $this->condition('', $select, 'NOT EXISTS');
+  }
+  
+  /**
+   * Implements QueryConditionInterface::conditions().
+   */
   public function &conditions() {
     return $this->conditions;
   }
 
+  /**
+   * Implements QueryConditionInterface::arguments().
+   */
   public function arguments() {
     // If the caller forgot to call compile() first, refuse to run.
     if ($this->changed) {
@@ -1334,6 +1716,9 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     return $this->arguments;
   }
 
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     if ($this->changed) {
       $condition_fragments = array();
@@ -1407,6 +1792,12 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     }
   }
 
+  /**
+   * Implements PHP magic __toString method to convert the conditions to string.
+   *
+   * @return string
+   *   A string version of the conditions.
+   */
   public function __toString() {
     // If the caller forgot to call compile() first, refuse to run.
     if ($this->changed) {
@@ -1415,6 +1806,12 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     return $this->stringVersion;
   }
 
+  /**
+   * PHP magic __clone() method.
+   *
+   * Only copies fields that implement QueryConditionInterface. Also sets
+   * $this->changed to TRUE.
+   */
   function __clone() {
     $this->changed = TRUE;
     foreach ($this->conditions as $key => $condition) {
@@ -1433,6 +1830,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
    *
    * @param $operator
    *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
+   *
    * @return
    *   The extra handling directives for the specified operator, or NULL.
    */
@@ -1442,6 +1840,8 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
       'BETWEEN' => array('delimiter' => ' AND '),
       'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
       'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
+      'EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
+      'NOT EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
       'IS NULL' => array('use_value' => FALSE),
       'IS NOT NULL' => array('use_value' => FALSE),
       // Use backslash for escaping wildcard characters.
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index 8b3a1f99a62e49d22da122beadac3a390fac4445..1423f655894b85e40397f543d165970b63ee0b86 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -1,14 +1,17 @@
 <?php
-// $Id: schema.inc,v 1.39 2010/08/22 13:55:53 dries Exp $
+// $Id: schema.inc,v 1.44 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
  * Generic Database schema code.
  */
 
+require_once dirname(__FILE__) . '/query.inc';
+
 /**
  * @defgroup schemaapi Schema API
  * @{
+ * API to handle database schemas.
  *
  * A Drupal schema definition is an array structure representing one or
  * more tables and their related keys and indexes. A schema is defined by
@@ -38,10 +41,16 @@
  *       description might contain "Always holds the largest (most
  *       recent) {node_revision}.vid value for this nid."
  *     - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int',
- *       'float', 'numeric', 'serial', 'date', 'datetime' or 'time'. Most types
- *       types just map to the according database engine specific datatypes. Use
- *       'serial' for auto incrementing fields. This will expand to 'INT
- *       auto_increment' on MySQL.
+ *       'float', 'numeric', or 'serial'. Most types just map to the according
+ *       database engine specific datatypes. Use 'serial' for auto incrementing
+ *       fields. This will expand to 'INT auto_increment' on MySQL.
+ *     - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to
+ *       use a record type not included in the officially supported list
+ *       of types above, you can specify a type for each database
+ *       backend. In this case, you can leave out the type parameter,
+ *       but be advised that your schema will fail to load on backends that
+ *       do not have a type specified. A possible solution can be to
+ *       use the "text" type as a fallback.
  *     - 'serialize': A boolean indicating whether the field will be stored as
  *       a serialized string.
  *     - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 9947002aaeac63c6856b3a4192c5f20eda346a4e..19e0464c2792febe24e63500add7aac3edf5ac21 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -1,11 +1,13 @@
 <?php
-// $Id: select.inc,v 1.52 2010/10/05 01:42:24 dries Exp $
+// $Id: select.inc,v 1.59 2010/12/31 20:43:43 webchick Exp $
 
 /**
  * @ingroup database
  * @{
  */
 
+require_once dirname(__FILE__) . '/query.inc';
+
 /**
  * Interface for extendable query objects.
  *
@@ -642,7 +644,9 @@ class SelectQueryExtender implements SelectQueryInterface {
   /* Implementations of QueryExtendableInterface. */
 
   public function extend($extender_name) {
-    $class = $this->connection->getDriverClass($extender_name);
+    // The extender can be anywhere so this needs to go to the registry, which
+    // is surely loaded by now.
+    $class = $this->connection->getDriverClass($extender_name, array(), TRUE);
     return new $class($this, $this->connection);
   }
 
@@ -806,6 +810,16 @@ class SelectQueryExtender implements SelectQueryInterface {
     return $this;
   }
 
+  public function exists(SelectQueryInterface $select) {
+    $this->query->exists($select);
+    return $this;
+  }
+
+  public function notExists(SelectQueryInterface $select) {
+    $this->query->notExists($select);
+    return $this;
+  }
+  
   public function __toString() {
     return (string) $this->query;
   }
@@ -1018,6 +1032,16 @@ class SelectQuery extends Query implements SelectQueryInterface {
     return $this;
   }
 
+  public function exists(SelectQueryInterface $select) {
+    $this->where->exists($select);
+    return $this;
+  }
+
+  public function notExists(SelectQueryInterface $select) {
+    $this->where->notExists($select);
+    return $this;
+  }
+  
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
     return $this->where->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
   }
@@ -1065,7 +1089,17 @@ class SelectQuery extends Query implements SelectQueryInterface {
     $this->having->isNotNull($field);
     return $this;
   }
-
+  
+  public function havingExists(SelectQueryInterface $select) {
+    $this->having->exists($select);
+    return $this;
+  }
+  
+  public function havingNotExists(SelectQueryInterface $select) {
+    $this->having->notExists($select);
+    return $this;
+  }
+  
   public function forUpdate($set = TRUE) {
     if (isset($set)) {
       $this->forUpdate = $set;
@@ -1350,7 +1384,7 @@ class SelectQuery extends Query implements SelectQueryInterface {
   }
 
   public function groupBy($field) {
-    $this->group[] = $field;
+    $this->group[$field] = $field;
     return $this;
   }
 
@@ -1358,7 +1392,7 @@ class SelectQuery extends Query implements SelectQueryInterface {
     // Create our new query object that we will mutate into a count query.
     $count = clone($this);
 
-    $group_by = array_keys($count->getGroupBy());
+    $group_by = $count->getGroupBy();
 
     if (!$count->distinct) {
       // When not executing a distinct query, we can zero-out existing fields
@@ -1366,14 +1400,14 @@ class SelectQuery extends Query implements SelectQueryInterface {
       // the GROUP BY clause need to be present in the query.
       $fields =& $count->getFields();
       foreach (array_keys($fields) as $field) {
-        if (!empty($group_by[$field])) {
+        if (empty($group_by[$field])) {
           unset($fields[$field]);
         }
       }
       $expressions =& $count->getExpressions();
       foreach (array_keys($expressions) as $field) {
-        if (!empty($group_by[$field])) {
-          unset($fields[$field]);
+        if (empty($group_by[$field])) {
+          unset($expressions[$field]);
         }
       }
 
diff --git a/includes/database/sqlite/database.inc b/includes/database/sqlite/database.inc
index e03e34f0830bbe679e8bd3bb1a31581ff5e7fd66..6163f2e42aac09962f58cdab8160fcf38f0917bb 100644
--- a/includes/database/sqlite/database.inc
+++ b/includes/database/sqlite/database.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.39 2010/10/03 01:29:41 dries Exp $
+// $Id: database.inc,v 1.41 2010/12/23 05:29:27 webchick Exp $
 
 /**
  * @file
@@ -24,7 +24,7 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
    * Version of sqlite lower then 3.6.8 can't use savepoints.
    * See http://www.sqlite.org/releaselog/3_6_8.html
    *
-   * @var bool
+   * @var boolean
    */
   protected $savepointSupport = FALSE;
 
@@ -35,6 +35,26 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
    */
   protected $willRollback;
 
+  /**
+   * All databases attached to the current database. This is used to allow
+   * prefixes to be safely handled without locking the table
+   * 
+   * @var array
+   */
+  protected $attachedDatabases = array();
+
+  /**
+   * Whether or not a table has been dropped this request: the destructor will
+   * only try to get rid of unnecessary databases if there is potential of them
+   * being empty.
+   * 
+   * This variable is set to public because DatabaseSchema_sqlite needs to
+   * access it. However, it should not be manually set.
+   * 
+   * @var boolean
+   */
+  var $tableDropped = FALSE;
+
   public function __construct(array $connection_options = array()) {
     // We don't need a specific PDOStatement class here, we simulate it below.
     $this->statementClass = NULL;
@@ -51,7 +71,26 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
       PDO::ATTR_STRINGIFY_FETCHES => TRUE,
     ));
 
-    $this->exec('PRAGMA encoding="UTF-8"');
+    // Attach one database for each registered prefix.
+    $prefixes = &$this->prefixes;
+    if (!empty($this->defaultPrefix)) {
+      // Add in the default prefix, which is also attached.
+      $prefixes[] = &$this->defaultPrefix;
+    }
+    foreach ($this->prefixes as $table => &$prefix) {
+      // Empty prefix means query the main database -- no need to attach anything.
+      if (!empty($prefix)) {
+        // Only attach the database once.
+        if (!isset($this->attachedDatabases[$prefix])) {
+          $this->attachedDatabases[$prefix] = $prefix;
+          $this->query('ATTACH DATABASE :database AS :prefix', array(':database' => $connection_options['database'] . '-' . $prefix, ':prefix' => $prefix));
+        }
+
+        // Add a ., so queries become prefix.table, which is proper syntax for
+        // querying an attached database.
+        $prefix .= '.';
+      }
+    }
 
     // Detect support for SAVEPOINT.
     $version = $this->query('SELECT sqlite_version()')->fetchField();
@@ -69,6 +108,36 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
     $this->sqliteCreateFunction('rand', array($this, 'sqlFunctionRand'));
   }
 
+  /**
+   * Destructor for the SQLite connection.
+   *
+   * We prune empty databases on destruct, but only if tables have been
+   * dropped. This is especially needed when running the test suite, which
+   * creates and destroy databases several times in a row.
+   */
+  public function __destruct() {
+    if ($this->tableDropped && !empty($this->attachedDatabases)) {
+      foreach ($this->attachedDatabases as $prefix) {
+        // Check if the database is now empty, ignore the internal SQLite tables.
+        try {
+          $count = $this->query('SELECT COUNT(*) FROM ' . $prefix . '.sqlite_master WHERE type = :type AND name NOT LIKE :pattern', array(':type' => 'table', ':pattern' => 'sqlite_%'))->fetchField();
+
+          // We can prune the database file if it doens't have any tables.
+          if ($count == 0) {
+            // Detach the database.
+            $this->query('DETACH DATABASE :schema', array(':schema' => $prefix));
+            // Destroy the database file.
+            unlink($this->connectionOptions['database'] . '-' . $prefix);
+          }
+        }
+        catch (Exception $e) {
+          // Ignore the exception and continue. There is nothing we can do here
+          // to report the error or fail safe.
+        }
+      }
+    }
+  }
+
   /**
    * SQLite compatibility implementation for the IF() SQL function.
    */
diff --git a/includes/database/sqlite/install.inc b/includes/database/sqlite/install.inc
index ee8fbdc87a4bb8dc20ccf2597378e957d42d6a5f..a5b0efaca9969bf09acb65e4e254ab0ba38af01d 100644
--- a/includes/database/sqlite/install.inc
+++ b/includes/database/sqlite/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.2 2009/07/27 19:42:56 dries Exp $
+// $Id: install.inc,v 1.6 2010/11/29 02:55:57 webchick Exp $
 
 /**
  * @file
@@ -8,8 +8,45 @@
 
 class DatabaseTasks_sqlite extends DatabaseTasks {
   protected $pdoDriver = 'sqlite';
+
   public function name() {
-    return 'SQLite';
+    return st('SQLite');
+  }
+
+  /**
+   * Minimum engine version.
+   *
+   * @todo: consider upping to 3.6.8 in Drupal 8 to get SAVEPOINT support.
+   */
+  public function minimumVersion() {
+    return '3.3.7';
+  }
+
+  public function getFormOptions($database) {
+    $form = parent::getFormOptions($database);
+
+    // Remove the options that only apply to client/server style databases.
+    unset($form['username'], $form['password'], $form['advanced_options']['host'], $form['advanced_options']['port']);
+
+    // Make the text more accurate for SQLite.
+    $form['database']['#title'] = st('Database file');
+    $form['database']['#description'] = st('The absolute path to the file where @drupal data will be stored. This must be writable by the web server and should exist outside of the web root.', array('@drupal' => drupal_install_profile_distribution_name()));
+    $default_database = conf_path(FALSE, TRUE) . '/files/.ht.sqlite';
+    $form['database']['#default_value'] = empty($database['database']) ? $default_database : $database['database'];
+    return $form;
+  }
+
+  public function validateDatabaseSettings($database) {
+    // Perform standard validation.
+    $errors = parent::validateDatabaseSettings($database);
+
+    // Verify the database is writable.
+    $db_directory = new SplFileInfo(dirname($database['database']));
+    if (!$db_directory->isWritable()) {
+      $errors[$database['driver'] . '][database'] = st('The directory you specified is not writable by the web server.');
+    }
+
+    return $errors;
   }
 }
 
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index fe33f44d5f07d9bc2b072f9844ddd52e5bb0f416..b0a62e07220315b39c7ef986be4a56fe368c74f2 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: query.inc,v 1.13 2010/09/25 01:41:26 dries Exp $
+// $Id: query.inc,v 1.15 2010/12/22 01:16:43 webchick Exp $
 
 /**
  * @file
@@ -11,16 +11,6 @@
  * @{
  */
 
-/**
- * SQLite specific query builder for SELECT statements.
- */
-class SelectQuery_sqlite extends SelectQuery {
-  public function forUpdate($set = TRUE) {
-    // SQLite does not support FOR UPDATE so nothing to do.
-    return $this;
-  }
-}
-
 /**
  * SQLite specific implementation of InsertQuery.
  *
@@ -107,7 +97,7 @@ class UpdateQuery_sqlite extends UpdateQuery {
     foreach ($fields as $field => $data) {
       if (is_array($data)) {
         // The field is an expression.
-        $condition->condition($field, $data['expression'], '<>');
+        $condition->where($field . ' <> ' . $data['expression']);
         $condition->isNull($field);
       }
       elseif (!isset($data)) {
diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc
index e8a02db95f37229879e880554d2059cd35502795..928e34b810412aee5bef6aa032234e87d5ecfbdb 100644
--- a/includes/database/sqlite/schema.inc
+++ b/includes/database/sqlite/schema.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.inc,v 1.20 2010/10/22 15:18:56 webchick Exp $
+// $Id: schema.inc,v 1.23 2010/12/23 01:43:38 webchick Exp $
 
 /**
  * @file
@@ -271,12 +271,12 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
     if (!$this->tableExists($table)) {
       return FALSE;
     }
-
+    $this->connection->tableDropped = TRUE;
     $this->connection->query('DROP TABLE {' . $table . '}');
     return TRUE;
   }
 
-  public function addField($table, $field, $spec, $keys_new = array()) {
+  public function addField($table, $field, $specification, $keys_new = array()) {
     if (!$this->tableExists($table)) {
       throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
     }
@@ -284,10 +284,50 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
     }
 
-    // TODO: $keys_new is not supported yet.
-    $query = 'ALTER TABLE {' . $table . '} ADD ';
-    $query .= $this->createFieldSql($field, $this->processField($spec));
-    $this->connection->query($query);
+    // SQLite doesn't have a full-featured ALTER TABLE statement. It only
+    // supports adding new fields to a table, in some simple cases. In most
+    // cases, we have to create a new table and copy the data over.
+    if (empty($keys_new) && (empty($specification['not null']) || isset($specification['default']))) {
+      // When we don't have to create new keys and we are not creating a
+      // NOT NULL column without a default value, we can use the quicker version.
+      $query = 'ALTER TABLE {' . $table . '} ADD ' . $this->createFieldSql($field, $this->processField($specification));
+      $this->connection->query($query);
+
+      // Apply the initial value if set.
+      if (isset($specification['initial'])) {
+        $this->connection->update($table)
+          ->fields(array($field => $specification['initial']))
+          ->execute();
+      }
+    }
+    else {
+      // We cannot add the field directly. Use the slower table alteration
+      // method, starting from the old schema.
+      $old_schema = $this->introspectSchema($table);
+      $new_schema = $old_schema;
+
+      // Add the new field.
+      $new_schema['fields'][$field] = $specification;
+
+      // Build the mapping between the old fields and the new fields.
+      $mapping = array();
+      if (isset($specification['initial'])) {
+        // If we have a initial value, copy it over.
+        $mapping[$field] = array(
+          'expression' => ':newfieldinitial',
+          'arguments' => array(':newfieldinitial' => $specification['initial']),
+        );
+      }
+      else {
+        // Else use the default of the field.
+        $mapping[$field] = NULL;
+      }
+
+      // Add the new indexes.
+      $new_schema += $keys_new;
+
+      $this->alterTable($table, $old_schema, $new_schema, $mapping);
+    }
   }
 
   /**
@@ -303,7 +343,13 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
    * @param $new_schema
    *   The new schema array for the table.
    * @param $mapping
-   *   An optional mapping between old fields => new fields.
+   *   An optional mapping between the fields of the old specification and the
+   *   fields of the new specification. An associative array, whose keys are
+   *   the fields of the new table, and values can take two possible forms:
+   *     - a simple string, which is interpreted as the name of a field of the
+   *       old table,
+   *     - an associative array with two keys 'expression' and 'arguments',
+   *       that will be used as an expression field.
    */
   protected function alterTable($table, $old_schema, $new_schema, array $mapping = array()) {
     $i = 0;
@@ -313,22 +359,25 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
 
     $this->createTable($new_table, $new_schema);
 
+    // Build a SQL query to migrate the data from the old table to the new.
+    $select = $this->connection->select($table);
+
     // Complete the mapping.
-    $old_keys = array_keys($old_schema['fields']);
-    $mapping += array_combine($old_keys, $old_keys);
+    $possible_keys = array_keys($new_schema['fields']);
+    $mapping += array_combine($possible_keys, $possible_keys);
+
+    // Now add the fields.
+    foreach ($mapping as $field_alias => $field_source) {
+      // Just ignore this field (ie. use it's default value).
+      if (!isset($field_source)) {
+        continue;
+      }
 
-    $select = $this->connection->select($table);
-    $fields = &$select->getFields();
-
-    // Map the fields.
-    foreach ($old_keys as $key) {
-      if (isset($mapping[$key])) {
-        // Don't use ->addField() here because it messes-up with the aliases.
-        $fields[$mapping[$key]] = array(
-          'field' => $key,
-          'table' => $table,
-          'alias' => $mapping[$key],
-        );
+      if (is_array($field_source)) {
+        $select->addExpression($field_source['expression'], $field_alias, $field_source['arguments']);
+      }
+      else {
+        $select->addField($table, $field_source, $field_alias);
       }
     }
 
@@ -427,8 +476,6 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
     $old_schema = $this->introspectSchema($table);
     $new_schema = $old_schema;
 
-    $mapping = array($field => NULL);
-
     unset($new_schema['fields'][$field]);
     foreach ($new_schema['indexes'] as $index => $fields) {
       foreach ($fields as $key => $field_name) {
@@ -441,7 +488,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
         unset($new_schema['indexes'][$index]);
       }
     }
-    $this->alterTable($table, $old_schema, $new_schema, $mapping);
+    $this->alterTable($table, $old_schema, $new_schema);
     return TRUE;
   }
 
@@ -458,7 +505,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
 
     // Map the old field to the new field.
     if ($field != $field_new) {
-      $mapping[$field] = $field_new;
+      $mapping[$field_new] = $field;
     }
     else {
       $mapping = array();
@@ -622,9 +669,13 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
   }
 
   public function findTables($table_expression) {
-    // Don't use {} around sqlite_master table.
-    $result = db_query("SELECT name FROM sqlite_master WHERE name LIKE :table_name", array(
-      ':table_name' => $table_expression,
+    // Don't add the prefix, $table_expression already includes the prefix.
+    $info = $this->getPrefixInfo($table_expression, FALSE);
+
+    // Can't use query placeholders because the query would have to be
+    // :prefixsqlite_master, which does not work.
+    $result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE name LIKE :table_name", array(
+      ':table_name' => $info['table'],
     ));
     return $result->fetchAllKeyed(0, 0);
   }
diff --git a/includes/database/sqlite/select.inc b/includes/database/sqlite/select.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3d89af4d555ca52480674ad526a7de3e097e54c7
--- /dev/null
+++ b/includes/database/sqlite/select.inc
@@ -0,0 +1,28 @@
+<?php
+// $Id: select.inc,v 1.1 2010/11/29 19:57:57 webchick Exp $
+
+/**
+ * @file
+ * Select builder for SQLite embedded database engine.
+ */
+
+/**
+ * @ingroup database
+ * @{
+ */
+
+/**
+ * SQLite specific query builder for SELECT statements.
+ */
+class SelectQuery_sqlite extends SelectQuery {
+  public function forUpdate($set = TRUE) {
+    // SQLite does not support FOR UPDATE so nothing to do.
+    return $this;
+  }
+}
+
+/**
+ * @} End of "ingroup database".
+ */
+
+
diff --git a/includes/date.inc b/includes/date.inc
index afde57f925973955cf80d5097c12a07e4e904680..6eaddd80601a2177e508d32f152add7214405a7a 100644
--- a/includes/date.inc
+++ b/includes/date.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: date.inc,v 1.1 2009/10/13 21:34:14 dries Exp $
+// $Id: date.inc,v 1.2 2010/12/09 01:51:15 dries Exp $
 
 /**
  * @file
@@ -7,7 +7,7 @@
  */
 
 /**
- * Implements hook_date_formats().
+ * Provides a default system list of date formats for system_date_formats().
  */
 function system_default_date_formats() {
   $formats = array();
diff --git a/includes/entity.inc b/includes/entity.inc
index 95c75de95407d6b9db1067afeb2ab2d5a7cbc9f4..fbc4f0292fe1baf6bf176376f918783c90c7396f 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: entity.inc,v 1.16 2010/10/09 02:36:46 webchick Exp $
+// $Id: entity.inc,v 1.19 2010/11/30 19:31:46 dries Exp $
 
 /**
  * Interface for entity controller classes.
@@ -24,8 +24,12 @@ interface DrupalEntityControllerInterface {
 
   /**
    * Resets the internal, static entity cache.
+   *
+   * @param $ids
+   *   (optional) If specified, the cache is reset for the entities with the
+   *   given ids only.
    */
-  public function resetCache();
+  public function resetCache(array $ids = NULL);
 
   /**
    * Loads one or more entities.
@@ -139,8 +143,15 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
   /**
    * Implements DrupalEntityControllerInterface::resetCache().
    */
-  public function resetCache() {
-    $this->entityCache = array();
+  public function resetCache(array $ids = NULL) {
+    if (isset($ids)) {
+      foreach ($ids as $id) {
+        unset($this->entityCache[$id]);
+      }
+    }
+    else {
+      $this->entityCache = array();
+    }
   }
 
   /**
@@ -418,6 +429,16 @@ class EntityFieldQuery {
    */
   const RETURN_ALL = NULL;
 
+  /**
+   * TRUE if the query has already been altered, FALSE if it hasn't.
+   *
+   * Used in alter hooks to check for cloned queries that have already been
+   * altered prior to the clone (for example, the pager count query).
+   *
+   * @var boolean
+   */
+  public $altered = FALSE;
+
   /**
    * Associative array of entity-generic metadata conditions.
    *
@@ -461,6 +482,15 @@ class EntityFieldQuery {
    */
   public $range = array();
 
+  /**
+   * The query pager data.
+   *
+   * @var array
+   *
+   * @see EntityFieldQuery::pager()
+   */
+  public $pager = array();
+
   /**
    * Query behavior for deleted data.
    *
@@ -549,6 +579,10 @@ class EntityFieldQuery {
    *
    * 'bundle', 'revision_id' and 'entity_id' have no such restrictions.
    *
+   * Note: The "comment" and "taxonomy_term" entity types don't support bundle
+   * conditions. For "taxonomy_term", propertyCondition('vid') can be used
+   * instead.
+   *
    * @param $name
    *   'entity_type', 'bundle', 'revision_id' or 'entity_id'.
    * @param $value
@@ -680,6 +714,9 @@ class EntityFieldQuery {
    * If called multiple times, the query will order by each specified column in
    * the order this method is called.
    *
+   * Note: The "comment" and "taxonomy_term" entity types don't support ordering
+   * by bundle. For "taxonomy_term", propertyOrderBy('vid') can be used instead.
+   *
    * @param $name
    *   'entity_type', 'bundle', 'revision_id' or 'entity_id'.
    * @param $direction
@@ -791,6 +828,68 @@ class EntityFieldQuery {
     return $this;
   }
 
+  /**
+   * Enable a pager for the query.
+   *
+   * @param $limit
+   *   An integer specifying the number of elements per page.  If passed a false
+   *   value (FALSE, 0, NULL), the pager is disabled.
+   * @param $element
+   *   An optional integer to distinguish between multiple pagers on one page.
+   *   If not provided, one is automatically calculated.
+   *
+   * @return EntityFieldQuery
+   *   The called object.
+   */
+  public function pager($limit = 10, $element = NULL) {
+    if (!isset($element)) {
+      $element = PagerDefault::$maxElement++;
+    }
+    elseif ($element >= PagerDefault::$maxElement) {
+      PagerDefault::$maxElement = $element + 1;
+    }
+
+    $this->pager = array(
+      'limit' => $limit,
+      'element' => $element,
+    );
+    return $this;
+  }
+
+  /**
+   * Enable sortable tables for this query.
+   *
+   * @param $headers
+   *   An EFQ Header array based on which the order clause is added to the query.
+   *
+   * @return EntityFieldQuery
+   *   The called object.
+   */
+  public function tableSort(&$headers) {
+    // If 'field' is not initialized, the header columns aren't clickable
+    foreach ($headers as $key =>$header) {
+      if (is_array($header) && isset($header['specifier'])) {
+        $headers[$key]['field'] = '';
+      }
+    }
+
+    $order = tablesort_get_order($headers);
+    $direction = tablesort_get_sort($headers);
+    foreach ($headers as $header) {
+      if (is_array($header) && ($header['data'] == $order['name'])) {
+        if ($header['type'] == 'field') {
+          $this->fieldOrderBy($header['specifier']['field'], $header['specifier']['column'], $direction);
+        }
+        else {
+          $header['direction'] = $direction;
+          $this->order[] = $header;
+        }
+      }
+    }
+
+    return $this;
+  }
+
   /**
    * Filters on the data being deleted.
    *
@@ -904,6 +1003,10 @@ class EntityFieldQuery {
   public function execute() {
     // Give a chance to other modules to alter the query.
     drupal_alter('entity_query', $this);
+    $this->altered = TRUE;
+
+    // Initialize the pager.
+    $this->initializePager();
 
     // Execute the query using the correct callback.
     $result = call_user_func($this->queryCallback(), $this);
@@ -959,12 +1062,12 @@ class EntityFieldQuery {
       throw new EntityFieldQueryException(t('For this query an entity type must be specified.'));
     }
     $entity_type = $this->entityConditions['entity_type']['value'];
-    unset($this->entityConditions['entity_type']);
     $entity_info = entity_get_info($entity_type);
     if (empty($entity_info['base table'])) {
       throw new EntityFieldQueryException(t('Entity %entity has no base table.', array('%entity' => $entity_type)));
     }
     $base_table = $entity_info['base table'];
+    $base_table_schema = drupal_get_schema($base_table);
     $select_query = db_select($base_table);
     $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type));
     // Process the property conditions.
@@ -997,8 +1100,11 @@ class EntityFieldQuery {
     // Handle bundles.
     if (!empty($entity_info['entity keys']['bundle'])) {
       $sql_field = $entity_info['entity keys']['bundle'];
-      $select_query->addField($base_table, $sql_field, 'bundle');
       $having = FALSE;
+
+      if (!empty($base_table_schema['fields'][$sql_field])) {
+        $select_query->addField($base_table, $sql_field, 'bundle');
+      }
     }
     else {
       $sql_field = 'bundle';
@@ -1027,6 +1133,24 @@ class EntityFieldQuery {
     return $this->finishQuery($select_query);
   }
 
+  /**
+   * Get the total number of results and initialize a pager for the query.
+   *
+   * This query can be detected by checking for ($this->pager && $this->count),
+   * which allows a driver to return 0 from the count query and disable
+   * the pager.
+   */
+  function initializePager() {
+    if ($this->pager && !$this->count) {
+      $page = pager_find_page($this->pager['element']);
+      $count_query = clone $this;
+      $this->pager['total'] = $count_query->count()->execute();
+      $this->pager['start'] = $page * $this->pager['limit'];
+      pager_default_initialize($this->pager['total'], $this->pager['limit'], $this->pager['element']);
+      $this->range($this->pager['start'], $this->pager['limit']);
+    }
+  }
+
   /**
    * Finishes the query.
    *
@@ -1057,7 +1181,8 @@ class EntityFieldQuery {
     }
     $return = array();
     foreach ($select_query->execute() as $partial_entity) {
-      $entity = entity_create_stub_entity($partial_entity->entity_type, array($partial_entity->entity_id, $partial_entity->revision_id, $partial_entity->bundle));
+      $bundle = isset($partial_entity->bundle) ? $partial_entity->bundle : NULL;
+      $entity = entity_create_stub_entity($partial_entity->entity_type, array($partial_entity->entity_id, $partial_entity->revision_id, $bundle));
       $return[$partial_entity->entity_type][$partial_entity->$id_key] = $entity;
       $this->ordered_results[] = $partial_entity;
     }
diff --git a/includes/file.inc b/includes/file.inc
index 4e9e9e2abe21d099f5643515c78a60bd0ee5e350..4e9f3a9a38481b3f422ebd23ebb24743ba826b7f 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.inc,v 1.239 2010/10/21 12:09:41 dries Exp $
+// $Id: file.inc,v 1.243 2010/12/15 03:39:41 webchick Exp $
 
 /**
  * @file
@@ -519,15 +519,21 @@ function file_create_htaccess($directory, $private = TRUE) {
  * @param $fids
  *   An array of file IDs.
  * @param $conditions
- *   An array of conditions to match against the {file_managed} table.
- *   These should be supplied in the form array('field_name' =>
- *   'field_value').
+ *   (deprecated) An associative array of conditions on the {file_managed}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have. Instead, it is preferable to use
+ *   EntityFieldQuery to retrieve a list of entity IDs loadable by
+ *   this function.
  *
  * @return
  *   An array of file objects, indexed by fid.
  *
  * @see hook_file_load()
  * @see file_load()
+ * @see entity_load()
+ * @see EntityFieldQuery
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function file_load_multiple($fids = array(), $conditions = array()) {
   return entity_load('file', $fids, $conditions);
@@ -568,6 +574,14 @@ function file_save(stdClass $file) {
   $file->timestamp = REQUEST_TIME;
   $file->filesize = filesize($file->uri);
 
+  // Load the stored entity, if any.
+  if (!empty($file->fid) && !isset($file->original)) {
+    $file->original = entity_load_unchanged('file', $file->fid);
+  }
+
+  module_invoke_all('file_presave', $file);
+  module_invoke_all('entity_presave', $file, 'file');
+
   if (empty($file->fid)) {
     drupal_write_record('file_managed', $file);
     // Inform modules about the newly added file.
@@ -581,6 +595,7 @@ function file_save(stdClass $file) {
     module_invoke_all('entity_update', $file, 'file');
   }
 
+  unset($file->original);
   return $file;
 }
 
@@ -859,7 +874,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
     $dirname = drupal_dirname($destination);
     if (!file_prepare_directory($dirname)) {
       // The destination is not valid.
-      watchdog('file', 'File %file could not be copied, because the destination directory %directory is not configured correctly.', array('%file' => $original_source, '%destination' => drupal_realpath($dirname)));
+      watchdog('file', 'File %file could not be copied, because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => drupal_realpath($dirname)));
       drupal_set_message(t('The specified file %file could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', array('%file' => $original_source)), 'error');
       return FALSE;
     }
diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc
index 4396de6e1874a31ec90e4967ee3f858391b8dfae..d7f47e090b9416f5d0fdd7245b33ab8e87a682fd 100644
--- a/includes/filetransfer/filetransfer.inc
+++ b/includes/filetransfer/filetransfer.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: filetransfer.inc,v 1.9 2010/04/11 18:33:43 dries Exp $
+// $Id: filetransfer.inc,v 1.14 2011/01/03 02:20:45 webchick Exp $
 
 /*
  * Base FileTransfer class.
@@ -28,8 +28,15 @@ abstract class FileTransfer {
    * Classes that extend this class must override the factory() static method.
    *
    * @param string $jail
+   *   The full path where all file operations performed by this object will
+   *   be restricted to. This prevents the FileTransfer classes from being
+   *   able to touch other parts of the filesystem.
    * @param array $settings
-   * @return object New instance of the appropriate FileTransfer subclass.
+   *   An array of connection settings for the FileTransfer subclass. If the
+   *   getSettingsForm() method uses any nested settings, the same structure
+   *   will be assumed here.
+   * @return object
+   *   New instance of the appropriate FileTransfer subclass.
    */
   static function factory($jail, $settings) {
     throw new FileTransferException('FileTransfer::factory() static method not overridden by FileTransfer subclass.');
@@ -208,7 +215,7 @@ abstract class FileTransfer {
       $destination = $destination . '/' . basename($source);
     }
     $this->createDirectory($destination);
-    foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
+    foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
       $relative_path = substr($filename, strlen($source));
       if ($file->isDir()) {
         $this->createDirectory($destination . $relative_path);
@@ -313,6 +320,42 @@ abstract class FileTransfer {
     $this->chroot = $this->findChroot();
     $this->jail = $this->fixRemotePath($this->jail);
   }
+
+  /**
+   * Returns a form to collect connection settings credentials.
+   *
+   * Implementing classes can either extend this form with fields collecting the
+   * specific information they need, or override it entirely.
+   */
+  public function getSettingsForm() {
+    $form['username'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Username'),
+    );
+    $form['password'] = array(
+      '#type' => 'password',
+      '#title' => t('Password'),
+      '#description' => t('Your password is not saved in the database and is only used to establish a connection.'),
+    );
+    $form['advanced'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Advanced settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['advanced']['hostname'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Host'),
+      '#default_value' => 'localhost',
+      '#description' => t('The connection will be created between your web server and the machine hosting the web server files. In the vast majority of cases, this will be the same machine, and "localhost" is correct.'),
+    );
+    $form['advanced']['port'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Port'),
+      '#default_value' => NULL,
+    );
+    return $form;
+  }
 }
 
 /**
@@ -345,3 +388,31 @@ interface FileTransferChmodInterface {
    */
   function chmodJailed($path, $mode, $recursive);
 }
+
+/**
+ * Provides an interface for iterating recursively over filesystem directories.
+ *
+ * Manually skips '.' and '..' directories, since no existing method is
+ * available in PHP 5.2.
+ *
+ * @todo Depreciate in favor of RecursiveDirectoryIterator::SKIP_DOTS once PHP
+ *   5.3 or later is required.
+ */
+class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator {
+  /**
+   * Constructs a SkipDotsRecursiveDirectoryIterator
+   *
+   * @param $path
+   *   The path of the directory to be iterated over.
+   */
+  function __construct($path) {
+    parent::__construct($path);
+  }
+
+  function next() {
+    parent::next();
+    while ($this->isDot()) {
+      parent::next();
+    }
+  }
+}
diff --git a/includes/filetransfer/ftp.inc b/includes/filetransfer/ftp.inc
index 6258f768dc0f8a7b94ce53fad4a599b0147fc1c0..97a6f9b155182f61e0d815b5352d073d0d0fa20e 100644
--- a/includes/filetransfer/ftp.inc
+++ b/includes/filetransfer/ftp.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: ftp.inc,v 1.14 2010/10/05 02:08:53 dries Exp $
+// $Id: ftp.inc,v 1.16 2011/01/03 02:20:45 webchick Exp $
 
 /**
  * Base class for FTP implementations.
@@ -24,8 +24,10 @@ abstract class FileTransferFTP extends FileTransfer {
    *   options. If the FTP PHP extension is available, use it.
    */
   static function factory($jail, $settings) {
-    $settings['hostname'] = empty($settings['hostname']) ? 'localhost' : $settings['hostname'];
-    $settings['port'] = empty($settings['port']) ? 21 : $settings['port'];
+    $username = empty($settings['username']) ? '' : $settings['username'];
+    $password = empty($settings['password']) ? '' : $settings['password'];
+    $hostname = empty($settings['advanced']['hostname']) ? 'localhost' : $settings['advanced']['hostname'];
+    $port = empty($settings['advanced']['port']) ? 21 : $settings['advanced']['port'];
 
     if (function_exists('ftp_connect')) {
       $class = 'FileTransferFTPExtension';
@@ -34,7 +36,16 @@ abstract class FileTransferFTP extends FileTransfer {
       throw new FileTransferException('No FTP backend available.');
     }
 
-    return new $class($jail, $settings['username'], $settings['password'], $settings['hostname'], $settings['port']);
+    return new $class($jail, $username, $password, $hostname, $port);
+  }
+
+  /**
+   * Returns the form to configure the FileTransfer class for FTP.
+   */
+  public function getSettingsForm() {
+    $form = parent::getSettingsForm();
+    $form['advanced']['port']['#default_value'] = 21;
+    return $form;
   }
 }
 
diff --git a/includes/filetransfer/local.inc b/includes/filetransfer/local.inc
index f7d7fa84683d7bd5bdcdfb935bc43f48e592014f..225a3408cea5a3961e816fb848a0a4228ad2bd19 100644
--- a/includes/filetransfer/local.inc
+++ b/includes/filetransfer/local.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: local.inc,v 1.4 2010/08/17 22:05:22 dries Exp $
+// $Id: local.inc,v 1.7 2010/12/01 00:13:47 webchick Exp $
 
 /**
  * The local connection class for copying files as the httpd user.
@@ -31,7 +31,7 @@ class FileTransferLocal extends FileTransfer implements FileTransferChmodInterfa
       // Programmer error assertion, not something we expect users to see.
       throw new FileTransferException('removeDirectoryJailed() called with a path (%directory) that is not a directory.', NULL, array('%directory' => $directory));
     }
-    foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory), RecursiveIteratorIterator::CHILD_FIRST) as $filename => $file) {
+    foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($directory), RecursiveIteratorIterator::CHILD_FIRST) as $filename => $file) {
       if ($file->isDir()) {
         if (@!drupal_rmdir($filename)) {
           throw new FileTransferException('Cannot remove directory %directory.', NULL, array('%directory' => $filename));
@@ -64,7 +64,7 @@ class FileTransferLocal extends FileTransfer implements FileTransferChmodInterfa
 
   public function chmodJailed($path, $mode, $recursive) {
     if ($recursive && is_dir($path)) {
-      foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
+      foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
         if (@!chmod($filename, $mode)) {
           throw new FileTransferException('Cannot chmod %path.', NULL, array('%path' => $filename));
         }
diff --git a/includes/filetransfer/ssh.inc b/includes/filetransfer/ssh.inc
index 64fea3aec2b3f93cb5ed3e80ccd4eedbb69de782..a47e967669802bf15f01a55f4fa3f4ff4c5aaaf9 100644
--- a/includes/filetransfer/ssh.inc
+++ b/includes/filetransfer/ssh.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: ssh.inc,v 1.5 2010/01/30 07:59:24 dries Exp $
+// $Id: ssh.inc,v 1.8 2011/01/03 02:32:27 webchick Exp $
 
 /**
  * The SSH connection class for the update module.
@@ -17,7 +17,7 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface
   function connect() {
     $this->connection = @ssh2_connect($this->hostname, $this->port);
     if (!$this->connection) {
-      throw new FileTransferException('SSH Connection failed to @host:@port', NULL, array('@host' => $this->hostname, '@port' => 21));
+      throw new FileTransferException('SSH Connection failed to @host:@port', NULL, array('@host' => $this->hostname, '@port' => $this->port));
     }
     if (!@ssh2_auth_password($this->connection, $this->username, $this->password)) {
       throw new FileTransferException('The supplied username/password combination was not accepted.');
@@ -25,9 +25,11 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface
   }
 
   static function factory($jail, $settings) {
-    $settings['hostname'] = empty($settings['hostname']) ? 'localhost' : $settings['hostname'];
-    $settings['port'] = empty($settings['port']) ? 22 : $settings['port'];
-    return new FileTransferSSH($jail, $settings['username'], $settings['password'], $settings['hostname'], $settings['port']);
+    $username = empty($settings['username']) ? '' : $settings['username'];
+    $password = empty($settings['password']) ? '' : $settings['password'];
+    $hostname = empty($settings['advanced']['hostname']) ? 'localhost' : $settings['advanced']['hostname'];
+    $port = empty($settings['advanced']['port']) ? 22 : $settings['advanced']['port'];
+    return new FileTransferSSH($jail, $username, $password, $hostname, $port);
   }
 
   protected function copyFileJailed($source, $destination) {
@@ -95,4 +97,13 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface
       throw new FileTransferException('Cannot change permissions of @path.', NULL, array('@path' => $path));
     }
   }
+
+  /**
+   * Returns the form to configure the FileTransfer class for SSH.
+   */
+  public function getSettingsForm() {
+    $form = parent::getSettingsForm();
+    $form['advanced']['port']['#default_value'] = 22;
+    return $form;
+  }
 }
diff --git a/includes/form.inc b/includes/form.inc
index 6c4757f4373fe8e55622910b95123500f2ce0b43..72a0acbfeb5308b7509d6a49ae70faaf53b3617a 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: form.inc,v 1.506 2010/10/21 20:46:58 webchick Exp $
+// $Id: form.inc,v 1.520 2011/01/04 16:46:24 webchick Exp $
 
 /**
  * @defgroup forms Form builder functions
@@ -88,6 +88,11 @@
  * the form system and each other.
  *
  * The $form_state keys are:
+ * - build_info: Do not change; internal information stored by Form API to be
+ *   able to build and rebuild the form:
+ *   - args: A list of arguments used to rebuild the form from cache.
+ *   - files: A list of include files to be loaded to rebuild the form. See
+ *     form_load_include().
  * - 'values': An associative array of values submitted to the form. The
  *   validation functions and submit functions use this array for nearly all
  *   their decision making. (Note that
@@ -163,7 +168,7 @@
  *   Any additional arguments are passed on to the functions called by
  *   drupal_get_form(), including the unique form constructor function. For
  *   example, the node_edit form requires that a node object is passed in here
- *   when it is called. These are available to implementations of 
+ *   when it is called. These are available to implementations of
  *   hook_form_alter() and hook_form_FORM_ID_alter() as the array
  *   $form_state['build_info']['args'].
  *
@@ -213,8 +218,8 @@ function drupal_get_form($form_id) {
  *       for building the form. Each array entry may be the path to a file or
  *       another array containing values for the parameters 'type', 'module' and
  *       'name' as needed by module_load_include(). The files listed here are
- *       automatically loaded by form_get_cache(). Defaults to the current menu
- *       router item's 'file' definition, if existent.
+ *       automatically loaded by form_get_cache(). By default the current menu
+ *       router item's 'file' definition is added, if existent.
  *   - rebuild: Normally, after the entire form processing is completed and
  *     submit handlers ran, a form is considered to be done and
  *     drupal_redirect_form() will redirect the user to a new page using a GET
@@ -363,7 +368,12 @@ function form_state_defaults() {
     'rebuild' => FALSE,
     'rebuild_info' => array(),
     'redirect' => NULL,
-    'build_info' => array('args' => array()),
+    // @todo 'args' is usually set, so no other default 'build_info' keys are
+    //   appended via += form_state_defaults().
+    'build_info' => array(
+      'args' => array(),
+      'files' => array(),
+    ),
     'temporary' => array(),
     'submitted' => FALSE,
     'executed' => FALSE,
@@ -470,7 +480,7 @@ function form_get_cache($form_build_id, &$form_state) {
         $form_state = $cached->data + $form_state;
 
         // If the original form is contained in include files, load the files.
-        // See drupal_build_form().
+        // @see form_load_include()
         $form_state['build_info'] += array('files' => array());
         foreach ($form_state['build_info']['files'] as $file) {
           if (is_array($file)) {
@@ -537,6 +547,55 @@ function form_state_keys_no_cache() {
   );
 }
 
+/**
+ * Loads an include file and makes sure it is loaded whenever the form is processed.
+ *
+ * Example:
+ * @code
+ *   // Load node.admin.inc from Node module.
+ *   form_load_include($form_state, 'inc', 'node', 'node.admin');
+ * @endcode
+ *
+ * Use this function instead of module_load_include() from inside a form
+ * constructor or any form processing logic as it ensures that the include file
+ * is loaded whenever the form is processed. In contrast to using
+ * module_load_include() directly, form_load_include() makes sure the include
+ * file is correctly loaded also if the form is cached.
+ *
+ * @param $form_state
+ *   The current state of the form.
+ * @param $type
+ *   The include file's type (file extension).
+ * @param $module
+ *   The module to which the include file belongs.
+ * @param $name
+ *   (optional) The base file name (without the $type extension). If omitted,
+ *   $module is used; i.e., resulting in "$module.$type" by default.
+ *
+ * @return
+ *   The filepath of the loaded include file, or FALSE if the include file was
+ *   not found or has been loaded already.
+ *
+ * @see module_load_include()
+ */
+function form_load_include(&$form_state, $type, $module, $name = NULL) {
+  if (!isset($name)) {
+    $name = $module;
+  }
+  if (!isset($form_state['build_info']['files']["$module:$name.$type"])) {
+    // Only add successfully included files to the form state.
+    if ($result = module_load_include($type, $module, $name)) {
+      $form_state['build_info']['files']["$module:$name.$type"] = array(
+        'type' => $type,
+        'module' => $module,
+        'name' => $name,
+      );
+      return $result;
+    }
+  }
+  return FALSE;
+}
+
 /**
  * Retrieves, populates, and processes a form.
  *
@@ -602,9 +661,14 @@ function drupal_form_submit($form_id, &$form_state) {
   // Merge in default values.
   $form_state += form_state_defaults();
 
-  $form = drupal_retrieve_form($form_id, $form_state);
+  // Populate $form_state['input'] with the submitted values before retrieving
+  // the form, to be consistent with what drupal_build_form() does for
+  // non-programmatic submissions (form builder functions may expect it to be
+  // there).
   $form_state['input'] = $form_state['values'];
+
   $form_state['programmed'] = TRUE;
+  $form = drupal_retrieve_form($form_id, $form_state);
   // Programmed forms are always submitted.
   $form_state['submitted'] = TRUE;
 
@@ -641,6 +705,8 @@ function drupal_retrieve_form($form_id, &$form_state) {
   if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
     $item = menu_get_item();
     if (!empty($item['include_file'])) {
+      // Do not use form_load_include() here, as the file is already loaded.
+      // Anyway, form_get_cache() is able to handle filepaths too.
       $form_state['build_info']['files']['menu'] = $item['include_file'];
     }
   }
@@ -1031,10 +1097,29 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
         drupal_array_set_nested_value($values, $section, $value);
       }
     }
-    // For convenience we always make the value of the pressed button available.
+    // A button's #value does not require validation, so for convenience we
+    // allow the value of the clicked button to be retained in its normal
+    // $form_state['values'] locations, even if these locations are not included
+    // in #limit_validation_errors.
     if (isset($form_state['triggering_element']['#button_type'])) {
-      $values[$form_state['triggering_element']['#name']] = $form_state['triggering_element']['#value'];
-      drupal_array_set_nested_value($values, $form_state['triggering_element']['#parents'], $form_state['triggering_element']['#value']);
+      $button_value = $form_state['triggering_element']['#value'];
+
+      // Like all input controls, the button value may be in the location
+      // dictated by #parents. If it is, copy it to $values, but do not override
+      // what may already be in $values.
+      $parents = $form_state['triggering_element']['#parents'];
+      if (!drupal_array_nested_key_exists($values, $parents) && drupal_array_get_nested_value($form_state['values'], $parents) === $button_value) {
+        drupal_array_set_nested_value($values, $parents, $button_value);
+      }
+
+      // Additionally, form_builder() places the button value in
+      // $form_state['values'][BUTTON_NAME]. If it's still there, after
+      // validation handlers have run, copy it to $values, but do not override
+      // what may already be in $values.
+      $name = $form_state['triggering_element']['#name'];
+      if (!isset($values[$name]) && isset($form_state['values'][$name]) && $form_state['values'][$name] === $button_value) {
+        $values[$name] = $button_value;
+      }
     }
     $form_state['values'] = $values;
   }
@@ -1427,8 +1512,10 @@ function form_set_error($name = NULL, $message = '', $limit_validation_errors =
         // reconstructed #parents begin with the same keys as the specified
         // section, then the element's values are within the part of
         // $form_state['values'] that the clicked button requires to be valid,
-        // so errors for this element must be recorded.
-        if (array_slice(explode('][', $name), 0, count($section)) === $section) {
+        // so errors for this element must be recorded. As the exploded array
+        // will all be strings, we need to cast every value of the section
+        // array to string.
+        if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
           $record = TRUE;
           break;
         }
@@ -1559,7 +1646,7 @@ function form_error(&$element, $message = '') {
  *   This is most commonly implemented with a submit handler setting persistent
  *   data within $form_state based on *validated* values in
  *   $form_state['values'] and setting $form_state['rebuild']. The form building
- *   functions must then be implmented to use the $form_state data to rebuild
+ *   functions must then be implemented to use the $form_state data to rebuild
  *   the form with the structure appropriate for the new state.
  * - Where user input must affect the rendering of the form without affecting
  *   its structure, the necessary conditional rendering logic should reside
@@ -1618,6 +1705,9 @@ function form_builder($form_id, &$element, &$form_state) {
     else {
       $form_state['process_input'] = FALSE;
     }
+
+    // All form elements should have an #array_parents property.
+    $element['#array_parents'] = array();
   }
 
   if (!isset($element['#id'])) {
@@ -1674,7 +1764,7 @@ function form_builder($form_id, &$element, &$form_state) {
       $element[$key]['#parents'] = $element[$key]['#tree'] && $element['#tree'] ? array_merge($element['#parents'], array($key)) : array($key);
     }
     // Ensure #array_parents follows the actual form structure.
-    $array_parents = isset($element['#array_parents']) ? $element['#array_parents'] : array();
+    $array_parents = $element['#array_parents'];
     $array_parents[] = $key;
     $element[$key]['#array_parents'] = $array_parents;
 
@@ -2073,11 +2163,29 @@ function form_type_image_button_value($form, $input, $form_state) {
  *   for this element. Return nothing to use the default.
  */
 function form_type_checkbox_value($element, $input = FALSE) {
-  if ($input !== FALSE) {
-    // Successful (checked) checkboxes are present with a value (possibly '0').
-    // http://www.w3.org/TR/html401/interact/forms.html#successful-controls
-    // For an unchecked checkbox, we return integer 0, so we can explicitly
-    // test for a value different than string '0'.
+  if ($input === FALSE) {
+    // Use #default_value as the default value of a checkbox, except change
+    // NULL to 0, because _form_builder_handle_input_element() would otherwise
+    // replace NULL with empty string, but an empty string is a potentially
+    // valid value for a checked checkbox.
+    return isset($element['#default_value']) ? $element['#default_value'] : 0;
+  }
+  else {
+    // Checked checkboxes are submitted with a value (possibly '0' or ''):
+    // http://www.w3.org/TR/html401/interact/forms.html#successful-controls.
+    // For checked checkboxes, browsers submit the string version of
+    // #return_value, but we return the original #return_value. For unchecked
+    // checkboxes, browsers submit nothing at all, but
+    // _form_builder_handle_input_element() detects this, and calls this
+    // function with $input=NULL. Returning NULL from a value callback means to
+    // use the default value, which is not what is wanted when an unchecked
+    // checkbox is submitted, so we use integer 0 as the value indicating an
+    // unchecked checkbox. Therefore, modules must not use integer 0 as a
+    // #return_value, as doing so results in the checkbox always being treated
+    // as unchecked. The string '0' is allowed for #return_value. The most
+    // common use-case for setting #return_value to either 0 or '0' is for the
+    // first option within a 0-indexed array of checkboxes, and for this,
+    // form_process_checkboxes() uses the string rather than the integer.
     return isset($input) ? $element['#return_value'] : 0;
   }
 }
@@ -2109,7 +2217,7 @@ function form_type_checkboxes_value($element, $input = FALSE) {
     // NULL elements from the array before constructing the return value, to
     // simulate the behavior of web browsers (which do not send unchecked
     // checkboxes to the server at all). This will not affect non-programmatic
-    // form submissions, since a checkbox can never legitimately be NULL.
+    // form submissions, since all values in $_POST are strings.
     foreach ($input as $key => $value) {
       if (!isset($value)) {
         unset($input[$key]);
@@ -2283,7 +2391,7 @@ function form_type_token_value($element, $input = FALSE) {
  *   Form state array where the value change should be recorded.
  */
 function form_set_value($element, $value, &$form_state) {
-  drupal_array_set_nested_value($form_state['values'], $element['#parents'], $value);
+  drupal_array_set_nested_value($form_state['values'], $element['#parents'], $value, TRUE);
 }
 
 /**
@@ -2550,6 +2658,9 @@ function theme_fieldset($variables) {
 /**
  * Returns HTML for a radio button form element.
  *
+ * Note: The input "name" attribute needs to be sanitized before output, which
+ *       is currently done by passing all attributes to drupal_attributes().
+ *
  * @param $variables
  *   An associative array containing:
  *   - element: An associative array containing the properties of the element.
@@ -2563,7 +2674,7 @@ function theme_radio($variables) {
   $element['#attributes']['type'] = 'radio';
   element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
 
-  if (isset($element['#return_value']) && check_plain($element['#value']) == $element['#return_value']) {
+  if (isset($element['#return_value']) && $element['#value'] !== FALSE && $element['#value'] == $element['#return_value']) {
     $element['#attributes']['checked'] = 'checked';
   }
   _form_set_class($element, array('form-radio'));
@@ -2768,22 +2879,30 @@ function weight_value(&$form) {
  */
 function form_process_radios($element) {
   if (count($element['#options']) > 0) {
+    $weight = 0;
     foreach ($element['#options'] as $key => $choice) {
-      if (!isset($element[$key])) {
-        // Generate the parents as the autogenerator does, so we will have a
-        // unique id for each radio button.
-        $parents_for_id = array_merge($element['#parents'], array($key));
-        $element[$key] = array(
-          '#type' => 'radio',
-          '#title' => $choice,
-          '#return_value' => check_plain($key),
-          '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
-          '#attributes' => $element['#attributes'],
-          '#parents' => $element['#parents'],
-          '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
-          '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
-        );
-      }
+      // Maintain order of options as defined in #options, in case the element
+      // defines custom option sub-elements, but does not define all option
+      // sub-elements.
+      $weight += 0.001;
+
+      $element += array($key => array());
+      // Generate the parents as the autogenerator does, so we will have a
+      // unique id for each radio button.
+      $parents_for_id = array_merge($element['#parents'], array($key));
+      $element[$key] += array(
+        '#type' => 'radio',
+        '#title' => $choice,
+        // The key is sanitized in drupal_attributes() during output from the
+        // theme function.
+        '#return_value' => $key,
+        '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
+        '#attributes' => $element['#attributes'],
+        '#parents' => $element['#parents'],
+        '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
+        '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
+        '#weight' => $weight,
+      );
     }
   }
   return $element;
@@ -2807,7 +2926,7 @@ function theme_checkbox($variables) {
   element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
 
   // Unchecked checkbox has #value of integer 0.
-  if (isset($element['#return_value']) && isset($element['#value']) && $element['#value'] !== 0 && $element['#value'] == $element['#return_value']) {
+  if (!empty($element['#checked'])) {
     $element['#attributes']['checked'] = 'checked';
   }
   _form_set_class($element, array('form-checkbox'));
@@ -2859,6 +2978,33 @@ function form_pre_render_conditional_form_element($element) {
   return $element;
 }
 
+/**
+ * Sets the #checked property of a checkbox element.
+ */
+function form_process_checkbox($element, $form_state) {
+  $value = $element['#value'];
+  $return_value = $element['#return_value'];
+  // On form submission, the #value of an available and enabled checked
+  // checkbox is #return_value, and the #value of an available and enabled
+  // unchecked checkbox is integer 0. On not submitted forms, and for
+  // checkboxes with #access=FALSE or #disabled=TRUE, the #value is
+  // #default_value (integer 0 if #default_value is NULL). Most of the time,
+  // a string comparison of #value and #return_value is sufficient for
+  // determining the "checked" state, but a value of TRUE always means checked
+  // (even if #return_value is 'foo'), and a value of FALSE or integer 0 always
+  // means unchecked (even if #return_value is '' or '0').
+  if ($value === TRUE || $value === FALSE || $value === 0) {
+    $element['#checked'] = (bool) $value;
+  }
+  else {
+    // Compare as strings, so that 15 is not considered equal to '15foo', but 1
+    // is considered equal to '1'. This cast does not imply that either #value
+    // or #return_value is expected to be a string.
+    $element['#checked'] = ((string) $value === (string) $return_value);
+  }
+  return $element;
+}
+
 function form_process_checkboxes($element) {
   $value = is_array($element['#value']) ? $element['#value'] : array();
   $element['#tree'] = TRUE;
@@ -2866,18 +3012,30 @@ function form_process_checkboxes($element) {
     if (!isset($element['#default_value']) || $element['#default_value'] == 0) {
       $element['#default_value'] = array();
     }
+    $weight = 0;
     foreach ($element['#options'] as $key => $choice) {
-      if (!isset($element[$key])) {
-        $element[$key] = array(
-          '#type' => 'checkbox',
-          '#processed' => TRUE,
-          '#title' => $choice,
-          '#return_value' => $key,
-          '#default_value' => isset($value[$key]) ? $key : NULL,
-          '#attributes' => $element['#attributes'],
-          '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
-        );
+      // Integer 0 is not a valid #return_value, so use '0' instead.
+      // @see form_type_checkbox_value().
+      // @todo For Drupal 8, cast all integer keys to strings for consistency
+      //   with form_process_radios().
+      if ($key === 0) {
+        $key = '0';
       }
+      // Maintain order of options as defined in #options, in case the element
+      // defines custom option sub-elements, but does not define all option
+      // sub-elements.
+      $weight += 0.001;
+
+      $element += array($key => array());
+      $element[$key] += array(
+        '#type' => 'checkbox',
+        '#title' => $choice,
+        '#return_value' => $key,
+        '#default_value' => isset($value[$key]) ? $key : NULL,
+        '#attributes' => $element['#attributes'],
+        '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
+        '#weight' => $weight,
+      );
     }
   }
   return $element;
@@ -2920,7 +3078,11 @@ function form_process_container($element, &$form_state) {
 }
 
 /**
- * Returns HTML for a container for grouped form items.
+ * Returns HTML to wrap child elements in a container.
+ *
+ * Used for grouped form items. Can also be used as a #theme_wrapper for any
+ * renderable element, to surround it with a <div> and add attributes such as
+ * classes or an HTML id.
  *
  * @param $variables
  *   An associative array containing:
@@ -2931,11 +3093,17 @@ function form_process_container($element, &$form_state) {
  */
 function theme_container($variables) {
   $element = $variables['element'];
-  if (!isset($element['#attributes']['id'])) {
-    $element['#attributes']['id'] = $element['#id'];
+
+  // Special handling for form elements.
+  if (isset($element['#array_parents'])) {
+    // Assign an html ID.
+    if (!isset($element['#attributes']['id'])) {
+      $element['#attributes']['id'] = $element['#id'];
+    }
+    // Add the 'form-wrapper' class.
+    $element['#attributes']['class'][] = 'form-wrapper';
   }
-  // Force the 'form-wrapper' class.
-  $element['#attributes']['class'][] = 'form-wrapper';
+
   return '<div' . drupal_attributes($element['#attributes']) . '>' . $element['#children'] . '</div>';
 }
 
@@ -3200,7 +3368,7 @@ function form_validate_machine_name(&$element, &$form_state) {
   // Verify that the machine name is unique.
   if ($element['#default_value'] !== $element['#value']) {
     $function = $element['#machine_name']['exists'];
-    if ($function($element['#value'])) {
+    if ($function($element['#value'], $element, $form_state)) {
       form_error($element, t('The machine-readable name is already in use. It must be unique.'));
     }
   }
@@ -3235,7 +3403,7 @@ function form_process_fieldset(&$element, &$form_state) {
   }
 
   // Contains form element summary functionalities.
-  $element['#attached']['js']['misc/form.js'] = array('group' => JS_LIBRARY, 'weight' => 1);
+  $element['#attached']['library'][] = array('system', 'drupal.form');
 
   // The .form-wrapper class is required for #states to treat fieldsets like
   // containers.
@@ -3245,7 +3413,7 @@ function form_process_fieldset(&$element, &$form_state) {
 
   // Collapsible fieldsets
   if (!empty($element['#collapsible'])) {
-    $element['#attached']['js'][] = 'misc/collapse.js';
+    $element['#attached']['library'][] = array('system', 'drupal.collapse');
     $element['#attributes']['class'][] = 'collapsible';
     if (!empty($element['#collapsed'])) {
       $element['#attributes']['class'][] = 'collapsed';
@@ -3361,7 +3529,7 @@ function form_process_vertical_tabs($element, &$form_state) {
 function theme_vertical_tabs($variables) {
   $element = $variables['element'];
   // Add required JavaScript and Stylesheet.
-  drupal_add_library('system', 'vertical-tabs');
+  drupal_add_library('system', 'drupal.vertical-tabs');
 
   $output = '<h2 class="element-invisible">' . t('Vertical Tabs') . '</h2>';
   $output .= '<div class="vertical-tabs-panes">' . $element['#children'] . '</div>';
@@ -3470,7 +3638,7 @@ function theme_textfield($variables) {
 
   $extra = '';
   if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
-    drupal_add_js('misc/autocomplete.js');
+    drupal_add_library('system', 'drupal.autocomplete');
     $element['#attributes']['class'][] = 'form-autocomplete';
 
     $attributes = array();
@@ -3532,7 +3700,7 @@ function theme_textarea($variables) {
 
   // Add resizable behavior.
   if (!empty($element['#resizable'])) {
-    drupal_add_js('misc/textarea.js');
+    drupal_add_library('system', 'drupal.textarea');
     $wrapper_attributes['class'][] = 'resizable';
   }
 
@@ -3818,6 +3986,8 @@ function _form_set_class(&$element, $class = array()) {
 /**
  * @defgroup batch Batch operations
  * @{
+ * Create and process batch operations.
+ *
  * Functions allowing forms processing to be spread out over several page
  * requests, thus ensuring that the processing does not get interrupted
  * because of a PHP timeout, while allowing the user to receive feedback
diff --git a/includes/image.inc b/includes/image.inc
index 394fb016331da0edb3e8afeb7e4c62387e9d98ad..ce6a5275f9c447d2766e495bfa44ddf3eb9eb84c 100644
--- a/includes/image.inc
+++ b/includes/image.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.inc,v 1.40 2010/07/16 02:39:38 dries Exp $
+// $Id: image.inc,v 1.42 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -9,6 +9,8 @@
 /**
  * @defgroup image Image toolkits
  * @{
+ * Functions for image file manipulations.
+ *
  * Drupal's image toolkits provide an abstraction layer for common image file
  * manipulations like scaling, cropping, and rotating. The abstraction frees
  * module authors from the need to support multiple image libraries, and it
@@ -122,7 +124,7 @@ function image_toolkit_invoke($method, stdClass $image, array $params = array())
  */
 function image_get_info($filepath, $toolkit = FALSE) {
   $details = FALSE;
-  if (!is_file($filepath)) {
+  if (!is_file($filepath) && !is_uploaded_file($filepath)) {
     return $details;
   }
 
diff --git a/includes/install.core.inc b/includes/install.core.inc
index 92473c7844d5e45c66f9013fd0b006623455b955..52ef5935433a7ddffcb83bb49a72f0ca362c9e6a 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.core.inc,v 1.40 2010/10/15 03:31:28 webchick Exp $
+// $Id: install.core.inc,v 1.49 2011/01/03 15:48:11 webchick Exp $
 
 /**
  * @file
@@ -289,7 +289,6 @@ function install_begin_request(&$install_state) {
     // 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';
-    spl_autoload_register('db_autoload');
 
     // Verify the last completed task in the database, if there is one.
     $task = install_verify_completed_task();
@@ -850,14 +849,13 @@ function install_settings_form($form, &$form_state, &$install_state) {
 
   drupal_set_title(st('Database configuration'));
 
-  $drivers = drupal_detect_database_types();
+  $drivers = drupal_get_database_types();
   $drivers_keys = array_keys($drivers);
 
   $form['driver'] = array(
     '#type' => 'radios',
     '#title' => st('Database type'),
     '#required' => TRUE,
-    '#options' => $drivers,
     '#default_value' => !empty($database['driver']) ? $database['driver'] : current($drivers_keys),
     '#description' => st('The type of database your @drupal data will be stored in.', array('@drupal' => drupal_install_profile_distribution_name())),
   );
@@ -866,82 +864,35 @@ function install_settings_form($form, &$form_state, &$install_state) {
     $form['driver']['#description'] .= ' ' . st('Your PHP configuration only supports a single database type, so it has been automatically selected.');
   }
 
-  // Database name.
-  $form['database'] = array(
-    '#type' => 'textfield',
-    '#title' => st('Database name'),
-    '#default_value' => empty($database['database']) ? '' : $database['database'],
-    '#size' => 45,
-    '#required' => TRUE,
-    '#description' => st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_distribution_name())),
-  );
-
-  // Database username.
-  $form['username'] = array(
-    '#type' => 'textfield',
-    '#title' => st('Database username'),
-    '#default_value' => empty($database['username']) ? '' : $database['username'],
-    '#size' => 45,
-  );
-
-  // Database password.
-  $form['password'] = array(
-    '#type' => 'password',
-    '#title' => st('Database password'),
-    '#default_value' => empty($database['password']) ? '' : $database['password'],
-    '#size' => 45,
-  );
-
-  $form['advanced_options'] = array(
-    '#type' => 'fieldset',
-    '#title' => st('Advanced options'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider.")
-  );
-
-  // Database host.
-  $form['advanced_options']['host'] = array(
-    '#type' => 'textfield',
-    '#title' => st('Database host'),
-    '#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
-    '#size' => 45,
-    // Hostnames can be 255 characters long.
-    '#maxlength' => 255,
-    '#required' => TRUE,
-    '#description' => st('If your database is located on a different server, change this.'),
-  );
-
-  // Database port.
-  $form['advanced_options']['port'] = array(
-    '#type' => 'textfield',
-    '#title' => st('Database port'),
-    '#default_value' => empty($database['port']) ? '' : $database['port'],
-    '#size' => 45,
-    // The maximum port number is 65536, 5 digits.
-    '#maxlength' => 5,
-    '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
-  );
-
-  // Table prefix.
-  $db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
-  $form['advanced_options']['db_prefix'] = array(
-    '#type' => 'textfield',
-    '#title' => st('Table prefix'),
-    '#default_value' => '',
-    '#size' => 45,
-    '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_distribution_name(), '%prefix' => $db_prefix)),
-  );
+  // Add driver specific configuration options.
+  foreach ($drivers as $key => $driver) {
+    $form['driver']['#options'][$key] = $driver->name();
+
+    $form['settings'][$key] = $driver->getFormOptions($database);
+    $form['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . st('@driver_name settings', array('@driver_name' => $driver->name())) . '</h2>';
+    $form['settings'][$key]['#type'] = 'container';
+    $form['settings'][$key]['#tree'] = TRUE;
+    $form['settings'][$key]['advanced_options']['#parents'] = array($key);
+    $form['settings'][$key]['#states'] = array(
+      'visible' => array(
+        ':input[name=driver]' => array('value' => $key),
+      )
+    );
+  }
 
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['save'] = array(
     '#type' => 'submit',
     '#value' => st('Save and continue'),
+    '#limit_validation_errors' => array(
+      array('driver'),
+      array(isset($form_state['input']['driver']) ? $form_state['input']['driver'] : current($drivers_keys)),
+    ),
+    '#submit' => array('install_settings_form_submit'),
   );
 
   $form['errors'] = array();
   $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
-  $form['_database'] = array('#type' => 'value');
 
   return $form;
 }
@@ -950,12 +901,17 @@ function install_settings_form($form, &$form_state, &$install_state) {
  * Form API validate for install_settings form.
  */
 function install_settings_form_validate($form, &$form_state) {
+  $driver = $form_state['values']['driver'];
+  $database = $form_state['values'][$driver];
+  $database['driver'] = $driver;
+
   // TODO: remove when PIFR will be updated to use 'db_prefix' instead of
   // 'prefix' in the database settings form.
-  $form_state['values']['prefix'] = $form_state['values']['db_prefix'];
+  $database['prefix'] = $database['db_prefix'];
+  unset($database['db_prefix']);
 
-  form_set_value($form['_database'], $form_state['values'], $form_state);
-  $errors = install_database_errors($form_state['values'], $form_state['values']['settings_file']);
+  $form_state['storage']['database'] = $database;
+  $errors = install_database_errors($database, $form_state['values']['settings_file']);
   foreach ($errors as $name => $message) {
     form_set_error($name, $message);
   }
@@ -967,22 +923,17 @@ function install_settings_form_validate($form, &$form_state) {
 function install_database_errors($database, $settings_file) {
   global $databases;
   $errors = array();
-  // Verify the table prefix.
-  if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
-    $errors['prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
-  }
-
-  if (!empty($database['port']) && !is_numeric($database['port'])) {
-    $errors['db_port'] = st('Database port must be a number.');
-  }
 
   // Check database type.
-  $database_types = drupal_detect_database_types();
+  $database_types = drupal_get_database_types();
   $driver = $database['driver'];
   if (!isset($database_types[$driver])) {
-    $errors['driver'] = st("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $database['driver']));
+    $errors['driver'] = st("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $driver));
   }
   else {
+    // Run driver specific validation
+    $errors += $database_types[$driver]->validateDatabaseSettings($database);
+
     // Run tasks associated with the database type. Any errors are caught in the
     // calling function.
     $databases['default']['default'] = $database;
@@ -991,13 +942,13 @@ function install_database_errors($database, $settings_file) {
     Database::parseConnectionInfo();
 
     try {
-      db_run_tasks($database['driver']);
+      db_run_tasks($driver);
     }
     catch (DatabaseTaskException $e) {
       // These are generic errors, so we do not have any specific key of the
       // database connection array to attach them to; therefore, we just put
       // them in the error array with standard numeric keys.
-      $errors[] = $e->getMessage();
+      $errors[$driver . '][0'] = $e->getMessage();
     }
   }
   return $errors;
@@ -1009,10 +960,9 @@ function install_database_errors($database, $settings_file) {
 function install_settings_form_submit($form, &$form_state) {
   global $install_state;
 
-  $database = array_intersect_key($form_state['values']['_database'], array_flip(array('driver', 'database', 'username', 'password', 'host', 'port', 'prefix')));
   // Update global settings array and save.
   $settings['databases'] = array(
-    'value'    => array('default' => array('default' => $database)),
+    'value'    => array('default' => array('default' => $form_state['storage']['database'])),
     'required' => TRUE,
   );
   $settings['drupal_hash_salt'] = array(
@@ -1170,6 +1120,15 @@ function install_select_profile_form($form, &$form_state, $profile_files) {
 function install_find_locales($profilename) {
   $locales = file_scan_directory('./profiles/' . $profilename . '/translations', '/\.po$/', array('recurse' => FALSE));
   array_unshift($locales, (object) array('name' => 'en'));
+  foreach ($locales as $key => $locale) {
+    // The locale (file name) might be drupal-7.2.cs.po instead of cs.po.
+    $locales[$key]->langcode = preg_replace('!^(.+\.)?([^\.]+)$!', '\2', $locale->name);
+    // Language codes cannot exceed 12 characters to fit into the {languages}
+    // table.
+    if (strlen($locales[$key]->langcode) > 12) {
+      unset($locales[$key]);
+    }
+  }
   return $locales;
 }
 
@@ -1195,8 +1154,8 @@ function install_select_locale(&$install_state) {
 
   if (!empty($_POST['locale'])) {
     foreach ($locales as $locale) {
-      if ($_POST['locale'] == $locale->name) {
-        $install_state['parameters']['locale'] = $locale->name;
+      if ($_POST['locale'] == $locale->langcode) {
+        $install_state['parameters']['locale'] = $locale->langcode;
         return;
       }
     }
@@ -1214,14 +1173,6 @@ function install_select_locale(&$install_state) {
           $output = '<p>Follow these steps to translate Drupal into your language:</p>';
           $output .= '<ol>';
           $output .= '<li>Download a translation from the <a href="http://localize.drupal.org/download" target="_blank">translation server</a>.</li>';
-          $output .= '<li>Rename the downloaded file retaining only the language code at the end of the file name and its extension. For example, if the file name is
-<pre>
-drupal-7.0.pt-br.po
-</pre>
-rename it to
-<pre>
-pt-br.po
-</pre></li>';
           $output .= '<li>Place it into the following directory:
 <pre>
 /profiles/' . $profilename . '/translations/
@@ -1287,16 +1238,15 @@ function install_select_locale_form($form, &$form_state, $locales, $profilename)
   include_once DRUPAL_ROOT . '/includes/iso.inc';
   $languages = _locale_get_predefined_list();
   foreach ($locales as $locale) {
-    // Try to use verbose locale name.
-    $name = $locale->name;
+    $name = $locale->langcode;
     if (isset($languages[$name])) {
       $name = $languages[$name][0] . (isset($languages[$name][1]) ? ' ' . st('(@language)', array('@language' => $languages[$name][1])) : '');
     }
-    $form['locale'][$locale->name] = array(
+    $form['locale'][$locale->langcode] = array(
       '#type' => 'radio',
-      '#return_value' => $locale->name,
-      '#default_value' => $locale->name == 'en' ? 'en' : '',
-      '#title' => $name . ($locale->name == 'en' ? ' ' . st('(built-in)') : ''),
+      '#return_value' => $locale->langcode,
+      '#default_value' => $locale->langcode == 'en' ? 'en' : '',
+      '#title' => $name . ($locale->langcode == 'en' ? ' ' . st('(built-in)') : ''),
       '#parents' => array('locale')
     );
   }
@@ -1425,8 +1375,19 @@ function install_profile_modules(&$install_state) {
 function install_import_locales(&$install_state) {
   include_once DRUPAL_ROOT . '/includes/locale.inc';
   $install_locale = $install_state['parameters']['locale'];
-  // Enable installation language as default site language.
-  locale_add_language($install_locale, NULL, NULL, NULL, '', NULL, 1, TRUE);
+
+  include_once DRUPAL_ROOT . '/includes/iso.inc';
+  $predefined = _locale_get_predefined_list();
+  if (!isset($predefined[$install_locale])) {
+    // Drupal does not know about this language, so we prefill its values with
+    // our best guess. The user will be able to edit afterwards.
+    locale_add_language($install_locale, $install_locale, $install_locale, LANGUAGE_LTR, '', '', TRUE, TRUE);
+  }
+  else {
+    // A known predefined language, details will be filled in properly.
+    locale_add_language($install_locale, NULL, NULL, NULL, '', '', TRUE, TRUE);
+  }
+
   // Collect files to import for this language.
   $batch = locale_batch_by_language($install_locale, NULL);
   if (!empty($batch)) {
@@ -1458,14 +1419,18 @@ function install_configure_form($form, &$form_state, &$install_state) {
   drupal_set_title(st('Configure site'));
 
   // Warn about settings.php permissions risk
-  $settings_dir = './' . conf_path();
+  $settings_dir = conf_path();
   $settings_file = $settings_dir . '/settings.php';
-  if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file($settings_dir, FILE_NOT_WRITABLE, 'dir')) {
+  // Check that $_POST is empty so we only show this message when the form is
+  // first displayed, not on the next page after it is submitted. (We do not
+  // want to repeat it multiple times because it is a general warning that is
+  // not related to the rest of the installation process; it would also be
+  // especially out of place on the last page of the installer, where it would
+  // distract from the message that the Drupal installation has completed
+  // successfully.)
+  if (empty($_POST) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) {
     drupal_set_message(st('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href="@handbook_url">online handbook</a>.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning');
   }
-  else {
-    drupal_set_message(st('All necessary changes to %dir and %file have been made. They have been set to read-only for security.', array('%dir' => $settings_dir, '%file' => $settings_file)));
-  }
 
   drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
   // Add JavaScript time zone detection.
@@ -1763,7 +1728,7 @@ function _install_configure_form($form, &$form_state, &$install_state) {
   $countries = country_get_list();
   $form['server_settings']['site_default_country'] = array(
     '#type' => 'select',
-    '#title' => t('Default country'),
+    '#title' => st('Default country'),
     '#empty_value' => '',
     '#default_value' => variable_get('site_default_country', NULL),
     '#options' => $countries,
diff --git a/includes/install.inc b/includes/install.inc
index 7bdc0efdc70351de26af2c199b72896000f532a6..3956ff9f672cdbd50e52b30ae78c82240f450af4 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: install.inc,v 1.142 2010/08/22 15:31:18 dries Exp $
+// $Id: install.inc,v 1.152 2011/01/02 17:23:20 webchick Exp $
 
 /**
  * Indicates that a module has not been installed yet.
@@ -175,6 +175,9 @@ function drupal_set_installed_schema_version($module, $version) {
     ->fields(array('schema_version' => $version))
     ->condition('name', $module)
     ->execute();
+
+  // Reset the static cache of module schema versions.
+  drupal_get_installed_schema_version(NULL, TRUE);
 }
 
 /**
@@ -227,6 +230,22 @@ function drupal_detect_baseurl($file = 'install.php') {
  *  An array of database types compiled into PHP.
  */
 function drupal_detect_database_types() {
+  $databases = drupal_get_database_types();
+
+  foreach ($databases as $driver => $installer) {
+    $databases[$driver] = $installer->name();
+  }
+
+  return $databases;
+}
+
+/**
+ * Return all supported database installer objects that are compiled into PHP.
+ *
+ * @return
+ *  An array of database installer objects compiled into PHP.
+ */
+function drupal_get_database_types() {
   $databases = array();
 
   // We define a driver as a directory in /includes/database that in turn
@@ -235,7 +254,6 @@ function drupal_detect_database_types() {
   // Because we have no registry yet, we need to also include the install.inc
   // file for the driver explicitly.
   require_once DRUPAL_ROOT . '/includes/database/database.inc';
-  spl_autoload_register('db_autoload');
   foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
     if (file_exists($file->uri . '/database.inc') && file_exists($file->uri . '/install.inc')) {
       $drivers[$file->filename] = $file->uri;
@@ -243,10 +261,9 @@ function drupal_detect_database_types() {
   }
 
   foreach ($drivers as $driver => $file) {
-    $class = 'DatabaseTasks_' . $driver;
-    $installer = new $class();
+    $installer = db_installer_object($driver);
     if ($installer->installable()) {
-      $databases[$driver] = $installer->name();
+      $databases[$driver] = $installer;
     }
   }
 
@@ -276,9 +293,13 @@ abstract class DatabaseTasks {
    * to call (optional) and any arguments to be passed to the function.
    */
   protected $tasks = array(
+    array(
+      'function'    => 'checkEngineVersion',
+      'arguments'   => array(),
+    ),
     array(
       'arguments'   => array(
-        'CREATE TABLE drupal_install_test (id int NULL)',
+        'CREATE TABLE {drupal_install_test} (id int NULL)',
         'Drupal can use CREATE TABLE database commands.',
         'Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>',
         TRUE,
@@ -286,33 +307,34 @@ abstract class DatabaseTasks {
     ),
     array(
       'arguments'   => array(
-        'INSERT INTO drupal_install_test (id) VALUES (1)',
+        'INSERT INTO {drupal_install_test} (id) VALUES (1)',
         'Drupal can use INSERT database commands.',
         'Failed to <strong>INSERT</strong> a value into a test table on your database server. We tried inserting a value with the command %query and the server reported the following error: %error.',
       ),
     ),
     array(
       'arguments'   => array(
-        'UPDATE drupal_install_test SET id = 2',
+        'UPDATE {drupal_install_test} SET id = 2',
         'Drupal can use UPDATE database commands.',
         'Failed to <strong>UPDATE</strong> a value in a test table on your database server. We tried updating a value with the command %query and the server reported the following error: %error.',
       ),
     ),
     array(
       'arguments'   => array(
-        'DELETE FROM drupal_install_test',
+        'DELETE FROM {drupal_install_test}',
         'Drupal can use DELETE database commands.',
         'Failed to <strong>DELETE</strong> a value from a test table on your database server. We tried deleting a value with the command %query and the server reported the following error: %error.',
       ),
     ),
     array(
       'arguments'   => array(
-        'DROP TABLE drupal_install_test',
+        'DROP TABLE {drupal_install_test}',
         'Drupal can use DROP TABLE database commands.',
         'Failed to <strong>DROP</strong> a test table from your database server. We tried dropping a table with the command %query and the server reported the following error %error.',
       ),
     ),
   );
+
   /**
    * Results from tasks.
    *
@@ -348,8 +370,22 @@ abstract class DatabaseTasks {
     return $this->hasPdoDriver() && empty($this->error);
   }
 
+  /**
+   * Return the human-readable name of the driver.
+   */
   abstract public function name();
 
+  /**
+   * Return the minimum required version of the engine.
+   *
+   * @return
+   *   A version string. If not NULL, it will be checked against the version
+   *   reported by the Database engine using version_compare().
+   */
+  public function minimumVersion() {
+    return NULL;
+  }
+
   /**
    * Run database tasks and tests to see if Drupal can run on the database.
    */
@@ -415,7 +451,125 @@ abstract class DatabaseTasks {
       return !$fatal;
     }
   }
+
+  /**
+   * Check the engine version.
+   */
+  protected function checkEngineVersion() {
+    if ($this->minimumVersion() && version_compare(Database::getConnection()->version(), $this->minimumVersion(), '<')) {
+      $this->fail(st("The database version %version is less than the minimum required version %minimum_version.", array('%version' => Database::getConnection()->version(), '%minimum_version' => $this->minimumVersion())));
+    }
+  }
+
+  /**
+   * Return driver specific configuration options.
+   *
+   * @param $database
+   *  An array of driver specific configuration options.
+   *
+   * @return
+   *   The options form array.
+   */
+  public function getFormOptions($database) {
+    $form['database'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database name'),
+      '#default_value' => empty($database['database']) ? '' : $database['database'],
+      '#size' => 45,
+      '#required' => TRUE,
+      '#description' => st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_distribution_name())),
+    );
+
+    $form['username'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database username'),
+      '#default_value' => empty($database['username']) ? '' : $database['username'],
+      '#required' => TRUE,
+      '#size' => 45,
+    );
+
+    $form['password'] = array(
+      '#type' => 'password',
+      '#title' => st('Database password'),
+      '#default_value' => empty($database['password']) ? '' : $database['password'],
+      '#required' => FALSE,
+      '#size' => 45,
+    );
+
+    $form['advanced_options'] = array(
+      '#type' => 'fieldset',
+      '#title' => st('Advanced options'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider."),
+      '#weight' => 10,
+    );
+
+    $profile = drupal_get_profile();
+    $db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
+    $form['advanced_options']['db_prefix'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Table prefix'),
+      '#default_value' => '',
+      '#size' => 45,
+      '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_distribution_name(), '%prefix' => $db_prefix)),
+      '#weight' => 10,
+    );
+
+    $form['advanced_options']['host'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database host'),
+      '#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
+      '#size' => 45,
+      // Hostnames can be 255 characters long.
+      '#maxlength' => 255,
+      '#required' => TRUE,
+      '#description' => st('If your database is located on a different server, change this.'),
+    );
+
+    $form['advanced_options']['port'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database port'),
+      '#default_value' => empty($database['port']) ? '' : $database['port'],
+      '#size' => 45,
+      // The maximum port number is 65536, 5 digits.
+      '#maxlength' => 5,
+      '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Validates driver specific configuration settings.
+   *
+   * Checks to ensure correct basic database settings and that a proper
+   * connection to the database can be established.
+   *
+   * @param $database
+   *   An array of driver specific configuration options.
+   * 
+   * @return
+   *   An array of driver configuration errors, keyed by form element name.
+   */
+  public function validateDatabaseSettings($database) {
+    $errors = array();
+
+    // Verify the table prefix.
+    if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
+      $errors[$database['driver'] . '][advanced_options][db_prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
+    }
+
+    // Verify the database port.
+    if (!empty($database['port']) && !is_numeric($database['port'])) {
+      $errors[$database['driver'] . '][advanced_options][port'] =  st('Database port must be a number.');
+    }
+
+    return $errors;
+  }
+
 }
+
 /**
  * @class Exception class used to throw error if the DatabaseInstaller fails.
  */
@@ -524,7 +678,7 @@ function drupal_verify_profile($install_state) {
 
   // Get a list of modules that exist in Drupal's assorted subdirectories.
   $present_modules = array();
-  foreach (drupal_system_listing('/\.module$/', 'modules', 'name', 0) as $present_module) {
+  foreach (drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0) as $present_module) {
     $present_modules[] = $present_module->name;
   }
 
@@ -581,12 +735,53 @@ function drupal_install_system() {
 }
 
 /**
- * Calls the uninstall function and updates the system table for a given module.
+ * Uninstalls a given list of modules.
  *
  * @param $module_list
  *   The modules to uninstall.
+ * @param $uninstall_dependents
+ *   If TRUE, the function will check that all modules which depend on the
+ *   passed-in module list either are already uninstalled or contained in the
+ *   list, and it will ensure that the modules are uninstalled in the correct
+ *   order. This incurs a significant performance cost, so use FALSE if you
+ *   know $module_list is already complete and in the correct order.
+ *
+ * @return
+ *   FALSE if one or more dependent modules are missing from the list, TRUE
+ *   otherwise.
  */
-function drupal_uninstall_modules($module_list = array()) {
+function drupal_uninstall_modules($module_list = array(), $uninstall_dependents = TRUE) {
+  if ($uninstall_dependents) {
+    // Get all module data so we can find dependents and sort.
+    $module_data = system_rebuild_module_data();
+    // Create an associative array with weights as values.
+    $module_list = array_flip(array_values($module_list));
+
+    $profile = drupal_get_profile();
+    while (list($module) = each($module_list)) {
+      if (!isset($module_data[$module]) || drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED) {
+        // This module doesn't exist or is already uninstalled, skip it.
+        unset($module_list[$module]);
+        continue;
+      }
+      $module_list[$module] = $module_data[$module]->sort;
+
+      // If the module has any dependents which are not already uninstalled and
+      // not included in the passed-in list, abort. It is not safe to uninstall
+      // them automatically because uninstalling a module is a destructive
+      // operation.
+      foreach (array_keys($module_data[$module]->required_by) as $dependent) {
+        if (!isset($module_list[$dependent]) && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED && $dependent != $profile) {
+          return FALSE;
+        }
+      }
+    }
+
+    // Sort the module list by pre-calculated weights.
+    asort($module_list);
+    $module_list = array_keys($module_list);
+  }
+
   foreach ($module_list as $module) {
     // First, retrieve all the module's menu paths from db.
     drupal_load('module', $module);
@@ -633,6 +828,8 @@ function drupal_uninstall_modules($module_list = array()) {
     // Call hook_module_uninstall to let other modules act
     module_invoke_all('modules_uninstalled', $module_list);
   }
+
+  return TRUE;
 }
 
 /**
@@ -872,11 +1069,16 @@ function st($string, array $args = array(), array $options = array()) {
   if (!isset($locale_strings)) {
     $locale_strings = array();
     if (isset($install_state['parameters']['profile']) && isset($install_state['parameters']['locale'])) {
-      $filename = 'profiles/' . $install_state['parameters']['profile'] . '/translations/' . $install_state['parameters']['locale'] . '.po';
-      if (file_exists(DRUPAL_ROOT . '/' . $filename)) {
+      // If the given locale was selected, there should be at least one .po file
+      // with its name ending in {$install_state['parameters']['locale']}.po
+      // This might or might not be the entire filename. It is also possible
+      // that multiple files end with the same extension, even if unlikely.
+      $po_files = file_scan_directory('./profiles/' . $install_state['parameters']['profile'] . '/translations', '/'. $install_state['parameters']['locale'] .'\.po$/', array('recurse' => FALSE));
+      if (count($po_files)) {
         require_once DRUPAL_ROOT . '/includes/locale.inc';
-        $file = (object) array('uri' => $filename);
-        _locale_import_read_po('mem-store', $file);
+        foreach ($po_files as $po_file) {
+          _locale_import_read_po('mem-store', $po_file);
+        }
         $locale_strings = _locale_import_one_string('mem-report');
       }
     }
@@ -1050,8 +1252,18 @@ function install_profile_info($profile, $locale = 'en') {
  * encoding.
  */
 function db_run_tasks($driver) {
-  $task_class = 'DatabaseTasks_' . $driver;
-  $DatabaseTasks = new $task_class();
-  $DatabaseTasks->runTasks();
+  db_installer_object($driver)->runTasks();
   return TRUE;
 }
+
+/**
+ * Returns a database installer object.
+ *
+ * @param $driver
+ *   The name of the driver.
+ */
+function db_installer_object($driver) {
+  Database::loadDriverFile($driver, array('install.inc'));
+  $task_class = 'DatabaseTasks_' . $driver;
+  return new $task_class();
+}
diff --git a/includes/iso.inc b/includes/iso.inc
index bf1a3fcabe0e13dafae7e52a089cff44483a21ec..5d8a09c078b4af9322ebab62ac16cdf627dbea23 100644
--- a/includes/iso.inc
+++ b/includes/iso.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: iso.inc,v 1.12 2010/10/09 18:20:43 webchick Exp $
+// $Id: iso.inc,v 1.13 2011/01/04 16:07:48 webchick Exp $
 
 /**
  * @file
@@ -241,7 +241,7 @@ function _country_get_predefined_list() {
     'TH' => $t('Thailand'),
     'TJ' => $t('Tajikistan'),
     'TK' => $t('Tokelau'),
-    'TL' => $t('East Timor'),
+    'TL' => $t('Timor-Leste'),
     'TM' => $t('Turkmenistan'),
     'TN' => $t('Tunisia'),
     'TO' => $t('Tonga'),
diff --git a/includes/locale.inc b/includes/locale.inc
index 42cdbf273e952a88b7424b1617f784cee163a765..e59e28e2d4ee18a9eebb7431c9100f562bc88f5b 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.inc,v 1.260 2010/10/06 13:38:39 dries Exp $
+// $Id: locale.inc,v 1.266 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -22,6 +22,12 @@ define('LOCALE_LANGUAGE_NEGOTIATION_BROWSER', 'locale-browser');
  */
 define('LOCALE_LANGUAGE_NEGOTIATION_INTERFACE', 'locale-interface');
 
+/**
+ * If no URL language is available language is determined using an already
+ * detected one.
+ */
+define('LOCALE_LANGUAGE_NEGOTIATION_URL_FALLBACK', 'locale-url-fallback');
+
 /**
  * The language is set based on the user language settings.
  */
@@ -64,6 +70,10 @@ define('LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN', 1);
 /**
  * @defgroup locale-languages-negotiation Language negotiation options
  * @{
+ * Functions for language negotiation.
+ *
+ * There are functions that provide the ability to identify the
+ * language. This behavior can be controlled by various options.
  */
 
 /**
@@ -210,6 +220,53 @@ function locale_language_from_url($languages) {
   return $language_url;
 }
 
+/**
+ * Determines the language to be assigned to URLs when none is detected.
+ *
+ * The language negotiation process has a fallback chain that ends with the
+ * default language provider. Each built-in language type has a separate
+ * initialization:
+ * - Interface language, which is the only configurable one, always gets a valid
+ *   value. If no request-specific language is detected, the default language
+ *   will be used.
+ * - Content language merely inherits the interface language by default.
+ * - URL language is detected from the requested URL and will be used to rewrite
+ *   URLs appearing in the page being rendered. If no language can be detected,
+ *   there are two possibilities:
+ *   - If the default language has no configured path prefix or domain, then the
+ *     default language is used. This guarantees that (missing) URL prefixes are
+ *     preserved when navigating through the site.
+ *   - If the default language has a configured path prefix or domain, a
+ *     requested URL having an empty prefix or domain is an anomaly that must be
+ *     fixed. This is done by introducing a prefix or domain in the rendered
+ *     page matching the detected interface language.
+ *
+ * @param $languages
+ *   (optional) An array of valid language objects. This is passed by
+ *   language_provider_invoke() to every language provider callback, but it is
+ *   not actually needed here. Defaults to NULL.
+ * @param $language_type
+ *   (optional) The language type to fall back to. Defaults to the interface
+ *   language.
+ *
+ * @return
+ *   A valid language code.
+ */
+function locale_language_url_fallback($language = NULL, $language_type = LANGUAGE_TYPE_INTERFACE) {
+  $default = language_default();
+  $prefix = (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) == LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX);
+
+  // If the default language is not configured to convey language information,
+  // a missing URL language information indicates that URL language should be
+  // the default one, otherwise we fall back to an already detected language.
+  if (($prefix && empty($default->prefix)) || (!$prefix && empty($default->domain))) {
+    return $default->language;
+  }
+  else {
+    return $GLOBALS[$language_type]->language;
+  }
+}
+
 /**
  * Return the URL language switcher block. Translation links may be provided by
  * other modules.
@@ -268,11 +325,27 @@ function locale_language_switcher_session($type, $path) {
  * Rewrite URLs for the URL language provider.
  */
 function locale_language_url_rewrite_url(&$path, &$options) {
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['languages'] = &drupal_static(__FUNCTION__);
+  }
+  $languages = &$drupal_static_fast['languages'];
+
+  if (!isset($languages)) {
+    $languages = language_list('enabled');
+    $languages = array_flip(array_keys($languages[1]));
+  }
+
   // Language can be passed as an option, or we go for current URL language.
   if (!isset($options['language'])) {
     global $language_url;
     $options['language'] = $language_url;
   }
+  // We allow only enabled languages here.
+  elseif (!isset($languages[$options['language']->language])) {
+    unset($options['language']);
+    return;
+  }
 
   if (isset($options['language'])) {
     switch (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX)) {
@@ -351,8 +424,11 @@ function locale_string_is_safe($string) {
 }
 
 /**
- * @defgroup locale-api-add Language addition API.
+ * @defgroup locale-api-add Language addition API
  * @{
+ * Add a language.
+ *
+ * The language addition API is used to create languages and store them.
  */
 
 /**
@@ -429,8 +505,12 @@ function locale_add_language($langcode, $name = NULL, $native = NULL, $direction
  */
 
 /**
- * @defgroup locale-api-import Translation import API.
+ * @defgroup locale-api-import-export Translation import/export API.
  * @{
+ * Functions to import and export translations.
+ *
+ * These functions provide the ability to import translations from
+ * external files and to export translations and translation templates.
  */
 
 /**
@@ -556,7 +636,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group =
       $context = "MSGID_PLURAL";
     }
     elseif (!strncmp("msgid", $line, 5)) {
-      if ($context == "MSGSTR") {   // End current entry, start a new one
+      if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) {   // End current entry, start a new one
         _locale_import_one_string($op, $current, $mode, $lang, $file, $group);
         $current = array();
       }
@@ -574,7 +654,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group =
       $context = "MSGID";
     }
     elseif (!strncmp("msgctxt", $line, 7)) {
-      if ($context == "MSGSTR") {   // End current entry, start a new one
+      if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) {   // End current entry, start a new one
         _locale_import_one_string($op, $current, $mode, $lang, $file, $group);
         $current = array();
       }
@@ -650,8 +730,8 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group =
     }
   }
 
-  // End of PO file, flush last entry
-  if (!empty($current) && !empty($current['msgstr'])) {
+  // End of PO file, flush last entry.
+  if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) {
     _locale_import_one_string($op, $current, $mode, $lang, $file, $group);
   }
   elseif ($context != "COMMENT") {
@@ -1205,7 +1285,7 @@ function _locale_import_parse_quoted($string) {
   }
 }
 /**
- * @} End of "locale-api-import"
+ * @} End of "locale-api-import-export"
  */
 
 /**
@@ -1278,7 +1358,7 @@ function _locale_parse_js_file($filepath) {
 }
 
 /**
- * @defgroup locale-api-export Translation (template) export API.
+ * @addtogroup locale-api-import-export
  * @{
  */
 
@@ -1515,12 +1595,16 @@ function _locale_export_remove_plural($entry) {
   return preg_replace('/(@count)\[[0-9]\]/', '\\1', $entry);
 }
 /**
- * @} End of "locale-api-export"
+ * @} End of "locale-api-import-export"
  */
 
 /**
- * @defgroup locale-api-seek String search functions.
+ * @defgroup locale-api-seek Translation search API
  * @{
+ * Functions to search in translation files.
+ *
+ * These functions provide the functionality to search for specific
+ * translations.
  */
 
 /**
@@ -1825,6 +1909,7 @@ function _locale_translate_language_list($translation, $limit_language) {
 /**
  * @defgroup locale-api-predefined List of predefined languages
  * @{
+ * API to provide a list of predefined languages.
  */
 
 /**
@@ -1859,6 +1944,10 @@ function _locale_prepare_predefined_list() {
 /**
  * @defgroup locale-autoimport Automatic interface translation import
  * @{
+ * Functions to create batches for importing translations.
+ *
+ * These functions can be used to import translations for installed
+ * modules.
  */
 
 /**
diff --git a/includes/lock.inc b/includes/lock.inc
index 546f6bff5dcae1af120106f0a586a0923e5fd81e..ddf4e7549e8985c9beccdd596e5dd50692071c42 100644
--- a/includes/lock.inc
+++ b/includes/lock.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: lock.inc,v 1.5 2010/07/16 11:19:38 dries Exp $
+// $Id: lock.inc,v 1.6 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -7,8 +7,10 @@
  */
 
 /**
- * @defgroup lock Functions to coordinate long-running operations across requests.
+ * @defgroup lock Locking mechanisms
  * @{
+ * Functions to coordinate long-running operations across requests.
+ *
  * In most environments, multiple Drupal page requests (a.k.a. threads or
  * processes) will execute in parallel. This leads to potential conflicts or
  * race conditions when two requests execute the same code at the same time. A
diff --git a/includes/menu.inc b/includes/menu.inc
index ecffedaa9d319415fdc878ba9ff86f4d96ee7fb4..fb61fd37edd192fbfb517d531bc3c1e1c7415ed3 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.inc,v 1.416 2010/10/21 11:56:17 dries Exp $
+// $Id: menu.inc,v 1.431 2011/01/04 06:20:30 dries Exp $
 
 /**
  * @file
@@ -49,8 +49,9 @@
  * Access to the callback functions is also protected by the menu system.
  * The "access callback" with an optional "access arguments" of each menu
  * item is called before the page callback proceeds. If this returns TRUE,
- * then access is granted; if FALSE, then access is denied. Menu items may
- * omit this attribute to use the value provided by an ancestor item.
+ * then access is granted; if FALSE, then access is denied. Default local task
+ * menu items (see next paragraph) may omit this attribute to use the value
+ * provided by the parent item.
  *
  * In the default Drupal interface, you will notice many links rendered as
  * tabs. These are known in the menu system as "local tasks", and they are
@@ -124,8 +125,10 @@ define('MENU_IS_LOCAL_ACTION', 0x0100);
 /**
  * @defgroup menu_item_types Menu item types
  * @{
+ * Definitions for various menu types.
+ *
  * Menu item definitions provide one of these constants, which are shortcuts for
- * combinations of the above flags.
+ * combinations of @link menu_flags Menu flags @endlink.
  */
 
 /**
@@ -250,7 +253,7 @@ define('MENU_SITE_ONLINE', 5);
 /**
  * @defgroup menu_tree_parameters Menu tree parameters
  * @{
- * Menu tree
+ * Parameters for a menu tree.
  */
 
  /**
@@ -335,25 +338,39 @@ function menu_get_ancestors($parts) {
 }
 
 /**
- * The menu system uses serialized arrays stored in the database for
- * arguments. However, often these need to change according to the
- * current path. This function unserializes such an array and does the
- * necessary change.
+ * Unserializes menu data, using a map to replace path elements.
+ *
+ * The menu system stores various path-related information (such as the 'page
+ * arguments' and 'access arguments' components of a menu item) in the database
+ * using serialized arrays, where integer values in the arrays represent
+ * arguments to be replaced by values from the path. This function first
+ * unserializes such menu information arrays, and then does the path
+ * replacement.
+ *
+ * The path replacement acts on each integer-valued element of the unserialized
+ * menu data array ($data) using a map array ($map, which is typically an array
+ * of path arguments) as a list of replacements. For instance, if there is an
+ * element of $data whose value is the number 2, then it is replaced in $data
+ * with $map[2]; non-integer values in $data are left alone.
  *
- * Integer values are mapped according to the $map parameter. For
- * example, if unserialize($data) is array('view', 1) and $map is
- * array('node', '12345') then 'view' will not be changed because
- * it is not an integer, but 1 will as it is an integer. As $map[1]
- * is '12345', 1 will be replaced with '12345'. So the result will
- * be array('node_load', '12345').
+ * As an example, an unserialized $data array with elements ('node_load', 1)
+ * represents instructions for calling the node_load() function. Specifically,
+ * this instruction says to use the path component at index 1 as the input
+ * parameter to node_load(). If the path is 'node/123', then $map will be the
+ * array ('node', 123), and the returned array from this function will have
+ * elements ('node_load', 123), since $map[1] is 123. This return value will
+ * indicate specifically that node_load(123) is to be called to load the node
+ * whose ID is 123 for this menu item.
  *
- * @param @data
- *   A serialized array.
- * @param @map
- *   An array of potential replacements.
+ * @param $data
+ *   A serialized array of menu data, as read from the database.
+ * @param $map
+ *   A path argument array, used to replace integer values in $data; an integer
+ *   value N in $data will be replaced by value $map[N]. Typically, the $map
+ *   array is generated from a call to the arg() function.
  *
  * @return
- *   The $data array unserialized and mapped.
+ *   The unserialized $data array, with path arguments replaced.
  */
 function menu_unserialize($data, $map) {
   if ($data = unserialize($data)) {
@@ -413,8 +430,6 @@ function menu_get_item($path = NULL, $router_item = NULL) {
   }
   if (!isset($router_items[$path])) {
     $original_map = arg(NULL, $path);
-    $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
-    $ancestors = menu_get_ancestors($parts);
 
     // Since there is no limit to the length of $path, use a hash to keep it
     // short yet unique.
@@ -423,10 +438,16 @@ function menu_get_item($path = NULL, $router_item = NULL) {
       $router_item = $cached->data;
     }
     else {
+      $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
+      $ancestors = menu_get_ancestors($parts);
       $router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc();
       cache_set($cid, $router_item, 'cache_menu');
     }
     if ($router_item) {
+      // Allow modules to alter the router item before it is translated and
+      // checked for access.
+      drupal_alter('menu_get_item', $router_item, $path, $original_map);
+
       $map = _menu_translate($router_item, $original_map);
       $router_item['original_map'] = $original_map;
       if ($map === FALSE) {
@@ -517,8 +538,8 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
 function _menu_load_objects(&$item, &$map) {
   if ($load_functions = $item['load_functions']) {
     // If someone calls this function twice, then unserialize will fail.
-    if ($load_functions_unserialized = unserialize($load_functions)) {
-      $load_functions = $load_functions_unserialized;
+    if (!is_array($load_functions)) {
+      $load_functions = unserialize($load_functions);
     }
     $path_map = $map;
     foreach ($load_functions as $index => $function) {
@@ -783,10 +804,30 @@ function _menu_link_map_translate(&$map, $to_arg_functions) {
   }
 }
 
+/**
+ * Returns path as one string from the argument we are currently at.
+ */
 function menu_tail_to_arg($arg, $map, $index) {
   return implode('/', array_slice($map, $index));
 }
 
+/**
+ * Loads path as one string from the argument we are currently at.
+ *
+ * To use this load function, you must specify the load arguments
+ * in the router item as:
+ * @code
+ * $item['load arguments'] = array('%map', '%index');
+ * @endcode
+ *
+ * @see search_menu().
+ */
+function menu_tail_load($arg, &$map, $index) {
+  $arg = implode('/', array_slice($map, $index));
+  $map = array_slice($map, 0, $index);
+  return $arg;
+}
+
 /**
  * This function is similar to _menu_translate() but does link-specific
  * preparation such as always calling to_arg functions
@@ -1627,15 +1668,14 @@ function menu_get_custom_theme($initialize = FALSE) {
     if (!empty($custom_themes)) {
       $custom_theme = array_pop($custom_themes);
     }
-    // Otherwise, execute the theme callback function for the current page, if
-    // there is one, in order to determine the custom theme to set.
-    if (!isset($custom_theme)) {
-      $router_item = menu_get_item();
-      if (!empty($router_item['access']) && !empty($router_item['theme_callback']) && function_exists($router_item['theme_callback'])) {
-        $theme_name = call_user_func_array($router_item['theme_callback'], $router_item['theme_arguments']);
-        if (drupal_theme_access($theme_name)) {
-          $custom_theme = $theme_name;
-        }
+    // If there is a theme callback function for the current page, execute it.
+    // If this returns a valid theme, it will override any theme that was set
+    // by a hook_custom_theme() implementation above.
+    $router_item = menu_get_item();
+    if (!empty($router_item['access']) && !empty($router_item['theme_callback']) && function_exists($router_item['theme_callback'])) {
+      $theme_name = call_user_func_array($router_item['theme_callback'], $router_item['theme_arguments']);
+      if (drupal_theme_access($theme_name)) {
+        $custom_theme = $theme_name;
       }
     }
   }
@@ -2128,22 +2168,35 @@ function menu_tab_root_path() {
 }
 
 /**
- * Returns renderable local tasks.
+ * Returns a renderable element for the primary and secondary tabs.
+ */
+function menu_local_tabs() {
+  return array(
+    '#theme' => 'menu_local_tasks',
+    '#primary' => menu_primary_local_tasks(),
+    '#secondary' => menu_secondary_local_tasks(),
+  );
+}
+
+/**
+ * Returns HTML for primary and secondary local tasks.
  *
  * @ingroup themeable
  */
-function theme_menu_local_tasks() {
-  $output = array();
+function theme_menu_local_tasks(&$variables) {
+  $output = '';
 
-  if ($primary = menu_primary_local_tasks()) {
-    $primary['#prefix'] = '<h2 class="element-invisible">' . t('Primary tabs') . '</h2><ul class="tabs primary">';
-    $primary['#suffix'] = '</ul>';
-    $output[] = $primary;
+  if (!empty($variables['primary'])) {
+    $variables['primary']['#prefix'] = '<h2 class="element-invisible">' . t('Primary tabs') . '</h2>';
+    $variables['primary']['#prefix'] .= '<ul class="tabs primary">';
+    $variables['primary']['#suffix'] = '</ul>';
+    $output .= drupal_render($variables['primary']);
   }
-  if ($secondary = menu_secondary_local_tasks()) {
-    $secondary['#prefix'] = '<h2 class="element-invisible">' . t('Secondary tabs') . '</h2><ul class="tabs secondary">';
-    $secondary['#suffix'] = '</ul>';
-    $output[] = $secondary;
+  if (!empty($variables['secondary'])) {
+    $variables['secondary']['#prefix'] = '<h2 class="element-invisible">' . t('Secondary tabs') . '</h2>';
+    $variables['secondary']['#prefix'] .= '<ul class="tabs secondary">';
+    $variables['secondary']['#suffix'] = '</ul>';
+    $output .= drupal_render($variables['secondary']);
   }
 
   return $output;
@@ -2196,10 +2249,10 @@ function menu_set_active_item($path) {
  *   Path to menu root of the current page, as an array of menu link items,
  *   starting with the site's home page. Each link item is an associative array
  *   with the following components:
- *   - 'title': Title of the item.
- *   - 'href': Drupal path of the item.
- *   - 'localized_options': Options for passing into the l() function.
- *   - 'type': A menu type constant, such as MENU_DEFAULT_LOCAL_TASK, or 0 to
+ *   - title: Title of the item.
+ *   - href: Drupal path of the item.
+ *   - localized_options: Options for passing into the l() function.
+ *   - type: A menu type constant, such as MENU_DEFAULT_LOCAL_TASK, or 0 to
  *     indicate it's not really in the menu (used for the home page item).
  *   If $new_trail is supplied, the value is saved in a static variable and
  *   returned. If $new_trail is not supplied, and there is a saved value from
@@ -2326,13 +2379,15 @@ function menu_link_get_preferred($path = NULL) {
     $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
     $query->fields('ml');
     // Weight must be taken from {menu_links}, not {menu_router}.
-    $query->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight')));
+    $query->addField('ml', 'weight', 'link_weight');
+    $query->fields('m');
     $query->condition('ml.menu_name', $menu_names, 'IN');
     $query->condition('ml.link_path', $path_candidates, 'IN');
 
     // Sort candidates by link path and menu name.
     $candidates = array();
     foreach ($query->execute() as $candidate) {
+      $candidate['weight'] = $candidate['link_weight'];
       $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
     }
 
@@ -2452,9 +2507,11 @@ function menu_link_load($mlid) {
     $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
     $query->fields('ml');
     // Weight should be taken from {menu_links}, not {menu_router}.
-    $query->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight')));
+    $query->addField('ml', 'weight', 'link_weight');
+    $query->fields('m');
     $query->condition('ml.mlid', $mlid);
     if ($item = $query->execute()->fetchAssoc()) {
+      $item['weight'] = $item['link_weight'];
       _menu_link_translate($item);
       return $item;
     }
@@ -2890,42 +2947,8 @@ function menu_link_save(&$item) {
     }
   }
 
-  // If we have a parent link ID, we use it to inherit 'menu_name' and 'depth'.
-  if (isset($item['plid'])) {
-    if ($item['plid']) {
-      $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc();
-    }
-    // If the parent link ID is zero, then this link lives at the top-level.
-    else {
-      $parent = FALSE;
-    }
-  }
-  // Otherwise, try to find a valid parent link for this link.
-  else {
-    $query = db_select('menu_links');
-    // Only links derived from router items should have module == 'system', and
-    // we want to find the parent even if it's in a different menu.
-    if ($item['module'] == 'system') {
-      $query->condition('module', 'system');
-    }
-    // We always respect the link's 'menu_name'; inheritance for router items is
-    // ensured in _menu_router_build().
-    $query->condition('menu_name', $item['menu_name']);
-
-    // Find the parent - it must be unique.
-    $parent_path = $item['link_path'];
-    do {
-      $parent = FALSE;
-      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
-      $new_query = clone $query;
-      $new_query->condition('link_path', $parent_path);
-      // Only valid if we get a unique result.
-      if ($new_query->countQuery()->execute()->fetchField() == 1) {
-        $parent = $new_query->fields('menu_links')->execute()->fetchAssoc();
-      }
-    } while ($parent === FALSE && $parent_path);
-  }
-  // If a parent link was found, assign it and derive its menu.
+  // Try to find a parent link. If found, assign it and derive its menu.
+  $parent = _menu_link_find_parent($item);
   if (!empty($parent['mlid'])) {
     $item['plid'] = $parent['mlid'];
     $item['menu_name'] = $parent['menu_name'];
@@ -3046,6 +3069,78 @@ function menu_link_save(&$item) {
   return $item['mlid'];
 }
 
+/**
+ * Find a possible parent for a given menu link.
+ *
+ * Because the parent of a given link might not exist anymore in the database,
+ * we apply a set of heuristics to determine a proper parent:
+ *
+ *  - use the passed parent link if specified and existing.
+ *  - else, use the first existing link down the previous link hierarchy
+ *  - else, for system menu links (derived from hook_menu()), reparent
+ *    based on the path hierarchy.
+ *
+ * @param $menu_link
+ *   A menu link.
+ * @return
+ *   A menu link structure of the possible parent or FALSE if no valid parent
+ *   has been found.
+ */
+function _menu_link_find_parent($menu_link) {
+  $parent = FALSE;
+
+  // This item is explicitely top-level, skip the rest of the parenting.
+  if (isset($menu_link['plid']) && empty($menu_link['plid'])) {
+    return $parent;
+  }
+
+  // If we have a parent link ID, try to use that.
+  $candidates = array();
+  if (isset($menu_link['plid'])) {
+    $candidates[] = $menu_link['plid'];
+  }
+
+  // Else, if we have a link hierarchy try to find a valid parent in there.
+  if (!empty($menu_link['depth']) && $menu_link['depth'] > 1) {
+    for ($depth = $menu_link['depth'] - 1; $depth >= 1; $depth--) {
+      $candidates[] = $menu_link['p' . $depth];
+    }
+  }
+
+  foreach ($candidates as $mlid) {
+    $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc();
+    if ($parent) {
+      return $parent;
+    }
+  }
+
+  // If everything else failed, try to derive the parent from the path
+  // hierarchy. This only makes sense for links derived from menu router
+  // items (ie. from hook_menu()).
+  if ($menu_link['module'] == 'system') {
+    $query = db_select('menu_links');
+    $query->condition('module', 'system');
+    // We always respect the link's 'menu_name'; inheritance for router items is
+    // ensured in _menu_router_build().
+    $query->condition('menu_name', $menu_link['menu_name']);
+
+    // Find the parent - it must be unique.
+    $parent_path = $menu_link['link_path'];
+    do {
+      $parent = FALSE;
+      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
+      $new_query = clone $query;
+      $new_query->condition('link_path', $parent_path);
+      // Only valid if we get a unique result.
+      if ($new_query->countQuery()->execute()->fetchField() == 1) {
+        $parent = $new_query->fields('menu_links')->execute()->fetchAssoc();
+      }
+    } while ($parent === FALSE && $parent_path);
+  }
+
+  return $parent;
+}
+
 /**
  * Helper function to clear the page and block caches at most twice per page load.
  */
@@ -3305,8 +3400,7 @@ function _menu_router_build($callbacks) {
       $match = FALSE;
       // Look for wildcards in the form allowed to be used in PHP functions,
       // because we are using these to construct the load function names.
-      // See http://php.net/manual/en/language.functions.php for reference.
-      if (preg_match('/^%(|[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$/', $part, $matches)) {
+      if (preg_match('/^%(|' . DRUPAL_PHP_FUNCTION_PATTERN . ')$/', $part, $matches)) {
         if (empty($matches[1])) {
           $match = TRUE;
           $load_functions[$k] = NULL;
@@ -3342,7 +3436,7 @@ function _menu_router_build($callbacks) {
       $fit = (1 << $number_parts) - 1;
     }
     $masks[$fit] = 1;
-    $item['load_functions'] = empty($load_functions) ? '' : serialize($load_functions);
+    $item['_load_functions'] = $load_functions;
     $item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions);
     $item += array(
       'title' => '',
@@ -3445,6 +3539,21 @@ function _menu_router_build($callbacks) {
             $item['theme arguments'] = $parent['theme arguments'];
           }
         }
+        // Same for load arguments: if a loader doesn't have any explict
+        // arguments, try to find arguments in the parent.
+        if (!isset($item['load arguments'])) {
+          foreach ($item['_load_functions'] as $k => $function) {
+            // This loader doesn't have any explict arguments...
+            if (!is_array($function)) {
+              // ... check the parent for a loader at the same position
+              // using the same function name and defining arguments...
+              if (isset($parent['_load_functions'][$k]) && is_array($parent['_load_functions'][$k]) && key($parent['_load_functions'][$k]) === $function) {
+                // ... and inherit the arguments on the child.
+                $item['_load_functions'][$k] = $parent['_load_functions'][$k];
+              }
+            }
+          }
+        }
       }
     }
     if (!isset($item['access callback']) && isset($item['access arguments'])) {
@@ -3458,6 +3567,7 @@ function _menu_router_build($callbacks) {
       $item['access callback'] = intval($item['access callback']);
     }
 
+    $item['load_functions'] = empty($item['_load_functions']) ? '' : serialize($item['_load_functions']);
     $item += array(
       'access arguments' => array(),
       'access callback' => '',
diff --git a/includes/module.inc b/includes/module.inc
index e75fdc7d6617c19a34d8bd98ef820c0b4fc006b3..1ae5583de30001f3241ebe5d075031b7674b4f6d 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: module.inc,v 1.202 2010/10/03 02:04:55 dries Exp $
+// $Id: module.inc,v 1.209 2010/11/27 20:41:38 dries Exp $
 
 /**
  * @file
@@ -32,27 +32,39 @@ function module_load_all($bootstrap = FALSE) {
 
 
 /**
- * Collect a list of all loaded modules. During the bootstrap, return only
- * vital modules. See bootstrap.inc
+ * Returns a list of currently active modules.
+ *
+ * Usually, this returns a list of all enabled modules. When called early on in
+ * the bootstrap, it will return a list of vital modules only (those needed to
+ * generate cached pages).
+ *
+ * All parameters to this function are optional and should generally not be
+ * changed from their defaults.
  *
  * @param $refresh
- *   Whether to force the module list to be regenerated (such as after the
- *   administrator has changed the system settings).
- * @param $bootstrap
- *   Whether to return the reduced set of modules loaded in "bootstrap mode"
- *   for cached pages. See bootstrap.inc.
+ *   (optional) Whether to force the module list to be regenerated (such as
+ *   after the administrator has changed the system settings). Defaults to
+ *   FALSE.
+ * @param $bootstrap_refresh
+ *   (optional) When $refresh is TRUE, setting $bootstrap_refresh to TRUE forces
+ *   the module list to be regenerated using the reduced set of modules loaded
+ *   in "bootstrap mode" for cached pages. Otherwise, setting $refresh to TRUE
+ *   generates the complete list of enabled modules.
  * @param $sort
- *   By default, modules are ordered by weight and module name. Set this option
- *   to TRUE to return a module list ordered only by module name.
+ *   (optional) By default, modules are ordered by weight and module name. Set
+ *   this option to TRUE to return a module list ordered only by module name.
  * @param $fixed_list
- *   (Optional) Override the module list with the given modules. Stays until the
- *   next call with $refresh = TRUE.
+ *   (optional) If an array of module names is provided, this will override the
+ *   module list with the given set of modules. This will persist until the next
+ *   call with $refresh set to TRUE or with a new $fixed_list passed in. This
+ *   parameter is primarily intended for internal use (e.g., in install.php and
+ *   update.php).
  *
  * @return
- *   An associative array whose keys and values are the names of all loaded
- *   modules.
+ *   An associative array whose keys and values are the names of the modules in
+ *   the list.
  */
-function module_list($refresh = FALSE, $bootstrap = FALSE, $sort = FALSE, $fixed_list = NULL) {
+function module_list($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE, $fixed_list = NULL) {
   static $list = array(), $sorted_list;
 
   if (empty($list) || $refresh || $fixed_list) {
@@ -70,7 +82,7 @@ function module_list($refresh = FALSE, $bootstrap = FALSE, $sort = FALSE, $fixed
         // data.
         drupal_static_reset('system_list');
       }
-      if ($bootstrap) {
+      if ($bootstrap_refresh) {
         $list = system_list('bootstrap');
       }
       else {
@@ -181,6 +193,7 @@ function system_list($type) {
  */
 function system_list_reset() {
   drupal_static_reset('system_list');
+  drupal_static_reset('system_rebuild_module_data');
   drupal_static_reset('list_themes');
   cache_clear_all('bootstrap_modules', 'cache_bootstrap');
   cache_clear_all('system_list', 'cache_bootstrap');
@@ -235,12 +248,18 @@ function module_exists($module) {
 
 /**
  * Load a module's installation hooks.
+ *
+ * @param $module
+ *   The name of the module (without the .module extension).
+ *
+ * @return
+ *   The name of the module's install file, if successful; FALSE otherwise.
  */
 function module_load_install($module) {
   // Make sure the installation API is available
   include_once DRUPAL_ROOT . '/includes/install.inc';
 
-  module_load_include('install', $module);
+  return module_load_include('install', $module);
 }
 
 /**
@@ -264,11 +283,14 @@ function module_load_install($module) {
  * @param $module
  *   The module to which the include file belongs.
  * @param $name
- *   Optionally, specify the base file name (without the $type extension).
- *   If not set, $module is used.
+ *   (optional) The base file name (without the $type extension). If omitted,
+ *   $module is used; i.e., resulting in "$module.$type" by default.
+ *
+ * @return
+ *   The name of the included file, if successful; FALSE otherwise.
  */
 function module_load_include($type, $module, $name = NULL) {
-  if (empty($name)) {
+  if (!isset($name)) {
     $name = $module;
   }
 
@@ -466,6 +488,7 @@ function module_disable($module_list, $disable_dependents = TRUE) {
     // Create an associative array with weights as values.
     $module_list = array_flip(array_values($module_list));
 
+    $profile = drupal_get_profile();
     while (list($module) = each($module_list)) {
       if (!isset($module_data[$module]) || !$module_data[$module]->status) {
         // This module doesn't exist or is already disabled, skip it.
@@ -477,7 +500,7 @@ function module_disable($module_list, $disable_dependents = TRUE) {
       // Add dependent modules to the list, with a placeholder weight.
       // The new modules will be processed as the while loop continues.
       foreach ($module_data[$module]->required_by as $dependent => $dependent_data) {
-        if (!isset($module_list[$dependent]) && !strstr($module_data[$dependent]->filename, '.profile')) {
+        if (!isset($module_list[$dependent]) && $dependent != $profile) {
           $module_list[$dependent] = 0;
         }
       }
@@ -569,7 +592,20 @@ function module_disable($module_list, $disable_dependents = TRUE) {
  *   implemented in that module.
  */
 function module_hook($module, $hook) {
-  return function_exists($module . '_' . $hook);
+  $function = $module . '_' . $hook;
+  if (function_exists($function)) {
+    return TRUE;
+  }
+  // If the hook implementation does not exist, check whether it may live in an
+  // optional include file registered via hook_hook_info().
+  $hook_info = module_hook_info();
+  if (isset($hook_info[$hook]['group'])) {
+    module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
+    if (function_exists($function)) {
+      return TRUE;
+    }
+  }
+  return FALSE;
 }
 
 /**
@@ -637,7 +673,9 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
     $list = module_list(FALSE, FALSE, $sort);
     foreach ($list as $module) {
       $include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
-      if (module_hook($module, $hook)) {
+      // Since module_hook() may needlessly try to load the include file again,
+      // function_exists() is used directly here.
+      if (function_exists($module . '_' . $hook)) {
         $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
       }
     }
@@ -655,9 +693,11 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
         module_load_include('inc', $module, "$module.$group");
       }
       // It is possible that a module removed a hook implementation without the
-      // implementations cache being rebuilt yet, so we check module_hook() on
-      // each request to avoid undefined function errors.
-      if (!module_hook($module, $hook)) {
+      // implementations cache being rebuilt yet, so we check whether the
+      // function exists on each request to avoid undefined function errors.
+      // Since module_hook() may needlessly try to load the include file again,
+      // function_exists() is used directly here.
+      if (!function_exists($module . '_' . $hook)) {
         // Clear out the stale implementation from the cache and force a cache
         // refresh to forget about no longer existing hook implementations.
         unset($implementations[$hook][$module]);
@@ -673,9 +713,17 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
  * Retrieve a list of what hooks are explicitly declared.
  */
 function module_hook_info() {
-  $hook_info = &drupal_static(__FUNCTION__, array());
+  // This function is indirectly invoked from bootstrap_invoke_all(), in which
+  // case common.inc, subsystems, and modules are not loaded yet, so it does not
+  // make sense to support hook groups resp. lazy-loaded include files prior to
+  // full bootstrap.
+  if (drupal_bootstrap(NULL, FALSE) != DRUPAL_BOOTSTRAP_FULL) {
+    return array();
+  }
+  $hook_info = &drupal_static(__FUNCTION__);
 
-  if (empty($hook_info)) {
+  if (!isset($hook_info)) {
+    $hook_info = array();
     $cache = cache_get('hook_info', 'cache_bootstrap');
     if ($cache === FALSE) {
       // Rebuild the cache and save it.
@@ -745,6 +793,7 @@ function module_invoke() {
     return call_user_func_array($module . '_' . $hook, $args);
   }
 }
+
 /**
  * Invoke a hook in all enabled modules that implement it.
  *
@@ -786,7 +835,7 @@ function module_invoke_all() {
  * Array of modules required by core.
  */
 function drupal_required_modules() {
-  $files = drupal_system_listing('/\.info$/', 'modules', 'name', 0);
+  $files = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'modules', 'name', 0);
   $required = array();
 
   // An install profile is required and one must always be loaded.
diff --git a/includes/pager.inc b/includes/pager.inc
index 22b3affeb20c358ccc00eb4d10d025a81e4352f4..1269298614adcc594d15cc6d9437ca991c336169 100644
--- a/includes/pager.inc
+++ b/includes/pager.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: pager.inc,v 1.85 2010/10/08 05:07:53 webchick Exp $
+// $Id: pager.inc,v 1.87 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -20,7 +20,7 @@ class PagerDefault extends SelectQueryExtender {
    *
    * @var int
    */
-  static protected $maxElement = 0;
+  static $maxElement = 0;
 
   /**
    * The number of elements per page to allow.
@@ -431,8 +431,9 @@ function theme_pager($variables) {
 /**
  * @defgroup pagerpieces Pager pieces
  * @{
- * Use these pieces to construct your own custom pagers in your theme. Note that
- * you should NOT modify this file to customize your pager.
+ * Use these pieces to construct your own custom pagers in your theme.
+ *
+ * Note that you should NOT modify this file to customize your pager.
  */
 
 /**
diff --git a/includes/password.inc b/includes/password.inc
index 364729b9ab49e1ec6afaf4877c17d919ade56f36..131ca63f619e9b34a3225a0a249030fd1358bb1f 100644
--- a/includes/password.inc
+++ b/includes/password.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: password.inc,v 1.8 2010/05/04 15:47:03 dries Exp $
+// $Id: password.inc,v 1.9 2010/12/18 00:56:18 dries Exp $
 
 /**
  * @file
@@ -99,17 +99,37 @@ function _password_base64_encode($input, $count) {
  */
 function _password_generate_salt($count_log2) {
   $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.
+  // Ensure that $count_log2 is within set bounds.
+  $count_log2 = _password_enforce_log2_boundaries($count_log2);
   // We encode the final log2 iteration count in base 64.
   $itoa64 = _password_itoa64();
-  $output .= $itoa64[min($count_log2, DRUPAL_MAX_HASH_COUNT)];
+  $output .= $itoa64[$count_log2];
   // 6 bytes is the standard salt for a portable phpass hash.
   $output .= _password_base64_encode(drupal_random_bytes(6), 6);
   return $output;
 }
 
+/**
+ * Ensures that $count_log2 is within set bounds.
+ *
+ * @param $count_log2
+ *   Integer that determines the number of iterations used in the hashing
+ *   process. A larger value is more secure, but takes more time to complete.
+ *
+ * @return
+ *   Integer within set bounds that is closest to $count_log2.
+ */
+function _password_enforce_log2_boundaries($count_log2) {
+  if ($count_log2 < DRUPAL_MIN_HASH_COUNT) {
+    return DRUPAL_MIN_HASH_COUNT;
+  }
+  elseif ($count_log2 > DRUPAL_MAX_HASH_COUNT) {
+    return DRUPAL_MAX_HASH_COUNT;
+  }
+
+  return (int) $count_log2;
+}
+
 /**
  * Hash a password using a secure stretched hash.
  *
@@ -261,7 +281,9 @@ function user_needs_new_hash($account) {
   if ((substr($account->pass, 0, 3) != '$S$') || (strlen($account->pass) != DRUPAL_HASH_LENGTH)) {
     return TRUE;
   }
+  // Ensure that $count_log2 is within set bounds.
+  $count_log2 = _password_enforce_log2_boundaries(variable_get('password_count_log2', DRUPAL_HASH_COUNT));
   // Check whether the iteration count used differs from the standard number.
-  return (_password_get_count_log2($account->pass) != variable_get('password_count_log2', DRUPAL_HASH_COUNT));
+  return (_password_get_count_log2($account->pass) !== $count_log2);
 }
 
diff --git a/includes/path.inc b/includes/path.inc
index 139542e1b314a17648a44813bcc982b569c13e48..1825c1ab565d1720ce391e65f1750a11487ca4f2 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.inc,v 1.71 2010/08/09 00:13:06 dries Exp $
+// $Id: path.inc,v 1.72 2010/11/30 01:05:24 dries Exp $
 
 /**
  * @file
@@ -94,13 +94,30 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) {
         if ($cached = cache_get($cid, 'cache_path')) {
           $cache['system_paths'] = $cached->data;
           // Now fetch the aliases corresponding to these system paths.
-          // We order by ASC and overwrite array keys to ensure the correct
-          // alias is used when there are multiple aliases per path.
-          $cache['map'][$path_language] = db_query("SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC", array(
+          $args = array(
             ':system' => $cache['system_paths'],
             ':language' => $path_language,
             ':language_none' => LANGUAGE_NONE,
-          ))->fetchAllKeyed();
+          );
+          // Always get the language-specific alias before the language-neutral
+          // one. For example 'de' is less than 'und' so the order needs to be
+          // ASC, while 'xx-lolspeak' is more than 'und' so the order needs to
+          // be DESC. We also order by pid ASC so that fetchAllKeyed() returns
+          // the most recently created alias for each source. Subsequent queries
+          // using fetchField() must use pid DESC to have the same effect.
+          // For performance reasons, the query builder is not used here.
+          if ($path_language == LANGUAGE_NONE) {
+            // Prevent PDO from complaining about a token the query doesn't use.
+            unset($args[':language']);
+            $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language = :language_none ORDER BY pid ASC', $args);
+          }
+          elseif ($path_language < LANGUAGE_NONE) {
+            $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC', $args);
+          }
+          else {
+            $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language DESC, pid ASC', $args);
+          }
+          $cache['map'][$path_language] = $result->fetchAllKeyed();
           // Keep a record of paths with no alias to avoid querying twice.
           $cache['no_aliases'][$path_language] = array_flip(array_diff_key($cache['system_paths'], array_keys($cache['map'][$path_language])));
         }
@@ -117,12 +134,22 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) {
       }
       // For system paths which were not cached, query aliases individually.
       elseif (!isset($cache['no_aliases'][$path_language][$path])) {
-        // Get the most fitting result falling back with alias without language
-        $alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
+        $args = array(
           ':source' => $path,
           ':language' => $path_language,
           ':language_none' => LANGUAGE_NONE,
-        ))->fetchField();
+        );
+        // See the queries above.
+        if ($path_language == LANGUAGE_NONE) {
+          unset($args[':language']);
+          $alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language = :language_none ORDER BY pid DESC", $args)->fetchField();
+        }
+        elseif ($path_language > LANGUAGE_NONE) {
+          $alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", $args)->fetchField();
+        }
+        else {
+          $alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language ASC, pid DESC", $args)->fetchField();
+        }
         $cache['map'][$path_language][$path] = $alias;
         return $alias;
       }
@@ -133,12 +160,23 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) {
       // Look for the value $path within the cached $map
       $source = FALSE;
       if (!isset($cache['map'][$path_language]) || !($source = array_search($path, $cache['map'][$path_language]))) {
-        // Get the most fitting result falling back with alias without language
-        if ($source = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
-                     ':alias' => $path,
-                     ':language' => $path_language,
-                     ':language_none' => LANGUAGE_NONE))
-            ->fetchField()) {
+        $args = array(
+          ':alias' => $path,
+          ':language' => $path_language,
+          ':language_none' => LANGUAGE_NONE,
+        );
+        // See the queries above.
+        if ($path_language == LANGUAGE_NONE) {
+          unset($args[':language']);
+          $result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language = :language_none ORDER BY pid DESC", $args);
+        }
+        elseif ($path_language > LANGUAGE_NONE) {
+          $result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", $args);
+        }
+        else {
+          $result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language ASC, pid DESC", $args);
+        }
+        if ($source = $result->fetchField()) {
           $cache['map'][$path_language][$source] = $path;
         }
         else {
diff --git a/includes/session.inc b/includes/session.inc
index 71e3f6c4ac8ed15d18aa0d48322c30b0c305f474..d86d72e00ea568ce9edaa16394e395b163114bbd 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: session.inc,v 1.90 2010/10/15 04:15:41 webchick Exp $
+// $Id: session.inc,v 1.92 2010/11/13 17:40:09 webchick Exp $
 
 /**
  * @file
@@ -180,21 +180,23 @@ function _drupal_session_write($sid, $value) {
         'timestamp' => REQUEST_TIME,
       );
 
-      // The "secure pages" setting allows a site to simultaneously use both
-      // secure and insecure session cookies. If enabled and both cookies are
-      // presented then use both keys. If not enabled but on HTTPS then use the
-      // PHP session id as 'ssid'. If on HTTP then use the PHP session id as
-      // 'sid'.
+      // Use the session ID as 'sid' and an empty string as 'ssid' by default.
+      // _drupal_session_read() does not allow empty strings so that's a safe
+      // default.
+      $key = array('sid' => $sid, 'ssid' => '');
+      // On HTTPS connections, use the session ID as both 'sid' and 'ssid'.
       if ($is_https) {
         $key['ssid'] = $sid;
-        $insecure_session_name = substr(session_name(), 1);
-        if (variable_get('https', FALSE) && isset($_COOKIE[$insecure_session_name])) {
-          $key['sid'] = $_COOKIE[$insecure_session_name];
+        // The "secure pages" setting allows a site to simultaneously use both
+        // secure and insecure session cookies. If enabled and both cookies are
+        // presented then use both keys.
+        if (variable_get('https', FALSE)) {
+          $insecure_session_name = substr(session_name(), 1);
+          if (isset($_COOKIE[$insecure_session_name])) {
+            $key['sid'] = $_COOKIE[$insecure_session_name];
+          }
         }
       }
-      else {
-        $key['sid'] = $sid;
-      }
 
       db_merge('sessions')
         ->key($key)
@@ -234,7 +236,9 @@ function drupal_session_initialize() {
 
   session_set_save_handler('_drupal_session_open', '_drupal_session_close', '_drupal_session_read', '_drupal_session_write', '_drupal_session_destroy', '_drupal_session_garbage_collection');
 
-  if (isset($_COOKIE[session_name()]) || ($is_https && variable_get('https', FALSE) && isset($_COOKIE[substr(session_name(), 1)]))) {
+  // We use !empty() in the following check to ensure that blank session IDs
+  // are not valid.
+  if (!empty($_COOKIE[session_name()]) || ($is_https && variable_get('https', FALSE) && !empty($_COOKIE[substr(session_name(), 1)]))) {
     // If a session cookie exists, initialize the session. Otherwise the
     // session is only started on demand in drupal_session_commit(), making
     // anonymous users not use a session cookie unless something is stored in
diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc
index c97f86bbc2dd5c2b3ab0dbd8d83a4b8cf4b6f878..081941b0b3f9efb1ede7dee5b8c9d435438e1a02 100644
--- a/includes/stream_wrappers.inc
+++ b/includes/stream_wrappers.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: stream_wrappers.inc,v 1.21 2010/10/21 12:09:41 dries Exp $
+// $Id: stream_wrappers.inc,v 1.22 2010/12/30 22:33:03 webchick Exp $
 
 /**
  * @file
@@ -671,11 +671,14 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
    */
   public function url_stat($uri, $flags) {
     $this->uri = $uri;
-    if ($flags & STREAM_URL_STAT_QUIET) {
-      return @stat($this->getLocalPath());
+    $path = $this->getLocalPath();
+    // Suppress warnings if requested or if the file or directory does not
+    // exist. This is consistent with PHP's plain filesystem stream wrapper.
+    if ($flags & STREAM_URL_STAT_QUIET || !file_exists($path)) {
+      return @stat($path);
     }
     else {
-      return stat($this->getLocalPath());
+      return stat($path);
     }
   }
 
diff --git a/includes/tablesort.inc b/includes/tablesort.inc
index 1242e8a87bb7eada78f7c521390b0ee994ab1a69..327738b5391e04bda70d0bee71162836357be439 100644
--- a/includes/tablesort.inc
+++ b/includes/tablesort.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: tablesort.inc,v 1.59 2010/10/15 04:34:15 webchick Exp $
+// $Id: tablesort.inc,v 1.61 2010/12/17 19:28:13 webchick Exp $
 
 /**
  * @file
@@ -80,7 +80,7 @@ class TableSort extends SelectQueryExtender {
     // User has not specified a sort. Use default if specified; otherwise use "asc".
     else {
       foreach ($this->header as $header) {
-        if (is_array($header) && array_key_exists('sort', $header)) {
+        if (is_array($header) && isset($header['sort'])) {
           return $header['sort'];
         }
       }
@@ -279,7 +279,7 @@ function tablesort_get_sort($headers) {
   // User has not specified a sort. Use default if specified; otherwise use "asc".
   else {
     foreach ($headers as $header) {
-      if (is_array($header) && array_key_exists('sort', $header)) {
+      if (isset($header['sort'])) {
         return $header['sort'];
       }
     }
diff --git a/includes/theme.inc b/includes/theme.inc
index 9db13f650b84afb3f9577c6d9e68ccd593affc48..0a82a8ad04c17aadb1cefcf93c16c1338b9d139a 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.inc,v 1.620 2010/10/21 19:31:39 dries Exp $
+// $Id: theme.inc,v 1.627 2011/01/03 08:02:11 webchick Exp $
 
 /**
  * @file
@@ -402,7 +402,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
       // that themes don't need to specify this information, since the module
       // that registered the theme hook already has.
       foreach (array('variables', 'render element', 'pattern', 'base hook') as $key) {
-        if (!array_key_exists($key, $info) && isset($cache[$hook][$key])) {
+        if (!isset($info[$key]) && isset($cache[$hook][$key])) {
           $result[$hook][$key] = $cache[$hook][$key];
         }
       }
@@ -1375,32 +1375,34 @@ function theme_link($variables) {
  *
  * @param $variables
  *   An associative array containing:
- *   - links: A keyed array of links to be themed. The key for each link is used
- *     as its css class. Each link should be itself an array, with the following
- *     keys:
- *     - title: the link text
- *     - href: the link URL. If omitted, the 'title' is shown as a plain text
+ *   - links: An associative array of links to be themed. The key for each link
+ *     is used as its css class. Each link should be itself an array, with the
+ *     following elements:
+ *     - title: The link text.
+ *     - href: The link URL. If omitted, the 'title' is shown as a plain text
  *       item in the links list.
- *     - html: (optional) set this to TRUE if 'title' is HTML so it will be
- *       escaped.
- *     Array items are passed on to the l() function's $options parameter when
- *     creating the link.
- *   - attributes: A keyed array of attributes.
- *   - heading: An optional keyed array or a string for a heading to precede the
- *     links. When using an array the following keys can be used:
- *     - text: the heading text
- *     - level: the heading level (e.g. 'h2', 'h3')
- *     - class: (optional) an array of the CSS classes for the heading
+ *     - html: (optional) Whether or not 'title' is HTML. If set, the title
+ *       will not be passed through check_plain().
+ *     - attributes: (optional) Attributes for the anchor, or for the <span> tag
+ *       used in its place if no 'href' is supplied.
+ *     If the 'href' element is supplied, the entire link array is passed to l()
+ *     as its $options parameter.
+ *   - attributes: A keyed array of attributes for the UL containing the
+ *     list of links.
+ *   - heading: (optional) A heading to precede the links. May be an associative
+ *     array or a string. If it's an array, it can have the following elements:
+ *     - text: The heading text.
+ *     - level: The heading level (e.g. 'h2', 'h3').
+ *     - class: (optional) An array of the CSS classes for the heading.
  *     When using a string it will be used as the text of the heading and the
- *     level will default to 'h2'.
- *
- *     Headings should be used on navigation menus and any list of links that
- *     consistently appears on multiple pages. To make the heading invisible
- *     use the 'element-invisible' CSS class. Do not use 'display:none', which
- *     removes it from screen-readers and assistive technology. Headings allow
- *     screen-reader and keyboard only users to navigate to or skip the links.
- *     See http://juicystudio.com/article/screen-readers-display-none.php
- *     and http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
+ *     level will default to 'h2'. Headings should be used on navigation menus
+ *     and any list of links that consistently appears on multiple pages. To
+ *     make the heading invisible use the 'element-invisible' CSS class. Do not
+ *     use 'display:none', which removes it from screen-readers and assistive
+ *     technology. Headings allow screen-reader and keyboard only users to
+ *     navigate to or skip the links. See
+ *     http://juicystudio.com/article/screen-readers-display-none.php and
+ *     http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
  */
 function theme_links($variables) {
   $links = $variables['links'];
@@ -1864,7 +1866,8 @@ function theme_more_help_link($variables) {
  *
  * @param $variables
  *   An associative array containing:
- *   - url: The url of the feed.
+ *   - url: An internal system path or a fully qualified external URL of the
+ *     feed.
  *   - title: A descriptive title of the feed.
  */
 function theme_feed_icon($variables) {
@@ -2192,14 +2195,18 @@ function template_preprocess_html(&$variables) {
 
   // Construct page title.
   if (drupal_get_title()) {
-    $head_title = array(strip_tags(drupal_get_title()), check_plain(variable_get('site_name', 'Drupal')));
+    $head_title = array(
+      'title' => strip_tags(drupal_get_title()),
+      'name' => check_plain(variable_get('site_name', 'Drupal')),
+    );
   }
   else {
-    $head_title = array(check_plain(variable_get('site_name', 'Drupal')));
+    $head_title = array('name' => check_plain(variable_get('site_name', 'Drupal')));
     if (variable_get('site_slogan', '')) {
-      $head_title[] = filter_xss_admin(variable_get('site_slogan', ''));
+      $head_title['slogan'] = filter_xss_admin(variable_get('site_slogan', ''));
     }
   }
+  $variables['head_title_array'] = $head_title;
   $variables['head_title'] = implode(' | ', $head_title);
 
   // Populate the page template suggestions.
@@ -2250,13 +2257,12 @@ function template_preprocess_page(&$variables) {
   $variables['language']          = $GLOBALS['language'];
   $variables['language']->dir     = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
   $variables['logo']              = theme_get_setting('logo');
-  $variables['messages']          = $variables['show_messages'] ? theme('status_messages') : '';
   $variables['main_menu']         = theme_get_setting('toggle_main_menu') ? menu_main_menu() : array();
   $variables['secondary_menu']    = theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() : array();
   $variables['action_links']      = menu_local_actions();
   $variables['site_name']         = (theme_get_setting('toggle_name') ? filter_xss_admin(variable_get('site_name', 'Drupal')) : '');
   $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : '');
-  $variables['tabs']              = theme('menu_local_tasks');
+  $variables['tabs']              = menu_local_tabs();
 
   if ($node = menu_get_object()) {
     $variables['node'] = $node;
@@ -2288,6 +2294,12 @@ function template_process_page(&$variables) {
   if (!isset($variables['title'])) {
     $variables['title'] = drupal_get_title();
   }
+
+  // Generate messages last in order to capture as many as possible for the
+  // current page.
+  if (!isset($variables['messages'])) {
+    $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : '';
+  }
 }
 
 /**
@@ -2352,8 +2364,19 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
   $suggestions = array();
   $prefix = $base;
   foreach ($args as $arg) {
-    // Remove slashes or null per SA-CORE-2009-003.
-    $arg = str_replace(array("/", "\\", "\0"), '', $arg);
+    // Remove slashes or null per SA-CORE-2009-003 and change - (hyphen) to _
+    // (underscore).
+    //
+    // When we discover templates in @see drupal_find_theme_templates,
+    // hyphens (-) are converted to underscores (_) before the theme hook
+    // is registered. We do this because the hyphens used for delimiters
+    // in hook suggestions cannot be used in the function names of the
+    // associated preprocess functions. Any page templates designed to be used
+    // on paths that contain a hyphen are also registered with these hyphens
+    // converted to underscores so here we must convert any hyphens in path
+    // arguments to underscores here before fetching theme hook suggestions
+    // to ensure the templates are appropriately recognized.
+    $arg = str_replace(array("/", "\\", "\0", '-'), array('', '', '', '_'), $arg);
     // The percent acts as a wildcard for numeric arguments since
     // asterisks are not valid filename characters on many filesystems.
     if (is_numeric($arg)) {
@@ -2417,18 +2440,22 @@ function template_preprocess_maintenance_page(&$variables) {
 
   // Construct page title
   if (drupal_get_title()) {
-    $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
+    $head_title = array(
+      'title' => strip_tags(drupal_get_title()),
+      'name' => variable_get('site_name', 'Drupal'),
+    );
   }
   else {
-    $head_title = array(variable_get('site_name', 'Drupal'));
+    $head_title = array('name' => variable_get('site_name', 'Drupal'));
     if (variable_get('site_slogan', '')) {
-      $head_title[] = variable_get('site_slogan', '');
+      $head_title['slogan'] = variable_get('site_slogan', '');
     }
   }
 
   // set the default language if necessary
   $language = isset($GLOBALS['language']) ? $GLOBALS['language'] : language_default();
 
+  $variables['head_title_array']  = $head_title;
   $variables['head_title']        = implode(' | ', $head_title);
   $variables['base_path']         = base_path();
   $variables['front_page']        = url();
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index 56d8b5487ae377aaed949a006ce4b4886410fff3..f165f993ebd9614d3531fba98c7da50109668993 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.maintenance.inc,v 1.67 2010/09/19 18:10:41 dries Exp $
+// $Id: theme.maintenance.inc,v 1.71 2010/11/29 04:45:10 webchick Exp $
 
 /**
  * @file
@@ -41,7 +41,6 @@ function _drupal_maintenance_theme() {
     // to work. See _drupal_log_error().
     if (!class_exists('Database', FALSE)) {
       require_once DRUPAL_ROOT . '/includes/database/database.inc';
-      spl_autoload_register('db_autoload');
     }
 
     // We use the default theme as the maintenance theme. If a default theme
@@ -176,13 +175,14 @@ function theme_authorize_report($variables) {
   if (!empty($messages)) {
     $output .= '<div id="authorize-results">';
     foreach ($messages as $heading => $logs) {
-      $output .= '<h3>' . check_plain($heading) . '</h3>';
+      $items = array();
       foreach ($logs as $number => $log_message) {
         if ($number === '#abort') {
           continue;
         }
-        $output .= theme('authorize_message', array('message' => $log_message['message'], 'success' => $log_message['success']));
+        $items[] = theme('authorize_message', array('message' => $log_message['message'], 'success' => $log_message['success']));
       }
+      $output .= theme('item_list',  array('items' => $items, 'title' => $heading));
     }
     $output .= '</div>';
   }
@@ -200,14 +200,13 @@ function theme_authorize_report($variables) {
  * @ingroup themeable
  */
 function theme_authorize_message($variables) {
-  $output = '';
   $message = $variables['message'];
   $success = $variables['success'];
   if ($success) {
-    $output .= '<li class="success">' . $message . '</li>';
+    $item = array('data' => $message, 'class' => array('success'));
   }
   else {
-    $output .= '<li class="failure"><strong>' . t('Failed') . ':</strong> ' . $message . '</li>';
+    $item = array('data' => '<strong>' . $message . '</strong>', 'class' => array('failure'));
   }
-  return $output;
+  return $item;
 }
diff --git a/includes/unicode.inc b/includes/unicode.inc
index fb7f51c40bc88456a46f6593e33d84d1c71a944e..12b801081bc3f4183da5a9bbb08d98673b6f2f0b 100644
--- a/includes/unicode.inc
+++ b/includes/unicode.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: unicode.inc,v 1.47 2010/08/11 10:58:22 dries Exp $
+// $Id: unicode.inc,v 1.48 2010/12/28 18:21:58 webchick Exp $
 
 /**
  * Indicates an error during check for PHP unicode support.
@@ -288,12 +288,12 @@ function drupal_truncate_bytes($string, $len) {
  *   If TRUE, attempt to truncate on a word boundary. Word boundaries are
  *   spaces, punctuation, and Unicode characters used as word boundaries in
  *   non-Latin languages; see PREG_CLASS_UNICODE_WORD_BOUNDARY for more
- *   information.  If a word boundary cannot be found that would make the length
+ *   information. If a word boundary cannot be found that would make the length
  *   of the returned string fall within length guidelines (see parameters
- *   $max_return_length and $min_wordsafe_length), word boundaries are ignored.
+ *   $max_length and $min_wordsafe_length), word boundaries are ignored.
  * @param $add_ellipsis
  *   If TRUE, add t('...') to the end of the truncated string (defaults to
- *   FALSE). The string length will still fall within $max_return_length.
+ *   FALSE). The string length will still fall within $max_length.
  * @param $min_wordsafe_length
  *   If $wordsafe is TRUE, the minimum acceptable length for truncation (before
  *   adding an ellipsis, if $add_ellipsis is TRUE). Has no effect if $wordsafe
diff --git a/includes/update.inc b/includes/update.inc
index 2e0bbce5bfc9026f92cb1ba3d08caf7581b0238b..3932bb88beb9e7c60f43179b0ef5e407eed0e82b 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.inc,v 1.78 2010/10/22 15:41:45 webchick Exp $
+// $Id: update.inc,v 1.87 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -62,8 +62,7 @@ function update_check_incompatibility($name, $type = 'module') {
   if (!isset($file)
       || !isset($file->info['core'])
       || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY
-      || version_compare(phpversion(), $file->info['php']) < 0
-      || ($type == 'module' && empty($file->info['files']))) {
+      || version_compare(phpversion(), $file->info['php']) < 0) {
     return TRUE;
   }
   return FALSE;
@@ -158,7 +157,30 @@ function update_prepare_d7_bootstrap() {
         'description' => $has_required_schema ? '' : 'Please update your Drupal 6 installation to the most recent version before attempting to upgrade to Drupal 7',
       ),
     );
+
+    // Make sure that the database environment is properly set up.
+    try {
+      db_run_tasks(db_driver());
+    }
+    catch (DatabaseTaskException $e) {
+      $requirements['database tasks'] = array(
+        'title' => 'Database environment',
+        'value' => 'There is a problem with your database environment',
+        'severity' => REQUIREMENT_ERROR,
+        'description' => $e->getMessage(),
+      );
+    }
+
     update_extra_requirements($requirements);
+
+    // Allow a D6 session to work, since the upgrade has not been performed yet.
+    $d6_session_name = update_get_d6_session_name();
+    if (!empty($_COOKIE[$d6_session_name])) {
+      // Set the current sid to the one found in the D6 cookie.
+      $sid = $_COOKIE[$d6_session_name];
+      $_COOKIE[session_name()] = $sid;
+      session_id($sid);
+    }
   }
 
   // Create the registry tables.
@@ -189,7 +211,7 @@ function update_prepare_d7_bootstrap() {
     db_create_table('registry_file', $schema['registry_file']);
   }
 
-  // Older versions of Drupal 6 do not include the semaphore table, which is 
+  // Older versions of Drupal 6 do not include the semaphore table, which is
   // required to bootstrap, so we add it now so that we can bootstrap and
   // provide a reasonable error message.
   if (!db_table_exists('semaphore')) {
@@ -469,6 +491,9 @@ function update_fix_d7_requirements() {
     db_add_index('system', 'system_list', array('weight', 'name'));
 
     // Add the cache_path table.
+    if (db_table_exists('cache_path')) {
+      db_drop_table('cache_path');
+    }
     require_once('./modules/system/system.install');
     $schema['cache_path'] = system_schema_cache_7054();
     $schema['cache_path']['description'] = 'Cache table used for path alias lookups.';
@@ -696,15 +721,22 @@ function update_fix_d7_requirements() {
       db_add_field('locales_source', 'context', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'description' => 'The context this string applies to.'));
     }
 
-    // Rename 'site_offline_message' variable to 'maintenance_mode_message'.
+    // Rename 'site_offline_message' variable to 'maintenance_mode_message'
+    // and 'site_offline' variable to 'maintenance_mode'.
     // Old variable is removed in update for system.module, see
     // system_update_7036().
     if ($message = variable_get('site_offline_message', NULL)) {
       variable_set('maintenance_mode_message', $message);
     }
+    // Old variable is removed in update for system.module, see
+    // system_update_7069().
+    $site_offline = variable_get('site_offline', -1);
+    if ($site_offline != -1) {
+      variable_set('maintenance_mode', $site_offline);
+    }
 
     // Add ssid column and index.
-    db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by PHP's Session API.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
+    db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
     db_add_index('sessions', 'ssid', array('ssid'));
     // Drop existing primary key.
     db_drop_primary_key('sessions');
@@ -821,6 +853,37 @@ function update_parse_db_url($db_url, $db_prefix) {
   return $databases;
 }
 
+/**
+ * Constructs a session name compatible with a D6 environment.
+ *
+ * @return
+ *   D6-compatible session name string.
+ *
+ * @see drupal_settings_initialize()
+ */
+function update_get_d6_session_name() {
+  global $base_url, $cookie_domain;
+  $cookie_secure = ini_get('session.cookie_secure');
+
+  // If a custom cookie domain is set in settings.php, that variable forms
+  // the basis of the session name. Re-compute the D7 hashing method to find
+  // out if $cookie_domain was used as the session name.
+  if (($cookie_secure ? 'SSESS' : 'SESS') . substr(hash('sha256', $cookie_domain), 0, 32) == session_name()) {
+    $session_name = $cookie_domain;
+  }
+  else {
+    // Otherwise use $base_url as session name, without the protocol
+    // to use the same session identifiers across http and https.
+    list( , $session_name) = explode('://', $base_url, 2);
+  }
+
+  if ($cookie_secure) {
+    $session_name .= 'SSL';
+  }
+
+  return 'SESS' . md5($session_name);
+}
+
 /**
  * Perform one update and store the results for display on finished page.
  *
@@ -885,7 +948,8 @@ function update_do_one($module, $number, $dependency_map, &$context) {
 
       require_once DRUPAL_ROOT . '/includes/errors.inc';
       $variables = _drupal_decode_exception($e);
-      $ret['#abort'] = array('success' => FALSE, 'query' => t('%type: %message in %function (line %line of %file).', $variables));
+      // The exception message is run through check_plain() by _drupal_decode_exception().
+      $ret['#abort'] = array('success' => FALSE, 'query' => t('%type: !message in %function (line %line of %file).', $variables));
     }
   }
 
@@ -1386,7 +1450,7 @@ function update_retrieve_dependencies() {
 }
 
 /**
- * @defgroup update-api-6.x-to-7.x Update versions of API functions.
+ * @defgroup update-api-6.x-to-7.x Update versions of API functions
  * @{
  * Functions similar to normal API function but not firing hooks.
  *
diff --git a/includes/updater.inc b/includes/updater.inc
index 669458b9731b68a1128433c9f25be874dc3a6bd2..ebdd2bc32772dbba38134a31278fb786a7a8d6a4 100644
--- a/includes/updater.inc
+++ b/includes/updater.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: updater.inc,v 1.7 2010/09/01 20:08:17 dries Exp $
+// $Id: updater.inc,v 1.8 2011/01/02 23:28:16 webchick Exp $
 
 /**
  * @file
@@ -137,7 +137,7 @@ class Updater {
    *   Path to the info file.
    */
   public static function findInfoFile($directory) {
-    $info_files = file_scan_directory($directory, '/.*\.info/');
+    $info_files = file_scan_directory($directory, '/.*\.info$/');
     if (!$info_files) {
       return FALSE;
     }
@@ -179,8 +179,11 @@ class Updater {
   public static function getProjectTitle($directory) {
     $info_file = self::findInfoFile($directory);
     $info = drupal_parse_info_file($info_file);
-    if (!$info) {
-      throw new UpdaterException(t('Unable to parse info file.'));
+    if (empty($info)) {
+      throw new UpdaterException(t('Unable to parse info file: %info_file.', array('%info_file' => $info_file)));
+    }
+    if (empty($info['name'])) {
+      throw new UpdaterException(t("The info file (%info_file) does not define a 'name' attribute.", array('%info_file' => $info_file)));
     }
     return $info['name'];
   }
diff --git a/misc/ajax.js b/misc/ajax.js
index dbbce837d3a59bbb9cc7d4949e73e1fea6a784f8..f20d563a2f20ee5b5ff721d4be28839db1486800 100644
--- a/misc/ajax.js
+++ b/misc/ajax.js
@@ -1,4 +1,4 @@
-// $Id: ajax.js,v 1.25 2010/10/21 19:31:39 dries Exp $
+// $Id: ajax.js,v 1.35 2010/12/23 04:26:31 webchick Exp $
 (function ($) {
 
 /**
@@ -25,6 +25,9 @@ Drupal.behaviors.AJAX = {
       if (!$('#' + base + '.ajax-processed').length) {
         var element_settings = settings.ajax[base];
 
+        if (typeof element_settings.selector == 'undefined') {
+          element_settings.selector = '#' + base;
+        }
         $(element_settings.selector).each(function () {
           element_settings.element = this;
           Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
@@ -37,6 +40,8 @@ Drupal.behaviors.AJAX = {
     // Bind AJAX behaviors to all items showing the class.
     $('.use-ajax:not(.ajax-processed)').addClass('ajax-processed').each(function () {
       var element_settings = {};
+      // Clicked links look better with the throbber than the progress bar.
+      element_settings.progress = { 'type': 'throbber' };
 
       // For anchor tags, these will go to the target of the anchor rather
       // than the usual location.
@@ -98,11 +103,11 @@ Drupal.ajax = function (base, element, element_settings) {
     keypress: true,
     selector: '#' + base,
     effect: 'none',
-    speed: 'slow',
+    speed: 'none',
     method: 'replaceWith',
     progress: {
-      type: 'bar',
-      message: 'Please wait...'
+      type: 'throbber',
+      message: Drupal.t('Please wait...')
     },
     submit: {
       'js': true
@@ -112,10 +117,20 @@ Drupal.ajax = function (base, element, element_settings) {
   $.extend(this, defaults, element_settings);
 
   this.element = element;
+  this.element_settings = element_settings;
 
   // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
   // the server detect when it needs to degrade gracefully.
-  this.url = element_settings.url.replace(/\/nojs(\/|$)/g, '/ajax$1');
+  // There are five scenarios to check for:
+  // 1. /nojs/
+  // 2. /nojs$ - The end of a URL string.
+  // 3. /nojs? - Followed by a query (with clean URLs enabled).
+  //      E.g.: path/nojs?destination=foobar
+  // 4. /nojs& - Followed by a query (without clean URLs enabled).
+  //      E.g.: ?q=path/nojs&destination=foobar
+  // 5. /nojs# - Followed by a fragment.
+  //      E.g.: path/nojs#myfragment
+  this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1');
   this.wrapper = '#' + element_settings.wrapper;
 
   // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
@@ -137,6 +152,10 @@ Drupal.ajax = function (base, element, element_settings) {
       ajax.ajaxing = true;
       return ajax.beforeSubmit(form_values, element_settings, options);
     },
+    beforeSend: function (xmlhttprequest, options) {
+      ajax.ajaxing = true;
+      return ajax.beforeSend(xmlhttprequest, options);
+    },
     success: function (response, status) {
       // Sanity check for browser support (object expected).
       // When using iFrame uploads, responses must be returned as a string.
@@ -156,35 +175,8 @@ Drupal.ajax = function (base, element, element_settings) {
   };
 
   // Bind the ajaxSubmit function to the element event.
-  $(this.element).bind(element_settings.event, function () {
-    if (ajax.ajaxing) {
-      return false;
-    }
-
-    try {
-      if (ajax.form) {
-        // If setClick is set, we must set this to ensure that the button's
-        // value is passed.
-        if (ajax.setClick) {
-          // Mark the clicked button. 'form.clk' is a special variable for
-          // ajaxSubmit that tells the system which element got clicked to
-          // trigger the submit. Without it there would be no 'op' or
-          // equivalent.
-          this.form.clk = this;
-        }
-
-        ajax.form.ajaxSubmit(ajax.options);
-      }
-      else {
-        ajax.beforeSerialize(ajax.element, ajax.options);
-        $.ajax(ajax.options);
-      }
-    }
-    catch (e) {
-      alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message);
-    }
-
-    return false;
+  $(ajax.element).bind(element_settings.event, function (event) {
+    return ajax.eventResponse(this, event);
   });
 
   // If necessary, enable keyboard submission so that AJAX behaviors
@@ -192,19 +184,93 @@ Drupal.ajax = function (base, element, element_settings) {
   // action.
   if (element_settings.keypress) {
     $(element_settings.element).keypress(function (event) {
-      // Detect enter key.
-      if (event.keyCode == 13) {
-        $(element_settings.element).trigger(element_settings.event);
-        return false;
-      }
+      return ajax.keypressResponse(this, event);
     });
   }
 };
 
+/**
+ * Handle a key press.
+ *
+ * The AJAX object will, if instructed, bind to a key press response. This
+ * will test to see if the key press is valid to trigger this event and
+ * if it is, trigger it for us and prevent other keypresses from triggering.
+ * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13
+ * and 32. RETURN is often used to submit a form when in a textfield, and 
+ * SPACE is often used to activate an element without submitting. 
+ */
+Drupal.ajax.prototype.keypressResponse = function (element, event) {
+  // Create a synonym for this to reduce code confusion.
+  var ajax = this;
+
+  // Detect enter key and space bar and allow the standard response for them,
+  // except for form elements of type 'text' and 'textarea', where the 
+  // spacebar activation causes inappropriate activation if #ajax['keypress'] is 
+  // TRUE. On a text-type widget a space should always be a space.
+  if (event.which == 13 || (event.which == 32 && element.type != 'text' && element.type != 'textarea')) {
+    $(ajax.element_settings.element).trigger(ajax.element_settings.event);
+    return false;
+  }
+};
+
+/**
+ * Handle an event that triggers an AJAX response.
+ *
+ * When an event that triggers an AJAX response happens, this method will
+ * perform the actual AJAX call. It is bound to the event using
+ * bind() in the constructor, and it uses the options specified on the
+ * ajax object.
+ */
+Drupal.ajax.prototype.eventResponse = function (element, event) {
+  // Create a synonym for this to reduce code confusion.
+  var ajax = this;
+
+  // Do not perform another ajax command if one is already in progress.
+  if (ajax.ajaxing) {
+    return false;
+  }
+
+  try {
+    if (ajax.form) {
+      // If setClick is set, we must set this to ensure that the button's
+      // value is passed.
+      if (ajax.setClick) {
+        // Mark the clicked button. 'form.clk' is a special variable for
+        // ajaxSubmit that tells the system which element got clicked to
+        // trigger the submit. Without it there would be no 'op' or
+        // equivalent.
+        element.form.clk = element;
+      }
+
+      ajax.form.ajaxSubmit(ajax.options);
+    }
+    else {
+      ajax.beforeSerialize(ajax.element, ajax.options);
+      $.ajax(ajax.options);
+    }
+  }
+  catch (e) {
+    // Unset the ajax.ajaxing flag here because it won't be unset during
+    // the complete response.
+    ajax.ajaxing = false;
+    alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message);
+  }
+
+  // For radio/checkbox, allow the default event. On IE, this means letting
+  // it actually check the box.
+  if (typeof element.type != 'undefined' && (element.type == 'checkbox' || element.type == 'radio')) {
+    return true;
+  }
+  else {
+    return false;
+  }
+
+};
+
 /**
  * Handler for the form serialization.
  *
- * Runs before the beforeSubmit() handler (see below), and unlike that one, runs
+ * Runs before the beforeSend() handler (see below), and unlike that one, runs
  * before field data is collected.
  */
 Drupal.ajax.prototype.beforeSerialize = function (element, options) {
@@ -241,10 +307,31 @@ Drupal.ajax.prototype.beforeSerialize = function (element, options) {
 };
 
 /**
- * Handler for the form redirection submission.
+ * Modify form values prior to form submission.
  */
 Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
-  // Disable the element that received the change.
+  // This function is left empty to make it simple to override for modules
+  // that wish to add functionality here.
+}
+
+/**
+ * Prepare the AJAX request before it is sent.
+ */
+Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) {
+  // Disable the element that received the change to prevent user interface
+  // interaction while the AJAX request is in progress. ajax.ajaxing prevents
+  // the element from triggering a new request, but does not prevent the user
+  // from changing its value.
+  // Forms without file inputs are already serialized before this function is
+  // called. Forms with file inputs use an IFRAME to perform a POST request
+  // similar to a browser, so disabled elements are not contained in the
+  // submitted values. Therefore, we manually add the element's value to
+  // options.extraData.
+  var v = $.fieldValue(this.element);
+  if (v !== null) {
+    options.extraData = options.extraData || {};
+    options.extraData[this.element.name] = v;
+  }
   $(this.element).addClass('progress-disabled').attr('disabled', true);
 
   // Insert progressbar or throbber.
@@ -280,7 +367,7 @@ Drupal.ajax.prototype.success = function (response, status) {
   if (this.progress.object) {
     this.progress.object.stopMonitoring();
   }
-  $(this.element).removeClass('progress-disabled').attr('disabled', false);
+  $(this.element).removeClass('progress-disabled').removeAttr('disabled');
 
   Drupal.freezeHeight();
 
@@ -348,7 +435,7 @@ Drupal.ajax.prototype.error = function (response, uri) {
   // Undo hide.
   $(this.wrapper).show();
   // Re-enable the element.
-  $(this.element).removeClass('progress-disabled').attr('disabled', false);
+  $(this.element).removeClass('progress-disabled').removeAttr('disabled');
   // Reattach behaviors, if they were detached in beforeSerialize().
   if (this.form) {
     var settings = response.settings || this.settings || Drupal.settings;
@@ -486,6 +573,14 @@ Drupal.ajax.prototype.commands = {
     $(response.selector).data(response.name, response.value);
   },
 
+  /**
+   * Command to apply a jQuery method.
+   */
+  invoke: function (ajax, response, status) {
+    var $element = $(response.selector);
+    $element[response.method].apply($element, response.arguments);
+  },
+
   /**
    * Command to restripe a table.
    */
diff --git a/misc/autocomplete.js b/misc/autocomplete.js
index b05f64f644f75c3c97373fe4b5bb859c8ad60bf9..57f3be67fb8449ceb9c49e12253b8492e0cca0b3 100644
--- a/misc/autocomplete.js
+++ b/misc/autocomplete.js
@@ -1,4 +1,4 @@
-// $Id: autocomplete.js,v 1.37 2010/06/13 05:31:02 dries Exp $
+// $Id: autocomplete.js,v 1.39 2010/11/20 07:49:56 webchick Exp $
 (function ($) {
 
 /**
@@ -12,10 +12,16 @@ Drupal.behaviors.autocomplete = {
       if (!acdb[uri]) {
         acdb[uri] = new Drupal.ACDB(uri);
       }
-      var input = $('#' + this.id.substr(0, this.id.length - 13))
-        .attr('autocomplete', 'OFF')[0];
-      $(input.form).submit(Drupal.autocompleteSubmit);
-      new Drupal.jsAC(input, acdb[uri]);
+      var $input = $('#' + this.id.substr(0, this.id.length - 13))
+        .attr('autocomplete', 'OFF')
+        .attr('aria-autocomplete', 'list');
+      $($input[0].form).submit(Drupal.autocompleteSubmit);
+      $input.parent()
+        .attr('role', 'application')
+        .append($('<span class="element-invisible" aria-live="assertive"></span>')
+          .attr('id', $input.attr('id') + '-autocomplete-aria-live')
+        );
+      new Drupal.jsAC($input, acdb[uri]);
     });
   }
 };
@@ -33,12 +39,13 @@ Drupal.autocompleteSubmit = function () {
 /**
  * An AutoComplete object.
  */
-Drupal.jsAC = function (input, db) {
+Drupal.jsAC = function ($input, db) {
   var ac = this;
-  this.input = input;
+  this.input = $input[0];
+  this.ariaLive = $('#' + $input.attr('id') + '-autocomplete-aria-live');
   this.db = db;
 
-  $(this.input)
+  $input
     .keydown(function (event) { return ac.onkeydown(this, event); })
     .keyup(function (event) { ac.onkeyup(this, event); })
     .blur(function () { ac.hidePopup(); ac.db.cancel(); });
@@ -141,6 +148,7 @@ Drupal.jsAC.prototype.highlight = function (node) {
   }
   $(node).addClass('selected');
   this.selected = node;
+  $(this.ariaLive).html($(this.selected).html());
 };
 
 /**
@@ -149,6 +157,7 @@ Drupal.jsAC.prototype.highlight = function (node) {
 Drupal.jsAC.prototype.unhighlight = function (node) {
   $(node).removeClass('selected');
   this.selected = false;
+  $(this.ariaLive).empty();
 };
 
 /**
@@ -166,12 +175,15 @@ Drupal.jsAC.prototype.hidePopup = function (keycode) {
     $(popup).fadeOut('fast', function () { $(popup).remove(); });
   }
   this.selected = false;
+  $(this.ariaLive).empty();
 };
 
 /**
  * Positions the suggestions popup and starts a search.
  */
 Drupal.jsAC.prototype.populatePopup = function () {
+  var $input = $(this.input);
+  var position = $input.position();
   // Show popup.
   if (this.popup) {
     $(this.popup).remove();
@@ -180,11 +192,12 @@ Drupal.jsAC.prototype.populatePopup = function () {
   this.popup = $('<div id="autocomplete"></div>')[0];
   this.popup.owner = this;
   $(this.popup).css({
-    marginTop: this.input.offsetHeight + 'px',
-    width: (this.input.offsetWidth - 4) + 'px',
+    top: parseInt(position.top + this.input.offsetHeight, 10) + 'px',
+    left: parseInt(position.left, 10) + 'px',
+    width: $input.innerWidth() + 'px',
     display: 'none'
   });
-  $(this.input).before(this.popup);
+  $input.before(this.popup);
 
   // Do search.
   this.db.owner = this;
@@ -217,6 +230,7 @@ Drupal.jsAC.prototype.found = function (matches) {
   if (this.popup) {
     if (ul.children().size()) {
       $(this.popup).empty().append(ul).show();
+      $(this.ariaLive).html(Drupal.t('Autocomplete popup'));
     }
     else {
       $(this.popup).css({ visibility: 'hidden' });
@@ -229,6 +243,7 @@ Drupal.jsAC.prototype.setStatus = function (status) {
   switch (status) {
     case 'begin':
       $(this.input).addClass('throbbing');
+      $(this.ariaLive).html(Drupal.t('Searching for matches...'));
       break;
     case 'cancel':
     case 'error':
diff --git a/misc/configure.png b/misc/configure.png
index 93b034fcfccf244d9d541940387f0c47d79db256..ff200dc1dc75a9c6a6432bb4a89e76fb8978613c 100755
Binary files a/misc/configure.png and b/misc/configure.png differ
diff --git a/misc/draggable.png b/misc/draggable.png
index bbfbf9302063bf8a4cca7f2db99f1acf2eb553ec..93d20d60d504041b9841a35d285d4ba5eaaf6167 100644
Binary files a/misc/draggable.png and b/misc/draggable.png differ
diff --git a/misc/drupal.js b/misc/drupal.js
index 7d0d0688f77e5f110f372ea9514e1f78831805d0..9695f5dad8ce0379309271c3fc10fcfed5aa6029 100644
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -1,4 +1,4 @@
-// $Id: drupal.js,v 1.69 2010/07/28 01:38:28 dries Exp $
+// $Id: drupal.js,v 1.72 2011/01/01 04:11:39 webchick Exp $
 
 var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
 
@@ -114,11 +114,14 @@ Drupal.detachBehaviors = function (context, settings, trigger) {
  * Encode special characters in a plain-text string for display as HTML.
  */
 Drupal.checkPlain = function (str) {
+  var character, regex,
+      replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
   str = String(str);
-  var replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
-  for (var character in replace) {
-    var regex = new RegExp(character, 'g');
-    str = str.replace(regex, replace[character]);
+  for (character in replace) {
+    if (replace.hasOwnProperty(character)) {
+      regex = new RegExp(character, 'g');
+      str = str.replace(regex, replace[character]);
+    }
   }
   return str;
 };
@@ -228,8 +231,9 @@ Drupal.formatPlural = function (count, singular, plural, args) {
  * theme does not provide an override function, the generic theme function is
  * called.
  *
- * For example, to retrieve the HTML that is output by theme_placeholder(text),
- * call Drupal.theme('placeholder', text).
+ * For example, to retrieve the HTML for text that should be emphasized and
+ * displayed as a placeholder inside a sentence, call
+ * Drupal.theme('placeholder', text).
  *
  * @param func
  *   The name of the theme function to call.
@@ -240,9 +244,7 @@ Drupal.formatPlural = function (count, singular, plural, args) {
  *   but also a complex object.
  */
 Drupal.theme = function (func) {
-  for (var i = 1, args = []; i < arguments.length; i++) {
-    args.push(arguments[i]);
-  }
+  var args = Array.prototype.slice.apply(arguments, [1]);
 
   return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
 };
@@ -312,8 +314,22 @@ Drupal.ajaxError = function (xmlhttp, uri) {
   }
   statusCode += "\n" + Drupal.t("Debugging information follows.");
   pathText = "\n" + Drupal.t("Path: !uri", {'!uri': uri} );
-  statusText = xmlhttp.statusText ? ("\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)})) : "";
-  responseText = xmlhttp.responseText ? ("\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText)})) : "";
+  statusText = '';
+  // In some cases, when statusCode == 0, xmlhttp.statusText may not be defined.
+  // Unfortunately, testing for it with typeof, etc, doesn't seem to catch that
+  // and the test causes an exception. So we need to catch the exception here.
+  try {
+    statusText = "\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)});
+  }
+  catch (e) {}
+
+  responseText = '';
+  // Again, we don't have a way to know for sure whether accessing
+  // xmlhttp.responseText is going to throw an exception. So we'll catch it.
+  try {
+    responseText = "\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText) } );
+  } catch (e) {}
+
   // Make the responseText more readable by stripping HTML tags and newlines.
   responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi,"");
   responseText = responseText.replace(/[\n]+\s+/g,"\n");
@@ -364,7 +380,7 @@ Drupal.theme.prototype = {
    *   The formatted text (html).
    */
   placeholder: function (str) {
-    return '<em>' + Drupal.checkPlain(str) + '</em>';
+    return '<em class="placeholder">' + Drupal.checkPlain(str) + '</em>';
   }
 };
 
diff --git a/misc/druplicon.png b/misc/druplicon.png
index 6680e660f364d181cbdbe1c4855b97e2cef3be24..3b49a4ce78dc8b1ce754706f400b3b61a99857d1 100644
Binary files a/misc/druplicon.png and b/misc/druplicon.png differ
diff --git a/misc/forum-closed.png b/misc/forum-closed.png
deleted file mode 100644
index 509fca6bc2f27467a664a343f6bf8a840dc4aff0..0000000000000000000000000000000000000000
Binary files a/misc/forum-closed.png and /dev/null differ
diff --git a/misc/forum-default.png b/misc/forum-default.png
deleted file mode 100644
index 4b84633c5186152a6cab29baf17a1bbf44e8f9fa..0000000000000000000000000000000000000000
Binary files a/misc/forum-default.png and /dev/null differ
diff --git a/misc/forum-hot-new.png b/misc/forum-hot-new.png
deleted file mode 100644
index 418c6135365908226c5da47a46cf61c2877ea3e7..0000000000000000000000000000000000000000
Binary files a/misc/forum-hot-new.png and /dev/null differ
diff --git a/misc/forum-hot.png b/misc/forum-hot.png
deleted file mode 100644
index 7e3991a67243690506c61d6f3fd8c2eb64fab98c..0000000000000000000000000000000000000000
Binary files a/misc/forum-hot.png and /dev/null differ
diff --git a/misc/forum-icons.png b/misc/forum-icons.png
new file mode 100644
index 0000000000000000000000000000000000000000..e291de672522d40458ed4b6fc15f58372c778afa
Binary files /dev/null and b/misc/forum-icons.png differ
diff --git a/misc/forum-new.png b/misc/forum-new.png
deleted file mode 100644
index cce21e627c05f2aa944f20c39a3c7cc0d83c0787..0000000000000000000000000000000000000000
Binary files a/misc/forum-new.png and /dev/null differ
diff --git a/misc/forum-sticky.png b/misc/forum-sticky.png
deleted file mode 100644
index 2b463c302442baf5c1eddea769664dce4d7baa0a..0000000000000000000000000000000000000000
Binary files a/misc/forum-sticky.png and /dev/null differ
diff --git a/misc/help.png b/misc/help.png
index a703ec4f7a9b541ddb9ad1609fe1f3fa66ab4904..dcc5cac7956f6e1d0733695af8db4cffcef90d84 100644
Binary files a/misc/help.png and b/misc/help.png differ
diff --git a/misc/jquery.form.js b/misc/jquery.form.js
index 9dc10bfd6fc0b18afe803e175c0c2975b30cf358..8457185ff937948bdb44688679b270feed01150b 100644
--- a/misc/jquery.form.js
+++ b/misc/jquery.form.js
@@ -1,13 +1,13 @@
-// $Id: jquery.form.js,v 1.5 2010/01/18 17:04:10 dries Exp $
+// $Id: jquery.form.js,v 1.7 2011/01/03 02:11:27 webchick Exp $
 
-/*
+/*!
  * jQuery Form Plugin
- * version: 2.36 (07-NOV-2009)
- * @requires jQuery v1.2.6 or later
+ * version: 2.52 (07-DEC-2010)
+ * @requires jQuery v1.3.2 or later
  *
  * Examples and documentation at: http://malsup.com/jquery/form/
  * Dual licensed under the MIT and GPL licenses:
  *   http://www.opensource.org/licenses/mit-license.php
  *   http://www.gnu.org/licenses/gpl.html
  */
-;(function($){$.fn.ajaxSubmit=function(options){if(!this.length){log("ajaxSubmit: skipping submit process - no element selected");return this;}if(typeof options=="function"){options={success:options};}options=$.extend({url:this.attr("action")||window.location.toString(),type:this.attr("method")||"GET"},options||{});var veto={};this.trigger("form-pre-serialize",[this,options,veto]);if(veto.veto){log("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this;}if(options.beforeSerialize&&options.beforeSerialize(this,options)===false){log("ajaxSubmit: submit aborted via beforeSerialize callback");return this;}var a=this.formToArray(options.semantic);if(options.data){options.extraData=options.data;for(var n in options.data){if(options.data[n] instanceof Array){for(var k in options.data[n]){a.push({name:n,value:options.data[n][k]});}}else{a.push({name:n,value:options.data[n]});}}}if(options.beforeSubmit&&options.beforeSubmit(a,this,options)===false){log("ajaxSubmit: submit aborted via beforeSubmit callback");return this;}this.trigger("form-submit-validate",[a,this,options,veto]);if(veto.veto){log("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this;}var q=$.param(a);if(options.type.toUpperCase()=="GET"){options.url+=(options.url.indexOf("?")>=0?"&":"?")+q;options.data=null;}else{options.data=q;}var $form=this,callbacks=[];if(options.resetForm){callbacks.push(function(){$form.resetForm();});}if(options.clearForm){callbacks.push(function(){$form.clearForm();});}if(!options.dataType&&options.target){var oldSuccess=options.success||function(){};callbacks.push(function(data){$(options.target).html(data).each(oldSuccess,arguments);});}else{if(options.success){callbacks.push(options.success);}}options.success=function(data,status){for(var i=0,max=callbacks.length;i<max;i++){callbacks[i].apply(options,[data,status,$form]);}};var files=$("input:file",this).fieldValue();var found=false;for(var j=0;j<files.length;j++){if(files[j]){found=true;}}if(options.iframe||found){if(options.closeKeepAlive){$.get(options.closeKeepAlive,fileUpload);}else{fileUpload();}}else{$.ajax(options);}this.trigger("form-submit-notify",[this,options]);return this;function fileUpload(){var form=$form[0];if($(":input[name=submit]",form).length){alert('Error: Form elements must not be named "submit".');return;}var opts=$.extend({},$.ajaxSettings,options);var s=jQuery.extend(true,{},$.extend(true,{},$.ajaxSettings),opts);var id="jqFormIO"+(new Date().getTime());var $io=$('<iframe id="'+id+'" name="'+id+'" src="about:blank" />');var io=$io[0];$io.css({position:"absolute",top:"-1000px",left:"-1000px"});var xhr={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(){this.aborted=1;$io.attr("src","about:blank");}};var g=opts.global;if(g&&!$.active++){$.event.trigger("ajaxStart");}if(g){$.event.trigger("ajaxSend",[xhr,opts]);}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;return;}if(xhr.aborted){return;}var cbInvoked=0;var timedOut=0;var sub=form.clk;if(sub){var n=sub.name;if(n&&!sub.disabled){options.extraData=options.extraData||{};options.extraData[n]=sub.value;if(sub.type=="image"){options.extraData[name+".x"]=form.clk_x;options.extraData[name+".y"]=form.clk_y;}}}setTimeout(function(){var t=$form.attr("target"),a=$form.attr("action");form.setAttribute("target",id);if(form.getAttribute("method")!="POST"){form.setAttribute("method","POST");}if(form.getAttribute("action")!=opts.url){form.setAttribute("action",opts.url);}if(!options.skipEncodingOverride){$form.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"});}if(opts.timeout){setTimeout(function(){timedOut=true;cb();},opts.timeout);}var extraInputs=[];try{if(options.extraData){for(var n in options.extraData){extraInputs.push($('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />').appendTo(form)[0]);}}$io.appendTo("body");io.attachEvent?io.attachEvent("onload",cb):io.addEventListener("load",cb,false);form.submit();}finally{form.setAttribute("action",a);t?form.setAttribute("target",t):$form.removeAttr("target");$(extraInputs).remove();}},10);var nullCheckFlag=0;function cb(){if(cbInvoked++){return;}var mike=opts;var mike2=xhr;io.detachEvent?io.detachEvent("onload",cb):io.removeEventListener("load",cb,false);var ok=true;try{if(timedOut){throw"timeout";}var data,doc;doc=io.contentWindow?io.contentWindow.document:io.contentDocument?io.contentDocument:io.document;if((doc.body==null||doc.body.innerHTML=="")&&!nullCheckFlag){nullCheckFlag=1;cbInvoked--;setTimeout(cb,100);return;}xhr.responseText=doc.body?doc.body.innerHTML:null;xhr.responseXML=doc.XMLDocument?doc.XMLDocument:doc;xhr.getResponseHeader=function(header){var headers={"content-type":opts.dataType};return headers[header];};if(opts.dataType=="json"||opts.dataType=="script"){var ta=doc.getElementsByTagName("textarea")[0];xhr.responseText=ta?ta.value:xhr.responseText;}else{if(opts.dataType=="xml"&&!xhr.responseXML&&xhr.responseText!=null){xhr.responseXML=toXml(xhr.responseText);}}data=$.httpData(xhr,opts.dataType);}catch(e){ok=false;$.handleError(opts,xhr,"error",e);}if(ok){opts.success(data,"success");if(g){$.event.trigger("ajaxSuccess",[xhr,opts]);}}if(g){$.event.trigger("ajaxComplete",[xhr,opts]);}if(g&&!--$.active){$.event.trigger("ajaxStop");}if(opts.complete){opts.complete(xhr,ok?"success":"error");}setTimeout(function(){$io.remove();xhr.responseXML=null;},100);}function toXml(s,doc){if(window.ActiveXObject){doc=new ActiveXObject("Microsoft.XMLDOM");doc.async="false";doc.loadXML(s);}else{doc=(new DOMParser()).parseFromString(s,"text/xml");}return(doc&&doc.documentElement&&doc.documentElement.tagName!="parsererror")?doc:null;}}};$.fn.ajaxForm=function(options){return this.ajaxFormUnbind().bind("submit.form-plugin",function(){$(this).ajaxSubmit(options);return false;}).each(function(){$(":submit,input:image",this).bind("click.form-plugin",function(e){var form=this.form;form.clk=this;if(this.type=="image"){if(e.offsetX!=undefined){form.clk_x=e.offsetX;form.clk_y=e.offsetY;}else{if(typeof $.fn.offset=="function"){var offset=$(this).offset();form.clk_x=e.pageX-offset.left;form.clk_y=e.pageY-offset.top;}else{form.clk_x=e.pageX-this.offsetLeft;form.clk_y=e.pageY-this.offsetTop;}}}setTimeout(function(){form.clk=form.clk_x=form.clk_y=null;},10);});});};$.fn.ajaxFormUnbind=function(){this.unbind("submit.form-plugin");return this.each(function(){$(":submit,input:image",this).unbind("click.form-plugin");});};$.fn.formToArray=function(semantic){var a=[];if(this.length==0){return a;}var form=this[0];var els=semantic?form.getElementsByTagName("*"):form.elements;if(!els){return a;}for(var i=0,max=els.length;i<max;i++){var el=els[i];var n=el.name;if(!n){continue;}if(semantic&&form.clk&&el.type=="image"){if(!el.disabled&&form.clk==el){a.push({name:n+".x",value:form.clk_x},{name:n+".y",value:form.clk_y});}continue;}var v=$.fieldValue(el,true);if(v&&v.constructor==Array){for(var j=0,jmax=v.length;j<jmax;j++){a.push({name:n,value:v[j]});}}else{if(v!==null&&typeof v!="undefined"){a.push({name:n,value:v});}}}if(!semantic&&form.clk){var inputs=form.getElementsByTagName("input");for(var i=0,max=inputs.length;i<max;i++){var input=inputs[i];var n=input.name;if(n&&!input.disabled&&input.type=="image"&&form.clk==input){a.push({name:n+".x",value:form.clk_x},{name:n+".y",value:form.clk_y});}}}return a;};$.fn.formSerialize=function(semantic){return $.param(this.formToArray(semantic));};$.fn.fieldSerialize=function(successful){var a=[];this.each(function(){var n=this.name;if(!n){return;}var v=$.fieldValue(this,successful);if(v&&v.constructor==Array){for(var i=0,max=v.length;i<max;i++){a.push({name:n,value:v[i]});}}else{if(v!==null&&typeof v!="undefined"){a.push({name:this.name,value:v});}}});return $.param(a);};$.fn.fieldValue=function(successful){for(var val=[],i=0,max=this.length;i<max;i++){var el=this[i];var v=$.fieldValue(el,successful);if(v===null||typeof v=="undefined"||(v.constructor==Array&&!v.length)){continue;}v.constructor==Array?$.merge(val,v):val.push(v);}return val;};$.fieldValue=function(el,successful){var n=el.name,t=el.type,tag=el.tagName.toLowerCase();if(typeof successful=="undefined"){successful=true;}if(successful&&(!n||el.disabled||t=="reset"||t=="button"||(t=="checkbox"||t=="radio")&&!el.checked||(t=="submit"||t=="image")&&el.form&&el.form.clk!=el||tag=="select"&&el.selectedIndex==-1)){return null;}if(tag=="select"){var index=el.selectedIndex;if(index<0){return null;}var a=[],ops=el.options;var one=(t=="select-one");var max=(one?index+1:ops.length);for(var i=(one?index:0);i<max;i++){var op=ops[i];if(op.selected){var v=op.value;if(!v){v=(op.attributes&&op.attributes.value&&!(op.attributes.value.specified))?op.text:op.value;}if(one){return v;}a.push(v);}}return a;}return el.value;};$.fn.clearForm=function(){return this.each(function(){$("input,select,textarea",this).clearFields();});};$.fn.clearFields=$.fn.clearInputs=function(){return this.each(function(){var t=this.type,tag=this.tagName.toLowerCase();if(t=="text"||t=="password"||tag=="textarea"){this.value="";}else{if(t=="checkbox"||t=="radio"){this.checked=false;}else{if(tag=="select"){this.selectedIndex=-1;}}}});};$.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset();}});};$.fn.enable=function(b){if(b==undefined){b=true;}return this.each(function(){this.disabled=!b;});};$.fn.selected=function(select){if(select==undefined){select=true;}return this.each(function(){var t=this.type;if(t=="checkbox"||t=="radio"){this.checked=select;}else{if(this.tagName.toLowerCase()=="option"){var $sel=$(this).parent("select");if(select&&$sel[0]&&$sel[0].type=="select-one"){$sel.find("option").selected(false);}this.selected=select;}}});};function log(){if($.fn.ajaxSubmit.debug&&window.console&&window.console.log){window.console.log("[jquery.form] "+Array.prototype.join.call(arguments,""));}}})(jQuery);
\ No newline at end of file
+;(function(b){function q(){if(b.fn.ajaxSubmit.debug){var a="[jquery.form] "+Array.prototype.join.call(arguments,"");if(window.console&&window.console.log)window.console.log(a);else window.opera&&window.opera.postError&&window.opera.postError(a)}}b.fn.ajaxSubmit=function(a){function f(){function t(){var o=i.attr("target"),m=i.attr("action");l.setAttribute("target",u);l.getAttribute("method")!="POST"&&l.setAttribute("method","POST");l.getAttribute("action")!=e.url&&l.setAttribute("action",e.url);e.skipEncodingOverride|| i.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"});e.timeout&&setTimeout(function(){F=true;s()},e.timeout);var v=[];try{if(e.extraData)for(var w in e.extraData)v.push(b('<input type="hidden" name="'+w+'" value="'+e.extraData[w]+'" />').appendTo(l)[0]);r.appendTo("body");r.data("form-plugin-onload",s);l.submit()}finally{l.setAttribute("action",m);o?l.setAttribute("target",o):i.removeAttr("target");b(v).remove()}}function s(){if(!G){r.removeData("form-plugin-onload");var o=true; try{if(F)throw"timeout";p=x.contentWindow?x.contentWindow.document:x.contentDocument?x.contentDocument:x.document;var m=e.dataType=="xml"||p.XMLDocument||b.isXMLDoc(p);q("isXml="+m);if(!m&&window.opera&&(p.body==null||p.body.innerHTML==""))if(--K){q("requeing onLoad callback, DOM not available");setTimeout(s,250);return}G=true;j.responseText=p.documentElement?p.documentElement.innerHTML:null;j.responseXML=p.XMLDocument?p.XMLDocument:p;j.getResponseHeader=function(L){return{"content-type":e.dataType}[L]}; var v=/(json|script)/.test(e.dataType);if(v||e.textarea){var w=p.getElementsByTagName("textarea")[0];if(w)j.responseText=w.value;else if(v){var H=p.getElementsByTagName("pre")[0],I=p.getElementsByTagName("body")[0];if(H)j.responseText=H.textContent;else if(I)j.responseText=I.innerHTML}}else if(e.dataType=="xml"&&!j.responseXML&&j.responseText!=null)j.responseXML=C(j.responseText);J=b.httpData(j,e.dataType)}catch(D){q("error caught:",D);o=false;j.error=D;b.handleError(e,j,"error",D)}if(j.aborted){q("upload aborted"); o=false}if(o){e.success.call(e.context,J,"success",j);y&&b.event.trigger("ajaxSuccess",[j,e])}y&&b.event.trigger("ajaxComplete",[j,e]);y&&!--b.active&&b.event.trigger("ajaxStop");if(e.complete)e.complete.call(e.context,j,o?"success":"error");setTimeout(function(){r.removeData("form-plugin-onload");r.remove();j.responseXML=null},100)}}function C(o,m){if(window.ActiveXObject){m=new ActiveXObject("Microsoft.XMLDOM");m.async="false";m.loadXML(o)}else m=(new DOMParser).parseFromString(o,"text/xml");return m&& m.documentElement&&m.documentElement.tagName!="parsererror"?m:null}var l=i[0];if(b(":input[name=submit],:input[id=submit]",l).length)alert('Error: Form elements must not have name or id of "submit".');else{var e=b.extend(true,{},b.ajaxSettings,a);e.context=e.context||e;var u="jqFormIO"+(new Date).getTime(),E="_"+u;window[E]=function(){var o=r.data("form-plugin-onload");if(o){o();window[E]=undefined;try{delete window[E]}catch(m){}}};var r=b('<iframe id="'+u+'" name="'+u+'" src="'+e.iframeSrc+'" onload="window[\'_\'+this.id]()" />'), x=r[0];r.css({position:"absolute",top:"-1000px",left:"-1000px"});var j={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(){this.aborted=1;r.attr("src",e.iframeSrc)}},y=e.global;y&&!b.active++&&b.event.trigger("ajaxStart");y&&b.event.trigger("ajaxSend",[j,e]);if(e.beforeSend&&e.beforeSend.call(e.context,j,e)===false)e.global&&b.active--;else if(!j.aborted){var G=false, F=0,z=l.clk;if(z){var A=z.name;if(A&&!z.disabled){e.extraData=e.extraData||{};e.extraData[A]=z.value;if(z.type=="image"){e.extraData[A+".x"]=l.clk_x;e.extraData[A+".y"]=l.clk_y}}}e.forceSync?t():setTimeout(t,10);var J,p,K=50}}}if(!this.length){q("ajaxSubmit: skipping submit process - no element selected");return this}if(typeof a=="function")a={success:a};var d=this.attr("action");if(d=typeof d==="string"?b.trim(d):"")d=(d.match(/^([^#]+)/)||[])[1];d=d||window.location.href||"";a=b.extend(true,{url:d, type:this.attr("method")||"GET",iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},a);d={};this.trigger("form-pre-serialize",[this,a,d]);if(d.veto){q("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this}if(a.beforeSerialize&&a.beforeSerialize(this,a)===false){q("ajaxSubmit: submit aborted via beforeSerialize callback");return this}var c,h,g=this.formToArray(a.semantic);if(a.data){a.extraData=a.data;for(c in a.data)if(a.data[c]instanceof Array)for(var k in a.data[c])g.push({name:c, value:a.data[c][k]});else{h=a.data[c];h=b.isFunction(h)?h():h;g.push({name:c,value:h})}}if(a.beforeSubmit&&a.beforeSubmit(g,this,a)===false){q("ajaxSubmit: submit aborted via beforeSubmit callback");return this}this.trigger("form-submit-validate",[g,this,a,d]);if(d.veto){q("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this}c=b.param(g);if(a.type.toUpperCase()=="GET"){a.url+=(a.url.indexOf("?")>=0?"&":"?")+c;a.data=null}else a.data=c;var i=this,n=[];a.resetForm&&n.push(function(){i.resetForm()}); a.clearForm&&n.push(function(){i.clearForm()});if(!a.dataType&&a.target){var B=a.success||function(){};n.push(function(t){var s=a.replaceTarget?"replaceWith":"html";b(a.target)[s](t).each(B,arguments)})}else a.success&&n.push(a.success);a.success=function(t,s,C){for(var l=a.context||a,e=0,u=n.length;e<u;e++)n[e].apply(l,[t,s,C||i,i])};c=b("input:file",this).length>0;k=i.attr("enctype")=="multipart/form-data"||i.attr("encoding")=="multipart/form-data";if(a.iframe!==false&&(c||a.iframe||k))a.closeKeepAlive? b.get(a.closeKeepAlive,f):f();else b.ajax(a);this.trigger("form-submit-notify",[this,a]);return this};b.fn.ajaxForm=function(a){if(this.length===0){var f={s:this.selector,c:this.context};if(!b.isReady&&f.s){q("DOM not ready, queuing ajaxForm");b(function(){b(f.s,f.c).ajaxForm(a)});return this}q("terminating; zero elements found by selector"+(b.isReady?"":" (DOM not ready)"));return this}return this.ajaxFormUnbind().bind("submit.form-plugin",function(d){if(!d.isDefaultPrevented()){d.preventDefault(); b(this).ajaxSubmit(a)}}).bind("click.form-plugin",function(d){var c=d.target,h=b(c);if(!h.is(":submit,input:image")){c=h.closest(":submit");if(c.length==0)return;c=c[0]}var g=this;g.clk=c;if(c.type=="image")if(d.offsetX!=undefined){g.clk_x=d.offsetX;g.clk_y=d.offsetY}else if(typeof b.fn.offset=="function"){h=h.offset();g.clk_x=d.pageX-h.left;g.clk_y=d.pageY-h.top}else{g.clk_x=d.pageX-c.offsetLeft;g.clk_y=d.pageY-c.offsetTop}setTimeout(function(){g.clk=g.clk_x=g.clk_y=null},100)})};b.fn.ajaxFormUnbind= function(){return this.unbind("submit.form-plugin click.form-plugin")};b.fn.formToArray=function(a){var f=[];if(this.length===0)return f;var d=this[0],c=a?d.getElementsByTagName("*"):d.elements;if(!c)return f;var h,g,k,i,n,B;h=0;for(n=c.length;h<n;h++){g=c[h];if(k=g.name)if(a&&d.clk&&g.type=="image"){if(!g.disabled&&d.clk==g){f.push({name:k,value:b(g).val()});f.push({name:k+".x",value:d.clk_x},{name:k+".y",value:d.clk_y})}}else if((i=b.fieldValue(g,true))&&i.constructor==Array){g=0;for(B=i.length;g< B;g++)f.push({name:k,value:i[g]})}else i!==null&&typeof i!="undefined"&&f.push({name:k,value:i})}if(!a&&d.clk){a=b(d.clk);c=a[0];if((k=c.name)&&!c.disabled&&c.type=="image"){f.push({name:k,value:a.val()});f.push({name:k+".x",value:d.clk_x},{name:k+".y",value:d.clk_y})}}return f};b.fn.formSerialize=function(a){return b.param(this.formToArray(a))};b.fn.fieldSerialize=function(a){var f=[];this.each(function(){var d=this.name;if(d){var c=b.fieldValue(this,a);if(c&&c.constructor==Array)for(var h=0,g=c.length;h< g;h++)f.push({name:d,value:c[h]});else c!==null&&typeof c!="undefined"&&f.push({name:this.name,value:c})}});return b.param(f)};b.fn.fieldValue=function(a){for(var f=[],d=0,c=this.length;d<c;d++){var h=b.fieldValue(this[d],a);h===null||typeof h=="undefined"||h.constructor==Array&&!h.length||(h.constructor==Array?b.merge(f,h):f.push(h))}return f};b.fieldValue=function(a,f){var d=a.name,c=a.type,h=a.tagName.toLowerCase();if(f===undefined)f=true;if(f&&(!d||a.disabled||c=="reset"||c=="button"||(c=="checkbox"|| c=="radio")&&!a.checked||(c=="submit"||c=="image")&&a.form&&a.form.clk!=a||h=="select"&&a.selectedIndex==-1))return null;if(h=="select"){var g=a.selectedIndex;if(g<0)return null;d=[];h=a.options;var k=(c=c=="select-one")?g+1:h.length;for(g=c?g:0;g<k;g++){var i=h[g];if(i.selected){var n=i.value;n||(n=i.attributes&&i.attributes.value&&!i.attributes.value.specified?i.text:i.value);if(c)return n;d.push(n)}}return d}return b(a).val()};b.fn.clearForm=function(){return this.each(function(){b("input,select,textarea", this).clearFields()})};b.fn.clearFields=b.fn.clearInputs=function(){return this.each(function(){var a=this.type,f=this.tagName.toLowerCase();if(a=="text"||a=="password"||f=="textarea")this.value="";else if(a=="checkbox"||a=="radio")this.checked=false;else if(f=="select")this.selectedIndex=-1})};b.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||typeof this.reset=="object"&&!this.reset.nodeType)this.reset()})};b.fn.enable=function(a){if(a===undefined)a=true;return this.each(function(){this.disabled= !a})};b.fn.selected=function(a){if(a===undefined)a=true;return this.each(function(){var f=this.type;if(f=="checkbox"||f=="radio")this.checked=a;else if(this.tagName.toLowerCase()=="option"){f=b(this).parent("select");a&&f[0]&&f[0].type=="select-one"&&f.find("option").selected(false);this.selected=a}})}})(jQuery);
\ No newline at end of file
diff --git a/misc/jquery.js b/misc/jquery.js
index 9cad87d25045497e99bb0d9f0afb2162e3c7ad1f..94031629329af4ecfe55b94eebe2c84d3edfcaae 100644
--- a/misc/jquery.js
+++ b/misc/jquery.js
@@ -1,7 +1,7 @@
-// $Id: jquery.js,v 1.18 2010/03/09 20:52:27 webchick Exp $
+// $Id: jquery.js,v 1.20 2010/11/12 01:36:08 webchick Exp $
 
 /*!
- * jQuery JavaScript Library v1.4.2
+ * jQuery JavaScript Library v1.4.4
  * http://jquery.com/
  *
  * Copyright 2010, John Resig
@@ -13,144 +13,157 @@
  * Copyright 2010, The Dojo Foundation
  * Released under the MIT, BSD, and GPL Licenses.
  *
- * Date: Sat Feb 13 22:33:48 2010 -0500
+ * Date: Thu Nov 11 19:04:53 2010 -0500
  */
-(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
-e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
-j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
-"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
-true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
-Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
-(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
-a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
-"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
-function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
-c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
-L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
-"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
-a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
-d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
-a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
-!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
-true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
-parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
-false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
-s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
-applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
-else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
-a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
-w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
-cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
-i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
-" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
-this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
-e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
-c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
-a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
-function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
-k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
-C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
-null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
-e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
-f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
-if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
-fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
-d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
-"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
-a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
-isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
-{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
-if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
-e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
-"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
-d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
-!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
-toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
-u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
-function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
-if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
-t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
-g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
-for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
-1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
-CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
-relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
-l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
-h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
-CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
-g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
-text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
-setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
-h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
-m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
-"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
-h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
-!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
-h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
-q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
-if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
-(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
-function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
-gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
-c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
-{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
-"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
-d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
-a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
-1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
-a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
-c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
+h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
+h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
+"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
+e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
+"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
+s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
+j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
+toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
+-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
+if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
+if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
+b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
+!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
+l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
+z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
+s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
+s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
+[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
+false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
+k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
+scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
+1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
+"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
+c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
+else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
+a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
+c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
+a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
+colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
+1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
+l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
+"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
+if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
+a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
+attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
+b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
+c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
+arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
+d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
+c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
+w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
+8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
+"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
+Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
+c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
+var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
+"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
+xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
+B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
+0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
+a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
+1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
+"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
+c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
+[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
+break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
+q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
+l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
+return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
+B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
+POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
+i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
+i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
+"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
+m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
+true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
+g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
+0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
+"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
+if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
+g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
+for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
+i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
+n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
+function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
+p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
+t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
+function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
+c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
+not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
+h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
+c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
+2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
+b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
+e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
+"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
 wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
 prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
-this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
-return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
-""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
-this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
-u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
-1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
-return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
-""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
-c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
-c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
-function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
-Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
-"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
-a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
-a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
-"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
-serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
-function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
-global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
-e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
-"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
-false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
-false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
-c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
-d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
-g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
-1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
-"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
-if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
-this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
-"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
-animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
-j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
-this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
-"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
-c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
-this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
-this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
-e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
-c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
-function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
-this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
-k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
-f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
-c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
-d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
-"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
-e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
+else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
+c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
+b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
+this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
+prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
+b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
+1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
+d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
+jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
+zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
+h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
+if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
+d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
+e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
+"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
+!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
+A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
+encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
+[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
+e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
+if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
+3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
+d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
+d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
+1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
+var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
+this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
+c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
+b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
+for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
+parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
+height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
+c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
diff --git a/misc/machine-name.js b/misc/machine-name.js
index 0e7870e6cf152922a2e1cc2997831dcc71c733b0..7d0c0bc5ebe5ff4b88a37f4f549b3aac110debf2 100644
--- a/misc/machine-name.js
+++ b/misc/machine-name.js
@@ -1,4 +1,4 @@
-// $Id: machine-name.js,v 1.1 2010/10/13 17:09:00 webchick Exp $
+// $Id: machine-name.js,v 1.2 2010/11/22 00:05:58 dries Exp $
 (function ($) {
 
 /**
@@ -38,34 +38,41 @@ Drupal.behaviors.machineName = {
       }
       // Hide the form item container of the machine name form element.
       $wrapper.hide();
-      // Append the machine name preview to the source field.
-      if ($target.is(':disabled')) {
+      // Determine the initial machine name value. Unless the machine name form
+      // element is disabled or not empty, the initial default value is based on
+      // the human-readable form element value.
+      if ($target.is(':disabled') || $target.val() != '') {
         var machine = $target.val();
       }
       else {
         var machine = self.transliterate($source.val(), options);
       }
+      // Append the machine name preview to the source field.
       var $preview = $('<span class="machine-name-value">' + machine + '</span>');
       $suffix.empty()
         .append(' ').append('<span class="machine-name-label">' + options.label + ':</span>')
         .append(' ').append($preview);
 
-      // Append a link to edit the machine name, if it is editable, and only if
-      // one of the following conditions is met:
-      // - the machine name is empty.
-      // - the human-readable name is equal to the existing machine name.
-      if (!$target.is(':disabled') && ($target.val() == '' || $target.val() == machine)) {
-        var $link = $('<span class="admin-link"><a href="#">' + Drupal.t('Edit') + '</a></span>')
-          .click(function () {
-            $wrapper.show();
-            $target.focus();
-            $suffix.hide();
-            $source.unbind('keyup.machineName');
-            return false;
-          });
-        $suffix.append(' ').append($link);
+      // If the machine name cannot be edited, stop further processing.
+      if ($target.is(':disabled')) {
+        return;
+      }
+
+      // If it is editable, append an edit link.
+      var $link = $('<span class="admin-link"><a href="#">' + Drupal.t('Edit') + '</a></span>')
+        .click(function () {
+          $wrapper.show();
+          $target.focus();
+          $suffix.hide();
+          $source.unbind('.machineName');
+          return false;
+        });
+      $suffix.append(' ').append($link);
 
-        // Preview machine name in realtime when the human-readable name changes.
+      // Preview the machine name in realtime when the human-readable name
+      // changes, but only if there is no machine name yet; i.e., only upon
+      // initial creation, not when editing.
+      if ($target.val() == '') {
         $source.bind('keyup.machineName change.machineName', function () {
           machine = self.transliterate($(this).val(), options);
           // Set the machine name to the transliterated value.
diff --git a/misc/message-16-error.png b/misc/message-16-error.png
new file mode 100644
index 0000000000000000000000000000000000000000..486390c9b0ae6870eb81f39ca8206ad93dadd84d
Binary files /dev/null and b/misc/message-16-error.png differ
diff --git a/misc/message-16-help.png b/misc/message-16-help.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc44326e46b705778b66c9aa27994fb703d7c775
Binary files /dev/null and b/misc/message-16-help.png differ
diff --git a/misc/message-16-info.png b/misc/message-16-info.png
new file mode 100644
index 0000000000000000000000000000000000000000..f47924fc8ab0c800363774a555ce2da7186cf787
Binary files /dev/null and b/misc/message-16-info.png differ
diff --git a/misc/message-16-ok.png b/misc/message-16-ok.png
new file mode 100644
index 0000000000000000000000000000000000000000..9edebe6bd22fa0cbc17a3d68507b47142458aa24
Binary files /dev/null and b/misc/message-16-ok.png differ
diff --git a/misc/message-16-warning.png b/misc/message-16-warning.png
new file mode 100644
index 0000000000000000000000000000000000000000..ffc43177abdc983dd2d9d46c25cb0ad697e2b3f0
Binary files /dev/null and b/misc/message-16-warning.png differ
diff --git a/misc/message-24-error.png b/misc/message-24-error.png
new file mode 100644
index 0000000000000000000000000000000000000000..b09418060cee9fe18a4717ed88dba3795b324a39
Binary files /dev/null and b/misc/message-24-error.png differ
diff --git a/misc/message-24-help.png b/misc/message-24-help.png
new file mode 100644
index 0000000000000000000000000000000000000000..66b89cee3d46dac9334b2d9e923b190bb48ce2a3
Binary files /dev/null and b/misc/message-24-help.png differ
diff --git a/misc/message-24-info.png b/misc/message-24-info.png
new file mode 100644
index 0000000000000000000000000000000000000000..be599cabe49f3ab2b4d2e5902936860572a00dc9
Binary files /dev/null and b/misc/message-24-info.png differ
diff --git a/misc/message-24-ok.png b/misc/message-24-ok.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd3666934fb9e2d0f0beac231c5ee23d572069f1
Binary files /dev/null and b/misc/message-24-ok.png differ
diff --git a/misc/message-24-warning.png b/misc/message-24-warning.png
new file mode 100644
index 0000000000000000000000000000000000000000..183297d8695d5cc436592e540cfb702c3e9118b3
Binary files /dev/null and b/misc/message-24-warning.png differ
diff --git a/misc/permissions.png b/misc/permissions.png
index 76547e95c97365d5d7284c8689f1ce8434997a1c..621471135b41177cc0c72dd95a81995f14b2336f 100755
Binary files a/misc/permissions.png and b/misc/permissions.png differ
diff --git a/misc/progress.gif b/misc/progress.gif
index eb7087b4a52c337378206f02b15592b88d4a4f12..f84a9de57677e5e8060f3f7ba25680cf41edd3ef 100644
Binary files a/misc/progress.gif and b/misc/progress.gif differ
diff --git a/misc/states.js b/misc/states.js
index 25bc1d7b453c26967cb997f11f70935809e52a6b..1f99a8c6d6e21e7d5853ce906d2198206e214c01 100644
--- a/misc/states.js
+++ b/misc/states.js
@@ -1,4 +1,4 @@
-// $Id: states.js,v 1.4 2010/04/30 19:30:44 webchick Exp $
+// $Id: states.js,v 1.5 2010/12/06 16:10:29 webchick Exp $
 (function ($) {
 
 /**
@@ -354,7 +354,7 @@ states.State.prototype = {
       $(e.target)
         .attr('disabled', e.value)
         .filter('.form-element')
-          .closest('.form-item, .form-wrapper')[e.value ? 'addClass' : 'removeClass']('form-disabled');
+          .closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'addClass' : 'removeClass']('form-disabled');
 
       // Note: WebKit nightlies don't reflect that change correctly.
       // See https://bugs.webkit.org/show_bug.cgi?id=23789
@@ -363,13 +363,13 @@ states.State.prototype = {
 
   $(document).bind('state:required', function(e) {
     if (e.trigger) {
-      $(e.target).closest('.form-item, .form-wrapper')[e.value ? 'addClass' : 'removeClass']('form-required');
+      $(e.target).closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'addClass' : 'removeClass']('form-required');
     }
   });
 
   $(document).bind('state:visible', function(e) {
     if (e.trigger) {
-      $(e.target).closest('.form-item, .form-wrapper')[e.value ? 'show' : 'hide']();
+      $(e.target).closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'show' : 'hide']();
     }
   });
 
diff --git a/misc/ui/images/ui-anim_basic_16x16_0.gif b/misc/ui/images/ui-anim_basic_16x16_0.gif
deleted file mode 100644
index 085ccaecaf5fa5c34bc14cd2c2ed5cbbd8e25dcb..0000000000000000000000000000000000000000
Binary files a/misc/ui/images/ui-anim_basic_16x16_0.gif and /dev/null differ
diff --git a/misc/ui/jquery.effects.blind.min.js b/misc/ui/jquery.effects.blind.min.js
index c889d78345a1ca24e2373b00067ed9a722f8d05f..f76085c16bfd599de210502c8c6533b6a6fe8c86 100644
--- a/misc/ui/jquery.effects.blind.min.js
+++ b/misc/ui/jquery.effects.blind.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.blind.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.blind.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Blind 1.8
+ * jQuery UI Effects Blind 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Blind
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.blind=function(b){return this.queue(function(){var d=a(this),c=["position","top","left"];var h=a.effects.setMode(d,b.options.mode||"hide");var g=b.options.direction||"vertical";a.effects.save(d,c);d.show();var j=a.effects.createWrapper(d).css({overflow:"hidden"});var e=(g=="vertical")?"height":"width";var i=(g=="vertical")?j.height():j.width();if(h=="show"){j.css(e,0)}var f={};f[e]=h=="show"?i:0;j.animate(f,b.duration,b.options.easing,function(){if(h=="hide"){d.hide()}a.effects.restore(d,c);a.effects.removeWrapper(d);if(b.callback){b.callback.apply(d[0],arguments)}d.dequeue()})})}})(jQuery);
\ No newline at end of file
+(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","left"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,g);b.effects.removeWrapper(a);
+c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.bounce.min.js b/misc/ui/jquery.effects.bounce.min.js
index 25ba51446a1bdda89d7da26e8415e219be60771a..a90de0d37276a95bc5161e946d800455b8170f4f 100644
--- a/misc/ui/jquery.effects.bounce.min.js
+++ b/misc/ui/jquery.effects.bounce.min.js
@@ -1,15 +1,17 @@
-// $Id: jquery.effects.bounce.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.bounce.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Bounce 1.8
+ * jQuery UI Effects Bounce 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Bounce
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.bounce=function(b){return this.queue(function(){var e=a(this),l=["position","top","left"];var k=a.effects.setMode(e,b.options.mode||"effect");var n=b.options.direction||"up";var c=b.options.distance||20;var d=b.options.times||5;var g=b.duration||250;if(/show|hide/.test(k)){l.push("opacity")}a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n=="up"||n=="down")?"top":"left";var p=(n=="up"||n=="left")?"pos":"neg";var c=b.options.distance||(f=="top"?e.outerHeight({margin:true})/3:e.outerWidth({margin:true})/3);if(k=="show"){e.css("opacity",0).css(f,p=="pos"?-c:c)}if(k=="hide"){c=c/(d*2)}if(k!="hide"){d--}if(k=="show"){var h={opacity:1};h[f]=(p=="pos"?"+=":"-=")+c;e.animate(h,g/2,b.options.easing);c=c/2;d--}for(var j=0;j<d;j++){var o={},m={};o[f]=(p=="pos"?"-=":"+=")+c;m[f]=(p=="pos"?"+=":"-=")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing);c=(k=="hide")?c*2:c/2}if(k=="hide"){var h={opacity:0};h[f]=(p=="pos"?"-=":"+=")+c;e.animate(h,g/2,b.options.easing,function(){e.hide();a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}else{var o={},m={};o[f]=(p=="pos"?"-=":"+=")+c;m[f]=(p=="pos"?"+=":"-=")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}e.queue("fx",function(){e.dequeue()});e.dequeue()})}})(jQuery);
\ No newline at end of file
+(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","left"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
+3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
+b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
diff --git a/misc/ui/jquery.effects.clip.min.js b/misc/ui/jquery.effects.clip.min.js
index b505d2d9e519edfdb0fe274ca2b56bf07f65aa6a..4824d1b3522246693d763774581c1e19ce63cbf8 100644
--- a/misc/ui/jquery.effects.clip.min.js
+++ b/misc/ui/jquery.effects.clip.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.clip.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.clip.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Clip 1.8
+ * jQuery UI Effects Clip 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Clip
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.clip=function(b){return this.queue(function(){var f=a(this),j=["position","top","left","height","width"];var i=a.effects.setMode(f,b.options.mode||"hide");var k=b.options.direction||"vertical";a.effects.save(f,j);f.show();var c=a.effects.createWrapper(f).css({overflow:"hidden"});var e=f[0].tagName=="IMG"?c:f;var g={size:(k=="vertical")?"height":"width",position:(k=="vertical")?"top":"left"};var d=(k=="vertical")?e.height():e.width();if(i=="show"){e.css(g.size,0);e.css(g.position,d/2)}var h={};h[g.size]=i=="show"?d:0;h[g.position]=i=="show"?0:d/2;e.animate(h,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){f.hide()}a.effects.restore(f,j);a.effects.removeWrapper(f);if(b.callback){b.callback.apply(f[0],arguments)}f.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","left","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,c/2)}var h={};h[g.size]=
+f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.core.min.js b/misc/ui/jquery.effects.core.min.js
index 370589ff6295c105af84b9325c7ed553091eeb13..bd57120228b441f9d7b685e55da9c1496b0c6fd0 100644
--- a/misc/ui/jquery.effects.core.min.js
+++ b/misc/ui/jquery.effects.core.min.js
@@ -1,12 +1,32 @@
-// $Id: jquery.effects.core.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.core.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects 1.8
+ * jQuery UI Effects 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/
  */
-jQuery.effects||(function(g){g.effects={};g.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(l,k){g.fx.step[k]=function(m){if(!m.colorInit){m.start=j(m.elem,k);m.end=i(m.end);m.colorInit=true}m.elem.style[k]="rgb("+Math.max(Math.min(parseInt((m.pos*(m.end[0]-m.start[0]))+m.start[0],10),255),0)+","+Math.max(Math.min(parseInt((m.pos*(m.end[1]-m.start[1]))+m.start[1],10),255),0)+","+Math.max(Math.min(parseInt((m.pos*(m.end[2]-m.start[2]))+m.start[2],10),255),0)+")"}});function i(l){var k;if(l&&l.constructor==Array&&l.length==3){return l}if(k=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(l)){return[parseInt(k[1],10),parseInt(k[2],10),parseInt(k[3],10)]}if(k=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(l)){return[parseFloat(k[1])*2.55,parseFloat(k[2])*2.55,parseFloat(k[3])*2.55]}if(k=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(l)){return[parseInt(k[1],16),parseInt(k[2],16),parseInt(k[3],16)]}if(k=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(l)){return[parseInt(k[1]+k[1],16),parseInt(k[2]+k[2],16),parseInt(k[3]+k[3],16)]}if(k=/rgba\(0, 0, 0, 0\)/.exec(l)){return a.transparent}return a[g.trim(l).toLowerCase()]}function j(m,k){var l;do{l=g.curCSS(m,k);if(l!=""&&l!="transparent"||g.nodeName(m,"body")){break}k="backgroundColor"}while(m=m.parentNode);return i(l)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};var e=["add","remove","toggle"],c={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};function f(){var n=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,o={},l,m;if(n&&n.length&&n[0]&&n[n[0]]){var k=n.length;while(k--){l=n[k];if(typeof n[l]=="string"){m=l.replace(/\-(\w)/g,function(p,q){return q.toUpperCase()});o[m]=n[l]}}}else{for(l in n){if(typeof n[l]==="string"){o[l]=n[l]}}}return o}function b(l){var k,m;for(k in l){m=l[k];if(m==null||g.isFunction(m)||k in c||(/scrollbar/).test(k)||(!(/color/i).test(k)&&isNaN(parseFloat(m)))){delete l[k]}}return l}function h(k,m){var n={_:0},l;for(l in m){if(k[l]!=m[l]){n[l]=m[l]}}return n}g.effects.animateClass=function(k,l,n,m){if(g.isFunction(n)){m=n;n=null}return this.each(function(){var r=g(this),o=r.attr("style")||" ",s=b(f.call(this)),q,p=r.attr("className");g.each(e,function(t,u){if(k[u]){r[u+"Class"](k[u])}});q=b(f.call(this));r.attr("className",p);r.animate(h(s,q),l,n,function(){g.each(e,function(t,u){if(k[u]){r[u+"Class"](k[u])}});if(typeof r.attr("style")=="object"){r.attr("style").cssText="";r.attr("style").cssText=o}else{r.attr("style",o)}if(m){m.apply(this,arguments)}})})};g.fn.extend({_addClass:g.fn.addClass,addClass:function(l,k,n,m){return k?g.effects.animateClass.apply(this,[{add:l},k,n,m]):this._addClass(l)},_removeClass:g.fn.removeClass,removeClass:function(l,k,n,m){return k?g.effects.animateClass.apply(this,[{remove:l},k,n,m]):this._removeClass(l)},_toggleClass:g.fn.toggleClass,toggleClass:function(m,l,k,o,n){if(typeof l=="boolean"||l===undefined){if(!k){return this._toggleClass(m,l)}else{return g.effects.animateClass.apply(this,[(l?{add:m}:{remove:m}),k,o,n])}}else{return g.effects.animateClass.apply(this,[{toggle:m},l,k,o])}},switchClass:function(k,m,l,o,n){return g.effects.animateClass.apply(this,[{add:m,remove:k},l,o,n])}});g.extend(g.effects,{version:"1.8",save:function(l,m){for(var k=0;k<m.length;k++){if(m[k]!==null){l.data("ec.storage."+m[k],l[0].style[m[k]])}}},restore:function(l,m){for(var k=0;k<m.length;k++){if(m[k]!==null){l.css(m[k],l.data("ec.storage."+m[k]))}}},setMode:function(k,l){if(l=="toggle"){l=k.is(":hidden")?"show":"hide"}return l},getBaseline:function(l,m){var n,k;switch(l[0]){case"top":n=0;break;case"middle":n=0.5;break;case"bottom":n=1;break;default:n=l[0]/m.height}switch(l[1]){case"left":k=0;break;case"center":k=0.5;break;case"right":k=1;break;default:k=l[1]/m.width}return{x:k,y:n}},createWrapper:function(k){if(k.parent().is(".ui-effects-wrapper")){return k.parent()}var l={width:k.outerWidth(true),height:k.outerHeight(true),"float":k.css("float")},m=g("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});k.wrap(m);m=k.parent();if(k.css("position")=="static"){m.css({position:"relative"});k.css({position:"relative"})}else{g.extend(l,{position:k.css("position"),zIndex:k.css("z-index")});g.each(["top","left","bottom","right"],function(n,o){l[o]=k.css(o);if(isNaN(parseInt(l[o],10))){l[o]="auto"}});k.css({position:"relative",top:0,left:0})}return m.css(l).show()},removeWrapper:function(k){if(k.parent().is(".ui-effects-wrapper")){return k.parent().replaceWith(k)}return k},setTransition:function(l,n,k,m){m=m||{};g.each(n,function(p,o){unit=l.cssUnit(o);if(unit[0]>0){m[o]=unit[0]*k+unit[1]}});return m}});function d(l,k,m,n){if(typeof l=="object"){n=k;m=null;k=l;l=k.effect}if(g.isFunction(k)){n=k;m=null;k={}}if(g.isFunction(m)){n=m;m=null}if(typeof k=="number"||g.fx.speeds[k]){n=m;m=k;k={}}k=k||{};m=m||k.duration;m=g.fx.off?0:typeof m=="number"?m:g.fx.speeds[m]||g.fx.speeds._default;n=n||k.complete;return[l,k,m,n]}g.fn.extend({effect:function(n,m,p,q){var l=d.apply(this,arguments),o={options:l[1],duration:l[2],callback:l[3]},k=g.effects[n];return k&&!g.fx.off?k.call(this,o):this},_show:g.fn.show,show:function(l){if(!l||typeof l=="number"||g.fx.speeds[l]){return this._show.apply(this,arguments)}else{var k=d.apply(this,arguments);k[1].mode="show";return this.effect.apply(this,k)}},_hide:g.fn.hide,hide:function(l){if(!l||typeof l=="number"||g.fx.speeds[l]){return this._hide.apply(this,arguments)}else{var k=d.apply(this,arguments);k[1].mode="hide";return this.effect.apply(this,k)}},__toggle:g.fn.toggle,toggle:function(l){if(!l||typeof l=="number"||g.fx.speeds[l]||typeof l=="boolean"||g.isFunction(l)){return this.__toggle.apply(this,arguments)}else{var k=d.apply(this,arguments);k[1].mode="toggle";return this.effect.apply(this,k)}},cssUnit:function(k){var l=this.css(k),m=[];g.each(["em","px","%","pt"],function(n,o){if(l.indexOf(o)>0){m=[parseFloat(l),o]}});return m}});g.easing.jswing=g.easing.swing;g.extend(g.easing,{def:"easeOutQuad",swing:function(l,m,k,o,n){return g.easing[g.easing.def](l,m,k,o,n)},easeInQuad:function(l,m,k,o,n){return o*(m/=n)*m+k},easeOutQuad:function(l,m,k,o,n){return -o*(m/=n)*(m-2)+k},easeInOutQuad:function(l,m,k,o,n){if((m/=n/2)<1){return o/2*m*m+k}return -o/2*((--m)*(m-2)-1)+k},easeInCubic:function(l,m,k,o,n){return o*(m/=n)*m*m+k},easeOutCubic:function(l,m,k,o,n){return o*((m=m/n-1)*m*m+1)+k},easeInOutCubic:function(l,m,k,o,n){if((m/=n/2)<1){return o/2*m*m*m+k}return o/2*((m-=2)*m*m+2)+k},easeInQuart:function(l,m,k,o,n){return o*(m/=n)*m*m*m+k},easeOutQuart:function(l,m,k,o,n){return -o*((m=m/n-1)*m*m*m-1)+k},easeInOutQuart:function(l,m,k,o,n){if((m/=n/2)<1){return o/2*m*m*m*m+k}return -o/2*((m-=2)*m*m*m-2)+k},easeInQuint:function(l,m,k,o,n){return o*(m/=n)*m*m*m*m+k},easeOutQuint:function(l,m,k,o,n){return o*((m=m/n-1)*m*m*m*m+1)+k},easeInOutQuint:function(l,m,k,o,n){if((m/=n/2)<1){return o/2*m*m*m*m*m+k}return o/2*((m-=2)*m*m*m*m+2)+k},easeInSine:function(l,m,k,o,n){return -o*Math.cos(m/n*(Math.PI/2))+o+k},easeOutSine:function(l,m,k,o,n){return o*Math.sin(m/n*(Math.PI/2))+k},easeInOutSine:function(l,m,k,o,n){return -o/2*(Math.cos(Math.PI*m/n)-1)+k},easeInExpo:function(l,m,k,o,n){return(m==0)?k:o*Math.pow(2,10*(m/n-1))+k},easeOutExpo:function(l,m,k,o,n){return(m==n)?k+o:o*(-Math.pow(2,-10*m/n)+1)+k},easeInOutExpo:function(l,m,k,o,n){if(m==0){return k}if(m==n){return k+o}if((m/=n/2)<1){return o/2*Math.pow(2,10*(m-1))+k}return o/2*(-Math.pow(2,-10*--m)+2)+k},easeInCirc:function(l,m,k,o,n){return -o*(Math.sqrt(1-(m/=n)*m)-1)+k},easeOutCirc:function(l,m,k,o,n){return o*Math.sqrt(1-(m=m/n-1)*m)+k},easeInOutCirc:function(l,m,k,o,n){if((m/=n/2)<1){return -o/2*(Math.sqrt(1-m*m)-1)+k}return o/2*(Math.sqrt(1-(m-=2)*m)+1)+k},easeInElastic:function(l,n,k,u,r){var o=1.70158;var q=0;var m=u;if(n==0){return k}if((n/=r)==1){return k+u}if(!q){q=r*0.3}if(m<Math.abs(u)){m=u;var o=q/4}else{var o=q/(2*Math.PI)*Math.asin(u/m)}return -(m*Math.pow(2,10*(n-=1))*Math.sin((n*r-o)*(2*Math.PI)/q))+k},easeOutElastic:function(l,n,k,u,r){var o=1.70158;var q=0;var m=u;if(n==0){return k}if((n/=r)==1){return k+u}if(!q){q=r*0.3}if(m<Math.abs(u)){m=u;var o=q/4}else{var o=q/(2*Math.PI)*Math.asin(u/m)}return m*Math.pow(2,-10*n)*Math.sin((n*r-o)*(2*Math.PI)/q)+u+k},easeInOutElastic:function(l,n,k,u,r){var o=1.70158;var q=0;var m=u;if(n==0){return k}if((n/=r/2)==2){return k+u}if(!q){q=r*(0.3*1.5)}if(m<Math.abs(u)){m=u;var o=q/4}else{var o=q/(2*Math.PI)*Math.asin(u/m)}if(n<1){return -0.5*(m*Math.pow(2,10*(n-=1))*Math.sin((n*r-o)*(2*Math.PI)/q))+k}return m*Math.pow(2,-10*(n-=1))*Math.sin((n*r-o)*(2*Math.PI)/q)*0.5+u+k},easeInBack:function(l,m,k,p,o,n){if(n==undefined){n=1.70158}return p*(m/=o)*m*((n+1)*m-n)+k},easeOutBack:function(l,m,k,p,o,n){if(n==undefined){n=1.70158}return p*((m=m/o-1)*m*((n+1)*m+n)+1)+k},easeInOutBack:function(l,m,k,p,o,n){if(n==undefined){n=1.70158}if((m/=o/2)<1){return p/2*(m*m*(((n*=(1.525))+1)*m-n))+k}return p/2*((m-=2)*m*(((n*=(1.525))+1)*m+n)+2)+k},easeInBounce:function(l,m,k,o,n){return o-g.easing.easeOutBounce(l,n-m,0,o,n)+k},easeOutBounce:function(l,m,k,o,n){if((m/=n)<(1/2.75)){return o*(7.5625*m*m)+k}else{if(m<(2/2.75)){return o*(7.5625*(m-=(1.5/2.75))*m+0.75)+k}else{if(m<(2.5/2.75)){return o*(7.5625*(m-=(2.25/2.75))*m+0.9375)+k}else{return o*(7.5625*(m-=(2.625/2.75))*m+0.984375)+k}}}},easeInOutBounce:function(l,m,k,o,n){if(m<n/2){return g.easing.easeInBounce(l,m*2,0,o,n)*0.5+k}return g.easing.easeOutBounce(l,m*2-n,0,o,n)*0.5+o*0.5+k}})})(jQuery);
\ No newline at end of file
+jQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
+16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
+a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
+a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
+"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
+0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
+211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
+d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){f.queue(this,"fx",function(){var e=f(this),g=e.attr("style")||" ",h=q(p.call(this)),l,v=e.attr("className");f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});l=q(p.call(this));e.attr("className",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)});h=f.queue(this);l=
+h.splice(h.length-1,1)[0];h.splice(1,0,l);f.dequeue(this)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},
+b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.7",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";
+return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",
+background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);
+return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments);
+else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),
+b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,
+a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,
+a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==
+e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=
+g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/
+h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,
+a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
diff --git a/misc/ui/jquery.effects.drop.min.js b/misc/ui/jquery.effects.drop.min.js
index 19988d73f10321c9b61ac472733da52e0d802441..2b258de72e8b3a7288116c554cfef6021e4952c4 100644
--- a/misc/ui/jquery.effects.drop.min.js
+++ b/misc/ui/jquery.effects.drop.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.drop.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.drop.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Drop 1.8
+ * jQuery UI Effects Drop 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Drop
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.drop=function(b){return this.queue(function(){var e=a(this),d=["position","top","left","opacity"];var i=a.effects.setMode(e,b.options.mode||"hide");var h=b.options.direction||"left";a.effects.save(e,d);e.show();a.effects.createWrapper(e);var f=(h=="up"||h=="down")?"top":"left";var c=(h=="up"||h=="left")?"pos":"neg";var j=b.options.distance||(f=="top"?e.outerHeight({margin:true})/2:e.outerWidth({margin:true})/2);if(i=="show"){e.css("opacity",0).css(f,c=="pos"?-j:j)}var g={opacity:i=="show"?1:0};g[f]=(i=="show"?(c=="pos"?"+=":"-="):(c=="pos"?"-=":"+="))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","left","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e=="show"?1:
+0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.explode.min.js b/misc/ui/jquery.effects.explode.min.js
index 505243fad6c0ad837f32650d6f7a99b6063fb10f..cb55bc52e0373965441876d3903531000fe2667b 100644
--- a/misc/ui/jquery.effects.explode.min.js
+++ b/misc/ui/jquery.effects.explode.min.js
@@ -1,15 +1,17 @@
-// $Id: jquery.effects.explode.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.explode.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Explode 1.8
+ * jQuery UI Effects Explode 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Explode
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.explode=function(b){return this.queue(function(){var k=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;var e=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?(a(this).is(":visible")?"hide":"show"):b.options.mode;var h=a(this).show().css("visibility","hidden");var l=h.offset();l.top-=parseInt(h.css("marginTop"),10)||0;l.left-=parseInt(h.css("marginLeft"),10)||0;var g=h.outerWidth(true);var c=h.outerHeight(true);for(var f=0;f<k;f++){for(var d=0;d<e;d++){h.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-d*(g/e),top:-f*(c/k)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/e,height:c/k,left:l.left+d*(g/e)+(b.options.mode=="show"?(d-Math.floor(e/2))*(g/e):0),top:l.top+f*(c/k)+(b.options.mode=="show"?(f-Math.floor(k/2))*(c/k):0),opacity:b.options.mode=="show"?0:1}).animate({left:l.left+d*(g/e)+(b.options.mode=="show"?0:(d-Math.floor(e/2))*(g/e)),top:l.top+f*(c/k)+(b.options.mode=="show"?0:(f-Math.floor(k/2))*(c/k)),opacity:b.options.mode=="show"?1:0},b.duration||500)}}setTimeout(function(){b.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();if(b.callback){b.callback.apply(h[0])}h.dequeue();a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);
\ No newline at end of file
+(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
+0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
+e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
diff --git a/misc/ui/jquery.effects.fade.min.js b/misc/ui/jquery.effects.fade.min.js
index eec6ae2459d7e5419d30de2d14f29165d5644418..1fde384a6d13e71f653d1c9cd65d4ed0e39061e7 100644
--- a/misc/ui/jquery.effects.fade.min.js
+++ b/misc/ui/jquery.effects.fade.min.js
@@ -1,15 +1,15 @@
-// $Id: jquery.effects.fade.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.fade.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Fade 1.8
+ * jQuery UI Effects Fade 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Fade
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){(b.callback&&b.callback.apply(this,arguments));c.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.fold.min.js b/misc/ui/jquery.effects.fold.min.js
index 8eb27038908cfe46ec95419379b20795b20a22a7..e3b95d09cbbb059a447e9c529a20d07566e75ac7 100644
--- a/misc/ui/jquery.effects.fold.min.js
+++ b/misc/ui/jquery.effects.fold.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.fold.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.fold.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Fold 1.8
+ * jQuery UI Effects Fold 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Fold
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=["position","top","left"];var h=a.effects.setMode(e,b.options.mode||"hide");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:"hidden"});var i=((h=="show")!=n);var f=i?["width","height"]:["height","width"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1],10)/100*c[h=="hide"?0:1]}if(h=="show"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h=="show"?c[0]:o;l[f[1]]=h=="show"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h=="hide"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);
\ No newline at end of file
+(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100*
+f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.highlight.min.js b/misc/ui/jquery.effects.highlight.min.js
index 2160a3cfb3b710ab6511b8e73bdec0bf681c8f4a..780d15a390c1f783ba6c6d043c8d9046ac9d5600 100644
--- a/misc/ui/jquery.effects.highlight.min.js
+++ b/misc/ui/jquery.effects.highlight.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.highlight.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.highlight.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Highlight 1.8
+ * jQuery UI Effects Highlight 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Highlight
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.highlight=function(b){return this.queue(function(){var d=a(this),c=["backgroundImage","backgroundColor","opacity"],f=a.effects.setMode(d,b.options.mode||"show"),e={backgroundColor:d.css("backgroundColor")};if(f=="hide"){e.opacity=0}a.effects.save(d,c);d.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(e,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){(f=="hide"&&d.hide());a.effects.restore(d,c);(f=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"));(b.callback&&b.callback.apply(this,arguments));d.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
+this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.pulsate.min.js b/misc/ui/jquery.effects.pulsate.min.js
index 41420f80fbecc62616a7b62da352df07516ca8e7..1757640f8a92fc0c546e9c610389c6cbf4c26425 100644
--- a/misc/ui/jquery.effects.pulsate.min.js
+++ b/misc/ui/jquery.effects.pulsate.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.pulsate.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.pulsate.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Pulsate 1.8
+ * jQuery UI Effects Pulsate 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Pulsate
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this),e=a.effects.setMode(d,b.options.mode||"show");times=((b.options.times||5)*2)-1;duration=b.duration?b.duration/2:a.fx.speeds._default/2,isVisible=d.is(":visible"),animateTo=0;if(!isVisible){d.css("opacity",0).show();animateTo=1}if((e=="hide"&&isVisible)||(e=="show"&&!isVisible)){times--}for(var c=0;c<times;c++){d.animate({opacity:animateTo},duration,b.options.easing);animateTo=(animateTo+1)%2}d.animate({opacity:animateTo},duration,b.options.easing,function(){if(animateTo==0){d.hide()}(b.callback&&b.callback.apply(this,arguments))});d.queue("fx",function(){d.dequeue()}).dequeue()})}})(jQuery);
\ No newline at end of file
+(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
+a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
diff --git a/misc/ui/jquery.effects.scale.min.js b/misc/ui/jquery.effects.scale.min.js
index a455ea0653aee51e4d1ccf7a7c7ee4c710eef093..16acd62807f35358faa1e2e29ef8efc0ba6db5a8 100644
--- a/misc/ui/jquery.effects.scale.min.js
+++ b/misc/ui/jquery.effects.scale.min.js
@@ -1,15 +1,22 @@
-// $Id: jquery.effects.scale.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.scale.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Scale 1.8
+ * jQuery UI Effects Scale 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Scale
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.puff=function(b){return this.queue(function(){var f=a(this),g=a.effects.setMode(f,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,d=e/100,c={height:f.height(),width:f.width()};a.extend(b.options,{fade:true,mode:g,percent:g=="hide"?e:100,from:g=="hide"?c:{height:c.height*d,width:c.width*d}});f.effect("scale",b.options,b.duration,b.callback);f.dequeue()})};a.effects.scale=function(b){return this.queue(function(){var g=a(this);var d=a.extend(true,{},b.options);var j=a.effects.setMode(g,b.options.mode||"effect");var h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:(j=="hide"?0:100));var i=b.options.direction||"both";var c=b.options.origin;if(j!="effect"){d.origin=c||["middle","center"];d.restore=true}var f={height:g.height(),width:g.width()};g.from=b.options.from||(j=="show"?{height:0,width:0}:f);var e={y:i!="horizontal"?(h/100):1,x:i!="vertical"?(h/100):1};g.to={height:f.height*e.y,width:f.width*e.x};if(b.options.fade){if(j=="show"){g.from.opacity=0;g.to.opacity=1}if(j=="hide"){g.from.opacity=1;g.to.opacity=0}}d.from=g.from;d.to=g.to;d.mode=j;g.effect("size",d,b.duration,b.callback);g.dequeue()})};a.effects.size=function(b){return this.queue(function(){var c=a(this),n=["position","top","left","width","height","overflow","opacity"];var m=["position","top","left","overflow","opacity"];var j=["width","height","overflow"];var p=["fontSize"];var k=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"];var f=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"];var g=a.effects.setMode(c,b.options.mode||"effect");var i=b.options.restore||false;var e=b.options.scale||"both";var o=b.options.origin;var d={height:c.height(),width:c.width()};c.from=b.options.from||d;c.to=b.options.to||d;if(o){var h=a.effects.getBaseline(o,d);c.from.top=(d.height-c.from.height)*h.y;c.from.left=(d.width-c.from.width)*h.x;c.to.top=(d.height-c.to.height)*h.y;c.to.left=(d.width-c.to.width)*h.x}var l={from:{y:c.from.height/d.height,x:c.from.width/d.width},to:{y:c.to.height/d.height,x:c.to.width/d.width}};if(e=="box"||e=="both"){if(l.from.y!=l.to.y){n=n.concat(k);c.from=a.effects.setTransition(c,k,l.from.y,c.from);c.to=a.effects.setTransition(c,k,l.to.y,c.to)}if(l.from.x!=l.to.x){n=n.concat(f);c.from=a.effects.setTransition(c,f,l.from.x,c.from);c.to=a.effects.setTransition(c,f,l.to.x,c.to)}}if(e=="content"||e=="both"){if(l.from.y!=l.to.y){n=n.concat(p);c.from=a.effects.setTransition(c,p,l.from.y,c.from);c.to=a.effects.setTransition(c,p,l.to.y,c.to)}}a.effects.save(c,i?n:m);c.show();a.effects.createWrapper(c);c.css("overflow","hidden").css(c.from);if(e=="content"||e=="both"){k=k.concat(["marginTop","marginBottom"]).concat(p);f=f.concat(["marginLeft","marginRight"]);j=n.concat(k).concat(f);c.find("*[width]").each(function(){child=a(this);if(i){a.effects.save(child,j)}var q={height:child.height(),width:child.width()};child.from={height:q.height*l.from.y,width:q.width*l.from.x};child.to={height:q.height*l.to.y,width:q.width*l.to.x};if(l.from.y!=l.to.y){child.from=a.effects.setTransition(child,k,l.from.y,child.from);child.to=a.effects.setTransition(child,k,l.to.y,child.to)}if(l.from.x!=l.to.x){child.from=a.effects.setTransition(child,f,l.from.x,child.from);child.to=a.effects.setTransition(child,f,l.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){if(i){a.effects.restore(child,j)}})})}c.animate(c.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(c.to.opacity===0){c.css("opacity",c.from.opacity)}if(g=="hide"){c.hide()}a.effects.restore(c,i?n:m);a.effects.removeWrapper(c);if(b.callback){b.callback.apply(this,arguments)}c.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
+b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
+1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","left","width","height","overflow","opacity"],g=["position","top","left","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=c.effects.setMode(a,
+b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};if(m=="box"||m=="both"){if(d.from.y!=
+d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);a.css("overflow","hidden").css(a.from);
+if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);child.to=c.effects.setTransition(child,
+f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,n?e:g);c.effects.removeWrapper(a);b.callback&&
+b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.shake.min.js b/misc/ui/jquery.effects.shake.min.js
index 37139ae47550ebc0d5c397c39a1c17574d8c123a..50d62b3c255bf438673db6103a992d2dd2df08e3 100644
--- a/misc/ui/jquery.effects.shake.min.js
+++ b/misc/ui/jquery.effects.shake.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.shake.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.shake.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Shake 1.8
+ * jQuery UI Effects Shake 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Shake
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.shake=function(b){return this.queue(function(){var e=a(this),l=["position","top","left"];var k=a.effects.setMode(e,b.options.mode||"effect");var n=b.options.direction||"left";var c=b.options.distance||20;var d=b.options.times||3;var g=b.duration||b.options.duration||140;a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n=="up"||n=="down")?"top":"left";var p=(n=="up"||n=="left")?"pos":"neg";var h={},o={},m={};h[f]=(p=="pos"?"-=":"+=")+c;o[f]=(p=="pos"?"+=":"-=")+c*2;m[f]=(p=="pos"?"-=":"+=")+c*2;e.animate(h,g,b.options.easing);for(var j=1;j<d;j++){e.animate(o,g,b.options.easing).animate(m,g,b.options.easing)}e.animate(o,g,b.options.easing).animate(h,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}});e.queue("fx",function(){e.dequeue()});e.dequeue()})}})(jQuery);
\ No newline at end of file
+(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","left"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=(h=="pos"?"-=":"+=")+
+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
diff --git a/misc/ui/jquery.effects.slide.min.js b/misc/ui/jquery.effects.slide.min.js
index a356e85acdbd75b67f2489b5aae7194645673347..9949129e0e55f7206a15cedaf946f413ae5d7421 100644
--- a/misc/ui/jquery.effects.slide.min.js
+++ b/misc/ui/jquery.effects.slide.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.slide.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.slide.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Slide 1.8
+ * jQuery UI Effects Slide 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Slide
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.slide=function(b){return this.queue(function(){var e=a(this),d=["position","top","left"];var i=a.effects.setMode(e,b.options.mode||"show");var h=b.options.direction||"left";a.effects.save(e,d);e.show();a.effects.createWrapper(e).css({overflow:"hidden"});var f=(h=="up"||h=="down")?"top":"left";var c=(h=="up"||h=="left")?"pos":"neg";var j=b.options.distance||(f=="top"?e.outerHeight({margin:true}):e.outerWidth({margin:true}));if(i=="show"){e.css(f,c=="pos"?-j:j)}var g={};g[f]=(i=="show"?(c=="pos"?"+=":"-="):(c=="pos"?"-=":"+="))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);
\ No newline at end of file
+(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","left"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e);var i={};i[g]=(f==
+"show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
diff --git a/misc/ui/jquery.effects.transfer.min.js b/misc/ui/jquery.effects.transfer.min.js
index 45c093ff3b6e659d5d0d7c74f034c6ba8a9697e1..94bc8dca3ae696abf9373444113a9deb1acb5945 100644
--- a/misc/ui/jquery.effects.transfer.min.js
+++ b/misc/ui/jquery.effects.transfer.min.js
@@ -1,15 +1,16 @@
-// $Id: jquery.effects.transfer.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.effects.transfer.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Effects Transfer 1.8
+ * jQuery UI Effects Transfer 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Effects/Transfer
  *
  * Depends:
  *	jquery.effects.core.js
  */
-(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);
\ No newline at end of file
+(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
+b.dequeue()})})}})(jQuery);
diff --git a/misc/ui/jquery.ui.accordion.css b/misc/ui/jquery.ui.accordion.css
index 525a73e570e3e201ac59f11ac09509f9f558b83b..3d470e0971a6b0f7acc639f626773563bf9b4762 100644
--- a/misc/ui/jquery.ui.accordion.css
+++ b/misc/ui/jquery.ui.accordion.css
@@ -1,7 +1,16 @@
-/* $Id: jquery.ui.accordion.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.accordion.css,v 1.3 2011/01/03 00:03:34 webchick Exp $ */
 
-/* Accordion
-----------------------------------*/
+/*
+ * jQuery UI Accordion 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
 .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
 .ui-accordion .ui-accordion-li-fix { display: inline; }
 .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
@@ -9,4 +18,4 @@
 .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
 .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
 .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
\ No newline at end of file
+.ui-accordion .ui-accordion-content-active { display: block; }
diff --git a/misc/ui/jquery.ui.accordion.min.js b/misc/ui/jquery.ui.accordion.min.js
index 0f371598d2d396e7bf0302e1481266fe0aa777f8..402f6a28f28d3fe72caa374d00db12d1d66bbbf1 100644
--- a/misc/ui/jquery.ui.accordion.min.js
+++ b/misc/ui/jquery.ui.accordion.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.accordion.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.accordion.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Accordion 1.8
+ * jQuery UI Accordion 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Accordion
  *
@@ -13,4 +13,20 @@
  *	jquery.ui.core.js
  *	jquery.ui.widget.js
  */
-(function(a){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},_create:function(){var d=this.options,b=this;this.running=0;this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix")}this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){a(this).removeClass("ui-state-focus")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){var e=c.closest(".ui-accordion-header");if(e.length){this.active=e}else{this.active=c.closest(".ui-accordion-content").prev()}}}this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");this._createIcons();if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(f){return b._keydown(f)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.headers.bind((d.event)+".accordion",function(f){b._clickHandler.call(b,f,this);f.preventDefault()})}},_createIcons:function(){var b=this.options;if(b.icons){a("<span/>").addClass("ui-icon "+b.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(c.autoHeight||c.fillHeight){b.css("height","")}return this},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b=="active"){this.activate(c)}if(b=="icons"){this._destroyIcons();if(c){this._createIcons()}}},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:this._clickHandler({target:e.target},e.target);e.preventDefault()}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var d=this.options,c;if(d.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){c-=a(this).outerHeight(true)});this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else{if(d.autoHeight){c=0;this.headers.next().each(function(){c=Math.max(c,a(this).height())}).height(c)}}return this},activate:function(b){this.options.active=b;var c=this._findActive(b)[0];this._clickHandler({target:c},c);return this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,f){var d=this.options;if(d.disabled){return}if(!b.target){if(!d.collapsible){return}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var h=this.active.next(),e={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:h},c=(this.active=a([]));this._toggle(c,h,e);return}var g=a(b.currentTarget||f);var i=g[0]==this.active[0];d.active=d.collapsible&&i?false:a(".ui-accordion-header",this.element).index(g);if(this.running||(!d.collapsible&&i)){return}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!i){g.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);g.next().addClass("ui-accordion-content-active")}var c=g.next(),h=this.active.next(),e={options:d,newHeader:i&&d.collapsible?a([]):g,oldHeader:this.active,newContent:i&&d.collapsible?a([]):c,oldContent:h},j=this.headers.index(this.active[0])>this.headers.index(g[0]);this.active=i?a([]):g;this._toggle(c,h,e,i,j);return},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(d.collapsible&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(h&&!l[h]&&!a.easing[h]){h="slide"}if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(d.collapsible&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.8",animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}if(!j.toShow.size()){j.toHide.animate({height:"hide"},j);return}var c=j.toShow.css("overflow"),g=0,d={},f={},e=["height","paddingTop","paddingBottom"],b;var i=j.toShow;b=i[0].style.width;i.width(parseInt(i.parent().width(),10)-parseInt(i.css("paddingLeft"),10)-parseInt(i.css("paddingRight"),10)-(parseInt(i.css("borderLeftWidth"),10)||0)-(parseInt(i.css("borderRightWidth"),10)||0));a.each(e,function(k,m){f[m]="hide";var l=(""+a.css(j.toShow[0],m)).match(/^([\d+-.]+)(.*)$/);d[m]={value:l[1],unit:l[2]||"px"}});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(f,{step:function(k,l){if(l.prop=="height"){g=(l.end-l.start===0)?0:(l.now-l.start)/(l.end-l.start)}j.toShow[0].style[l.prop]=(g*d[l.prop].value)+d[l.prop].unit},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","")}j.toShow.css("width",b);j.toShow.css({overflow:c});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})}}})})(jQuery);
\ No newline at end of file
+(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
+a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
+if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var f=d.closest(".ui-accordion-header");a.active=f.length?f:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",
+function(g){return a._keydown(g)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(g){a._clickHandler.call(a,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+
+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
+this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
+b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
+a.preventDefault()}if(g){c(a.target).attr("tabIndex",-1);c(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
+c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
+if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);
+a.next().addClass("ui-accordion-content-active")}h=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):h,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(h,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
+this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},h=this.active=c([]);this._toggle(h,f,g)}},_toggle:function(a,b,d,f,g){var h=this,e=h.options;h.toShow=a;h.toHide=b;h.data=d;var j=function(){if(h)return h._completed.apply(h,arguments)};h._trigger("changestart",null,h.data);h.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),toHide:b,complete:j,
+down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!f[k]&&!c.easing[k])k="slide";f[k]||(f[k]=function(l){this.slide(l,{easing:k,duration:i||700})});
+f[k](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.7",animations:{slide:function(a,
+b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},h={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){h[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);g[i]={value:j[1],
+unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(h,{step:function(j,i){if(i.prop=="height")f=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=f*g[i.prop].value+g[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
+paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
diff --git a/misc/ui/jquery.ui.autocomplete.css b/misc/ui/jquery.ui.autocomplete.css
index 85987621f7c85eb8a85f1b65377fb7fa63103345..b0c8b96b88b0ff43ad758b1281f64054847797fb 100644
--- a/misc/ui/jquery.ui.autocomplete.css
+++ b/misc/ui/jquery.ui.autocomplete.css
@@ -1,20 +1,34 @@
-/* $Id: jquery.ui.autocomplete.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.autocomplete.css,v 1.3 2011/01/03 00:03:34 webchick Exp $ */
 
-/* Autocomplete
-----------------------------------*/
+/*
+ * jQuery UI Autocomplete 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
 .ui-autocomplete { position: absolute; cursor: default; }	
-.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
 
 /* workarounds */
 * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
 
-/* Menu
-----------------------------------*/
+/*
+ * jQuery UI Menu 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
 .ui-menu {
 	list-style:none;
 	padding: 2px;
 	margin: 0;
 	display:block;
+	float: left;
 }
 .ui-menu .ui-menu {
 	margin-top: -3px;
@@ -22,6 +36,9 @@
 .ui-menu .ui-menu-item {
 	margin:0;
 	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
 	width: 100%;
 }
 .ui-menu .ui-menu-item a {
@@ -33,5 +50,6 @@
 }
 .ui-menu .ui-menu-item a.ui-state-hover,
 .ui-menu .ui-menu-item a.ui-state-active {
+	font-weight: normal;
 	margin: -1px;
 }
diff --git a/misc/ui/jquery.ui.autocomplete.min.js b/misc/ui/jquery.ui.autocomplete.min.js
index 78fd9b0f4f4a52a7272224f99d2385104a124136..f243dada9be51b4f79fc9115623ee655be46cb70 100644
--- a/misc/ui/jquery.ui.autocomplete.min.js
+++ b/misc/ui/jquery.ui.autocomplete.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.autocomplete.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.autocomplete.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Autocomplete 1.8
+ * jQuery UI Autocomplete 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Autocomplete
  *
@@ -14,4 +14,20 @@
  *	jquery.ui.widget.js
  *	jquery.ui.position.js
  */
-(function(a){a.widget("ui.autocomplete",{options:{minLength:1,delay:300},_create:function(){var b=this,c=this.element[0].ownerDocument;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(d){var e=a.ui.keyCode;switch(d.keyCode){case e.PAGE_UP:b._move("previousPage",d);break;case e.PAGE_DOWN:b._move("nextPage",d);break;case e.UP:b._move("previous",d);d.preventDefault();break;case e.DOWN:b._move("next",d);d.preventDefault();break;case e.ENTER:if(b.menu.active){d.preventDefault()}case e.TAB:if(!b.menu.active){return}b.menu.select();break;case e.ESCAPE:b.element.val(b.term);b.close(d);break;case e.SHIFT:case e.CONTROL:case 18:break;default:clearTimeout(b.searching);b.searching=setTimeout(function(){b.search(null,d)},b.options.delay);break}}).bind("focus.autocomplete",function(){b.previous=b.element.val()}).bind("blur.autocomplete",function(d){clearTimeout(b.searching);b.closing=setTimeout(function(){b.close(d)},150)});this._initSource();this.response=function(){return b._response.apply(b,arguments)};this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo("body",c).menu({focus:function(e,f){var d=f.item.data("item.autocomplete");if(false!==b._trigger("focus",null,{item:d})){b.element.val(d.value)}},selected:function(e,f){var d=f.item.data("item.autocomplete");if(false!==b._trigger("select",e,{item:d})){b.element.val(d.value)}b.close(e);b.previous=b.element.val();if(b.element[0]!==c.activeElement){b.element.focus()}},blur:function(d,e){if(b.menu.element.is(":visible")){b.element.val(b.term)}}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");if(a.fn.bgiframe){this.menu.element.bgiframe()}},destroy:function(){this.element.removeClass("ui-autocomplete-input ui-widget ui-widget-content").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();a.Widget.prototype.destroy.call(this)},_setOption:function(b){a.Widget.prototype._setOption.apply(this,arguments);if(b==="source"){this._initSource()}},_initSource:function(){var c,b;if(a.isArray(this.options.source)){c=this.options.source;this.source=function(e,d){var f=new RegExp(a.ui.autocomplete.escapeRegex(e.term),"i");d(a.grep(c,function(g){return f.test(g.label||g.value||g)}))}}else{if(typeof this.options.source==="string"){b=this.options.source;this.source=function(e,d){a.getJSON(b,e,d)}}else{this.source=this.options.source}}},search:function(c,b){c=c!=null?c:this.element.val();if(c.length<this.options.minLength){return this.close(b)}clearTimeout(this.closing);if(this._trigger("search")===false){return}return this._search(c)},_search:function(b){this.term=this.element.addClass("ui-autocomplete-loading").val();this.source({term:b},this.response)},_response:function(b){if(b.length){b=this._normalize(b);this._suggest(b);this._trigger("open")}else{this.close()}this.element.removeClass("ui-autocomplete-loading")},close:function(b){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this._trigger("close",b);this.menu.element.hide();this.menu.deactivate()}if(this.previous!==this.element.val()){this._trigger("change",b)}},_normalize:function(b){if(b.length&&b[0].label&&b[0].value){return b}return a.map(b,function(c){if(typeof c==="string"){return{label:c,value:c}}return a.extend({label:c.label||c.value,value:c.value||c.label},c)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1),d,e;this._renderMenu(c,b);this.menu.deactivate();this.menu.refresh();this.menu.element.show().position({my:"left top",at:"left bottom",of:this.element,collision:"none"});d=c.width("").width();e=this.element.width();c.width(Math.max(d,e))},_renderMenu:function(d,c){var b=this;a.each(c,function(e,f){b._renderItem(d,f)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append("<a>"+c.label+"</a>").appendTo(b)},_move:function(c,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(c)||this.menu.last()&&/^next/.test(c)){this.element.val(this.term);this.menu.deactivate();return}this.menu[c]()},widget:function(){return this.menu.element}});a.extend(a.ui.autocomplete,{escapeRegex:function(b){return b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")}})}(jQuery));(function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){c.preventDefault();b.select()});this.refresh()},refresh:function(){var c=this;var b=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");b.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(){c.activate(a(this).parent())}).mouseleave(function(){c.deactivate()})},activate:function(d){this.deactivate();if(this.hasScroll()){var e=d.offset().top-this.element.offset().top,b=this.element.attr("scrollTop"),c=this.element.height();if(e<0){this.element.attr("scrollTop",b+e)}else{if(e>c){this.element.attr("scrollTop",b+e-c+d.height())}}}this.active=d.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",null,{item:d})},deactivate:function(){if(!this.active){return}this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null},next:function(){this.move("next","li:first")},previous:function(){this.move("prev","li:last")},first:function(){return this.active&&!this.active.prev().length},last:function(){return this.active&&!this.active.next().length},move:function(d,c){if(!this.active){this.activate(this.element.children(c));return}var b=this.active[d]();if(b.length){this.activate(b)}else{this.activate(this.element.children(c))}},nextPage:function(){if(this.hasScroll()){if(!this.active||this.last()){this.activate(this.element.children(":first"));return}var d=this.active.offset().top,c=this.element.height(),b=this.element.children("li").filter(function(){var e=a(this).offset().top-d-c+a(this).height();return e<10&&e>-10});if(!b.length){b=this.element.children(":last")}this.activate(b)}else{this.activate(this.element.children(!this.active||this.last()?":first":":last"))}},previousPage:function(){if(this.hasScroll()){if(!this.active||this.first()){this.activate(this.element.children(":last"));return}var c=this.active.offset().top,b=this.element.height();result=this.element.children("li").filter(function(){var d=a(this).offset().top-c+b-a(this).height();return d<10&&d>-10});if(!result.length){result=this.element.children(":first")}this.activate(result)}else{this.activate(this.element.children(!this.active||this.first()?":last":":first"))}},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(){this._trigger("selected",null,{item:this.active})}})}(jQuery));
\ No newline at end of file
+(function(d){d.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},_create:function(){var a=this,b=this.element[0].ownerDocument,f;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){f=false;var e=d.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:a._move("previousPage",
+c);break;case e.PAGE_DOWN:a._move("nextPage",c);break;case e.UP:a._move("previous",c);c.preventDefault();break;case e.DOWN:a._move("next",c);c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:if(a.menu.active){f=true;c.preventDefault()}case e.TAB:if(!a.menu.active)return;a.menu.select(c);break;case e.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);
+break}}}).bind("keypress.autocomplete",function(c){if(f){f=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||
+"body",b)[0]).mousedown(function(c){var e=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(g){g.target!==a.element[0]&&g.target!==e&&!d.ui.contains(e,g.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,e){e=e.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:e})&&/^key/.test(c.originalEvent.type)&&a.element.val(e.value)},selected:function(c,e){var g=e.item.data("item.autocomplete"),
+h=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=h;setTimeout(function(){a.previous=h;a.selectedItem=g},1)}false!==a._trigger("select",c,{item:g})&&a.element.val(g.value);a.term=a.element.val();a.close(c);a.selectedItem=g},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
+this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0])},_initSource:function(){var a=this,b,f;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,e){e(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){f=this.options.source;this.source=
+function(c,e){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:f,data:c,dataType:"json",success:function(g,h,i){i===a.xhr&&e(g);a.xhr=null},error:function(g){g===a.xhr&&e([]);a.xhr=null}})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.element.addClass("ui-autocomplete-loading");
+this.source({term:a},this.response)},_response:function(a){if(a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&
+a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),
+this.element.outerWidth()))},_renderMenu:function(a,b){var f=this;d.each(b,function(c,e){f._renderItem(a,e)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});
+d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(a,b){var f=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return f.test(c.label||c.value||c)})}})})(jQuery);
+(function(d){d.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(d(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(b){a.activate(b,d(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var f=b.offset().top-this.element.offset().top,c=this.element.attr("scrollTop"),e=this.element.height();if(f<0)this.element.attr("scrollTop",c+f);else f>=e&&this.element.attr("scrollTop",c+f-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},
+deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,f){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);
+a.length?this.activate(f,a):this.activate(f,this.element.children(b))}else this.activate(f,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(".ui-menu-item:first"));else{var b=this.active.offset().top,f=this.element.height(),c=this.element.children(".ui-menu-item").filter(function(){var e=d(this).offset().top-b-f+d(this).height();return e<10&&e>-10});c.length||(c=this.element.children(".ui-menu-item:last"));this.activate(a,
+c)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(".ui-menu-item:last"));else{var b=this.active.offset().top,f=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-b+f-d(this).height();return c<10&&c>-10});result.length||(result=this.element.children(".ui-menu-item:first"));
+this.activate(a,result)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
diff --git a/misc/ui/jquery.ui.button.css b/misc/ui/jquery.ui.button.css
index 24766cfc66b79cf7eee41a672ec9c4fa95d1cffa..ca82478964884521d0bf0670aac87b3ef02769d3 100644
--- a/misc/ui/jquery.ui.button.css
+++ b/misc/ui/jquery.ui.button.css
@@ -1,8 +1,14 @@
-/* $Id: jquery.ui.button.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
-
-/* Button
-----------------------------------*/
+/* $Id: jquery.ui.button.css,v 1.3 2011/01/03 00:03:34 webchick Exp $ */
 
+/*
+ * jQuery UI Button 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
 .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
 .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
 button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
@@ -13,15 +19,17 @@ button.ui-button-icons-only { width: 3.7em; }
 .ui-button .ui-button-text { display: block; line-height: 1.4;  }
 .ui-button-text-only .ui-button-text { padding: .4em 1em; }
 .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
 .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
 /* no icon support for input elements, provide padding by default */
 input.ui-button { padding: .4em 1em; }
 
 /*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
 .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
 .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
 
 /*button sets*/
diff --git a/misc/ui/jquery.ui.button.min.js b/misc/ui/jquery.ui.button.min.js
index bc1ab2bb1d084c9ce6a892b8b944693a2e8f8b84..ee04bcb4bf4fe8265d574f764b5444b1d44df5e8 100644
--- a/misc/ui/jquery.ui.button.min.js
+++ b/misc/ui/jquery.ui.button.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.button.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.button.min.js,v 1.3 2011/01/03 00:03:34 webchick Exp $
 
 /*
- * jQuery UI Button 1.8
+ * jQuery UI Button 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Button
  *
@@ -13,4 +13,15 @@
  *	jquery.ui.core.js
  *	jquery.ui.widget.js
  */
-(function(f){var d,c="ui-button ui-widget ui-state-default ui-corner-all",b="ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon ui-button-text-only",e=function(g){f(":ui-button",g.target.form).each(function(){var h=f(this).data("button");setTimeout(function(){h.refresh()},1)})},a=function(h){var g=h.name,i=h.form,j=f([]);if(g){if(i){j=f(i).find("[name='"+g+"']")}else{j=f("[name='"+g+"']",h.ownerDocument).filter(function(){return !this.form})}}return j};f.widget("ui.button",{options:{text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",e);this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var g=this,i=this.options,j=this.type==="checkbox"||this.type==="radio",k="ui-state-hover"+(!j?" ui-state-active":""),h="ui-state-focus";if(i.label===null){i.label=this.buttonElement.html()}if(this.element.is(":disabled")){i.disabled=true}this.buttonElement.addClass(c).attr("role","button").bind("mouseenter.button",function(){if(i.disabled){return}f(this).addClass("ui-state-hover");if(this===d){f(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){if(i.disabled){return}f(this).removeClass(k)}).bind("focus.button",function(){f(this).addClass(h)}).bind("blur.button",function(){f(this).removeClass(h)});if(j){this.element.bind("change.button",function(){g.refresh()})}if(this.type==="checkbox"){this.buttonElement.bind("click.button",function(){if(i.disabled){return false}f(this).toggleClass("ui-state-active");g.buttonElement.attr("aria-pressed",g.element[0].checked)})}else{if(this.type==="radio"){this.buttonElement.bind("click.button",function(){if(i.disabled){return false}f(this).addClass("ui-state-active");g.buttonElement.attr("aria-pressed",true);var l=g.element[0];a(l).not(l).map(function(){return f(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)})}else{this.buttonElement.bind("mousedown.button",function(){if(i.disabled){return false}f(this).addClass("ui-state-active");d=this;f(document).one("mouseup",function(){d=null})}).bind("mouseup.button",function(){if(i.disabled){return false}f(this).removeClass("ui-state-active")}).bind("keydown.button",function(l){if(i.disabled){return false}if(l.keyCode==f.ui.keyCode.SPACE||l.keyCode==f.ui.keyCode.ENTER){f(this).addClass("ui-state-active")}}).bind("keyup.button",function(){f(this).removeClass("ui-state-active")});if(this.buttonElement.is("a")){this.buttonElement.keyup(function(l){if(l.keyCode===f.ui.keyCode.SPACE){f(this).click()}})}}}this._setOption("disabled",i.disabled)},_determineButtonType:function(){if(this.element.is(":checkbox")){this.type="checkbox"}else{if(this.element.is(":radio")){this.type="radio"}else{if(this.element.is("input")){this.type="input"}else{this.type="button"}}}if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var g=this.element.is(":checked");if(g){this.buttonElement.addClass("ui-state-active")}this.buttonElement.attr("aria-pressed",g)}else{this.buttonElement=this.element}},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass(c+" "+b).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());if(!this.hasTitle){this.buttonElement.removeAttr("title")}f.Widget.prototype.destroy.call(this)},_setOption:function(g,h){f.Widget.prototype._setOption.apply(this,arguments);if(g==="disabled"){if(h){this.element.attr("disabled",true)}else{this.element.removeAttr("disabled")}}this._resetButton()},refresh:function(){var g=this.element.is(":disabled");if(g!==this.options.disabled){this._setOption("disabled",g)}if(this.type==="radio"){a(this.element[0]).each(function(){if(f(this).is(":checked")){f(this).button("widget").addClass("ui-state-active").attr("aria-pressed",true)}else{f(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)}})}else{if(this.type==="checkbox"){if(this.element.is(":checked")){this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true)}else{this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)}}}},_resetButton:function(){if(this.type==="input"){if(this.options.label){this.element.val(this.options.label)}return}var j=this.buttonElement,i=f("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(j.empty()).text(),h=this.options.icons,g=h.primary&&h.secondary;if(h.primary||h.secondary){j.addClass("ui-button-text-icon"+(g?"s":""));if(h.primary){j.prepend("<span class='ui-button-icon-primary ui-icon "+h.primary+"'></span>")}if(h.secondary){j.append("<span class='ui-button-icon-secondary ui-icon "+h.secondary+"'></span>")}if(!this.options.text){j.addClass(g?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon");if(!this.hasTitle){j.attr("title",i)}}}else{j.addClass("ui-button-text-only")}}});f.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(g,h){if(g==="disabled"){this.buttons.button("option",g,h)}f.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return f(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return f(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");f.Widget.prototype.destroy.call(this)}})}(jQuery));
\ No newline at end of file
+(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
+i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
+function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
+b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
+g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
+c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
+this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active  ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
+this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
+true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
+c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
+this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},
+destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
diff --git a/misc/ui/jquery.ui.core.css b/misc/ui/jquery.ui.core.css
index d6c126c89f81f68f6a8302266d1c91d4378ae0aa..f5acbf0ca6751391025807e968266a92e9226126 100644
--- a/misc/ui/jquery.ui.core.css
+++ b/misc/ui/jquery.ui.core.css
@@ -1,15 +1,19 @@
-/* $Id: jquery.ui.core.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.core.css,v 1.3 2011/01/03 00:03:34 webchick Exp $ */
 
 /*
-* jQuery UI CSS Framework
-* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
+ * jQuery UI CSS Framework 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
 
 /* Layout helpers
 ----------------------------------*/
 .ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
 .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
 .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
 .ui-helper-clearfix { display: inline-block; }
diff --git a/misc/ui/jquery.ui.core.min.js b/misc/ui/jquery.ui.core.min.js
index 946627a33dc650e3ef14742bac10aa803a10acdc..87769b48a7a0a8882e3cb35c810ee3ee0692b19c 100644
--- a/misc/ui/jquery.ui.core.min.js
+++ b/misc/ui/jquery.ui.core.min.js
@@ -1,12 +1,19 @@
-// $Id: jquery.ui.core.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.core.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*!
- * jQuery UI 1.8
+ * jQuery UI 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI
  */
-jQuery.ui||(function(a){a.ui={version:"1.8",plugin:{add:function(c,d,f){var e=a.ui[c].prototype;for(var b in f){e.plugins[b]=e.plugins[b]||[];e.plugins[b].push([d,f[b]])}},call:function(b,d,c){var f=b.plugins[d];if(!f||!b.element[0].parentNode){return}for(var e=0;e<f.length;e++){if(b.options[f[e][0]]){f[e][1].apply(b.element,c)}}}},contains:function(d,c){return document.compareDocumentPosition?d.compareDocumentPosition(c)&16:d!==c&&d.contains(c)},hasScroll:function(e,c){if(a(e).css("overflow")=="hidden"){return false}var b=(c&&c=="left")?"scrollLeft":"scrollTop",d=false;if(e[b]>0){return true}e[b]=1;d=(e[b]>0);e[b]=0;return d},isOverAxis:function(c,b,d){return(c>b)&&(c<(b+d))},isOver:function(g,c,f,e,b,d){return a.ui.isOverAxis(g,f,b)&&a.ui.isOverAxis(c,e,d)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};a.fn.extend({_focus:a.fn.focus,focus:function(b,c){return typeof b==="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus();(c&&c.call(d))},b)}):this._focus.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var b;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){b=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{b=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!b.length?a(document):b},zIndex:function(e){if(e!==undefined){return this.css("zIndex",e)}if(this.length){var c=a(this[0]),b,d;while(c.length&&c[0]!==document){b=c.css("position");if(b=="absolute"||b=="relative"||b=="fixed"){d=parseInt(c.css("zIndex"));if(!isNaN(d)&&d!=0){return d}}c=c.parent()}}return 0}});a.extend(a.expr[":"],{data:function(d,c,b){return !!a.data(d,b[3])},focusable:function(c){var d=c.nodeName.toLowerCase(),b=a.attr(c,"tabindex");return(/input|select|textarea|button|object/.test(d)?!c.disabled:"a"==d||"area"==d?c.href||!isNaN(b):!isNaN(b))&&!a(c)["area"==d?"parents":"closest"](":hidden").length},tabbable:function(c){var b=a.attr(c,"tabindex");return(isNaN(b)||b>=0)&&a(c).is(":focusable")}})})(jQuery);
\ No newline at end of file
+(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.7",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
+NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
+"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
+if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
+"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,
+d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
+c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&
+b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
diff --git a/misc/ui/jquery.ui.datepicker.css b/misc/ui/jquery.ui.datepicker.css
index 1fc0d50cfcfd9bddd07bc3cf6a0ee5ad65c5021d..b7fbb52202153ed288f8360ce3dd95c2808001dc 100644
--- a/misc/ui/jquery.ui.datepicker.css
+++ b/misc/ui/jquery.ui.datepicker.css
@@ -1,8 +1,15 @@
-/* $Id: jquery.ui.datepicker.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.datepicker.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Datepicker
-----------------------------------*/
-.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+/*
+ * jQuery UI Datepicker 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
 .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
 .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
 .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
@@ -60,4 +67,4 @@
     left: -4px; /*must have*/
     width: 200px; /*must have*/
     height: 200px; /*must have*/
-}
\ No newline at end of file
+}
diff --git a/misc/ui/jquery.ui.datepicker.min.js b/misc/ui/jquery.ui.datepicker.min.js
index 3e7275ee1d7d7d9a5ba6686f91c650cb34943b6a..03de55eef969f6650db24468c6b838e0be3fe1aa 100644
--- a/misc/ui/jquery.ui.datepicker.min.js
+++ b/misc/ui/jquery.ui.datepicker.min.js
@@ -1,15 +1,83 @@
-// $Id: jquery.ui.datepicker.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.datepicker.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Datepicker 1.8
+ * jQuery UI Datepicker 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Datepicker
  *
  * Depends:
  *	jquery.ui.core.js
  */
-(function($){$.extend($.ui,{datepicker:{version:"1.8"}});var PROP_NAME="datepicker";var dpuuid=new Date().getTime();function Datepicker(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._datepickerShowing=false;this._inDialog=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass="ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"show",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"_default",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};$.extend(this._defaults,this.regional[""]);this.dpDiv=$('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([^A-Za-z0-9_])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}this._attachments(input,inst);input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});this._autoSize(inst);$.data(target,PROP_NAME,inst)},_attachments:function(input,inst){var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(inst.append){inst.append.remove()}if(appendText){inst.append=$('<span class="'+this._appendClass+'">'+appendText+"</span>");input[isRTL?"before":"after"](inst.append)}input.unbind("focus",this._showDatepicker);if(inst.trigger){inst.trigger.remove()}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('<button type="button"></button>').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("<img/>").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==input[0]){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(input[0])}return false})}},_autoSize:function(inst){if(this._get(inst,"autoSize")&&!inst.inline){var date=new Date(2009,12-1,20);var dateFormat=this._get(inst,"dateFormat");if(dateFormat.match(/[DM]/)){var findMax=function(names){var max=0;var maxI=0;for(var i=0;i<names.length;i++){if(names[i].length>max){max=names[i].length;maxI=i}}return maxI};date.setMonth(findMax(this._get(inst,(dateFormat.match(/MM/)?"monthNames":"monthNamesShort"))));date.setDate(findMax(this._get(inst,(dateFormat.match(/DD/)?"dayNames":"dayNamesShort")))+20-date.getDay())}inst.input.attr("size",this._formatDate(inst,date).length)}},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst),true);this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,date,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('<input type="text" id="'+id+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});date=(date&&date.constructor==Date?this._formatDate(inst,date):date);this._dialogInput.val(date);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=document.documentElement.clientWidth;var browserHeight=document.documentElement.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",(this._pos[0]+20)+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i<this._disabledInputs.length;i++){if(this._disabledInputs[i]==target){return true}}return false},_getInst:function(target){try{return $.data(target,PROP_NAME)}catch(err){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(target,name,value){var inst=this._getInst(target);if(arguments.length==2&&typeof name=="string"){return(name=="defaults"?$.extend({},$.datepicker._defaults):(inst?(name=="all"?$.extend({},inst.settings):this._get(inst,name)):null))}var settings=name||{};if(typeof name=="string"){settings={};settings[name]=value}if(inst){if(this._curInst==inst){this._hideDatepicker()}var date=this._getDateDatepicker(target,true);extendRemove(inst.settings,settings);this._attachments($(target),inst);this._autoSize(inst);this._setDateDatepicker(target,date);this._updateDatepicker(inst)}},_changeDatepicker:function(target,name,value){this._optionDatepicker(target,name,value)},_refreshDatepicker:function(target){var inst=this._getInst(target);if(inst){this._updateDatepicker(inst)}},_setDateDatepicker:function(target,date){var inst=this._getInst(target);if(inst){this._setDate(inst,date);this._updateDatepicker(inst);this._updateAlternate(inst)}},_getDateDatepicker:function(target,noDefault){var inst=this._getInst(target);if(inst&&!inst.inline){this._setDateFromField(inst,noDefault)}return(inst?this._getDate(inst):null)},_doKeyDown:function(event){var inst=$.datepicker._getInst(event.target);var handled=true;var isRTL=inst.dpDiv.is(".ui-datepicker-rtl");inst._keyEvent=true;if($.datepicker._datepickerShowing){switch(event.keyCode){case 9:$.datepicker._hideDatepicker();handled=false;break;case 13:var sel=$("td."+$.datepicker._dayOverClass,inst.dpDiv).add($("td."+$.datepicker._currentClass,inst.dpDiv));if(sel[0]){$.datepicker._selectDay(event.target,inst.selectedMonth,inst.selectedYear,sel[0])}else{$.datepicker._hideDatepicker()}return false;break;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M");break;case 34:$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M");break;case 35:if(event.ctrlKey||event.metaKey){$.datepicker._clearDate(event.target)}handled=event.ctrlKey||event.metaKey;break;case 36:if(event.ctrlKey||event.metaKey){$.datepicker._gotoToday(event.target)}handled=event.ctrlKey||event.metaKey;break;case 37:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?+1:-1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M")}break;case 38:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,-7,"D")}handled=event.ctrlKey||event.metaKey;break;case 39:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?-1:+1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M")}break;case 40:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,+7,"D")}handled=event.ctrlKey||event.metaKey;break;default:handled=false}}else{if(event.keyCode==36&&event.ctrlKey){$.datepicker._showDatepicker(this)}else{handled=false}}if(handled){event.preventDefault();event.stopPropagation()}},_doKeyPress:function(event){var inst=$.datepicker._getInst(event.target);if($.datepicker._get(inst,"constrainInput")){var chars=$.datepicker._possibleChars($.datepicker._get(inst,"dateFormat"));var chr=String.fromCharCode(event.charCode==undefined?event.keyCode:event.charCode);return event.ctrlKey||(chr<" "||!chars||chars.indexOf(chr)>-1)}},_doKeyUp:function(event){var inst=$.datepicker._getInst(event.target);if(inst.input.val()!=inst.lastVal){try{var date=$.datepicker.parseDate($.datepicker._get(inst,"dateFormat"),(inst.input?inst.input.val():null),$.datepicker._getFormatConfig(inst));if(date){$.datepicker._setDateFromField(inst);$.datepicker._updateAlternate(inst);$.datepicker._updateDatepicker(inst)}}catch(event){$.datepicker.log(event)}}return true},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);if($.datepicker._curInst&&$.datepicker._curInst!=inst){$.datepicker._curInst.dpDiv.stop(true,true)}var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));inst.lastVal=null;$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim");var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;var borders=$.datepicker._getBorders(inst.dpDiv);inst.dpDiv.find("iframe.ui-datepicker-cover").css({left:-borders[0],top:-borders[1],width:inst.dpDiv.outerWidth(),height:inst.dpDiv.outerHeight()})};inst.dpDiv.zIndex($(input).zIndex()+1);if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim||"show"]((showAnim?duration:null),postProcess)}if(!showAnim||!duration){postProcess()}if(inst.input.is(":visible")&&!inst.input.is(":disabled")){inst.input.focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var self=this;var borders=$.datepicker._getBorders(inst.dpDiv);inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({left:-borders[0],top:-borders[1],width:inst.dpDiv.outerWidth(),height:inst.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst==$.datepicker._curInst&&$.datepicker._datepickerShowing&&inst.input&&inst.input.is(":visible")&&!inst.input.is(":disabled")){inst.input.focus()}},_getBorders:function(elem){var convert=function(value){return{thin:1,medium:2,thick:3}[value]||value};return[parseFloat(convert(elem.css("border-left-width"))),parseFloat(convert(elem.css("border-top-width")))]},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=document.documentElement.clientWidth+$(document).scrollLeft();var viewHeight=document.documentElement.clientHeight+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=Math.min(offset.left,(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0);offset.top-=Math.min(offset.top,(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(dpHeight+inputHeight):0);return offset},_findPos:function(obj){var inst=this._getInst(obj);var isRTL=this._get(inst,"isRTL");while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj[isRTL?"previousSibling":"nextSibling"]}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(this._datepickerShowing){var showAnim=this._get(inst,"showAnim");var duration=this._get(inst,"duration");var postProcess=function(){$.datepicker._tidyDialog(inst);this._curInst=null};if($.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide"))]((showAnim?duration:null),postProcess)}if(!showAnim){postProcess()}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if($target[0].id!=$.datepicker._mainDivId&&$target.parents("#"+$.datepicker._mainDivId).length==0&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker()}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input.focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{this._hideDatepicker();this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input.focus()}this._lastInput=null}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);var dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getTime());checkDate.setDate(checkDate.getDate()+4-(checkDate.getDay()||7));var time=checkDate.getTime();checkDate.setMonth(0);checkDate.setDate(1);return Math.floor(Math.round((time-checkDate)/86400000)/7)+1},parseDate:function(format,value,settings){if(format==null||value==null){throw"Invalid arguments"}value=(typeof value=="object"?value.toString():value+"");if(value==""){return null}var shortYearCutoff=(settings?settings.shortYearCutoff:null)||this._defaults.shortYearCutoff;var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var year=-1;var month=-1;var day=-1;var doy=-1;var literal=false;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var getNumber=function(match){lookAhead(match);var size=(match=="@"?14:(match=="!"?20:(match=="y"?4:(match=="o"?3:2))));var digits=new RegExp("^\\d{1,"+size+"}");var num=value.substring(iValue).match(digits);if(!num){throw"Missing number at position "+iValue}iValue+=num[0].length;return parseInt(num[0],10)};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);for(var i=0;i<names.length;i++){if(value.substr(iValue,names[i].length)==names[i]){iValue+=names[i].length;return i+1}}throw"Unknown name at position "+iValue};var checkLiteral=function(){if(value.charAt(iValue)!=format.charAt(iFormat)){throw"Unexpected literal at position "+iValue}iValue++};var iValue=0;for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{checkLiteral()}}else{switch(format.charAt(iFormat)){case"d":day=getNumber("d");break;case"D":getName("D",dayNamesShort,dayNames);break;case"o":doy=getNumber("o");break;case"m":month=getNumber("m");break;case"M":month=getName("M",monthNamesShort,monthNames);break;case"y":year=getNumber("y");break;case"@":var date=new Date(getNumber("@"));year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"!":var date=new Date((getNumber("!")-this._ticksTo1970)/10000);year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"'":if(lookAhead("'")){checkLiteral()}else{literal=true}break;default:checkLiteral()}}}if(year==-1){year=new Date().getFullYear()}else{if(year<100){year+=new Date().getFullYear()-new Date().getFullYear()%100+(year<=shortYearCutoff?0:-100)}}if(doy>-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(((1970-1)*365+Math.floor(1970/4)-Math.floor(1970/100)+Math.floor(1970/400))*24*60*60*10000000),formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var formatNumber=function(match,value,len){var num=""+value;if(lookAhead(match)){while(num.length<len){num="0"+num}}return num};var formatName=function(match,value,shortNames,longNames){return(lookAhead(match)?longNames[value]:shortNames[value])};var output="";var literal=false;if(date){for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{output+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":output+=formatNumber("d",date.getDate(),2);break;case"D":output+=formatName("D",date.getDay(),dayNamesShort,dayNames);break;case"o":output+=formatNumber("o",(date.getTime()-new Date(date.getFullYear(),0,0).getTime())/86400000,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"!":output+=date.getTime()*10000+this._ticksTo1970;break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{chars+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":case"m":case"y":case"@":chars+="0123456789";break;case"D":case"M":return null;case"'":if(lookAhead("'")){chars+="'"}else{literal=true}break;default:chars+=format.charAt(iFormat)}}}return chars},_get:function(inst,name){return inst.settings[name]!==undefined?inst.settings[name]:this._defaults[name]},_setDateFromField:function(inst,noDefault){if(inst.input.val()==inst.lastVal){return}var dateFormat=this._get(inst,"dateFormat");var dates=inst.lastVal=inst.input?inst.input.val():null;var date,defaultDate;date=defaultDate=this._getDefaultDate(inst);var settings=this._getFormatConfig(inst);try{date=this.parseDate(dateFormat,dates,settings)||defaultDate}catch(event){this.log(event);dates=(noDefault?"":dates)}inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();inst.currentDay=(dates?date.getDate():0);inst.currentMonth=(dates?date.getMonth():0);inst.currentYear=(dates?date.getFullYear():0);this._adjustInstDate(inst)},_getDefaultDate:function(inst){return this._restrictMinMax(inst,this._determineDate(inst,this._get(inst,"defaultDate"),new Date()))},_determineDate:function(inst,date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset){try{return $.datepicker.parseDate($.datepicker._get(inst,"dateFormat"),offset,$.datepicker._getFormatConfig(inst))}catch(e){}var date=(offset.toLowerCase().match(/^c/)?$.datepicker._getDate(inst):null)||new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,$.datepicker._getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,$.datepicker._getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,noChange){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._restrictMinMax(inst,this._determineDate(inst,date,new Date()));inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if((origMonth!=inst.selectedMonth||origYear!=inst.selectedYear)&&!noChange){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-(numMonths[0]*numMonths[1])+1,maxDate.getDate()));maxDraw=(minDate&&maxDraw<minDate?minDate:maxDraw);while(this._daylightSavingAdjust(new Date(drawYear,drawMonth,1))>maxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+inst.id+"', -"+stepMonths+", 'M');\" title=\""+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>"));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+inst.id+"', +"+stepMonths+", 'M');\" title=\""+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>"));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+dpuuid+'.datepicker._hideDatepicker();">'+this._get(inst,"closeText")+"</button>":"");var buttonPanel=(showButtonPanel)?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._gotoToday('#"+inst.id+"');\">"+currentText+"</button>":"")+(isRTL?"":controls)+"</div>":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var showWeek=this._get(inst,"showWeek");var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var selectOtherMonths=this._get(inst,"selectOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row<numMonths[0];row++){var group="";for(var col=0;col<numMonths[1];col++){var selectedDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,inst.selectedDay));var cornerClass=" ui-corner-all";var calender="";if(isMultiMonth){calender+='<div class="ui-datepicker-group';if(numMonths[1]>1){switch(col){case 0:calender+=" ui-datepicker-group-first";cornerClass=" ui-corner-"+(isRTL?"right":"left");break;case numMonths[1]-1:calender+=" ui-datepicker-group-last";cornerClass=" ui-corner-"+(isRTL?"left":"right");break;default:calender+=" ui-datepicker-group-middle";cornerClass="";break}}calender+='">'}calender+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+cornerClass+'">'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,row>0||col>0,monthNames,monthNamesShort)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var thead=(showWeek?'<th class="ui-datepicker-week-col">'+this._get(inst,"weekHeader")+"</th>":"");for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="<th"+((dow+firstDay+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+dayNames[day]+'">'+dayNamesMin[day]+"</span></th>"}calender+=thead+"</tr></thead><tbody>";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow<numRows;dRow++){calender+="<tr>";var tbody=(!showWeek?"":'<td class="ui-datepicker-week-col">'+this._get(inst,"calculateWeek")(printDate)+"</td>");for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=(otherMonth&&!selectOtherMonths)||!daySettings[0]||(minDate&&printDate<minDate)||(maxDate&&printDate>maxDate);tbody+='<td class="'+((dow+firstDay+6)%7>=5?" ui-datepicker-week-end":"")+(otherMonth?" ui-datepicker-other-month":"")+((printDate.getTime()==selectedDate.getTime()&&drawMonth==inst.selectedMonth&&inst._keyEvent)||(defaultDate.getTime()==printDate.getTime()&&defaultDate.getTime()==selectedDate.getTime())?" "+this._dayOverClass:"")+(unselectable?" "+this._unselectableClass+" ui-state-disabled":"")+(otherMonth&&!showOtherMonths?"":" "+daySettings[1]+(printDate.getTime()==currentDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":' onclick="DP_jQuery_'+dpuuid+".datepicker._selectDay('#"+inst.id+"',"+printDate.getMonth()+","+printDate.getFullYear()+', this);return false;"')+">"+(otherMonth&&!showOtherMonths?"&#xa0;":(unselectable?'<span class="ui-state-default">'+printDate.getDate()+"</span>":'<a class="ui-state-default'+(printDate.getTime()==today.getTime()?" ui-state-highlight":"")+(printDate.getTime()==currentDate.getTime()?" ui-state-active":"")+(otherMonth?" ui-priority-secondary":"")+'" href="#">'+printDate.getDate()+"</a>"))+"</td>";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+"</tr>"}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="</tbody></table>"+(isMultiMonth?"</div>"+((numMonths[0]>0&&col==numMonths[1]-1)?'<div class="ui-datepicker-row-break"></div>':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,secondary,monthNames,monthNamesShort){var changeMonth=this._get(inst,"changeMonth");var changeYear=this._get(inst,"changeYear");var showMonthAfterYear=this._get(inst,"showMonthAfterYear");var html='<div class="ui-datepicker-title">';var monthHtml="";if(secondary||!changeMonth){monthHtml+='<span class="ui-datepicker-month">'+monthNames[drawMonth]+"</span>"}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+inst.id+"', this, 'M');\" onclick=\"DP_jQuery_"+dpuuid+".datepicker._clickMonthYear('#"+inst.id+"');\">";for(var month=0;month<12;month++){if((!inMinYear||month>=minDate.getMonth())&&(!inMaxYear||month<=maxDate.getMonth())){monthHtml+='<option value="'+month+'"'+(month==drawMonth?' selected="selected"':"")+">"+monthNamesShort[month]+"</option>"}}monthHtml+="</select>"}if(!showMonthAfterYear){html+=monthHtml+(secondary||!(changeMonth&&changeYear)?"&#xa0;":"")}if(secondary||!changeYear){html+='<span class="ui-datepicker-year">'+drawYear+"</span>"}else{var years=this._get(inst,"yearRange").split(":");var thisYear=new Date().getFullYear();var determineYear=function(value){var year=(value.match(/c[+-].*/)?drawYear+parseInt(value.substring(1),10):(value.match(/[+-].*/)?thisYear+parseInt(value,10):parseInt(value,10)));return(isNaN(year)?thisYear:year)};var year=determineYear(years[0]);var endYear=Math.max(year,determineYear(years[1]||""));year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+inst.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+dpuuid+".datepicker._clickMonthYear('#"+inst.id+"');\">";for(;year<=endYear;year++){html+='<option value="'+year+'"'+(year==drawYear?' selected="selected"':"")+">"+year+"</option>"}html+="</select>"}html+=this._get(inst,"yearSuffix");if(showMonthAfterYear){html+=(secondary||!(changeMonth&&changeYear)?"&#xa0;":"")+monthHtml}html+="</div>";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._restrictMinMax(inst,this._daylightSavingAdjust(new Date(year,month,day)));inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_restrictMinMax:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&date<minDate?minDate:date);date=(maxDate&&date>maxDate?maxDate:date);return date},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax){return this._determineDate(inst,this._get(inst,minMax+"Date"),null)},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[0]*numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");return((!minDate||date.getTime()>=minDate.getTime())&&(!maxDate||date.getTime()<=maxDate.getTime()))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate"||options=="widget")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.8";window["DP_jQuery_"+dpuuid]=$})(jQuery);
\ No newline at end of file
+(function(d,G){function K(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
+"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
+"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
+minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}function E(a,b){d.extend(a,b);for(var c in b)if(b[c]==
+null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.7"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();
+f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
+_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
+b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
+""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
+c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
+true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});
+b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);
+this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",
+this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,
+function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:
+f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},
+e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);
+this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]?
+d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||
+a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,
+e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,
+"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},
+_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=
+d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,
+c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&
+d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find("iframe.ui-datepicker-cover");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",
+function(){d(this).removeClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=
+-1&&d(this).addClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,
+"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},
+_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-
+g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?
+b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},
+_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):
+0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=
+false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=
+d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);
+else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=
+a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,
+j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){var v=o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&v?4:p=="o"?3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,v,H){p=o(p)?H:v;for(v=0;v<p.length;v++)if(b.substr(s,p[v].length).toLowerCase()==p[v].toLowerCase()){s+=p[v].length;return v+1}throw"Unknown name at position "+s;},r=function(){if(b.charAt(s)!=
+a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(k)if(a.charAt(z)=="'"&&!o("'"))k=false;else r();else switch(a.charAt(z)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var w=new Date(m("@"));c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;case "!":w=new Date((m("!")-this._ticksTo1970)/1E4);c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;
+case "'":if(o("'"))r();else k=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw"Invalid date";return w},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",
+RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&a.charAt(k+1)==o)&&k++;
+return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",b.getMonth(),h,c);break;
+case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+=
+"0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=
+f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=
+(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,
+l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=
+a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),
+b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=
+this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+
+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+
+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>";j=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,
+"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=
+this._get(a,"monthNames"),w=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),v=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var L=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var M="",D=0;D<i[1];D++){var N=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-
+1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,C>0||D>0,z,w)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=
+(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=
+p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,J=B&&!H||!F[0]||k&&q<k||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==N.getTime()&&g==a.selectedMonth&&a._keyEvent||L.getTime()==q.getTime()&&L.getTime()==N.getTime()?" "+this._dayOverClass:"")+(J?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!v?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":
+""))+'"'+((!B||v)&&F[2]?' title="'+F[2]+'"':"")+(J?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!v?"&#xa0;":J?'<span class="ui-state-default">'+q.getDate()+"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==u.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=
+P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',
+o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&
+l)?"&#xa0;":""));a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+
+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";if(d.browser.mozilla)k+='<select class="ui-datepicker-year"><option value="'+c+'" selected="selected">'+c+"</option></select>";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?"&#xa0;":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=
+a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
+"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
+c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
+"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
+function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
+return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.7";window["DP_jQuery_"+y]=d})(jQuery);
diff --git a/misc/ui/jquery.ui.dialog.css b/misc/ui/jquery.ui.dialog.css
index d03fa855b1ef3b62d821aa7b25cf622e1afc6ea5..e167b663d75a5e116c69c66c43196cd95503584a 100644
--- a/misc/ui/jquery.ui.dialog.css
+++ b/misc/ui/jquery.ui.dialog.css
@@ -1,15 +1,23 @@
-/* $Id: jquery.ui.dialog.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.dialog.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Dialog
-----------------------------------*/
+/*
+ * jQuery UI Dialog 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
 .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
 .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative;  }
 .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } 
 .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
 .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
 .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
 .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
 .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
 .ui-draggable .ui-dialog-titlebar { cursor: move; }
diff --git a/misc/ui/jquery.ui.dialog.min.js b/misc/ui/jquery.ui.dialog.min.js
index 7d345c9217249b51a5ffcb8ff36a2214ceba9680..dcbe845c6268490902d068291e595aa5b0467e0b 100644
--- a/misc/ui/jquery.ui.dialog.min.js
+++ b/misc/ui/jquery.ui.dialog.min.js
@@ -1,21 +1,42 @@
-// $Id: jquery.ui.dialog.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.dialog.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Dialog 1.8
+ * jQuery UI Dialog 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Dialog
  *
  * Depends:
  *	jquery.ui.core.js
  *	jquery.ui.widget.js
- * jquery.ui.button.js
+ *  jquery.ui.button.js
  *	jquery.ui.draggable.js
  *	jquery.ui.mouse.js
  *	jquery.ui.position.js
  *	jquery.ui.resizable.js
  */
-(function(b){var a="ui-dialog ui-widget ui-widget-content ui-corner-all ";b.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},_create:function(){this.originalTitle=this.element.attr("title");var k=this,l=k.options,i=l.title||k.originalTitle||"&#160;",d=b.ui.dialog.getTitleId(k.element),j=(k.uiDialog=b("<div></div>")).appendTo(document.body).hide().addClass(a+l.dialogClass).css({zIndex:l.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(m){if(l.closeOnEscape&&m.keyCode&&m.keyCode===b.ui.keyCode.ESCAPE){k.close(m);m.preventDefault()}}).attr({role:"dialog","aria-labelledby":d}).mousedown(function(m){k.moveToTop(false,m)}),f=k.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(j),e=(k.uiDialogTitlebar=b("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(j),h=b('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(m){k.close(m);return false}).appendTo(e),g=(k.uiDialogTitlebarCloseText=b("<span></span>")).addClass("ui-icon ui-icon-closethick").text(l.closeText).appendTo(h),c=b("<span></span>").addClass("ui-dialog-title").attr("id",d).html(i).prependTo(e);if(b.isFunction(l.beforeclose)&&!b.isFunction(l.beforeClose)){l.beforeClose=l.beforeclose}e.find("*").add(e).disableSelection();if(l.draggable&&b.fn.draggable){k._makeDraggable()}if(l.resizable&&b.fn.resizable){k._makeResizable()}k._createButtons(l.buttons);k._isOpen=false;if(b.fn.bgiframe){j.bgiframe()}},_init:function(){if(this.options.autoOpen){this.open()}},destroy:function(){var c=this;if(c.overlay){c.overlay.destroy()}c.uiDialog.hide();c.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");c.uiDialog.remove();if(c.originalTitle){c.element.attr("title",c.originalTitle)}return c},widget:function(){return this.uiDialog},close:function(e){var c=this,d;if(false===c._trigger("beforeClose",e)){return}if(c.overlay){c.overlay.destroy()}c.uiDialog.unbind("keypress.ui-dialog");c._isOpen=false;if(c.options.hide){c.uiDialog.hide(c.options.hide,function(){c._trigger("close",e)})}else{c.uiDialog.hide();c._trigger("close",e)}b.ui.dialog.overlay.resize();if(c.options.modal){d=0;b(".ui-dialog").each(function(){if(this!==c.uiDialog[0]){d=Math.max(d,b(this).css("z-index"))}});b.ui.dialog.maxZ=d}return c},isOpen:function(){return this._isOpen},moveToTop:function(g,f){var c=this,e=c.options,d;if((e.modal&&!g)||(!e.stack&&!e.modal)){return c._trigger("focus",f)}if(e.zIndex>b.ui.dialog.maxZ){b.ui.dialog.maxZ=e.zIndex}if(c.overlay){b.ui.dialog.maxZ+=1;c.overlay.$el.css("z-index",b.ui.dialog.overlay.maxZ=b.ui.dialog.maxZ)}d={scrollTop:c.element.attr("scrollTop"),scrollLeft:c.element.attr("scrollLeft")};b.ui.dialog.maxZ+=1;c.uiDialog.css("z-index",b.ui.dialog.maxZ);c.element.attr(d);c._trigger("focus",f);return c},open:function(){if(this._isOpen){return}var d=this,e=d.options,c=d.uiDialog;d.overlay=e.modal?new b.ui.dialog.overlay(d):null;if(c.next().length){c.appendTo("body")}d._size();d._position(e.position);c.show(e.show);d.moveToTop(true);if(e.modal){c.bind("keypress.ui-dialog",function(h){if(h.keyCode!==b.ui.keyCode.TAB){return}var g=b(":tabbable",this),i=g.filter(":first"),f=g.filter(":last");if(h.target===f[0]&&!h.shiftKey){i.focus(1);return false}else{if(h.target===i[0]&&h.shiftKey){f.focus(1);return false}}})}b([]).add(c.find(".ui-dialog-content :tabbable:first")).add(c.find(".ui-dialog-buttonpane :tabbable:first")).add(c).filter(":first").focus();d._trigger("open");d._isOpen=true;return d},_createButtons:function(f){var e=this,c=false,d=b("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");e.uiDialog.find(".ui-dialog-buttonpane").remove();if(typeof f==="object"&&f!==null){b.each(f,function(){return !(c=true)})}if(c){b.each(f,function(g,i){var h=b('<button type="button"></button>').text(g).click(function(){i.apply(e.element[0],arguments)}).appendTo(d);if(b.fn.button){h.button()}});d.appendTo(e.uiDialog)}},_makeDraggable:function(){var c=this,f=c.options,g=b(document),e;function d(h){return{position:h.position,offset:h.offset}}c.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(h,i){e=f.height==="auto"?"auto":b(this).height();b(this).height(b(this).height()).addClass("ui-dialog-dragging");c._trigger("dragStart",h,d(i))},drag:function(h,i){c._trigger("drag",h,d(i))},stop:function(h,i){f.position=[i.position.left-g.scrollLeft(),i.position.top-g.scrollTop()];b(this).removeClass("ui-dialog-dragging").height(e);c._trigger("dragStop",h,d(i));b.ui.dialog.overlay.resize()}})},_makeResizable:function(h){h=(h===undefined?this.options.resizable:h);var d=this,g=d.options,c=d.uiDialog.css("position"),f=(typeof h==="string"?h:"n,e,s,w,se,sw,ne,nw");function e(i){return{originalPosition:i.originalPosition,originalSize:i.originalSize,position:i.position,size:i.size}}d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:g.maxWidth,maxHeight:g.maxHeight,minWidth:g.minWidth,minHeight:d._minHeight(),handles:f,start:function(i,j){b(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",i,e(j))},resize:function(i,j){d._trigger("resize",i,e(j))},stop:function(i,j){b(this).removeClass("ui-dialog-resizing");g.height=b(this).height();g.width=b(this).width();d._trigger("resizeStop",i,e(j));b.ui.dialog.overlay.resize()}}).css("position",c).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var c=this.options;if(c.height==="auto"){return c.minHeight}else{return Math.min(c.minHeight,c.height)}},_position:function(d){var e=[],f=[0,0],c;d=d||b.ui.dialog.prototype.options.position;if(typeof d==="string"||(typeof d==="object"&&"0" in d)){e=d.split?d.split(" "):[d[0],d[1]];if(e.length===1){e[1]=e[0]}b.each(["left","top"],function(h,g){if(+e[h]===e[h]){f[h]=e[h];e[h]=g}})}else{if(typeof d==="object"){if("left" in d){e[0]="left";f[0]=d.left}else{if("right" in d){e[0]="right";f[0]=-d.right}}if("top" in d){e[1]="top";f[1]=d.top}else{if("bottom" in d){e[1]="bottom";f[1]=-d.bottom}}}}c=this.uiDialog.is(":visible");if(!c){this.uiDialog.show()}this.uiDialog.css({top:0,left:0}).position({my:e.join(" "),at:e.join(" "),offset:f.join(" "),of:window,collision:"fit",using:function(h){var g=b(this).css(h).offset().top;if(g<0){b(this).css("top",h.top-g)}}});if(!c){this.uiDialog.hide()}},_setOption:function(f,g){var d=this,c=d.uiDialog,h=c.is(":data(resizable)"),e=false;switch(f){case"beforeclose":f="beforeClose";break;case"buttons":d._createButtons(g);break;case"closeText":d.uiDialogTitlebarCloseText.text(""+g);break;case"dialogClass":c.removeClass(d.options.dialogClass).addClass(a+g);break;case"disabled":if(g){c.addClass("ui-dialog-disabled")}else{c.removeClass("ui-dialog-disabled")}break;case"draggable":if(g){d._makeDraggable()}else{c.draggable("destroy")}break;case"height":e=true;break;case"maxHeight":if(h){c.resizable("option","maxHeight",g)}e=true;break;case"maxWidth":if(h){c.resizable("option","maxWidth",g)}e=true;break;case"minHeight":if(h){c.resizable("option","minHeight",g)}e=true;break;case"minWidth":if(h){c.resizable("option","minWidth",g)}e=true;break;case"position":d._position(g);break;case"resizable":if(h&&!g){c.resizable("destroy")}if(h&&typeof g==="string"){c.resizable("option","handles",g)}if(!h&&g!==false){d._makeResizable(g)}break;case"title":b(".ui-dialog-title",d.uiDialogTitlebar).html(""+(g||"&#160;"));break;case"width":e=true;break}b.Widget.prototype._setOption.apply(d,arguments);if(e){d._size()}},_size:function(){var d=this.options,c;this.element.css("width","auto").hide();c=this.uiDialog.css({height:"auto",width:d.width}).height();this.element.css(d.height==="auto"?{minHeight:Math.max(d.minHeight-c,0),height:"auto"}:{minHeight:0,height:Math.max(d.height-c,0)}).show();if(this.uiDialog.is(":data(resizable)")){this.uiDialog.resizable("option","minHeight",this._minHeight())}}});b.extend(b.ui.dialog,{version:"1.8",uuid:0,maxZ:0,getTitleId:function(c){var d=c.attr("id");if(!d){this.uuid+=1;d=this.uuid}return"ui-dialog-title-"+d},overlay:function(c){this.$el=b.ui.dialog.overlay.create(c)}});b.extend(b.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:b.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(c){return c+".dialog-overlay"}).join(" "),create:function(d){if(this.instances.length===0){setTimeout(function(){if(b.ui.dialog.overlay.instances.length){b(document).bind(b.ui.dialog.overlay.events,function(e){return(b(e.target).zIndex()>=b.ui.dialog.overlay.maxZ)})}},1);b(document).bind("keydown.dialog-overlay",function(e){if(d.options.closeOnEscape&&e.keyCode&&e.keyCode===b.ui.keyCode.ESCAPE){d.close(e);e.preventDefault()}});b(window).bind("resize.dialog-overlay",b.ui.dialog.overlay.resize)}var c=(this.oldInstances.pop()||b("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});if(b.fn.bgiframe){c.bgiframe()}this.instances.push(c);return c},destroy:function(c){this.oldInstances.push(this.instances.splice(b.inArray(c,this.instances),1)[0]);if(this.instances.length===0){b([document,window]).unbind(".dialog-overlay")}c.remove();var d=0;b.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var d,c;if(b.browser.msie&&b.browser.version<7){d=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(d<c){return b(window).height()+"px"}else{return d+"px"}}else{return b(document).height()+"px"}},width:function(){var c,d;if(b.browser.msie&&b.browser.version<7){c=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);d=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);if(c<d){return b(window).width()+"px"}else{return c+"px"}}else{return b(document).width()+"px"}},resize:function(){var c=b([]);b.each(b.ui.dialog.overlay.instances,function(){c=c.add(this)});c.css({width:0,height:0}).css({width:b.ui.dialog.overlay.width(),height:b.ui.dialog.overlay.height()})}});b.extend(b.ui.dialog.overlay.prototype,{destroy:function(){b.ui.dialog.overlay.destroy(this.$el)}})}(jQuery));
\ No newline at end of file
+(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&
+c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||"&#160;",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",
+-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role",
+"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=
+b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&
+a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index");
+isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);
+d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});
+c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,
+h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('<button type="button"></button>').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=
+d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,
+position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,
+h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===
+1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in
+l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");
+break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||"&#160;"));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=
+this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&&
+this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.7",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===
+0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),
+height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
+b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,
+function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
diff --git a/misc/ui/jquery.ui.draggable.min.js b/misc/ui/jquery.ui.draggable.min.js
index a8f4f38cbb85c93444681f83183a8cae72e584b2..28e072c269f772064d500bfea84574d1439a57f1 100644
--- a/misc/ui/jquery.ui.draggable.min.js
+++ b/misc/ui/jquery.ui.draggable.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.draggable.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.draggable.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Draggable 1.8
+ * jQuery UI Draggable 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Draggables
  *
@@ -14,4 +14,39 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  */
-(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;(c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt));if(c.containment){this._setContainment()}if(this._trigger("start",b)===false){this._clear();return false}this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();if(this._trigger("drag",b,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode){return false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){if(b._trigger("stop",c)!==false){b._clear()}})}else{if(this._trigger("stop",c)!==false){this._clear()}}return false},cancel:function(){if(this.helper.is(".ui-draggable-dragging")){this._mouseUp({})}else{this._clear()}return this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(typeof b=="string"){b=b.split(" ")}if(a.isArray(b)){b={left:+b[0],top:+b[1]||0}}if("left" in b){this.offset.click.left=b.left+this.margins.left}if("right" in b){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if("top" in b){this.offset.click.top=b.top+this.margins.top}if("bottom" in b){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,c,d){d=d||this._uiHash();a.ui.plugin.call(this,b,[c,d]);if(b=="drag"){this.positionAbs=this._convertPositionTo("absolute")}return a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(b){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});a.extend(a.ui.draggable,{version:"1.8"});a.ui.plugin.add("draggable","connectToSortable",{start:function(c,e){var d=a(this).data("draggable"),f=d.options,b=a.extend({},e,{item:d.element});d.sortables=[];a(f.connectToSortable).each(function(){var g=a.data(this,"sortable");if(g&&!g.options.disabled){d.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",c,b)}})},stop:function(c,e){var d=a(this).data("draggable"),b=a.extend({},e,{item:d.element});a.each(d.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;d.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=true}this.instance._mouseStop(c);this.instance.options.helper=this.instance.options._helper;if(d.options.helper=="original"){this.instance.currentItem.css({top:"auto",left:"auto"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",c,b)}})},drag:function(c,f){var e=a(this).data("draggable"),b=this;var d=function(i){var n=this.offset.click.top,m=this.offset.click.left;var g=this.positionAbs.top,k=this.positionAbs.left;var j=i.height,l=i.width;var p=i.top,h=i.left;return a.ui.isOver(g+n,k+m,p,h,j,l)};a.each(e.sortables,function(g){this.instance.positionAbs=e.positionAbs;this.instance.helperProportions=e.helperProportions;this.instance.offset.click=e.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(b).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return f.helper[0]};c.target=this.instance.currentItem[0];this.instance._mouseCapture(c,true);this.instance._mouseStart(c,true,true);this.instance.offset.click.top=e.offset.click.top;this.instance.offset.click.left=e.offset.click.left;this.instance.offset.parent.left-=e.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=e.offset.parent.top-this.instance.offset.parent.top;e._trigger("toSortable",c);e.dropped=this.instance.element;e.currentItem=e.element;this.instance.fromOutside=e}if(this.instance.currentItem){this.instance._mouseDrag(c)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",c,this.instance._uiHash(this.instance));this.instance._mouseStop(c,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}e._trigger("fromSortable",c);e.dropped=false}}})}});a.ui.plugin.add("draggable","cursor",{start:function(c,d){var b=a("body"),e=a(this).data("draggable").options;if(b.css("cursor")){e._cursor=b.css("cursor")}b.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._cursor){a("body").css("cursor",d._cursor)}}});a.ui.plugin.add("draggable","iframeFix",{start:function(b,c){var d=a(this).data("draggable").options;a(d.iframeFix===true?"iframe":d.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop+f.scrollSpeed}else{if(d.pageY-c.overflowOffset.top<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop-f.scrollSpeed}}}if(!f.axis||f.axis!="y"){if((c.overflowOffset.left+c.scrollParent[0].offsetWidth)-d.pageX<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft+f.scrollSpeed}else{if(d.pageX-c.overflowOffset.left<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft-f.scrollSpeed}}}}else{if(!f.axis||f.axis!="x"){if(d.pageY-a(document).scrollTop()<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-f.scrollSpeed)}else{if(a(window).height()-(d.pageY-a(document).scrollTop())<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+f.scrollSpeed)}}}if(!f.axis||f.axis!="y"){if(d.pageX-a(document).scrollLeft()<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-f.scrollSpeed)}else{if(a(window).width()-(d.pageX-a(document).scrollLeft())<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+f.scrollSpeed)}}}}if(b!==false&&a.ui.ddmanager&&!f.dropBehaviour){a.ui.ddmanager.prepareOffsets(c,d)}}});a.ui.plugin.add("draggable","snap",{start:function(c,d){var b=a(this).data("draggable"),e=b.options;b.snapElements=[];a(e.snap.constructor!=String?(e.snap.items||":data(draggable)"):e.snap).each(function(){var g=a(this);var f=g.offset();if(this!=b.element[0]){b.snapElements.push({item:this,width:g.outerWidth(),height:g.outerHeight(),top:f.top,left:f.left})}})},drag:function(u,p){var g=a(this).data("draggable"),q=g.options;var y=q.snapTolerance;var x=p.offset.left,w=x+g.helperProportions.width,f=p.offset.top,e=f+g.helperProportions.height;for(var v=g.snapElements.length-1;v>=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y<x&&x<n+y&&m-y<f&&f<A+y)||(s-y<x&&x<n+y&&m-y<e&&e<A+y)||(s-y<w&&w<n+y&&m-y<f&&f<A+y)||(s-y<w&&w<n+y&&m-y<e&&e<A+y))){if(g.snapElements[v].snapping){(g.options.snap.release&&g.options.snap.release.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=false;continue}if(q.snapMode!="inner"){var c=Math.abs(m-e)<=y;var z=Math.abs(A-f)<=y;var j=Math.abs(s-w)<=y;var k=Math.abs(n-x)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m-g.helperProportions.height,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s-g.helperProportions.width}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n}).left-g.margins.left}}var h=(c||z||j||k);if(q.snapMode!="outer"){var c=Math.abs(m-f)<=y;var z=Math.abs(A-e)<=y;var j=Math.abs(s-x)<=y;var k=Math.abs(n-w)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A-g.helperProportions.height,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n-g.helperProportions.width}).left-g.margins.left}}if(!g.snapElements[v].snapping&&(c||z||j||k||h)){(g.options.snap.snap&&g.options.snap.snap.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=(c||z||j||k||h)}}});a.ui.plugin.add("draggable","stack",{start:function(c,d){var f=a(this).data("draggable").options;var e=a.makeArray(a(f.stack)).sort(function(h,g){return(parseInt(a(h).css("zIndex"),10)||0)-(parseInt(a(g).css("zIndex"),10)||0)});if(!e.length){return}var b=parseInt(e[0].style.zIndex)||0;a(e).each(function(g){this.style.zIndex=b+g});this[0].style.zIndex=b+e.length}});a.ui.plugin.add("draggable","zIndex",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("zIndex")){e._zIndex=b.css("zIndex")}b.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._zIndex){a(c.helper).css("zIndex",d._zIndex)}}})})(jQuery);
\ No newline at end of file
+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
+this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
+d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
+this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,
+b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
+a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
+0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
+this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
+(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
+"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?
+0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),
+10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==
+Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
+f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;
+if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/
+b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-
+this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=
+this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.7"});
+d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=
+0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=
+c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,
+true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=
+0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=
+a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},
+stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=
+document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-
+c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-
+(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable",
+"snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=
+c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",
+{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,
+left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,
+a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,
+b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
diff --git a/misc/ui/jquery.ui.droppable.min.js b/misc/ui/jquery.ui.droppable.min.js
index 2eecbd503cefd34444f7caea6d4f662ac795920c..a5e739b8a24e7d3637a856fff04c3e7a9db368ab 100644
--- a/misc/ui/jquery.ui.droppable.min.js
+++ b/misc/ui/jquery.ui.droppable.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.droppable.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.droppable.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Droppable 1.8
+ * jQuery UI Droppable 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Droppables
  *
@@ -15,4 +15,14 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.draggable.js
  */
-(function(a){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var c=this.options,b=c.accept;this.isover=0;this.isout=1;this.accept=a.isFunction(b)?b:function(e){return e.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[c.scope]=a.ui.ddmanager.droppables[c.scope]||[];a.ui.ddmanager.droppables[c.scope].push(this);(c.addClasses&&this.element.addClass("ui-droppable"))},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++){if(b[c]==this){b.splice(c,1)}}this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(b,c){if(b=="accept"){this.accept=a.isFunction(c)?c:function(e){return e.is(c)}}a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass)}(b&&this._trigger("activate",c,this.ui(b)))},_deactivate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}(b&&this._trigger("deactivate",c,this.ui(b)))},_over:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass)}this._trigger("over",c,this.ui(b))}},_out:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("out",c,this.ui(b))}},_drop:function(c,d){var b=d||a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return false}var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var f=a.data(this,"droppable");if(f.options.greedy&&!f.options.disabled&&f.options.scope==b.options.scope&&f.accept.call(f.element[0],(b.currentItem||b.element))&&a.ui.intersect(b,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e){return false}if(this.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("drop",c,this.ui(b));return this.element}return false},ui:function(b){return{draggable:(b.currentItem||b.element),helper:b.helper,position:b.position,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.8"});a.ui.intersect=function(q,j,o){if(!j.offset){return false}var e=(q.positionAbs||q.position.absolute).left,d=e+q.helperProportions.width,n=(q.positionAbs||q.position.absolute).top,m=n+q.helperProportions.height;var g=j.offset.left,c=g+j.proportions.width,p=j.offset.top,k=p+j.proportions.height;switch(o){case"fit":return(g<e&&d<c&&p<n&&m<k);break;case"intersect":return(g<e+(q.helperProportions.width/2)&&d-(q.helperProportions.width/2)<c&&p<n+(q.helperProportions.height/2)&&m-(q.helperProportions.height/2)<k);break;case"pointer":var h=((q.positionAbs||q.position.absolute).left+(q.clickOffset||q.offset.click).left),i=((q.positionAbs||q.position.absolute).top+(q.clickOffset||q.offset.click).top),f=a.ui.isOver(i,h,p,g,j.proportions.height,j.proportions.width);return f;break;case"touch":return((n>=p&&n<=k)||(m>=p&&m<=k)||(n<p&&m>k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e<g&&d>c));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope]||[];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d<b.length;d++){if(b[d].options.disabled||(e&&!b[d].accept.call(b[d].element[0],(e.currentItem||e.element)))){continue}for(var c=0;c<h.length;c++){if(h[c]==b[d].element[0]){b[d].proportions.height=0;continue droppablesLoop}}b[d].visible=b[d].element.css("display")!="none";if(!b[d].visible){continue}b[d].offset=b[d].element.offset();b[d].proportions={width:b[d].element[0].offsetWidth,height:b[d].element[0].offsetHeight};if(f=="mousedown"){b[d]._activate.call(b[d],g)}}},drop:function(b,c){var d=false;a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options){return}if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)){d=d||this._drop.call(this,c)}if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],(b.currentItem||b.element))){this.isout=1;this.isover=0;this._deactivate.call(this,c)}});return d},drag:function(b,c){if(b.options.refreshPositions){a.ui.ddmanager.prepareOffsets(b,c)}a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible){return}var e=a.ui.intersect(b,this,this.options.tolerance);var g=!e&&this.isover==1?"isout":(e&&this.isover==0?"isover":null);if(!g){return}var f;if(this.options.greedy){var d=this.element.parents(":data(droppable):eq(0)");if(d.length){f=a.data(d[0],"droppable");f.greedyChild=(g=="isover"?1:0)}}if(f&&g=="isover"){f.isover=0;f.isout=1;f._out.call(f,c)}this[g]=1;this[g=="isout"?"isover":"isout"]=0;this[g=="isover"?"_over":"_out"].call(this,c);if(f&&g=="isout"){f.isout=0;f.isover=1;f._over.call(f,c)}})}}})(jQuery);
\ No newline at end of file
+(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
+a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
+this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
+this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
+d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
+a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.7"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
+switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
+i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
+"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
+a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
+d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
diff --git a/misc/ui/jquery.ui.mouse.min.js b/misc/ui/jquery.ui.mouse.min.js
index 5078d8b8fc653837f19a8a221f9950f3b47e3e56..dfa32c922c5717e8e81a9910686d1f8cd52f07e9 100644
--- a/misc/ui/jquery.ui.mouse.min.js
+++ b/misc/ui/jquery.ui.mouse.min.js
@@ -1,15 +1,19 @@
-// $Id: jquery.ui.mouse.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.mouse.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*!
- * jQuery UI Mouse 1.8
+ * jQuery UI Mouse 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Mouse
  *
  * Depends:
  *	jquery.ui.widget.js
  */
-(function(a){a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(c){return b._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(b._preventClickEvent){b._preventClickEvent=false;c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(d){d.originalEvent=d.originalEvent||{};if(d.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(d));this._mouseDownEvent=d;var c=this,e=(d.which==1),b=(typeof this.options.cancel=="string"?a(d.target).parents().add(d.target).filter(this.options.cancel).length:false);if(!e||b||!this._mouseCapture(d)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(d)!==false);if(!this._mouseStarted){d.preventDefault();return true}}this._mouseMoveDelegate=function(f){return c._mouseMove(f)};this._mouseUpDelegate=function(f){return c._mouseUp(f)};a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(a.browser.safari||d.preventDefault());d.originalEvent.mouseHandled=true;return true},_mouseMove:function(b){if(a.browser.msie&&!b.button){return this._mouseUp(b)}if(this._mouseStarted){this._mouseDrag(b);return b.preventDefault()}if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,b)!==false);(this._mouseStarted?this._mouseDrag(b):this._mouseUp(b))}return !this._mouseStarted},_mouseUp:function(b){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(b.target==this._mouseDownEvent.target);this._mouseStop(b)}return false},_mouseDistanceMet:function(b){return(Math.max(Math.abs(this._mouseDownEvent.pageX-b.pageX),Math.abs(this._mouseDownEvent.pageY-b.pageY))>=this.options.distance)},_mouseDelayMet:function(b){return this.mouseDelayMet},_mouseStart:function(b){},_mouseDrag:function(b){},_mouseStop:function(b){},_mouseCapture:function(b){return true}})})(jQuery);
\ No newline at end of file
+(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(true===c.data(b.target,a.widgetName+".preventClickEvent")){c.removeData(b.target,a.widgetName+".preventClickEvent");b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=
+a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);
+return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent",
+true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
diff --git a/misc/ui/jquery.ui.position.min.js b/misc/ui/jquery.ui.position.min.js
index 91e610d8dfa39aef9ff74082e1d077f8a32a720b..5d47efbd9de8ad7dee7b4a742caf71b7f6c8a08e 100644
--- a/misc/ui/jquery.ui.position.min.js
+++ b/misc/ui/jquery.ui.position.min.js
@@ -1,12 +1,18 @@
-// $Id: jquery.ui.position.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.position.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Position 1.8
+ * jQuery UI Position 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Position
  */
-(function(f){f.ui=f.ui||{};var c=/left|center|right/,e="center",d=/top|center|bottom/,g="center",a=f.fn.position,b=f.fn.offset;f.fn.position=function(i){if(!i||!i.of){return a.apply(this,arguments)}i=f.extend({},i);var l=f(i.of),n=(i.collision||"flip").split(" "),m=i.offset?i.offset.split(" "):[0,0],k,h,j;if(i.of.nodeType===9){k=l.width();h=l.height();j={top:0,left:0}}else{if(i.of.scrollTo&&i.of.document){k=l.width();h=l.height();j={top:l.scrollTop(),left:l.scrollLeft()}}else{if(i.of.preventDefault){i.at="left top";k=h=0;j={top:i.of.pageY,left:i.of.pageX}}else{k=l.outerWidth();h=l.outerHeight();j=l.offset()}}}f.each(["my","at"],function(){var o=(i[this]||"").split(" ");if(o.length===1){o=c.test(o[0])?o.concat([g]):d.test(o[0])?[e].concat(o):[e,g]}o[0]=c.test(o[0])?o[0]:e;o[1]=d.test(o[1])?o[1]:g;i[this]=o});if(n.length===1){n[1]=n[0]}m[0]=parseInt(m[0],10)||0;if(m.length===1){m[1]=m[0]}m[1]=parseInt(m[1],10)||0;if(i.at[0]==="right"){j.left+=k}else{if(i.at[0]===e){j.left+=k/2}}if(i.at[1]==="bottom"){j.top+=h}else{if(i.at[1]===g){j.top+=h/2}}j.left+=m[0];j.top+=m[1];return this.each(function(){var r=f(this),q=r.outerWidth(),p=r.outerHeight(),o=f.extend({},j);if(i.my[0]==="right"){o.left-=q}else{if(i.my[0]===e){o.left-=q/2}}if(i.my[1]==="bottom"){o.top-=p}else{if(i.my[1]===g){o.top-=p/2}}f.each(["left","top"],function(t,s){if(f.ui.position[n[t]]){f.ui.position[n[t]][s](o,{targetWidth:k,targetHeight:h,elemWidth:q,elemHeight:p,offset:m,my:i.my,at:i.at})}});if(f.fn.bgiframe){r.bgiframe()}r.offset(f.extend(o,{using:i.using}))})};f.ui.position={fit:{left:function(h,i){var k=f(window),j=h.left+i.elemWidth-k.width()-k.scrollLeft();h.left=j>0?h.left-j:Math.max(0,h.left)},top:function(h,i){var k=f(window),j=h.top+i.elemHeight-k.height()-k.scrollTop();h.top=j>0?h.top-j:Math.max(0,h.top)}},flip:{left:function(i,j){if(j.at[0]==="center"){return}var l=f(window),k=i.left+j.elemWidth-l.width()-l.scrollLeft(),h=j.my[0]==="left"?-j.elemWidth:j.my[0]==="right"?j.elemWidth:0,m=-2*j.offset[0];i.left+=i.left<0?h+j.targetWidth+m:k>0?h-j.targetWidth+m:0},top:function(i,k){if(k.at[1]==="center"){return}var m=f(window),l=i.top+k.elemHeight-m.height()-m.scrollTop(),h=k.my[1]==="top"?-k.elemHeight:k.my[1]==="bottom"?k.elemHeight:0,j=k.at[1]==="top"?k.targetHeight:-k.targetHeight,n=-2*k.offset[1];i.top+=i.top<0?h+k.targetHeight+n:l>0?h+j+n:0}}};if(!f.offset.setOffset){f.offset.setOffset=function(l,i){if(/static/.test(f.curCSS(l,"position"))){l.style.position="relative"}var k=f(l),n=k.offset(),h=parseInt(f.curCSS(l,"top",true),10)||0,m=parseInt(f.curCSS(l,"left",true),10)||0,j={top:(i.top-n.top)+h,left:(i.left-n.left)+m};if("using" in i){i.using.call(l,j)}else{k.css(j)}};f.fn.offset=function(h){var i=this[0];if(!i||!i.ownerDocument){return null}if(h){return this.each(function(){f.offset.setOffset(this,h)})}return b.call(this)}}}(jQuery));
\ No newline at end of file
+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+parseInt(c.curCSS(this,"marginRight",true))||0,w=m+q+parseInt(c.curCSS(this,"marginBottom",true))||0,i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=m/2;
+i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
diff --git a/misc/ui/jquery.ui.progressbar.css b/misc/ui/jquery.ui.progressbar.css
index a19bb38936967388d3ef8d17dc8ada1fd714b079..57a7a0bb2f864cbf97902692e2e382dd3adae221 100644
--- a/misc/ui/jquery.ui.progressbar.css
+++ b/misc/ui/jquery.ui.progressbar.css
@@ -1,6 +1,13 @@
-/* $Id: jquery.ui.progressbar.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.progressbar.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Progressbar
-----------------------------------*/
+/*
+ * jQuery UI Progressbar 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
 .ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
diff --git a/misc/ui/jquery.ui.progressbar.min.js b/misc/ui/jquery.ui.progressbar.min.js
index 26a873048ecfead9a4433d79f48a637d2bc4d359..4ac85b622abacbaffdd9e877182c662578b9626a 100644
--- a/misc/ui/jquery.ui.progressbar.min.js
+++ b/misc/ui/jquery.ui.progressbar.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.progressbar.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.progressbar.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Progressbar 1.8
+ * jQuery UI Progressbar 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Progressbar
  *
@@ -13,4 +13,6 @@
  *   jquery.ui.core.js
  *   jquery.ui.widget.js
  */
-(function(a){a.widget("ui.progressbar",{options:{value:0},_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");this.valueDiv.remove();a.Widget.prototype.destroy.apply(this,arguments)},value:function(b){if(b===undefined){return this._value()}this._setOption("value",b);return this},_setOption:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change");break}a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var b=this.options.value;if(typeof b!=="number"){b=0}if(b<this._valueMin()){b=this._valueMin()}if(b>this._valueMax()){b=this._valueMax()}return b},_valueMin:function(){return 0},_valueMax:function(){return 100},_refreshValue:function(){var b=this.value();this.valueDiv[b===this._valueMax()?"addClass":"removeClass"]("ui-corner-right").width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.8"})})(jQuery);
\ No newline at end of file
+(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
+this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*
+this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.7"})})(jQuery);
diff --git a/misc/ui/jquery.ui.resizable.css b/misc/ui/jquery.ui.resizable.css
index 1feea8a14d814fdf62e833926f3f9868c91a3c48..f9585811cce2fdf8956d1615d6303fd49d8ac1e2 100644
--- a/misc/ui/jquery.ui.resizable.css
+++ b/misc/ui/jquery.ui.resizable.css
@@ -1,7 +1,14 @@
-/* $Id: jquery.ui.resizable.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.resizable.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Resizable
-----------------------------------*/
+/*
+ * jQuery UI Resizable 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
 .ui-resizable { position: relative;}
 .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
 .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
@@ -12,4 +19,4 @@
 .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
 .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
 .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
diff --git a/misc/ui/jquery.ui.resizable.min.js b/misc/ui/jquery.ui.resizable.min.js
index 8d73f5c8233e8f512d1a62f59a39dae8b2d447c9..4cb39c612be1d1519e5bfc0d323828f40953035d 100644
--- a/misc/ui/jquery.ui.resizable.min.js
+++ b/misc/ui/jquery.ui.resizable.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.resizable.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.resizable.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Resizable 1.8
+ * jQuery UI Resizable 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Resizables
  *
@@ -14,4 +14,36 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  */
-(function(c){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.after(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement);return this},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return !this.options.disabled&&f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8"});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),h=d.options;var g=function(i){c(i).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(h.alsoResize)=="object"&&!h.alsoResize.parentNode){if(h.alsoResize.length){h.alsoResize=h.alsoResize[0];g(h.alsoResize)}else{c.each(h.alsoResize,function(i,j){g(i)})}}else{g(h.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);
\ No newline at end of file
+(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
+_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
+top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
+this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
+nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
+if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
+d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
+this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
+this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
+b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
+f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
+b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
+a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
+k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
+c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
+this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
+arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
+{version:"1.8.7"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
+function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
+(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
+false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
+a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
+b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
+"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
+f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
+a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
+e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
+height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
+d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
diff --git a/misc/ui/jquery.ui.selectable.css b/misc/ui/jquery.ui.selectable.css
new file mode 100644
index 0000000000000000000000000000000000000000..688d8ae91e31a1d9fe7ec4d6233aef06555f0a06
--- /dev/null
+++ b/misc/ui/jquery.ui.selectable.css
@@ -0,0 +1,12 @@
+/* $Id: jquery.ui.selectable.css,v 1.2 2011/01/03 00:03:35 webchick Exp $ */
+
+/*
+ * jQuery UI Selectable 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
diff --git a/misc/ui/jquery.ui.selectable.min.js b/misc/ui/jquery.ui.selectable.min.js
index 80fdf073e78c4c9e3a1a36f01b1f75bd56d8b57d..d5402bdb79456b702211ae7458f398df2e51af96 100644
--- a/misc/ui/jquery.ui.selectable.min.js
+++ b/misc/ui/jquery.ui.selectable.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.selectable.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.selectable.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Selectable 1.8
+ * jQuery UI Selectable 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Selectables
  *
@@ -14,4 +14,11 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  */
-(function(a){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.right<d||j.top>g||j.bottom<h))}else{if(e.tolerance=="fit"){k=(j.left>d&&j.right<b&&j.top>h&&j.bottom<g)}}if(k){if(j.selected){j.$element.removeClass("ui-selected");j.selected=false}if(j.unselecting){j.$element.removeClass("ui-unselecting");j.unselecting=false}if(!j.selecting){j.$element.addClass("ui-selecting");j.selecting=true;c._trigger("selecting",i,{selecting:j.element})}}else{if(j.selecting){if(i.metaKey&&j.startselected){j.$element.removeClass("ui-selecting");j.selecting=false;j.$element.addClass("ui-selected");j.selected=true}else{j.$element.removeClass("ui-selecting");j.selecting=false;if(j.startselected){j.$element.addClass("ui-unselecting");j.unselecting=true}c._trigger("unselecting",i,{unselecting:j.element})}}if(j.selected){if(!i.metaKey&&!j.startselected){j.$element.removeClass("ui-selected");j.selected=false;j.$element.addClass("ui-unselecting");j.unselecting=true;c._trigger("unselecting",i,{unselecting:j.element})}}}});return false},_mouseStop:function(d){var b=this;this.dragged=false;var c=this.options;a(".ui-unselecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-unselecting");e.unselecting=false;e.startselected=false;b._trigger("unselected",d,{unselected:e.element})});a(".ui-selecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-selecting").addClass("ui-selected");e.selecting=false;e.selected=true;e.startselected=true;b._trigger("selected",d,{selected:e.element})});this._trigger("stop",d);this.helper.remove();return false}});a.extend(a.ui.selectable,{version:"1.8"})})(jQuery);
\ No newline at end of file
+(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
+selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
+c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
+c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
+this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
+a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
+!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
+e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.7"})})(jQuery);
diff --git a/misc/ui/jquery.ui.slider.css b/misc/ui/jquery.ui.slider.css
index 58437ec6aa4266dff613dffe13e689474417f0dc..319603d0e31755d60863d7d6298a44172acaff2a 100644
--- a/misc/ui/jquery.ui.slider.css
+++ b/misc/ui/jquery.ui.slider.css
@@ -1,7 +1,14 @@
-/* $Id: jquery.ui.slider.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.slider.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Slider
-----------------------------------*/
+/*
+ * jQuery UI Slider 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
 .ui-slider { position: relative; text-align: left; }
 .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
 .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
@@ -16,4 +23,4 @@
 .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
 .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
 .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }
\ No newline at end of file
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
diff --git a/misc/ui/jquery.ui.slider.min.js b/misc/ui/jquery.ui.slider.min.js
index 10e741beca485173d54e6f5cbe5a77a32e1a5cf8..1867be180af5a71bca95bb1dffab800e3448d1ef 100644
--- a/misc/ui/jquery.ui.slider.min.js
+++ b/misc/ui/jquery.ui.slider.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.slider.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.slider.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Slider 1.8
+ * jQuery UI Slider 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Slider
  *
@@ -14,4 +14,22 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  */
-(function(b){var a=5;b.widget("ui.slider",b.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var c=this,d=this.options;this._keySliding=false;this._mouseSliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");if(d.disabled){this.element.addClass("ui-slider-disabled ui-disabled")}this.range=b([]);if(d.range){if(d.range===true){this.range=b("<div></div>");if(!d.values){d.values=[this._valueMin(),this._valueMin()]}if(d.values.length&&d.values.length!=2){d.values=[d.values[0],d.values[0]]}}else{this.range=b("<div></div>")}this.range.appendTo(this.element).addClass("ui-slider-range");if(d.range=="min"||d.range=="max"){this.range.addClass("ui-slider-range-"+d.range)}this.range.addClass("ui-widget-header")}if(b(".ui-slider-handle",this.element).length==0){b('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}if(d.values&&d.values.length){while(b(".ui-slider-handle",this.element).length<d.values.length){b('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=b(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(e){e.preventDefault()}).hover(function(){if(!d.disabled){b(this).addClass("ui-state-hover")}},function(){b(this).removeClass("ui-state-hover")}).focus(function(){if(!d.disabled){b(".ui-slider .ui-state-focus").removeClass("ui-state-focus");b(this).addClass("ui-state-focus")}else{b(this).blur()}}).blur(function(){b(this).removeClass("ui-state-focus")});this.handles.each(function(e){b(this).data("index.ui-slider-handle",e)});this.handles.keydown(function(j){var g=true;var f=b(this).data("index.ui-slider-handle");if(c.options.disabled){return}switch(j.keyCode){case b.ui.keyCode.HOME:case b.ui.keyCode.END:case b.ui.keyCode.PAGE_UP:case b.ui.keyCode.PAGE_DOWN:case b.ui.keyCode.UP:case b.ui.keyCode.RIGHT:case b.ui.keyCode.DOWN:case b.ui.keyCode.LEFT:g=false;if(!c._keySliding){c._keySliding=true;b(this).addClass("ui-state-active");c._start(j,f)}break}var h,e,i=c._step();if(c.options.values&&c.options.values.length){h=e=c.values(f)}else{h=e=c.value()}switch(j.keyCode){case b.ui.keyCode.HOME:e=c._valueMin();break;case b.ui.keyCode.END:e=c._valueMax();break;case b.ui.keyCode.PAGE_UP:e=h+((c._valueMax()-c._valueMin())/a);break;case b.ui.keyCode.PAGE_DOWN:e=h-((c._valueMax()-c._valueMin())/a);break;case b.ui.keyCode.UP:case b.ui.keyCode.RIGHT:if(h==c._valueMax()){return}e=h+i;break;case b.ui.keyCode.DOWN:case b.ui.keyCode.LEFT:if(h==c._valueMin()){return}e=h-i;break}c._slide(j,f,e);return g}).keyup(function(f){var e=b(this).data("index.ui-slider-handle");if(c._keySliding){c._keySliding=false;c._stop(f,e);c._change(f,e);b(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy();return this},_mouseCapture:function(e){var f=this.options;if(f.disabled){return false}this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var i={x:e.pageX,y:e.pageY};var k=this._normValueFromMouse(i);var d=this._valueMax()-this._valueMin()+1,g;var l=this,j;this.handles.each(function(m){var n=Math.abs(k-l.values(m));if(d>n){d=n;g=b(this);j=m}});if(f.range==true&&this.values(1)==f.min){g=b(this.handles[++j])}this._start(e,j);this._mouseSliding=true;l._handleIndex=j;g.addClass("ui-state-active").focus();var h=g.offset();var c=!b(e.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=c?{left:0,top:0}:{left:e.pageX-h.left-(g.width()/2),top:e.pageY-h.top-(g.height()/2)-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)};k=this._normValueFromMouse(i);this._slide(e,j,k);this._animateOff=true;return true},_mouseStart:function(c){return true},_mouseDrag:function(e){var c={x:e.pageX,y:e.pageY};var d=this._normValueFromMouse(c);this._slide(e,this._handleIndex,d);return false},_mouseStop:function(c){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(c,this._handleIndex);this._change(c,this._handleIndex);this._handleIndex=null;this._clickOffset=null;this._animateOff=false;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(e){var d,i;if("horizontal"==this.orientation){d=this.elementSize.width;i=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{d=this.elementSize.height;i=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var g=(i/d);if(g>1){g=1}if(g<0){g=0}if("vertical"==this.orientation){g=1-g}var f=this._valueMax()-this._valueMin(),j=g*f,c=j%this.options.step,h=this._valueMin()+j-c;if(c>(this.options.step/2)){h+=this.options.step}return parseFloat(h.toFixed(5))},_start:function(e,d){var c={handle:this.handles[d],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(d);c.values=this.values()}this._trigger("start",e,c)},_slide:function(g,f,e){var h=this.handles[f];if(this.options.values&&this.options.values.length){var c=this.values(f?0:1);if((this.options.values.length==2&&this.options.range===true)&&((f==0&&e>c)||(f==1&&e<c))){e=c}if(e!=this.values(f)){var d=this.values();d[f]=e;var i=this._trigger("slide",g,{handle:this.handles[f],value:e,values:d});var c=this.values(f?0:1);if(i!==false){this.values(f,e,true)}}}else{if(e!=this.value()){var i=this._trigger("slide",g,{handle:this.handles[f],value:e});if(i!==false){this.value(e)}}}},_stop:function(e,d){var c={handle:this.handles[d],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(d);c.values=this.values()}this._trigger("stop",e,c)},_change:function(e,d){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[d],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(d);c.values=this.values()}this._trigger("change",e,c)}},value:function(c){if(arguments.length){this.options.value=this._trimValue(c);this._refreshValue();this._change(null,0)}return this._value()},values:function(e,h){if(arguments.length>1){this.options.values[e]=this._trimValue(h);this._refreshValue();this._change(null,e)}if(arguments.length){if(b.isArray(arguments[0])){var g=this.options.values,d=arguments[0];for(var f=0,c=g.length;f<c;f++){g[f]=this._trimValue(d[f]);this._change(null,f)}this._refreshValue()}else{if(this.options.values&&this.options.values.length){return this._values(e)}else{return this.value()}}}else{return this._values()}},_setOption:function(d,e){var c,f=0;if(jQuery.isArray(this.options.values)){f=this.options.values.length}b.Widget.prototype._setOption.apply(this,arguments);switch(d){case"disabled":if(e){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case"value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case"values":this._animateOff=true;this._refreshValue();for(c=0;c<f;c++){this._change(null,c)}this._animateOff=false;break}},_step:function(){var c=this.options.step;return c},_value:function(){var c=this.options.value;c=this._trimValue(c);return c},_values:function(d){if(arguments.length){var g=this.options.values[d];g=this._trimValue(g);return g}else{var f=this.options.values.slice();for(var e=0,c=f.length;e<c;e++){f[e]=this._trimValue(f[e])}return f}},_trimValue:function(c){if(c<this._valueMin()){c=this._valueMin()}if(c>this._valueMax()){c=this._valueMax()}return c},_valueMin:function(){var c=this.options.min;return c},_valueMax:function(){var c=this.options.max;return c},_refreshValue:function(){var g=this.options.range,e=this.options,m=this;var d=(!this._animateOff)?e.animate:false;if(this.options.values&&this.options.values.length){var j,i;this.handles.each(function(q,o){var p=(m.values(q)-m._valueMin())/(m._valueMax()-m._valueMin())*100;var n={};n[m.orientation=="horizontal"?"left":"bottom"]=p+"%";b(this).stop(1,1)[d?"animate":"css"](n,e.animate);if(m.options.range===true){if(m.orientation=="horizontal"){(q==0)&&m.range.stop(1,1)[d?"animate":"css"]({left:p+"%"},e.animate);(q==1)&&m.range[d?"animate":"css"]({width:(p-lastValPercent)+"%"},{queue:false,duration:e.animate})}else{(q==0)&&m.range.stop(1,1)[d?"animate":"css"]({bottom:(p)+"%"},e.animate);(q==1)&&m.range[d?"animate":"css"]({height:(p-lastValPercent)+"%"},{queue:false,duration:e.animate})}}lastValPercent=p})}else{var k=this.value(),h=this._valueMin(),l=this._valueMax(),f=l!=h?(k-h)/(l-h)*100:0;var c={};c[m.orientation=="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[d?"animate":"css"](c,e.animate);(g=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[d?"animate":"css"]({width:f+"%"},e.animate);(g=="max")&&(this.orientation=="horizontal")&&this.range[d?"animate":"css"]({width:(100-f)+"%"},{queue:false,duration:e.animate});(g=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[d?"animate":"css"]({height:f+"%"},e.animate);(g=="max")&&(this.orientation=="vertical")&&this.range[d?"animate":"css"]({height:(100-f)+"%"},{queue:false,duration:e.animate})}}});b.extend(b.ui.slider,{version:"1.8"})})(jQuery);
\ No newline at end of file
+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
+this.range=d([]);if(a.range){if(a.range===true){this.range=d("<div></div>");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
+if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length<a.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();
+else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
+false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
+b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
+this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,
+g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},
+_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;
+if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=
+this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],
+value:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value=
+this._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();
+else return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
+this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];
+return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},
+_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);
+if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,
+1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.7"})})(jQuery);
diff --git a/misc/ui/jquery.ui.sortable.min.js b/misc/ui/jquery.ui.sortable.min.js
index a7efc0fe5914c6b42079d14d255930498b4814fe..b394ed1140647f19522ee44c902f56afed3b8879 100644
--- a/misc/ui/jquery.ui.sortable.min.js
+++ b/misc/ui/jquery.ui.sortable.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.sortable.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.sortable.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Sortable 1.8
+ * jQuery UI Sortable 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Sortables
  *
@@ -14,4 +14,49 @@
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  */
-(function(a){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000},_create:function(){var b=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData("sortable-item")}return this},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;(g.cursorAt&&this._adjustOffsetFromHelper(g.cursorAt));this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop+g.scrollSpeed}else{if(f.pageY-this.overflowOffset.top<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop-g.scrollSpeed}}if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-f.pageX<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft+g.scrollSpeed}else{if(f.pageX-this.overflowOffset.left<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft-g.scrollSpeed}}}else{if(f.pageY-a(document).scrollTop()<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-g.scrollSpeed)}else{if(a(window).height()-(f.pageY-a(document).scrollTop())<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+g.scrollSpeed)}}if(f.pageX-a(document).scrollLeft()<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-g.scrollSpeed)}else{if(a(window).width()-(f.pageX-a(document).scrollLeft())<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+g.scrollSpeed)}}}if(b!==false&&a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,f)}}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)<i&&(e+h)>f&&(e+h)<c;if(this.options.tolerance=="pointer"||this.options.forcePointerForContainers||(this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>m[this.floating?"width":"height"])){return g}else{return(f<e+(this.helperProportions.width/2)&&d-(this.helperProportions.width/2)<c&&n<k+(this.helperProportions.height/2)&&j-(this.helperProportions.height/2)<i)}},_intersectsWithPointer:function(d){var e=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,d.top,d.height),c=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,d.left,d.width),g=e&&c,b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(!g){return false}return this.floating?(((f&&f=="right")||b=="down")?2:1):(b&&(b=="down"?2:1))},_intersectsWithSides:function(e){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+(e.height/2),e.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+(e.width/2),e.width),b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(this.floating&&f){return((f=="right"&&d)||(f=="left"&&!d))}else{return b&&((b=="down"&&c)||(b=="up"&&!c))}},_getDragVerticalDirection:function(){var b=this.positionAbs.top-this.lastPositionAbs.top;return b!=0&&(b>0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions();return this},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c<this.items.length;c++){for(var b=0;b<d.length;b++){if(d[b]==this.items[c].item[0]){this.items.splice(c,1)}}}},_refreshItems:function(b){this.items=[];this.containers=[this];var h=this.items;var p=this;var f=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]];var l=this._connectWith();if(l){for(var e=l.length-1;e>=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d<n;d++){var o=a(c[d]);o.data("sortable-item",k);h.push({item:o,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset()}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d];var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}return this},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(b){var d=null,k=null;for(var f=this.containers.length-1;f>=0;f--){if(a.ui.contains(this.currentItem[0],this.containers[f].element[0])){continue}if(this._intersectsWith(this.containers[f].containerCache)){if(d&&a.ui.contains(this.containers[f].element[0],d.element[0])){continue}d=this.containers[f];k=f}else{if(this.containers[f].containerCache.over){this.containers[f]._trigger("out",b,this._uiHash(this));this.containers[f].containerCache.over=0}}}if(!d){return}if(this.containers.length===1){this.containers[k]._trigger("over",b,this._uiHash(this));this.containers[k].containerCache.over=1}else{if(this.currentContainer!=this.containers[k]){var h=10000;var g=null;var c=this.positionAbs[this.containers[k].floating?"left":"top"];for(var e=this.items.length-1;e>=0;e--){if(!a.ui.contains(this.containers[k].element[0],this.items[e].item[0])){continue}var l=this.items[e][this.containers[k].floating?"left":"top"];if(Math.abs(l-c)<h){h=Math.abs(l-c);g=this.items[e]}}if(!g&&!this.options.dropOnEmpty){return}this.currentContainer=this.containers[k];g?this._rearrange(b,g,null,true):this._rearrange(b,null,this.containers[k].element,true);this._trigger("change",b,this._uiHash());this.containers[k]._trigger("change",b,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[k]._trigger("over",b,this._uiHash(this));this.containers[k].containerCache.over=1}}},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c,this.currentItem])):(d.helper=="clone"?this.currentItem.clone():this.currentItem);if(!b.parents("body").length){a(d.appendTo!="parent"?d.appendTo:this.currentItem[0].parentNode)[0].appendChild(b[0])}if(b[0]==this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}}if(b[0].style.width==""||d.forceHelperSize){b.width(this.currentItem.width())}if(b[0].style.height==""||d.forceHelperSize){b.height(this.currentItem.height())}return b},_adjustOffsetFromHelper:function(b){if(typeof b=="string"){b=b.split(" ")}if(a.isArray(b)){b={left:+b[0],top:+b[1]||0}}if("left" in b){this.offset.click.left=b.left+this.margins.left}if("right" in b){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if("top" in b){this.offset.click.top=b.top+this.margins.top}if("bottom" in b){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.currentItem.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.currentItem.css("marginLeft"),10)||0),top:(parseInt(this.currentItem.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)){var c=a(e.containment)[0];var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_rearrange:function(g,f,c,e){c?c[0].appendChild(this.placeholder[0]):f.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction=="down"?f.item[0]:f.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var d=this,b=this.counter;window.setTimeout(function(){if(b==d.counter){d.refreshPositions(!e)}},0)},_clear:function(d,e){this.reverting=false;var f=[],b=this;if(!this._noFinalSort&&this.currentItem[0].parentNode){this.placeholder.before(this.currentItem)}this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var c in this._storedCSS){if(this._storedCSS[c]=="auto"||this._storedCSS[c]=="static"){this._storedCSS[c]=""}}this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}if(this.fromOutside&&!e){f.push(function(g){this._trigger("receive",g,this._uiHash(this.fromOutside))})}if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!e){f.push(function(g){this._trigger("update",g,this._uiHash())})}if(!a.ui.contains(this.element[0],this.currentItem[0])){if(!e){f.push(function(g){this._trigger("remove",g,this._uiHash())})}for(var c=this.containers.length-1;c>=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}return false}if(!e){this._trigger("beforeStop",d,this._uiHash())}this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!=this.currentItem[0]){this.helper.remove()}this.helper=null;if(!e){for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){if(a.Widget.prototype._trigger.apply(this,arguments)===false){this.cancel()}},_uiHash:function(c){var b=c||this;return{helper:b.helper,placeholder:b.placeholder||a([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:c?c.element:null}}});a.extend(a.ui.sortable,{version:"1.8"})})(jQuery);
\ No newline at end of file
+(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
+this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
+arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
+c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
+{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
+if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
+a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
+if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
+c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
+document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
+null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
+d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||
+"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+
+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?
+2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},
+_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=
+this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=
+this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");
+if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=
+0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=
+this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},
+update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=
+null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));
+this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,
+null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||
+d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a==
+"string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition==
+"absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==
+"relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},
+_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-
+this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),
+10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?
+this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=
+this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+
+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?
+g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
+e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==
+f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",
+f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",
+g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=
+0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});
+d.extend(d.ui.sortable,{version:"1.8.7"})})(jQuery);
diff --git a/misc/ui/jquery.ui.tabs.css b/misc/ui/jquery.ui.tabs.css
index 986a94d593e7e69bda53292f67aa2f0036250937..c801d735de2989498b9c629d1c643733236bee38 100644
--- a/misc/ui/jquery.ui.tabs.css
+++ b/misc/ui/jquery.ui.tabs.css
@@ -1,7 +1,14 @@
-/* $Id: jquery.ui.tabs.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.tabs.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
-/* Tabs
-----------------------------------*/
+/*
+ * jQuery UI Tabs 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
 .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
 .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
 .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
@@ -9,5 +16,5 @@
 .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
 .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
 .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border: 0; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
 .ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/misc/ui/jquery.ui.tabs.min.js b/misc/ui/jquery.ui.tabs.min.js
index b1198e2d70baf41518dc5eac6892b358fb9ce041..6fe9fad1763ad943f5fcb53e802386f647bc7764 100644
--- a/misc/ui/jquery.ui.tabs.min.js
+++ b/misc/ui/jquery.ui.tabs.min.js
@@ -1,11 +1,11 @@
-// $Id: jquery.ui.tabs.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.tabs.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*
- * jQuery UI Tabs 1.8
+ * jQuery UI Tabs 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Tabs
  *
@@ -13,4 +13,25 @@
  *	jquery.ui.core.js
  *	jquery.ui.widget.js
  */
-(function(c){var b=0,a=0;c.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:'<li><a href="#{href}"><span>#{label}</span></a></li>'},_create:function(){this._tabify(true)},_setOption:function(d,e){if(d=="selected"){if(this.options.collapsible&&e==this.options.selected){return}this.select(e)}else{this.options[d]=e;this._tabify()}},_tabId:function(d){return d.title&&d.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+(++b)},_sanitizeSelector:function(d){return d.replace(/:/g,"\\:")},_cookie:function(){var d=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+(++a));return c.cookie.apply(null,[d].concat(c.makeArray(arguments)))},_ui:function(e,d){return{tab:e,panel:d,index:this.anchors.index(e)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var d=c(this);d.html(d.data("label.tabs")).removeData("label.tabs")})},_tabify:function(q){this.list=this.element.find("ol,ul").eq(0);this.lis=c("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return c("a",this)[0]});this.panels=c([]);var r=this,f=this.options;var e=/^#.+/;this.anchors.each(function(u,o){var s=c(o).attr("href");var v=s.split("#")[0],w;if(v&&(v===location.toString().split("#")[0]||(w=c("base")[0])&&v===w.href)){s=o.hash;o.href=s}if(e.test(s)){r.panels=r.panels.add(r._sanitizeSelector(s))}else{if(s!="#"){c.data(o,"href.tabs",s);c.data(o,"load.tabs",s.replace(/#.*$/,""));var y=r._tabId(o);o.href="#"+y;var x=c("#"+y);if(!x.length){x=c(f.panelTemplate).attr("id",y).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(r.panels[u-1]||r.list);x.data("destroy.tabs",true)}r.panels=r.panels.add(x)}else{f.disabled.push(u)}}});if(q){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(f.selected===undefined){if(location.hash){this.anchors.each(function(s,o){if(o.hash==location.hash){f.selected=s;return false}})}if(typeof f.selected!="number"&&f.cookie){f.selected=parseInt(r._cookie(),10)}if(typeof f.selected!="number"&&this.lis.filter(".ui-tabs-selected").length){f.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}f.selected=f.selected||(this.lis.length?0:-1)}else{if(f.selected===null){f.selected=-1}}f.selected=((f.selected>=0&&this.anchors[f.selected])||f.selected<0)?f.selected:0;f.disabled=c.unique(f.disabled.concat(c.map(this.lis.filter(".ui-state-disabled"),function(s,o){return r.lis.index(s)}))).sort();if(c.inArray(f.selected,f.disabled)!=-1){f.disabled.splice(c.inArray(f.selected,f.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(f.selected>=0&&this.anchors.length){this.panels.eq(f.selected).removeClass("ui-tabs-hide");this.lis.eq(f.selected).addClass("ui-tabs-selected ui-state-active");r.element.queue("tabs",function(){r._trigger("show",null,r._ui(r.anchors[f.selected],r.panels[f.selected]))});this.load(f.selected)}c(window).bind("unload",function(){r.lis.add(r.anchors).unbind(".tabs");r.lis=r.anchors=r.panels=null})}else{f.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[f.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(f.cookie){this._cookie(f.selected,f.cookie)}for(var j=0,p;(p=this.lis[j]);j++){c(p)[c.inArray(j,f.disabled)!=-1&&!c(p).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(f.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(f.event!="mouseover"){var h=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var l=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){h("hover",c(this))});this.lis.bind("mouseout.tabs",function(){l("hover",c(this))});this.anchors.bind("focus.tabs",function(){h("focus",c(this).closest("li"))});this.anchors.bind("blur.tabs",function(){l("focus",c(this).closest("li"))})}var d,k;if(f.fx){if(c.isArray(f.fx)){d=f.fx[0];k=f.fx[1]}else{d=k=f.fx}}function g(i,o){i.css({display:""});if(!c.support.opacity&&o.opacity){i[0].style.removeAttribute("filter")}}var m=k?function(i,o){c(i).closest("li").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(k,k.duration||"normal",function(){g(o,k);r._trigger("show",null,r._ui(i,o[0]))})}:function(i,o){c(i).closest("li").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");r._trigger("show",null,r._ui(i,o[0]))};var n=d?function(o,i){i.animate(d,d.duration||"normal",function(){r.lis.removeClass("ui-tabs-selected ui-state-active");i.addClass("ui-tabs-hide");g(i,d);r.element.dequeue("tabs")})}:function(o,i,s){r.lis.removeClass("ui-tabs-selected ui-state-active");i.addClass("ui-tabs-hide");r.element.dequeue("tabs")};this.anchors.bind(f.event+".tabs",function(){var o=this,u=c(this).closest("li"),i=r.panels.filter(":not(.ui-tabs-hide)"),s=c(r._sanitizeSelector(this.hash));if((u.hasClass("ui-tabs-selected")&&!f.collapsible)||u.hasClass("ui-state-disabled")||u.hasClass("ui-state-processing")||r._trigger("select",null,r._ui(this,s[0]))===false){this.blur();return false}f.selected=r.anchors.index(this);r.abort();if(f.collapsible){if(u.hasClass("ui-tabs-selected")){f.selected=-1;if(f.cookie){r._cookie(f.selected,f.cookie)}r.element.queue("tabs",function(){n(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(f.cookie){r._cookie(f.selected,f.cookie)}r.element.queue("tabs",function(){m(o,s)});r.load(r.anchors.index(this));this.blur();return false}}}if(f.cookie){r._cookie(f.selected,f.cookie)}if(s.length){if(i.length){r.element.queue("tabs",function(){n(o,i)})}r.element.queue("tabs",function(){m(o,s)});r.load(r.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(c.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var d=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=c.data(this,"href.tabs");if(e){this.href=e}var f=c(this).unbind(".tabs");c.each(["href","load","cache"],function(g,h){f.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(c.data(this,"destroy.tabs")){c(this).remove()}else{c(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(d.cookie){this._cookie(null,d.cookie)}return this},add:function(g,f,e){if(e===undefined){e=this.anchors.length}var d=this,i=this.options,k=c(i.tabTemplate.replace(/#\{href\}/g,g).replace(/#\{label\}/g,f)),j=!g.indexOf("#")?g.replace("#",""):this._tabId(c("a",k)[0]);k.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var h=c("#"+j);if(!h.length){h=c(i.panelTemplate).attr("id",j).data("destroy.tabs",true)}h.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(e>=this.lis.length){k.appendTo(this.list);h.appendTo(this.list[0].parentNode)}else{k.insertBefore(this.lis[e]);h.insertBefore(this.panels[e])}i.disabled=c.map(i.disabled,function(m,l){return m>=e?++m:m});this._tabify();if(this.anchors.length==1){i.selected=0;k.addClass("ui-tabs-selected ui-state-active");h.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[0],d.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[e],this.panels[e]));return this},remove:function(d){var f=this.options,g=this.lis.eq(d).remove(),e=this.panels.eq(d).remove();if(g.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(d+(d+1<this.anchors.length?1:-1))}f.disabled=c.map(c.grep(f.disabled,function(j,h){return j!=d}),function(j,h){return j>=d?--j:j});this._tabify();this._trigger("remove",null,this._ui(g.find("a")[0],e[0]));return this},enable:function(d){var e=this.options;if(c.inArray(d,e.disabled)==-1){return}this.lis.eq(d).removeClass("ui-state-disabled");e.disabled=c.grep(e.disabled,function(g,f){return g!=d});this._trigger("enable",null,this._ui(this.anchors[d],this.panels[d]));return this},disable:function(e){var d=this,f=this.options;if(e!=f.selected){this.lis.eq(e).addClass("ui-state-disabled");f.disabled.push(e);f.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[e],this.panels[e]))}return this},select:function(d){if(typeof d=="string"){d=this.anchors.index(this.anchors.filter("[href$="+d+"]"))}else{if(d===null){d=-1}}if(d==-1&&this.options.collapsible){d=this.options.selected}this.anchors.eq(d).trigger(this.options.event+".tabs");return this},load:function(g){var e=this,i=this.options,d=this.anchors.eq(g)[0],f=c.data(d,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&c.data(d,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(g).addClass("ui-state-processing");if(i.spinner){var h=c("span",d);h.data("label.tabs",h.html()).html(i.spinner)}this.xhr=c.ajax(c.extend({},i.ajaxOptions,{url:f,success:function(k,j){c(e._sanitizeSelector(d.hash)).html(k);e._cleanup();if(i.cache){c.data(d,"cache.tabs",true)}e._trigger("load",null,e._ui(e.anchors[g],e.panels[g]));try{i.ajaxOptions.success(k,j)}catch(l){}},error:function(l,j,k){e._cleanup();e._trigger("load",null,e._ui(e.anchors[g],e.panels[g]));try{i.ajaxOptions.error(l,j,g,d)}catch(k){}}}));e.element.dequeue("tabs");return this},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(e,d){this.anchors.eq(e).removeData("cache.tabs").data("load.tabs",d);return this},length:function(){return this.anchors.length}});c.extend(c.ui.tabs,{version:"1.8"});c.extend(c.ui.tabs.prototype,{rotation:null,rotate:function(f,h){var d=this,i=this.options;var e=d._rotate||(d._rotate=function(j){clearTimeout(d.rotation);d.rotation=setTimeout(function(){var k=i.selected;d.select(++k<d.anchors.length?k:0)},f);if(j){j.stopPropagation()}});var g=d._unrotate||(d._unrotate=!h?function(j){if(j.clientX){d.rotate(null)}}:function(j){t=i.selected;e()});if(f){this.element.bind("tabsshow",e);this.anchors.bind(i.event+".tabs",g);e()}else{clearTimeout(d.rotation);this.element.unbind("tabsshow",e);this.anchors.unbind(i.event+".tabs",g);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
\ No newline at end of file
+(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&
+e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=
+d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
+(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
+this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
+this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
+if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
+this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
+g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
+function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
+this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=
+-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";
+d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=
+d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,
+e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);
+j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();
+if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,
+this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
+load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
+"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
+url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.7"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&
+a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
diff --git a/misc/ui/jquery.ui.theme.css b/misc/ui/jquery.ui.theme.css
index 7bbff471d0d04fa3299d81cf604977bd0ddbd7e8..32a1a2a7827fe3df71dade61e7db48017ee1b4fd 100644
--- a/misc/ui/jquery.ui.theme.css
+++ b/misc/ui/jquery.ui.theme.css
@@ -1,11 +1,16 @@
-/* $Id: jquery.ui.theme.css,v 1.1 2010/03/21 03:47:32 webchick Exp $ */
+/* $Id: jquery.ui.theme.css,v 1.3 2011/01/03 00:03:35 webchick Exp $ */
 
 /*
-* jQuery UI CSS Framework
-* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-* To view and modify this theme, visit http://jqueryui.com/themeroller/
-*/
+ * jQuery UI CSS Framework 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/
+ */
 
 
 /* Component containers
@@ -20,24 +25,24 @@
 
 /* Interaction states
 ----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
 .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
 .ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
 .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
 .ui-widget :active { outline: none; }
 
 /* Interaction Cues
 ----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
-.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
-.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
 
 /* Icons
 ----------------------------------*/
@@ -246,4 +251,4 @@
 
 /* Overlays */
 .ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
-.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
\ No newline at end of file
+.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
diff --git a/misc/ui/jquery.ui.widget.min.js b/misc/ui/jquery.ui.widget.min.js
index 38ec772517d0e337a26b60f2a1a2fa8284abd6db..d46919917bdbd31009a0ff6c66ccdb55c50490e1 100644
--- a/misc/ui/jquery.ui.widget.min.js
+++ b/misc/ui/jquery.ui.widget.min.js
@@ -1,12 +1,17 @@
-// $Id: jquery.ui.widget.min.js,v 1.1 2010/03/21 03:47:32 webchick Exp $
+// $Id: jquery.ui.widget.min.js,v 1.3 2011/01/03 00:03:35 webchick Exp $
 
 /*!
- * jQuery UI Widget 1.8
+ * jQuery UI Widget 1.8.7
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Widget
  */
-(function(b){var a=b.fn.remove;b.fn.remove=function(c,d){return this.each(function(){if(!d){if(!c||b.filter(c,[this]).length){b("*",this).add(this).each(function(){b(this).triggerHandler("remove")})}}return a.call(b(this),c,d)})};b.widget=function(d,f,c){var e=d.split(".")[0],h;d=d.split(".")[1];h=e+"-"+d;if(!c){c=f;f=b.Widget}b.expr[":"][h]=function(i){return !!b.data(i,d)};b[e]=b[e]||{};b[e][d]=function(i,j){if(arguments.length){this._createWidget(i,j)}};var g=new f();g.options=b.extend({},g.options);b[e][d].prototype=b.extend(true,g,{namespace:e,widgetName:d,widgetEventPrefix:b[e][d].prototype.widgetEventPrefix||d,widgetBaseClass:h},c);b.widget.bridge(d,b[e][d])};b.widget.bridge=function(d,c){b.fn[d]=function(g){var e=typeof g==="string",f=Array.prototype.slice.call(arguments,1),h=this;g=!e&&f.length?b.extend.apply(null,[true,g].concat(f)):g;if(e&&g.substring(0,1)==="_"){return h}if(e){this.each(function(){var i=b.data(this,d),j=i&&b.isFunction(i[g])?i[g].apply(i,f):i;if(j!==i&&j!==undefined){h=j;return false}})}else{this.each(function(){var i=b.data(this,d);if(i){if(g){i.option(g)}i._init()}else{b.data(this,d,new c(g,this))}})}return h}};b.Widget=function(c,d){if(arguments.length){this._createWidget(c,d)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(d,e){this.element=b(e).data(this.widgetName,this);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(e)[this.widgetName],d);var c=this;this.element.bind("remove."+this.widgetName,function(){c.destroy()});this._create();this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled")},widget:function(){return this.element},option:function(e,f){var d=e,c=this;if(arguments.length===0){return b.extend({},c.options)}if(typeof e==="string"){if(f===undefined){return this.options[e]}d={};d[e]=f}b.each(d,function(g,h){c._setOption(g,h)});return c},_setOption:function(c,d){this.options[c]=d;if(c==="disabled"){this.widget()[d?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",d)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(d,e,f){var h=this.options[d];e=b.Event(e);e.type=(d===this.widgetEventPrefix?d:this.widgetEventPrefix+d).toLowerCase();f=f||{};if(e.originalEvent){for(var c=b.event.props.length,g;c;){g=b.event.props[--c];e[g]=e.originalEvent[g]}}this.element.trigger(e,f);return !(b.isFunction(h)&&h.call(this.element[0],e,f)===false||e.isDefaultPrevented())}}})(jQuery);
\ No newline at end of file
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
+a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
+e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
+this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
+widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
+enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
diff --git a/misc/watchdog-error.png b/misc/watchdog-error.png
index ce9b86e92feb8a2e0781dde936118bb34cabf3df..f7e60e5238ee0f613c73d556f69f7ff52be7a8bb 100644
Binary files a/misc/watchdog-error.png and b/misc/watchdog-error.png differ
diff --git a/misc/watchdog-ok.png b/misc/watchdog-ok.png
index 34d161d684a823fdf2541498eb0e0a5383d0038b..6ebea3e53d5fd889eb4ada215506c6e0e48b48bf 100644
Binary files a/misc/watchdog-ok.png and b/misc/watchdog-ok.png differ
diff --git a/misc/watchdog-warning.png b/misc/watchdog-warning.png
index 121416e09c48318513daf840008f8ce7fc453efe..5d33a512ee78ecd82a36763d4588ffa9ba45b767 100644
Binary files a/misc/watchdog-warning.png and b/misc/watchdog-warning.png differ
diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info
index 47a90f24eb4d5fed90ddbe2ef27a262ae7f6b362..b31da62ce3864eb832e4035a3c07beac24d301e9 100644
--- a/modules/aggregator/aggregator.info
+++ b/modules/aggregator/aggregator.info
@@ -1,22 +1,15 @@
-; $Id: aggregator.info,v 1.14 2010/09/05 02:21:37 dries Exp $
+; $Id: aggregator.info,v 1.15 2010/12/20 19:59:40 webchick Exp $
 name = Aggregator
 description = "Aggregates syndicated content (RSS, RDF, and Atom feeds)."
 package = Core
 version = VERSION
 core = 7.x
-files[] = aggregator.module
-files[] = aggregator.admin.inc
-files[] = aggregator.pages.inc
-files[] = aggregator.fetcher.inc
-files[] = aggregator.parser.inc
-files[] = aggregator.processor.inc
-files[] = aggregator.install
 files[] = aggregator.test
 configure = admin/config/services/aggregator/settings
 stylesheets[all][] = aggregator.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test
index c5d17bc00809d28df78b23ff9895ac7d05f81c25..2e5260793111d9e0c05e37ac35e6642ead7c6e29 100644
--- a/modules/aggregator/aggregator.test
+++ b/modules/aggregator/aggregator.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: aggregator.test,v 1.46 2010/09/07 23:17:47 dries Exp $
+// $Id: aggregator.test,v 1.47 2010/10/25 15:51:21 webchick Exp $
 
 /**
  * @file
@@ -603,11 +603,11 @@ class ImportOPMLTestCase extends AggregatorTestCase {
       ->execute();
 
     $this->drupalGet('admin/config/services/aggregator/add/opml');
-    $this->assertText('A single OPML document may contain a collection of many feeds.', t('Looking for help text.'));
-    $this->assertFieldByName('files[upload]', '', t('Looking for file upload field.'));
-    $this->assertFieldByName('remote', '', t('Looking for remote URL field.'));
-    $this->assertFieldByName('refresh', '', t('Looking for refresh field.'));
-    $this->assertFieldByName("category[$cid]", $cid, t('Looking for category field.'));
+    $this->assertText('A single OPML document may contain a collection of many feeds.', t('Found OPML help text.'));
+    $this->assertField('files[upload]', t('Found file upload field.'));
+    $this->assertField('remote', t('Found Remote URL field.'));
+    $this->assertField('refresh', '', t('Found Refresh field.'));
+    $this->assertFieldByName("category[$cid]", $cid, t('Found category field.'));
   }
 
   /**
diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info
index 50b8b93b324c96d8f0eb3400322d501921d3d92f..7d79a08b77c8192504dbeee5401643be7b899cd1 100644
--- a/modules/aggregator/tests/aggregator_test.info
+++ b/modules/aggregator/tests/aggregator_test.info
@@ -1,14 +1,13 @@
-; $Id: aggregator_test.info,v 1.1 2009/04/02 20:50:37 dries Exp $
+; $Id: aggregator_test.info,v 1.2 2010/12/20 19:59:40 webchick Exp $
 name = "Aggregator module tests"
 description = "Support module for aggregator related testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = aggregator_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/block/block.admin.inc b/modules/block/block.admin.inc
index 06111cc3515d88b46efea04497a42457ad9ea80b..72dec8f93aa599d078d57384afe67e0cda06e728 100644
--- a/modules/block/block.admin.inc
+++ b/modules/block/block.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.admin.inc,v 1.90 2010/10/10 20:11:21 dries Exp $
+// $Id: block.admin.inc,v 1.91 2010/11/06 23:24:33 webchick Exp $
 
 /**
  * @file
@@ -291,6 +291,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
   );
 
   $theme_default = variable_get('theme_default', 'bartik');
+  $admin_theme = variable_get('admin_theme');
   foreach (list_themes() as $key => $theme) {
     // Only display enabled themes
     if ($theme->status) {
@@ -300,9 +301,18 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
         ':theme' => $key,
       ))->fetchField();
 
+      // Use a meaningful title for the main site theme and administrative
+      // theme.
+      $theme_title = $theme->info['name'];
+      if ($key == $theme_default) {
+        $theme_title = t('!theme (default theme)', array('!theme' => $theme_title));
+      }
+      elseif ($admin_theme && $key == $admin_theme) {
+        $theme_title = t('!theme (administration theme)', array('!theme' => $theme_title));
+      }
       $form['regions'][$key] = array(
         '#type' => 'select',
-        '#title' => $theme->info['name'],
+        '#title' => $theme_title,
         '#default_value' => !empty($region) && $region != -1 ? $region : NULL,
         '#empty_value' => BLOCK_REGION_NONE,
         '#options' => system_region_list($key, REGIONS_VISIBLE),
diff --git a/modules/block/block.api.php b/modules/block/block.api.php
index 2827af6e6e513121dce27300d354bd6070b5bd74..2df97df8561347b5dfd3c01495f96d3bfdf63e68 100644
--- a/modules/block/block.api.php
+++ b/modules/block/block.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.api.php,v 1.13 2010/08/13 12:25:14 dries Exp $
+// $Id: block.api.php,v 1.15 2010/11/23 16:12:15 webchick Exp $
 
 /**
  * @file
@@ -57,6 +57,12 @@
  *     - DRUPAL_CACHE_GLOBAL: The block is the same for every user on every
  *       page where it is visible.
  *     - DRUPAL_NO_CACHE: The block should not get cached.
+ *   - 'properties': (optional) Array of additional metadata to add to the
+ *     block. Common properties include:
+ *     - 'administrative': Boolean which categorizes this block as usable in
+ *       an administrative context. This might include blocks which help an
+ *       administrator approve/deny comments, or view recently created
+ *       user accounts.
  *   - 'weight': (optional) Initial value for the ordering weight of this block.
  *     Most modules do not provide an initial value, and any value provided can
  *     be modified by a user on the block configuration screen.
@@ -187,9 +193,11 @@ function hook_block_save($delta = '', $edit = array()) {
  *   within the module, defined in hook_block_info().
  *
  * @return
- *   An array containing required elements 'subject' (the block's localized
- *   title) and 'content' (the block's body). The 'content' element may be a
- *   renderable array (preferable) or rendered HTML content.
+ *   An array containing the following elements:
+ *   - subject: The default localized title of the block. If the block does not
+ *     have a default title, this should be set to NULL.
+ *   - content: The content of the block's body. This may be a renderable array
+ *     (preferable) or a string containing rendered HTML content.
  *
  * For a detailed usage example, see block_example.module.
  *
@@ -236,7 +244,7 @@ function hook_block_view($delta = '') {
  * @param $data
  *   An array of data, as returned from the hook_block_view() implementation of
  *   the module that defined the block:
- *   - subject: The localized title of the block.
+ *   - subject: The default localized title of the block.
  *   - content: Either a string or a renderable array representing the content
  *     of the block. You should check that the content is an array before trying
  *     to modify parts of the renderable structure.
diff --git a/modules/block/block.css b/modules/block/block.css
index 9febed825b52cf5c4814670057f435d573a12d78..a146be040633bf8d295b62d112e5f8d90d0df809 100644
--- a/modules/block/block.css
+++ b/modules/block/block.css
@@ -1,4 +1,4 @@
-/* $Id: block.css,v 1.8 2010/07/31 12:54:58 webchick Exp $ */
+/* $Id: block.css,v 1.9 2011/01/03 07:04:48 webchick Exp $ */
 
 #blocks tr.region-title td {
   font-weight: bold;
@@ -20,9 +20,9 @@ a.block-demo-backlink,
 a.block-demo-backlink:link,
 a.block-demo-backlink:visited {
   background-color: #B4D7F0;
-  border-radius: 0 0 10px 10px;
   -moz-border-radius: 0 0 10px 10px;
   -webkit-border-radius: 0 0 10px 10px;
+  border-radius: 0 0 10px 10px;
   color: #000;
   font-family: "Lucida Grande", Verdana, sans-serif;
   font-size: small;
diff --git a/modules/block/block.info b/modules/block/block.info
index 381c0bdc357c1b68362c3491204c11257a1fc437..7e51b488167d6ff440b3780361cffbb89d069df3 100644
--- a/modules/block/block.info
+++ b/modules/block/block.info
@@ -1,17 +1,14 @@
-; $Id: block.info,v 1.15 2009/11/17 21:24:18 dries Exp $
+; $Id: block.info,v 1.16 2010/12/20 19:59:40 webchick Exp $
 name = Block
 description = Controls the visual building blocks a page is constructed with. Blocks are boxes of content rendered into an area, or region, of a web page.
 package = Core
 version = VERSION
 core = 7.x
-files[] = block.module
-files[] = block.admin.inc
-files[] = block.install
 files[] = block.test
 configure = admin/structure/block
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/block/block.install b/modules/block/block.install
index 95f74c42d9aac126c2dbd3eb0fd8d604ebb1136e..dafcfb3ccda741a03cb272756da89b5edc289964 100644
--- a/modules/block/block.install
+++ b/modules/block/block.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.install,v 1.47 2010/10/20 01:15:58 dries Exp $
+// $Id: block.install,v 1.48 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -206,7 +206,7 @@ function block_update_dependencies() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Block updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -462,6 +462,5 @@ function block_update_7007() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/block/block.module b/modules/block/block.module
index 27e31bc02f73274096d2d82f73afc746f16cce38..ae4889ee51194c5150d8f6d747d529352b11db5e 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.module,v 1.431 2010/09/28 03:30:37 webchick Exp $
+// $Id: block.module,v 1.435 2010/11/23 16:12:15 webchick Exp $
 
 /**
  * @file
@@ -240,8 +240,9 @@ function block_block_save($delta = 0, $edit = array()) {
  *
  * Generates the administrator-defined blocks for display.
  */
-function block_block_view($delta = 0, $edit = array()) {
+function block_block_view($delta = '') {
   $block = db_query('SELECT body, format FROM {block_custom} WHERE bid = :bid', array(':bid' => $delta))->fetchObject();
+  $data['subject'] = NULL;
   $data['content'] = check_markup($block->body, $block->format, '', TRUE);
   return $data;
 }
@@ -559,7 +560,7 @@ function block_form_user_profile_form_alter(&$form, &$form_state) {
         $blocks[$block->module][$block->delta] = array(
           '#type' => 'checkbox',
           '#title' => check_plain($data[$block->delta]['info']),
-          '#default_value' => isset($account->block[$block->module][$block->delta]) ? $account->block[$block->module][$block->delta] : ($block->custom == 1),
+          '#default_value' => isset($account->data['block'][$block->module][$block->delta]) ? $account->data['block'][$block->module][$block->delta] : ($block->custom == 1),
         );
       }
     }
@@ -578,6 +579,15 @@ function block_form_user_profile_form_alter(&$form, &$form_state) {
   }
 }
 
+/**
+ * Implements hook_user_presave().
+ */
+function block_user_presave(&$edit, $account, $category) {
+  if (isset($edit['block'])) {
+    $edit['data']['block'] = $edit['block'];
+  }
+}
+
 /**
  * Initialize blocks for enabled themes.
  */
@@ -607,7 +617,7 @@ function block_theme_initialize($theme) {
     $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC));
     foreach ($result as $block) {
       // If the region isn't supported by the theme, assign the block to the theme's default region.
-      if ($block['status'] && !array_key_exists($block['region'], $regions)) {
+      if ($block['status'] && !isset($regions[$block['region']])) {
         $block['region'] = system_default_region($theme);
       }
       $block['theme'] = $theme;
@@ -741,8 +751,8 @@ function block_block_list_alter(&$blocks) {
 
     // Use the user's block visibility setting, if necessary.
     if ($block->custom != BLOCK_CUSTOM_FIXED) {
-      if ($user->uid && isset($user->block[$block->module][$block->delta])) {
-        $enabled = $user->block[$block->module][$block->delta];
+      if ($user->uid && isset($user->data['block'][$block->module][$block->delta])) {
+        $enabled = $user->data['block'][$block->module][$block->delta];
       }
       else {
         $enabled = ($block->custom == BLOCK_CUSTOM_ENABLED);
diff --git a/modules/block/block.test b/modules/block/block.test
index 863c6979e3567bb6715c6c9be8dfb86ec8d97e7d..ce0ff8077f4a36b85a20e2e6017fa1a5e5089354 100644
--- a/modules/block/block.test
+++ b/modules/block/block.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.test,v 1.59 2010/10/21 19:31:39 dries Exp $
+// $Id: block.test,v 1.64 2010/11/29 06:38:51 webchick Exp $
 
 /**
  * @file
@@ -23,7 +23,7 @@ class BlockTestCase extends DrupalWebTestCase {
 
     // Create and log in an administrative user having access to the Full HTML
     // text format.
-    $full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
+    $full_html_format = filter_format_load('full_html');
     $this->admin_user = $this->drupalCreateUser(array(
       'administer blocks',
       filter_permission_name($full_html_format),
@@ -75,9 +75,15 @@ class BlockTestCase extends DrupalWebTestCase {
     $this->assertText(t('The block has been created.'), t('Custom block successfully created.'));
     $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
 
-    // Check to see if the custom block was created by checking that it's in the database..
+    // Check to see if the custom block was created by checking that it's in the database.
     $this->assertNotNull($bid, t('Custom block found in database'));
 
+    // Check that block_block_view() returns the correct title and content.
+    $data = block_block_view($bid);
+    $format = db_query("SELECT format FROM {block_custom} WHERE bid = :bid", array(':bid' => $bid))->fetchField();
+    $this->assertTrue(array_key_exists('subject', $data) && empty($data['subject']), t('block_block_view() provides an empty block subject, since custom blocks do not have default titles.'));
+    $this->assertEqual(check_markup($custom_block['body[value]'], $format), $data['content'], t('block_block_view() provides correct block content.'));
+
     // Check if the block can be moved to all availble regions.
     $custom_block['module'] = 'block';
     $custom_block['delta'] = $bid;
@@ -113,8 +119,8 @@ class BlockTestCase extends DrupalWebTestCase {
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $this->randomName(8);
     $custom_block['body[value]'] = '<h1>Full HTML</h1>';
-    $full_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchField();
-    $custom_block['body[format]'] = $full_html_format_id;
+    $full_html_format = filter_format_load('full_html');
+    $custom_block['body[format]'] = $full_html_format->format;
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
 
     // Set the created custom block to a specific region.
@@ -187,6 +193,57 @@ class BlockTestCase extends DrupalWebTestCase {
     $this->assertNoText($title, t('Block was not displayed to anonymous users.'));
   }
 
+  /**
+   * Test user customization of block visibility.
+   */
+  function testBlockVisibilityPerUser() {
+    $block = array();
+
+    // Create a random title for the block.
+    $title = $this->randomName(8);
+
+    // Create our custom test block.
+    $custom_block = array();
+    $custom_block['info'] = $this->randomName(8);
+    $custom_block['title'] = $title;
+    $custom_block['body[value]'] = $this->randomName(32);
+    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
+
+    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
+    $block['module'] = 'block';
+    $block['delta'] = $bid;
+    $block['title'] = $title;
+
+    // Move block to the first sidebar.
+    $this->moveBlockToRegion($block, $this->regions[1]);
+
+    // Set the block to be customizable per user, visible by default.
+    $edit = array();
+    $edit['custom'] = BLOCK_CUSTOM_ENABLED;
+    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));
+
+    // Disable block visibility for the admin user.
+    $edit = array();
+    $edit['block[' . $block['module'] . '][' . $block['delta'] . ']'] = FALSE;
+    $this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));
+
+    $this->drupalGet('');
+    $this->assertNoText($block['title'], t('Block was not displayed according to per user block visibility setting.'));
+
+    // Set the block to be customizable per user, hidden by default.
+    $edit = array();
+    $edit['custom'] = BLOCK_CUSTOM_DISABLED;
+    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));
+
+    // Enable block visibility for the admin user.
+    $edit = array();
+    $edit['block[' . $block['module'] . '][' . $block['delta'] . ']'] = TRUE;
+    $this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));
+
+    $this->drupalGet('');
+    $this->assertText($block['title'], t('Block was displayed according to per user block visibility setting.'));
+  }
+
   /**
    * Test configuring and moving a module-define block to specific regions.
    */
@@ -254,7 +311,7 @@ class BlockTestCase extends DrupalWebTestCase {
       ':region-class' => 'region region-' . str_replace('_', '-', $region),
       ':block-id' => 'block-' . $block['module'] . '-' . $block['delta'],
     ));
-    $this->assertFieldByXPath($xpath, FALSE, t('Custom block found in %region_name region.', array('%region_name' => $region)));
+    $this->assertFieldByXPath($xpath, NULL, t('Custom block found in %region_name region.', array('%region_name' => $region)));
   }
 
   /**
diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info
index 38c8d06fdcf5f89028da29d0c5652330a0b853e1..5c6978c75e2cb656a826aedc510ae70a3e4be0ca 100644
--- a/modules/block/tests/block_test.info
+++ b/modules/block/tests/block_test.info
@@ -1,14 +1,13 @@
-; $Id: block_test.info,v 1.1 2010/02/28 17:28:38 dries Exp $
+; $Id: block_test.info,v 1.2 2010/12/20 19:59:40 webchick Exp $
 name = Block test
 description = Provides test blocks.
 package = Testing
 version = VERSION
 core = 7.x
-files[] = block_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/blog/blog.info b/modules/blog/blog.info
index 2de09d1c0c8e4d249cece9993474f3afd43ba3ed..a69e8524e84e47e542967cc8204e3a1185a38a27 100644
--- a/modules/blog/blog.info
+++ b/modules/blog/blog.info
@@ -1,16 +1,13 @@
-; $Id: blog.info,v 1.11 2009/06/08 09:23:51 dries Exp $
-
+; $Id: blog.info,v 1.12 2010/12/20 19:59:40 webchick Exp $
 name = Blog
 description = Enables multi-user blogs.
 package = Core
 version = VERSION
 core = 7.x
-files[] = blog.module
-files[] = blog.pages.inc
 files[] = blog.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index 3a485cbbb11bc77772b8c3aa3f266b96215adc91..c9bee7b9e5c2323ce29a9f2c10f10ccb719efbb6 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: blog.module,v 1.360 2010/08/30 05:58:46 webchick Exp $
+// $Id: blog.module,v 1.362 2010/11/14 21:04:45 webchick Exp $
 
 /**
  * @file
@@ -80,11 +80,16 @@ function blog_view($node, $view_mode) {
 function blog_node_view($node, $view_mode) {
   if ($view_mode != 'rss') {
     if ($node->type == 'blog' && (arg(0) != 'blog' || arg(1) != $node->uid)) {
-      $node->content['links']['#links']['blog_usernames_blog'] = array(
+      $links['blog_usernames_blog'] = array(
         'title' => t("!username's blog", array('!username' => format_username($node))),
         'href' => "blog/$node->uid",
         'attributes' => array('title' => t("Read !username's latest blog entries.", array('!username' => format_username($node)))),
       );
+      $node->content['links']['blog'] = array(
+        '#theme' => 'links__node__blog',
+        '#links' => $links,
+        '#attributes' => array('class' => array('links', 'inline')),
+      );
     }
   }
 }
@@ -190,6 +195,7 @@ function _blog_post_exists($account) {
  */
 function blog_block_info() {
   $block['recent']['info'] = t('Recent blog posts');
+  $block['recent']['properties']['administrative'] = TRUE;
   return $block;
 }
 
diff --git a/modules/book/book-export-html.tpl.php b/modules/book/book-export-html.tpl.php
index 23e5b15ce0a034c6405992ce59343498932f6b62..dffd446b6f800b8639c7ec9baf46fbb7db7dea92 100644
--- a/modules/book/book-export-html.tpl.php
+++ b/modules/book/book-export-html.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: book-export-html.tpl.php,v 1.2 2008/05/15 21:19:24 dries Exp $
+// $Id: book-export-html.tpl.php,v 1.3 2010/10/23 15:35:35 webchick Exp $
 
 /**
  * @file
@@ -11,7 +11,7 @@
  * - $language: Language code. e.g. "en" for english.
  * - $language_rtl: TRUE or FALSE depending on right to left language scripts.
  * - $base_url: URL to home page.
- * - $content: Nodes within the current outline rendered through
+ * - $contents: Nodes within the current outline rendered through
  *   book-node-export-html.tpl.php.
  *
  * @see template_preprocess_book_export_html()
diff --git a/modules/book/book.admin.inc b/modules/book/book.admin.inc
index 41b4aaa15ea53b92f0d0f8d3008fadd84e5d6d5f..386dfccfd9462baf7d3625bde53d7e62c8b7f981 100644
--- a/modules/book/book.admin.inc
+++ b/modules/book/book.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.admin.inc,v 1.38 2010/10/20 01:31:06 dries Exp $
+// $Id: book.admin.inc,v 1.39 2011/01/03 07:34:46 webchick Exp $
 
 /**
  * @file
@@ -175,6 +175,10 @@ function _book_admin_table($node, &$form) {
  * @see book_admin_edit()
  */
 function _book_admin_table_tree($tree, &$form) {
+  // The delta must be big enough to give each node a distinct value.
+  $count = count($tree);
+  $delta = ($count < 30) ? 15 : intval($count / 2) + 1;
+
   foreach ($tree as $data) {
     $form['book-admin-' . $data['link']['nid']] = array(
       '#item' => $data['link'],
@@ -190,7 +194,7 @@ function _book_admin_table_tree($tree, &$form) {
       'weight' => array(
         '#type' => 'weight',
         '#default_value' => $data['link']['weight'],
-        '#delta' => 15,
+        '#delta' => max($delta, abs($data['link']['weight'])),
         '#title' => t('Weight for @title', array('@title' => $data['link']['title'])),
         '#title_display' => 'invisible',
       ),
diff --git a/modules/book/book.info b/modules/book/book.info
index 0a1079da31691723f7f8b4de84d80750d038b8cc..1e05f525ba9c4ae00b12c9f74f9b0718f14ad346 100644
--- a/modules/book/book.info
+++ b/modules/book/book.info
@@ -1,19 +1,15 @@
-; $Id: book.info,v 1.14 2010/09/05 02:21:38 dries Exp $
+; $Id: book.info,v 1.15 2010/12/20 19:59:41 webchick Exp $
 name = Book
 description = Allows users to create and organize related content in an outline.
 package = Core
 version = VERSION
 core = 7.x
-files[] = book.module
-files[] = book.admin.inc
-files[] = book.pages.inc
-files[] = book.install
 files[] = book.test
 configure = admin/content/book/settings
 stylesheets[all][] = book.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/book/book.js b/modules/book/book.js
index e978c8b5e856f7f3318b85c8acf2ae4c31527012..a7d1b873aa75b0d2408074495eca2a2488eb2bd1 100644
--- a/modules/book/book.js
+++ b/modules/book/book.js
@@ -1,11 +1,11 @@
-// $Id: book.js,v 1.7 2010/04/16 13:55:06 dries Exp $
+// $Id: book.js,v 1.8 2010/11/05 19:47:20 dries Exp $
 
 (function ($) {
 
 Drupal.behaviors.bookFieldsetSummaries = {
   attach: function (context) {
-    $('fieldset#edit-book', context).drupalSetSummary(function (context) {
-      var val = $('#edit-book-bid').val();
+    $('fieldset.book-form', context).drupalSetSummary(function (context) {
+      var val = $('.form-item-book-bid select').val();
 
       if (val === '0') {
         return Drupal.t('Not in book');
@@ -14,7 +14,7 @@ Drupal.behaviors.bookFieldsetSummaries = {
         return Drupal.t('New book');
       }
       else {
-        return Drupal.checkPlain($('#edit-book-bid :selected').text());
+        return Drupal.checkPlain($('.form-item-book-bid select :selected').text());
       }
     });
   }
diff --git a/modules/book/book.module b/modules/book/book.module
index 18194f64b81e98dbb55c4fc52e1af2ffa513212e..4252f3e9bc1661573f41d99c448be2802e3891fc 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.module,v 1.554 2010/10/18 05:53:34 webchick Exp $
+// $Id: book.module,v 1.558 2011/01/03 07:34:46 webchick Exp $
 
 /**
  * @file
@@ -112,7 +112,11 @@ function book_node_view_link($node, $view_mode) {
   }
 
   if (!empty($links)) {
-    $node->content['links']['#links'] = array_merge($node->content['links']['#links'], $links);
+    $node->content['links']['book'] = array(
+      '#theme' => 'links__node__book',
+      '#links' => $links,
+      '#attributes' => array('class' => array('links', 'inline')),
+    );
   }
 }
 
@@ -170,7 +174,6 @@ function book_menu() {
     'page arguments' => array(1),
     'access callback' => '_book_outline_access',
     'access arguments' => array(1),
-    'theme callback' => '_node_custom_theme',
     'type' => MENU_LOCAL_TASK,
     'weight' => 2,
     'file' => 'book.pages.inc',
@@ -181,7 +184,6 @@ function book_menu() {
     'page arguments' => array('book_remove_form', 1),
     'access callback' => '_book_outline_remove_access',
     'access arguments' => array(1),
-    'theme callback' => '_node_custom_theme',
     'file' => 'book.pages.inc',
   );
 
@@ -206,11 +208,13 @@ function _book_outline_remove_access($node) {
  * Implements hook_admin_paths().
  */
 function book_admin_paths() {
-  $paths = array(
-    'node/*/outline' => TRUE,
-    'node/*/outline/remove' => TRUE,
-  );
-  return $paths;
+  if (variable_get('node_admin_theme')) {
+    $paths = array(
+      'node/*/outline' => TRUE,
+      'node/*/outline/remove' => TRUE,
+    );
+    return $paths;
+  }
 }
 
 /**
@@ -488,6 +492,9 @@ function _book_add_form_elements(&$form, &$form_state, $node) {
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('book-form'),
+    ),
     '#attached' => array(
       'js' => array(drupal_get_path('module', 'book') . '/book.js'),
     ),
@@ -503,11 +510,12 @@ function _book_add_form_elements(&$form, &$form_state, $node) {
 
   $form['book']['plid'] = _book_parent_select($node->book);
 
+  // @see _book_admin_table_tree(). The weight may be larger than 15.
   $form['book']['weight'] = array(
     '#type' => 'weight',
     '#title' => t('Weight'),
     '#default_value' => $node->book['weight'],
-    '#delta' => 15,
+    '#delta' => max(15, abs($node->book['weight'])),
     '#weight' => 5,
     '#description' => t('Pages at a given level are ordered first by weight and then by title.'),
   );
diff --git a/modules/color/color.info b/modules/color/color.info
index 69d711755e29916b59263910ce4e1776668e596f..96a07d6cb4a1b8e903dcd51e43f70de0ca91a514 100644
--- a/modules/color/color.info
+++ b/modules/color/color.info
@@ -1,16 +1,13 @@
-; $Id: color.info,v 1.10 2009/09/01 20:39:55 webchick Exp $
-
+; $Id: color.info,v 1.11 2010/12/20 19:59:41 webchick Exp $
 name = Color
 description = Allows administrators to change the color scheme of compatible themes.
 package = Core
 version = VERSION
 core = 7.x
-files[] = color.module
-files[] = color.install
 files[] = color.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/color/color.install b/modules/color/color.install
index 5ecf551bd371f8ee1d2b9a81faeb610c588d3e5a..83a0780b448189f01578207a64d01332826f1419 100644
--- a/modules/color/color.install
+++ b/modules/color/color.install
@@ -1,5 +1,5 @@
 <?php
-/* $Id: color.install,v 1.8 2010/10/15 23:41:53 webchick Exp $ */
+// $Id: color.install,v 1.9 2010/11/19 20:37:17 dries Exp $
 
 /**
  * @file
diff --git a/modules/color/color.test b/modules/color/color.test
index e0566439be4ea0730dc91a482520d3593f7a7abd..8f89b4bfc48bd3f2224189687a7427d8c7f48363 100644
--- a/modules/color/color.test
+++ b/modules/color/color.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: color.test,v 1.7 2010/08/12 16:59:04 dries Exp $
+// $Id: color.test,v 1.8 2010/11/13 14:06:43 dries Exp $
 
 /**
  * @file
@@ -71,8 +71,7 @@ class ColorTestCase extends DrupalWebTestCase {
     $this->assertPattern('|' . file_create_url($stylesheets[0]) . '|', 'Make sure the color stylesheet is included in the content. (' . $theme . ')');
 
     $stylesheet_content = join("\n", file($stylesheets[0]));
-    $matched = preg_match('/(.*color: #123456.*)/i', $stylesheet_content, $matches);
-    $this->assertTrue($matched == 1, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
+    $this->assertTrue(strpos($stylesheet_content, 'color: #123456') !== FALSE, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
 
     $this->drupalGet($settings_path);
     $this->assertResponse(200);
@@ -82,7 +81,17 @@ class ColorTestCase extends DrupalWebTestCase {
     $this->drupalGet('<front>');
     $stylesheets = variable_get('color_' . $theme . '_stylesheets', array());
     $stylesheet_content = join("\n", file($stylesheets[0]));
-    $matched = preg_match('/(.*color: ' . $test_values['scheme_color'] . '.*)/i', $stylesheet_content, $matches);
-    $this->assertTrue($matched == 1, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
+    $this->assertTrue(strpos($stylesheet_content, 'color: ' . $test_values['scheme_color']) !== FALSE, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
+
+    // Test with aggregated CSS turned on.
+    variable_set('preprocess_css', 1);
+    $this->drupalGet('<front>');
+    $stylesheets = variable_get('drupal_css_cache_files', array());
+    $stylesheet_content = '';
+    foreach ($stylesheets as $key => $uri) {
+      $stylesheet_content .= join("\n", file(drupal_realpath($uri)));
+    }
+    $this->assertTrue(strpos($stylesheet_content, 'public://') === FALSE, 'Make sure the color paths have been translated to local paths. (' . $theme . ')');
+    variable_set('preprocess_css', 0);
   }
 }
diff --git a/modules/color/images/hook-rtl.png b/modules/color/images/hook-rtl.png
index 7a80e7aecfc9eefc71b7b7fd195b5d189437c0f3..a26b211e126c298b68a23bef312d8a6dd68f9f29 100644
Binary files a/modules/color/images/hook-rtl.png and b/modules/color/images/hook-rtl.png differ
diff --git a/modules/color/images/hook.png b/modules/color/images/hook.png
index 664f0915b847f453cd6bddfdbafa6f01d4f4f3c6..dc1897370f928a8de70f257cc4786f9e79cf3c57 100644
Binary files a/modules/color/images/hook.png and b/modules/color/images/hook.png differ
diff --git a/modules/color/images/lock.png b/modules/color/images/lock.png
index 6903a9db777a4c852197e43b24dfa2dcff0fab39..9e1e00e5efd11ffcf50d13257fd935b92804f840 100644
Binary files a/modules/color/images/lock.png and b/modules/color/images/lock.png differ
diff --git a/modules/comment/comment-node-form.js b/modules/comment/comment-node-form.js
index 2401cfdb910992cba276a57682613b9d638d295b..e8f07b243d033caf21f0cf7915f7946deecd9e33 100644
--- a/modules/comment/comment-node-form.js
+++ b/modules/comment/comment-node-form.js
@@ -1,27 +1,28 @@
-// $Id: comment-node-form.js,v 1.5 2010/04/16 13:55:06 dries Exp $
+// $Id: comment-node-form.js,v 1.6 2010/11/05 19:47:20 dries Exp $
 
 (function ($) {
 
 Drupal.behaviors.commentFieldsetSummaries = {
   attach: function (context) {
-    $('fieldset#edit-comment-settings', context).drupalSetSummary(function (context) {
-      return Drupal.checkPlain($('input:checked', context).next('label').text());
+    $('fieldset.comment-node-settings-form', context).drupalSetSummary(function (context) {
+      return Drupal.checkPlain($('.form-item-comment input:checked', context).next('label').text());
     });
+
     // Provide the summary for the node type form.
-    $('fieldset#edit-comment', context).drupalSetSummary(function(context) {
+    $('fieldset.comment-node-type-settings-form', context).drupalSetSummary(function(context) {
       var vals = [];
 
       // Default comment setting.
-      vals.push($("select[name='comment'] option:selected", context).text());
+      vals.push($(".form-item-comment select option:selected", context).text());
 
       // Threading.
-      var threading = $("input[name='comment_default_mode']:checked", context).next('label').text();
+      var threading = $(".form-item-comment-default-mode input:checked", context).next('label').text();
       if (threading) {
         vals.push(threading);
       }
 
       // Comments per page.
-      var number = $("select[name='comment_default_per_page'] option:selected", context).val();
+      var number = $(".form-item-comment-default-per-page select option:selected", context).val();
       vals.push(Drupal.t('@number comments per page', {'@number': number}));
 
       return Drupal.checkPlain(vals.join(', '));
diff --git a/modules/comment/comment.admin.inc b/modules/comment/comment.admin.inc
index 0e6a58fe18a623c06c62f4d7196802acbb327492..91ce977b8cd07b92dc944b233362588fe4a4626e 100644
--- a/modules/comment/comment.admin.inc
+++ b/modules/comment/comment.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.admin.inc,v 1.51 2010/10/20 01:31:06 dries Exp $
+// $Id: comment.admin.inc,v 1.53 2011/01/03 05:18:42 webchick Exp $
 
 /**
  * @file
@@ -73,6 +73,7 @@ function comment_admin_overview($form, &$form_state, $arg) {
   $query = db_select('comment', 'c')->extend('PagerDefault')->extend('TableSort');
   $query->join('node', 'n', 'n.nid = c.nid');
   $query->addField('n', 'title', 'node_title');
+  $query->addTag('node_access');
   $result = $query
     ->fields('c', array('cid', 'subject', 'name', 'changed'))
     ->condition('c.status', $status)
@@ -232,7 +233,7 @@ function comment_multiple_delete_confirm_submit($form, &$form_state) {
     cache_clear_all();
     $count = count($form_state['values']['comments']);
     watchdog('content', 'Deleted @count comments.', array('@count' => $count));
-    drupal_set_message(t('Deleted @count comments.', array('@count' => $count)));
+    drupal_set_message(format_plural($count, 'Deleted 1 comment.', 'Deleted @count comments.'));
   }
   $form_state['redirect'] = 'admin/content/comment';
 }
diff --git a/modules/comment/comment.api.php b/modules/comment/comment.api.php
index a36ea1771b46267a432aed0c70381b8802b0dfa2..648088dd6dcc87eab79a729b4bcb3a2ff432ecee 100644
--- a/modules/comment/comment.api.php
+++ b/modules/comment/comment.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.api.php,v 1.17 2010/10/03 01:15:33 dries Exp $
+// $Id: comment.api.php,v 1.18 2010/10/23 15:30:34 webchick Exp $
 
 /**
  * @file
@@ -68,6 +68,8 @@ function hook_comment_load($comments) {
  *   View mode, e.g. 'full', 'teaser'...
  * @param $langcode
  *   The language code used for rendering.
+ *
+ * @see hook_entity_view()
  */
 function hook_comment_view($comment, $view_mode, $langcode) {
   // how old is the comment
@@ -90,6 +92,7 @@ function hook_comment_view($comment, $view_mode, $langcode) {
  *   A renderable array representing the comment.
  *
  * @see comment_view()
+ * @see hook_entity_view_alter()
  */
 function hook_comment_view_alter(&$build) {
   // Check for the existence of a field added by another module.
diff --git a/modules/comment/comment.info b/modules/comment/comment.info
index 4127d72dd056b79d20c17494f7fcbe8b55bbd5c1..aceac3b1d2dfe8f00484bbe39b96f46bef0097a8 100644
--- a/modules/comment/comment.info
+++ b/modules/comment/comment.info
@@ -1,4 +1,4 @@
-; $Id: comment.info,v 1.14 2010/09/05 02:21:38 dries Exp $
+; $Id: comment.info,v 1.15 2010/12/20 19:59:41 webchick Exp $
 name = Comment
 description = Allows users to comment on and discuss published content.
 package = Core
@@ -6,16 +6,12 @@ version = VERSION
 core = 7.x
 dependencies[] = text
 files[] = comment.module
-files[] = comment.admin.inc
-files[] = comment.pages.inc
-files[] = comment.install
 files[] = comment.test
-files[] = comment.tokens.inc
 configure = admin/content/comment
 stylesheets[all][] = comment.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/comment/comment.install b/modules/comment/comment.install
index 8d25520cf906e2e31556a2a28aa41e4b819cf84e..7959e79d37df90ae06e5c0c2e325090123e40a5c 100644
--- a/modules/comment/comment.install
+++ b/modules/comment/comment.install
@@ -1,40 +1,11 @@
 <?php
-// $Id: comment.install,v 1.73 2010/09/28 03:30:37 webchick Exp $
+// $Id: comment.install,v 1.76 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
  * Install, update and uninstall functions for the comment module.
  */
 
-/**
- * Implements hook_install().
- */
-function comment_install() {
-  // Create comment body field.
-  if (!field_info_field('comment_body')) {
-    $field = array(
-      'field_name' => 'comment_body',
-      'type' => 'text_long',
-      'entity_types' => array('comment'),
-    );
-    field_create_field($field);
-  }
-
-  // There is a separate comment bundle for each node type to allow for
-  // per-node-type customization of comment fields. Each one of these bundles
-  // needs a comment body field instance. A comment bundle is needed even for
-  // node types whose comments are disabled by default, because individual nodes
-  // may override that default.
-  // @todo This should be changed to call field_attach_create_bundle() instead,
-  //   and a comment_field_attach_create_bundle() function should be added to
-  //   handle the creation of the comment body field instance.
-  foreach (node_type_get_types() as $type => $info) {
-    if (!isset($info->is_new) && !isset($info->disabled) && !field_info_instance('comment', 'comment_body', 'comment_node_' . $info->type)) {
-      _comment_body_field_instance_create($info);
-    }
-  }
-}
-
 /**
  * Implements hook_uninstall().
  */
@@ -77,6 +48,37 @@ function comment_enable() {
     ->execute();
 }
 
+/**
+ * Implements hook_modules_enabled().
+ *
+ * Creates comment body fields for node types existing before the comment module
+ * is enabled. We use hook_modules_enabled() rather than hook_enable() so we can
+ * react to node types of existing modules, and those of modules being enabled
+ * both before and after comment module in the loop of module_enable().
+ *
+ * There is a separate comment bundle for each node type to allow for
+ * per-node-type customization of comment fields. Each one of these bundles
+ * needs a comment body field instance. A comment bundle is needed even for
+ * node types whose comments are disabled by default, because individual nodes
+ * may override that default.
+ *
+ * @see comment_node_type_insert()
+ */
+function comment_modules_enabled($modules) {
+  // Only react if comment module is one of the modules being enabled.
+  // hook_node_type_insert() is used to create body fields while the comment
+  // module is enabled.
+  if (in_array('comment', $modules)) {
+    // Ensure that the list of node types reflects newly enabled modules.
+    node_types_rebuild();
+
+    // Create comment body fields for each node type, if needed.
+    foreach (node_type_get_types() as $type => $info) {
+      _comment_body_field_create($info);
+    }
+  }
+}
+
 /**
  * Implements hook_update_dependencies().
  */
@@ -97,7 +99,7 @@ function comment_update_dependencies() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Comment updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -286,7 +288,6 @@ function comment_update_7006(&$sandbox) {
     $comments = (bool) db_query_range('SELECT 1 FROM {comment}', 0, 1)->fetchField();
     $sandbox['types'] = array();
     if ($comments) {
-      $sandbox['etid'] = _field_sql_storage_etid('comment');
       $sandbox['types'] = array_keys(_update_7000_node_get_types());
     }
     $sandbox['total'] = count($sandbox['types']);
@@ -299,7 +300,7 @@ function comment_update_7006(&$sandbox) {
     $query->innerJoin('node', 'n', 'c.nid = n.nid AND n.type = :type', array(':type' => $type));
     $query->addField('c', 'cid', 'entity_id');
     $query->addExpression("'comment_node_$type'", 'bundle');
-    $query->addExpression($sandbox['etid'], 'etid');
+    $query->addExpression("'comment'", 'entity_type');
     $query->addExpression('0', 'deleted');
     $query->addExpression("'" . LANGUAGE_NONE . "'", 'language');
     $query->addExpression('0', 'delta');
@@ -337,8 +338,7 @@ function comment_update_7006(&$sandbox) {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
 
 /**
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 2a0c073aff168a5cc3f8ab7f094f58d03b67106a..c295179a35a05fd2f1e3d2e01f4c6cc438b39b03 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.module,v 1.906 2010/10/20 01:31:06 dries Exp $
+// $Id: comment.module,v 1.931 2011/01/02 23:54:05 webchick Exp $
 
 /**
  * @file
@@ -314,12 +314,15 @@ function comment_count_unpublished() {
 
 /**
  * Implements hook_node_type_insert().
+ *
+ * Creates a comment body field for a node type created while the comment module
+ * is enabled. For node types created before the comment module is enabled,
+ * hook_modules_enabled() serves to create the body fields.
+ *
+ * @see comment_modules_enabled()
  */
 function comment_node_type_insert($info) {
-  field_attach_create_bundle('comment', 'comment_node_' . $info->type);
-  // @todo Create a comment_field_attach_create_bundle() function, and have that
-  //   function create the comment body field instance.
-  _comment_body_field_instance_create($info);
+  _comment_body_field_create($info);
 }
 
 /**
@@ -351,27 +354,39 @@ function comment_node_type_delete($info) {
 }
 
  /**
- * Helper function which creates a comment body field instance for a given node
- * type.
- */
-function _comment_body_field_instance_create($info) {
-  // Attaches the body field by default.
-  $instance = array(
-    'field_name' => 'comment_body',
-    'label' => 'Comment',
-    'entity_type' => 'comment',
-    'bundle' => 'comment_node_' . $info->type,
-    'settings' => array('text_processing' => 1),
-    'required' => TRUE,
-    'display' => array(
-      'default' => array(
-        'label' => 'hidden',
-        'type' => 'text_default',
-        'weight' => 0,
+ * Creates a comment_body field instance for a given node type.
+ */
+function _comment_body_field_create($info) {
+  // Create the field if needed.
+  if (!field_read_field('comment_body', array('include_inactive' => TRUE))) {
+    $field = array(
+      'field_name' => 'comment_body',
+      'type' => 'text_long',
+      'entity_types' => array('comment'),
+    );
+    field_create_field($field);
+  }
+  // Create the instance if needed.
+  if (!field_read_instance('comment', 'comment_body', 'comment_node_' . $info->type, array('include_inactive' => TRUE))) {
+    field_attach_create_bundle('comment', 'comment_node_' . $info->type);
+    // Attaches the body field by default.
+    $instance = array(
+      'field_name' => 'comment_body',
+      'label' => 'Comment',
+      'entity_type' => 'comment',
+      'bundle' => 'comment_node_' . $info->type,
+      'settings' => array('text_processing' => 1),
+      'required' => TRUE,
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'type' => 'text_default',
+          'weight' => 0,
+        ),
       ),
-    ),
-  );
-  field_create_instance($instance);
+    );
+    field_create_instance($instance);
+  }
 }
 
 /**
@@ -402,6 +417,7 @@ function comment_permission() {
  */
 function comment_block_info() {
   $blocks['recent']['info'] = t('Recent comments');
+  $blocks['recent']['properties']['administrative'] = TRUE;
 
   return $blocks;
 }
@@ -595,15 +611,13 @@ function theme_comment_block() {
 function comment_node_view($node, $view_mode) {
   $links = array();
 
-  if ($node->comment) {
+  if ($node->comment != COMMENT_NODE_HIDDEN) {
     if ($view_mode == 'rss') {
-      if ($node->comment != COMMENT_NODE_HIDDEN) {
-        // Add a comments RSS element which is a URL to the comments of this node.
-        $node->rss_elements[] = array(
-          'key' => 'comments',
-          'value' => url('node/' . $node->nid, array('fragment' => 'comments', 'absolute' => TRUE))
-        );
-      }
+      // Add a comments RSS element which is a URL to the comments of this node.
+      $node->rss_elements[] = array(
+        'key' => 'comments',
+        'value' => url('node/' . $node->nid, array('fragment' => 'comments', 'absolute' => TRUE))
+      );
     }
     elseif ($view_mode == 'teaser') {
       // Teaser view: display the number of comments that have been posted,
@@ -618,9 +632,8 @@ function comment_node_view($node, $view_mode) {
             'fragment' => 'comments',
             'html' => TRUE,
           );
-
-          $new = comment_num_new($node->nid);
-          if (!$new) {
+          // Show a link to the first new comment.
+          if ($new = comment_num_new($node->nid)) {
             $links['comment-new-comments'] = array(
               'title' => format_plural($new, '1 new comment', '@count new comments'),
               'href' => "node/$node->nid",
@@ -631,61 +644,66 @@ function comment_node_view($node, $view_mode) {
             );
           }
         }
+      }
+      if ($node->comment == COMMENT_NODE_OPEN) {
+        if (user_access('post comments')) {
+          $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.')),
+            'fragment' => 'comment-form',
+          );
+        }
         else {
-          if ($node->comment == COMMENT_NODE_OPEN) {
-            if (user_access('post comments')) {
-              $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.')),
-                'fragment' => 'comment-form',
-                'html' => TRUE,
-              );
-            }
-            else {
-              $links['comment_forbidden']['title'] = theme('comment_post_forbidden', array('node' => $node));
-            }
-          }
+          $links['comment_forbidden'] = array(
+            'title' => theme('comment_post_forbidden', array('node' => $node)),
+            'html' => TRUE,
+          );
         }
       }
     }
-    elseif ($view_mode != 'search_index') {
+    elseif ($view_mode != 'search_index' && $view_mode != 'search_result') {
       // Node in other view modes: add a "post comment" link if the user is
       // allowed to post comments and if this node is allowing new comments.
       // But we don't want this link if we're building the node for search
-      // indexing.
+      // indexing or constructing a search result excerpt.
       if ($node->comment == COMMENT_NODE_OPEN) {
+        $comment_form_location = variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW);
         if (user_access('post comments')) {
-          $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";
-          }
-          else {
-            $links['comment-add']['href'] = "node/$node->nid";
+          // Show the "post comment" link if the form is on another page, or
+          // if there are existing comments that the link will skip past.
+          if ($comment_form_location == COMMENT_FORM_SEPARATE_PAGE || (!empty($node->comment_count) && user_access('access comments'))) {
+            $links['comment-add'] = array(
+              'title' => t('Add new comment'),
+              'attributes' => array('title' => t('Share your thoughts and opinions related to this posting.')),
+              'href' => "node/$node->nid",
+              'fragment' => 'comment-form',
+            );
+            if ($comment_form_location == COMMENT_FORM_SEPARATE_PAGE) {
+              $links['comment-add']['href'] = "comment/reply/$node->nid";
+            }
           }
         }
         else {
-          $links['comment_forbidden']['title'] = theme('comment_post_forbidden', array('node' => $node));
+          $links['comment_forbidden'] = array(
+            'title' => theme('comment_post_forbidden', array('node' => $node)),
+            'html' => TRUE,
+          );
         }
       }
     }
 
-    if (isset($links['comment_forbidden'])) {
-      $links['comment_forbidden']['html'] = TRUE;
-    }
-
-    $node->content['links']['#links'] = array_merge($node->content['links']['#links'], $links);
+    $node->content['links']['comment'] = array(
+      '#theme' => 'links__node__comment',
+      '#links' => $links,
+      '#attributes' => array('class' => array('links', 'inline')),
+    );
 
     // Only append comments when we are building a node on its own node detail
     // page. We compare $node and $page_node to ensure that comments are not
     // appended to other nodes shown on the page, for example a node_reference
     // displayed in 'full' view mode within another node.
-    if ($node->comment && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview) && user_access('access comments')) {
+    if ($node->comment && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
       $node->content['comments'] = comment_node_page_additions($node);
     }
   }
@@ -703,7 +721,7 @@ function comment_node_page_additions($node) {
   // Only attempt to render comments if the node has visible comments.
   // Unpublished comments are not included in $node->comment_count, so show
   // comments unconditionally if the user is an administrator.
-  if ($node->comment_count || user_access('administer comments')) {
+  if (($node->comment_count && user_access('access comments')) || user_access('administer comments')) {
     $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
     $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50);
     if ($cids = comment_get_thread($node, $mode, $comments_per_page)) {
@@ -826,7 +844,8 @@ function comment_get_thread($node, $mode, $comments_per_page) {
     // See comment above. Analysis reveals that this doesn't cost too
     // much. It scales much much better than having the whole comment
     // structure.
-    $query->orderBy('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'ASC');
+    $query->addExpression('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'torder');
+    $query->orderBy('torder', 'ASC');
   }
 
   $query->setCountQuery($count_query);
@@ -939,7 +958,8 @@ function comment_view($comment, $node, $view_mode = 'full', $langcode = NULL) {
   }
 
   // Allow modules to modify the structured comment.
-  drupal_alter('comment_view', $build);
+  $type = 'comment';
+  drupal_alter(array('comment_view', 'entity_view'), $build, $type);
 
   return $build;
 }
@@ -973,9 +993,14 @@ function comment_build_content($comment, $node, $view_mode = 'full', $langcode =
   entity_prepare_view('comment', array($comment->cid => $comment));
   $comment->content += field_attach_view('comment', $comment, $view_mode, $langcode);
 
+  $comment->content['links'] = array(
+    '#theme' => 'links__comment',
+    '#pre_render' => array('drupal_pre_render_links'),
+    '#attributes' => array('class' => array('links', 'inline')),
+  );
   if (empty($comment->in_preview)) {
     $comment->content['links']['comment'] = array(
-      '#theme' => 'links__comment',
+      '#theme' => 'links__comment__comment',
       '#links' => comment_links($comment, $node),
       '#attributes' => array('class' => array('links', 'inline')),
     );
@@ -983,6 +1008,7 @@ function comment_build_content($comment, $node, $view_mode = 'full', $langcode =
 
   // Allow modules to make their own additions to the comment.
   module_invoke_all('comment_view', $comment, $view_mode, $langcode);
+  module_invoke_all('entity_view', $comment, 'comment', $view_mode, $langcode);
 }
 
 /**
@@ -1091,15 +1117,25 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
       '#collapsible' => TRUE,
       '#collapsed' => TRUE,
       '#group' => 'additional_settings',
+      '#attributes' => array(
+        'class' => array('comment-node-type-settings-form'),
+      ),
       '#attached' => array(
         'js' => array(drupal_get_path('module', 'comment') . '/comment-node-form.js'),
       ),
     );
+    // Unlike coment_form_node_form_alter(), all of these settings are applied
+    // as defaults to all new nodes. Therefore, it would be wrong to use #states
+    // to hide the other settings based on the primary comment setting.
     $form['comment']['comment'] = array(
       '#type' => 'select',
       '#title' => t('Default comment setting for new content'),
       '#default_value' => variable_get('comment_' . $form['#node_type']->type, COMMENT_NODE_OPEN),
-      '#options' => array(t('Hidden'), t('Closed'), t('Open')),
+      '#options' => array(
+        COMMENT_NODE_OPEN => t('Open'),
+        COMMENT_NODE_CLOSED => t('Closed'),
+        COMMENT_NODE_HIDDEN => t('Hidden'),
+      ),
     );
     $form['comment']['comment_default_mode'] = array(
       '#type' => 'checkbox',
@@ -1120,13 +1156,10 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
       '#options' => array(
         COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'),
         COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
-        COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information'))
+        COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information'),
+      ),
+      '#access' => user_access('post comments', drupal_anonymous_user()),
     );
-
-    if (!user_access('post comments', drupal_anonymous_user())) {
-      $form['comment']['comment_anonymous']['#access'] = FALSE;
-    }
-
     $form['comment']['comment_subject_field'] = array(
       '#type' => 'checkbox',
       '#title' => t('Allow comment title'),
@@ -1162,6 +1195,9 @@ function comment_form_node_form_alter(&$form, $form_state) {
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('comment-node-settings-form'),
+    ),
     '#attached' => array(
       'js' => array(drupal_get_path('module', 'comment') . '/comment-node-form.js'),
      ),
@@ -1181,31 +1217,13 @@ function comment_form_node_form_alter(&$form, $form_state) {
       COMMENT_NODE_HIDDEN => t('Hidden'),
     ),
     COMMENT_NODE_OPEN => array(
-      '#type' => 'radio',
-      '#title' => t('Open'),
       '#description' => t('Users with the "Post comments" permission can post comments.'),
-      '#return_value' => COMMENT_NODE_OPEN,
-      '#default_value' => $comment_settings,
-      '#id' => 'edit-comment-2',
-      '#parents' => array('comment'),
     ),
     COMMENT_NODE_CLOSED => array(
-      '#type' => 'radio',
-      '#title' => t('Closed'),
       '#description' => t('Users cannot post comments, but existing comments will be displayed.'),
-      '#return_value' => COMMENT_NODE_CLOSED,
-      '#default_value' => $comment_settings,
-      '#id' => 'edit-comment-1',
-      '#parents' => array('comment'),
     ),
     COMMENT_NODE_HIDDEN => array(
-      '#type' => 'radio',
-      '#title' => t('Hidden'),
       '#description' => t('Comments are hidden from view.'),
-      '#return_value' => COMMENT_NODE_HIDDEN,
-      '#default_value' => $comment_settings,
-      '#id' => 'edit-comment-0',
-      '#parents' => array('comment'),
     ),
   );
   // If the node doesn't have any comments, the "hidden" option makes no
@@ -1234,17 +1252,19 @@ function comment_node_load($nodes, $types) {
       $node->cid = 0;
       $node->last_comment_timestamp = $node->created;
       $node->last_comment_name = '';
+      $node->last_comment_uid = $node->uid;
       $node->comment_count = 0;
     }
   }
 
   // For nodes with comments enabled, fetch information from the database.
   if (!empty($comments_enabled)) {
-    $result = db_query('SELECT nid, cid, last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid IN (:comments_enabled)', array(':comments_enabled' => $comments_enabled));
+    $result = db_query('SELECT nid, cid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count FROM {node_comment_statistics} WHERE nid IN (:comments_enabled)', array(':comments_enabled' => $comments_enabled));
     foreach ($result as $record) {
       $nodes[$record->nid]->cid = $record->cid;
       $nodes[$record->nid]->last_comment_timestamp = $record->last_comment_timestamp;
       $nodes[$record->nid]->last_comment_name = $record->last_comment_name;
+      $nodes[$record->nid]->last_comment_uid = $record->last_comment_uid;
       $nodes[$record->nid]->comment_count = $record->comment_count;
     }
   }
@@ -1436,10 +1456,16 @@ function comment_save($comment) {
       $comment->node_type = 'comment_node_' . $node->type;
     }
 
+    // Load the stored entity, if any.
+    if (!empty($comment->cid) && !isset($comment->original)) {
+      $comment->original = entity_load_unchanged('comment', $comment->cid);
+    }
+
     field_attach_presave('comment', $comment);
 
     // Allow modules to alter the comment before saving.
     module_invoke_all('comment_presave', $comment);
+    module_invoke_all('entity_presave', $comment, 'comment');
 
     if ($comment->cid) {
       // Update the comment in the database.
@@ -1458,6 +1484,10 @@ function comment_save($comment) {
         ->condition('cid', $comment->cid)
         ->execute();
 
+      // Ignore slave server temporarily to give time for the
+      // saved comment to be propagated to the slave.
+      db_ignore_slave();
+
       // Update the {node_comment_statistics} table prior to executing hooks.
        _comment_update_node_statistics($comment->nid);
 
@@ -1543,7 +1573,7 @@ function comment_save($comment) {
         ->execute();
 
       // Ignore slave server temporarily to give time for the
-      // saved node to be propagated to the slave.
+      // created comment to be propagated to the slave.
       db_ignore_slave();
 
       // Update the {node_comment_statistics} table prior to executing hooks.
@@ -1558,6 +1588,7 @@ function comment_save($comment) {
     if ($comment->status == COMMENT_PUBLISHED) {
       module_invoke_all('comment_publish', $comment);
     }
+    unset($comment->original);
   }
   catch (Exception $e) {
     $transaction->rollback('comment');
@@ -1586,20 +1617,27 @@ function comment_delete($cid) {
 function comment_delete_multiple($cids) {
   $comments = comment_load_multiple($cids);
   if ($comments) {
-
-    // Delete the comments.
-    db_delete('comment')
-      ->condition('cid', array_keys($comments), 'IN')
-      ->execute();
-    foreach ($comments as $comment) {
-      field_attach_delete('comment', $comment);
-      module_invoke_all('comment_delete', $comment);
-      module_invoke_all('entity_delete', $comment, 'comment');
-
-      // Delete the comment's replies.
-      $child_cids = db_query('SELECT cid FROM {comment} WHERE pid = :cid', array(':cid' => $comment->cid))->fetchCol();
-      comment_delete_multiple($child_cids);
-      _comment_update_node_statistics($comment->nid);
+    $transaction = db_transaction();
+    try {
+      // Delete the comments.
+      db_delete('comment')
+        ->condition('cid', array_keys($comments), 'IN')
+        ->execute();
+      foreach ($comments as $comment) {
+        field_attach_delete('comment', $comment);
+        module_invoke_all('comment_delete', $comment);
+        module_invoke_all('entity_delete', $comment, 'comment');
+
+        // Delete the comment's replies.
+        $child_cids = db_query('SELECT cid FROM {comment} WHERE pid = :cid', array(':cid' => $comment->cid))->fetchCol();
+        comment_delete_multiple($child_cids);
+        _comment_update_node_statistics($comment->nid);
+      }
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('comment', $e);
+      throw $e;
     }
   }
 }
@@ -1610,10 +1648,19 @@ function comment_delete_multiple($cids) {
  * @param $cids
  *   An array of comment IDs.
  * @param $conditions
- *   An array of conditions to match against the {comments} table. These
- *   should be supplied in the form array('field_name' => 'field_value').
+ *   (deprecated) An associative array of conditions on the {comments}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have. Instead, it is preferable to use
+ *   EntityFieldQuery to retrieve a list of entity IDs loadable by
+ *   this function.
+ *
  * @return
- *  An array of comment objects, indexed by comment ID.
+ *   An array of comment objects, indexed by comment ID.
+ *
+ * @see entity_load()
+ * @see EntityFieldQuery
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function comment_load_multiple($cids = array(), $conditions = array()) {
   return entity_load('comment', $cids, $conditions);
@@ -1826,7 +1873,7 @@ function comment_form($form, &$form_state, $comment) {
   $is_admin = (!empty($comment->cid) && user_access('administer comments'));
 
   if (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
-    $form['#attached']['library'][] = array('system', 'cookie');
+    $form['#attached']['library'][] = array('system', 'jquery.cookie');
     $form['#attributes']['class'][] = 'user-info-from-cookie';
   }
 
@@ -1861,14 +1908,14 @@ function comment_form($form, &$form_state, $comment) {
   if ($is_admin) {
     $author = (!$comment->uid && $comment->name ? $comment->name : $comment->registered_name);
     $status = (isset($comment->status) ? $comment->status : COMMENT_NOT_PUBLISHED);
-    $date = (!empty($comment->date) ? $comment->date : format_date($comment->changed, 'custom', 'Y-m-d H:i O'));
+    $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));
   }
   else {
     if ($user->uid) {
       $author = $user->name;
     }
     else {
-      $author = ($comment->name ? $comment->name : variable_get('anonymous', t('Anonymous')));
+      $author = ($comment->name ? $comment->name : '');
     }
     $status = (user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED);
     $date = '';
@@ -1990,7 +2037,6 @@ function comment_form($form, &$form_state, $comment) {
 
   // Attach fields.
   $comment->node_type = 'comment_node_' . $node->type;
-  $form['#builder_function'] = 'comment_form_submit_build_comment';
   field_attach_form('comment', $comment, $form, $form_state);
 
   return $form;
@@ -2000,7 +2046,7 @@ function comment_form($form, &$form_state, $comment) {
  * Build a preview from submitted form values.
  */
 function comment_form_build_preview($form, &$form_state) {
-  $comment = $form['#builder_function']($form, $form_state);
+  $comment = comment_form_submit_build_comment($form, $form_state);
   $form_state['comment_preview'] = comment_preview($comment);
   $form_state['rebuild'] = TRUE;
 }
@@ -2114,13 +2160,19 @@ function comment_submit($comment) {
   if (empty($comment->date)) {
     $comment->date = 'now';
   }
-
   $comment->created = strtotime($comment->date);
   $comment->changed = REQUEST_TIME;
 
+  // If the comment was posted by a registered user, assign the author's ID.
+  // @todo Too fragile. Should be prepared and stored in comment_form() already.
   if (!$comment->is_anonymous && !empty($comment->name) && ($account = user_load_by_name($comment->name))) {
     $comment->uid = $account->uid;
   }
+  // If the comment was posted by an anonymous user and no author name was
+  // required, use "Anonymous" by default.
+  if ($comment->is_anonymous && (!isset($comment->name) || $comment->name === '')) {
+    $comment->name = variable_get('anonymous', t('Anonymous'));
+  }
 
   // Validate the comment's subject. If not specified, extract from comment body.
   if (trim($comment->subject) == '') {
@@ -2141,7 +2193,7 @@ function comment_submit($comment) {
 /**
  * Updates the form state's comment entity by processing this submission's values.
  *
- * This is the default #builder_function for the comment form. It is called
+ * This is the default builder function for the comment form. It is called
  * during the "Save" and "Preview" submit handlers to retrieve the entity to
  * save or preview. This function can also be called by a "Next" button of a
  * wizard to update the form state's entity with the current step's values
@@ -2161,7 +2213,7 @@ function comment_form_submit_build_comment($form, &$form_state) {
  */
 function comment_form_submit($form, &$form_state) {
   $node = node_load($form_state['values']['nid']);
-  $comment = $form['#builder_function']($form, $form_state);
+  $comment = comment_form_submit_build_comment($form, $form_state);
   if (user_access('post comments') && (user_access('administer comments') || $node->comment == COMMENT_NODE_OPEN)) {
     // Save the anonymous user information to a cookie for reuse.
     if (!$comment->uid) {
@@ -2227,6 +2279,7 @@ function template_preprocess_comment(&$variables) {
 
   $variables['title']     = l($comment->subject, $uri['path'], $uri['options']);
   $variables['permalink'] = l(t('Permalink'), $uri['path'], $uri['options']);
+  $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['author'], '!datetime' => $variables['created']));
 
   // Preprocess fields.
   field_attach_preprocess('comment', $comment, $variables['elements'], $variables);
@@ -2285,7 +2338,8 @@ function theme_comment_post_forbidden($variables) {
     if (!isset($authenticated_post_comments)) {
       // We only output a link if we are certain that users will get permission
       // to post comments by logging in.
-      $authenticated_post_comments = array_key_exists(DRUPAL_AUTHENTICATED_RID, user_roles(TRUE, 'post comments') + user_roles(TRUE, 'skip comment approval'));
+      $comment_roles = user_roles(TRUE, 'post comments');
+      $authenticated_post_comments = isset($comment_roles[DRUPAL_AUTHENTICATED_RID]);
     }
 
     if ($authenticated_post_comments) {
@@ -2320,6 +2374,8 @@ function template_preprocess_comment_wrapper(&$variables) {
   // Provide contextual information.
   $variables['node'] = $variables['content']['#node'];
   $variables['display_mode'] = variable_get('comment_default_mode_' . $variables['node']->type, COMMENT_MODE_THREADED);
+  // The comment form is optional and may not exist.
+  $variables['content'] += array('comment_form' => array());
 }
 
 /**
@@ -2472,13 +2528,13 @@ function comment_action_info() {
  * @ingroup actions
  */
 function comment_publish_action($comment, $context = array()) {
-  if (isset($comment->comment)) {
+  if (isset($comment->subject)) {
     $subject = $comment->subject;
     $comment->status = COMMENT_PUBLISHED;
   }
   else {
     $cid = $context['cid'];
-    $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid', $cid))->fetchField();
+    $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
     db_update('comment')
       ->fields(array('status' => COMMENT_PUBLISHED))
       ->condition('cid', $cid)
@@ -2499,13 +2555,13 @@ function comment_publish_action($comment, $context = array()) {
  * @ingroup actions
  */
 function comment_unpublish_action($comment, $context = array()) {
-  if (isset($comment->comment)) {
+  if (isset($comment->subject)) {
     $subject = $comment->subject;
     $comment->status = COMMENT_NOT_PUBLISHED;
   }
   else {
     $cid = $context['cid'];
-    $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid', $cid))->fetchField();
+    $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
     db_update('comment')
       ->fields(array('status' => COMMENT_NOT_PUBLISHED))
       ->condition('cid', $cid)
diff --git a/modules/comment/comment.pages.inc b/modules/comment/comment.pages.inc
index df78493b457adbd1f51cf0270154dd1b4d0dd1f5..791974e56144e2e1168f52724888110e4e7d0ef6 100644
--- a/modules/comment/comment.pages.inc
+++ b/modules/comment/comment.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.pages.inc,v 1.40 2010/09/09 23:01:48 dries Exp $
+// $Id: comment.pages.inc,v 1.41 2011/01/02 23:54:05 webchick Exp $
 
 /**
  * @file
@@ -33,26 +33,26 @@ function comment_reply($node, $pid = NULL) {
   $op = isset($_POST['op']) ? $_POST['op'] : '';
   $build = array();
 
-  if (user_access('access comments')) {
-    // The user is previewing a comment prior to submitting it.
-    if ($op == t('Preview')) {
-      if (user_access('post comments')) {
-        $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) array('pid' => $pid, 'nid' => $node->nid));
-      }
-      else {
-        drupal_set_message(t('You are not authorized to post comments.'), 'error');
-        drupal_goto("node/$node->nid");
-      }
+  // The user is previewing a comment prior to submitting it.
+  if ($op == t('Preview')) {
+    if (user_access('post comments')) {
+      $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) array('pid' => $pid, 'nid' => $node->nid));
     }
     else {
-      // $pid indicates that this is a reply to a comment.
-      if ($pid) {
+      drupal_set_message(t('You are not authorized to post comments.'), 'error');
+      drupal_goto("node/$node->nid");
+    }
+  }
+  else {
+    // $pid indicates that this is a reply to a comment.
+    if ($pid) {
+      if (user_access('access comments')) {
         // Load the comment whose cid = $pid
         $comment = db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data FROM {comment} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = :cid AND c.status = :status', array(
           ':cid' => $pid,
           ':status' => COMMENT_PUBLISHED,
         ))->fetchObject();
-        if ( $comment ) {
+        if ($comment) {
           // If that comment exists, make sure that the current comment and the
           // parent comment both belong to the same parent node.
           if ($comment->nid != $node->nid) {
@@ -71,29 +71,29 @@ function comment_reply($node, $pid = NULL) {
           drupal_goto("node/$node->nid");
         }
       }
-      // This is the case where the comment is in response to a node. Display the node.
-      elseif (user_access('access content')) {
-        $build['comment_node'] = node_view($node);
-      }
-
-      // Should we show the reply box?
-      if ($node->comment != COMMENT_NODE_OPEN) {
-        drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
-        drupal_goto("node/$node->nid");
-      }
-      elseif (user_access('post comments')) {
-        $edit = array('nid' => $node->nid, 'pid' => $pid);
-        $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) $edit);
-      }
       else {
-        drupal_set_message(t('You are not authorized to post comments.'), 'error');
+        drupal_set_message(t('You are not authorized to view comments.'), 'error');
         drupal_goto("node/$node->nid");
       }
     }
-  }
-  else {
-    drupal_set_message(t('You are not authorized to view comments.'), 'error');
-    drupal_goto("node/$node->nid");
+    // This is the case where the comment is in response to a node. Display the node.
+    elseif (user_access('access content')) {
+      $build['comment_node'] = node_view($node);
+    }
+
+    // Should we show the reply box?
+    if ($node->comment != COMMENT_NODE_OPEN) {
+      drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
+      drupal_goto("node/$node->nid");
+    }
+    elseif (user_access('post comments')) {
+      $edit = array('nid' => $node->nid, 'pid' => $pid);
+      $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", (object) $edit);
+    }
+    else {
+      drupal_set_message(t('You are not authorized to post comments.'), 'error');
+      drupal_goto("node/$node->nid");
+    }
   }
 
   return $build;
diff --git a/modules/comment/comment.test b/modules/comment/comment.test
index 0f423ec45dee1f8551e6cd17492b15e686a99eb3..8e3a92ff36e5fe5d5d73bd9288cf13f791b2e541 100644
--- a/modules/comment/comment.test
+++ b/modules/comment/comment.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.test,v 1.90 2010/10/05 06:17:28 webchick Exp $
+// $Id: comment.test,v 1.98 2011/01/02 23:54:05 webchick Exp $
 
 class CommentHelperCase extends DrupalWebTestCase {
   protected $admin_user;
@@ -226,7 +226,7 @@ class CommentHelperCase extends DrupalWebTestCase {
 
     if ($operation == 'delete') {
       $this->drupalPost(NULL, array(), t('Delete comments'));
-      $this->assertRaw(t('Deleted @count comments.', array('@count' => 1)), t('Operation "' . $operation . '" was performed on comment.'));
+      $this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), t('Operation "' . $operation . '" was performed on comment.'));
     }
     else {
       $this->assertText(t('The update has been performed.'), t('Operation "' . $operation . '" was performed on comment.'));
@@ -390,6 +390,363 @@ class CommentInterfaceTest extends CommentHelperCase {
     $this->drupalLogin($this->admin_user);
     $this->setCommentForm(FALSE);
   }
+
+  /**
+   * Tests the node comment statistics.
+   */
+  function testCommentNodeCommentStatistics() {
+    $langcode = LANGUAGE_NONE;
+    // Set comments to have subject and preview disabled.
+    $this->drupalLogin($this->admin_user);
+    $this->setCommentPreview(DRUPAL_DISABLED);
+    $this->setCommentForm(TRUE);
+    $this->setCommentSubject(FALSE);
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Comment paging changed.'));
+    $this->drupalLogout();
+
+    // Creates a second user to post comments.
+    $this->web_user2 = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content', 'edit own comments'));
+
+    // Checks the initial values of node comment statistics with no comment.
+    $node = node_load($this->node->nid);
+    $this->assertEqual($node->last_comment_timestamp, $this->node->created, t('The initial value of node last_comment_timestamp is the node created date.'));
+    $this->assertEqual($node->last_comment_name, NULL, t('The initial value of node last_comment_name is NULL.'));
+    $this->assertEqual($node->last_comment_uid, $this->web_user->uid, t('The initial value of node last_comment_uid is the node uid.'));
+    $this->assertEqual($node->comment_count, 0, t('The initial value of node comment_count is zero.'));
+
+    // Post comment #1 as web_user2.
+    $this->drupalLogin($this->web_user2);
+    $comment_text = $this->randomName();
+    $comment = $this->postComment($this->node, $comment_text);
+    $comment_loaded = comment_load($comment->id);
+
+    // Checks the new values of node comment statistics with comment #1.
+    // The node needs to be reloaded with a node_load_multiple cache reset.
+    $node = node_load($this->node->nid, NULL, TRUE);
+    $this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is NULL.'));
+    $this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is the comment #1 uid.'));
+    $this->assertEqual($node->comment_count, 1, t('The value of node comment_count is 1.'));
+
+    // Prepare for anonymous comment submission (comment approval enabled).
+    variable_set('user_register', USER_REGISTER_VISITORS);
+    $this->drupalLogin($this->admin_user);
+    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
+      'access comments' => TRUE,
+      'post comments' => TRUE,
+      'skip comment approval' => FALSE,
+    ));
+    // Ensure that the poster can leave some contact info.
+    $this->setCommentAnonymous('1');
+    $this->drupalLogout();
+
+    // Post comment #2 as anonymous (comment approval enabled).
+    $this->drupalGet('comment/reply/' . $this->node->nid);
+    $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', TRUE);
+    $comment_unpublished_loaded = comment_load($anonymous_comment->id);
+
+    // Checks the new values of node comment statistics with comment #2 and
+    // ensure they haven't changed since the comment has not been moderated.
+    // The node needs to be reloaded with a node_load_multiple cache reset.
+    $node = node_load($this->node->nid, NULL, TRUE);
+    $this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is still NULL.'));
+    $this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is still the comment #1 uid.'));
+    $this->assertEqual($node->comment_count, 1, t('The value of node comment_count is still 1.'));
+
+    // Prepare for anonymous comment submission (no approval required).
+    $this->drupalLogin($this->admin_user);
+    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
+      'access comments' => TRUE,
+      'post comments' => TRUE,
+      'skip comment approval' => TRUE,
+    ));
+    $this->drupalLogout();
+
+    // Post comment #3 as anonymous.
+    $this->drupalGet('comment/reply/' . $this->node->nid);
+    $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', array('name' => $this->randomName()));
+    $comment_loaded = comment_load($anonymous_comment->id);
+
+    // Checks the new values of node comment statistics with comment #3.
+    // The node needs to be reloaded with a node_load_multiple cache reset.
+    $node = node_load($this->node->nid, NULL, TRUE);
+    $this->assertEqual($node->last_comment_name, $comment_loaded->name, t('The value of node last_comment_name is the name of the anonymous user.'));
+    $this->assertEqual($node->last_comment_uid, 0, t('The value of node last_comment_uid is zero.'));
+    $this->assertEqual($node->comment_count, 2, t('The value of node comment_count is 2.'));
+  }
+
+  /**
+   * Tests comment links.
+   *
+   * The output of comment links depends on various environment conditions:
+   * - Various Comment module configuration settings, user registration
+   *   settings, and user access permissions.
+   * - Whether the user is authenticated or not, and whether any comments exist.
+   *
+   * To account for all possible cases, this test creates permutations of all
+   * possible conditions and tests the expected appearance of comment links in
+   * each environment.
+   */
+  function testCommentLinks() {
+    // Bartik theme alters comment links, so use a different theme.
+    theme_enable(array('garland'));
+    variable_set('theme_default', 'garland');
+
+    // Remove additional user permissions from $this->web_user added by setUp(),
+    // since this test is limited to anonymous and authenticated roles only.
+    user_role_delete(key($this->web_user->roles));
+
+    // Matrix of possible environmental conditions and configuration settings.
+    // See setEnvironment() for details.
+    $conditions = array(
+      'authenticated'   => array(FALSE, TRUE),
+      'comment count'   => array(FALSE, TRUE),
+      'access comments' => array(0, 1),
+      'post comments'   => array(0, 1),
+      'form'            => array(COMMENT_FORM_BELOW, COMMENT_FORM_SEPARATE_PAGE),
+      // USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL is irrelevant for this
+      // test; there is only a difference between open and closed registration.
+      'user_register'   => array(USER_REGISTER_VISITORS, USER_REGISTER_ADMINISTRATORS_ONLY),
+      // @todo Complete test coverage for:
+      //'comments'        => array(COMMENT_NODE_OPEN, COMMENT_NODE_CLOSED, COMMENT_NODE_HIDDEN),
+      //// COMMENT_ANONYMOUS_MUST_CONTACT is irrelevant for this test.
+      //'contact '        => array(COMMENT_ANONYMOUS_MAY_CONTACT, COMMENT_ANONYMOUS_MAYNOT_CONTACT),
+    );
+
+    $environments = $this->generatePermutations($conditions);
+    foreach ($environments as $info) {
+      $this->assertCommentLinks($info);
+    }
+  }
+
+  /**
+   * Re-configures the environment, module settings, and user permissions.
+   *
+   * @param $info
+   *   An associative array describing the environment to setup:
+   *   - Environment conditions:
+   *     - authenticated: Boolean whether to test with $this->web_user or
+   *       anonymous.
+   *     - comment count: Boolean whether to test with a new/unread comment on
+   *       $this->node or no comments.
+   *   - Configuration settings:
+   *     - form: COMMENT_FORM_BELOW or COMMENT_FORM_SEPARATE_PAGE.
+   *     - user_register: USER_REGISTER_ADMINISTRATORS_ONLY or
+   *       USER_REGISTER_VISITORS.
+   *     - contact: COMMENT_ANONYMOUS_MAY_CONTACT or
+   *       COMMENT_ANONYMOUS_MAYNOT_CONTACT.
+   *     - comments: COMMENT_NODE_OPEN, COMMENT_NODE_CLOSED, or
+   *       COMMENT_NODE_HIDDEN.
+   *   - User permissions:
+   *     These are granted or revoked for the user, according to the
+   *     'authenticated' flag above. Pass 0 or 1 as parameter values. See
+   *     user_role_change_permissions().
+   *     - access comments
+   *     - post comments
+   *     - skip comment approval
+   *     - edit own comments
+   */
+  function setEnvironment(array $info) {
+    static $current;
+
+    // Apply defaults to initial environment.
+    if (!isset($current)) {
+      $current = array(
+        'authenticated' => FALSE,
+        'comment count' => FALSE,
+        'form' => COMMENT_FORM_BELOW,
+        'user_register' => USER_REGISTER_VISITORS,
+        'contact' => COMMENT_ANONYMOUS_MAY_CONTACT,
+        'comments' => COMMENT_NODE_OPEN,
+        'access comments' => 0,
+        'post comments' => 0,
+        // Enabled by default, because it's irrelevant for this test.
+        'skip comment approval' => 1,
+        'edit own comments' => 0,
+      );
+    }
+    // Complete new environment with current environment.
+    $info = array_merge($current, $info);
+
+    // Change environment conditions.
+    if ($current['authenticated'] != $info['authenticated']) {
+      if ($this->loggedInUser) {
+        $this->drupalLogout();
+      }
+      else {
+        $this->drupalLogin($this->web_user);
+      }
+    }
+    if ($current['comment count'] != $info['comment count']) {
+      if ($info['comment count']) {
+        // Create a comment via CRUD API functionality, since
+        // $this->postComment() relies on actual user permissions.
+        $comment = (object) array(
+          'cid' => NULL,
+          'nid' => $this->node->nid,
+          'node_type' => $this->node->type,
+          'pid' => 0,
+          'uid' => 0,
+          'status' => COMMENT_PUBLISHED,
+          'subject' => $this->randomName(),
+          'hostname' => ip_address(),
+          'language' => LANGUAGE_NONE,
+          'comment_body' => array(LANGUAGE_NONE => array($this->randomName())),
+        );
+        comment_save($comment);
+        $this->comment = $comment;
+
+        // comment_num_new() relies on node_last_viewed(), so ensure that no one
+        // has seen the node of this comment.
+        db_delete('history')->condition('nid', $this->node->nid)->execute();
+      }
+      else {
+        $cids = db_query("SELECT cid FROM {comment}")->fetchCol();
+        comment_delete_multiple($cids);
+        unset($this->comment);
+      }
+    }
+
+    // Change comment settings.
+    variable_set('comment_form_location_' . $this->node->type, $info['form']);
+    variable_set('comment_anonymous_' . $this->node->type, $info['contact']);
+    if ($this->node->comment != $info['comments']) {
+      $this->node->comment = $info['comments'];
+      node_save($this->node);
+    }
+
+    // Change user settings.
+    variable_set('user_register', $info['user_register']);
+
+    // Change user permissions.
+    $rid = ($this->loggedInUser ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID);
+    $perms = array_intersect_key($info, array('access comments' => 1, 'post comments' => 1, 'skip comment approval' => 1, 'edit own comments' => 1));
+    user_role_change_permissions($rid, $perms);
+
+    // Output verbose debugging information.
+    // @see DrupalTestCase::error()
+    $t_form = array(
+      COMMENT_FORM_BELOW => 'below',
+      COMMENT_FORM_SEPARATE_PAGE => 'separate page',
+    );
+    $t_contact = array(
+      COMMENT_ANONYMOUS_MAY_CONTACT => 'optional',
+      COMMENT_ANONYMOUS_MAYNOT_CONTACT => 'disabled',
+      COMMENT_ANONYMOUS_MUST_CONTACT => 'required',
+    );
+    $t_comments = array(
+      COMMENT_NODE_OPEN => 'open',
+      COMMENT_NODE_CLOSED => 'closed',
+      COMMENT_NODE_HIDDEN => 'hidden',
+    );
+    $verbose = $info;
+    $verbose['form'] = $t_form[$info['form']];
+    $verbose['contact'] = $t_contact[$info['contact']];
+    $verbose['comments'] = $t_comments[$info['comments']];
+    $message = t('Changed environment:<pre>@verbose</pre>', array(
+      '@verbose' => var_export($verbose, TRUE),
+    ));
+    $this->assert('debug', $message, 'Debug');
+
+    // Update current environment.
+    $current = $info;
+
+    return $info;
+  }
+
+  /**
+   * Asserts that comment links appear according to the passed environment setup.
+   *
+   * @param $info
+   *   An associative array describing the environment to pass to
+   *   setEnvironment().
+   */
+  function assertCommentLinks(array $info) {
+    $info = $this->setEnvironment($info);
+
+    $nid = $this->node->nid;
+
+    foreach (array('', "node/$nid") as $path) {
+      $this->drupalGet($path);
+
+      // User is allowed to view comments.
+      if ($info['access comments']) {
+        if ($path == '') {
+          // In teaser view, a link containing the comment count is always
+          // expected.
+          if ($info['comment count']) {
+            $this->assertLink(t('1 comment'));
+
+            // For logged in users, a link containing the amount of new/unread
+            // comments is expected.
+            // See important note about comment_num_new() below.
+            if ($this->loggedInUser && isset($this->comment) && !isset($this->comment->seen)) {
+              $this->assertLink(t('1 new comment'));
+              $this->comment->seen = TRUE;
+            }
+          }
+        }
+      }
+      else {
+        $this->assertNoLink(t('1 comment'));
+        $this->assertNoLink(t('1 new comment'));
+      }
+      // comment_num_new() is based on node views, so comments are marked as
+      // read when a node is viewed, regardless of whether we have access to
+      // comments.
+      if ($path == "node/$nid" && $this->loggedInUser && isset($this->comment)) {
+        $this->comment->seen = TRUE;
+      }
+
+      // User is not allowed to post comments.
+      if (!$info['post comments']) {
+        $this->assertNoLink('Add new comment');
+
+        // Anonymous users should see a note to log in or register in case
+        // authenticated users are allowed to post comments.
+        // @see theme_comment_post_forbidden()
+        if (!$this->loggedInUser) {
+          if (user_access('post comments', $this->web_user)) {
+            // The note depends on whether users are actually able to register.
+            if ($info['user_register']) {
+              $this->assertText('Log in or register to post comments');
+            }
+            else {
+              $this->assertText('Log in to post comments');
+            }
+          }
+          else {
+            $this->assertNoText('Log in or register to post comments');
+            $this->assertNoText('Log in to post comments');
+          }
+        }
+      }
+      // User is allowed to post comments.
+      else {
+        $this->assertNoText('Log in or register to post comments');
+
+        // "Add new comment" is always expected, except when there are no
+        // comments or if the user cannot see them.
+        if ($path == "node/$nid" && $info['form'] == COMMENT_FORM_BELOW && (!$info['comment count'] || !$info['access comments'])) {
+          $this->assertNoLink('Add new comment');
+        }
+        else {
+          $this->assertLink('Add new comment');
+        }
+
+        // Also verify that the comment form appears according to the configured
+        // location.
+        if ($path == "node/$nid") {
+          $elements = $this->xpath('//form[@id=:id]', array(':id' => 'comment-form'));
+          if ($info['form'] == COMMENT_FORM_BELOW) {
+            $this->assertTrue(count($elements), t('Comment form found below.'));
+          }
+          else {
+            $this->assertFalse(count($elements), t('Comment form not found below.'));
+          }
+        }
+      }
+    }
+  }
 }
 
 /**
@@ -436,9 +793,9 @@ class CommentPreviewTest extends CommentHelperCase {
   }
 
   /**
-   * Test comment edit and preview.
+   * Test comment edit, preview, and save.
    */
-  function testCommentEditPreview() {
+  function testCommentEditPreviewSave() {
     $langcode = LANGUAGE_NONE;
     $web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'skip comment approval'));
     $this->drupalLogin($this->admin_user);
@@ -452,7 +809,9 @@ class CommentPreviewTest extends CommentHelperCase {
     $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
     $edit['name'] = $web_user->name;
     $edit['date'] = '2008-03-02 17:23 +0300';
-    $expected_date = format_date(strtotime($edit['date']));
+    $raw_date = strtotime($edit['date']);
+    $expected_text_date = format_date($raw_date);
+    $expected_form_date = format_date($raw_date, 'custom', 'Y-m-d H:i O');
     $comment = $this->postComment($this->node, $edit['subject'], $edit['comment_body[' . $langcode . '][0][value]'], TRUE);
     $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Preview'));
 
@@ -461,13 +820,40 @@ class CommentPreviewTest extends CommentHelperCase {
     $this->assertText($edit['subject'], t('Subject displayed.'));
     $this->assertText($edit['comment_body[' . $langcode . '][0][value]'], t('Comment displayed.'));
     $this->assertText($edit['name'], t('Author displayed.'));
-    $this->assertText($expected_date, t('Date displayed.'));
+    $this->assertText($expected_text_date, t('Date displayed.'));
 
-    // Check that the title and body fields are displayed with the correct values.
+    // Check that the subject, comment, author and date fields are displayed with the correct values.
     $this->assertFieldByName('subject', $edit['subject'], t('Subject field displayed.'));
     $this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], t('Comment field displayed.'));
     $this->assertFieldByName('name', $edit['name'], t('Author field displayed.'));
     $this->assertFieldByName('date', $edit['date'], t('Date field displayed.'));
+
+    // Check that saving a comment produces a success message.
+    $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Save'));
+    $this->assertText(t('Your comment has been posted.'), t('Comment posted.'));
+
+    // Check that the comment fields are correct after loading the saved comment.
+    $this->drupalGet('comment/' . $comment->id . '/edit');
+    $this->assertFieldByName('subject', $edit['subject'], t('Subject field displayed.'));
+    $this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], t('Comment field displayed.'));
+    $this->assertFieldByName('name', $edit['name'], t('Author field displayed.'));
+    $this->assertFieldByName('date', $expected_form_date, t('Date field displayed.'));
+
+    // Submit the form using the displayed values.
+    $displayed = array();
+    $displayed['subject'] = (string) current($this->xpath("//input[@id='edit-subject']/@value"));
+    $displayed['comment_body[' . $langcode . '][0][value]'] = (string) current($this->xpath("//textarea[@id='edit-comment-body-" . $langcode . "-0-value']"));
+    $displayed['name'] = (string) current($this->xpath("//input[@id='edit-name']/@value"));
+    $displayed['date'] = (string) current($this->xpath("//input[@id='edit-date']/@value"));
+    $this->drupalPost('comment/' . $comment->id . '/edit', $displayed, t('Save'));
+
+    // Check that the saved comment is still correct.
+    $comment_loaded = comment_load($comment->id);
+    $this->assertEqual($comment_loaded->subject, $edit['subject'], t('Subject loaded.'));
+    $this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], t('Comment body loaded.'));
+    $this->assertEqual($comment_loaded->name, $edit['name'], t('Name loaded.'));
+    $this->assertEqual($comment_loaded->created, $raw_date, t('Date loaded.'));
+
   }
 
 }
@@ -522,11 +908,12 @@ class CommentAnonymous extends CommentHelperCase {
     $this->assertTrue($this->commentExists($anonymous_comment2), t('Anonymous comment with contact info (optional) found.'));
 
     // Ensure anonymous users cannot post in the name of registered users.
+    $langcode = LANGUAGE_NONE;
     $edit = array(
       'name' => $this->admin_user->name,
       'mail' => $this->randomName() . '@example.com',
       'subject' => $this->randomName(),
-      'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
+      "comment_body[$langcode][0][value]" => $this->randomName(),
     );
     $this->drupalPost('comment/reply/' . $this->node->nid, $edit, t('Save'));
     $this->assertText(t('The name you used belongs to a registered user.'));
@@ -586,14 +973,14 @@ class CommentAnonymous extends CommentHelperCase {
     // NOTE: if authenticated user has permission to post comments, then a
     // "Login or register to post comments" type link may be shown.
     $this->drupalGet('node/' . $this->node->nid);
-    $this->assertNoPattern('/<div ([^>]*?)id="comments"([^>]*?)>/', t('Comments were not displayed.'));
+    $this->assertNoPattern('@<h2[^>]*>Comments</h2>@', t('Comments were not displayed.'));
     $this->assertNoLink('Add new comment', t('Link to add comment was found.'));
 
     // Attempt to view node-comment form while disallowed.
     $this->drupalGet('comment/reply/' . $this->node->nid);
-    $this->assertText('You are not authorized to view comments', t('Error attempting to post comment.'));
+    $this->assertText('You are not authorized to post comments', t('Error attempting to post comment.'));
     $this->assertNoFieldByName('subject', '', t('Subject field not found.'));
-    $this->assertNoFieldByName('comment[value]', '', t('Comment field not found.'));
+    $this->assertNoFieldByName("comment_body[$langcode][0][value]", '', t('Comment field not found.'));
 
     user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
       'access comments' => TRUE,
@@ -601,9 +988,23 @@ class CommentAnonymous extends CommentHelperCase {
       'skip comment approval' => FALSE,
     ));
     $this->drupalGet('node/' . $this->node->nid);
-    $this->assertPattern('/<div ([^>]*?)id="comments"([^>]*?)>/', t('Comments were displayed.'));
+    $this->assertPattern('@<h2[^>]*>Comments</h2>@', t('Comments were displayed.'));
     $this->assertLink('Log in', 1, t('Link to log in was found.'));
     $this->assertLink('register', 1, t('Link to register was found.'));
+
+    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
+      'access comments' => FALSE,
+      'post comments' => TRUE,
+      'skip comment approval' => TRUE,
+    ));
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertNoPattern('@<h2[^>]*>Comments</h2>@', t('Comments were not displayed.'));
+    $this->assertFieldByName('subject', '', t('Subject field found.'));
+    $this->assertFieldByName("comment_body[$langcode][0][value]", '', t('Comment field found.'));
+
+    $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $anonymous_comment3->id);
+    $this->assertText('You are not authorized to view comments', t('Error attempting to post reply.'));
+    $this->assertNoText($author_name, t('Comment not displayed.'));
   }
 }
 
@@ -873,6 +1274,75 @@ class CommentPagerTest extends CommentHelperCase {
   }
 }
 
+/**
+ * Tests comments with node access.
+ *
+ * See http://drupal.org/node/886752 -- verify there is no PostgreSQL error when
+ * viewing a node with threaded comments (a comment and a reply), if a node
+ * access module is in use.
+ */
+class CommentNodeAccessTest extends CommentHelperCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment node access',
+      'description' => 'Test comment viewing with node access.',
+      'group' => 'Comment',
+    );
+  }
+
+  function setUp() {
+    DrupalWebTestCase::setUp('comment', 'search', 'node_access_test');
+    node_access_rebuild();
+
+    // Create users and test node.
+    $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer blocks'));
+    $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content', 'edit own comments', 'node test view'));
+    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->web_user->uid));
+  }
+
+  /**
+   * Test that threaded comments can be viewed.
+   */
+  function testThreadedCommentView() {
+    $langcode = LANGUAGE_NONE;
+    // Set comments to have subject required and preview disabled.
+    $this->drupalLogin($this->admin_user);
+    $this->setCommentPreview(DRUPAL_DISABLED);
+    $this->setCommentForm(TRUE);
+    $this->setCommentSubject(TRUE);
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Comment paging changed.'));
+    $this->drupalLogout();
+
+    // Post comment.
+    $this->drupalLogin($this->web_user);
+    $comment_text = $this->randomName();
+    $comment_subject = $this->randomName();
+    $comment = $this->postComment($this->node, $comment_text, $comment_subject);
+    $comment_loaded = comment_load($comment->id);
+    $this->assertTrue($this->commentExists($comment), t('Comment found.'));
+
+    // Check comment display.
+    $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
+    $this->assertText($comment_subject, t('Individual comment subject found.'));
+    $this->assertText($comment_text, t('Individual comment body found.'));
+
+    // Reply to comment, creating second comment.
+    $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
+    $reply_text = $this->randomName();
+    $reply_subject = $this->randomName();
+    $reply = $this->postComment(NULL, $reply_text, $reply_subject, TRUE);
+    $reply_loaded = comment_load($reply->id);
+    $this->assertTrue($this->commentExists($reply, TRUE), t('Reply found.'));
+
+    // Go to the node page and verify comment and reply are visible.
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertText($comment_text);
+    $this->assertText($comment_subject);
+    $this->assertText($reply_text);
+    $this->assertText($reply_subject);
+  }
+}
+
 class CommentApprovalTest extends CommentHelperCase {
   public static function getInfo() {
     return array(
@@ -1257,3 +1727,165 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
     }
   }
 }
+
+/**
+ * Test actions provided by the comment module.
+ */
+class CommentActionsTestCase extends CommentHelperCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment actions',
+      'description' => 'Test actions provided by the comment module.',
+      'group' => 'Comment',
+    );
+  }
+
+  /**
+   * Test comment publish and unpublish actions.
+   */
+  function testCommentPublishUnpublishActions() {
+    $this->drupalLogin($this->web_user);
+    $comment_text = $this->randomName();
+    $subject = $this->randomName();
+    $comment = $this->postComment($this->node, $comment_text, $subject);
+    $comment = comment_load($comment->id);
+
+    // Unpublish a comment (direct form: doesn't actually save the comment).
+    comment_unpublish_action($comment);
+    $this->assertEqual($comment->status, COMMENT_NOT_PUBLISHED, t('Comment was unpublished'));
+    $this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
+    $this->clearWatchdog();
+
+    // Unpublish a comment (indirect form: modify the comment in the database).
+    comment_unpublish_action(NULL, array('cid' => $comment->cid));
+    $this->assertEqual(comment_load($comment->cid)->status, COMMENT_NOT_PUBLISHED, t('Comment was unpublished'));
+    $this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
+
+    // Publish a comment (direct form: doesn't actually save the comment).
+    comment_publish_action($comment);
+    $this->assertEqual($comment->status, COMMENT_PUBLISHED, t('Comment was published'));
+    $this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
+    $this->clearWatchdog();
+
+    // Publish a comment (indirect form: modify the comment in the database).
+    comment_publish_action(NULL, array('cid' => $comment->cid));
+    $this->assertEqual(comment_load($comment->cid)->status, COMMENT_PUBLISHED, t('Comment was published'));
+    $this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
+    $this->clearWatchdog();
+  }
+
+  /**
+   * Verify that a watchdog message has been entered.
+   *
+   * @param $watchdog_message
+   *   The watchdog message.
+   * @param $variables
+   *   The array of variables passed to watchdog().
+   * @param $message
+   *   The assertion message.
+   */
+  function assertWatchdogMessage($watchdog_message, $variables, $message) {
+    $status = (bool) db_query_range("SELECT 1 FROM {watchdog} WHERE message = :message AND variables = :variables", 0, 1, array(':message' => $watchdog_message, ':variables' => serialize($variables)))->fetchField();
+    return $this->assert($status, $message);
+  }
+
+  /**
+   * Helper function: clear the watchdog.
+   */
+  function clearWatchdog() {
+    db_truncate('watchdog')->execute();
+  }
+}
+
+/**
+ * Test fields on comments.
+ */
+class CommentFieldsTest extends CommentHelperCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment fields',
+      'description' => 'Tests fields on comments.',
+      'group' => 'Comment',
+    );
+  }
+
+  /**
+   * Tests that the default 'comment_body' field is correctly added.
+   */
+  function testCommentDefaultFields() {
+    // Do not make assumptions on default node types created by the test
+    // install profile, and create our own.
+    $this->drupalCreateContentType(array('type' => 'test_node_type'));
+
+    // Check that the 'comment_body' field is present on all comment bundles.
+    $instances = field_info_instances('comment');
+    foreach (node_type_get_types() as $type_name => $info) {
+      $this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), t('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
+
+      // Delete the instance along the way.
+      field_delete_instance($instances['comment_node_' . $type_name]['comment_body']);
+    }
+
+    // Check that the 'comment_body' field is deleted.
+    $field = field_info_field('comment_body');
+    $this->assertTrue(empty($field), t('The comment_body field was deleted'));
+
+    // Create a new content type.
+    $type_name = 'test_node_type_2';
+    $this->drupalCreateContentType(array('type' => $type_name));
+
+    // Check that the 'comment_body' field exists and has an instance on the
+    // new comment bundle.
+    $field = field_info_field('comment_body');
+    $this->assertTrue($field, t('The comment_body field exists'));
+    $instances = field_info_instances('comment');
+    $this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), t('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
+  }
+
+  /**
+   * Test that comment module works when enabled after a content module.
+   */
+  function testCommentEnable() {
+    // Create a user to do module administration.
+    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules'));
+    $this->drupalLogin($this->admin_user);
+
+    // Disable the comment module.
+    $edit = array();
+    $edit['modules[Core][comment][enable]'] = FALSE;
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->resetAll();
+    $this->assertFalse(module_exists('comment'), t('Comment module disabled.'));
+
+    // Enable core content type modules (blog, book, and poll).
+    $edit = array();
+    $edit['modules[Core][blog][enable]'] = 'blog';
+    $edit['modules[Core][book][enable]'] = 'book';
+    $edit['modules[Core][poll][enable]'] = 'poll';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->resetAll();
+
+    // Now enable the comment module.
+    $edit = array();
+    $edit['modules[Core][comment][enable]'] = 'comment';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->resetAll();
+    $this->assertTrue(module_exists('comment'), t('Comment module enabled.'));
+
+    // Create nodes of each type.
+    $blog_node = $this->drupalCreateNode(array('type' => 'blog'));
+    $book_node = $this->drupalCreateNode(array('type' => 'book'));
+    $poll_node = $this->drupalCreateNode(array('type' => 'poll', 'active' => 1, 'runtime' => 0, 'choice' => array(array('chtext' => ''))));
+
+    $this->drupalLogout();
+
+    // Try to post a comment on each node. A failure will be triggered if the
+    // comment body is missing on one of these forms, due to postComment()
+    // asserting that the body is actually posted correctly.
+    $this->web_user = $this->drupalCreateUser(array('access content', 'access comments', 'post comments', 'skip comment approval'));
+    $this->drupalLogin($this->web_user);
+    $this->postComment($blog_node, $this->randomName(), $this->randomName());
+    $this->postComment($book_node, $this->randomName(), $this->randomName());
+    $this->postComment($poll_node, $this->randomName(), $this->randomName());
+  }
+}
diff --git a/modules/comment/comment.tpl.php b/modules/comment/comment.tpl.php
index 287a931d54545355cd7d07f9cfe982cdad63a602..3ef3858239841217431e43b49ef045f13d571f11 100644
--- a/modules/comment/comment.tpl.php
+++ b/modules/comment/comment.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.tpl.php,v 1.18 2010/01/07 05:23:51 webchick Exp $
+// $Id: comment.tpl.php,v 1.19 2010/12/01 00:18:15 webchick Exp $
 
 /**
  * @file
@@ -19,6 +19,8 @@
  *   desired parameters on the $comment->changed variable.
  * - $new: New comment marker.
  * - $permalink: Comment permalink.
+ * - $submitted: Submission information created from $author and $created during
+ *   template_preprocess_comment().
  * - $picture: Authors picture.
  * - $signature: Authors signature.
  * - $status: Comment status. Possible values are:
@@ -69,10 +71,7 @@
 
   <div class="submitted">
     <?php print $permalink; ?>
-    <?php
-      print t('Submitted by !username on !datetime.',
-        array('!username' => $author, '!datetime' => $created));
-    ?>
+    <?php print $submitted; ?>
   </div>
 
   <div class="content"<?php print $content_attributes; ?>>
diff --git a/modules/contact/contact.info b/modules/contact/contact.info
index e0afaa59b585408cbb56f220974f8bca10c29e62..f44e025e4e4f2079da8300556a8e9ddbb3f8c080 100644
--- a/modules/contact/contact.info
+++ b/modules/contact/contact.info
@@ -1,18 +1,14 @@
-; $Id: contact.info,v 1.10 2009/11/17 21:24:18 dries Exp $
+; $Id: contact.info,v 1.11 2010/12/20 19:59:41 webchick Exp $
 name = Contact
 description = Enables the use of both personal and site-wide contact forms.
 package = Core
 version = VERSION
 core = 7.x
-files[] = contact.module
-files[] = contact.admin.inc
-files[] = contact.pages.inc
-files[] = contact.install
 files[] = contact.test
 configure = admin/structure/contact
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/contact/contact.install b/modules/contact/contact.install
index 3011f8df5106eb766541343109c7d9b9ce8efcd9..c0e570c33c68eccee0b5bb4d76acbead73a2270d 100644
--- a/modules/contact/contact.install
+++ b/modules/contact/contact.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: contact.install,v 1.25 2010/06/08 03:48:14 webchick Exp $
+// $Id: contact.install,v 1.26 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -90,7 +90,7 @@ function contact_uninstall() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Contact updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -146,6 +146,5 @@ function contact_update_7003() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/contact/contact.module b/modules/contact/contact.module
index b424d95e60099984829eb245473b0cd7bcf8754d..7ecaa671ee0c03c77a5b605f0abf1260fbe9e581 100644
--- a/modules/contact/contact.module
+++ b/modules/contact/contact.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: contact.module,v 1.148 2010/09/24 00:37:42 dries Exp $
+// $Id: contact.module,v 1.150 2010/12/20 19:59:41 webchick Exp $
 
 /**
  * @file
@@ -116,7 +116,7 @@ function contact_menu() {
  *   TRUE if the current user has access to the requested user's contact form,
  *   or FALSE otherwise.
  */
-function _contact_personal_tab_access(stdClass $account) {
+function _contact_personal_tab_access($account) {
   global $user;
 
   // Anonymous users cannot have contact forms.
@@ -239,7 +239,7 @@ function contact_user_presave(&$edit, $account, $category) {
 }
 
 /**
- * Implement of hook_form_FORM_ID_alter().
+ * Implements hook_form_FORM_ID_alter().
  *
  * Add the default personal contact setting on the user settings page.
  */
@@ -253,6 +253,6 @@ function contact_form_user_admin_settings_alter(&$form, &$form_state) {
     '#type' => 'checkbox',
     '#title' => t('Enable the personal contact form by default for new users.'),
     '#description' => t('Changing this setting will not affect existing users.'),
-    '#default_value' => 1,
+    '#default_value' => variable_get('contact_default_status', 1),
   );
 }
diff --git a/modules/contact/contact.pages.inc b/modules/contact/contact.pages.inc
index 0cf6c126f07fa2a244ae5cfdfc9df7711983d04c..21076e906d7ce01a66c7754e6a1b82ce1c3c2472 100644
--- a/modules/contact/contact.pages.inc
+++ b/modules/contact/contact.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: contact.pages.inc,v 1.44 2010/10/08 03:36:03 webchick Exp $
+// $Id: contact.pages.inc,v 1.45 2010/11/30 17:16:37 dries Exp $
 
 /**
  * @file
@@ -57,7 +57,7 @@ function contact_site_form($form, &$form_state) {
   }
 
   if (!$user->uid) {
-    $form['#attached']['library'][] = array('system', 'cookie');
+    $form['#attached']['library'][] = array('system', 'jquery.cookie');
     $form['#attributes']['class'][] = 'user-info-from-cookie';
   }
 
@@ -187,7 +187,7 @@ function contact_personal_form($form, &$form_state, $recipient) {
   drupal_set_title(t('Contact @username', array('@username' => format_username($recipient))), PASS_THROUGH);
 
   if (!$user->uid) {
-    $form['#attached']['library'][] = array('system', 'cookie');
+    $form['#attached']['library'][] = array('system', 'jquery.cookie');
     $form['#attributes']['class'][] = 'user-info-from-cookie';
   }
 
diff --git a/modules/contextual/contextual.css b/modules/contextual/contextual.css
index abaccbba9d85012a248f13ee777f422935a5f944..875fb5d6a76dcdb024d0518f3cfce175fe492986 100644
--- a/modules/contextual/contextual.css
+++ b/modules/contextual/contextual.css
@@ -1,4 +1,4 @@
-/* $Id: contextual.css,v 1.6 2010/06/04 20:38:55 dries Exp $ */
+/* $Id: contextual.css,v 1.9 2011/01/03 07:04:48 webchick Exp $ */
 
 /**
  * Contextual links regions.
@@ -36,9 +36,9 @@ a.contextual-links-trigger {
   text-indent: 34px; /* LTR */
   width: 28px;
   overflow: hidden;
+  -khtml-border-radius: 4px;
   -moz-border-radius: 4px;
   -webkit-border-radius: 4px;
-  -khtml-border-radius: 4px;
   border-radius: 4px;
 }
 a.contextual-links-trigger:hover,
@@ -53,8 +53,8 @@ div.contextual-links-active a.contextual-links-trigger {
   position: relative;
   z-index: 1;
   -moz-border-radius: 4px 4px 0 0;
-  -webkit-border-bottom-right-radius: 0;
   -webkit-border-bottom-left-radius: 0;
+  -webkit-border-bottom-right-radius: 0;
   border-radius: 4px 4px 0 0;
 }
 div.contextual-links-wrapper ul.contextual-links {
@@ -69,10 +69,10 @@ div.contextual-links-wrapper ul.contextual-links {
   top: 18px;
   white-space: nowrap;
   -moz-border-radius: 4px 0 4px 4px; /* LTR */
-  -webkit-border-top-left-radius: 4px; /* LTR */
-  -webkit-border-top-right-radius: 0; /* LTR */
-  -webkit-border-bottom-right-radius: 4px;
   -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-top-right-radius: 0; /* LTR */
+  -webkit-border-top-left-radius: 4px; /* LTR */
   border-radius: 4px 0 4px 4px; /* LTR */
 }
 .contextual-links-region:hover a.contextual-links-trigger,
diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info
index 820fe382f4e37a217683af8f16886510bf3a3a0f..a4678d97c9cf7c0521db6630d36d670171ee4440 100644
--- a/modules/contextual/contextual.info
+++ b/modules/contextual/contextual.info
@@ -1,13 +1,12 @@
-; $Id: contextual.info,v 1.1 2009/12/06 01:00:27 dries Exp $
+; $Id: contextual.info,v 1.2 2010/12/20 19:59:41 webchick Exp $
 name = Contextual links
 description = Provides contextual links to perform actions related to elements on a page.
 package = Core
 version = VERSION
 core = 7.x
-files[] = contextual.module
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/contextual/contextual.js b/modules/contextual/contextual.js
index f5abcff3aecb7bc7f527b20a241353951d80ef1e..59d5b0b8210dab54b3f373457280984779f541b0 100644
--- a/modules/contextual/contextual.js
+++ b/modules/contextual/contextual.js
@@ -1,4 +1,4 @@
-// $Id: contextual.js,v 1.5 2010/03/26 18:59:54 dries Exp $
+// $Id: contextual.js,v 1.6 2010/11/16 18:43:06 dries Exp $
 (function ($) {
 
 Drupal.contextualLinks = Drupal.contextualLinks || {};
@@ -24,8 +24,8 @@ Drupal.behaviors.contextualLinks = {
         function () { $region.addClass('contextual-links-region-active'); },
         function () { $region.removeClass('contextual-links-region-active'); }
       );
-      // Hide the contextual links when user rolls out of the .contextual-links-region.
-      $region.bind('mouseleave', Drupal.contextualLinks.mouseleave);
+      // Hide the contextual links when user clicks a link or rolls out of the .contextual-links-region.
+      $region.bind('mouseleave click', Drupal.contextualLinks.mouseleave);
       // Prepend the trigger.
       $wrapper.prepend($trigger);
     });
diff --git a/modules/contextual/contextual.module b/modules/contextual/contextual.module
index 5587a20b6182159161b6d19fe88e9f390f76d29b..8ed4d93aa5fef7a3724668edcbaccaa8a372eaef 100644
--- a/modules/contextual/contextual.module
+++ b/modules/contextual/contextual.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: contextual.module,v 1.8 2010/09/11 14:35:13 dries Exp $
+// $Id: contextual.module,v 1.9 2010/10/31 03:56:46 dries Exp $
 
 /**
  * @file
@@ -95,7 +95,7 @@ function contextual_preprocess(&$variables, $hook) {
   }
 
   // Determine the primary theme function argument.
-  if (isset($hooks[$hook]['variables'])) {
+  if (!empty($hooks[$hook]['variables'])) {
     $keys = array_keys($hooks[$hook]['variables']);
     $key = $keys[0];
   }
diff --git a/modules/contextual/images/gear-select.png b/modules/contextual/images/gear-select.png
index e8031d4482d809ab71ec6e790e8a8ebc650f786f..adf65822d442caf2f29dc8c1c0655e413d3a9c77 100644
Binary files a/modules/contextual/images/gear-select.png and b/modules/contextual/images/gear-select.png differ
diff --git a/modules/dashboard/dashboard.css b/modules/dashboard/dashboard.css
index 4b76dd530c0c0c1b33b96c37ae706582d96c5cfc..f1c0fcfc2055078aef528619137f490b54cec067 100644
--- a/modules/dashboard/dashboard.css
+++ b/modules/dashboard/dashboard.css
@@ -1,4 +1,4 @@
-/* $Id: dashboard.css,v 1.14 2010/08/30 00:22:03 webchick Exp $ */
+/* $Id: dashboard.css,v 1.16 2011/01/03 07:04:48 webchick Exp $ */
 
 #dashboard div.dashboard-region {
   float: left;
@@ -32,9 +32,13 @@
   padding: 6px 4px 6px 8px;
   margin: 3px 3px 3px 0;
   float: left;
-  border-radius: 4px;
   -moz-border-radius: 4px;
   -webkit-border-radius: 4px;
+  border-radius: 4px;
+}
+
+#dashboard .dashboard-add-other-blocks {
+  margin: 10px 0 0 0;
 }
 
 #dashboard .ui-sortable {
@@ -66,7 +70,6 @@
   background-color: #E0E0D8;
   border: #ccc 1px solid;
   padding: 10px;
-  min-height: 90px;
 }
 
 #dashboard #disabled-blocks {
diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info
index 28952d18b7640080ab90ecff5396d04dd40b0289..ac7c950974bb7f8ed4c8dff9671406e5a75f51c3 100644
--- a/modules/dashboard/dashboard.info
+++ b/modules/dashboard/dashboard.info
@@ -1,16 +1,15 @@
-; $Id: dashboard.info,v 1.4 2010/06/04 23:04:32 webchick Exp $
+; $Id: dashboard.info,v 1.5 2010/12/20 19:59:41 webchick Exp $
 name = Dashboard
 description = Provides a dashboard page in the administrative interface for organizing administrative tasks and tracking information within your site.
 core = 7.x
 package = Core
 version = VERSION
-files[] = dashboard.module
 files[] = dashboard.test
 dependencies[] = block
 configure = admin/dashboard/customize
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/dashboard/dashboard.install b/modules/dashboard/dashboard.install
new file mode 100644
index 0000000000000000000000000000000000000000..ab0e6dcb68b7483a0dd2fd46930d71e29d64c689
--- /dev/null
+++ b/modules/dashboard/dashboard.install
@@ -0,0 +1,79 @@
+<?php
+// $Id: dashboard.install,v 1.1 2010/11/01 00:44:31 webchick Exp $
+
+/**
+ * @file
+ * Install, update and uninstall functions for the dashboard module.
+ */
+
+/**
+ * Implements hook_disable().
+ *
+ * Stash a list of blocks enabled on the dashboard, so they can be re-enabled
+ * if the dashboard is re-enabled. Then disable those blocks, since the
+ * dashboard regions will no longer be defined.
+ */
+function dashboard_disable() {
+  // Stash a list of currently enabled blocks.
+  $stashed_blocks = array();
+
+  $result = db_select('block', 'b')
+    ->fields('b', array('module', 'delta', 'region'))
+    ->condition('b.region', dashboard_regions(), 'IN')
+    ->execute();
+
+  foreach ($result as $block) {
+    $stashed_blocks[] = array(
+      'module' => $block->module,
+      'delta' => $block->delta,
+      'region' => $block->region,
+    );
+  }
+  variable_set('dashboard_stashed_blocks', $stashed_blocks);
+
+  // Disable the dashboard blocks.
+  db_update('block')
+    ->fields(array(
+      'status' => 0,
+      'region' => BLOCK_REGION_NONE,
+    ))
+    ->condition('region', dashboard_regions(), 'IN')
+    ->execute();
+}
+
+/**
+ * Implements hook_enable().
+ *
+ * Restores blocks to the dashboard that were there when the dashboard module
+ * was disabled.
+ */
+function dashboard_enable() {
+  global $theme_key;
+  if (!$stashed_blocks = variable_get('dashboard_stashed_blocks')) {
+    return;
+  }
+  if (!$admin_theme = variable_get('admin_theme')) {
+    drupal_theme_initialize();
+    $admin_theme = $theme_key;
+  }
+  foreach ($stashed_blocks as $block) {
+    db_update('block')
+      ->fields(array(
+        'status' => 1,
+        'region' => $block['region']
+      ))
+      ->condition('module', $block['module'])
+      ->condition('delta', $block['delta'])
+      ->condition('theme', $admin_theme)
+      ->condition('status', 0)
+      ->execute();
+  }
+  variable_del('dashboard_stashed_blocks');
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function dashboard_uninstall() {
+  variable_del('dashboard_stashed_blocks');
+}
diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module
index 376090a61e26c36459478efe69840746ff37c995..d1e3582e388f8d12764b942c4e71b0f7d8dc67d6 100644
--- a/modules/dashboard/dashboard.module
+++ b/modules/dashboard/dashboard.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: dashboard.module,v 1.40 2010/10/21 11:55:08 dries Exp $
+// $Id: dashboard.module,v 1.41 2010/11/06 23:24:33 webchick Exp $
 
 /**
  * Implements hook_help().
@@ -9,7 +9,7 @@ function dashboard_help($path, $arg) {
     case 'admin/help#dashboard':
       $output = '';
       $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Dashboard module provides a <a href="@dashboard">Dashboard page</a> in the administrative interface for organizing administrative tasks and navigation, and tracking information within your site. The Dashboard page contains blocks, which you can add to and arrange using the drag and drop interface that appears when you click on the <em>Customize dashboard</em> link. For more information, see the online handbook entry for <a href="@handbook">Dashboard module</a>.', array('@handbook' => 'http://drupal.org/handbook/modules/dashboard', '@dashboard' => url('admin/dashboard'))) . '</p>';
+      $output .= '<p>' . t('The Dashboard module provides a <a href="@dashboard">Dashboard page</a> in the administrative interface for organizing administrative tasks and navigation, and tracking information within your site. The Dashboard page contains blocks, which you can add to and arrange using the drag-and-drop interface that appears when you click on the <em>Customize dashboard</em> link. Within this interface, blocks that are not primarily used for site administration do not appear by default, but can be added via the <em>Add other blocks</em> link. For more information, see the online handbook entry for <a href="@handbook">Dashboard module</a>.', array('@handbook' => 'http://drupal.org/handbook/modules/dashboard', '@dashboard' => url('admin/dashboard'))) . '</p>';
       $output .= '<h3>' . t('Uses') . '</h3>';
       $output .= '<dl>';
       $output .= '<dt>' . t('Tracking user activity') . '</dt>';
@@ -22,7 +22,7 @@ function dashboard_help($path, $arg) {
     case 'admin/dashboard/configure':
       // @todo This assumes the current page is being displayed using the same
       //   theme that the dashboard is displayed in.
-      $output = '<p>' . t('Rearrange blocks for display on the <a href="@dashboard-url">dashboard</a>. Disabling a block makes it available on the main <a href="@blocks-url">blocks administration page</a>.', array('@dashboard-url' => url('admin/dashboard'), '@blocks-url' => url("admin/structure/block/list/{$GLOBALS['theme_key']}"))) . '</p>';
+      $output = '<p>' . t('Rearrange blocks for display on the <a href="@dashboard-url">Dashboard page</a>. Blocks placed in the <em>Dashboard (inactive)</em> region are not displayed when viewing the Dashboard page, but are available within its <em>Customize dashboard</em> interface. Removing a block from active dashboard display makes it available on the main <a href="@blocks-url">blocks administration page</a>.', array('@dashboard-url' => url('admin/dashboard'), '@blocks-url' => url("admin/structure/block/list/{$GLOBALS['theme_key']}"))) . '</p>';
       return $output;
   }
 }
@@ -89,6 +89,25 @@ function dashboard_permission() {
   );
 }
 
+/**
+ * Implements hook_block_info_alter().
+ */
+function dashboard_block_info_alter(&$blocks, $theme, $code_blocks) {
+  $admin_theme = variable_get('admin_theme');
+  if (($admin_theme && $theme == $admin_theme) || (!$admin_theme && $theme == variable_get('theme_default', 'bartik'))) {
+    foreach ($blocks as $module => &$module_blocks) {
+      foreach ($module_blocks as $delta => &$block) {
+        // Make administrative blocks that are not already in use elsewhere
+        // available for the dashboard.
+        if (empty($block['status']) && (empty($block['region']) || $block['region'] == BLOCK_REGION_NONE) && !empty($code_blocks[$module][$delta]['properties']['administrative'])) {
+          $block['status'] = 1;
+          $block['region'] = 'dashboard_inactive';
+        }
+      }
+    }
+  }
+}
+
 /**
  * Implements hook_block_list_alter().
  *
@@ -121,6 +140,10 @@ function dashboard_page_build(&$page) {
     // region into it.
     $page['content']['dashboard'] = array('#theme_wrappers' => array('dashboard'));
     foreach (dashboard_regions() as $region) {
+      // Do not show dashboard blocks that are disabled.
+      if ($region == 'dashboard_inactive') {
+        continue;
+      }
       // Insert regions even when they are empty, so that they will be
       // displayed when the dashboard is being configured.
       $page['content']['dashboard'][$region] = !empty($page[$region]) ? $page[$region] : array();
@@ -177,7 +200,15 @@ function dashboard_page_build(&$page) {
  */
 function dashboard_system_info_alter(&$info, $file, $type) {
   if ($type == 'theme') {
-    $info['regions'] += dashboard_region_descriptions();
+    // Add the dashboard regions (the "inactive" region should always appear
+    // last in the list, for usability reasons).
+    $dashboard_regions = dashboard_region_descriptions();
+    if (isset($dashboard_regions['dashboard_inactive'])) {
+      $inactive_region = $dashboard_regions['dashboard_inactive'];
+      unset($dashboard_regions['dashboard_inactive']);
+      $dashboard_regions['dashboard_inactive'] = $inactive_region;
+    }
+    $info['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.
@@ -312,12 +343,23 @@ function dashboard_form_block_admin_display_form_alter(&$form, &$form_state, $fo
     $form['block_regions']['#value'] = array_diff_key($form['block_regions']['#value'], $dashboard_regions);
     foreach (element_children($form['blocks']) as $i) {
       $block = &$form['blocks'][$i];
-      if (isset($block['region']['#default_value']) && isset($dashboard_regions[$block['region']['#default_value']])) {
+      if (isset($block['region']['#default_value']) && isset($dashboard_regions[$block['region']['#default_value']]) && $block['region']['#default_value'] != 'dashboard_inactive') {
         $block['#access'] = FALSE;
       }
       elseif (isset($block['region']['#options'])) {
         $block['region']['#options'] = array_diff_key($block['region']['#options'], $dashboard_regions);
       }
+      // Show inactive dashboard blocks as disabled on the main block
+      // administration form, so that they are available to place in other
+      // regions of the theme. Note that when the form is submitted, any such
+      // blocks which still remain disabled will immediately be put back in the
+      // 'dashboard_inactive' region, because dashboard_block_info_alter() is
+      // called when the blocks are rehashed. Fortunately, this is the exact
+      // behavior we want.
+      if ($block['region']['#default_value'] == 'dashboard_inactive') {
+        // @todo These do not wind up in correct alphabetical order.
+        $block['region']['#default_value'] = NULL;
+      }
     }
   }
 }
@@ -370,6 +412,9 @@ function dashboard_form_block_add_block_form_alter(&$form, &$form_state) {
  */
 function template_preprocess_dashboard_admin_display_form(&$variables) {
   template_preprocess_block_admin_display_form($variables);
+  if (isset($variables['block_regions'][BLOCK_REGION_NONE])) {
+    $variables['block_regions'][BLOCK_REGION_NONE] = t('Other blocks');
+  }
 }
 
 /**
@@ -431,8 +476,9 @@ function dashboard_regions() {
  */
 function dashboard_dashboard_regions() {
   return array(
-    'dashboard_main' => 'Dashboard main',
-    'dashboard_sidebar' => 'Dashboard sidebar',
+    'dashboard_main' => 'Dashboard (main)',
+    'dashboard_sidebar' => 'Dashboard (sidebar)',
+    'dashboard_inactive' => 'Dashboard (inactive)',
   );
 }
 
@@ -445,9 +491,9 @@ function dashboard_show_disabled() {
   // Blocks are not necessarily initialized at this point.
   $blocks = _block_rehash();
 
-  // Limit the list to disabled blocks for the current theme.
+  // Limit the list to blocks that are marked as disabled for the dashboard.
   foreach ($blocks as $key => $block) {
-    if ($block['theme'] != $theme_key || (!empty($block['status']) && !empty($block['region']))) {
+    if ($block['theme'] != $theme_key || $block['region'] != 'dashboard_inactive') {
       unset($blocks[$key]);
     }
   }
@@ -496,7 +542,7 @@ function dashboard_update() {
     parse_str($_REQUEST['regions'], $regions);
     foreach ($regions as $region_name => $blocks) {
       if ($region_name == 'disabled_blocks') {
-        $region_name = '';
+        $region_name = 'dashboard_inactive';
       }
       foreach ($blocks as $weight => $block_string) {
         // Parse the query string to determine the block's module and delta.
@@ -507,12 +553,7 @@ function dashboard_update() {
 
         $block->region = $region_name;
         $block->weight = $weight;
-        if (empty($region_name)) {
-          $block->status = 0;
-        }
-        else {
-          $block->status = 1;
-        }
+        $block->status = 1;
 
         db_merge('block')
           ->key(array(
@@ -603,6 +644,8 @@ function theme_dashboard_disabled_blocks($variables) {
   foreach ($blocks as $block) {
     $output .= theme('dashboard_disabled_block', array('block' => $block));
   }
+  $output .= '<div class="clearfix"></div>';
+  $output .= '<p class="dashboard-add-other-blocks">' . l(t('Add other blocks'), 'admin/dashboard/configure') . '</p>';
   $output .= '</div></div></div>';
   return $output;
 }
diff --git a/modules/dashboard/dashboard.test b/modules/dashboard/dashboard.test
index af96de79963487733894e2f688d7a5b07e72e6f4..e9b1283249dc3ad93763183b02523f1b4d09b440 100644
--- a/modules/dashboard/dashboard.test
+++ b/modules/dashboard/dashboard.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: dashboard.test,v 1.6 2010/10/21 11:55:09 dries Exp $
+// $Id: dashboard.test,v 1.8 2010/11/06 23:24:33 webchick Exp $
 
 /**
  * @file
@@ -19,7 +19,7 @@ class DashboardBlocksTestCase extends DrupalWebTestCase {
     parent::setUp();
 
     // Create and log in an administrative user having access to the dashboard.
-    $admin_user = $this->drupalCreateUser(array('access dashboard', 'administer blocks'));
+    $admin_user = $this->drupalCreateUser(array('access dashboard', 'administer blocks', 'access administration pages', 'administer modules'));
     $this->drupalLogin($admin_user);
 
     // Make sure that the dashboard is using the same theme as the rest of the
@@ -79,4 +79,63 @@ class DashboardBlocksTestCase extends DrupalWebTestCase {
       $this->assertTrue(empty($elements), t('%region is not an available choice on the block configuration page.', array('%region' => $region)));
     }
   }
+
+  /**
+   * Test that the dashboard module can be disabled and enabled again,
+   * retaining its blocks.
+   */
+  function testDisableEnable() {
+    // Add a new custom block to a dashboard region.
+    $custom_block = array();
+    $custom_block['info'] = $this->randomName(8);
+    $custom_block['title'] = $this->randomName(8);
+    $custom_block['body[value]'] = $this->randomName(32);
+    $custom_block['regions[stark]'] = 'dashboard_main';
+    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
+    $this->drupalGet('admin/dashboard');
+    $this->assertRaw($custom_block['title'], t('Block appears on the dashboard.'));
+
+    $edit = array();
+    $edit['modules[Core][dashboard][enable]'] = FALSE;
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+    $this->assertNoRaw('assigned to the invalid region', t('Dashboard blocks gracefully disabled.'));
+    module_list(TRUE);
+    $this->assertFalse(module_exists('dashboard'), t('Dashboard disabled.'));
+
+    $edit['modules[Core][dashboard][enable]'] = 'dashboard';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+    module_list(TRUE);
+    $this->assertTrue(module_exists('dashboard'), t('Dashboard enabled.'));
+
+    $this->drupalGet('admin/dashboard');
+    $this->assertRaw($custom_block['title'], t('Block still appears on the dashboard.'));
+  }
+
+  /**
+   * Test that defining a block with ['properties']['administrative'] = TRUE
+   * adds it as an available block for the dashboard.
+   */
+  function testBlockAvailability() {
+    // Test "Recent comments", which should be available (defined as
+    // "administrative") but not enabled.
+    $this->drupalGet('admin/dashboard');
+    $this->assertNoText(t('Recent comments'), t('"Recent comments" not on dashboard.'));
+    $this->drupalGet('admin/dashboard/drawer');
+    $this->assertText(t('Recent comments'), t('Drawer of disabled blocks includes a block defined as "administrative".'));
+    $this->assertNoText(t('Syndicate'), t('Drawer of disabled blocks excludes a block not defined as "administrative".'));
+    $this->drupalGet('admin/dashboard/configure');
+    $elements = $this->xpath('//select[@id=:id]//option[@selected="selected"]', array(':id' => 'edit-blocks-comment-recent-region'));
+    $this->assertTrue($elements[0]['value'] == 'dashboard_inactive', t('A block defined as "administrative" defaults to dashboard_inactive.'));
+
+    // Now enable the block on the dashboard.
+    $values = array();
+    $values['blocks[comment_recent][region]'] = 'dashboard_main';
+    $this->drupalPost('admin/dashboard/configure', $values, t('Save blocks'));
+    $this->drupalGet('admin/dashboard');
+    $this->assertText(t('Recent comments'), t('"Recent comments" was placed on dashboard.'));
+    $this->drupalGet('admin/dashboard/drawer');
+    $this->assertNoText(t('Recent comments'), t('Drawer of disabled blocks excludes enabled blocks.'));
+  }
 }
diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc
index aada662c6757f67dacca7943c21f0a3aa3a85c99..048a7df1268abdb9a83367f0d8f3556c6aacb24a 100644
--- a/modules/dblog/dblog.admin.inc
+++ b/modules/dblog/dblog.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: dblog.admin.inc,v 1.40 2010/09/09 15:47:03 webchick Exp $
+// $Id: dblog.admin.inc,v 1.42 2010/12/04 01:52:15 webchick Exp $
 
 /**
  * @file
@@ -220,7 +220,7 @@ function dblog_filters() {
   $filters = array();
 
   foreach (_dblog_get_message_types() as $type) {
-    $types[$type] = $type;
+    $types[$type] = t($type);
   }
 
   if (!empty($types)) {
@@ -376,6 +376,7 @@ function dblog_clear_log_form($form) {
  * Submit callback: clear database with log messages.
  */
 function dblog_clear_log_submit() {
+  $_SESSION['dblog_overview_filter'] = array();
   db_delete('watchdog')->execute();
   drupal_set_message(t('Database log cleared.'));
 }
diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info
index 9b052c7f9de640f49f8a78229b838f0e5f1d2e2f..bcdad9180366f62134ab1720ffc2ab381a43687a 100644
--- a/modules/dblog/dblog.info
+++ b/modules/dblog/dblog.info
@@ -1,16 +1,13 @@
-; $Id: dblog.info,v 1.7 2009/06/08 09:23:51 dries Exp $
+; $Id: dblog.info,v 1.8 2010/12/20 19:59:41 webchick Exp $
 name = Database logging
 description = Logs and records system events to the database.
 package = Core
 version = VERSION
 core = 7.x
-files[] = dblog.module
-files[] = dblog.admin.inc
-files[] = dblog.install
 files[] = dblog.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/dblog/dblog.install b/modules/dblog/dblog.install
index 1b9fda10b24e5087e53e67295344f2d39ae4d11f..279993e7cb9ed1c95e71966e865023cafd6c66c8 100644
--- a/modules/dblog/dblog.install
+++ b/modules/dblog/dblog.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: dblog.install,v 1.23 2010/09/05 19:56:03 dries Exp $
+// $Id: dblog.install,v 1.24 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -93,7 +93,7 @@ function dblog_schema() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x database logging updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -132,6 +132,5 @@ function dblog_update_7001() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
index caafa2661509cbe4563466ee11e9dfeb57205707..019f0194b237756c3521ae3ccfed9908052c0e83 100644
--- a/modules/dblog/dblog.test
+++ b/modules/dblog/dblog.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: dblog.test,v 1.39 2010/09/01 03:03:05 dries Exp $
+// $Id: dblog.test,v 1.40 2010/12/04 01:52:15 webchick Exp $
 
 class DBLogTestCase extends DrupalWebTestCase {
   protected $big_user;
@@ -467,6 +467,10 @@ class DBLogTestCase extends DrupalWebTestCase {
       $count = $this->getTypeCount($types);
       $this->assertEqual(array_sum($count), $type['count'], 'Count matched');
     }
+    
+    // Clear all logs and make sure the confirmation message is found.
+    $this->drupalPost('admin/reports/dblog', array(), t('Clear log messages'));
+    $this->assertText(t('Database log cleared.'), t('Confirmation message found'));
   }
 
   /**
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 35243dcb95110604b2a64b34026764b4b2174ad3..103be8b4ff7eeb6d91b7c097112fce14c564dfc5 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.api.php,v 1.91 2010/10/03 01:15:33 dries Exp $
+// $Id: field.api.php,v 1.101 2010/12/14 19:50:05 dries Exp $
 
 /**
  * @ingroup field_fieldable_type
@@ -227,11 +227,14 @@ function hook_field_info_alter(&$info) {
  *     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.
+ *   - indexes: (optional) 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.
+ *   - foreign keys: (optional) An array of Schema API foreign keys
+ *     definitions.
  */
 function hook_field_schema($field) {
   if ($field['type'] == 'text_long') {
@@ -264,6 +267,12 @@ function hook_field_schema($field) {
     'indexes' => array(
       'format' => array('format'),
     ),
+    'foreign keys' => array(
+      'format' => array(
+        'table' => 'filter_format',
+        'columns' => array('format' => 'format'),
+      ),
+    ),
   );
 }
 
@@ -383,19 +392,18 @@ function hook_field_prepare_view($entity_type, $entities, $field, $instances, $l
  * @param $items
  *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  * @param $errors
- *   The array of errors, keyed by field name and by value delta, that have
- *   already been reported for the entity. The function should add its errors
- *   to this array. Each error is an associative array, with the following
+ *   The array of errors (keyed by field name, language code, and delta) that
+ *   have 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).
+ *   - 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) {
   foreach ($items as $delta => $item) {
     if (!empty($item['value'])) {
       if (!empty($field['settings']['max_length']) && drupal_strlen($item['value']) > $field['settings']['max_length']) {
-        $errors[$field['field_name']][$delta][] = array(
+        $errors[$field['field_name']][$langcode][$delta][] = array(
           'error' => 'text_max_length',
           'message' => t('%name: the value may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length'])),
         );
@@ -759,18 +767,29 @@ function hook_field_widget_info_alter(&$info) {
  * 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
- * 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
- * $instance definitions, they should not use the field_info_*() functions, but
- * fetch the information present in $form_state['field']:
- * - $form_state['field'][$field_name][$langcode]['field']
- * - $form_state['field'][$field_name][$langcode]['instance']
+ * (regular entity form, field configuration form, advanced search form...),
+ * the values for $field and $instance might be different from the "official"
+ * definitions returned by field_info_field() and field_info_instance().
+ * Examples: mono-value widget even if the field is multi-valued, non-required
+ * widget even if the field is 'required'...
+ *
+ * Therefore, the FAPI element callbacks (such as #process, #element_validate,
+ * #value_callback...) used by the widget cannot use the field_info_field()
+ * or field_info_instance() functions to retrieve the $field or $instance
+ * definitions they should operate on. The field_widget_field() and
+ * field_widget_instance() functions should be used instead to fetch the
+ * current working definitions from $form_state, where Field API stores them.
+ *
+ * Alternatively, hook_field_widget_form() can extract the needed specific
+ * properties from $field and $instance and set them as ad-hoc
+ * $element['#custom'] properties, for later use by its element callbacks.
+ *
+ * @see field_widget_field()
+ * @see field_widget_instance()
  *
  * @param $form
- *   The entire form array.
+ *   The form structure where widgets are being attached to. This might be a
+ *   full form structure, or a sub-element of a larger form.
  * @param $form_state
  *   An associative array containing the current state of the form.
  * @param $field
@@ -789,6 +808,12 @@ function hook_field_widget_info_alter(&$info) {
  *   - #bundle: The name of the field bundle the field is contained in.
  *   - #field_name: The name of the field.
  *   - #language: The language the field is being edited in.
+ *   - #field_parents: The 'parents' space for the field in the form. Most
+ *       widgets can simply overlook this property. This identifies the
+ *       location where the field values are placed within
+ *       $form_state['values'], and is used to access processing information
+ *       for the field through the field_form_get_state() and
+ *       field_form_set_state() functions.
  *   - #columns: A list of field storage columns of the field.
  *   - #title: The sanitized element label for the field instance, ready for
  *     output.
@@ -825,7 +850,8 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
  *     errors to different form elements inside the widget.
  *   - message: the human readable message to be displayed.
  * @param $form
- *   The form array.
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-element of a larger form.
  * @param $form_state
  *   An associative array containing the current state of the form.
  */
@@ -1060,7 +1086,7 @@ function hook_field_formatter_view($entity_type, $entity, $field, $instance, $la
  */
 
 /**
- * Act on field_attach_form.
+ * 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.
@@ -1068,10 +1094,15 @@ function hook_field_formatter_view($entity_type, $entity, $field, $instance, $la
  * @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.
+ *   The entity for which an edit form is being built.
  * @param $form
- *   The form structure to fill in.
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-element of a larger form. The
+ *   $form['#parents'] property can be used to identify the corresponding part
+ *   of $form_state['values']. Hook implementations that need to act on the
+ *   top-level properties of the global form (like #submit, #validate...) can
+ *   add a #process callback to the array received in the $form parameter, and
+ *   act on the $complete_form parameter in the process callback.
  * @param $form_state
  *   An associative array containing the current state of the form.
  * @param $langcode
@@ -1079,7 +1110,12 @@ function hook_field_formatter_view($entity_type, $entity, $field, $instance, $la
  *   is provided the default site language will be used.
  */
 function hook_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
-  // @todo Needs function body.
+  // Add a checkbox allowing a given field to be emptied.
+  // See hook_field_attach_submit() for the corresponding processing code.
+  $form['empty_field_foo'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Empty the 'field_foo' field"),
+  );
 }
 
 /**
@@ -1117,10 +1153,26 @@ function hook_field_attach_validate($entity_type, $entity, &$errors) {
  *
  * This hook is invoked after the field module has performed the operation.
  *
- * See field_attach_submit() for details and arguments.
+ * @param $entity_type
+ *   The type of $entity; for example, 'node' or 'user'.
+ * @param $entity
+ *   The entity for which an edit form is being submitted. The incoming form
+ *   values have been extracted as field values of the $entity object.
+ * @param $form
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-part of a larger form. The $form['#parents']
+ *   property can be used to identify the corresponding part of
+ *   $form_state['values'].
+ * @param $form_state
+ *   An associative array containing the current state of the form.
  */
 function hook_field_attach_submit($entity_type, $entity, $form, &$form_state) {
-  // @todo Needs function body.
+  // Sample case of an 'Empty the field' checkbox added on the form, allowing
+  // a given field to be emptied.
+  $values = drupal_array_get_nested_value($form_state['values'], $form['#parents']);
+  if (!empty($values['empty_field_foo'])) {
+    unset($entity->field_foo);
+  }
 }
 
 /**
@@ -1225,7 +1277,7 @@ function hook_field_attach_purge($entity_type, $entity, $field, $instance) {
 }
 
 /**
- * Perform alterations on field_attach_view().
+ * Perform alterations on field_attach_view() or field_view_field().
  *
  * This hook is invoked after the field module has performed the operation.
  *
@@ -1235,7 +1287,13 @@ function hook_field_attach_purge($entity_type, $entity, $field, $instance) {
  *   An associative array containing:
  *   - 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'.
+ *   - view_mode: View mode; for example, 'full' or 'teaser'.
+ *   - display: Either a view mode string or an array of display settings. If
+ *     this hook is being invoked from field_attach_view(), the 'display'
+ *     element is set to the view mode string. If this hook is being invoked
+ *     from field_view_field(), this element is set to the $display argument
+ *     and the view_mode element is set to '_custom'. See field_view_field()
+ *     for more information on what its $display argument contains.
  *   - language: The language code used for rendering.
  */
 function hook_field_attach_view_alter(&$output, $context) {
@@ -1525,7 +1583,6 @@ function hook_field_storage_details_alter(&$details, $field) {
  */
 function hook_field_storage_load($entity_type, &$entities, $age, $fields, $options) {
   $field_info = field_info_field_by_ids();
-  $etid = _field_sql_storage_etid($entity_type);
   $load_current = $age == FIELD_LOAD_CURRENT;
 
   foreach ($fields as $field_id => $ids) {
@@ -1535,7 +1592,7 @@ function hook_field_storage_load($entity_type, &$entities, $age, $fields, $optio
 
     $query = db_select($table, 't')
       ->fields('t')
-      ->condition('etid', $etid)
+      ->condition('entity_type', $entity_type)
       ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
       ->condition('language', field_available_languages($entity_type, $field), 'IN')
       ->orderBy('delta');
@@ -1588,7 +1645,9 @@ function hook_field_storage_load($entity_type, &$entities, $age, $fields, $optio
  */
 function hook_field_storage_write($entity_type, $entity, $op, $fields) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
+  if (!isset($vid)) {
+    $vid = $id;
+  }
 
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
@@ -1606,31 +1665,27 @@ function hook_field_storage_write($entity_type, $entity, $op, $fields) {
       $languages = !empty($entity->$field_name) ? $field_languages : $all_languages;
       if ($languages) {
         db_delete($table_name)
-          ->condition('etid', $etid)
+          ->condition('entity_type', $entity_type)
           ->condition('entity_id', $id)
           ->condition('language', $languages, 'IN')
           ->execute();
-        if (isset($vid)) {
-          db_delete($revision_name)
-            ->condition('etid', $etid)
-            ->condition('entity_id', $id)
-            ->condition('revision_id', $vid)
-            ->condition('language', $languages, 'IN')
-            ->execute();
-        }
+        db_delete($revision_name)
+          ->condition('entity_type', $entity_type)
+          ->condition('entity_id', $id)
+          ->condition('revision_id', $vid)
+          ->condition('language', $languages, 'IN')
+          ->execute();
       }
     }
 
     // Prepare the multi-insert query.
     $do_insert = FALSE;
-    $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
+    $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
     foreach ($field['columns'] as $column => $attributes) {
       $columns[] = _field_sql_storage_columnname($field_name, $column);
     }
     $query = db_insert($table_name)->fields($columns);
-    if (isset($vid)) {
-      $revision_query = db_insert($revision_name)->fields($columns);
-    }
+    $revision_query = db_insert($revision_name)->fields($columns);
 
     foreach ($field_languages as $langcode) {
       $items = (array) $entity->{$field_name}[$langcode];
@@ -1639,7 +1694,7 @@ function hook_field_storage_write($entity_type, $entity, $op, $fields) {
         // We now know we have someting to insert.
         $do_insert = TRUE;
         $record = array(
-          'etid' => $etid,
+          'entity_type' => $entity_type,
           'entity_id' => $id,
           'revision_id' => $vid,
           'bundle' => $bundle,
@@ -1663,9 +1718,7 @@ function hook_field_storage_write($entity_type, $entity, $op, $fields) {
     // Execute the query if we have values to insert.
     if ($do_insert) {
       $query->execute();
-      if (isset($vid)) {
-        $revision_query->execute();
-      }
+      $revision_query->execute();
     }
   }
 }
@@ -1686,7 +1739,6 @@ function hook_field_storage_write($entity_type, $entity, $op, $fields) {
  */
 function hook_field_storage_delete($entity_type, $entity, $fields) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   foreach (field_info_instances($entity_type, $bundle) as $instance) {
     if (isset($fields[$instance['field_id']])) {
@@ -1717,14 +1769,13 @@ function hook_field_storage_delete($entity_type, $entity, $fields) {
  */
 function hook_field_storage_delete_revision($entity_type, $entity, $fields) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   if (isset($vid)) {
     foreach ($fields as $field_id) {
       $field = field_info_field_by_id($field_id);
       $revision_name = _field_sql_storage_revision_tablename($field);
       db_delete($revision_name)
-        ->condition('etid', $etid)
+        ->condition('entity_type', $entity_type)
         ->condition('entity_id', $id)
         ->condition('revision_id', $vid)
         ->execute();
@@ -1747,126 +1798,104 @@ function hook_field_storage_delete_revision($entity_type, $entity, $fields) {
  *   See EntityFieldQuery::execute() for the return values.
  */
 function hook_field_storage_query($query) {
-  $load_current = $options['age'] == FIELD_LOAD_CURRENT;
-
-  $field = field_info_field_by_id($field_id);
-  $field_name = $field['field_name'];
-  $table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
-  $field_columns = array_keys($field['columns']);
-
-  // Build the query.
-  $query = db_select($table, 't');
-  $query->join('field_config_entity_type', 'e', 't.etid = e.etid');
-
-  // Add conditions.
-  foreach ($conditions as $condition) {
-    // A condition is either a (column, value, operator) triple, or a
-    // (column, value) pair with implied operator.
-    @list($column, $value, $operator) = $condition;
-    // Translate operator and value if needed.
-    switch ($operator) {
-      case 'STARTS_WITH':
-        $operator = 'LIKE';
-        $value = db_like($value) . '%';
-        break;
-
-      case 'ENDS_WITH':
-        $operator = 'LIKE';
-        $value = '%' . db_like($value);
-        break;
-
-      case 'CONTAINS':
-        $operator = 'LIKE';
-        $value = '%' . db_like($value) . '%';
-        break;
+  $groups = array();
+  if ($query->age == FIELD_LOAD_CURRENT) {
+    $tablename_function = '_field_sql_storage_tablename';
+    $id_key = 'entity_id';
+  }
+  else {
+    $tablename_function = '_field_sql_storage_revision_tablename';
+    $id_key = 'revision_id';
+  }
+  $table_aliases = array();
+  // Add tables for the fields used.
+  foreach ($query->fields as $key => $field) {
+    $tablename = $tablename_function($field);
+    // Every field needs a new table.
+    $table_alias = $tablename . $key;
+    $table_aliases[$key] = $table_alias;
+    if ($key) {
+      $select_query->join($tablename, $table_alias, "$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key");
     }
-    // Translate field columns into prefixed db columns.
-    if (in_array($column, $field_columns)) {
-      $column = _field_sql_storage_columnname($field_name, $column);
+    else {
+      $select_query = db_select($tablename, $table_alias);
+      $select_query->addTag('entity_field_access');
+      $select_query->addMetaData('base_table', $tablename);
+      $select_query->fields($table_alias, array('entity_type', 'entity_id', 'revision_id', 'bundle'));
+      $field_base_table = $table_alias;
     }
-    // Translate entity types into numeric ids. Expressing the condition on the
-    // local 'etid' column rather than the JOINed 'type' column avoids a
-    // filesort.
-    if ($column == 'type') {
-      $column = 't.etid';
-      if (is_array($value)) {
-        foreach (array_keys($value) as $key) {
-          $value[$key] = _field_sql_storage_etid($value[$key]);
+    if ($field['cardinality'] != 1) {
+      $select_query->distinct();
+    }
+  }
+
+  // Add field conditions.
+  foreach ($query->fieldConditions as $key => $condition) {
+    $table_alias = $table_aliases[$key];
+    $field = $condition['field'];
+    // Add the specified condition.
+    $sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $condition['column']);
+    $query->addCondition($select_query, $sql_field, $condition);
+    // Add delta / language group conditions.
+    foreach (array('delta', 'language') as $column) {
+      if (isset($condition[$column . '_group'])) {
+        $group_name = $condition[$column . '_group'];
+        if (!isset($groups[$column][$group_name])) {
+          $groups[$column][$group_name] = $table_alias;
+        }
+        else {
+          $select_query->where("$table_alias.$column = " . $groups[$column][$group_name] . ".$column");
         }
-      }
-      else {
-        $value = _field_sql_storage_etid($value);
       }
     }
-    // Track condition on 'deleted'.
-    if ($column == 'deleted') {
-      $condition_deleted = TRUE;
-    }
-
-    $query->condition($column, $value, $operator);
   }
 
-  // Exclude deleted data unless we have a condition on it.
-  if (!isset($condition_deleted)) {
-    $query->condition('deleted', 0);
+  if (isset($query->deleted)) {
+    $select_query->condition("$field_base_table.deleted", (int) $query->deleted);
   }
 
-  // For a count query, return the count now.
-  if ($options['count']) {
-    return $query
-      ->fields('t', array('etid', 'entity_id', 'revision_id'))
-      ->distinct()
-      ->countQuery()
-      ->execute()
-      ->fetchField();
+  // Is there a need to sort the query by property?
+  $has_property_order = FALSE;
+  foreach ($query->order as $order) {
+    if ($order['type'] == 'property') {
+      $has_property_order = TRUE;
+    }
   }
 
-  // For a data query, add fields.
-  $query
-    ->fields('t', array('bundle', 'entity_id', 'revision_id'))
-    ->fields('e', array('type'))
-    // We need to ensure entities arrive in a consistent order for the
-    // range() operation to work.
-    ->orderBy('t.etid')
-    ->orderBy('t.entity_id');
-
-  // Initialize results array
-  $return = array();
-
-  // Getting $count entities possibly requires reading more than $count rows
-  // since fields with multiple values span over several rows. We query for
-  // batches of $count rows until we've either read $count entities or received
-  // less rows than asked for.
-  $entity_count = 0;
-  do {
-    if ($options['limit'] != FIELD_QUERY_NO_LIMIT) {
-      $query->range($options['cursor'], $options['limit']);
+  if ($query->propertyConditions || $has_property_order) {
+    if (empty($query->entityConditions['entity_type']['value'])) {
+      throw new EntityFieldQueryException('Property conditions and orders must have an entity type defined.');
     }
-    $results = $query->execute();
-
-    $row_count = 0;
-    foreach ($results as $row) {
-      $row_count++;
-      $options['cursor']++;
-      // If querying all revisions and the entity type has revisions, we need
-      // to key the results by revision_ids.
-      $entity_type = entity_get_info($row->type);
-      $id = ($load_current || empty($entity_type['entity keys']['revision'])) ? $row->entity_id : $row->revision_id;
-
-      if (!isset($return[$row->type][$id])) {
-        $return[$row->type][$id] = entity_create_stub_entity($row->type, array($row->entity_id, $row->revision_id, $row->bundle));
-        $entity_count++;
-      }
+    $entity_type = $query->entityConditions['entity_type']['value'];
+    $entity_base_table = _field_sql_storage_query_join_entity($select_query, $entity_type, $field_base_table);
+    $query->entityConditions['entity_type']['operator'] = '=';
+    foreach ($query->propertyConditions as $property_condition) {
+      $query->addCondition($select_query, "$entity_base_table." . $property_condition['column'], $property_condition);
     }
-  } while ($options['limit'] != FIELD_QUERY_NO_LIMIT && $row_count == $options['limit'] && $entity_count < $options['limit']);
+  }
+  foreach ($query->entityConditions as $key => $condition) {
+    $query->addCondition($select_query, "$field_base_table.$key", $condition);
+  }
 
-  // The query is complete when the last batch returns less rows than asked
-  // for.
-  if ($row_count < $options['limit']) {
-    $options['cursor'] = FIELD_QUERY_COMPLETE;
+  // Order the query.
+  foreach ($query->order as $order) {
+    if ($order['type'] == 'entity') {
+      $key = $order['specifier'];
+      $select_query->orderBy("$field_base_table.$key", $order['direction']);
+    }
+    elseif ($order['type'] == 'field') {
+      $specifier = $order['specifier'];
+      $field = $specifier['field'];
+      $table_alias = $table_aliases[$specifier['index']];
+      $sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $specifier['column']);
+      $select_query->orderBy($sql_field, $order['direction']);
+    }
+    elseif ($order['type'] == 'property') {
+      $select_query->orderBy("$entity_base_table." . $order['specifier'], $order['direction']);
+    }
   }
 
-  return $return;
+  return $query->finishQuery($select_query, $id_key);
 }
 
 /**
@@ -1924,18 +1953,17 @@ function hook_field_storage_delete_field($field) {
  *   The instance being deleted.
  */
 function hook_field_storage_delete_instance($instance) {
-  $etid = _field_sql_storage_etid($instance['entity_type']);
   $field = field_info_field($instance['field_name']);
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_update($table_name)
     ->fields(array('deleted' => 1))
-    ->condition('etid', $etid)
+    ->condition('entity_type', $instance['entity_type'])
     ->condition('bundle', $instance['bundle'])
     ->execute();
   db_update($revision_name)
     ->fields(array('deleted' => 1))
-    ->condition('etid', $etid)
+    ->condition('entity_type', $instance['entity_type'])
     ->condition('bundle', $instance['bundle'])
     ->execute();
 }
@@ -2112,6 +2140,7 @@ function hook_field_info_max_weight($entity_type, $bundle, $context) {
  *   - entity_type: The entity type; e.g. 'node' or 'user'.
  *   - field: The field being rendered.
  *   - instance: The instance being rendered.
+ *   - entity: The entity being rendered.
  *   - view_mode: The view mode, e.g. 'full', 'teaser'...
  *
  * @see hook_field_display_ENTITY_TYPE_alter()
@@ -2146,6 +2175,7 @@ function hook_field_display_alter(&$display, $context) {
  *   - entity_type: The entity type; e.g. 'node' or 'user'.
  *   - field: The field being rendered.
  *   - instance: The instance being rendered.
+ *   - entity: The entity being rendered.
  *   - view_mode: The view mode, e.g. 'full', 'teaser'...
  *
  * @see hook_field_display_alter()
@@ -2178,6 +2208,71 @@ function hook_field_extra_fields_display_alter(&$displays, $context) {
     $displays['description']['visibility'] = FALSE;
   }
 }
+
+/**
+ * Alters the widget properties of a field instance before it gets displayed.
+ *
+ * Note that instead of hook_field_widget_properties_alter(), which is called
+ * for all fields on all entity types,
+ * hook_field_widget_properties_ENTITY_TYPE_alter() may be used to alter widget
+ * properties for fields on a specific entity type only.
+ *
+ * This hook is called once per field per added or edit entity. If the result
+ * of the hook involves reading from the database, it is highly recommended to
+ * statically cache the information.
+ *
+ * @param $widget
+ *   The instance's widget properties.
+ * @param $context
+ *   An associative array containing:
+ *   - entity_type: The entity type; e.g. 'node' or 'user'.
+ *   - entity: The entity object.
+ *   - field: The field that the widget belongs to.
+ *   - instance: The instance of the field.
+ *
+ * @see hook_field_widget_properties_ENTITY_TYPE_alter()
+ */
+function hook_field_widget_properties_alter(&$widget, $context) {
+  // Change a widget's type according to the time of day.
+  $field = $context['field'];
+  if ($context['entity_type'] == 'node' && $field['field_name'] == 'field_foo') {
+    $time = date('H');
+    $widget['type'] = $time < 12 ? 'widget_am' : 'widget_pm';
+  }
+}
+
+/**
+ * Alters the widget properties of a field instance on a given entity type
+ * before it gets displayed.
+ *
+ * Modules can implement hook_field_widget_properties_ENTITY_TYPE_alter() to
+ * alter the widget properties for fields on a specific entity type, rather than
+ * implementing hook_field_widget_properties_alter().
+ *
+ * This hook is called once per field per displayed widget entity. If the result
+ * of the hook involves reading from the database, it is highly recommended to
+ * statically cache the information.
+ *
+ * @param $widget
+ *   The instance's widget properties.
+ * @param $context
+ *   An associative array containing:
+ *   - entity_type: The entity type; e.g. 'node' or 'user'.
+ *   - entity: The entity object.
+ *   - field: The field that the widget belongs to.
+ *   - instance: The instance of the field.
+ *
+ * @see hook_field_widget_properties_alter()
+ */
+function hook_field_widget_properties_ENTITY_TYPE_alter(&$widget, $context) {
+  // Change a widget's type according to the time of day.
+  $field = $context['field'];
+  if ($field['field_name'] == 'field_foo') {
+    $time = date('H');
+    $widget['type'] = $time < 12 ? 'widget_am' : 'widget_pm';
+  }
+}
+
 /**
  * @} End of "ingroup field_storage"
  */
@@ -2422,16 +2517,15 @@ function hook_field_storage_purge_field_instance($instance) {
  */
 function hook_field_storage_purge($entity_type, $entity, $field, $instance) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_delete($table_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $id)
     ->execute();
   db_delete($revision_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $id)
     ->execute();
 }
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 5a496e741bc755c0294067109ef8106020290e73..e2224381785948a381a2e1eb3ce623aa05382637 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.attach.inc,v 1.96 2010/10/03 01:15:33 dries Exp $
+// $Id: field.attach.inc,v 1.98 2010/12/07 05:09:58 webchick Exp $
 
 /**
  * @file
@@ -442,9 +442,26 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
 /**
  * Add form elements for all fields for an entity to a form structure.
  *
- * Sample structure for $form:
+ * The form elements for the entity's fields are added by reference as direct
+ * children in the $form parameter. This parameter can be a full form structure
+ * (most common case for entity edit forms), or a sub-element of a larger form.
+ *
+ * By default, submitted field values appear at the top-level of
+ * $form_state['values']. A different location within $form_state['values'] can
+ * be specified by setting the '#parents' property on the incoming $form
+ * parameter. Because of name clashes, two instances of the same field cannot
+ * appear within the same $form element, or within the same '#parents' space.
+ *
+ * For each call to field_attach_form(), field values are processed by calling
+ * field_attach_form_validate() and field_attach_submit() on the same $form
+ * element.
+ *
+ * Sample resulting structure in $form:
  * @code
- *   // One sub-array per field appearing in the form, keyed by field name.
+ *   '#parents' => The location of field values in $form_state['values'],
+ *   '#entity_type' => The name of the entity type,
+ *   '#bundle' => The name of the bundle,
+ *   // One sub-array per field appearing in the entity, keyed by field name.
  *   // The structure of the array differs slightly depending on whether the
  *   // widget is 'single-value' (provides the input for one field value,
  *   // most common case), and will therefore be repeated as many times as
@@ -456,29 +473,36 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
  *   // to access the field sub-array when $langcode is unknown.
  *   'field_foo' => array(
  *     '#tree' => TRUE,
- *     '#field_name' => the name of the field,
+ *     '#field_name' => The name of the field,
  *     '#language' => $langcode,
  *     $langcode => array(
- *       '#field_name' => the name of the field,
- *       '#tree' => TRUE,
- *       '#required' => whether or not the field is required,
- *       '#title' => the label of the field instance,
- *       '#description' => the description text for the field instance,
+ *       '#field_name' => The name of the field,
+ *       '#language' => $langcode,
+ *       '#field_parents' => The 'parents' space for the field in the form,
+ *          equal to the #parents property of the $form parameter received by
+ *          field_attach_form(),
+ *       '#required' => Whether or not the field is required,
+ *       '#title' => The label of the field instance,
+ *       '#description' => The description text for the field instance,
  *
  *       // Only for 'single' widgets:
  *       '#theme' => 'field_multiple_value_form',
- *       '#cardinality' => the field cardinality,
+ *       '#cardinality' => The field cardinality,
  *       // One sub-array per copy of the widget, keyed by delta.
  *       0 => array(
- *         '#title' => the title to be displayed by the widget,
- *         '#default_value' => the field value for delta 0,
- *         '#required' => whether the widget should be marked required,
+ *         '#entity_type' => The name of the entity type,
+ *         '#bundle' => The name of the bundle,
+ *         '#field_name' => The name of the field,
+ *         '#field_parents' => The 'parents' space for the field in the form,
+ *            equal to the #parents property of the $form parameter received by
+ *            field_attach_form(),
+ *         '#title' => The title to be displayed by the widget,
+ *         '#default_value' => The field value for delta 0,
+ *         '#required' => Whether the widget should be marked required,
  *         '#delta' => 0,
- *         '#field_name' => the name of the field,
- *         '#bundle' => the name of the bundle,
- *         '#columns' => the array of field columns,
+ *         '#columns' => The array of field columns,
  *         // The remaining elements in the sub-array depend on the widget.
- *         '#type' => the type of the widget,
+ *         '#type' => The type of the widget,
  *         ...
  *       ),
  *       1 => array(
@@ -486,10 +510,11 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
  *       ),
  *
  *       // Only for multiple widgets:
+ *       '#entity_type' => The name of the entity type,
  *       '#bundle' => $instance['bundle'],
  *       '#columns'  => array_keys($field['columns']),
  *       // The remaining elements in the sub-array depend on the widget.
- *       '#type' => the type of the widget,
+ *       '#type' => The type of the widget,
  *       ...
  *     ),
  *     ...
@@ -497,27 +522,8 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
  * )
  * @endcode
  *
- * Sample structure for $form_state['field']:
- * @code
- * array(
- *   // One sub-array per field appearing in the form, keyed by field name.
- *   'field_foo' => array(
- *     $langcode => array(
- *       'field' => the field definition array,
- *       'instance' => the field instance definition array,
- *       'array_parents' => an array of keys indicating the path to the field
- *         element within the full $form structure. This entry is populated at
- *         form build time.
- *       'errors' => the array of field validation errors reported on the
- *         field. This entry is populated at form validation time.
- *     ),
- *   ),
- * ),
- * @endcode
- *
- * field_attach_load() is automatically called by the default entity controller
- * class, and thus, in most cases, doesn't need to be explicitly called by the
- * entity type module.
+ * Additionally, some processing data is placed in $form_state, and can be
+ * accessed by field_form_get_state() and field_form_set_state().
  *
  * @param $entity_type
  *   The type of $entity; e.g. 'node' or 'user'.
@@ -525,18 +531,24 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
  *   The entity for which to load form elements, used to initialize
  *   default form values.
  * @param $form
- *   The form structure to fill in.
+ *   The form structure to fill in. This can be a full form structure, or a
+ *   sub-element of a larger form. The #parents property can be set to control
+ *   the location of submitted field values within $form_state['values']. If
+ *   not specified, $form['#parents'] is set to an empty array, placing field
+ *   values at the top-level of $form_state['values'].
  * @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, if no language
  *   is provided the default site language will be used.
- * @return
- *   The form elements are added by reference at the top level of the $form
- *   parameter. Processing information is added by reference in
- *   $form_state['field'].
+ *
+ * @see field_form_get_state()
+ * @see field_form_set_state()
  */
 function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode = NULL) {
+  // Set #parents to 'top-level' by default.
+  $form += array('#parents' => array());
+
   // If no language is provided use the default site language.
   $options = array('language' => field_valid_language($langcode));
   $form += (array) _field_invoke_default('form', $entity_type, $entity, $form, $form_state, $options);
@@ -561,6 +573,10 @@ function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcod
  * Loads all fields for each entity object in a group of a single entity type.
  * The loaded field values are added directly to the entity objects.
  *
+ * field_attach_load() is automatically called by the default entity controller
+ * class, and thus, in most cases, doesn't need to be explicitly called by the
+ * entity type module.
+ *
  * @param $entity_type
  *   The type of $entity; e.g., 'node' or 'user'.
  * @param $entities
@@ -782,7 +798,8 @@ function field_attach_validate($entity_type, $entity) {
  *   'revision' keys should be present. The actual field values will be read
  *   from $form_state['values'].
  * @param $form
- *   The form structure.
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-element of a larger form.
  * @param $form_state
  *   An associative array containing the current state of the form.
  */
@@ -798,8 +815,10 @@ function field_attach_form_validate($entity_type, $entity, $form, &$form_state)
     // Pass field-level validation errors back to widgets for accurate error
     // flagging.
     foreach ($e->errors as $field_name => $field_errors) {
-      foreach ($field_errors as $langcode => $language_errors) {
-        $form_state['field'][$field_name][$langcode]['errors'] = $language_errors;
+      foreach ($field_errors as $langcode => $errors) {
+        $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+        $field_state['errors'] = $errors;
+        field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
       }
     }
     _field_invoke_default('form_errors', $entity_type, $entity, $form, $form_state);
@@ -819,7 +838,8 @@ function field_attach_form_validate($entity_type, $entity, $form, &$form_state)
  *   'revision' keys should be present. The actual field values will be read
  *   from $form_state['values'].
  * @param $form
- *   The form structure to fill in.
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-element of a larger form.
  * @param $form_state
  *   An associative array containing the current state of the form.
  */
@@ -1146,6 +1166,7 @@ function field_attach_view($entity_type, $entity, $view_mode, $langcode = NULL)
     'entity_type' => $entity_type,
     'entity' => $entity,
     'view_mode' => $view_mode,
+    'display' => $view_mode,
     'language' => $langcode,
   );
   drupal_alter('field_attach_view', $output, $context);
diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc
index 400399e3dc43aaf8e40319c10e7002e26f7bc1e2..c2eb3ab6c6fc8f59fab2dbb1aea7f44703ac902b 100644
--- a/modules/field/field.crud.inc
+++ b/modules/field/field.crud.inc
@@ -1,206 +1,11 @@
 <?php
-// $Id: field.crud.inc,v 1.71 2010/09/29 01:37:02 dries Exp $
+// $Id: field.crud.inc,v 1.74 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
  * Field CRUD API, handling field and field instance creation and deletion.
  */
 
-/**
- * @defgroup field_structs Field API data structures
- * @{
- * Represent Field API fields and instances.
- *
- * The Field API defines two primary data structures, Field and
- * Instance, and the concept of a Bundle. A Field defines a
- * particular type of data that can be attached to entities. A Field
- * Instance is a Field attached to a single Bundle. A Bundle is a set
- * of fields that are treated as a group by the Field Attach API and
- * is related to a single fieldable entity type.
- *
- * For example, suppose a site administrator wants Article nodes to
- * have a subtitle and photo. Using the Field API or Field UI module,
- * the administrator creates a field named 'subtitle' of type 'text'
- * and a field named 'photo' of type 'image'. The administrator
- * (again, via a UI) creates two Field Instances, one attaching the
- * field 'subtitle' to the 'node' bundle 'article' and one attaching
- * the field 'photo' to the 'node' bundle 'article'. When the node
- * system uses the Field Attach API to load all fields for an Article
- * node, it passes the node's entity type (which is 'node') and
- * content type (which is 'article') as the node's bundle.
- * field_attach_load() then loads the 'subtitle' and 'photo' fields
- * because they are both attached to the 'node' bundle 'article'.
- *
- * Field definitions are represented as an array of key/value pairs.
- *
- * @param array $field:
- * - id (integer, read-only)
- *     The primary identifier of the field. It is assigned automatically
- *     by field_create_field().
- * - field_name (string)
- *     The name of the field. Each field name is unique within Field API.
- *     When a field is attached to an entity, the field's data is stored
- *     in $entity->$field_name. Maximum length is 32 characters.
- * - type (string)
- *     The type of the field, such as 'text' or 'image'. Field types
- *     are defined by modules that implement hook_field_info().
- * - entity_types (array)
- *     The array of entity types that can hold instances of this field. If
- *     empty or not specified, the field can have instances in any entity type.
- * - cardinality (integer)
- *     The number of values the field can hold. Legal values are any
- *     positive integer or FIELD_CARDINALITY_UNLIMITED.
- * - translatable (integer)
- *     Whether the field is translatable.
- * - locked (integer)
- *     Whether or not the field is available for editing. If TRUE, users can't
- *     change field settings or create new instances of the field in the UI.
- *     Defaults to FALSE.
- * - module (string, read-only)
- *     The name of the module that implements the field type.
- * - active (integer, read-only)
- *     TRUE if the module that implements the field type is currently
- *     enabled, FALSE otherwise.
- * - deleted (integer, read-only)
- *     TRUE if this field has been deleted, FALSE otherwise. Deleted
- *     fields are ignored by the Field Attach API. This property exists
- *     because fields can be marked for deletion but only actually
- *     destroyed by a separate garbage-collection process.
- * - columns (array, read-only).
- *     An array of the Field API columns used to store each value of
- *     this field. The column list may depend on field settings; it is
- *     not constant per field type. Field API column specifications are
- *     exactly like Schema API column specifications but, depending on
- *     the field storage module in use, the name of the column may not
- *     represent an actual column in an SQL database.
- * - indexes (array).
- *     An array of indexes on data columns, using the same definition format
- *     as Schema API index specifications. Only columns that appear in the
- *     'columns' setting are allowed. Note that field types can specify
- *     default indexes, which can be modified or added to when
- *     creating a field.
- * - foreign keys: (optional) An associative array of relations, using the same
- *   structure as the 'foreign keys' definition of hook_schema(). Note, however,
- *   that the field data is not necessarily stored in SQL. Also, the possible
- *   usage is limited, as you cannot specify another field as related, only
- *   existing SQL tables, such as filter formats.
- * - settings (array)
- *     A sub-array of key/value pairs of field-type-specific settings. Each
- *     field type module defines and documents its own field settings.
- * - storage (array)
- *     A sub-array of key/value pairs identifying the storage backend to use for
- *     the for the field.
- *     - type (string)
- *         The storage backend used by the field. Storage backends are defined
- *         by modules that implement hook_field_storage_info().
- *     - module (string, read-only)
- *         The name of the module that implements the storage backend.
- *     - active (integer, read-only)
- *         TRUE if the module that implements the storage backend is currently
- *         enabled, FALSE otherwise.
- *     - settings (array)
- *         A sub-array of key/value pairs of settings. Each storage backend
- *         defines and documents its own settings.
- *
- * Field instance definitions are represented as an array of key/value pairs.
- *
- * @param array $instance:
- * - id (integer, read-only)
- *     The primary identifier of this field instance. It is assigned
- *     automatically by field_create_instance().
- * - field_id (integer, read-only)
- *     The foreign key of the field attached to the bundle by this instance.
- *     It is populated automatically by field_create_instance().
- * - field_name (string)
- *     The name of the field attached to the bundle by this instance.
- * - entity_type (string)
- *     The name of the entity type the instance is attached to.
- * - bundle (string)
- *     The name of the bundle that the field is attached to.
- * - label (string)
- *     A human-readable label for the field when used with this
- *     bundle. For example, the label will be the title of Form API
- *     elements for this instance.
- * - description (string)
- *     A human-readable description for the field when used with this
- *     bundle. For example, the description will be the help text of
- *     Form API elements for this instance.
- * - required (integer)
- *     TRUE if a value for this field is required when used with this
- *     bundle, FALSE otherwise. Currently, required-ness is only enforced
- *     during Form API operations, not by field_attach_load(),
- *     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.
- *     This property exists because instances can be marked for deletion but
- *     only actually destroyed by a separate garbage-collection process.
- * - settings (array)
- *     A sub-array of key/value pairs of field-type-specific instance
- *     settings. Each field type module defines and documents its own
- *     instance settings.
- * - widget (array)
- *     A sub-array of key/value pairs identifying the Form API input widget
- *     for the field when used by this bundle.
- *     - type (string)
- *         The type of the widget, such as text_textfield. Widget types
- *         are defined by modules that implement hook_field_widget_info().
- *     - settings (array)
- *         A sub-array of key/value pairs of widget-type-specific settings.
- *         Each field widget type module defines and documents its own
- *         widget settings.
- *     - weight (float)
- *         The weight of the widget relative to the other elements in entity
- *         edit forms.
- *     - module (string, read-only)
- *         The name of the module that implements the widget type.
- * - display (array)
- *     A sub-array of key/value pairs identifying the way field values should
- *     be displayed in each of the entity type's view modes, plus the 'default'
- *     mode. For each view mode, Field UI lets site administrators define
- *     whether they want to use a dedicated set of display options or the
- *     'default' options to reduce the number of displays to maintain as they
- *     add new fields. For nodes, on a fresh install, only the 'teaser' view
- *     mode is configured to use custom display options, all other view modes
- *     defined use the 'default' options by default. When programmatically
- *     adding field instances on nodes, it is therefore recommended to at least
- *     specify display options for 'default' and 'teaser'.
- *     - default (array)
- *         A sub-array of key/value pairs describing the display options to be
- *         used when the field is being displayed in view modes that are not
- *         configured to use dedicated display options.
- *         - label (string)
- *             Position of the label. 'inline', 'above' and 'hidden' are the
- *             values recognized by the default 'field' theme implementation.
- *         - type (string)
- *             The type of the display formatter, or 'hidden' for no display.
- *         - settings (array)
- *             A sub-array of key/value pairs of display options specific to
- *             the formatter.
- *        - weight (float)
- *            The weight of the field relative to the other entity components
- *            displayed in this view mode.
- *         - module (string, read-only)
- *             The name of the module which implements the display formatter.
- *     - some_mode
- *         A sub-array of key/value pairs describing the display options to be
- *         used when the field is being displayed in the 'some_mode' view mode.
- *         Those options will only be actually applied at run time if the view
- *         mode is not configured to use default settings for this bundle.
- *         - ...
- *     - other_mode
- *        - ...
- *
- * Bundles are represented by two strings, an entity type and a bundle name.
- */
-/**
- * @} End of "defgroup field_structs".
- */
-
 /**
  * @defgroup field_crud Field CRUD API
  * @{
@@ -210,7 +15,7 @@
  * data structures. UI modules will use it to create a user interface.
  *
  * The Field CRUD API uses
- * @link field_structs Field API data structures @endlink.
+ * @link field Field API data structures @endlink.
  */
 
 /**
@@ -243,7 +48,7 @@
  * @throw
  *   FieldException
  *
- * See: @link field_structs Field API data structures @endlink.
+ * See: @link field Field API data structures @endlink.
  */
 function field_create_field($field) {
   // Field name is required.
@@ -588,7 +393,7 @@ function field_delete_field($field_name) {
     foreach ($field['bundles'] as $entity_type => $bundles) {
       foreach ($bundles as $bundle) {
         $instance = field_info_instance($entity_type, $field_name, $bundle);
-        field_delete_instance($instance);
+        field_delete_instance($instance, FALSE);
       }
     }
   }
@@ -642,7 +447,7 @@ function field_delete_field($field_name) {
  * @throw
  *   FieldException
  *
- * See: @link field_structs Field API data structures @endlink.
+ * See: @link field Field API data structures @endlink.
  */
 function field_create_instance($instance) {
   $field = field_read_field($instance['field_name']);
@@ -700,13 +505,16 @@ function field_create_instance($instance) {
  * @param $instance
  *   An associative array representing an instance structure. The required
  *   keys and values are:
- *     field_name: The name of an existing field.
- *     bundle: The bundle this field belongs to.
+ *   - entity_type: The type of the entity the field is attached to.
+ *   - bundle: The bundle this field belongs to.
+ *   - field_name: The name of an existing field.
  *   Read-only_id properties are assigned automatically. Any other
  *   properties specified in $instance overwrite the existing values for
  *   the instance.
+ *
  * @throw
  *   FieldException
+ *
  * @see field_create_instance()
  */
 function field_update_instance($instance) {
@@ -920,8 +728,12 @@ function field_read_instances($params = array(), $include_additional = array())
  *
  * @param $instance
  *   An instance structure.
+ * @param $field_cleanup
+ *   If TRUE, the field will be deleted as well if its last instance is being
+ *   deleted. If FALSE, it is the caller's responsability to handle the case of
+ *   fields left without instances. Defaults to TRUE.
  */
-function field_delete_instance($instance) {
+function field_delete_instance($instance, $field_cleanup = TRUE) {
   // Mark the field instance for deletion.
   db_update('field_config_instance')
     ->fields(array('deleted' => 1))
@@ -930,14 +742,20 @@ function field_delete_instance($instance) {
     ->condition('bundle', $instance['bundle'])
     ->execute();
 
+  // Clear the cache.
+  field_cache_clear();
+
   // Mark instance data for deletion.
   $field = field_info_field($instance['field_name']);
   module_invoke($field['storage']['module'], 'field_storage_delete_instance', $instance);
 
-  // Clear the cache.
-  field_cache_clear();
-
+  // Let modules react to the deletion of the instance.
   module_invoke_all('field_delete_instance', $instance);
+
+  // Delete the field itself if we just deleted its last instance.
+  if ($field_cleanup && count($field['bundles']) == 0) {
+    field_delete_field($field['field_name']);
+  }
 }
 
 /**
@@ -1055,12 +873,11 @@ function field_purge_batch($batch_size) {
     }
   }
 
-  // Retrieve all deleted fields. Any that have no bundles can be purged.
+  // Retrieve all deleted fields. Any that have no instances can be purged.
   $fields = field_read_fields(array('deleted' => 1), array('include_deleted' => 1));
   foreach ($fields as $field) {
-    // field_read_fields() does not return $field['bundles'] which we need.
-    $field = field_info_field_by_id($field['id']);
-    if (!isset($field['bundles']) || count($field['bundles']) == 0) {
+    $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
+    if (empty($instances)) {
       field_purge_field($field);
     }
   }
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index 1353bd6495d99b7490cef867a903bbd7e4ecf795..eb09858a0fadc2ab311af2c6bfca24894da0a158 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.default.inc,v 1.39 2010/08/04 06:55:35 webchick Exp $
+// $Id: field.default.inc,v 1.41 2010/11/21 19:09:18 dries Exp $
 
 /**
  * @file
@@ -11,13 +11,36 @@
  * the corresponding field_attach_[operation]() function.
  */
 
+/**
+ * Extracts field values from submitted form values.
+ *
+ * @param $entity_type
+ *   The type of $entity.
+ * @param $entity
+ *   The entity for the operation.
+ * @param $field
+ *   The field structure for the operation.
+ * @param $instance
+ *   The instance structure for $field on $entity's bundle.
+ * @param $langcode
+ *   The language associated to $items.
+ * @param $items
+ *   The field values. This parameter is altered by reference to receive the
+ *   incoming form values.
+ * @param $form
+ *   The form structure where field elements are attached to. This might be a
+ *   full form structure, or a sub-element of a larger form.
+ * @param $form_state
+ *   The form state.
+ */
 function field_default_extract_form_values($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
-  $field_name = $field['field_name'];
-
-  if (isset($form_state['values'][$field_name][$langcode])) {
-    $items = $form_state['values'][$field_name][$langcode];
+  $path = array_merge($form['#parents'], array($field['field_name'], $langcode));
+  $key_exists = NULL;
+  $values = drupal_array_get_nested_value($form_state['values'], $path, $key_exists);
+  if ($key_exists) {
     // Remove the 'value' of the 'add more' button.
-    unset($items['add_more']);
+    unset($values['add_more']);
+    $items = $values;
   }
 }
 
@@ -119,7 +142,7 @@ function field_default_prepare_view($entity_type, $entities, $field, $instances,
   foreach ($instances as $id => $instance) {
     if (is_string($display)) {
       $view_mode = $display;
-      $display = field_get_display($instance, $view_mode);
+      $display = field_get_display($instance, $view_mode, $entities[$id]);
     }
     if ($display['type'] !== 'hidden') {
       $module = $display['module'];
@@ -171,7 +194,7 @@ function field_default_view($entity_type, $entity, $field, $instance, $langcode,
   // Prepare incoming display specifications.
   if (is_string($display)) {
     $view_mode = $display;
-    $display = field_get_display($instance, $view_mode);
+    $display = field_get_display($instance, $view_mode, $entity);
   }
   else {
     $view_mode = '_custom_display';
diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc
index 3727382bcb03660a811ca59864dc414224716312..02a8d56d61d781e4bddac1629ee58d63d94b695c 100644
--- a/modules/field/field.form.inc
+++ b/modules/field/field.form.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.form.inc,v 1.51 2010/10/20 01:31:06 dries Exp $
+// $Id: field.form.inc,v 1.54 2010/11/20 19:57:01 webchick Exp $
 
 /**
  * @file
@@ -16,6 +16,8 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
     list($id, , ) = entity_extract_ids($entity_type, $entity);
   }
 
+  $parents = $form['#parents'];
+
   $addition = array();
   $field_name = $field['field_name'];
   $addition[$field_name] = array();
@@ -25,9 +27,30 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
     $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
   }
 
+  // Let modules alter the widget properties.
+  $context = array(
+    'entity_type' => $entity_type,
+    'entity' => $entity,
+    'field' => $field,
+    'instance' => $instance,
+  );
+  drupal_alter(array('field_widget_properties', 'field_widget_properties_' . $entity_type), $instance['widget'], $context);
+
   // Collect widget elements.
   $elements = array();
   if (field_access('edit', $field, $entity_type, $entity)) {
+    // Store field information in $form_state.
+    if (!field_form_get_state($parents, $field_name, $langcode, $form_state)) {
+      $field_state = array(
+        'field' => $field,
+        'instance' => $instance,
+        'items_count' => count($items),
+        'array_parents' => array(),
+        'errors' => array(),
+      );
+      field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+    }
+
     // If field module handles multiple values for this form element, and we
     // are displaying an individual element, process the multiple value form.
     if (!isset($get_delta) && field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
@@ -45,6 +68,7 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
           '#bundle' => $instance['bundle'],
           '#field_name' => $field_name,
           '#language' => $langcode,
+          '#field_parents' => $parents,
           '#columns' => array_keys($field['columns']),
           '#title' => check_plain(t($instance['label'])),
           '#description' => field_filter_xss($instance['description']),
@@ -70,16 +94,6 @@ 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(
@@ -101,6 +115,7 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
   $elements['#after_build'][] = 'field_form_element_after_build';
   $elements['#field_name'] = $field_name;
   $elements['#language'] = $langcode;
+  $elements['#field_parents'] = $parents;
 
   $addition[$field_name] += array(
     '#tree' => TRUE,
@@ -123,20 +138,15 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode,
  */
 function field_multiple_value_form($field, $instance, $langcode, $items, &$form, &$form_state) {
   $field_name = $field['field_name'];
+  $parents = $form['#parents'];
 
   // Determine the number of widgets to display.
   switch ($field['cardinality']) {
     case FIELD_CARDINALITY_UNLIMITED:
-      $filled_items = _field_filter_items($field, $items);
-      $current_item_count = isset($form_state['field_item_count'][$field_name])
-                            ? $form_state['field_item_count'][$field_name]
-                            : count($items);
-      // We always want at least one empty icon for the user to fill in.
-      $max = ($current_item_count > count($filled_items))
-              ? $current_item_count - 1
-              : $current_item_count;
-
+      $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+      $max = $field_state['items_count'];
       break;
+
     default:
       $max = $field['cardinality'] - 1;
       break;
@@ -144,7 +154,10 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
 
   $title = check_plain(t($instance['label']));
   $description = field_filter_xss(t($instance['description']));
-  $wrapper_id = drupal_html_id($field_name . '-add-more-wrapper');
+
+  $id_prefix = implode('-', array_merge($parents, array($field_name)));
+  $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
+
   $field_elements = array();
 
   $function = $instance['widget']['module'] . '_field_widget_form';
@@ -156,6 +169,7 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
         '#bundle' => $instance['bundle'],
         '#field_name' => $field_name,
         '#language' => $langcode,
+        '#field_parents' => $parents,
         '#columns' => array_keys($field['columns']),
         // For multiple fields, title and description are handled by the wrapping table.
         '#title' => $multiple ? '' : $title,
@@ -200,20 +214,16 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form,
       if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
         $field_elements['add_more'] = array(
           '#type' => 'submit',
-          '#name' => $field_name . '_add_more',
+          '#name' => strtr($id_prefix, '-', '_') . '_add_more',
           '#value' => t('Add another item'),
           '#attributes' => array('class' => array('field-add-more-submit')),
-          '#limit_validation_errors' => array(array($field_name, $langcode)),
+          '#limit_validation_errors' => array(array_merge($parents, array($field_name, $langcode))),
           '#submit' => array('field_add_more_submit'),
           '#ajax' => array(
             'callback' => 'field_add_more_js',
             'wrapper' => $wrapper_id,
             'effect' => 'fade',
           ),
-          // The field_add_more_submit() and field_add_more_js() handlers will
-          // find the relevant field using those entries.
-          '#field_name' => $field_name,
-          '#language' => $langcode,
         );
       }
     }
@@ -299,18 +309,22 @@ function theme_field_multiple_value_form($variables) {
 }
 
 /**
- * Stores information about the built form structure in the form storage.
+ * #after_build callback for field elements in a form.
+ *
+ * This stores the final location of the field within the form structure so
+ * that field_default_form_errors() can assign validation errors to the right
+ * form element.
  *
- * The 'array_parents' array is used to assign validation errors to actual form
- * elements, and to identify the form element to return in the AJAX 'add more'
- * button handler.
  * @see field_default_form_errors()
- * @see field_add_more_js()
  */
 function field_form_element_after_build($element, &$form_state) {
+  $parents = $element['#field_parents'];
   $field_name = $element['#field_name'];
   $langcode = $element['#language'];
-  $form_state['field'][$field_name][$langcode]['array_parents'] = $element['#array_parents'];
+
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+  $field_state['array_parents'] = $element['#array_parents'];
+  field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
 
   return $element;
 }
@@ -319,21 +333,17 @@ function field_form_element_after_build($element, &$form_state) {
  * Transfer field-level validation errors to widgets.
  */
 function field_default_form_errors($entity_type, $entity, $field, $instance, $langcode, $items, $form, &$form_state) {
-  $field_name = $field['field_name'];
-  $field_info = $form_state['field'][$field_name][$langcode];
+  $field_state = field_form_get_state($form['#parents'], $field['field_name'], $langcode, $form_state);
 
-  if (!empty($field_info['errors'])) {
+  if (!empty($field_state['errors'])) {
     $function = $instance['widget']['module'] . '_field_widget_error';
     $function_exists = function_exists($function);
 
-    // Walk the form down to where the widget lives.
-    $element = $form;
-    foreach ($field_info['array_parents'] as $key) {
-      $element = $element[$key];
-    }
+    // Locate the correct element in the the form.
+    $element = drupal_array_get_nested_value($form_state['complete form'], $field_state['array_parents']);
 
     $multiple_widget = field_behaviors_widget('multiple values', $instance) != FIELD_BEHAVIOR_DEFAULT;
-    foreach ($field_info['errors'] as $delta => $delta_errors) {
+    foreach ($field_state['errors'] as $delta => $delta_errors) {
       // For multiple single-value widgets, pass errors by delta.
       // For a multiple-value widget, all errors are passed to the main widget.
       $error_element = $multiple_widget ? $element : $element[$delta];
@@ -344,10 +354,13 @@ function field_default_form_errors($entity_type, $entity, $field, $instance, $la
         else {
           // Make sure that errors are reported (even incorrectly flagged) if
           // the widget module fails to implement hook_field_widget_error().
-          form_error($error_element, $error['error'], $form, $form_state);
+          form_error($error_element, $error['error']);
         }
       }
     }
+    // Reinitialize the errors list for the next submit.
+    $field_state['errors'] = array();
+    field_form_set_state($form['#parents'], $field['field_name'], $langcode, $form_state, $field_state);
   }
 }
 
@@ -361,11 +374,19 @@ function field_default_form_errors($entity_type, $entity, $field, $instance, $la
  * to return just the changed part of the form.
  */
 function field_add_more_submit($form, &$form_state) {
-  $field_name = $form_state['clicked_button']['#field_name'];
-  $langcode = $form_state['clicked_button']['#language'];
-  if ($form_state['values'][$field_name . '_add_more']) {
-    $form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name][$langcode]);
-  }
+  $button = $form_state['clicked_button'];
+
+  // Go one level up in the form, to the widgets container.
+  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
+  $field_name = $element['#field_name'];
+  $langcode = $element['#language'];
+  $parents = $element['#field_parents'];
+
+  // Increment the items count.
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+  $field_state['items_count']++;
+  field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+
   $form_state['rebuild'] = TRUE;
 }
 
@@ -378,27 +399,150 @@ function field_add_more_submit($form, &$form_state) {
  * @see field_add_more_submit()
  */
 function field_add_more_js($form, $form_state) {
-  // Retrieve field information.
-  $field_name = $form_state['clicked_button']['#field_name'];
-  $langcode = $form_state['clicked_button']['#language'];
-  $field_info = $form_state['field'][$field_name][$langcode];
-  $field = $field_info['field'];
+  $button = $form_state['clicked_button'];
 
-  if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
-    return;
-  }
+  // Go one level up in the form, to the widgets container.
+  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
+  $field_name = $element['#field_name'];
+  $langcode = $element['#language'];
+  $parents = $element['#field_parents'];
 
-  // Navigate to the right element in the the form.
-  $element = $form;
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
 
-  foreach ($field_info['array_parents'] as $key) {
-    $element = $element[$key];
+  $field = $field_state['field'];
+  if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
+    return;
   }
 
-  // Add a DIV around the new field to receive the AJAX effect.
+  // Add a DIV around the delta receiving the AJAX effect.
   $delta = $element['#max_delta'];
   $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
   $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
 
   return $element;
 }
+
+/**
+ * Retrieves processing information about a field from $form_state.
+ *
+ * @param $parents
+ *   The array of #parents where the field lives in the form.
+ * @param $field_name
+ *   The field name.
+ * @param $langcode
+ *   The language in which the field values are entered.
+ * @param $form_state
+ *   The form state.
+ *
+ * @return
+ *   An array with the following key/data pairs:
+ *   - field: the field definition array,
+ *   - instance: the field instance definition array,
+ *   - items_count: the number of widgets to display for the field,
+ *   - array_parents: the location of the field's widgets within the $form
+ *     structure. This entry is populated at '#after_build' time.
+ *   - errors: the array of field validation errors reported on the field. This
+ *     entry is populated at field_attach_form_validate() time.
+ *
+ * @see field_form_set_state()
+ */
+function field_form_get_state($parents, $field_name, $langcode, &$form_state) {
+  $form_state_parents = _field_form_state_parents($parents, $field_name, $langcode);
+  return drupal_array_get_nested_value($form_state, $form_state_parents);
+}
+
+/**
+ * Stores processing information about a field in $form_state.
+ *
+ * @param $parents
+ *   The array of #parents where the field lives in the form.
+ * @param $field_name
+ *   The field name.
+ * @param $langcode
+ *   The language in which the field values are entered.
+ * @param $form_state
+ *   The form state.
+ * @param $field_state
+ *   The array of data to store. See field_form_get_state() for the structure
+ *   and content of the array.
+ *
+ * @see field_form_get_state()
+ */
+function field_form_set_state($parents, $field_name, $langcode, &$form_state, $field_state) {
+  $form_state_parents = _field_form_state_parents($parents, $field_name, $langcode);
+  drupal_array_set_nested_value($form_state, $form_state_parents, $field_state);
+}
+
+/**
+ * Returns the location of processing information within $form_state.
+ */
+function _field_form_state_parents($parents, $field_name, $langcode) {
+  // To ensure backwards compatibility on regular entity forms for widgets that
+  // still access $form_state['field'][$field_name] directly,
+  // - top-level fields (empty $parents) are placed directly under
+  //   $form_state['fields'][$field_name].
+  // - Other fields are placed under
+  //   $form_state['field']['#parents'][...$parents...]['#fields'][$field_name]
+  //   to avoid clashes between field names and $parents parts.
+  // @todo Remove backwards compatibility in Drupal 8, and use a unique
+  // $form_state['field'][...$parents...]['#fields'][$field_name] structure.
+  if (!empty($parents)) {
+    $form_state_parents = array_merge(array('#parents'), $parents, array('#fields'));
+  }
+  else {
+    $form_state_parents = array();
+  }
+  $form_state_parents = array_merge(array('field'), $form_state_parents, array($field_name, $langcode));
+
+  return $form_state_parents;
+}
+
+/**
+ * Retrieves the field definition for a widget's helper callbacks.
+ *
+ * Widgets helper element callbacks (such as #process, #element_validate,
+ * #value_callback, ...) should use field_widget_field() and
+ * field_widget_instance() instead of field_info_field() and
+ * field_info_instance() when they need to access field or instance properties.
+ * See hook_field_widget_form() for more details.
+ *
+ * @param $element
+ *   The structured array for the widget.
+ * @param $form_state
+ *   The form state.
+ *
+ * @return
+ *   The $field definition array for the current widget.
+ *
+ * @see field_widget_instance()
+ * @see hook_field_widget_form()
+ */
+function field_widget_field($element, $form_state) {
+  $field_state = field_form_get_state($element['#field_parents'], $element['#field_name'], $element['#language'], $form_state);
+  return $field_state['field'];
+}
+
+/**
+ * Retrieves the instance definition array for a widget's helper callbacks.
+ *
+ * Widgets helper element callbacks (such as #process, #element_validate,
+ * #value_callback, ...) should use field_widget_field() and
+ * field_widget_instance() instead of field_info_field() and
+ * field_info_instance() when they need to access field or instance properties.
+ * See hook_field_widget_form() for more details.
+ *
+ * @param $element
+ *   The structured array for the widget.
+ * @param $form_state
+ *   The form state.
+ *
+ * @return
+ *   The $instance definition array for the current widget.
+ *
+ * @see field_widget_field()
+ * @see hook_field_widget_form()
+ */
+function field_widget_instance($element, $form_state) {
+  $field_state = field_form_get_state($element['#field_parents'], $element['#field_name'], $element['#language'], $form_state);
+  return $field_state['instance'];
+}
diff --git a/modules/field/field.info b/modules/field/field.info
index 95a5116bb0f832bfb71ac14196f3ba314e0399ca..f4416d544cc83ba5037f1c6af89a34ff5464cb37 100644
--- a/modules/field/field.info
+++ b/modules/field/field.info
@@ -1,24 +1,18 @@
-; $Id: field.info,v 1.9 2010/09/05 02:21:38 dries Exp $
+; $Id: field.info,v 1.10 2010/12/20 19:59:41 webchick Exp $
 name = Field
 description = Field API to add fields to entities like nodes and users.
 package = Core
 version = VERSION
 core = 7.x
 files[] = field.module
-files[] = field.install
-files[] = field.crud.inc
-files[] = field.info.inc
-files[] = field.default.inc
-files[] = field.multilingual.inc
 files[] = field.attach.inc
-files[] = field.form.inc
 files[] = tests/field.test
 dependencies[] = field_sql_storage
 required = TRUE
 stylesheets[all][] = theme/field.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc
index faef36cbd5ca2bf1eb960fbc74c72e238566d4e2..40dde2d9ddfc8692b5d3f55e6e810781d76cda89 100644
--- a/modules/field/field.info.inc
+++ b/modules/field/field.info.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.info.inc,v 1.55 2010/10/23 01:34:02 webchick Exp $
+// $Id: field.info.inc,v 1.58 2010/12/17 01:36:04 dries Exp $
 
 /**
  * @file
@@ -24,6 +24,8 @@
  * are affected.
  */
 function field_info_cache_clear() {
+  drupal_static_reset('field_view_mode_settings');
+
   // @todo: Remove this when field_attach_*_bundle() bundle management
   // functions are moved to the entity API.
   entity_info_cache_clear();
@@ -165,15 +167,15 @@ function _field_info_collate_types($reset = FALSE) {
  * @return
  *   If $reset is TRUE, nothing.
  *   If $reset is FALSE, an array containing the following elements:
- *   - fields: Array of existing fields, keyed by field name. This entry only
- *     lists non-deleted fields. Each field has an additional element,
- *     'bundles', which is an array of all non-deleted instances to which the
- *     field is assigned.
- *   - fields_id: Array of existing fields, keyed by field id. This entry lists
- *     both deleted and non-deleted fields. The bundles element is the same as
- *     for 'fields'.
+ *   - fields: Array of existing fields, keyed by field ID. This element
+ *     lists deleted and non-deleted fields, but not inactive ones.
+ *     Each field has an additional element, 'bundles', which is an array
+ *     of all non-deleted instances of that field.
+ *   - field_ids: Array of field IDs, keyed by field name. This element
+ *     only lists non-deleted, active fields.
  *   - instances: Array of existing instances, keyed by entity type, bundle
- *     name and field name. This entry only lists non-deleted instances.
+ *     name and field name. This element only lists non-deleted instances
+ *     whose field is active.
  */
 function _field_info_collate_fields($reset = FALSE) {
   static $info;
@@ -273,7 +275,7 @@ function _field_info_prepare_field($field) {
  * Prepares an instance definition for the current run-time context.
  *
  * Since the instance was last saved or updated, a number of things might have
- * changed: widgets or formatters disabled, new settings expected, new build
+ * changed: widgets or formatters disabled, new settings expected, new view
  * modes added...
  *
  * @param $instance
@@ -301,16 +303,21 @@ function _field_info_prepare_instance($instance, $field) {
     $instance['display'][$view_mode] = _field_info_prepare_instance_display($field, $display);
   }
 
-  // Fallback to 'hidden' for unspecified view modes.
+  // Fallback to 'hidden' for view modes configured to use custom display
+  // settings, and for which the instance has no explicit settings.
   $entity_info = entity_get_info($instance['entity_type']);
-  foreach ($entity_info['view modes'] as $view_mode => $info) {
-    if (!isset($instance['display'][$view_mode])) {
-      $instance['display'][$view_mode] = array(
-        'type' => 'hidden',
-        'label' => 'above',
-        'settings' => array(),
-        'weight' => 0,
-      );
+  $view_modes = array_merge(array('default'), array_keys($entity_info['view modes']));
+  $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
+  foreach ($view_modes as $view_mode) {
+    if ($view_mode == 'default' || !empty($view_mode_settings[$view_mode]['custom_settings'])) {
+      if (!isset($instance['display'][$view_mode])) {
+        $instance['display'][$view_mode] = array(
+          'type' => 'hidden',
+          'label' => 'above',
+          'settings' => array(),
+          'weight' => 0,
+        );
+      }
     }
   }
 
@@ -598,7 +605,8 @@ function field_info_fields() {
  *
  * @param $field_name
  *   The name of the field to retrieve. $field_name can only refer to a
- *   non-deleted field.
+ *   non-deleted, active field. Use field_read_fields() to retrieve information
+ *   on deleted or inactive fields.
  *
  * @return
  *   The field array, as returned by field_read_fields(), with an
diff --git a/modules/field/field.install b/modules/field/field.install
index 11fe78d325965bdf57cdfde233d627eb19dd40b5..ab77eb80386e9f7dde01dde5e8e4cc41ee5f037b 100644
--- a/modules/field/field.install
+++ b/modules/field/field.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.install,v 1.23 2010/10/20 01:15:58 dries Exp $
+// $Id: field.install,v 1.27 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -197,6 +197,17 @@ function _update_7000_field_create_field(&$field) {
     'active' => 1,
   );
 
+  // Fetch the field schema to initialize columns and indexes. The field module
+  // is not guaranteed to be loaded at this point.
+  module_load_install($field['module']);
+  $schema = (array) module_invoke($field['module'], 'field_schema', $field);
+  $schema += array('columns' => array(), 'indexes' => array());
+  // 'columns' are hardcoded in the field type.
+  $field['columns'] = $schema['columns'];
+  // 'indexes' can be both hardcoded in the field type, and specified in the
+  // incoming $field definition.
+  $field['indexes'] += $schema['indexes'];
+
   // The serialized 'data' column contains everything from $field that does not
   // have its own column and is not automatically populated when the field is
   // read.
@@ -226,17 +237,7 @@ function _update_7000_field_create_field(&$field) {
     ->fields($record)
     ->execute();
 
-  // Create storage for this field, the field module is not guaranteed to be
-  // loaded at this point.
-  module_load_install($field['module']);
-  $schema = (array) module_invoke($field['module'], 'field_schema', $field);
-  $schema += array('columns' => array(), 'indexes' => array());
-  // 'columns' are hardcoded in the field type.
-  $field['columns'] = $schema['columns'];
-  // 'indexes' can be both hardcoded in the field type, and specified in the
-  // incoming $field definition.
-  $field['indexes'] += $schema['indexes'];
-
+  // Create storage for the field.
   field_sql_storage_field_storage_create_field($field);
 }
 
@@ -296,13 +297,12 @@ function _update_7000_field_delete_instance($field_name, $entity_type, $bundle)
     ->execute();
 
   // Nuke data.
-  $etid = _field_sql_storage_etid($entity_type);
   db_delete('field_data_' . $field_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('bundle', $bundle)
     ->execute();
   db_delete('field_revision_' . $field_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('bundle', $bundle)
     ->execute();
 }
@@ -379,7 +379,7 @@ function _update_7000_field_create_instance($field, &$instance) {
 }
 
 /**
- * @defgroup field-updates-6.x-to-7.x Field updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -396,5 +396,36 @@ function field_update_7000() {
 }
 
 /**
- * @} End of "defgroup field-updates-6.x-to-7.x"
+ * Fix fields definitions created during the d6 to d7 upgrade path.
+ */
+function field_update_7001() {
+  $fields = _update_7000_field_read_fields();
+  foreach ($fields as $field) {
+    // _update_7000_field_create_field() was broken in d7 RC2, and the fields
+    // created during a d6 to d7 upgrade do not correcly store the 'index'
+    // entry. See http://drupal.org/node/996160.
+
+    module_load_install($field['module']);
+    $schema = (array) module_invoke($field['module'], 'field_schema', $field);
+    $schema += array('indexes' => array());
+    // 'indexes' can be both hardcoded in the field type, and specified in the
+    // incoming $field definition.
+    $field['indexes'] += $schema['indexes'];
+
+    // Place the updated entries in the existing serialized 'data' column.
+    $data = db_query("SELECT data FROM {field_config} WHERE id = :id", array(':id' => $field['id']))->fetchField();
+    $data = unserialize($data);
+    $data['columns'] = $field['columns'];
+    $data['indexes'] = $field['indexes'];
+
+    // Save the new data.
+    $query = db_update('field_config')
+      ->condition('id', $field['id'])
+      ->fields(array('data' => serialize($data)))
+      ->execute();
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/field/field.module b/modules/field/field.module
index 074cc212bae8c7d75186b267548ef9077b48dbbd..089dccfa15388fe6192dae637c58eabc33028e9c 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.module,v 1.88 2010/10/23 01:34:02 webchick Exp $
+// $Id: field.module,v 1.94 2011/01/02 17:26:39 webchick Exp $
 /**
  * @file
  * Attach custom data fields to Drupal entities.
@@ -38,7 +38,191 @@ require_once DRUPAL_ROOT . '/modules/field/field.form.inc';
  * fields via a web browser as well as a wide and flexible variety of
  * data type, form element, and display format capabilities.
  *
- * - @link field_structs Data structures: Field, Instance, Bundle @endlink.
+ * The Field API defines two primary data structures, Field and
+ * Instance, and the concept of a Bundle. A Field defines a
+ * particular type of data that can be attached to entities. A Field
+ * Instance is a Field attached to a single Bundle. A Bundle is a set
+ * of fields that are treated as a group by the Field Attach API and
+ * is related to a single fieldable entity type.
+ *
+ * For example, suppose a site administrator wants Article nodes to
+ * have a subtitle and photo. Using the Field API or Field UI module,
+ * the administrator creates a field named 'subtitle' of type 'text'
+ * and a field named 'photo' of type 'image'. The administrator
+ * (again, via a UI) creates two Field Instances, one attaching the
+ * field 'subtitle' to the 'node' bundle 'article' and one attaching
+ * the field 'photo' to the 'node' bundle 'article'. When the node
+ * system uses the Field Attach API to load all fields for an Article
+ * node, it passes the node's entity type (which is 'node') and
+ * content type (which is 'article') as the node's bundle.
+ * field_attach_load() then loads the 'subtitle' and 'photo' fields
+ * because they are both attached to the 'node' bundle 'article'.
+ *
+ * Field definitions are represented as an array of key/value pairs.
+ *
+ * array $field:
+ * - id (integer, read-only)
+ *     The primary identifier of the field. It is assigned automatically
+ *     by field_create_field().
+ * - field_name (string)
+ *     The name of the field. Each field name is unique within Field API.
+ *     When a field is attached to an entity, the field's data is stored
+ *     in $entity->$field_name. Maximum length is 32 characters.
+ * - type (string)
+ *     The type of the field, such as 'text' or 'image'. Field types
+ *     are defined by modules that implement hook_field_info().
+ * - entity_types (array)
+ *     The array of entity types that can hold instances of this field. If
+ *     empty or not specified, the field can have instances in any entity type.
+ * - cardinality (integer)
+ *     The number of values the field can hold. Legal values are any
+ *     positive integer or FIELD_CARDINALITY_UNLIMITED.
+ * - translatable (integer)
+ *     Whether the field is translatable.
+ * - locked (integer)
+ *     Whether or not the field is available for editing. If TRUE, users can't
+ *     change field settings or create new instances of the field in the UI.
+ *     Defaults to FALSE.
+ * - module (string, read-only)
+ *     The name of the module that implements the field type.
+ * - active (integer, read-only)
+ *     TRUE if the module that implements the field type is currently
+ *     enabled, FALSE otherwise.
+ * - deleted (integer, read-only)
+ *     TRUE if this field has been deleted, FALSE otherwise. Deleted
+ *     fields are ignored by the Field Attach API. This property exists
+ *     because fields can be marked for deletion but only actually
+ *     destroyed by a separate garbage-collection process.
+ * - columns (array, read-only).
+ *     An array of the Field API columns used to store each value of
+ *     this field. The column list may depend on field settings; it is
+ *     not constant per field type. Field API column specifications are
+ *     exactly like Schema API column specifications but, depending on
+ *     the field storage module in use, the name of the column may not
+ *     represent an actual column in an SQL database.
+ * - indexes (array).
+ *     An array of indexes on data columns, using the same definition format
+ *     as Schema API index specifications. Only columns that appear in the
+ *     'columns' setting are allowed. Note that field types can specify
+ *     default indexes, which can be modified or added to when
+ *     creating a field.
+ * - foreign keys: (optional) An associative array of relations, using the same
+ *   structure as the 'foreign keys' definition of hook_schema(). Note, however,
+ *   that the field data is not necessarily stored in SQL. Also, the possible
+ *   usage is limited, as you cannot specify another field as related, only
+ *   existing SQL tables, such as filter formats.
+ * - settings (array)
+ *     A sub-array of key/value pairs of field-type-specific settings. Each
+ *     field type module defines and documents its own field settings.
+ * - storage (array)
+ *     A sub-array of key/value pairs identifying the storage backend to use for
+ *     the for the field.
+ *     - type (string)
+ *         The storage backend used by the field. Storage backends are defined
+ *         by modules that implement hook_field_storage_info().
+ *     - module (string, read-only)
+ *         The name of the module that implements the storage backend.
+ *     - active (integer, read-only)
+ *         TRUE if the module that implements the storage backend is currently
+ *         enabled, FALSE otherwise.
+ *     - settings (array)
+ *         A sub-array of key/value pairs of settings. Each storage backend
+ *         defines and documents its own settings.
+ *
+ * Field instance definitions are represented as an array of key/value pairs.
+ *
+ * array $instance:
+ * - id (integer, read-only)
+ *     The primary identifier of this field instance. It is assigned
+ *     automatically by field_create_instance().
+ * - field_id (integer, read-only)
+ *     The foreign key of the field attached to the bundle by this instance.
+ *     It is populated automatically by field_create_instance().
+ * - field_name (string)
+ *     The name of the field attached to the bundle by this instance.
+ * - entity_type (string)
+ *     The name of the entity type the instance is attached to.
+ * - bundle (string)
+ *     The name of the bundle that the field is attached to.
+ * - label (string)
+ *     A human-readable label for the field when used with this
+ *     bundle. For example, the label will be the title of Form API
+ *     elements for this instance.
+ * - description (string)
+ *     A human-readable description for the field when used with this
+ *     bundle. For example, the description will be the help text of
+ *     Form API elements for this instance.
+ * - required (integer)
+ *     TRUE if a value for this field is required when used with this
+ *     bundle, FALSE otherwise. Currently, required-ness is only enforced
+ *     during Form API operations, not by field_attach_load(),
+ *     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.
+ *     This property exists because instances can be marked for deletion but
+ *     only actually destroyed by a separate garbage-collection process.
+ * - settings (array)
+ *     A sub-array of key/value pairs of field-type-specific instance
+ *     settings. Each field type module defines and documents its own
+ *     instance settings.
+ * - widget (array)
+ *     A sub-array of key/value pairs identifying the Form API input widget
+ *     for the field when used by this bundle.
+ *     - type (string)
+ *         The type of the widget, such as text_textfield. Widget types
+ *         are defined by modules that implement hook_field_widget_info().
+ *     - settings (array)
+ *         A sub-array of key/value pairs of widget-type-specific settings.
+ *         Each field widget type module defines and documents its own
+ *         widget settings.
+ *     - weight (float)
+ *         The weight of the widget relative to the other elements in entity
+ *         edit forms.
+ *     - module (string, read-only)
+ *         The name of the module that implements the widget type.
+ * - display (array)
+ *     A sub-array of key/value pairs identifying the way field values should
+ *     be displayed in each of the entity type's view modes, plus the 'default'
+ *     mode. For each view mode, Field UI lets site administrators define
+ *     whether they want to use a dedicated set of display options or the
+ *     'default' options to reduce the number of displays to maintain as they
+ *     add new fields. For nodes, on a fresh install, only the 'teaser' view
+ *     mode is configured to use custom display options, all other view modes
+ *     defined use the 'default' options by default. When programmatically
+ *     adding field instances on nodes, it is therefore recommended to at least
+ *     specify display options for 'default' and 'teaser'.
+ *     - default (array)
+ *         A sub-array of key/value pairs describing the display options to be
+ *         used when the field is being displayed in view modes that are not
+ *         configured to use dedicated display options.
+ *         - label (string)
+ *             Position of the label. 'inline', 'above' and 'hidden' are the
+ *             values recognized by the default 'field' theme implementation.
+ *         - type (string)
+ *             The type of the display formatter, or 'hidden' for no display.
+ *         - settings (array)
+ *             A sub-array of key/value pairs of display options specific to
+ *             the formatter.
+ *        - weight (float)
+ *            The weight of the field relative to the other entity components
+ *            displayed in this view mode.
+ *         - module (string, read-only)
+ *             The name of the module which implements the display formatter.
+ *     - some_mode
+ *         A sub-array of key/value pairs describing the display options to be
+ *         used when the field is being displayed in the 'some_mode' view mode.
+ *         Those options will only be actually applied at run time if the view
+ *         mode is not configured to use default settings for this bundle.
+ *         - ...
+ *     - other_mode
+ *        - ...
+ *
+ * Bundles are represented by two strings, an entity type and a bundle name.
  *
  * - @link field_types Field Types API @endlink. Defines field types,
  *   widget types, and display formatters. Field modules use this API
@@ -75,21 +259,33 @@ require_once DRUPAL_ROOT . '/modules/field/field.form.inc';
  */
 
 /**
- * Value for $field['cardinality'] property to indicate it can hold an
- * unlimited number of values.
+ * Value for field API indicating a field accepts an unlimited number of values.
  */
 define('FIELD_CARDINALITY_UNLIMITED', -1);
 
 /**
- * TODO
+ * Value for field API indicating a widget doesn't accept default values.
+ *
+ * @see hook_field_widget_info()
  */
 define('FIELD_BEHAVIOR_NONE', 0x0001);
+
 /**
- * TODO
+ * Value for field API concerning widget default and multiple value settings.
+ *
+ * @see hook_field_widget_info()
+ *
+ * When used in a widget default context, indicates the widget accepts default
+ * values. When used in a multiple value context for a widget that allows the
+ * input of one single field value, indicates that the widget will be repeated
+ * for each value input.
  */
 define('FIELD_BEHAVIOR_DEFAULT', 0x0002);
+
 /**
- * TODO
+ * Value for field API indicating a widget can receive several field values.
+ *
+ * @see hook_field_widget_info()
  */
 define('FIELD_BEHAVIOR_CUSTOM', 0x0004);
 
@@ -98,6 +294,7 @@ define('FIELD_BEHAVIOR_CUSTOM', 0x0004);
  * field data with field_attach_load().
  */
 define('FIELD_LOAD_CURRENT', 'FIELD_LOAD_CURRENT');
+
 /**
  * Age argument for loading the version of an entity's field data
  * specified in the entity with field_attach_load().
@@ -124,7 +321,7 @@ function field_help($path, $arg) {
     case 'admin/help#field':
       $output = '';
       $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Field module allows custom data fields to be attached to Drupal <em>entities</em> (content nodes, users, taxonomy vocabularies, etc.) and takes care of storing, loading, editing, and rendering field data. Most users will not interact with the Field module directly, but will instead use the <a href="@field-ui-help">Field UI module</a> user interface. Module developers can use the Field API to make new entities "fieldable" and thus allow fields to be attached to their entities. For more information, see the online handbook entry for <a href="@field">Field module</a>.', array('@field-ui-help' => url('admin/help/field_ui'), '@field' => 'http://drupal.org/handbook/modules/field')) . '</p>';
+      $output .= '<p>' . t('The Field module allows custom data fields to be defined for <em>entity</em> types (entities include content items, comments, user accounts, and taxonomy terms). The Field module takes care of storing, loading, editing, and rendering field data. Most users will not interact with the Field module directly, but will instead use the <a href="@field-ui-help">Field UI module</a> user interface. Module developers can use the Field API to make new entity types "fieldable" and thus allow fields to be attached to them. For more information, see the online handbook entry for <a href="@field">Field module</a>.', array('@field-ui-help' => url('admin/help/field_ui'), '@field' => 'http://drupal.org/handbook/modules/field')) . '</p>';
       $output .= '<h3>' . t('Uses') . '</h3>';
       $output .= '<dl>';
       $output .= '<dt>' . t('Enabling field types') . '</dt>';
@@ -369,7 +566,7 @@ function _field_sort_items_value_helper($a, $b) {
  *       'extra_field_2' => ...
  *     ),
  *   ),
- * ),
+ * );
  * @endcode
  *
  * @param $entity_type
@@ -387,8 +584,8 @@ function field_bundle_settings($entity_type, $bundle, $settings = NULL) {
 
   if (isset($settings)) {
     $stored_settings[$entity_type][$bundle] = $settings;
+
     variable_set('field_bundle_settings', $stored_settings);
-    drupal_static_reset('field_view_mode_settings');
     field_info_cache_clear();
   }
   else {
@@ -397,6 +594,10 @@ function field_bundle_settings($entity_type, $bundle, $settings = NULL) {
       'view_modes' => array(),
       'extra_fields' => array(),
     );
+    $settings['extra_fields'] += array(
+      'form' => array(),
+      'display' => array(),
+    );
 
     return $settings;
   }
@@ -444,11 +645,13 @@ function field_view_mode_settings($entity_type, $bundle) {
  *   The field instance being displayed.
  * @param $view_mode
  *   The view mode.
+ * @param $entity
+ *   The entity being displayed.
  *
  * @return
  *   The display settings to be used when displaying the field values.
  */
-function field_get_display($instance, $view_mode) {
+function field_get_display($instance, $view_mode, $entity) {
   // Check whether the view mode uses custom display settings or the 'default'
   // mode.
   $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
@@ -460,6 +663,7 @@ function field_get_display($instance, $view_mode) {
     'entity_type' => $instance['entity_type'],
     'field' => field_info_field($instance['field_name']),
     'instance' => $instance,
+    'entity' => $entity,
     'view_mode' => $view_mode,
   );
   drupal_alter(array('field_display', 'field_display_' . $instance['entity_type']), $display, $context);
@@ -698,6 +902,7 @@ function field_view_field($entity_type, $entity, $field_name, $display = array()
       'entity_type' => $entity_type,
       'entity' => $entity,
       'view_mode' => '_custom',
+      'display' => $display,
     );
     drupal_alter('field_attach_view', $result, $context);
 
diff --git a/modules/field/field.multilingual.inc b/modules/field/field.multilingual.inc
index fe227a784d4bc01da80ac6f047faf5879c372535..b2bb36ca3a2e2a18636ba725b87f0a954b28d5e8 100644
--- a/modules/field/field.multilingual.inc
+++ b/modules/field/field.multilingual.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.multilingual.inc,v 1.14 2010/10/09 03:43:31 webchick Exp $
+// $Id: field.multilingual.inc,v 1.15 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -7,7 +7,7 @@
  */
 
 /**
- * @defgroup field_language Field language API
+ * @defgroup field_language Field Language API
  * @{
  * Handling of multilingual fields.
  *
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 a9936aa8d2fff528fc51ce2d4b34b27106582c01..b7e02d5e4d391cbfd82fce60765ab8c621265634 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.info
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.info
@@ -1,17 +1,15 @@
-; $Id: field_sql_storage.info,v 1.5 2010/08/16 20:57:22 dries Exp $
+; $Id: field_sql_storage.info,v 1.6 2010/12/20 19:59:41 webchick Exp $
 name = Field SQL storage
 description = Stores field data in an SQL database.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = field_sql_storage.module
-files[] = field_sql_storage.install
 files[] = field_sql_storage.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.install b/modules/field/modules/field_sql_storage/field_sql_storage.install
index 554660ea8a22b489649847f09fe8ea9e82757c29..bdb56312033bea12915ccaa56fbe1b794a105d0f 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.install
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_sql_storage.install,v 1.10 2010/09/29 19:46:40 dries Exp $
+// $Id: field_sql_storage.install,v 1.14 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -12,26 +12,6 @@
 function field_sql_storage_schema() {
   $schema = array();
 
-  // Static (meta-data) tables.
-  $schema['field_config_entity_type'] = array(
-    'fields' => array(
-      'etid' => array(
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The unique id for this entity type',
-      ),
-      'type' => array(
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'description' => 'An entity type',
-      ),
-    ),
-    'primary key' => array('etid'),
-    'unique keys' => array('type' => array('type')),
-  );
-
   // Dynamic (data) tables.
   if (db_table_exists('field_config')) {
     $fields = field_read_fields(array(), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
@@ -54,16 +34,15 @@ function field_sql_storage_schema() {
  * @ingroup update-api-6.x-to-7.x
  */
 function _update_7000_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, $data) {
-  $etid = _field_sql_storage_etid($entity_type);
   $table_name = "field_data_{$field_name}";
   $revision_name = "field_revision_{$field_name}";
 
   db_delete($table_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $entity_id)
     ->execute();
   db_delete($revision_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $entity_id)
     ->condition('revision_id', $revision_id)
     ->execute();
@@ -72,7 +51,7 @@ function _update_7000_field_sql_storage_write($entity_type, $bundle, $entity_id,
   foreach ($data as $langcode => $items) {
     foreach ($items as $delta => $item) {
       $record = array(
-        'etid' => $etid,
+        'entity_type' => $entity_type,
         'entity_id' => $entity_id,
         'revision_id' => $revision_id,
         'bundle' => $bundle,
@@ -104,7 +83,7 @@ function _update_7000_field_sql_storage_write($entity_type, $bundle, $entity_id,
 }
 
 /**
- * @defgroup field-sql-storage-updates-6.x-to-7.x Field SQL storage updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -122,5 +101,116 @@ function field_sql_storage_update_7000() {
 }
 
 /**
- * @} End of "defgroup field-updates-6.x-to-7.x"
+ * Remove the field_config_entity_type table and store 'entity_type' strings.
+ */
+function field_sql_storage_update_7001(&$sandbox) {
+  if (!isset($sandbox['progress'])) {
+    // Collect current etids.
+    $sandbox['etids'] = db_query('SELECT etid, type FROM {field_config_entity_type}')->fetchAllKeyed();
+
+    // Collect affected tables: field data, field revision data, 'deleted'
+    // tables.
+    $sandbox['tables'] = array();
+    $results = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC))
+      ->fields('fc')
+      ->condition('storage_module', 'field_sql_storage')
+      ->execute();
+    foreach ($results as $field) {
+      if ($field['deleted']) {
+        $sandbox['tables']["field_deleted_data_{$field['id']}"] = 'data';
+        $sandbox['tables']["field_deleted_revision_{$field['id']}"] = 'revision';
+      }
+      else {
+        $sandbox['tables']["field_data_{$field['field_name']}"] = 'data';
+        $sandbox['tables']["field_revision_{$field['field_name']}"] = 'revision';
+      }
+    }
+    reset($sandbox['tables']);
+
+    $sandbox['total'] = count($sandbox['tables']);
+    $sandbox['progress'] = 0;
+  }
+
+  if ($sandbox['tables']) {
+    // Grab the next table to process.
+    $table = key($sandbox['tables']);
+    $type = array_shift($sandbox['tables']);
+
+    if (db_table_exists($table)) {
+      // Add the 'entity_type' column.
+      if (!db_field_exists($table, 'entity_type')) {
+        $column = array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The entity type this data is attached to.',
+        );
+        db_add_field($table, 'entity_type', $column);
+
+        // Populate the 'entity_type' column based on the 'etid' column.
+        foreach ($sandbox['etids'] as $etid => $entity_type) {
+          db_update($table)
+            ->fields(array('entity_type' => $entity_type))
+            ->condition('etid', $etid)
+            ->execute();
+        }
+
+        // Index the new column.
+        db_add_index($table, 'entity_type', array('entity_type'));
+      }
+
+      // Use the 'entity_type' column in the primary key.
+      db_drop_primary_key($table);
+      $primary_keys = array(
+        'data' => array('entity_type', 'entity_id', 'deleted', 'delta', 'language'),
+        'revision' => array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'language'),
+      );
+      db_add_primary_key($table, $primary_keys[$type]);
+
+      // Drop the 'etid' column.
+      if (db_field_exists($table, 'etid')) {
+        db_drop_field($table, 'etid');
+      }
+    }
+
+    // Report progress.
+    $sandbox['progress']++;
+    $sandbox['#finished'] = min(0.99, $sandbox['progress'] / $sandbox['total']);
+  }
+  else {
+    // No more tables left: drop the field_config_entity_type table.
+    db_drop_table('field_config_entity_type');
+
+    // Drop the previous 'field_sql_storage_ENTITYTYPE_etid' system variables.
+    foreach ($sandbox['etids'] as $etid => $entity_type) {
+      variable_del('field_sql_storage_' . $entity_type . '_etid');
+    }
+
+    // We're done.
+    $sandbox['#finished'] = 1;
+  }
+}
+
+/**
+ * Fix primary keys in field revision data tables.
+ */
+function field_sql_storage_update_7002() {
+  $results = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC))
+    ->fields('fc')
+    ->condition('storage_module', 'field_sql_storage')
+    ->execute();
+  foreach ($results as $field) {
+    // Revision tables of deleted fields do not need to be fixed, since no new
+    // data is written to them.
+    if (!$field['deleted']) {
+      $table = "field_revision_{$field['field_name']}";
+      db_drop_primary_key($table);
+      db_add_primary_key($table, array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'language'));
+    }
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
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 f2e64301beb232e355870d3d18e5ff1ddec2fa0a..23f449007e3f65d95bc746efad4682a69f7898f7 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.56 2010/10/06 13:57:47 dries Exp $
+// $Id: field_sql_storage.module,v 1.58 2010/12/21 04:11:12 webchick Exp $
 
 /**
  * @file
@@ -95,24 +95,6 @@ function _field_sql_storage_indexname($name, $index) {
   return $name . '_' . $index;
 }
 
-/**
- * Retrieve or assign an entity type id for an entity type.
- *
- * @param $entity_type
- *   The entity type, such as 'node' or 'user'.
- * @return
- *   The entity type id.
- *
- */
-function _field_sql_storage_etid($entity_type) {
-  $etid = variable_get('field_sql_storage_' . $entity_type . '_etid', NULL);
-  if (!isset($etid)) {
-    $etid = db_insert('field_config_entity_type')->fields(array('type' => $entity_type))->execute();
-    variable_set('field_sql_storage_' . $entity_type . '_etid', $etid);
-  }
-  return $etid;
-}
-
 /**
  * Return the database schema for a field. This may contain one or
  * more tables. Each table will contain the columns relevant for the
@@ -129,11 +111,12 @@ function _field_sql_storage_schema($field) {
   $current = array(
     'description' => "Data storage for {$deleted}field {$field['id']} ({$field['field_name']})",
     'fields' => array(
-      'etid' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => 128,
         'not null' => TRUE,
-        'description' => 'The entity type id this data is attached to',
+        'default' => '',
+        'description' => 'The entity type this data is attached to',
       ),
       'bundle' => array(
         'type' => 'varchar',
@@ -176,10 +159,9 @@ function _field_sql_storage_schema($field) {
         'description' => 'The sequence number for this data item, used for multi-value fields',
       ),
     ),
-    // @todo Is the primary key needed at all ?
-    'primary key' => array('etid', 'entity_id', 'deleted', 'delta', 'language'),
+    'primary key' => array('entity_type', 'entity_id', 'deleted', 'delta', 'language'),
     'indexes' => array(
-      'etid' => array('etid'),
+      'entity_type' => array('entity_type'),
       'bundle' => array('bundle'),
       'deleted' => array('deleted'),
       'entity_id' => array('entity_id'),
@@ -213,12 +195,10 @@ function _field_sql_storage_schema($field) {
     }
   }
 
-  // Construct the revision table. The primary key includes
-  // revision_id but not entity_id so that multiple revision loads can
-  // use the IN operator.
+  // Construct the revision table.
   $revision = $current;
   $revision['description'] = "Revision archive storage for {$deleted}field {$field['id']} ({$field['field_name']})";
-  $revision['primary key'] = array('etid', 'revision_id', 'deleted', 'delta', 'language');
+  $revision['primary key'] = array('entity_type', 'entity_id', 'revision_id', 'deleted', 'delta', 'language');
   $revision['fields']['revision_id']['not null'] = TRUE;
   $revision['fields']['revision_id']['description'] = 'The entity revision id this data is attached to';
 
@@ -322,7 +302,6 @@ function field_sql_storage_field_storage_delete_field($field) {
  */
 function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fields, $options) {
   $field_info = field_info_field_by_ids();
-  $etid = _field_sql_storage_etid($entity_type);
   $load_current = $age == FIELD_LOAD_CURRENT;
 
   foreach ($fields as $field_id => $ids) {
@@ -332,7 +311,7 @@ function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fi
 
     $query = db_select($table, 't')
       ->fields('t')
-      ->condition('etid', $etid)
+      ->condition('entity_type', $entity_type)
       ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
       ->condition('language', field_available_languages($entity_type, $field), 'IN')
       ->orderBy('delta');
@@ -374,7 +353,6 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel
   if (!isset($vid)) {
     $vid = $id;
   }
-  $etid = _field_sql_storage_etid($entity_type);
 
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
@@ -392,12 +370,12 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel
       $languages = !empty($entity->$field_name) ? $field_languages : $all_languages;
       if ($languages) {
         db_delete($table_name)
-          ->condition('etid', $etid)
+          ->condition('entity_type', $entity_type)
           ->condition('entity_id', $id)
           ->condition('language', $languages, 'IN')
           ->execute();
         db_delete($revision_name)
-          ->condition('etid', $etid)
+          ->condition('entity_type', $entity_type)
           ->condition('entity_id', $id)
           ->condition('revision_id', $vid)
           ->condition('language', $languages, 'IN')
@@ -407,7 +385,7 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel
 
     // Prepare the multi-insert query.
     $do_insert = FALSE;
-    $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
+    $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
     foreach ($field['columns'] as $column => $attributes) {
       $columns[] = _field_sql_storage_columnname($field_name, $column);
     }
@@ -421,7 +399,7 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel
         // We now know we have someting to insert.
         $do_insert = TRUE;
         $record = array(
-          'etid' => $etid,
+          'entity_type' => $entity_type,
           'entity_id' => $id,
           'revision_id' => $vid,
           'bundle' => $bundle,
@@ -457,7 +435,6 @@ function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fiel
  */
 function field_sql_storage_field_storage_delete($entity_type, $entity, $fields) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   foreach (field_info_instances($entity_type, $bundle) as $instance) {
     if (isset($fields[$instance['field_id']])) {
@@ -475,16 +452,15 @@ function field_sql_storage_field_storage_delete($entity_type, $entity, $fields)
  */
 function field_sql_storage_field_storage_purge($entity_type, $entity, $field, $instance) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_delete($table_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $id)
     ->execute();
   db_delete($revision_name)
-    ->condition('etid', $etid)
+    ->condition('entity_type', $entity_type)
     ->condition('entity_id', $id)
     ->execute();
 }
@@ -510,18 +486,13 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
     $table_alias = $tablename . $key;
     $table_aliases[$key] = $table_alias;
     if ($key) {
-      $select_query->join($tablename, $table_alias, "$table_alias.etid = $field_base_table.etid AND $table_alias.$id_key = $field_base_table.$id_key");
+      $select_query->join($tablename, $table_alias, "$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key");
     }
     else {
       $select_query = db_select($tablename, $table_alias);
       $select_query->addTag('entity_field_access');
       $select_query->addMetaData('base_table', $tablename);
-      $select_query->fields($table_alias, array('entity_id', 'revision_id', 'bundle'));
-      // As only a numeric ID is stored instead of the entity type add the
-      // field_config_entity_type table to resolve the etid to a more readable
-      // name.
-      $select_query->join('field_config_entity_type', 'fcet', "fcet.etid = $table_alias.etid");
-      $select_query->addField('fcet', 'type', 'entity_type');
+      $select_query->fields($table_alias, array('entity_type', 'entity_id', 'revision_id', 'bundle'));
       $field_base_table = $table_alias;
     }
     if ($field['cardinality'] != 1) {
@@ -574,16 +545,14 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
     }
   }
   foreach ($query->entityConditions as $key => $condition) {
-    $sql_field = $key == 'entity_type' ? 'fcet.type' : "$field_base_table.$key";
-    $query->addCondition($select_query, $sql_field, $condition);
+    $query->addCondition($select_query, "$field_base_table.$key", $condition);
   }
 
   // Order the query.
   foreach ($query->order as $order) {
     if ($order['type'] == 'entity') {
       $key = $order['specifier'];
-      $sql_field = $key == 'entity_type' ? 'fcet.type' : "$field_base_table.$key";
-      $select_query->orderBy($sql_field, $order['direction']);
+      $select_query->orderBy("$field_base_table.$key", $order['direction']);
     }
     elseif ($order['type'] == 'field') {
       $specifier = $order['specifier'];
@@ -630,14 +599,13 @@ function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity
  */
 function field_sql_storage_field_storage_delete_revision($entity_type, $entity, $fields) {
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $etid = _field_sql_storage_etid($entity_type);
 
   if (isset($vid)) {
     foreach ($fields as $field_id) {
       $field = field_info_field_by_id($field_id);
       $revision_name = _field_sql_storage_revision_tablename($field);
       db_delete($revision_name)
-        ->condition('etid', $etid)
+        ->condition('entity_type', $entity_type)
         ->condition('entity_id', $id)
         ->condition('revision_id', $vid)
         ->execute();
@@ -651,18 +619,17 @@ function field_sql_storage_field_storage_delete_revision($entity_type, $entity,
  * This function simply marks for deletion all data associated with the field.
  */
 function field_sql_storage_field_storage_delete_instance($instance) {
-  $etid = _field_sql_storage_etid($instance['entity_type']);
   $field = field_info_field($instance['field_name']);
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_update($table_name)
     ->fields(array('deleted' => 1))
-    ->condition('etid', $etid)
+    ->condition('entity_type', $instance['entity_type'])
     ->condition('bundle', $instance['bundle'])
     ->execute();
   db_update($revision_name)
     ->fields(array('deleted' => 1))
-    ->condition('etid', $etid)
+    ->condition('entity_type', $instance['entity_type'])
     ->condition('bundle', $instance['bundle'])
     ->execute();
 }
@@ -671,7 +638,6 @@ function field_sql_storage_field_storage_delete_instance($instance) {
  * Implements hook_field_attach_rename_bundle().
  */
 function field_sql_storage_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
-  $etid = _field_sql_storage_etid($entity_type);
   // We need to account for deleted or inactive fields and instances.
   $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
   foreach ($instances as $instance) {
@@ -681,12 +647,12 @@ function field_sql_storage_field_attach_rename_bundle($entity_type, $bundle_old,
       $revision_name = _field_sql_storage_revision_tablename($field);
       db_update($table_name)
         ->fields(array('bundle' => $bundle_new))
-        ->condition('etid', $etid)
+        ->condition('entity_type', $entity_type)
         ->condition('bundle', $bundle_old)
         ->execute();
       db_update($revision_name)
         ->fields(array('bundle' => $bundle_new))
-        ->condition('etid', $etid)
+        ->condition('entity_type', $entity_type)
         ->condition('bundle', $bundle_old)
         ->execute();
     }
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.test b/modules/field/modules/field_sql_storage/field_sql_storage.test
index bbef5cc8f3300d9d695b2e8b1677d85e34de0574..e5d626226e4cfdb805054aca3e7c14e867eef096 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.test
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_sql_storage.test,v 1.22 2010/09/29 01:37:02 dries Exp $
+// $Id: field_sql_storage.test,v 1.23 2010/12/14 19:50:05 dries Exp $
 
 /**
  * @file
@@ -37,19 +37,6 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
 
   }
 
-  function testEntityTypeId() {
-    $t1 = _field_sql_storage_etid('t1');
-    $t2 = _field_sql_storage_etid('t2');
-
-    $this->assertEqual($t1+1, $t2, 'Entity type ids are sequential');
-    $this->assertIdentical(variable_get('field_sql_storage_t1_etid', NULL), $t1, 'First entity type variable is correct');
-    $this->assertIdentical(variable_get('field_sql_storage_t2_etid', NULL), $t2, 'Second entity type variable is correct');
-    $this->assertEqual(db_query("SELECT etid FROM {field_config_entity_type} WHERE type='t1'")->fetchField(), $t1, 'First entity type in database is correct');
-    $this->assertEqual(db_query("SELECT etid FROM {field_config_entity_type} WHERE type='t2'")->fetchField(), $t2, 'Second entity type in database is correct');
-    $this->assertEqual($t1, _field_sql_storage_etid('t1'), '_field_sql_storage_etid returns the same value for the first entity type');
-    $this->assertEqual($t2, _field_sql_storage_etid('t2'), '_field_sql_storage_etid returns the same value for the second entity type');
-  }
-
   /**
    * Uses the mysql tables and records to verify
    * field_load_revision works correctly.
@@ -59,8 +46,7 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
     $eid = 0;
     $langcode = LANGUAGE_NONE;
 
-    $etid = _field_sql_storage_etid($entity_type);
-    $columns = array('etid', 'entity_id', 'revision_id', 'delta', 'language', $this->field_name . '_value');
+    $columns = array('entity_type', 'entity_id', 'revision_id', 'delta', 'language', $this->field_name . '_value');
 
     // Insert data for four revisions to the field revisions table
     $query = db_insert($this->revision_table)->fields($columns);
@@ -70,7 +56,7 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
       for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
         $value = mt_rand(1, 127);
         $values[$evid][] = $value;
-        $query->values(array($etid, $eid, $evid, $delta, $langcode, $value));
+        $query->values(array($entity_type, $eid, $evid, $delta, $langcode, $value));
       }
     }
     $query->execute();
@@ -78,7 +64,7 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
     // Insert data for the "most current revision" into the field table
     $query = db_insert($this->table)->fields($columns);
     foreach ($values[0] as $delta => $value) {
-      $query->values(array($etid, $eid, 0, $delta, $langcode, $value));
+      $query->values(array($entity_type, $eid, 0, $delta, $langcode, $value));
     }
     $query->execute();
 
@@ -112,7 +98,7 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
     $eid = $evid = 1;
     $unavailable_language = 'xx';
     $entity = field_test_create_stub_entity($eid, $evid, $this->instance['bundle']);
-    $values = array($etid, $eid, $evid, 0, $unavailable_language, mt_rand(1, 127));
+    $values = array($entity_type, $eid, $evid, 0, $unavailable_language, mt_rand(1, 127));
     db_insert($this->table)->fields($columns)->values($values)->execute();
     db_insert($this->revision_table)->fields($columns)->values($values)->execute();
     field_attach_load($entity_type, array($eid => $entity));
@@ -256,8 +242,8 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
     // Add a translation in an unavailable language.
     $unavailable_language = 'xx';
     db_insert($this->table)
-      ->fields(array('etid', 'bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'language'))
-      ->values(array(_field_sql_storage_etid($entity_type), $this->instance['bundle'], 0, 0, 0, 0, $unavailable_language))
+      ->fields(array('entity_type', 'bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'language'))
+      ->values(array($entity_type, $this->instance['bundle'], 0, 0, 0, 0, $unavailable_language))
       ->execute();
     $count = db_select($this->table)
       ->countQuery()
diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info
index 1cf247d15a4e87fbf7c16f00f099f1b0e38602d6..cefac307f9665b51da6602fac9e0b8879e62af5d 100644
--- a/modules/field/modules/list/list.info
+++ b/modules/field/modules/list/list.info
@@ -1,16 +1,15 @@
-; $Id: list.info,v 1.8 2010/08/16 20:57:22 dries Exp $
+; $Id: list.info,v 1.10 2010/12/20 19:59:41 webchick Exp $
 name = List
 description = Defines list field types. Use with Options to create selection lists.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = list.module
+dependencies[] = options
 files[] = tests/list.test
-required = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/list/list.install b/modules/field/modules/list/list.install
index d9398a38183ccf27dfd0707a2447333990bdceb1..3642b1d5355f63ac38c6e8fb209fbc6f1b7e3115 100644
--- a/modules/field/modules/list/list.install
+++ b/modules/field/modules/list/list.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: list.install,v 1.1 2010/09/04 15:40:51 dries Exp $
+// $Id: list.install,v 1.4 2010/12/18 00:50:03 dries Exp $
 
 /**
  * @file
@@ -20,7 +20,7 @@ function list_field_schema($field) {
         ),
       );
       break;
-    case 'list_number':
+    case 'list_float':
       $columns = array(
         'value' => array(
           'type' => 'float',
@@ -28,7 +28,8 @@ function list_field_schema($field) {
         ),
       );
       break;
-    default:
+    case 'list_integer':
+    case 'list_boolean':
       $columns = array(
         'value' => array(
           'type' => 'int',
@@ -43,4 +44,75 @@ function list_field_schema($field) {
       'value' => array('value'),
     ),
   );
-}
\ No newline at end of file
+}
+
+/**
+ * Rename the list field types and change 'allowed_values' format.
+ */
+function list_update_7001() {
+  $fields = _update_7000_field_read_fields(array('module' => 'list'));
+  foreach ($fields as $field_name => $field) {
+    $update = array();
+
+    // Translate the old string format into the new array format.
+    $allowed_values = $field['settings']['allowed_values'];
+    if (is_string($allowed_values)) {
+      $position_keys = ($field['type'] == 'list');
+      $allowed_values = _list_update_7001_extract_allowed_values($allowed_values, $position_keys);
+
+      // Additionally, float keys need to be disambiguated ('.5' is '0.5').
+      if ($field['type'] == 'list_number') {
+        $keys = array_map(create_function('$a', 'return (string) (float) $a;'), array_keys($allowed_values));
+        $allowed_values = array_combine($keys, array_values($allowed_values));
+      }
+
+      // Place the new setting in the existing serialized 'data' column.
+      $data = db_query("SELECT data FROM {field_config} WHERE id = :id", array(':id' => $field['id']))->fetchField();
+      $data = unserialize($data);
+      $data['settings']['allowed_values'] = $allowed_values;
+      $update['data'] = serialize($data);
+    }
+
+    // Rename field types.
+    $types = array('list' => 'list_integer', 'list_number' => 'list_float');
+    if (isset($types[$field['type']])) {
+      $update['type'] = $types[$field['type']];
+    }
+
+    // Save the new data.
+    if ($update) {
+      $query = db_update('field_config')
+        ->condition('id', $field['id'])
+        ->fields($update)
+        ->execute();
+    }
+  }
+}
+
+/**
+ * Helper function for list_update_7001: extract allowed values from a string.
+ *
+ * This reproduces the parsing logic in use before D7 RC2.
+ */
+function _list_update_7001_extract_allowed_values($string, $position_keys) {
+  $values = array();
+
+  $list = explode("\n", $string);
+  $list = array_map('trim', $list);
+  $list = array_filter($list, 'strlen');
+
+  foreach ($list as $key => $value) {
+    // Check for a manually specified key.
+    if (strpos($value, '|') !== FALSE) {
+      list($key, $value) = explode('|', $value);
+    }
+    // Otherwise see if we need to use the value as the key. The "list" type
+    // will automatically convert non-keyed lines to integers.
+    elseif (!$position_keys) {
+      $key = $value;
+    }
+    $values[$key] = (isset($value) && $value !== '') ? $value : $key;
+  }
+
+  return $values;
+}
diff --git a/modules/field/modules/list/list.module b/modules/field/modules/list/list.module
index 4310ab4e0f0a4c24cc4c986a3adb89aee2c6575f..ca45e68f3cf5d9ac8230bf452e6c123936d6083d 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.35 2010/10/11 19:57:00 dries Exp $
+// $Id: list.module,v 1.39 2010/12/18 00:50:03 dries Exp $
 
 /**
  * @file
@@ -24,95 +24,112 @@ function list_help($path, $arg) {
  */
 function list_field_info() {
   return array(
-    'list' => array(
-      'label' => t('List'),
-      'description' => t('This field stores numeric keys from key/value lists of allowed values where the key is a simple alias for the position of the value, i.e. 0|First option, 1|Second option, 2|Third option.'),
-      'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
+    'list_integer' => array(
+      'label' => t('List (integer)'),
+      'description' => t("This field stores integer values from a list of allowed 'value => label' pairs, i.e. 'Lifetime in days': 1 => 1 day, 7 => 1 week, 31 => 1 month."),
+      'settings' => array('allowed_values' => array(), 'allowed_values_function' => ''),
       'default_widget' => 'options_select',
       'default_formatter' => 'list_default',
     ),
-    'list_boolean' => array(
-      'label' => t('Boolean'),
-      'description' => t('This field stores simple on/off or yes/no options.'),
-      'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
-      'default_widget' => 'options_buttons',
-      'default_formatter' => 'list_default',
-    ),
-    'list_number' => array(
-      'label' => t('List (numeric)'),
-      'description' => t('This field stores keys from key/value lists of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'),
-      'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
+    'list_float' => array(
+      'label' => t('List (float)'),
+      'description' => t("This field stores float values from a list of allowed 'value => label' pairs, i.e. 'Fraction': 0 => 0, .25 => 1/4, .75 => 3/4, 1 => 1."),
+      'settings' => array('allowed_values' => array(), 'allowed_values_function' => ''),
       'default_widget' => 'options_select',
       'default_formatter' => 'list_default',
     ),
     'list_text' => array(
       'label' => t('List (text)'),
-      'description' => t('This field stores keys from key/value lists of allowed values where the stored key has significance and must be a varchar, i.e. \'US States\': IL|Illinois, IA|Iowa, IN|Indiana'),
-      'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
+      'description' => t("This field stores text values from a list of allowed 'value => label' pairs, i.e. 'US States': IL => Illinois, IA => Iowa, IN => Indiana."),
+      'settings' => array('allowed_values' => array(), 'allowed_values_function' => ''),
       'default_widget' => 'options_select',
       'default_formatter' => 'list_default',
     ),
+    'list_boolean' => array(
+      'label' => t('Boolean'),
+      'description' => t('This field stores simple on/off or yes/no options.'),
+      'settings' => array('allowed_values' => array(), 'allowed_values_function' => ''),
+      'default_widget' => 'options_buttons',
+      'default_formatter' => 'list_default',
+    ),
   );
 }
 
 /**
  * Implements hook_field_settings_form().
- *
- * @todo: If $has_data, add a form validate function to verify that the
- * new allowed values do not exclude any keys for which data already
- * exists in the field storage (use EntityFieldQuery to find out).
- * Implement the validate function via hook_field_update_forbid() so
- * list.module does not depend on form submission.
  */
 function list_field_settings_form($field, $instance, $has_data) {
   $settings = $field['settings'];
 
-  $form['allowed_values'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Allowed values list'),
-    '#default_value' => $settings['allowed_values'],
-    '#required' => FALSE,
-    '#rows' => 10,
-    '#description' => '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label. The key is the value that will be stored in the database, and must be a %type value. The label is optional, and the key will be used as the label if no label is specified.', array('%type' => $field['type'] == 'list_text' ? t('text') : t('numeric'))) . '</p>',
-    '#element_validate' => array('list_allowed_values_setting_validate'),
-    '#list_field_type' => $field['type'],
-    '#access' => empty($settings['allowed_values_function']),
-  );
+  switch ($field['type']) {
+    case 'list_integer':
+    case 'list_float':
+    case 'list_text':
+      $form['allowed_values'] = array(
+        '#type' => 'textarea',
+        '#title' => t('Allowed values list'),
+        '#default_value' => list_allowed_values_string($settings['allowed_values']),
+        '#rows' => 10,
+        '#element_validate' => array('list_allowed_values_setting_validate'),
+        '#field_has_data' => $has_data,
+        '#field' => $field,
+        '#field_type' => $field['type'],
+        '#access' => empty($settings['allowed_values_function']),
+      );
+
+      $description = '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label.');
+      if ($field['type'] == 'list_integer' || $field['type'] == 'list_float') {
+        $description .= '<br/>' . t('The key is the stored value, and must be numeric. The label will be used in displayed values and edit forms.');
+        $description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
+        $description .= '<br/>' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.');
+      }
+      else {
+        $description .= '<br/>' . t('The key is the stored value. The label will be used in displayed values and edit forms.');
+        $description .= '<br/>' . t('The label is optional: if a line contains a single string, it will be used as key and label.');
+      }
+      $description .= '</p>';
+      $form['allowed_values']['#description'] = $description;
+
+      break;
 
-  if ($field['type'] == 'list_boolean') {
-    $values = list_extract_allowed_values($settings['allowed_values']);
-    $off_value = array_shift($values);
-    $on_value = array_shift($values);
-    $form['allowed_values'] = array(
-      '#type' => 'value',
-      '#description' => '',
-      '#value_callback' => 'list_boolean_allowed_values_callback',
-      '#access' => empty($settings['allowed_values_function']),
-    );
-    $form['allowed_values']['on'] = array(
-      '#type' => 'textfield',
-      '#title' => t('On value'),
-      '#default_value' => $on_value,
-      '#required' => FALSE,
-      '#description' => t('If left empty, "1" will be used.'),
-      // Change #parents to make sure the element is not saved into field
-      // settings.
-      '#parents' => array('on'),
-    );
-    $form['allowed_values']['off'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Off value'),
-      '#default_value' => $off_value,
-      '#required' => FALSE,
-      '#description' => t('If left empty, "0" will be used.'),
-      // Change #parents to make sure the element is not saved into field
-      // settings.
-      '#parents' => array('off'),
-    );
-    // Link the allowed value to the on / off elements to prepare for the rare
-    // case of an alter changing #parents.
-    $form['allowed_values']['#on_parents'] = &$form['allowed_values']['on']['#parents'];
-    $form['allowed_values']['#off_parents'] = &$form['allowed_values']['off']['#parents'];
+    case 'list_boolean':
+      $values = $settings['allowed_values'];
+      $off_value = array_shift($values);
+      $on_value = array_shift($values);
+
+      $form['allowed_values'] = array(
+        '#type' => 'value',
+        '#description' => '',
+        '#value_callback' => 'list_boolean_allowed_values_callback',
+        '#access' => empty($settings['allowed_values_function']),
+      );
+      $form['allowed_values']['on'] = array(
+        '#type' => 'textfield',
+        '#title' => t('On value'),
+        '#default_value' => $on_value,
+        '#required' => FALSE,
+        '#description' => t('If left empty, "1" will be used.'),
+        // Change #parents to make sure the element is not saved into field
+        // settings.
+        '#parents' => array('on'),
+      );
+      $form['allowed_values']['off'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Off value'),
+        '#default_value' => $off_value,
+        '#required' => FALSE,
+        '#description' => t('If left empty, "0" will be used.'),
+        // Change #parents to make sure the element is not saved into field
+        // settings.
+        '#parents' => array('off'),
+      );
+
+      // Link the allowed value to the on / off elements to prepare for the rare
+      // case of an alter changing #parents.
+      $form['allowed_values']['#on_parents'] = &$form['allowed_values']['on']['#parents'];
+      $form['allowed_values']['#off_parents'] = &$form['allowed_values']['off']['#parents'];
+
+      break;
   }
 
   // Alter the description for allowed values depending on the widget type.
@@ -122,7 +139,7 @@ function list_field_settings_form($field, $instance, $has_data) {
   elseif ($instance['widget']['type'] == 'options_buttons') {
     $form['allowed_values']['#description'] .= '<p>' . t("The 'checkboxes/radio buttons' widget will display checkboxes if the <em>Number of values</em> option is greater than 1 for this field, otherwise radios will be displayed.") . '</p>';
   }
-  $form['allowed_values']['#description'] .= t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags()));
+  $form['allowed_values']['#description'] .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '</p>';
 
   $form['allowed_values_function'] = array(
     '#type' => 'value',
@@ -142,23 +159,42 @@ function list_field_settings_form($field, $instance, $has_data) {
  * Element validate callback; check that the entered values are valid.
  */
 function list_allowed_values_setting_validate($element, &$form_state) {
-  $values = list_extract_allowed_values($element['#value'], $element['#list_field_type'] == 'list');
-  $field_type = $element['#list_field_type'];
+  $field = $element['#field'];
+  $has_data = $element['#field_has_data'];
+  $field_type = $field['type'];
+  $generate_keys = ($field_type == 'list_integer' || $field_type == 'list_float') && !$has_data;
 
-  // Check that keys are valid for the field type.
-  foreach ($values as $key => $value) {
-    if ($field_type == 'list_number' && !is_numeric($key)) {
-      form_error($element, t('Allowed values list: each key must be a valid integer or decimal.'));
-      break;
-    }
-    elseif ($field_type == 'list_text' && drupal_strlen($key) > 255) {
-      form_error($element, t('Allowed values list: each key must be a string at most 255 characters long.'));
-      break;
+  $values = list_extract_allowed_values($element['#value'], $field['type'], $generate_keys);
+
+  if (!is_array($values)) {
+    form_error($element, t('Allowed values list: invalid input.'));
+  }
+  else {
+    // Check that keys are valid for the field type.
+    foreach ($values as $key => $value) {
+      if ($field_type == 'list_integer' && !preg_match('/^-?\d+$/', $key)) {
+        form_error($element, t('Allowed values list: keys must be integers.'));
+        break;
+      }
+      if ($field_type == 'list_float' && !is_numeric($key)) {
+        form_error($element, t('Allowed values list: each key must be a valid integer or decimal.'));
+        break;
+      }
+      elseif ($field_type == 'list_text' && drupal_strlen($key) > 255) {
+        form_error($element, t('Allowed values list: each key must be a string at most 255 characters long.'));
+        break;
+      }
     }
-    elseif ($field_type == 'list' && !preg_match('/^-?\d+$/', $key)) {
-      form_error($element, t('Allowed values list: keys must be integers.'));
-      break;
+
+    // Prevent removing values currently in use.
+    if ($has_data) {
+      $lost_keys = array_diff(array_keys($field['settings']['allowed_values']), array_keys($values));
+      if (_list_values_in_use($field, $lost_keys)) {
+        form_error($element, t('Allowed values list: some values are being removed while currently in use.'));
+      }
     }
+
+    form_set_value($element, $values, $form_state);
   }
 }
 
@@ -168,7 +204,7 @@ function list_allowed_values_setting_validate($element, &$form_state) {
 function list_boolean_allowed_values_callback($element, $input, $form_state) {
   $on = drupal_array_get_nested_value($form_state['input'], $element['#on_parents']);
   $off = drupal_array_get_nested_value($form_state['input'], $element['#off_parents']);
-  return "0|$off\n1|$on";
+  return array($off, $on);
 }
 
 /**
@@ -179,7 +215,7 @@ function list_field_update_field($field, $prior_field, $has_data) {
 }
 
 /**
- * Returns the set of allowed values for a list field.
+ * Returns the array of allowed values for a list field.
  *
  * The strings are not safe for output. Keys and values of the array should be
  * sanitized through field_filter_xss() before being displayed.
@@ -189,21 +225,18 @@ function list_field_update_field($field, $prior_field, $has_data) {
  *
  * @return
  *   The array of allowed values. Keys of the array are the raw stored values
- *   (integer or text), values of the array are the display aliases.
+ *   (number or text), values of the array are the display labels.
  */
 function list_allowed_values($field) {
   $allowed_values = &drupal_static(__FUNCTION__, array());
 
   if (!isset($allowed_values[$field['id']])) {
-    $values = array();
-
     $function = $field['settings']['allowed_values_function'];
     if (!empty($function) && function_exists($function)) {
       $values = $function($field);
     }
-    elseif (!empty($field['settings']['allowed_values'])) {
-      $position_keys = $field['type'] == 'list';
-      $values = list_extract_allowed_values($field['settings']['allowed_values'], $position_keys);
+    else {
+      $values = $field['settings']['allowed_values'];
     }
 
     $allowed_values[$field['id']] = $values;
@@ -213,44 +246,127 @@ function list_allowed_values($field) {
 }
 
 /**
- * Generates an array of values from a string.
- *
- * Explode a string with keys and labels separated with '|' and with each new
- * value on its own line.
+ * Parses a string of 'allowed values' into an array.
  *
- * @param $string_values
- *   The list of choices as a string, in the format expected by the
- *   'allowed_values' setting:
- *    - Values are separated by a carriage return.
- *    - Each value is in the format "value|label" or "value".
- * @param $position_keys
+ * @param $string
+ *   The list of allowed values in string format descibed in
+ *   list_allowed_values_string().
+ * @param $field_type
+ *   The field type. Either 'list_number' or 'list_text'.
+ * @param $generate_keys
  *   Boolean value indicating whether to generate keys based on the position of
- *   the value if a key is not manually specified, effectively generating
- *   integer-based keys. This should only be TRUE for fields that have a type of
- *   "list". Otherwise the value will be used as the key if not specified.
+ *   the value if a key is not manually specified, and if the value cannot be
+ *   used as a key. This should only be TRUE for fields of type 'list_number'.
+ *
+ * @return
+ *   The array of extracted key/value pairs, or NULL if the string is invalid.
+ *
+ * @see list_allowed_values_string()
  */
-function list_extract_allowed_values($string_values, $position_keys = FALSE) {
+function list_extract_allowed_values($string, $field_type, $generate_keys) {
   $values = array();
 
-  $list = explode("\n", $string_values);
+  $list = explode("\n", $string);
   $list = array_map('trim', $list);
   $list = array_filter($list, 'strlen');
-  foreach ($list as $key => $value) {
-    // Check for a manually specified key.
-    if (strpos($value, '|') !== FALSE) {
-      list($key, $value) = explode('|', $value);
+
+  $generated_keys = $explicit_keys = FALSE;
+  foreach ($list as $position => $text) {
+    $value = $key = FALSE;
+
+    // Check for an explicit key.
+    $matches = array();
+    if (preg_match('/(.*)\|(.*)/', $text, $matches)) {
+      $key = $matches[1];
+      $value = $matches[2];
+      $explicit_keys = TRUE;
+    }
+    // Otherwise see if we can use the value as the key. Detecting true integer
+    // strings takes a little trick.
+    elseif ($field_type == 'list_text'
+    || ($field_type == 'list_float' && is_numeric($text))
+    || ($field_type == 'list_integer' && is_numeric($text) && (float) $text == intval($text))) {
+      $key = $value = $text;
+      $explicit_keys = TRUE;
+    }
+    // Otherwise see if we can generate a key from the position.
+    elseif ($generate_keys) {
+      $key = (string) $position;
+      $value = $text;
+      $generated_keys = TRUE;
+    }
+    else {
+      return;
     }
-    // Otherwise see if we need to use the value as the key. The "list" type
-    // will automatically convert non-keyed lines to integers.
-    elseif (!$position_keys) {
-      $key = $value;
+
+    // Float keys are represented as strings and need to be disambiguated
+    // ('.5' is '0.5').
+    if ($field_type == 'list_float' && is_numeric($key)) {
+      $key = (string) (float) $key;
     }
-    $values[$key] = (isset($value) && $value !== '') ? $value : $key;
+
+    $values[$key] = $value;
+  }
+
+  // We generate keys only if the list contains no explicit key at all.
+  if ($explicit_keys && $generated_keys) {
+    return;
   }
 
   return $values;
 }
 
+/**
+ * Generates a string representation of an array of 'allowed values'.
+ *
+ * This string format is suitable for edition in a textarea.
+ *
+ * @param $values
+ *   An array of values, where array keys are values and array values are
+ *   labels.
+ *
+ * @return
+ *   The string representation of the $values array:
+ *    - Values are separated by a carriage return.
+ *    - Each value is in the format "value|label" or "value".
+ */
+function list_allowed_values_string($values) {
+  $lines = array();
+  foreach ($values as $key => $value) {
+    $lines[] = "$key|$value";
+  }
+  return implode("\n", $lines);
+}
+
+/**
+ * Implements hook_field_update_forbid().
+ */
+function list_field_update_forbid($field, $prior_field, $has_data) {
+  if ($field['module'] == 'list' && $has_data) {
+    // Forbid any update that removes allowed values with actual data.
+    $lost_keys = array_diff(array_keys($field['settings']['allowed_values']), array_keys($prior_field['settings']['allowed_values']));
+    if (_list_values_in_use($field, $lost_keys)) {
+      throw new FieldUpdateForbiddenException(t('Cannot update a list field to not include keys with existing data.'));
+    }
+  }
+}
+
+/**
+ * Checks if a list of values are being used in actual field values.
+ */
+function _list_values_in_use($field, $values) {
+  if ($values) {
+    $query = new EntityFieldQuery();
+    $found = $query
+      ->fieldCondition($field['field_name'], 'value', $values)
+      ->range(0, 1)
+      ->execute();
+    return !empty($found);
+  }
+
+  return FALSE;
+}
+
 /**
  * Implements hook_field_validate().
  *
@@ -261,7 +377,7 @@ function list_field_validate($entity_type, $entity, $field, $instance, $langcode
   $allowed_values = list_allowed_values($field);
   foreach ($items as $delta => $item) {
     if (!empty($item['value'])) {
-      if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
+      if (!empty($allowed_values) && !isset($allowed_values[$item['value']])) {
         $errors[$field['field_name']][$langcode][$delta][] = array(
           'error' => 'list_illegal_value',
           'message' => t('%name: illegal value.', array('%name' => t($instance['label']))),
@@ -291,8 +407,8 @@ function list_field_is_empty($item, $field) {
  */
 function list_field_widget_info_alter(&$info) {
   $widgets = array(
-    'options_select' => array('list', 'list_text', 'list_number'),
-    'options_buttons' => array('list', 'list_text', 'list_number', 'list_boolean'),
+    'options_select' => array('list_integer', 'list_float', 'list_text'),
+    'options_buttons' => array('list_integer', 'list_float', 'list_text', 'list_boolean'),
     'options_onoff' => array('list_boolean'),
   );
 
@@ -315,11 +431,11 @@ function list_field_formatter_info() {
   return array(
     'list_default' => array(
       'label' => t('Default'),
-      'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
+      'field types' => array('list_integer', 'list_float', 'list_text', 'list_boolean'),
     ),
     'list_key' => array(
       'label' => t('Key'),
-      'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
+      'field types' => array('list_integer', 'list_float', 'list_text', 'list_boolean'),
     ),
   );
 }
diff --git a/modules/field/modules/list/tests/list.test b/modules/field/modules/list/tests/list.test
index 3a1472dad27b1e4ebbb62f48a6f099f3fff2b4a2..ea23e6cb60c4180570af2041bacf8b40235431e6 100644
--- a/modules/field/modules/list/tests/list.test
+++ b/modules/field/modules/list/tests/list.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: list.test,v 1.8 2010/10/11 19:57:00 dries Exp $
+// $Id: list.test,v 1.11 2010/12/18 00:50:03 dries Exp $
 
 /**
  * @file
@@ -24,10 +24,10 @@ class ListFieldTestCase extends FieldTestCase {
     $this->field_name = 'test_list';
     $this->field = array(
       'field_name' => $this->field_name,
-      'type' => 'list',
+      'type' => 'list_integer',
       'cardinality' => 1,
       'settings' => array(
-        'allowed_values' => "1|One\n2|Two\n3|Three\n",
+        'allowed_values' => array(1 => 'One', 2 => 'Two', 3 => 'Three'),
       ),
     );
     $this->field = field_create_field($this->field);
@@ -57,7 +57,7 @@ class ListFieldTestCase extends FieldTestCase {
     $this->assertTrue(!empty($form[$this->field_name][$langcode][3]), t('Option 3 exists'));
 
     // Removed options do not appear.
-    $this->field['settings']['allowed_values'] = "2|Two";
+    $this->field['settings']['allowed_values'] = array(2 => 'Two');
     field_update_field($this->field);
     $entity = field_test_create_stub_entity();
     $form = drupal_get_form('field_test_entity_form', $entity);
@@ -66,7 +66,7 @@ class ListFieldTestCase extends FieldTestCase {
     $this->assertTrue(empty($form[$this->field_name][$langcode][3]), t('Option 3 does not exist'));
 
     // Completely new options appear.
-    $this->field['settings']['allowed_values'] = "10|Update\n20|Twenty";
+    $this->field['settings']['allowed_values'] = array(10 => 'Update', 20 => 'Twenty');
     field_update_field($this->field);
     $form = drupal_get_form('field_test_entity_form', $entity);
     $this->assertTrue(empty($form[$this->field_name][$langcode][1]), t('Option 1 does not exist'));
@@ -78,7 +78,7 @@ class ListFieldTestCase extends FieldTestCase {
     // Options are reset when a new field with the same name is created.
     field_delete_field($this->field_name);
     unset($this->field['id']);
-    $this->field['settings']['allowed_values'] = "1|One\n2|Two\n3|Three\n";
+    $this->field['settings']['allowed_values'] = array(1 => 'One', 2 => 'Two', 3 => 'Three');
     $this->field = field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
@@ -122,84 +122,237 @@ class ListFieldUITestCase extends FieldTestCase {
     $this->type = $type->type;
     // Store a valid URL name, with hyphens instead of underscores.
     $this->hyphen_type = str_replace('_', '-', $this->type);
+  }
+
+  /**
+   * List (integer) : test 'allowed values' input.
+   */
+  function testListAllowedValuesInteger() {
+    $this->field_name = 'field_list_integer';
+    $this->createListField('list_integer');
+
+    // Flat list of textual values.
+    $string = "Zero\nOne";
+    $array = array('0' => 'Zero', '1' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Unkeyed lists are accepted.'));
+    // Explicit integer keys.
+    $string = "0|Zero\n2|Two";
+    $array = array('0' => 'Zero', '2' => 'Two');
+    $this->assertAllowedValuesInput($string, $array, t('Integer keys are accepted.'));
+    // Check that values can be added and removed.
+    $string = "0|Zero\n1|One";
+    $array = array('0' => 'Zero', '1' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added and removed.'));
+    // Non-integer keys.
+    $this->assertAllowedValuesInput("1.1|One", 'keys must be integers', t('Non integer keys are rejected.'));
+    $this->assertAllowedValuesInput("abc|abc", 'keys must be integers', t('Non integer keys are rejected.'));
+    // Mixed list of keyed and unkeyed values.
+    $this->assertAllowedValuesInput("Zero\n1|One", 'invalid input', t('Mixed lists are rejected.'));
+
+    // Create a node with actual data for the field.
+    $settings = array(
+      'type' => $this->type,
+      $this->field_name => array(LANGUAGE_NONE => array(array('value' => 1))),
+    );
+    $node = $this->drupalCreateNode($settings);
+
+    // Check that a flat list of values is rejected once the field has data.
+    $this->assertAllowedValuesInput( "Zero\nOne", 'invalid input', t('Unkeyed lists are rejected once the field has data.'));
+
+    // Check that values can be added but values in use cannot be removed.
+    $string = "0|Zero\n1|One\n2|Two";
+    $array = array('0' => 'Zero', '1' => 'One', '2' => 'Two');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added.'));
+    $string = "0|Zero\n1|One";
+    $array = array('0' => 'Zero', '1' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
+    $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', t('Values in use cannot be removed.'));
+
+    // Delete the node, remove the value.
+    node_delete($node->nid);
+    $string = "0|Zero";
+    $array = array('0' => 'Zero');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
+  }
+
+  /**
+   * List (float) : test 'allowed values' input.
+   */
+  function testListAllowedValuesFloat() {
+    $this->field_name = 'field_list_float';
+    $this->createListField('list_float');
+
+    // Flat list of textual values.
+    $string = "Zero\nOne";
+    $array = array('0' => 'Zero', '1' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Unkeyed lists are accepted.'));
+    // Explicit numeric keys.
+    $string = "0|Zero\n.5|Point five";
+    $array = array('0' => 'Zero', '0.5' => 'Point five');
+    $this->assertAllowedValuesInput($string, $array, t('Integer keys are accepted.'));
+    // Check that values can be added and removed.
+    $string = "0|Zero\n.5|Point five\n1.0|One";
+    $array = array('0' => 'Zero', '0.5' => 'Point five', '1' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added and removed.'));
+    // Non-numeric keys.
+    $this->assertAllowedValuesInput("abc|abc\n", 'each key must be a valid integer or decimal', t('Non numeric keys are rejected.'));
+    // Mixed list of keyed and unkeyed values.
+    $this->assertAllowedValuesInput("Zero\n1|One\n", 'invalid input', t('Mixed lists are rejected.'));
+
+    // Create a node with actual data for the field.
+    $settings = array(
+      'type' => $this->type,
+      $this->field_name => array(LANGUAGE_NONE => array(array('value' => .5))),
+    );
+    $node = $this->drupalCreateNode($settings);
+
+    // Check that a flat list of values is rejected once the field has data.
+    $this->assertAllowedValuesInput("Zero\nOne", 'invalid input', t('Unkeyed lists are rejected once the field has data.'));
+
+    // Check that values can be added but values in use cannot be removed.
+    $string = "0|Zero\n.5|Point five\n2|Two";
+    $array = array('0' => 'Zero', '0.5' => 'Point five', '2' => 'Two');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added.'));
+    $string = "0|Zero\n.5|Point five";
+    $array = array('0' => 'Zero', '0.5' => 'Point five');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
+    $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', t('Values in use cannot be removed.'));
 
-    // Create random field name.
-    $this->field_label = $this->randomString();
-    $this->field_name = strtolower($this->randomName());
+    // Delete the node, remove the value.
+    node_delete($node->nid);
+    $string = "0|Zero";
+    $array = array('0' => 'Zero');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
   }
 
   /**
-   * Tests that allowed values are properly validated in the UI.
+   * List (text) : test 'allowed values' input.
    */
-  function testAllowedValues() {
-    $element_name = "field[settings][allowed_values]";
-
-    // Test 'List' field type.
-    $admin_path = $this->createListFieldAndEdit('list');
-    // Check that non-integer keys are rejected.
-    $edit = array($element_name => "1.1|one\n");
-    $this->drupalPost($admin_path, $edit, t('Save settings'));
-    $this->assertText("keys must be integers", t('Form validation failed.'));
-
-    // Test 'List (number)' field type.
-    $admin_path = $this->createListFieldAndEdit('list_number');
-    // Check that non-numeric keys are rejected.
-    $edit = array($element_name => "1|one\nB|two");
-    $this->drupalPost($admin_path, $edit, t('Save settings'));
-    $this->assertText("each key must be a valid integer or decimal", t('Form validation failed.'));
-
-    // Test 'List (text)' field type.
-    $admin_path = $this->createListFieldAndEdit('list_text');
-    // Check that overly long keys are rejected.
-    $edit = array($element_name => "1|one\n" . $this->randomName(256) . "|two");
-    $this->drupalPost($admin_path, $edit, t('Save settings'));
-    $this->assertText("each key must be a string at most 255 characters long", t('Form validation failed.'));
-
-    // Test 'Boolean' field type.
-    $admin_path = $this->createListFieldAndEdit('list_boolean');
+  function testListAllowedValuesText() {
+    $this->field_name = 'field_list_text';
+    $this->createListField('list_text');
+
+    // Flat list of textual values.
+    $string = "Zero\nOne";
+    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Unkeyed lists are accepted.'));
+    // Explicit keys.
+    $string = "zero|Zero\none|One";
+    $array = array('zero' => 'Zero', 'one' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Explicit keys are accepted.'));
+    // Check that values can be added and removed.
+    $string = "zero|Zero\ntwo|Two";
+    $array = array('zero' => 'Zero', 'two' => 'Two');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added and removed.'));
+    // Mixed list of keyed and unkeyed values.
+    $string = "zero|Zero\nOne\n";
+    $array = array('zero' => 'Zero', 'One' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Mixed lists are accepted.'));
+    // Overly long keys.
+    $this->assertAllowedValuesInput("zero|Zero\n" . $this->randomName(256) . "|One", 'each key must be a string at most 255 characters long', t('Overly long keys are rejected.'));
+
+    // Create a node with actual data for the field.
+    $settings = array(
+      'type' => $this->type,
+      $this->field_name => array(LANGUAGE_NONE => array(array('value' => 'One'))),
+    );
+    $node = $this->drupalCreateNode($settings);
+
+    // Check that flat lists of values are still accepted once the field has
+    // data.
+    $string = "Zero\nOne";
+    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Unkeyed lists are still accepted once the field has data.'));
+
+    // Check that values can be added but values in use cannot be removed.
+    $string = "Zero\nOne\nTwo";
+    $array = array('Zero' => 'Zero', 'One' => 'One', 'Two' => 'Two');
+    $this->assertAllowedValuesInput($string, $array, t('Values can be added.'));
+    $string = "Zero\nOne";
+    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
+    $this->assertAllowedValuesInput("Zero", 'some values are being removed while currently in use', t('Values in use cannot be removed.'));
+
+    // Delete the node, remove the value.
+    node_delete($node->nid);
+    $string = "Zero";
+    $array = array('Zero' => 'Zero');
+    $this->assertAllowedValuesInput($string, $array, t('Values not in use can be removed.'));
+  }
+
+  /**
+   * List (boolen) : test 'On/Off' values input.
+   */
+  function testListAllowedValuesBoolean() {
+    $this->field_name = 'field_list_boolean';
+    $this->createListField('list_boolean');
+
     // Check that the seperate 'On' and 'Off' form fields work.
     $on = $this->randomName();
     $off = $this->randomName();
+    $allowed_values = array(1 => $on, 0 => $off);
     $edit = array(
       'on' => $on,
       'off' => $off,
     );
-    $this->drupalPost($admin_path, $edit, t('Save settings'));
-    $this->assertText("Saved test_list_boolean configuration.", t("The 'On' and 'Off' form fields work for boolean fields."));
+    $this->drupalPost($this->admin_path, $edit, t('Save settings'));
+    $this->assertText("Saved field_list_boolean configuration.", t("The 'On' and 'Off' form fields work for boolean fields."));
     // Test the allowed_values on the field settings form.
-    $this->drupalGet($admin_path);
+    $this->drupalGet($this->admin_path);
     $this->assertFieldByName('on', $on, t("The 'On' value is stored correctly."));
     $this->assertFieldByName('off', $off, t("The 'Off' value is stored correctly."));
-    $field = field_info_field($this->field['field_name']);
-    $this->assertEqual($field['settings']['allowed_values'], "0|$off\n1|$on", t('The allowed value is correct'));
+    $field = field_info_field($this->field_name);
+    $this->assertEqual($field['settings']['allowed_values'], $allowed_values, t('The allowed value is correct'));
     $this->assertFalse(isset($field['settings']['on']), t('The on value is not saved into settings'));
     $this->assertFalse(isset($field['settings']['off']), t('The off value is not saved into settings'));
   }
 
   /**
-   * Helper function to create list field of a given type and get the edit page.
+   * Helper function to create list field of a given type.
    *
    * @param string $type
-   *   'list', 'list_boolean', 'list_number', or 'list_text'
+   *   'list_integer', 'list_float', 'list_text' or 'list_boolean'
    */
-  protected function createListFieldAndEdit($type) {
+  protected function createListField($type) {
     // Create a test field and instance.
-    $field_name = 'test_' . $type;
     $field = array(
-      'field_name' => $field_name,
+      'field_name' => $this->field_name,
       'type' => $type,
     );
     field_create_field($field);
-    $this->field = $field;
     $instance = array(
-      'field_name' => $field_name,
+      'field_name' => $this->field_name,
       'entity_type' => 'node',
       'bundle' => $this->type,
     );
     field_create_instance($instance);
 
-    $admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name;
-    return $admin_path;
+    $this->admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $this->field_name;
   }
 
+  /**
+   * Tests a string input for the 'allowed values' form element.
+   *
+   * @param $input_string
+   *   The input string, in the pipe-linefeed format expected by the form
+   *   element.
+   * @param $result
+   *   Either an expected resulting array in
+   *   $field['settings']['allowed_values'], or an expected error message.
+   * @param $message
+   *   Message to display.
+   */
+  function assertAllowedValuesInput($input_string, $result, $message) {
+    $edit = array('field[settings][allowed_values]' => $input_string);
+    $this->drupalPost($this->admin_path, $edit, t('Save settings'));
+
+    if (is_string($result)) {
+      $this->assertText($result, $message);
+    }
+    else {
+      field_info_cache_clear();
+      $field = field_info_field($this->field_name);
+      $this->assertIdentical($field['settings']['allowed_values'], $result, $message);
+    }
+  }
 }
diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info
index c045041943c69d87e27d76bf206abb8383033159..0760a3e7424943c52179ea7be88fe686614e6e25 100644
--- a/modules/field/modules/list/tests/list_test.info
+++ b/modules/field/modules/list/tests/list_test.info
@@ -1,14 +1,13 @@
-;$Id: list_test.info,v 1.1 2009/12/14 20:18:55 dries Exp $
+;$Id: list_test.info,v 1.2 2010/12/20 19:59:41 webchick Exp $
 name = "List test"
 description = "Support module for the List module tests."
 core = 7.x
 package = Testing
-files[] = list_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info
index f6c4bf3a11c4a7ae9a0581b9ea7f24d95809e9db..5c39c1fa48b6c52024cc65ee35d93c9c94bfba54 100644
--- a/modules/field/modules/number/number.info
+++ b/modules/field/modules/number/number.info
@@ -1,15 +1,14 @@
-; $Id: number.info,v 1.6 2010/08/16 20:57:22 dries Exp $
+; $Id: number.info,v 1.9 2010/12/20 19:59:41 webchick Exp $
 name = Number
 description = Defines numeric field types.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = number.module
-required = TRUE
+files[] = number.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/number/number.module b/modules/field/modules/number/number.module
index 4d0f7b8f3a52867a686d892ff9ed95f77cde4937..591440816ca314a0c04f9295f66c8b5fffdf2727 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.44 2010/10/22 00:42:42 dries Exp $
+// $Id: number.module,v 1.46 2010/10/31 12:11:59 dries Exp $
 
 /**
  * @file
@@ -330,8 +330,9 @@ function number_field_widget_form(&$form, &$form_state, $field, $instance, $lang
     '#default_value' => $value,
     // Allow a slightly larger size that the field length to allow for some
     // configurations where all characters won't fit in input field.
-    '#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 12,
-    '#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] : 10,
+    '#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 4 : 12,
+    // Allow two extra characters for signed values and decimal separator.
+    '#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 10,
     // Extract the number type from the field type name for easier validation.
     '#number_type' => str_replace('number_', '', $field['type']),
   );
@@ -355,8 +356,8 @@ function number_field_widget_form(&$form, &$form_state, $field, $instance, $lang
  * FAPI validation of an individual number element.
  */
 function number_field_widget_validate($element, &$form_state) {
-  $field = $form_state['field'][$element['#field_name']][$element['#language']]['field'];
-  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
 
   $type = $element['#number_type'];
   $value = $element['#value'];
diff --git a/modules/field/modules/number/number.test b/modules/field/modules/number/number.test
new file mode 100644
index 0000000000000000000000000000000000000000..21a4c94f54dda5e3a197357e485415a7772a0c52
--- /dev/null
+++ b/modules/field/modules/number/number.test
@@ -0,0 +1,75 @@
+<?php
+// $Id: number.test,v 1.1 2010/10/23 21:03:22 webchick Exp $
+
+/**
+ * @file
+ * Tests for number field types.
+ */
+
+/**
+ * Tests for number field types.
+ */
+class NumberFieldTestCase extends DrupalWebTestCase {
+  protected $field;
+  protected $instance;
+  protected $web_user;
+
+  public static function getInfo() {
+    return array(
+      'name'  => 'Number field',
+      'description'  => 'Test the creation of number fields.',
+      'group' => 'Field types'
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_test');
+    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $this->drupalLogin($this->web_user);
+  }
+
+  /**
+   * Test number_decimal field.
+   */
+  function testNumberDecimalField() {
+    // Create a field with settings to validate.
+    $this->field = array(
+      'field_name' => drupal_strtolower($this->randomName()),
+      'type' => 'number_decimal',
+      'settings' => array(
+        'precision' => 8, 'scale' => 4, 'decimal_separator' => '.',
+      )
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field['field_name'],
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
+      'widget' => array(
+        'type' => 'number',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'number_decimal',
+        ),
+      ),
+    );
+    field_create_instance($this->instance);
+
+    // Display creation form.
+    $this->drupalGet('test-entity/add/test-bundle');
+    $langcode = LANGUAGE_NONE;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', t('Widget is displayed'));
+
+    // Submit a signed decimal value within the allowed precision and scale.
+    $value = '-1234.5678';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value]" => $value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
+    $this->assertRaw(round($value, 2), t('Value is displayed.'));
+  }
+}
diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info
index 0ef6e0415aeb4124cd1e20286f96f39f341dcbb3..b99963033a1802c8b75d1310cd62cd692dfa3b54 100644
--- a/modules/field/modules/options/options.info
+++ b/modules/field/modules/options/options.info
@@ -1,16 +1,14 @@
-; $Id: options.info,v 1.6 2010/08/16 20:57:22 dries Exp $
+; $Id: options.info,v 1.8 2010/12/20 19:59:41 webchick Exp $
 name = Options
 description = Defines selection, check box and radio button widgets for text and numeric fields.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = options.module
 files[] = options.test
-required = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/options/options.module b/modules/field/modules/options/options.module
index 3994ba470a11bb3dfc76b37fe4d71e4739f70122..0da436c5a269b0627a488c2a6131923ce3ef3d68 100644
--- a/modules/field/modules/options/options.module
+++ b/modules/field/modules/options/options.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: options.module,v 1.27 2010/08/17 21:48:39 dries Exp $
+// $Id: options.module,v 1.30 2010/12/06 18:04:27 webchick Exp $
 
 /**
  * @file
@@ -61,6 +61,7 @@ function options_field_widget_info() {
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
       ),
+      'settings' => array('display_label' => 0),
     ),
   );
 }
@@ -122,6 +123,10 @@ function options_field_widget_form(&$form, &$form_state, $field, $instance, $lan
       );
       // Override the title from the incoming $element.
       $element['#title'] = isset($options[$on_value]) ? $options[$on_value] : '';
+
+      if ($instance['widget']['settings']['display_label']) {
+        $element['#title'] = $instance['label'];
+      }
       break;
   }
 
@@ -134,6 +139,22 @@ function options_field_widget_form(&$form, &$form_state, $field, $instance, $lan
   return $element;
 }
 
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function options_field_widget_settings_form($field, $instance) {
+  $form = array();
+  if ($instance['widget']['type'] == 'options_onoff') {
+    $form['display_label'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Use field label instead of the "On value" as label'),
+      '#default_value' => $instance['widget']['settings']['display_label'],
+      '#weight' => -1,
+    );
+  }
+  return $form;
+}
+
 /**
  * Form element validation handler for options element.
  */
@@ -152,7 +173,6 @@ function options_field_widget_validate($element, &$form_state) {
  */
 function _options_properties($type, $multiple, $required, $has_value) {
   $base = array(
-    'zero_placeholder' => FALSE,
     'filter_xss' => FALSE,
     'strip_tags' => FALSE,
     'empty_option' => FALSE,
@@ -190,9 +210,6 @@ function _options_properties($type, $multiple, $required, $has_value) {
     case 'buttons':
       $properties = array(
         'filter_xss' => TRUE,
-        // Form API 'checkboxes' do not suport 0 as an option, so we replace it with
-        // a placeholder within the form workflow.
-        'zero_placeholder' => $multiple,
       );
       // Add a 'none' option for non-required radio buttons.
       if (!$required && !$multiple) {
@@ -238,18 +255,6 @@ function _options_get_options($field, $instance, $properties) {
  * The function is recursive to support optgroups.
  */
 function _options_prepare_options(&$options, $properties) {
-  // Substitute the '_0' placeholder.
-  if ($properties['zero_placeholder']) {
-    $values = array_keys($options);
-    $labels = array_values($options);
-    // Use a strict comparison, because 0 == 'any string'.
-    $index = array_search(0, $values, TRUE);
-    if ($index !== FALSE && !is_array($options[$index])) {
-      $values[$index] = '_0';
-      $options = array_combine($values, $labels);
-    }
-  }
-
   foreach ($options as $value => $label) {
     // Recurse for optgroups.
     if (is_array($label)) {
@@ -273,14 +278,6 @@ function _options_storage_to_form($items, $options, $column, $properties) {
   $items_transposed = options_array_transpose($items);
   $values = (isset($items_transposed[$column]) && is_array($items_transposed[$column])) ? $items_transposed[$column] : array();
 
-  // Substitute the '_0' placeholder.
-  if ($properties['zero_placeholder']) {
-    $index = array_search('0', $values);
-    if ($index !== FALSE) {
-      $values[$index] = '_0';
-    }
-  }
-
   // Discard values that are not in the current list of options. Flatten the
   // array if needed.
   if ($properties['optgroups']) {
@@ -302,14 +299,6 @@ function _options_form_to_storage($element) {
     $values = array($values[0] ? $element['#on_value'] : $element['#off_value']);
   }
 
-  // Substitute the '_0' placeholder.
-  if ($properties['zero_placeholder']) {
-    $index = array_search('_0', $values);
-    if ($index !== FALSE) {
-      $values[$index] = 0;
-    }
-  }
-
   // Filter out the 'none' option. Use a strict comparison, because
   // 0 == 'any string'.
   if ($properties['empty_option']) {
diff --git a/modules/field/modules/options/options.test b/modules/field/modules/options/options.test
index 729a1e172544a492c161114a78656879d1d37e82..e94f4c03299c31e88d6a62c97c3b90371c625f49 100644
--- a/modules/field/modules/options/options.test
+++ b/modules/field/modules/options/options.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: options.test,v 1.17 2010/09/24 00:37:42 dries Exp $
+// $Id: options.test,v 1.23 2010/12/18 00:50:03 dries Exp $
 
 class OptionsWidgetsTestCase extends FieldTestCase {
   public static function getInfo() {
@@ -16,11 +16,11 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     // Field with cardinality 1.
     $this->card_1 = array(
       'field_name' => 'card_1',
-      'type' => 'list',
+      'type' => 'list_integer',
       'cardinality' => 1,
       'settings' => array(
         // Make sure that 0 works as an option.
-        'allowed_values' => "0|Zero\n1|One\n2|Some <script>dangerous</script> & unescaped <strong>markup</strong>\n",
+        'allowed_values' => array(0 => 'Zero', 1 => 'One', 2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>'),
       ),
     );
     $this->card_1 = field_create_field($this->card_1);
@@ -28,11 +28,11 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     // Field with cardinality 2.
     $this->card_2 = array(
       'field_name' => 'card_2',
-      'type' => 'list',
+      'type' => 'list_integer',
       'cardinality' => 2,
       'settings' => array(
         // Make sure that 0 works as an option.
-        'allowed_values' => "0|Zero\n1|One\n2|Some <script>dangerous</script> & unescaped <strong>markup</strong>\n",
+        'allowed_values' => array(0 => 'Zero', 1 => 'One', 2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>'),
       ),
     );
     $this->card_2 = field_create_field($this->card_2);
@@ -44,7 +44,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
       'cardinality' => 1,
       'settings' => array(
         // Make sure that 0 works as a 'on' value'.
-        'allowed_values' => "1|No\n0|Some <script>dangerous</script> & unescaped <strong>markup</strong>\n",
+        'allowed_values' => array(1 => 'Zero', 0 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>'),
       ),
     );
     $this->bool = field_create_field($this->bool);
@@ -100,7 +100,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array());
 
     // Check that required radios with one option is auto-selected.
-    $this->card_1['settings']['allowed_values'] = '99|Only allowed value';
+    $this->card_1['settings']['allowed_values'] = array(99 => 'Only allowed value');
     field_update_field($this->card_1);
     $instance['required'] = TRUE;
     field_update_instance($instance);
@@ -112,9 +112,6 @@ class OptionsWidgetsTestCase extends FieldTestCase {
    * Tests the 'options_buttons' widget (multiple select).
    */
   function testCheckBoxes() {
-    // Checkboxes do not support '0' as an option, the widget internally
-    // replaces it with '_0'.
-
     // Create an instance of the 'multiple values' field.
     $instance = array(
       'field_name' => $this->card_2['field_name'],
@@ -142,7 +139,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
 
     // Submit form: select first and third options.
     $edit = array(
-      "card_2[$langcode][_0]" => TRUE,
+      "card_2[$langcode][0]" => TRUE,
       "card_2[$langcode][1]" => FALSE,
       "card_2[$langcode][2]" => TRUE,
     );
@@ -157,7 +154,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
 
     // Submit form: select only first option.
     $edit = array(
-      "card_2[$langcode][_0]" => TRUE,
+      "card_2[$langcode][0]" => TRUE,
       "card_2[$langcode][1]" => FALSE,
       "card_2[$langcode][2]" => FALSE,
     );
@@ -172,7 +169,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
 
     // Submit form: select the three options while the field accepts only 2.
     $edit = array(
-      "card_2[$langcode][_0]" => TRUE,
+      "card_2[$langcode][0]" => TRUE,
       "card_2[$langcode][1]" => TRUE,
       "card_2[$langcode][2]" => TRUE,
     );
@@ -181,7 +178,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
 
     // Submit form: uncheck all options.
     $edit = array(
-      "card_2[$langcode][_0]" => FALSE,
+      "card_2[$langcode][0]" => FALSE,
       "card_2[$langcode][1]" => FALSE,
       "card_2[$langcode][2]" => FALSE,
     );
@@ -190,7 +187,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array());
 
     // Required checkbox with one option is auto-selected.
-    $this->card_2['settings']['allowed_values'] = '99|Only allowed value';
+    $this->card_2['settings']['allowed_values'] = array(99 => 'Only allowed value');
     field_update_field($this->card_2);
     $instance['required'] = TRUE;
     field_update_instance($instance);
@@ -266,7 +263,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
 
     // Test optgroups.
 
-    $this->card_1['settings']['allowed_values'] = NULL;
+    $this->card_1['settings']['allowed_values'] = array();
     $this->card_1['settings']['allowed_values_function'] = 'list_test_allowed_values_callback';
     field_update_field($this->card_1);
 
@@ -381,7 +378,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     // Test optgroups.
 
     // Use a callback function defining optgroups.
-    $this->card_2['settings']['allowed_values'] = NULL;
+    $this->card_2['settings']['allowed_values'] = array();
     $this->card_2['settings']['allowed_values_function'] = 'list_test_allowed_values_callback';
     field_update_field($this->card_2);
     $instance['required'] = FALSE;
@@ -456,6 +453,62 @@ class OptionsWidgetsTestCase extends FieldTestCase {
     // Display form: with 'off' value, option is unchecked.
     $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoFieldChecked("edit-bool-$langcode");
+
+    // Create admin user.
+    $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
+    $this->drupalLogin($admin_user);
+
+    // Create a test field instance.
+    $fieldUpdate = $this->bool;
+    $fieldUpdate['settings']['allowed_values'] = array(0 => 0, 1 => 'MyOnValue');
+    field_update_field($fieldUpdate);
+    $instance = array(
+      'field_name' => $this->bool['field_name'],
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'widget' => array(
+            'type' => 'options_onoff',
+            'module' => 'options',
+        ),
+    );
+    field_create_instance($instance);
+
+    // Go to the edit page and check if the default settings works as expected
+    $fieldEditUrl = 'admin/structure/types/manage/page/fields/bool';
+    $this->drupalGet($fieldEditUrl);
+
+    $this->assertText(
+      'Use field label instead of the "On value" as label ',
+      t('Display setting checkbox available.')
+    );
+
+    $this->assertFieldByXPath(
+      '*//label[@for="edit-' . $this->bool['field_name'] . '-und" and text()="MyOnValue "]',
+      TRUE,
+      t('Default case shows "On value"')
+    );
+
+    // Enable setting
+    $edit = array('instance[widget][settings][display_label]' => 1);
+    // Save the new Settings
+    $this->drupalPost($fieldEditUrl, $edit, t('Save settings'));
+
+    // Go again to the edit page and check if the setting
+    // is stored and has the expected effect
+    $this->drupalGet($fieldEditUrl);
+    $this->assertText(
+      'Use field label instead of the "On value" as label ',
+      t('Display setting checkbox is available')
+    );
+    $this->assertFieldChecked(
+      'edit-instance-widget-settings-display-label',
+      t('Display settings checkbox checked')
+    );
+    $this->assertFieldByXPath(
+      '*//label[@for="edit-' . $this->bool['field_name'] . '-und" and text()="' . $this->bool['field_name'] . ' "]',
+      TRUE,
+      t('Display label changes label of the checkbox')
+    );
   }
 }
 
diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info
index a2ed62fd0605434a2483d2ff6167b906aaa1e0f0..0b90b111fecc4eb15e7a9f8f543af5b5c295b427 100644
--- a/modules/field/modules/text/text.info
+++ b/modules/field/modules/text/text.info
@@ -1,16 +1,15 @@
-; $Id: text.info,v 1.8 2010/08/16 20:57:22 dries Exp $
+; $Id: text.info,v 1.9 2010/12/20 19:59:41 webchick Exp $
 name = Text
 description = Defines simple text field types.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = text.module
 files[] = text.test
 required = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/modules/text/text.js b/modules/field/modules/text/text.js
index 8388a743492dcd7c4b41f5fb025c04817d008424..5de60b634232a7d7fa830dc2895c1493f4a3fc69 100644
--- a/modules/field/modules/text/text.js
+++ b/modules/field/modules/text/text.js
@@ -1,4 +1,4 @@
-// $Id: text.js,v 1.4 2010/06/12 08:18:59 webchick Exp $
+// $Id: text.js,v 1.5 2010/10/24 04:18:10 webchick Exp $
 
 (function ($) {
 
@@ -38,7 +38,7 @@ Drupal.behaviors.textSummary = {
         ).appendTo($summaryLabel);
 
         // If no summary is set, hide the summary field.
-        if ($(this).val() == '') {
+        if ($(this).find('.text-summary').val() == '') {
           $link.click();
         }
         return;
diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module
index d0c5d8da220a016fe5048360998267f5e7792ed2..7d101fdb15e13b67cefc4dff64d54d49a2e70de8 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.66 2010/10/22 00:42:42 dries Exp $
+// $Id: text.module,v 1.68 2010/11/13 07:39:35 webchick Exp $
 
 /**
  * @file
@@ -170,8 +170,8 @@ 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') {
-    return TRUE;
+  if (!isset($item['value']) || $item['value'] === '') {
+    return !isset($item['summary']) || $item['summary'] === '';
   }
   return FALSE;
 }
diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test
index 35df54349114d471ca74a5a9464e5dbbdace4200..a2003eebbc6e93fd27e4c0c9e3a90d16d17a1f10 100644
--- a/modules/field/modules/text/text.test
+++ b/modules/field/modules/text/text.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: text.test,v 1.30 2010/10/20 01:15:58 dries Exp $
+// $Id: text.test,v 1.32 2010/10/25 15:51:21 webchick Exp $
 
 class TextFieldTestCase extends DrupalWebTestCase {
   protected $instance;
@@ -215,8 +215,8 @@ class TextFieldTestCase extends DrupalWebTestCase {
     // Display edition form.
     // We should now have a 'text format' selector.
     $this->drupalGet('test-entity/manage/' . $id . '/edit');
-    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
-    $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));
+    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", NULL, t('Widget is displayed'));
+    $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", NULL, t('Format selector is displayed'));
 
     // Edit and change the text format to the new one that was created.
     $edit = array(
@@ -242,6 +242,11 @@ class TextSummaryTestCase extends DrupalWebTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp();
+    $this->article_creator = $this->drupalCreateUser(array('create article content', 'edit own article content'));
+  }
+
   /**
    * Tests an edge case where the first sentence is a question and
    * subsequent sentences are not. This edge case is documented at
@@ -376,6 +381,24 @@ class TextSummaryTestCase extends DrupalWebTestCase {
     $summary = text_summary($text, $format, $size);
     $this->assertIdentical($summary, $expected, t('Generated summary "@summary" matches expected "@expected".', array('@summary' => $summary, '@expected' => $expected)));
   }
+
+  /**
+   * Test sending only summary.
+   */
+  function testOnlyTextSummary() {
+    // Login as article creator.
+    $this->drupalLogin($this->article_creator);
+    // Create article with summary but empty body.
+    $summary = $this->randomName();
+    $edit = array(
+      "title" => $this->randomName(),
+      "body[und][0][summary]" => $summary,
+    );
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+
+    $this->assertIdentical($node->body['und'][0]['summary'], $summary, t('Article with with summary and no body has been submitted.'));
+  }
 }
 
 class TextTranslationTestCase extends DrupalWebTestCase {
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index 155ee5784b0f807e2772018f423196064c70add9..79c7c9717f095f939c0ce74830b5c8ef6c7bce1c 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: field.test,v 1.42 2010/09/28 02:30:31 dries Exp $
+// $Id: field.test,v 1.47 2010/12/15 04:13:48 webchick Exp $
 
 /**
  * @file
@@ -988,11 +988,12 @@ class FieldInfoTestCase extends FieldTestCase {
    */
   function testFieldInfo() {
     // Test that field_test module's fields, widgets, and formatters show up.
-    $field_test_info = field_test_field_info();
-    $formatter_info = field_test_field_formatter_info();
-    $widget_info = field_test_field_widget_info();
-    $storage_info = field_test_field_storage_info();
 
+    $field_test_info = field_test_field_info();
+    // We need to account for the existence of user_field_info_alter().
+    foreach (array_keys($field_test_info) as $name) {
+      $field_test_info[$name]['instance_settings']['user_register_form'] = FALSE;
+    }
     $info = field_info_field_types();
     foreach ($field_test_info as $t_key => $field_type) {
       foreach ($field_type as $key => $val) {
@@ -1001,6 +1002,7 @@ class FieldInfoTestCase extends FieldTestCase {
       $this->assertEqual($info[$t_key]['module'], 'field_test',  t("Field type field_test module appears"));
     }
 
+    $formatter_info = field_test_field_formatter_info();
     $info = field_info_formatter_types();
     foreach ($formatter_info as $f_key => $formatter) {
       foreach ($formatter as $key => $val) {
@@ -1009,6 +1011,7 @@ class FieldInfoTestCase extends FieldTestCase {
       $this->assertEqual($info[$f_key]['module'], 'field_test',  t("Formatter type field_test module appears"));
     }
 
+    $widget_info = field_test_field_widget_info();
     $info = field_info_widget_types();
     foreach ($widget_info as $w_key => $widget) {
       foreach ($widget as $key => $val) {
@@ -1017,6 +1020,7 @@ class FieldInfoTestCase extends FieldTestCase {
       $this->assertEqual($info[$w_key]['module'], 'field_test',  t("Widget type field_test module appears"));
     }
 
+    $storage_info = field_test_field_storage_info();
     $info = field_info_storage_types();
     foreach ($storage_info as $s_key => $storage) {
       foreach ($storage as $key => $val) {
@@ -1180,6 +1184,10 @@ class FieldInfoTestCase extends FieldTestCase {
    */
   function testSettingsInfo() {
     $info = field_test_field_info();
+    // We need to account for the existence of user_field_info_alter().
+    foreach (array_keys($info) as $name) {
+      $info[$name]['instance_settings']['user_register_form'] = FALSE;
+    }
     foreach ($info as $type => $data) {
       $this->assertIdentical(field_info_field_settings($type), $data['settings'], "field_info_field_settings returns {$type}'s field settings");
       $this->assertIdentical(field_info_instance_settings($type), $data['instance_settings'], "field_info_field_settings returns {$type}'s field instance settings");
@@ -1212,9 +1220,9 @@ class FieldFormTestCase extends FieldTestCase {
     $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
     $this->drupalLogin($web_user);
 
-    $this->field_single = array('field_name' => drupal_strtolower($this->randomName()), 'type' => 'test_field');
-    $this->field_multiple = array('field_name' => drupal_strtolower($this->randomName()), 'type' => 'test_field', 'cardinality' => 4);
-    $this->field_unlimited = array('field_name' => drupal_strtolower($this->randomName()), 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
+    $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field');
+    $this->field_multiple = array('field_name' => 'field_multiple', 'type' => 'test_field', 'cardinality' => 4);
+    $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
 
     $this->instance = array(
       'entity_type' => 'test_entity',
@@ -1355,11 +1363,13 @@ class FieldFormTestCase extends FieldTestCase {
     $delta_range = $count - 1;
     $values = $weights = $pattern = $expected_values = $edit = array();
     for ($delta = 0; $delta <= $delta_range; $delta++) {
-      // Assign unique random weights.
+      // Assign unique random values and weights.
+      do {
+        $value = mt_rand(1, 127);
+      } while (in_array($value, $values));
       do {
         $weight = mt_rand(-$delta_range, $delta_range);
       } while (in_array($weight, $weights));
-      $value = mt_rand(1, 127);
       $edit["$this->field_name[$langcode][$delta][value]"] = $value;
       $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight;
       // We'll need three slightly different formats to check the values.
@@ -1423,11 +1433,13 @@ class FieldFormTestCase extends FieldTestCase {
     $delta_range = $count - 1;
     $values = $weights = $pattern = $expected_values = $edit = array();
     for ($delta = 0; $delta <= $delta_range; $delta++) {
-      // Assign unique random weights.
+      // Assign unique random values and weights.
+      do {
+        $value = mt_rand(1, 127);
+      } while (in_array($value, $values));
       do {
         $weight = mt_rand(-$delta_range, $delta_range);
       } while (in_array($weight, $weights));
-      $value = mt_rand(1, 127);
       $edit["$this->field_name[$langcode][$delta][value]"] = $value;
       $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight;
       // We'll need three slightly different formats to check the values.
@@ -1551,6 +1563,115 @@ class FieldFormTestCase extends FieldTestCase {
     $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('New revision has the expected value for the field with no edit access.'));
     $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, t('New revision has the expected value for the field with edit access.'));
   }
+
+  /**
+   * Tests Field API form integration within a subform.
+   */
+  function testNestedFieldForm() {
+     // Add two instances on the 'test_bundle'
+     field_create_field($this->field_single);
+     field_create_field($this->field_unlimited);
+     $this->instance['field_name'] = 'field_single';
+     $this->instance['label'] = 'Single field';
+     field_create_instance($this->instance);
+     $this->instance['field_name'] = 'field_unlimited';
+     $this->instance['label'] = 'Unlimited field';
+     field_create_instance($this->instance);
+
+     // Create two entities.
+     $entity_1 = field_test_create_stub_entity(1, 1);
+     $entity_1->is_new = TRUE;
+     $entity_1->field_single[LANGUAGE_NONE][] = array('value' => 0);
+     $entity_1->field_unlimited[LANGUAGE_NONE][] = array('value' => 1);
+     field_test_entity_save($entity_1);
+
+     $entity_2 = field_test_create_stub_entity(2, 2);
+     $entity_2->is_new = TRUE;
+     $entity_2->field_single[LANGUAGE_NONE][] = array('value' => 10);
+     $entity_2->field_unlimited[LANGUAGE_NONE][] = array('value' => 11);
+     field_test_entity_save($entity_2);
+
+     // Display the 'combined form'.
+     $this->drupalGet('test-entity/nested/1/2');
+     $this->assertFieldByName('field_single[und][0][value]', 0, t('Entity 1: field_single value appears correctly is the form.'));
+     $this->assertFieldByName('field_unlimited[und][0][value]', 1, t('Entity 1: field_unlimited value 0 appears correctly is the form.'));
+     $this->assertFieldByName('entity_2[field_single][und][0][value]', 10, t('Entity 2: field_single value appears correctly is the form.'));
+     $this->assertFieldByName('entity_2[field_unlimited][und][0][value]', 11, t('Entity 2: field_unlimited value 0 appears correctly is the form.'));
+
+     // Submit the form and check that the entities are updated accordingly.
+     $edit = array(
+       'field_single[und][0][value]' => 1,
+       'field_unlimited[und][0][value]' => 2,
+       'field_unlimited[und][1][value]' => 3,
+       'entity_2[field_single][und][0][value]' => 11,
+       'entity_2[field_unlimited][und][0][value]' => 12,
+       'entity_2[field_unlimited][und][1][value]' => 13,
+     );
+     $this->drupalPost(NULL, $edit, t('Save'));
+     field_cache_clear();
+     $entity_1 = field_test_create_stub_entity(1);
+     $entity_2 = field_test_create_stub_entity(2);
+     $this->assertFieldValues($entity_1, 'field_single', LANGUAGE_NONE, array(1));
+     $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(2, 3));
+     $this->assertFieldValues($entity_2, 'field_single', LANGUAGE_NONE, array(11));
+     $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(12, 13));
+
+     // Submit invalid values and check that errors are reported on the
+     // correct widgets.
+     $edit = array(
+       'field_unlimited[und][1][value]' => -1,
+     );
+     $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
+     $this->assertRaw(t('%label does not accept the value -1', array('%label' => 'Unlimited field')), t('Entity 1: the field validation error was reported.'));
+     $error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', array(':id' => 'edit-field-unlimited-und-1-value'));
+     $this->assertTrue($error_field, t('Entity 1: the error was flagged on the correct element.'));
+     $edit = array(
+       'entity_2[field_unlimited][und][1][value]' => -1,
+     );
+     $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
+     $this->assertRaw(t('%label does not accept the value -1', array('%label' => 'Unlimited field')), t('Entity 2: the field validation error was reported.'));
+     $error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', array(':id' => 'edit-entity-2-field-unlimited-und-1-value'));
+     $this->assertTrue($error_field, t('Entity 2: the error was flagged on the correct element.'));
+
+     // Test that reordering works on both entities.
+     $edit = array(
+       'field_unlimited[und][0][_weight]' => 0,
+       'field_unlimited[und][1][_weight]' => -1,
+       'entity_2[field_unlimited][und][0][_weight]' => 0,
+       'entity_2[field_unlimited][und][1][_weight]' => -1,
+     );
+     $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
+     field_cache_clear();
+     $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(3, 2));
+     $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(13, 12));
+
+     // Test the 'add more' buttons. Only AJAX submission is tested, because
+     // the two 'add more' buttons present in the form have the same #value,
+     // which confuses drupalPost().
+     // 'Add more' button in the first entity:
+     $this->drupalGet('test-entity/nested/1/2');
+     $this->drupalPostAJAX(NULL, array(), 'field_unlimited_add_more');
+     $this->assertFieldByName('field_unlimited[und][0][value]', 3, t('Entity 1: field_unlimited value 0 appears correctly is the form.'));
+     $this->assertFieldByName('field_unlimited[und][1][value]', 2, t('Entity 1: field_unlimited value 1 appears correctly is the form.'));
+     $this->assertFieldByName('field_unlimited[und][2][value]', '', t('Entity 1: field_unlimited value 2 appears correctly is the form.'));
+     $this->assertFieldByName('field_unlimited[und][3][value]', '', t('Entity 1: an empty widget was added for field_unlimited value 3.'));
+     // 'Add more' button in the first entity (changing field values):
+     $edit = array(
+       'entity_2[field_unlimited][und][0][value]' => 13,
+       'entity_2[field_unlimited][und][1][value]' => 14,
+       'entity_2[field_unlimited][und][2][value]' => 15,
+     );
+     $this->drupalPostAJAX(NULL, $edit, 'entity_2_field_unlimited_add_more');
+     $this->assertFieldByName('entity_2[field_unlimited][und][0][value]', 13, t('Entity 2: field_unlimited value 0 appears correctly is the form.'));
+     $this->assertFieldByName('entity_2[field_unlimited][und][1][value]', 14, t('Entity 2: field_unlimited value 1 appears correctly is the form.'));
+     $this->assertFieldByName('entity_2[field_unlimited][und][2][value]', 15, t('Entity 2: field_unlimited value 2 appears correctly is the form.'));
+     $this->assertFieldByName('entity_2[field_unlimited][und][3][value]', '', t('Entity 2: an empty widget was added for field_unlimited value 3.'));
+     // Save the form and check values are saved correclty.
+     $this->drupalPost(NULL, array(), t('Save'));
+     field_cache_clear();
+     $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(3, 2));
+     $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(13, 14, 15));
+  }
 }
 
 class FieldDisplayAPITestCase extends FieldTestCase {
@@ -1626,12 +1747,14 @@ class FieldDisplayAPITestCase extends FieldTestCase {
       'type' => 'field_test_multiple',
       'settings' => array(
         'test_formatter_setting_multiple' => $this->randomName(),
+        'alter' => TRUE,
       ),
     );
     $output = field_view_field('test_entity', $this->entity, $this->field_name, $display);
     $this->drupalSetContent(drupal_render($output));
     $setting = $display['settings']['test_formatter_setting_multiple'];
     $this->assertNoText($this->label, t('Label was not displayed.'));
+    $this->assertText('field_test_field_attach_view_alter', t('Alter fired, display passed.'));
     $array = array();
     foreach ($this->values as $delta => $value) {
       $array[] = $delta . ':' . $value['value'];
@@ -1651,6 +1774,7 @@ class FieldDisplayAPITestCase extends FieldTestCase {
     $this->drupalSetContent($view);
     $setting = $display['settings']['test_formatter_setting_additional'];
     $this->assertNoText($this->label, t('Label was not displayed.'));
+    $this->assertNoText('field_test_field_attach_view_alter', t('Alter not fired.'));
     foreach ($this->values as $delta => $value) {
       $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
@@ -2421,6 +2545,11 @@ class FieldInstanceCrudTestCase extends FieldTestCase {
     // Make sure the other field instance is not deleted.
     $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
     $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), t('A non-deleted field instance is not marked for deletion.'));
+
+    // Make sure the field is deleted when its last instance is deleted.
+    field_delete_instance($another_instance);
+    $field = field_read_field($another_instance['field_name'], array('include_deleted' => TRUE));
+    $this->assertTrue(!empty($field['deleted']), t('A deleted field is marked for deletion after all its instances have been marked for deletion.'));
   }
 }
 
@@ -2957,30 +3086,32 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
   function testPurgeField() {
     $field = reset($this->fields);
 
-    foreach ($this->bundles as $bundle) {
-      // Delete the instance.
-      $instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
-      field_delete_instance($instance);
+    // Delete the first instance.
+    $instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_1');
+    field_delete_instance($instance);
 
-      // Purge the data.
-      field_purge_batch(10);
+    // Purge the data.
+    field_purge_batch(10);
 
-      // Purge again to purge the instance.
-      field_purge_batch(0);
+    // Purge again to purge the instance.
+    field_purge_batch(0);
 
-      // The field still exists, not deleted, because it was never deleted.
-      $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1));
-      $this->assertTrue(isset($fields[$field['id']]), 'The field exists and is not deleted');
-    }
+    // The field still exists, not deleted.
+    $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1));
+    $this->assertTrue(isset($fields[$field['id']]) && !$fields[$field['id']]['deleted'], 'The field exists and is not deleted');
 
-    // Delete the field.
-    field_delete_field($field['field_name']);
+    // Delete the second instance.
+    $instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_2');
+    field_delete_instance($instance);
+
+    // Purge the data.
+    field_purge_batch(10);
 
     // The field still exists, deleted.
-    $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1));
-    $this->assertEqual($fields[$field['id']]['deleted'], 1, 'The field exists and is deleted');
+    $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1));
+    $this->assertTrue(isset($fields[$field['id']]) && $fields[$field['id']]['deleted'], 'The field exists and is deleted');
 
-    // Purge the field.
+    // Purge again to purge the instance and the field.
     field_purge_batch(0);
 
     // The field is gone.
diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc
index 39f2a69b2ec46747761ef501a57237be4f7d6702..37c29e221cd4328f26034eae5d0dd1ed1b9b13fc 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.14 2010/09/24 00:37:42 dries Exp $
+// $Id: field_test.entity.inc,v 1.17 2010/11/20 19:57:01 webchick Exp $
 
 /**
  * @file
@@ -62,13 +62,16 @@ function field_test_entity_info() {
       'bundles' => array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2')),
       'view modes' => $test_entity_modes,
     ),
+    // In this case, the bundle key is not stored in the database.
     'test_entity_bundle' => array(
       'name' => t('Test Entity with a specified bundle.'),
       'base table' => 'test_entity_bundle',
       'fieldable' => TRUE,
+      'controller class' => 'TestEntityBundleController',
       'field cache' => FALSE,
       'entity keys' => array(
         'id' => 'ftid',
+        'bundle' => 'fttype',
       ),
       'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')),
       'view modes' => $test_entity_modes,
@@ -352,7 +355,6 @@ function field_test_entity_form($form, &$form_state, $entity, $add = FALSE) {
   }
 
   // Add field widgets.
-  $form['#builder_function'] = 'field_test_entity_form_submit_builder';
   field_attach_form('test_entity', $entity, $form, $form_state);
 
   if (!$add) {
@@ -384,7 +386,7 @@ function field_test_entity_form_validate($form, &$form_state) {
  * Submit handler for field_test_entity_form().
  */
 function field_test_entity_form_submit($form, &$form_state) {
-  $entity = $form['#builder_function']($form, $form_state);
+  $entity = field_test_entity_form_submit_build_test_entity($form, $form_state);
   $insert = empty($entity->ftid);
   field_test_entity_save($entity);
 
@@ -404,8 +406,90 @@ function field_test_entity_form_submit($form, &$form_state) {
 /**
  * Updates the form state's entity by processing this submission's values.
  */
-function field_test_entity_form_submit_builder($form, &$form_state) {
+function field_test_entity_form_submit_build_test_entity($form, &$form_state) {
   $entity = $form_state['test_entity'];
   entity_form_submit_build_entity('test_entity', $entity, $form, $form_state);
   return $entity;
 }
+
+/**
+ * Form combining two separate entities.
+ */
+function field_test_entity_nested_form($form, &$form_state, $entity_1, $entity_2) {
+  // First entity.
+  foreach (array('ftid', 'ftvid', 'fttype') as $key) {
+    $form[$key] = array(
+      '#type' => 'value',
+      '#value' => $entity_1->$key,
+    );
+  }
+  field_attach_form('test_entity', $entity_1, $form, $form_state);
+
+  // Second entity.
+  $form['entity_2'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Second entity'),
+    '#tree' => TRUE,
+    '#parents' => array('entity_2'),
+    '#weight' => 50,
+  );
+  foreach (array('ftid', 'ftvid', 'fttype') as $key) {
+    $form['entity_2'][$key] = array(
+      '#type' => 'value',
+      '#value' => $entity_2->$key,
+    );
+  }
+  field_attach_form('test_entity', $entity_2, $form['entity_2'], $form_state);
+
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 100,
+  );
+
+  return $form;
+}
+
+/**
+ * Validate handler for field_test_entity_nested_form().
+ */
+function field_test_entity_nested_form_validate($form, &$form_state) {
+  $entity_1 = (object) $form_state['values'];
+  field_attach_form_validate('test_entity', $entity_1, $form, $form_state);
+
+  $entity_2 = (object) $form_state['values']['entity_2'];
+  field_attach_form_validate('test_entity', $entity_2, $form['entity_2'], $form_state);
+}
+
+/**
+ * Submit handler for field_test_entity_nested_form().
+ */
+function field_test_entity_nested_form_submit($form, &$form_state) {
+  $entity_1 = (object) $form_state['values'];
+  field_attach_submit('test_entity', $entity_1, $form, $form_state);
+  field_test_entity_save($entity_1);
+
+  $entity_2 = (object) $form_state['values']['entity_2'];
+  field_attach_submit('test_entity', $entity_2, $form['entity_2'], $form_state);
+  field_test_entity_save($entity_2);
+
+  drupal_set_message(t('test_entities @id_1 and @id_2 have been updated.', array('@id_1' => $entity_1->ftid, '@id_2' => $entity_2->ftid)));
+}
+
+/**
+ * Controller class for the test_entity_bundle entity type.
+ *
+ * This extends the DrupalDefaultEntityController class, adding required
+ * special handling for bundles (since they are not stored in the database).
+ */
+class TestEntityBundleController extends DrupalDefaultEntityController {
+
+  protected function attachLoad(&$entities, $revision_id = FALSE) {
+    // Add bundle information.
+    foreach ($entities as $key => $entity) {
+      $entity->fttype = 'test_entity_bundle';
+      $entities[$key] = $entity;
+    }
+    parent::attachLoad($entities, $revision_id);
+  }
+}
diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info
index 21adeb274178fe7e667504a79d92127ab51e7df7..6de86895fd51fb4f0112f5db0792538dc851c5f0 100644
--- a/modules/field/tests/field_test.info
+++ b/modules/field/tests/field_test.info
@@ -1,18 +1,14 @@
-;$Id: field_test.info,v 1.1 2009/11/20 23:29:28 webchick Exp $
+;$Id: field_test.info,v 1.2 2010/12/20 19:59:41 webchick Exp $
 name = "Field API Test"
 description = "Support module for the Field API tests."
 core = 7.x
 package = Testing
-files[] = field_test.module
 files[] = field_test.entity.inc
-files[] = field_test.field.inc
-files[] = field_test.storage.inc
-files[] = field_test.install
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module
index baaef3f38b26799f82dca19a22322e66064c44dc..525c028642de0c274e7f5a9df1acb6035c843874 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.12 2010/09/26 23:31:35 dries Exp $
+// $Id: field_test.module,v 1.14 2010/12/07 05:09:58 webchick Exp $
 
 /**
  * @file
@@ -60,6 +60,14 @@ function field_test_menu() {
     'type' => MENU_NORMAL_ITEM,
   );
 
+  $items['test-entity/nested/%field_test_entity_test/%field_test_entity_test'] = array(
+    'title' => 'Nested entity form',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('field_test_entity_nested_form', 2, 3),
+    'access arguments' => array('administer field_test content'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+
   return $items;
 }
 
@@ -227,3 +235,12 @@ function field_test_dummy_field_storage_query(EntityFieldQuery $query) {
 function field_test_entity_label_callback($entity) {
   return 'label callback ' . $entity->ftlabel;
 }
+
+/**
+ * Implements hook_field_attach_view_alter().
+ */
+function field_test_field_attach_view_alter(&$output, $context) {
+  if (!empty($context['display']['settings']['alter'])) {
+    $output['test_field'][] = array('#markup' => 'field_test_field_attach_view_alter');
+  }
+}
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index 25fe69285df6018ad065336e6c6137053369efe6..824709129eddcf5d49d1663f0cbd15c9c14c3d38 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.79 2010/10/23 01:34:02 webchick Exp $
+// $Id: field_ui.admin.inc,v 1.88 2010/12/15 04:13:48 webchick Exp $
 
 /**
  * @file
@@ -21,8 +21,8 @@ function field_ui_fields_list() {
         $field = field_info_field($field_name);
         $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
         $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
-        $rows[$field_name]['data'][1] = t($field_types[$field['type']]['label']);
-        $rows[$field_name]['data'][2][] = l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields');
+        $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'];
+        $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
         $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
       }
     }
@@ -54,7 +54,7 @@ function field_ui_inactive_message($entity_type, $bundle) {
       $list[] = t('%field (@field_name) field requires the %widget_type widget provided by %widget_module module', array(
       '%field' => $instance['label'],
       '@field_name' => $instance['field_name'],
-      '%widget_type' => array_key_exists($instance['widget']['type'], $widget_types) ? $widget_types[$instance['widget']['type']]['label'] : $instance['widget']['type'],
+      '%widget_type' => isset($widget_types[$instance['widget']['type']]) ? $widget_types[$instance['widget']['type']]['label'] : $instance['widget']['type'],
       '%widget_module' => $instance['widget']['module'],
       ));
     }
@@ -158,15 +158,14 @@ function field_ui_table_pre_render($elements) {
         // Add row id and associate JS settings.
         $id = drupal_html_class($name);
         $row['#attributes']['id'] = $id;
-        $row += array(
-          '#js_settings' => array(),
-        );
-        $row['#js_settings'] += array(
-          'rowHandler' => $row['#row_type'],
-          'name' => $name,
-          'region' => $region_name,
-        );
-        $js_settings[$id] = $row['#js_settings'];
+        if (isset($row['#js_settings'])) {
+          $row['#js_settings'] += array(
+            'rowHandler' => $row['#row_type'],
+            'name' => $name,
+            'region' => $region_name,
+          );
+          $js_settings[$id] = $row['#js_settings'];
+        }
       }
     }
   }
@@ -304,7 +303,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
     ),
     '#parent_options' => array(),
     '#regions' => array(
-      'main' => array(),
+      'main' => array('message' => t('No fields are present yet.')),
       'add_new' => array('title' => '&nbsp;'),
     ),
     '#attributes' => array(
@@ -852,7 +851,7 @@ function field_ui_display_overview_form($form, &$form_state, $entity_type, $bund
     '#extra' => array_keys($extra_fields),
   );
 
-  if (empty($instances)) {
+  if (empty($instances) && empty($extra_fields)) {
     drupal_set_message(t('There are no fields yet added. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => url($admin_path . '/fields'))), 'warning');
     return $form;
   }
@@ -1267,19 +1266,23 @@ function field_ui_display_overview_form_submit($form, &$form_state) {
 
   // Save data for 'regular' fields.
   foreach ($form['#fields'] as $field_name) {
-    $instance = field_info_instance($entity_type, $field_name, $bundle);
+    // Retrieve the stored instance settings to merge with the incoming values.
+    $instance = field_read_instance($entity_type, $field_name, $bundle);
     $values = $form_values['fields'][$field_name];
     // Get formatter settings. They lie either directly in submitted form
     // values (if the whole form was submitted while some formatter
     // settings were being edited), or have been persisted in
     // $form_state.
-    $settings = $instance['display'][$view_mode]['settings'];
+    $settings = array();
     if (isset($values['settings_edit_form']['settings'])) {
       $settings = $values['settings_edit_form']['settings'];
     }
     elseif (isset($form_state['formatter_settings'][$field_name])) {
       $settings = $form_state['formatter_settings'][$field_name];
     }
+    elseif (isset($instance['display'][$view_mode]['settings'])) {
+      $settings = $instance['display'][$view_mode]['settings'];
+    }
 
     // Only save settings actually used by the selected formatter.
     $default_settings = field_info_formatter_settings($values['type']);
@@ -1311,10 +1314,14 @@ function field_ui_display_overview_form_submit($form, &$form_state) {
     foreach ($form_values['view_modes_custom'] as $view_mode_name => $value) {
       // Display a message for each view mode newly configured to use custom
       // settings.
-      if (!empty($value) && empty($bundle_settings['view_modes'][$view_mode_name]['custom_settings'])) {
+      $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
+      if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) {
         $view_mode_label = $entity_info['view modes'][$view_mode_name]['label'];
         $path = _field_ui_bundle_admin_path($entity_type, $bundle) . "/display/$view_mode_name";
         drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to <a href="@url">configure them</a>.', array('%view_mode' => $view_mode_label, '@url' => url($path))));
+        // Initialize the newly customized view mode with the display settings
+        // from the default view mode.
+        _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode_name, $bundle_settings);
       }
       $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value);
     }
@@ -1326,6 +1333,50 @@ function field_ui_display_overview_form_submit($form, &$form_state) {
   drupal_set_message(t('Your settings have been saved.'));
 }
 
+/**
+ * Helper function for field_ui_display_overview_form_submit().
+ *
+ * When an administrator decides to use custom display settings for a view mode,
+ * that view mode needs to be initialized with the display settings for the
+ * 'default' view mode, which it was previously using. This helper function
+ * adds the new custom display settings to this bundle's instances, and saves
+ * them. It also modifies the passed-in $settings array, which the caller can
+ * then save using field_bundle_settings().
+ *
+ * @see field_bundle_settings()
+ *
+ * @param $entity_type
+ *   The bundle's entity type.
+ * @param $bundle
+ *   The bundle whose view mode is being customized.
+ * @param $view_mode
+ *   The view mode that the administrator has set to use custom settings.
+ * @param $settings
+ *   An associative array of bundle settings, as expected by
+ *   field_bundle_settings().
+ */
+function _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode, &$settings) {
+  // Update display settings for field instances.
+  $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle));
+  foreach ($instances as $instance) {
+    // If this field instance has display settings defined for this view mode,
+    // respect those settings.
+    if (!isset($instance['display'][$view_mode])) {
+      // The instance doesn't specify anything for this view mode, so use the
+      // default display settings.
+      $instance['display'][$view_mode] = $instance['display']['default'];
+      field_update_instance($instance);
+    }
+  }
+
+  // Update display settings for 'extra fields'.
+  foreach (array_keys($settings['extra_fields']['display']) as $name) {
+    if (!isset($settings['extra_fields']['display'][$name][$view_mode])) {
+      $settings['extra_fields']['display'][$name][$view_mode] = $settings['extra_fields']['display'][$name]['default'];
+    }
+  }
+}
+
 /**
  * Return an array of field_type options.
  */
@@ -1537,17 +1588,24 @@ function field_ui_field_settings_form_submit($form, &$form_state) {
  * Menu callback; select a widget for the field.
  */
 function field_ui_widget_type_form($form, &$form_state, $instance) {
+  drupal_set_title($instance['label']);
+
   $bundle = $instance['bundle'];
   $entity_type = $instance['entity_type'];
-  $field = field_info_field($instance['field_name']);
-
-  drupal_set_title($instance['label']);
+  $field_name = $instance['field_name'];
 
+  $field = field_info_field($field_name);
   $field_type = field_info_field_types($field['type']);
   $widget_type = field_info_widget_types($instance['widget']['type']);
   $bundles = field_info_bundles();
   $bundle_label = $bundles[$entity_type][$bundle]['label'];
 
+  $form = array(
+    '#bundle' => $bundle,
+    '#entity_type' => $entity_type,
+    '#field_name' => $field_name,
+  );
+
   $form['basic'] = array(
     '#type' => 'fieldset',
     '#title' => t('Change widget'),
@@ -1561,7 +1619,6 @@ function field_ui_widget_type_form($form, &$form_state, $instance) {
     '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)),
   );
 
-  $form['#instance'] = $instance;
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Continue'));
 
@@ -1576,9 +1633,12 @@ function field_ui_widget_type_form($form, &$form_state, $instance) {
  */
 function field_ui_widget_type_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
-  $instance = $form['#instance'];
-  $bundle = $instance['bundle'];
-  $entity_type = $instance['entity_type'];
+  $bundle = $form['#bundle'];
+  $entity_type = $form['#entity_type'];
+  $field_name = $form['#field_name'];
+
+  // Retrieve the stored instance settings to merge with the incoming values.
+  $instance = field_read_instance($entity_type, $field_name, $bundle);
 
   // Set the right module information.
   $widget_type = field_info_widget_types($form_values['widget_type']);
@@ -1586,6 +1646,7 @@ function field_ui_widget_type_form_submit($form, &$form_state) {
 
   $instance['widget']['type'] = $form_values['widget_type'];
   $instance['widget']['module'] = $widget_module;
+
   try {
     field_update_instance($instance);
     drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance['label'])));
@@ -1645,10 +1706,6 @@ function field_ui_field_delete_form_submit($form, &$form_state) {
 
   if (!empty($bundle) && $field && !$field['locked'] && $form_values['confirm']) {
     field_delete_instance($instance);
-    // Delete the field if that was the last instance.
-    if (count($field['bundles']) == 1 && count(current($field['bundles'])) == 1) {
-      field_delete_field($field['field_name']);
-    }
     drupal_set_message(t('The field %field has been deleted from the %type content type.', array('%field' => $instance['label'], '%type' => $bundle_label)));
   }
   else {
@@ -1670,6 +1727,7 @@ function field_ui_field_edit_form($form, &$form_state, $instance) {
   drupal_set_title($instance['label']);
 
   $form['#field'] = $field;
+  $form['#instance'] = $instance;
 
   if (!empty($field['locked'])) {
     $form['locked'] = array(
@@ -1683,13 +1741,7 @@ function field_ui_field_edit_form($form, &$form_state, $instance) {
   $bundles = field_info_bundles();
 
   // Create a form structure for the instance values.
-  // @todo Fieldset element info needs to be merged in order to not skip the
-  //   default element definition for #pre_render. While the current default
-  //   value could simply be hard-coded, we'd possibly forget this location
-  //   when system_element_info() is updated. See also form_builder(). This
-  //   particular #pre_render, field_ui_field_edit_instance_pre_render(), might
-  //   as well be entirely needless though.
-  $form['instance'] = array_merge(element_info('fieldset'), array(
+  $form['instance'] = array(
     '#tree' => TRUE,
     '#type' => 'fieldset',
     '#title' => t('%type settings', array('%type' => $bundles[$entity_type][$bundle]['label'])),
@@ -1697,8 +1749,10 @@ function field_ui_field_edit_form($form, &$form_state, $instance) {
       '%field' => $instance['label'],
       '%type' => $bundles[$entity_type][$bundle]['label'],
     )),
-    '#pre_render' => array('field_ui_field_edit_instance_pre_render'),
-  ));
+    // Ensure field_ui_field_edit_instance_pre_render() gets called in addition
+    // to, not instead of, the #pre_render function(s) needed by all fieldsets.
+    '#pre_render' => array_merge(array('field_ui_field_edit_instance_pre_render'), element_info_property('fieldset', '#pre_render', array())),
+  );
 
   // Build the non-configurable instance values.
   $form['instance']['field_name'] = array(
@@ -1855,7 +1909,9 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
     '#collapsible' => FALSE,
     '#tree' => TRUE,
     '#description' => t('The default value for this field, used when creating new content.'),
-    // Make sure the values appear at the top-level of $form_state['values'].
+    // Stick to an empty 'parents' on this form in order not to breaks widgets
+    // that do not use field_widget_[field|instance]() and still access
+    // $form_state['field'] directly.
     '#parents' => array(),
   );
 
@@ -1863,8 +1919,9 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
   $items = $instance['default_value'];
   $instance['required'] = FALSE;
   $instance['description'] = '';
+
   // @todo Allow multiple values (requires more work on 'add more' JS handler).
-  $element += field_default_form(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state, 0);
+  $element += field_default_form(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state, 0);
 
   return $element;
 }
@@ -1873,22 +1930,34 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
  * Form validation handler for field instance settings form.
  */
 function field_ui_field_edit_form_validate($form, &$form_state) {
+  // Take the incoming values as the $instance definition, so that the 'default
+  // value' gets validated using the instance settings being submitted.
   $instance = $form_state['values']['instance'];
   $field_name = $instance['field_name'];
-  $field = field_info_field($field_name);
 
-  // Extract the 'default value'.
-  $items = array();
-  field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state);
-  // Validate the value and report errors.
-  $errors = array();
-  $function = $field['module'] . '_field_validate';
-  if (function_exists($function)) {
-    $function(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $errors);
-  }
-  if (isset($errors[$field_name][LANGUAGE_NONE])) {
-    $form_state['field'][$field_name][LANGUAGE_NONE]['errors'] = $errors[$field_name][LANGUAGE_NONE];
-    field_default_form_errors(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state);
+  if (isset($form['instance']['default_value_widget'])) {
+    $element = $form['instance']['default_value_widget'];
+
+    $field_state = field_form_get_state($element['#parents'], $field_name, LANGUAGE_NONE, $form_state);
+    $field = $field_state['field'];
+
+    // Extract the 'default value'.
+    $items = array();
+    field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+
+    // Validate the value and report errors.
+    $errors = array();
+    $function = $field['module'] . '_field_validate';
+    if (function_exists($function)) {
+      $function(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $errors);
+    }
+    if (isset($errors[$field_name][LANGUAGE_NONE])) {
+      // Store reported errors in $form_state.
+      $field_state['errors'] = $errors[$field_name][LANGUAGE_NONE];
+      field_form_set_state($element['#parents'], $field_name, LANGUAGE_NONE, $form_state, $field_state);
+      // Assign reported errors to the correct form element.
+      field_default_form_errors(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+    }
   }
 }
 
@@ -1905,15 +1974,19 @@ function field_ui_field_edit_form_submit($form, &$form_state) {
   field_update_field($field);
 
   // Handle the default value.
-  // Extract field values.
-  $items = array();
-  field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state);
-  // Prepare field values.
-  field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $form, $form_state);
-  $instance['default_value'] = $items ? $items : NULL;
-
-  // Update the instance settings.
-  $instance_source = field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
+  if (isset($form['instance']['default_value_widget'])) {
+    $element = $form['instance']['default_value_widget'];
+
+    // Extract field values.
+    $items = array();
+    field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+    field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+
+    $instance['default_value'] = $items ? $items : NULL;
+  }
+
+  // Retrieve the stored instance settings to merge with the incoming values.
+  $instance_source = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
   $instance = array_merge($instance_source, $instance);
   field_update_instance($instance);
 
diff --git a/modules/field_ui/field_ui.api.php b/modules/field_ui/field_ui.api.php
index c8e09918a7196d7ccccb9788f0d1960e5f2d1a73..0eff874a882aff6b08d00508aa6ec7e597932c55 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.8 2010/07/17 19:19:39 dries Exp $
+// $Id: field_ui.api.php,v 1.10 2010/11/12 03:10:38 dries Exp $
 
 /**
  * @file
@@ -173,6 +173,10 @@ function hook_field_formatter_settings_form($field, $instance, $view_mode, $form
 /**
  * Returns a short summary for the current formatter settings of an instance.
  *
+ * If an empty result is returned, the formatter is assumed to have no
+ * configurable settings, and no UI will be provided to display a settings
+ * form.
+ *
  * @param $field
  *   The field structure.
  * @param $instance
diff --git a/modules/field_ui/field_ui.css b/modules/field_ui/field_ui.css
index 3a61509d912ee9b5e397eb02660f462cc99cb28a..f9bc281658914afe04ca535894cc58759f5c54a2 100644
--- a/modules/field_ui/field_ui.css
+++ b/modules/field_ui/field_ui.css
@@ -1,4 +1,4 @@
-/* $Id: field_ui.css,v 1.5 2010/09/11 00:03:42 webchick Exp $ */
+/* $Id: field_ui.css,v 1.6 2010/11/20 09:06:32 webchick Exp $ */
 
 /* 'Manage fields' and 'Manage display' overviews */
 table.field-ui-overview tr.add-new .label-input {
@@ -14,20 +14,20 @@ table.field-ui-overview tr.add-new .add-new-placeholder {
   font-weight: bold;
   padding-bottom: .5em;
 }
-table.field-ui-overview tr.region-add-new-title {
-  display: none;
-}
-
-/* 'Manage display' overview */
-#field-display-overview tr.region-title td {
+table.field-ui-overview tr.region-title td {
   font-weight: bold;
 }
-#field-display-overview tr.region-message td {
+table.field-ui-overview tr.region-message td {
   font-style: italic;
 }
-#field-display-overview tr.region-populated {
+table.field-ui-overview tr.region-populated {
   display: none;
 }
+table.field-ui-overview tr.region-add-new-title {
+  display: none;
+}
+
+/* 'Manage display' overview */
 #field-display-overview .field-formatter-summary-cell {
   line-height: 1em;
 }
diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info
index e054fe8bb9e6c4aaf48ace350badbc7953bd53b6..324dce84b7abdba480469bdeeaf8360f99dffdab 100644
--- a/modules/field_ui/field_ui.info
+++ b/modules/field_ui/field_ui.info
@@ -1,16 +1,14 @@
-; $Id: field_ui.info,v 1.4 2010/08/16 20:57:23 dries Exp $
+; $Id: field_ui.info,v 1.5 2010/12/20 19:59:41 webchick Exp $
 name = Field UI
 description = User interface for the Field API.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = field_ui.module
-files[] = field_ui.admin.inc
 files[] = field_ui.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/field_ui/field_ui.js b/modules/field_ui/field_ui.js
index 2aa77310070ef286c3181a18fe6ae9e9cdbe7c26..cae909f4a5eda32022defabe5fa551e5fc1c5c3b 100644
--- a/modules/field_ui/field_ui.js
+++ b/modules/field_ui/field_ui.js
@@ -1,4 +1,4 @@
-// $Id: field_ui.js,v 1.6 2010/10/06 13:09:11 dries Exp $
+// $Id: field_ui.js,v 1.8 2010/11/21 08:50:49 webchick Exp $
 
 (function($) {
 
@@ -60,7 +60,7 @@ Drupal.fieldUIFieldOverview = {
       // and label when field type comes pre-selected (on failed validation).
       $(this).trigger('change', false);
     });
-  },
+  }
 };
 
 /**
@@ -114,12 +114,14 @@ Drupal.fieldUIOverview = {
     $('tr.draggable', table).each(function () {
       // Extract server-side data for the row.
       var row = this;
-      var data = rowsData[row.id];
-      data.tableDrag = tableDrag;
+      if (row.id in rowsData) {
+        var data = rowsData[row.id];
+        data.tableDrag = tableDrag;
 
-      // Create the row handler, make it accessible from the DOM row element.
-      var rowHandler = eval('new rowHandlers.' + data.rowHandler + '(row, data);');
-      $(row).data('fieldUIRowHandler', rowHandler);
+        // Create the row handler, make it accessible from the DOM row element.
+        var rowHandler = eval('new rowHandlers.' + data.rowHandler + '(row, data);');
+        $(row).data('fieldUIRowHandler', rowHandler);
+      }
     });
   },
 
@@ -156,17 +158,18 @@ Drupal.fieldUIOverview = {
     var dragObject = this;
     var row = dragObject.rowObject.element;
     var rowHandler = $(row).data('fieldUIRowHandler');
-
-    var regionRow = $(row).prevAll('tr.region-message').get(0);
-    var region = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
-
-    if (region != rowHandler.region) {
-      // Let the row handler deal with the region change.
-      refreshRows = rowHandler.regionChange(region);
-      // Update the row region.
-      rowHandler.region = region;
-      // AJAX-update the rows.
-      Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
+    if (rowHandler !== undefined) {
+      var regionRow = $(row).prevAll('tr.region-message').get(0);
+      var region = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+
+      if (region != rowHandler.region) {
+        // Let the row handler deal with the region change.
+        refreshRows = rowHandler.regionChange(region);
+        // Update the row region.
+        rowHandler.region = region;
+        // AJAX-update the rows.
+        Drupal.fieldUIOverview.AJAXRefreshRows(refreshRows);
+      }
     }
   },
 
@@ -239,7 +242,7 @@ Drupal.fieldUIOverview = {
       // elements disabled only after firing the request.
       $(ajaxElements).attr('disabled', true);
     }
-  },
+  }
 };
 
 
@@ -322,7 +325,7 @@ Drupal.fieldUIDisplayOverview.field.prototype = {
     refreshRows[this.name] = this.$formatSelect.get(0);
 
     return refreshRows;
-  },
+  }
 };
 
 })(jQuery);
diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module
index 21ce45033c7122485c699ce4937cca0c679588c9..9af3327adca04cde7393d2084c4b684902a07591 100644
--- a/modules/field_ui/field_ui.module
+++ b/modules/field_ui/field_ui.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: field_ui.module,v 1.33 2010/09/24 00:37:42 dries Exp $
+// $Id: field_ui.module,v 1.34 2010/11/21 07:28:39 webchick Exp $
 
 /**
  * @file
@@ -308,7 +308,9 @@ function field_ui_field_attach_create_bundle($entity_type, $bundle) {
 function _field_ui_bundle_admin_path($entity_type, $bundle_name) {
   $bundles = field_info_bundles($entity_type);
   $bundle_info = $bundles[$bundle_name];
-  return isset($bundle_info['admin']['real path']) ? $bundle_info['admin']['real path'] : $bundle_info['admin']['path'];
+  if (isset($bundle_info['admin'])) {
+    return isset($bundle_info['admin']['real path']) ? $bundle_info['admin']['real path'] : $bundle_info['admin']['path'];
+  }
 }
 
 /**
diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test
index 710a13b27548f20acdaedd9426943ab619b33afb..1f1b43f8b8b8a3e37f9b0004046b205156bef739 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.25 2010/10/23 01:34:02 webchick Exp $
+// $Id: field_ui.test,v 1.27 2010/10/27 18:29:17 dries Exp $
 
 /**
  * @file
@@ -470,4 +470,154 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase {
     $this->assertEqual($current_format, $format, t('The formatter was updated.'));
     $this->assertEqual($current_setting_value, $setting_value, t('The setting was updated.'));
   }
+
+  /**
+   * Test switching view modes to use custom or 'default' settings'.
+   */
+  function testViewModeCustom() {
+    // Create a field, and a node with some data for the field.
+    $edit = array(
+      'fields[_add_new_field][label]' => 'Test field',
+      'fields[_add_new_field][field_name]' => 'field_test',
+    );
+    $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit);
+    // For this test, use a formatter setting value that is an integer unlikely
+    // to appear in a rendered node other than as part of the field being tested
+    // (for example, unlikely to be part of the "Submitted by ... on ..." line).
+    $value = 12345;
+    $settings = array(
+      'type' => $this->type,
+      'field_test' => array(LANGUAGE_NONE => array(array('value' => $value))),
+    );
+    $node = $this->drupalCreateNode($settings);
+
+    // Gather expected output values with the various formatters.
+    $formatters = field_info_formatter_types();
+    $output = array(
+      'field_test_default' => $formatters['field_test_default']['settings']['test_formatter_setting'] . '|' . $value,
+      'field_test_with_prepare_view' => $formatters['field_test_with_prepare_view']['settings']['test_formatter_setting_additional'] . '|' . $value. '|' . ($value + 1),
+    );
+
+    // Check that the field is displayed with the default formatter in 'rss'
+    // mode (uses 'default'), and hidden in 'teaser' mode (uses custom settings).
+    $this->assertNodeViewText($node, 'rss', $output['field_test_default'], t("The field is displayed as expected in view modes that use 'default' settings."));
+    $this->assertNodeViewNoText($node, 'teaser', $value, t("The field is hidden in view modes that use custom settings."));
+
+    // Change fomatter for 'default' mode, check that the field is displayed
+    // accordingly in 'rss' mode.
+    $edit = array(
+      'fields[field_test][type]' => 'field_test_with_prepare_view',
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
+    $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected in view modes that use 'default' settings."));
+
+    // Specialize the 'rss' mode, check that the field is displayed the same.
+    $edit = array(
+      "view_modes_custom[rss]" => TRUE,
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
+    $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected in newly specialized 'rss' mode."));
+
+    // Set the field to 'hidden' in the view mode, check that the field is
+    // hidden.
+    $edit = array(
+      'fields[field_test][type]' => 'hidden',
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display/rss', $edit, t('Save'));
+    $this->assertNodeViewNoText($node, 'rss', $value, t("The field is hidden in 'rss' mode."));
+
+    // Set the view mode back to 'default', check that the field is displayed
+    // accordingly.
+    $edit = array(
+      "view_modes_custom[rss]" => FALSE,
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
+    $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected when 'rss' mode is set back to 'default' settings."));
+
+    // Specialize the view mode again.
+    $edit = array(
+      "view_modes_custom[rss]" => TRUE,
+    );
+    $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save'));
+    // Check that the previous settings for the view mode have been kept.
+    $this->assertNodeViewNoText($node, 'rss', $value, t("The previous settings are kept when 'rss' mode is specialized again."));
+  }
+
+  /**
+   * Pass if the text is found in the rendered node in a given view mode.
+   *
+   * @param $node
+   *   The node.
+   * @param $view_mode
+   *   The view mode in which the node should be displayed.
+   * @param $text
+   *   Plain text to look for.
+   * @param $message
+   *   Message to display.
+   *
+   * @return
+   *   TRUE on pass, FALSE on fail.
+   */
+  function assertNodeViewText($node, $view_mode, $text, $message) {
+    return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, FALSE);
+  }
+
+  /**
+   * Pass if the text is node found in the rendered node in a given view mode.
+   *
+   * @param $node
+   *   The node.
+   * @param $view_mode
+   *   The view mode in which the node should be displayed.
+   * @param $text
+   *   Plain text to look for.
+   * @param $message
+   *   Message to display.
+   * @return
+   *   TRUE on pass, FALSE on fail.
+   */
+  function assertNodeViewNoText($node, $view_mode, $text, $message) {
+    return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, TRUE);
+  }
+
+  /**
+   * Helper for assertNodeViewText and assertNodeViewNoText.
+   *
+   * @param $node
+   *   The node.
+   * @param $view_mode
+   *   The view mode in which the node should be displayed.
+   * @param $text
+   *   Plain text to look for.
+   * @param $message
+   *   Message to display.
+   * @param $not_exists
+   *   TRUE if this text should not exist, FALSE if it should.
+   *
+   * @return
+   *   TRUE on pass, FALSE on fail.
+   */
+  function assertNodeViewTextHelper($node, $view_mode, $text, $message, $not_exists) {
+    // Make sure caches on the tester side are refreshed after changes
+    // submitted on the tested side.
+    field_info_cache_clear();
+
+    // Save current content so that we can restore it when we're done.
+    $old_content = $this->drupalGetContent();
+
+    // Render a cloned node, so that we do not alter the original.
+    $clone = clone $node;
+    $output = drupal_render(node_view($clone, $view_mode));
+    $this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '<hr />'. $output);
+
+    // Assign content so that DrupalWebTestCase functions can be used.
+    $this->drupalSetContent($output);
+    $method = ($not_exists ? 'assertNoText' : 'assertText');
+    $return = $this->{$method}((string) $text, $message);
+
+    // Restore previous content.
+    $this->drupalSetContent($old_content);
+
+    return $return;
+  }
 }
diff --git a/modules/file/file.field.inc b/modules/file/file.field.inc
index 3f2350fe4dad49349478c1748acd26b11bbb1ce3..e58f0877fe4969807b771b266b99b39c7901cb06 100644
--- a/modules/file/file.field.inc
+++ b/modules/file/file.field.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.field.inc,v 1.37 2010/10/20 15:22:53 dries Exp $
+// $Id: file.field.inc,v 1.42 2010/12/24 15:25:28 webchick Exp $
 
 /**
  * @file
@@ -79,7 +79,7 @@ function file_field_instance_settings_form($field, $instance) {
     '#type' => 'textfield',
     '#title' => t('File directory'),
     '#default_value' => $settings['file_directory'],
-    '#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.', array('%directory' => variable_get('file_directory_path', 'files') . '/')),
+    '#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.'),
     '#element_validate' => array('_file_generic_settings_file_directory_validate'),
     '#weight' => 3,
   );
@@ -450,9 +450,14 @@ function file_field_widget_form(&$form, &$form_state, $field, $instance, $langco
 
   // Retrieve any values set in $form_state, as will be the case during AJAX
   // rebuilds of this form.
-  if (isset($form_state['values'][$field['field_name']][$langcode])) {
-    $items = $form_state['values'][$field['field_name']][$langcode];
-    unset($form_state['values'][$field['field_name']][$langcode]);
+  if (isset($form_state['values'])) {
+    $path = array_merge($element['#field_parents'], array($field['field_name'], $langcode));
+    $path_exists = FALSE;
+    $values = drupal_array_get_nested_value($form_state['values'], $path, $path_exists);
+    if ($path_exists) {
+      $items = $values;
+      drupal_array_set_nested_value($form_state['values'], $path, NULL);
+    }
   }
 
   foreach ($items as $delta => $item) {
@@ -583,7 +588,7 @@ function file_field_widget_value($element, $input = FALSE, $form_state) {
   if ($input) {
     // Checkboxes lose their value when empty.
     // If the display field is present make sure its unchecked value is saved.
-    $field = $form_state['field'][$element['#field_name']][$element['#language']]['field'];
+    $field = field_widget_field($element, $form_state);
     if (empty($input['display'])) {
       $input['display'] = $field['settings']['display_field'] ? 0 : 1;
     }
@@ -611,8 +616,8 @@ function file_field_widget_process($element, &$form_state, $form) {
   $item = $element['#value'];
   $item['fid'] = $element['fid']['#value'];
 
-  $field = $form_state['field'][$element['#field_name']][$element['#language']]['field'];
-  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
   $settings = $instance['widget']['settings'];
 
   $element['#theme'] = 'file_widget';
@@ -648,8 +653,9 @@ function file_field_widget_process($element, &$form_state, $form) {
   // Adjust the AJAX settings so that on upload and remove of any individual
   // file, the entire group of file fields is updated together.
   if ($field['cardinality'] != 1) {
-    $new_path = preg_replace('/\/\d+\//', '/', $element['remove_button']['#ajax']['path'], 1);
-    $field_element = drupal_array_get_nested_value($form, array_slice($element['#array_parents'], 0, -1));
+    $parents = array_slice($element['#array_parents'], 0, -1);
+    $new_path = 'file/ajax/' . implode('/', $parents) . '/' . $form['form_build_id']['#value'];
+    $field_element = drupal_array_get_nested_value($form, $parents);
     $new_wrapper = $field_element['#id'] . '-ajax-wrapper';
     foreach (element_children($element) as $key) {
       if (isset($element[$key]['#ajax'])) {
@@ -747,8 +753,8 @@ function file_field_widget_submit($form, &$form_state) {
   // to avoid a mismatch between old and new deltas. The rebuilt elements will
   // have #default_value set appropriately for the current state of the field,
   // so nothing is lost in doing this.
-  list($field_name, $langcode) = $form_state['triggering_element']['#parents'];
-  unset($form_state['input'][$field_name][$langcode]);
+  $parents = array_slice($form_state['triggering_element']['#parents'], 0, -2);
+  drupal_array_set_nested_value($form_state['input'], $parents, NULL);
 }
 
 /**
@@ -788,13 +794,6 @@ function theme_file_widget($variables) {
 function theme_file_widget_multiple($variables) {
   $element = $variables['element'];
 
-  // Get our list of widgets in order.
-  $widgets = array();
-  foreach (element_children($element) as $key) {
-    $widgets[$key] = $element[$key];
-  }
-  usort($widgets, '_field_sort_items_value_helper');
-
   // Special ID and classes for draggable tables.
   $weight_class = $element['#id'] . '-weight';
   $table_id = $element['#id'] . '-table';
@@ -811,35 +810,43 @@ function theme_file_widget_multiple($variables) {
   $headers[] = t('Weight');
   $headers[] = t('Operations');
 
+  // Get our list of widgets in order (needed when the form comes back after
+  // preview or failed validation).
+  $widgets = array();
+  foreach (element_children($element) as $key) {
+    $widgets[] = &$element[$key];
+  }
+  usort($widgets, '_field_sort_items_value_helper');
+
   $rows = array();
-  foreach ($widgets as $key => $widget) {
+  foreach ($widgets as $key => &$widget) {
     // Save the uploading row for last.
-    if ($element[$key]['#file'] == FALSE) {
-      $element[$key]['#title'] = $element['#file_upload_title'];
-      $element[$key]['#description'] = $element['#file_upload_description'];
+    if ($widget['#file'] == FALSE) {
+      $widget['#title'] = $element['#file_upload_title'];
+      $widget['#description'] = $element['#file_upload_description'];
       continue;
     }
 
     // Delay rendering of the buttons, so that they can be rendered later in the
     // "operations" column.
     $operations_elements = array();
-    foreach (element_children($element[$key]) as $sub_key) {
-      if (isset($element[$key][$sub_key]['#type']) && $element[$key][$sub_key]['#type'] == 'submit') {
-        hide($element[$key][$sub_key]);
-        $operations_elements[] = &$element[$key][$sub_key];
+    foreach (element_children($widget) as $sub_key) {
+      if (isset($widget[$sub_key]['#type']) && $widget[$sub_key]['#type'] == 'submit') {
+        hide($widget[$sub_key]);
+        $operations_elements[] = &$widget[$sub_key];
       }
     }
 
     // Delay rendering of the "Display" option and the weight selector, so that
     // each can be rendered later in its own column.
     if ($element['#display_field']) {
-      hide($element[$key]['display']);
+      hide($widget['display']);
     }
-    hide($element[$key]['_weight']);
+    hide($widget['_weight']);
 
     // Render everything else together in a column, without the normal wrappers.
-    $element[$key]['#theme_wrappers'] = array();
-    $information = drupal_render($element[$key]);
+    $widget['#theme_wrappers'] = array();
+    $information = drupal_render($widget);
 
     // Render the previously hidden elements, using render() instead of
     // drupal_render(), to undo the earlier hide().
@@ -849,14 +856,14 @@ function theme_file_widget_multiple($variables) {
     }
     $display = '';
     if ($element['#display_field']) {
-      unset($element[$key]['display']['#title']);
+      unset($widget['display']['#title']);
       $display = array(
-        'data' => render($element[$key]['display']),
+        'data' => render($widget['display']),
         'class' => array('checkbox'),
       );
     }
-    $element[$key]['_weight']['#attributes']['class'] = array($weight_class);
-    $weight = render($element[$key]['_weight']);
+    $widget['_weight']['#attributes']['class'] = array($weight_class);
+    $weight = render($widget['_weight']);
 
     // Arrange the row with all of the rendered columns.
     $row = array();
@@ -868,7 +875,7 @@ function theme_file_widget_multiple($variables) {
     $row[] = $operations;
     $rows[] = array(
       'data' => $row,
-      'class' => isset($element[$key]['#attributes']['class']) ? array_merge($element[$key]['#attributes']['class'], array('draggable')) : array('draggable'),
+      'class' => isset($widget['#attributes']['class']) ? array_merge($widget['#attributes']['class'], array('draggable')) : array('draggable'),
     );
   }
 
@@ -880,6 +887,7 @@ function theme_file_widget_multiple($variables) {
   return $output;
 }
 
+
 /**
  * Returns HTML for help text based on file upload validators.
  *
diff --git a/modules/file/file.info b/modules/file/file.info
index 12cb50fec9935f32665540eb1c8b76250939d15a..e2b6edeb276c9f81c529595afdcd900a88072e4a 100644
--- a/modules/file/file.info
+++ b/modules/file/file.info
@@ -1,17 +1,14 @@
-; $Id: file.info,v 1.2 2010/08/16 20:57:23 dries Exp $
+; $Id: file.info,v 1.3 2010/12/20 19:59:41 webchick Exp $
 name = File
 description = Defines a file field type.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = field
-files[] = file.module
-files[] = file.field.inc
-files[] = file.install
 files[] = tests/file.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/file/file.install b/modules/file/file.install
index 995c332c93af0bd118e47a983dbb27b13cfb090d..fab07ed10241f75a6d451d9dd199fe6efac21381 100644
--- a/modules/file/file.install
+++ b/modules/file/file.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.install,v 1.4 2010/09/29 01:37:03 dries Exp $
+// $Id: file.install,v 1.5 2010/11/21 09:24:41 webchick Exp $
 
 /**
  * @file
@@ -13,7 +13,7 @@ function file_field_schema($field) {
   return array(
     'columns' => array(
       'fid' => array(
-        'description' => 'The {files}.fid being referenced in this field.',
+        'description' => 'The {file_managed}.fid being referenced in this field.',
         'type' => 'int',
         'not null' => FALSE,
         'unsigned' => TRUE,
@@ -37,7 +37,7 @@ function file_field_schema($field) {
     ),
     'foreign keys' => array(
       'fid' => array(
-        'table' => 'file',
+        'table' => 'file_managed',
         'columns' => array('fid' => 'fid'),
       ),
     ),
diff --git a/modules/file/file.js b/modules/file/file.js
index 774e525072e84d44d88922c9e0592e26feed79f0..19cd8061f96d0e980e91d3fff6b40badf49e24a9 100644
--- a/modules/file/file.js
+++ b/modules/file/file.js
@@ -1,4 +1,4 @@
-// $Id: file.js,v 1.5 2010/09/28 02:31:52 dries Exp $
+// $Id: file.js,v 1.6 2010/11/23 05:51:16 webchick Exp $
 
 /**
  * @file
@@ -15,11 +15,20 @@
  * Attach behaviors to managed file element upload fields.
  */
 Drupal.behaviors.fileValidateAutoAttach = {
-  attach: function (context) {
-    $('div.form-managed-file input.form-file[accept]', context).bind('change', Drupal.file.validateExtension);
+  attach: function (context, settings) {
+    if (settings.file && settings.file.elements) {
+      $.each(settings.file.elements, function(selector) {
+        var extensions = settings.file.elements[selector];
+        $(selector, context).bind('change', {extensions: extensions}, Drupal.file.validateExtension);
+      });
+    }
   },
-  detach: function (context) {
-    $('div.form-managed-file input.form-file[accept]', context).unbind('change', Drupal.file.validateExtension);
+  detach: function (context, settings) {
+    if (settings.file && settings.file.elements) {
+      $.each(settings.file.elements, function(selector) {
+        $(selector, context).unbind('change', Drupal.file.validateExtension);
+      });
+    }
   }
 };
 
@@ -54,20 +63,20 @@ Drupal.behaviors.filePreviewLinks = {
  */
 Drupal.file = Drupal.file || {
   /**
-   * Client-side file input validation based on the HTML "accept" attribute.
+   * Client-side file input validation of file extensions.
    */
   validateExtension: function (event) {
     // Remove any previous errors.
     $('.file-upload-js-error').remove();
 
-    // Add client side validation for the input[type=file] accept attribute.
-    var accept = this.accept.replace(/,\s*/g, '|');
-    if (accept.length > 1 && this.value.length > 0) {
-      var acceptableMatch = new RegExp('\\.(' + accept + ')$', 'gi');
+    // Add client side validation for the input[type=file].
+    var extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
+    if (extensionPattern.length > 1 && this.value.length > 0) {
+      var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi');
       if (!acceptableMatch.test(this.value)) {
         var error = Drupal.t("The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.", {
           '%filename': this.value,
-          '%extensions': accept.replace(/\|/g, ', ')
+          '%extensions': extensionPattern.replace(/\|/g, ', ')
         });
         $(this).parents('div.form-managed-file').prepend('<div class="messages error file-upload-js-error">' + error + '</div>');
         this.value = '';
diff --git a/modules/file/file.module b/modules/file/file.module
index a1b4450fa4ba2a0b52856af9a818bdaf339c2143..2dd2bad312a8ac1aa44850338b9562b7812c8547 100644
--- a/modules/file/file.module
+++ b/modules/file/file.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.module,v 1.45 2010/10/20 15:22:53 dries Exp $
+// $Id: file.module,v 1.50 2010/12/29 04:35:23 webchick Exp $
 
 /**
  * @file
@@ -141,7 +141,7 @@ function file_file_download($uri, $field_type = 'file') {
   }
 
   // Find out which (if any) fields of this type contain the file.
-  $references = file_get_file_references($file, NULL, FIELD_LOAD_REVISION, $field_type);
+  $references = file_get_file_references($file, NULL, FIELD_LOAD_CURRENT, $field_type);
 
   // If there are no references, stop processing, to avoid returning headers
   // for files controlled by other modules.
@@ -237,7 +237,7 @@ function file_ajax_upload() {
     drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
     $commands = array();
     $commands[] = ajax_command_replace(NULL, theme('status_messages'));
-    return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
+    return array('#type' => 'ajax', '#commands' => $commands);
   }
 
   list($form, $form_state) = ajax_get_form();
@@ -247,7 +247,7 @@ function file_ajax_upload() {
     drupal_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error');
     $commands = array();
     $commands[] = ajax_command_replace(NULL, theme('status_messages'));
-    return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
+    return array('#type' => 'ajax', '#commands' => $commands);
   }
 
   // Get the current element and count the number of files.
@@ -280,7 +280,7 @@ function file_ajax_upload() {
 
   $commands = array();
   $commands[] = ajax_command_replace(NULL, $output, $settings);
-  return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
+  return array('#type' => 'ajax', '#commands' => $commands);
 }
 
 /**
@@ -360,7 +360,7 @@ function file_managed_file_process($element, &$form_state, $form) {
   $element['#tree'] = TRUE;
 
   $ajax_settings = array(
-    'path' => 'file/ajax/' . implode('/', $element['#parents']) . '/' . $form['form_build_id']['#value'],
+    'path' => 'file/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'],
     'wrapper' => $element['#id'] . '-ajax-wrapper',
     'effect' => 'fade',
     'progress' => array(
@@ -442,10 +442,15 @@ function file_managed_file_process($element, &$form_state, $form) {
     );
   }
 
-  // The "accept" attribute is valid XHTML, but not enforced in browsers.
-  // We use it for our own purposes in our JavaScript validation.
+  // Add the extension list to the page as JavaScript settings.
   if (isset($element['#upload_validators']['file_validate_extensions'][0])) {
-    $element['upload']['#attributes']['accept'] = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
+    $extension_list = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
+    $element['upload']['#attached']['js'] = array(
+      array(
+        'type' => 'setting',
+        'data' => array('file' => array('elements' => array('#' . $element['#id'] . '-upload' => $extension_list)))
+      )
+    );
   }
 
   // Prefix and suffix used for AJAX replacement.
@@ -489,7 +494,7 @@ function file_managed_file_value(&$element, $input = FALSE, $form_state = NULL)
       // functionality to allow File fields to be extended through FAPI.
       if (isset($element['#file_value_callbacks'])) {
         foreach ($element['#file_value_callbacks'] as $callback) {
-          $callback($element, $input);
+          $callback($element, $input, $form_state);
         }
       }
       // Load file if the FID has changed to confirm it exists.
diff --git a/modules/file/icons/application-octet-stream.png b/modules/file/icons/application-octet-stream.png
index cc56d6baaa25c224f659b4fe4dbe28168225f731..d5453217dc5cc30e805d3d0da8fa91e5a0684b86 100644
Binary files a/modules/file/icons/application-octet-stream.png and b/modules/file/icons/application-octet-stream.png differ
diff --git a/modules/file/icons/application-pdf.png b/modules/file/icons/application-pdf.png
index 7263cf27a6cef6d4431636d1f32cdac44b200b00..36107d6e804015e13d122c53cb035d33632678d2 100644
Binary files a/modules/file/icons/application-pdf.png and b/modules/file/icons/application-pdf.png differ
diff --git a/modules/file/icons/application-x-executable.png b/modules/file/icons/application-x-executable.png
index cc56d6baaa25c224f659b4fe4dbe28168225f731..d5453217dc5cc30e805d3d0da8fa91e5a0684b86 100644
Binary files a/modules/file/icons/application-x-executable.png and b/modules/file/icons/application-x-executable.png differ
diff --git a/modules/file/icons/audio-x-generic.png b/modules/file/icons/audio-x-generic.png
index b4777fcc299655f740465adac1e57f4c691e47a4..28d7f50862b5dbb153c0809e9119fd879d499788 100644
Binary files a/modules/file/icons/audio-x-generic.png and b/modules/file/icons/audio-x-generic.png differ
diff --git a/modules/file/icons/image-x-generic.png b/modules/file/icons/image-x-generic.png
index 96acccfe0bd09845a36d673fbe41b3093570c2f1..c1b814f7cb6f4a21e165e88db557ffe4692babad 100644
Binary files a/modules/file/icons/image-x-generic.png and b/modules/file/icons/image-x-generic.png differ
diff --git a/modules/file/icons/package-x-generic.png b/modules/file/icons/package-x-generic.png
index 80fa1bc79c09704afb1cc2e0e365c3a8034fa4b2..21fc382cba23efb9d7cfaefb6a98b86324d531e3 100644
Binary files a/modules/file/icons/package-x-generic.png and b/modules/file/icons/package-x-generic.png differ
diff --git a/modules/file/icons/text-html.png b/modules/file/icons/text-html.png
index 07ef1a271af4301cbc3f42a7ee0f6c6b7a90e082..9c7c7932c25ad93adc9c9e6962d984d1703cd17f 100644
Binary files a/modules/file/icons/text-html.png and b/modules/file/icons/text-html.png differ
diff --git a/modules/file/icons/text-plain.png b/modules/file/icons/text-plain.png
index 7ee2c2dbd77ef655615eaff81e3be0b2f3cb19c2..06804849b8331ed8be3d1ae089311ae58ea79c83 100644
Binary files a/modules/file/icons/text-plain.png and b/modules/file/icons/text-plain.png differ
diff --git a/modules/file/icons/text-x-generic.png b/modules/file/icons/text-x-generic.png
index 7ee2c2dbd77ef655615eaff81e3be0b2f3cb19c2..06804849b8331ed8be3d1ae089311ae58ea79c83 100644
Binary files a/modules/file/icons/text-x-generic.png and b/modules/file/icons/text-x-generic.png differ
diff --git a/modules/file/icons/text-x-script.png b/modules/file/icons/text-x-script.png
index 4e66ed8069e9a6365d53f08922ea39792070d5e3..f9ecca813882ad9d8f3509464e2d8ac017910b81 100644
Binary files a/modules/file/icons/text-x-script.png and b/modules/file/icons/text-x-script.png differ
diff --git a/modules/file/icons/video-x-generic.png b/modules/file/icons/video-x-generic.png
index 2743ac27c18d638838a20c093fa33b2be460df98..a2b71f95d9e1a5bf86d90a1272bf4f9ae44fcb71 100644
Binary files a/modules/file/icons/video-x-generic.png and b/modules/file/icons/video-x-generic.png differ
diff --git a/modules/file/icons/x-office-document.png b/modules/file/icons/x-office-document.png
index 4cd6b619595066733b38649acf006b34f1694839..40db538fcb71e1f46147a717cdf7134c4e74a239 100644
Binary files a/modules/file/icons/x-office-document.png and b/modules/file/icons/x-office-document.png differ
diff --git a/modules/file/icons/x-office-presentation.png b/modules/file/icons/x-office-presentation.png
index c1ca337d950323c9cedb965a325ad85f72efb3c2..fb119e5ba91dd5141e07aad5229754cd06401c99 100644
Binary files a/modules/file/icons/x-office-presentation.png and b/modules/file/icons/x-office-presentation.png differ
diff --git a/modules/file/icons/x-office-spreadsheet.png b/modules/file/icons/x-office-spreadsheet.png
index 375a43a37d671d9bf9db11484bab179f01877aff..9af7b61ea11fb8bd71c0b5c6506a2101d5c1f714 100644
Binary files a/modules/file/icons/x-office-spreadsheet.png and b/modules/file/icons/x-office-spreadsheet.png differ
diff --git a/modules/file/tests/file.test b/modules/file/tests/file.test
index 464a8125d29b6559fbb4a04b48be1210e8bdd03c..629119785022852d114531aed0d168208f731ec9 100644
--- a/modules/file/tests/file.test
+++ b/modules/file/tests/file.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.test,v 1.27 2010/10/20 15:22:53 dries Exp $
+// $Id: file.test,v 1.29 2010/12/11 01:32:20 dries Exp $
 
 /**
  * @file
@@ -13,7 +13,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
   protected $admin_user;
 
   function setUp() {
-    parent::setUp('file');
+    parent::setUp('file', 'file_module_test');
     $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access'));
     $this->drupalLogin($this->admin_user);
   }
@@ -31,6 +31,13 @@ class FileFieldTestCase extends DrupalWebTestCase {
     return $file;
   }
 
+  /**
+   * Get the fid of the last inserted file.
+   */
+  function getLastFileId() {
+    return (int) db_query('SELECT MAX(fid) FROM {file_managed}')->fetchField();
+  }
+
   /**
    * Create a new file field.
    *
@@ -114,20 +121,23 @@ class FileFieldTestCase extends DrupalWebTestCase {
     );
 
     if (is_numeric($nid_or_type)) {
-      $node = node_load($nid_or_type, NULL, TRUE);
-      $delta = isset($node->{$field_name}[LANGUAGE_NONE]) ? count($node->{$field_name}[LANGUAGE_NONE]) : 0;
-      $edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']'] = drupal_realpath($file->uri);
-      $this->drupalPost('node/' . $nid_or_type . '/edit', $edit, t('Save'));
+      $nid = $nid_or_type;
     }
     else {
-      $edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($file->uri);
-      $type_name = str_replace('_', '-', $nid_or_type);
-      $this->drupalPost('node/add/' . $type_name, $edit, t('Save'));
+      // Add a new node.
+      $node = $this->drupalCreateNode(array('type' => $nid_or_type));
+      $nid = $node->nid;
+      // Save at least one revision to better simulate a real site.
+      $this->drupalCreateNode(get_object_vars($node));
+      $node = node_load($nid, NULL, TRUE);
+      $this->assertNotEqual($nid, $node->vid, t('Node revision exists.'));
     }
 
-    $matches = array();
-    preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
-    return isset($matches[1]) ? $matches[1] : FALSE;
+    // Attach a file to the node.
+    $edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($file->uri);
+    $this->drupalPost("node/$nid/edit", $edit, t('Save'));
+
+    return $nid;
   }
 
   /**
@@ -201,6 +211,95 @@ class FileFieldTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Test class for testing the 'managed_file' element type on its own, not as part of a file field.
+ *
+ * @todo Create a FileTestCase base class and move FileFieldTestCase methods
+ *   that aren't related to fields into it.
+ */
+class FileManagedFileElementTestCase extends FileFieldTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Managed file element test',
+      'description' => 'Tests the managed_file element type.',
+      'group' => 'File',
+    );
+  }
+
+  /**
+   * Tests the managed_file element type.
+   */
+  function testManagedFile() {
+    // Perform the tests with all permutations of $form['#tree'] and
+    // $element['#extended'].
+    foreach (array(0, 1) as $tree) {
+      foreach (array(0, 1) as $extended) {
+        $test_file = $this->getTestFile('text');
+        $path = 'file/test/' . $tree . '/' . $extended;
+        $input_base_name = $tree ? 'nested_file' : 'file';
+
+        // Submit without a file.
+        $this->drupalPost($path, array(), t('Save'));
+        $this->assertRaw(t('The file id is %fid.', array('%fid' => 0)), t('Submitted without a file.'));
+
+        // Submit a new file, without using the Upload button.
+        $last_fid_prior = $this->getLastFileId();
+        $edit = array('files[' . $input_base_name . ']' => drupal_realpath($test_file->uri));
+        $this->drupalPost($path, $edit, t('Save'));
+        $last_fid = $this->getLastFileId();
+        $this->assertTrue($last_fid > $last_fid_prior, t('New file got saved.'));
+        $this->assertRaw(t('The file id is %fid.', array('%fid' => $last_fid)), t('Submit handler has correct file info.'));
+
+        // Submit no new input, but with a default file.
+        $this->drupalPost($path . '/' . $last_fid, array(), t('Save'));
+        $this->assertRaw(t('The file id is %fid.', array('%fid' => $last_fid)), t('Empty submission did not change an existing file.'));
+
+        // Now, test the Upload and Remove buttons, with and without AJAX.
+        foreach (array(FALSE, TRUE) as $ajax) {
+          // Upload, then Submit.
+          $last_fid_prior = $this->getLastFileId();
+          $this->drupalGet($path);
+          $edit = array('files[' . $input_base_name . ']' => drupal_realpath($test_file->uri));
+          if ($ajax) {
+            $this->drupalPostAJAX(NULL, $edit, $input_base_name . '_upload_button');
+          }
+          else {
+            $this->drupalPost(NULL, $edit, t('Upload'));
+          }
+          $last_fid = $this->getLastFileId();
+          $this->assertTrue($last_fid > $last_fid_prior, t('New file got uploaded.'));
+          $this->drupalPost(NULL, array(), t('Save'));
+          $this->assertRaw(t('The file id is %fid.', array('%fid' => $last_fid)), t('Submit handler has correct file info.'));
+
+          // Remove, then Submit.
+          $this->drupalGet($path . '/' . $last_fid);
+          if ($ajax) {
+            $this->drupalPostAJAX(NULL, array(), $input_base_name . '_remove_button');
+          }
+          else {
+            $this->drupalPost(NULL, array(), t('Remove'));
+          }
+          $this->drupalPost(NULL, array(), t('Save'));
+          $this->assertRaw(t('The file id is %fid.', array('%fid' => 0)), t('Submission after file removal was successful.'));
+
+          // Upload, then Remove, then Submit.
+          $this->drupalGet($path);
+          $edit = array('files[' . $input_base_name . ']' => drupal_realpath($test_file->uri));
+          if ($ajax) {
+            $this->drupalPostAJAX(NULL, $edit, $input_base_name . '_upload_button');
+            $this->drupalPostAJAX(NULL, array(), $input_base_name . '_remove_button');
+          }
+          else {
+            $this->drupalPost(NULL, $edit, t('Upload'));
+            $this->drupalPost(NULL, array(), t('Remove'));
+          }
+          $this->drupalPost(NULL, array(), t('Save'));
+          $this->assertRaw(t('The file id is %fid.', array('%fid' => 0)), t('Submission after file upload and removal was successful.'));
+        }
+      }
+    }
+  }
+}
 
 /**
  * Test class to test file field widget, single and multi-valued, with and without AJAX, with public and private files.
@@ -905,7 +1004,7 @@ class FileTokenReplaceTestCase extends FileFieldTestCase {
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
 
     // Load the node and the file.
-    $node = node_load($nid);
+    $node = node_load($nid, NULL, TRUE);
     $file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
     $file->description = 'File description.';
 
diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info
index 7a3a45f72ce04cc1d95258f2d12be521d8526b55..9c6ee0ad00a3306e10a73058f1c62630a1843983 100644
--- a/modules/file/tests/file_module_test.info
+++ b/modules/file/tests/file_module_test.info
@@ -1,14 +1,13 @@
-; $Id: file_module_test.info,v 1.1 2009/08/29 12:52:32 dries Exp $
+; $Id: file_module_test.info,v 1.2 2010/12/20 19:59:41 webchick Exp $
 name = File test
 description = Provides hooks for testing File module functionality.
 package = Core
 version = VERSION
 core = 7.x
-files[] = file_module_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/file/tests/file_module_test.module b/modules/file/tests/file_module_test.module
index 157e478b05c1dba1173651051ddff9d3bbb83a5f..b02134a47a4b5fb14c326fb74ed9373b70c550bb 100644
--- a/modules/file/tests/file_module_test.module
+++ b/modules/file/tests/file_module_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: file_module_test.module,v 1.3 2009/12/04 16:49:46 dries Exp $
+// $Id: file_module_test.module,v 1.4 2010/11/13 14:04:08 dries Exp $
 
 /**
  * @file
@@ -22,15 +22,22 @@ function file_module_test_menu() {
   return $items;
 }
 
-function file_module_test_form($form, $form_state) {
-  $form['#tree'] = TRUE;
+/**
+ * Form builder for testing a 'managed_file' element.
+ */
+function file_module_test_form($form, &$form_state, $tree = TRUE, $extended = FALSE, $default_fid = NULL) {
+  $form['#tree'] = (bool) $tree;
 
-  $form['file'] = array(
+  $form['nested']['file'] = array(
     '#type' => 'managed_file',
     '#title' => t('Managed file'),
     '#upload_location' => 'public://test',
     '#progress_message' => t('Please wait...'),
+    '#extended' => (bool) $extended,
   );
+  if ($default_fid) {
+    $form['nested']['file']['#default_value'] = $extended ? array('fid' => $default_fid) : $default_fid;
+  }
 
   $form['textfield'] = array(
     '#type' => 'textfield',
@@ -44,3 +51,16 @@ function file_module_test_form($form, $form_state) {
 
   return $form;
 }
+
+/**
+ * Form submission handler for file_module_test_form().
+ */
+function file_module_test_form_submit($form, &$form_state) {
+  if ($form['#tree']) {
+    $fid = $form['nested']['file']['#extended'] ? $form_state['values']['nested']['file']['fid'] : $form_state['values']['nested']['file'];
+  }
+  else {
+    $fid = $form['nested']['file']['#extended'] ? $form_state['values']['file']['fid'] : $form_state['values']['file'];
+  }
+  drupal_set_message(t('The file id is %fid.', array('%fid' => $fid)));
+}
diff --git a/modules/filter/filter.admin.inc b/modules/filter/filter.admin.inc
index a75c0d485c30515791c18aec0ca200e583b2f2e5..465d7520c04529d0e103c519c5cf2f9ae5be8de6 100644
--- a/modules/filter/filter.admin.inc
+++ b/modules/filter/filter.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.admin.inc,v 1.69 2010/10/22 16:36:14 webchick Exp $
+// $Id: filter.admin.inc,v 1.71 2010/12/14 02:40:15 dries Exp $
 
 /**
  * @file
@@ -172,6 +172,9 @@ function filter_admin_format_form($form, &$form_state, $format) {
     // Create an empty filter object for new/unconfigured filters.
     if (!isset($filters[$name])) {
       $filters[$name] = new stdClass();
+      $filters[$name]->format = $format->format;
+      $filters[$name]->module = $filter['module'];
+      $filters[$name]->name = $name;
       $filters[$name]->status = 0;
       $filters[$name]->weight = $filter['weight'];
       $filters[$name]->settings = array();
@@ -308,8 +311,11 @@ function filter_admin_format_form_submit($form, &$form_state) {
   // Remove unnecessary values.
   form_state_values_clean($form_state);
 
-  // Save text format.
-  $format = (object) $form_state['values'];
+  // Add the submitted form values to the text format, and save it.
+  $format = $form['#format'];
+  foreach ($form_state['values'] as $key => $value) {
+    $format->$key = $value;
+  }
   $status = filter_format_save($format);
 
   // Save user permissions.
diff --git a/modules/filter/filter.api.php b/modules/filter/filter.api.php
index 4d59a26f9698778f2007b920f908aca79abd2da8..b43af6f9c6763e193e51ca48d732739035207bf6 100644
--- a/modules/filter/filter.api.php
+++ b/modules/filter/filter.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.api.php,v 1.21 2010/09/18 02:18:35 dries Exp $
+// $Id: filter.api.php,v 1.22 2010/12/09 02:04:16 dries Exp $
 
 /**
  * @file
@@ -14,114 +14,29 @@
 /**
  * Define content filters.
  *
- * Content in Drupal is passed through a group of filters before it is output.
- * This lets a module modify content to the site administrator's liking.
- *
- * This hook allows modules to declare input filters they provide. A module can
- * contain as many filters as it wants.
- *
- * The overall, logical flow is as follows:
- * - hook_filter_info() is invoked to retrieve one or more filter definitions.
- * - The site administrator enables and configures the filter, where the
- *   following properties may be used:
- *   - 'title': The filter's title.
- *   - 'description': The filter's short-description.
- *   Additionally, if a filter is configurable:
- *   - 'settings callback': A form builder function name providing a settings
- *     form for the filter.
- *   - 'default settings': An array containing default settings for the filter.
- * - When a form containing a text format-enabled text widget/textarea is
- *   rendered, the following property are checked:
- *   - 'tips callback': A function name providing filter guidelines to be
- *      displayed in the text format widget.
- * - When a content using a text format is rendered, the following properties
- *   may be used:
- *   - 'prepare callback': A name of a function that escapes the to be filtered
- *     content before the actual filtering happens.
- *   - 'process callback': The name the function that performs the actual
- *     filtering.
+ * User submitted content is passed through a group of filters before it is
+ * output in HTML, in order to remove insecure or unwanted parts, correct or
+ * enhance the formatting, transform special keywords, etc. A group of filters
+ * is referred to as a "text format". Administrators can create as many text
+ * formats as needed. Individual filters can be enabled and configured
+ * differently for each text format.
+ *
+ * This hook is invoked by filter_get_filters() and allows modules to register
+ * input filters they provide.
  *
  * Filtering is a two-step process. First, the content is 'prepared' by calling
  * the 'prepare callback' function for every filter. The purpose of the 'prepare
  * callback' is to escape HTML-like structures. For example, imagine a filter
  * which allows the user to paste entire chunks of programming code without
- * requiring manual escaping of special HTML characters like @< or @&. If the
+ * requiring manual escaping of special HTML characters like < or &. If the
  * programming code were left untouched, then other filters could think it was
- * HTML and change it. For most filters however, the prepare-step is not
- * necessary, and they can just return the input without changes.
- *
- * Filters should not use the 'prepare callback' step for anything other than
- * escaping, because that would short-circuit the control the user has over the
- * order in which filters are applied.
- *
- * The second step is the actual processing step. The result from the prepare
- * step gets passed to all the filters again, this time with the 'process
- * callback' function. It's here where filters should perform actual changing of
- * the content: transforming URLs into hyperlinks, converting smileys into
- * images, etc.
- *
- * An important aspect of the filtering system is 'text formats'. Every text
- * format is an entire filter setup: which filters to enable, in what order
- * and with what settings.
- *
- * Filters that require settings should provide the form controls to configure
- * the settings in a form builder function, specified in 'settings callback'.
- * The filter system stores the settings in the database per text format.
- *
- * If the filter's behavior depends on an extensive list and/or external data
- * (e.g. a list of smileys, a list of glossary terms) then filters are allowed
- * to provide a separate, global configuration page rather than provide settings
- * per format. In that case, there should be a link from the format-specific
- * settings to the separate settings page.
- *
- * The $filter object with the current settings is passed to the 'settings
- * callback' function. If 'default settings' were defined in hook_filter_info(),
- * those are passed as second argument to the 'settings callback'. Each filter
- * should apply either the default settings or the configured settings contained
- * in $filter->settings.
- *
- * 'settings callback' is invoked with the following arguments (most filter
- * implementations will only need $form_state, $filter and $defaults):
- * - $form: The prepopulated form array, which will usually have no use here.
- * - &$form_state: The form state of the (entire) configuration form.
- * - $filter: The filter object containing settings for the given format.
- * - $format: The format object being configured.
- * - $defaults: The default settings for the filter, as defined in 'default
- *   settings' in hook_filter_info().
- * - $filters: Complete list of filter objects that are enabled for the given
- *   format.
- *
- * @code
- *   function mymodule_filter_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
- *     $settings['mymodule_url_length'] = array(
- *       '#type' => 'textfield',
- *       '#title' => t('Maximum link text length'),
- *       '#default_value' => isset($filter->settings['mymodule_url_length']) ? $filter->settings['mymodule_url_length'] : $defaults['mymodule_url_length'],
- *     );
- *     return $settings;
- *   }
- * @endcode
- *
- * 'prepare callback' and 'process callback' are invoked with the following
- * arguments:
- * - $text: The text to be filtered.
- * - $filter: The filter object containing settings for the given format.
- * - $format: The format object of the text to be filtered.
- * - $langcode: (optional) The language code of the text to be filtered.
- * - $cache: Boolean whether check_markup() will cache the filtered $text in
- *   {cache_filter}.
- * - $cache_id: The cache ID used for $text in {cache_filter} when $cache is
- *   TRUE.
- *
- * @see check_markup()
+ * HTML and change it. For many filters, the prepare step is not necessary.
  *
- * 'prepare callback' and 'process callback' functions may access the filter
- * settings in $filter->settings['mymodule_url_length'].
- *
- * 'tips callback' is invoked with the following parameters:
- * - $filter: The filter object containing settings for the given format.
- * - $format: The format object of the text to be filtered.
- * - $long: Boolean whether to return long or short filter guidelines.
+ * The second step is the actual processing step. The result from passing the
+ * text through all the filters' prepare steps gets passed to all the filters
+ * again, this time with the 'process callback' function. The process callbacks
+ * should then actually change the content: transform URLs into hyperlinks,
+ * convert smileys into images, etc.
  *
  * For performance reasons content is only filtered once; the result is stored
  * in the cache table and retrieved from the cache the next time the same piece
@@ -131,36 +46,37 @@
  * caching for the entire format, not just for one filter.
  *
  * Beware of the filter cache when developing your module: it is advised to set
- * your filter to 'cache' => FALSE while developing, but be sure to remove it
- * again if it's not needed. You can clear the cache by running the SQL query
- * 'DELETE * FROM cache_filter';
+ * your filter to 'cache' => FALSE while developing, but be sure to remove that
+ * setting if it's not needed, when you are no longer in development mode.
  *
  * @return
- *   An array of filter items. Each filter item has a unique name, prefixed
- *   with the name of the module that provides it. The item is an associative
- *   array that may contain the following key-value pairs:
- *   - 'title': (required) The administrative title of the filter.
- *   - 'description': A short, administrative description of what this filter
- *     does.
- *   - 'prepare callback': A callback function to call in the 'prepare' step
- *     of the filtering.
- *   - 'process callback': (required) The callback function to call in the
- *     'process' step of the filtering.
- *   - 'settings callback': A callback function that provides form controls
- *     for the filter's settings. Each filter should apply either the default
- *     settings or the configured settings contained in $filter->settings. The
- *     user submitted values are stored in the database.
- *   - 'default settings': An array containing default settings for a filter to
- *     be applied when the filter has not been configured yet.
- *   - 'tips callback': A callback function that provides tips for using the
- *     filter. A module's tips should be informative and to the point. Short
- *     tips are preferably one-liners.
- *   - 'cache': Specifies whether the filtered text can be cached. TRUE by
- *     default. Note that defining FALSE makes the entire text format not
+ *   An associative array of filters, whose keys are internal filter names,
+ *   which should be unique and therefore prefixed with the name of the module.
+ *   Each value is an associative array describing the filter, with the
+ *   following elements (all are optional except as noted):
+ *   - title: (required) An administrative summary of what the filter does.
+ *   - description: Additional administrative information about the filter's
+ *     behavior, if needed for clarification.
+ *   - settings callback: The name of a function that returns configuration form
+ *     elements for the filter. See hook_filter_FILTER_settings() for details.
+ *   - default settings: An associative array containing default settings for
+ *     the filter, to be applied when the filter has not been configured yet.
+ *   - prepare callback: The name of a function that escapes the content before
+ *     the actual filtering happens. See hook_filter_FILTER_prepare() for
+ *     details.
+ *   - process callback: (required) The name the function that performs the
+ *     actual filtering. See hook_filter_FILTER_process() for details.
+ *   - cache (default TRUE): Specifies whether the filtered text can be cached.
+ *     Note that setting this to FALSE makes the entire text format not
  *     cacheable, which may have an impact on the site's overall performance.
+ *     See filter_format_allowcache() for details.
+ *   - tips callback: The name of a function that returns end-user-facing filter
+ *     usage guidelines for the filter. See hook_filter_FILTER_tips() for
+ *     details.
+ *   - weight: A default weight for the filter in new text formats.
  *
- * For a detailed usage example, see filter_example.module. For an example of
- * using multiple filters in one module, see filter_filter_info().
+ * @see filter_example.module
+ * @see hook_filter_info_alter()
  */
 function hook_filter_info() {
   $filters['filter_html'] = array(
@@ -202,6 +118,164 @@ function hook_filter_info_alter(&$info) {
   );
 }
 
+/**
+ * @} End of "addtogroup hooks".
+ */
+
+/**
+ * Settings callback for hook_filter_info().
+ *
+ * Note: This is not really a hook. The function name is manually specified via
+ * 'settings callback' in hook_filter_info(), with this recommended callback
+ * name pattern. It is called from filter_admin_format_form().
+ *
+ * This callback function is used to provide a settings form for filter
+ * settings, for filters that need settings on a per-text-format basis. This
+ * function should return the form elements for the settings; the filter
+ * module will take care of saving the settings in the database.
+ *
+ * If the filter's behavior depends on an extensive list and/or external data
+ * (e.g. a list of smileys, a list of glossary terms), then the filter module
+ * can choose to provide a separate, global configuration page rather than
+ * per-text-format settings. In that case, the settings callback function
+ * should provide a link to the separate settings page.
+ *
+ * @param $form
+ *   The prepopulated form array of the filter administration form.
+ * @param $form_state
+ *   The state of the (entire) configuration form.
+ * @param $filter
+ *   The filter object containing the current settings for the given format,
+ *   in $filter->settings.
+ * @param $format
+ *   The format object being configured.
+ * @param $defaults
+ *   The default settings for the filter, as defined in 'default settings' in
+ *   hook_filter_info(). These should be combined with $filter->settings to
+ *   define the form element defaults.
+ * @param $filters
+ *   The complete list of filter objects that are enabled for the given format.
+ *
+ * @return
+ *   An array of form elements defining settings for the filter. Array keys
+ *   should match the array keys in $filter->settings and $defaults.
+ */
+function hook_filter_FILTER_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
+  $filter->settings += $defaults;
+
+  $elements = array();
+  $elements['nofollow'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Add rel="nofollow" to all links'),
+    '#default_value' => $filter->settings['nofollow'],
+  );
+  return $elements;
+}
+
+/**
+ * Prepare callback for hook_filter_info().
+ *
+ * Note: This is not really a hook. The function name is manually specified via
+ * 'prepare callback' in hook_filter_info(), with this recommended callback
+ * name pattern. It is called from check_markup().
+ *
+ * See hook_filter_info() for a description of the filtering process. Filters
+ * should not use the 'prepare callback' step for anything other than escaping,
+ * because that would short-circuit the control the user has over the order in
+ * which filters are applied.
+ *
+ * @param $text
+ *   The text string to be filtered.
+ * @param $filter
+ *   The filter object containing settings for the given format.
+ * @param $format
+ *   The text format object assigned to the text to be filtered.
+ * @param $langcode
+ *   The language code of the text to be filtered.
+ * @param $cache
+ *   A Boolean indicating whether the filtered text is going to be cached in
+ *   {cache_filter}.
+ * @param $cache_id
+ *   The ID of the filtered text in {cache_filter}, if $cache is TRUE.
+ *
+ * @return
+ *   The prepared, escaped text.
+ */
+function hook_filter_FILTER_prepare($text, $filter, $format, $langcode, $cache, $cache_id) {
+  // Escape <code> and </code> tags.
+  $text = preg_replace('|<code>(.+?)</code>|se', "[codefilter_code]$1[/codefilter_code]", $text);
+  return $text;
+}
+
+/**
+ * Process callback for hook_filter_info().
+ *
+ * Note: This is not really a hook. The function name is manually specified via
+ * 'process callback' in hook_filter_info(), with this recommended callback
+ * name pattern. It is called from check_markup().
+ *
+ * See hook_filter_info() for a description of the filtering process. This step
+ * is where the filter actually transforms the text.
+ *
+ * @param $text
+ *   The text string to be filtered.
+ * @param $filter
+ *   The filter object containing settings for the given format.
+ * @param $format
+ *   The text format object assigned to the text to be filtered.
+ * @param $langcode
+ *   The language code of the text to be filtered.
+ * @param $cache
+ *   A Boolean indicating whether the filtered text is going to be cached in
+ *   {cache_filter}.
+ * @param $cache_id
+ *   The ID of the filtered text in {cache_filter}, if $cache is TRUE.
+ *
+ * @return
+ *   The filtered text.
+ */
+function hook_filter_FILTER_process($text, $filter, $format, $langcode, $cache, $cache_id) {
+  $text = preg_replace('|\[codefilter_code\](.+?)\[/codefilter_code\]|se', "<pre>$1</pre>", $text);
+
+  return $text;
+}
+
+/**
+ * Tips callback for hook_filter_info().
+ *
+ * Note: This is not really a hook. The function name is manually specified via
+ * 'tips callback' in hook_filter_info(), with this recommended callback
+ * name pattern. It is called from _filter_tips().
+ *
+ * A filter's tips should be informative and to the point. Short tips are
+ * preferably one-liners.
+ *
+ * @param $filter
+ *   An object representing the filter.
+ * @param $format
+ *   An object representing the text format the filter is contained in.
+ * @param $long
+ *   Whether this callback should return a short tip to display in a form
+ *   (FALSE), or whether a more elaborate filter tips should be returned for
+ *   theme_filter_tips() (TRUE).
+ *
+ * @return
+ *   Translated text to display as a tip.
+ */
+function hook_filter_FILTER_tips($filter, $format, $long) {
+ if ($long) {
+    return t('Lines and paragraphs are automatically recognized. The &lt;br /&gt; line break, &lt;p&gt; paragraph and &lt;/p&gt; close paragraph tags are inserted automatically. If paragraphs are not recognized simply add a couple blank lines.');
+  }
+  else {
+    return t('Lines and paragraphs break automatically.');
+  }
+}
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
 /**
  * Perform actions when a new text format has been created.
  *
diff --git a/modules/filter/filter.info b/modules/filter/filter.info
index f353db36328fd08327e40d49dfd61b863d90f397..c6b614d273b94c7f1283a27a0167b2d7077c8d24 100644
--- a/modules/filter/filter.info
+++ b/modules/filter/filter.info
@@ -1,19 +1,15 @@
-; $Id: filter.info,v 1.13 2009/11/17 21:24:18 dries Exp $
+; $Id: filter.info,v 1.14 2010/12/20 19:59:42 webchick Exp $
 name = Filter
 description = Filters content in preparation for display.
 package = Core
 version = VERSION
 core = 7.x
-files[] = filter.module
-files[] = filter.admin.inc
-files[] = filter.pages.inc
-files[] = filter.install
 files[] = filter.test
 required = TRUE
 configure = admin/config/content/formats
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/filter/filter.install b/modules/filter/filter.install
index 8a9d997bebffd6cd96a4a4d2cf033fd2939d7eda..b62caef9e045c1d73abb4ee31f12c05e463aac98 100644
--- a/modules/filter/filter.install
+++ b/modules/filter/filter.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.install,v 1.49 2010/10/23 00:43:48 webchick Exp $
+// $Id: filter.install,v 1.51 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -162,7 +162,7 @@ function filter_update_dependencies() {
   return $dependencies;
 }
 /**
- * @defgroup updates-6.x-to-7.x Filter updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -205,7 +205,7 @@ function filter_update_7001() {
     if (variable_get('filter_html_' . $format_id, 1) == 2) {
       $insert->values(array(
         'format' => $format_id,
-        'filter' => 'filter',
+        'module' => 'filter',
         'delta' => 4,
         'weight' => 0,
       ));
@@ -490,6 +490,5 @@ function filter_update_7010() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index a19acb6f2152808e4cb6942079368eaa4cd462f3..5365a2fe6e44f1c4f4f6d4b915ad027bef8a8e49 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.module,v 1.355 2010/10/22 16:36:14 webchick Exp $
+// $Id: filter.module,v 1.361 2010/12/09 02:04:16 dries Exp $
 
 /**
  * @file
@@ -173,6 +173,8 @@ function filter_format_load($format_id) {
  *     to save. If this corresponds to an existing text format, that format
  *     will be updated; otherwise, a new format will be created.
  *   - 'name': The title of the text format.
+ *   - 'status': (optional) An integer indicating whether the text format is
+ *     enabled (1) or not (0). Defaults to 1.
  *   - 'weight': (optional) The weight of the text format, which controls its
  *     placement in text format lists. If omitted, the weight is set to 0.
  *   - 'filters': (optional) An associative, multi-dimensional array of filters
@@ -358,15 +360,6 @@ function filter_permission_name($format) {
   return FALSE;
 }
 
-/**
- * Implements hook_cron().
- *
- * Expire outdated filter cache entries
- */
-function filter_cron() {
-  cache_clear_all(NULL, 'cache_filter');
-}
-
 /**
  * Implements hook_modules_enabled().
  */
@@ -1046,8 +1039,9 @@ function _filter_tips($format_id, $long = FALSE) {
  *   A DOMDocument that represents the loaded (X)HTML snippet.
  */
 function filter_dom_load($text) {
+  $dom_document = new DOMDocument();
   // Ignore warnings during HTML soup loading.
-  $dom_document = @DOMDocument::loadHTML('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>' . $text . '</body></html>');
+  @$dom_document->loadHTML('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>' . $text . '</body></html>');
 
   return $dom_document;
 }
@@ -1201,22 +1195,24 @@ function filter_filter_info() {
  * Settings callback for the HTML filter.
  */
 function _filter_html_settings($form, &$form_state, $filter, $format, $defaults) {
+  $filter->settings += $defaults;
+
   $settings['allowed_html'] = array(
     '#type' => 'textfield',
     '#title' => t('Allowed HTML tags'),
-    '#default_value' => isset($filter->settings['allowed_html']) ? $filter->settings['allowed_html'] : $defaults['allowed_html'],
+    '#default_value' => $filter->settings['allowed_html'],
     '#maxlength' => 1024,
     '#description' => t('A list of HTML tags that can be used. JavaScript event attributes, JavaScript URLs, and CSS are always stripped.'),
   );
   $settings['filter_html_help'] = array(
     '#type' => 'checkbox',
     '#title' => t('Display basic HTML help in long filter tips'),
-    '#default_value' => isset($filter->settings['filter_html_help']) ? $filter->settings['filter_html_help'] : $defaults['filter_html_help'],
+    '#default_value' => $filter->settings['filter_html_help'],
   );
   $settings['filter_html_nofollow'] = array(
     '#type' => 'checkbox',
     '#title' => t('Add rel="nofollow" to all links'),
-    '#default_value' => isset($filter->settings['filter_html_nofollow']) ? $filter->settings['filter_html_nofollow'] : $defaults['filter_html_nofollow'],
+    '#default_value' => $filter->settings['filter_html_nofollow'],
   );
   return $settings;
 }
@@ -1265,7 +1261,7 @@ function _filter_html_tips($filter, $format, $long = FALSE) {
     'a' => array(t('Anchors are used to make links to other pages.'), '<a href="' . $base_url . '">' . check_plain(variable_get('site_name', 'Drupal')) . '</a>'),
     'br' => array(t('By default line break tags are automatically added, so use this tag to add additional ones. Use of this tag is different because it is not used with an open/close pair like all the others. Use the extra " /" inside the tag to maintain XHTML 1.0 compatibility'), t('Text with <br />line break')),
     'p' => array(t('By default paragraph tags are automatically added, so use this tag to add additional ones.'), '<p>' . t('Paragraph one.') . '</p> <p>' . t('Paragraph two.') . '</p>'),
-    'strong' => array(t('Strong'), '<strong>' . t('Strong') . '</strong>'),
+    'strong' => array(t('Strong', array(), array('context' => 'Font weight')), '<strong>' . t('Strong', array(), array('context' => 'Font weight')) . '</strong>'),
     'em' => array(t('Emphasized'), '<em>' . t('Emphasized') . '</em>'),
     'cite' => array(t('Cited'), '<cite>' . t('Cited') . '</cite>'),
     'code' => array(t('Coded text used to show programming source code'), '<code>' . t('Coded') . '</code>'),
@@ -1301,14 +1297,12 @@ function _filter_html_tips($filter, $format, $long = FALSE) {
   $header = array(t('Tag Description'), t('You Type'), t('You Get'));
   preg_match_all('/<([a-z0-9]+)[^a-z0-9]/i', $allowed_html, $out);
   foreach ($out[1] as $tag) {
-    if (array_key_exists($tag, $tips)) {
-      if ($tips[$tag]) {
-        $rows[] = array(
-          array('data' => $tips[$tag][0], 'class' => array('description')),
-          array('data' => '<code>' . check_plain($tips[$tag][1]) . '</code>', 'class' => array('type')),
-          array('data' => $tips[$tag][1], 'class' => array('get'))
-        );
-      }
+    if (!empty($tips[$tag])) {
+      $rows[] = array(
+        array('data' => $tips[$tag][0], 'class' => array('description')),
+        array('data' => '<code>' . check_plain($tips[$tag][1]) . '</code>', 'class' => array('type')),
+        array('data' => $tips[$tag][1], 'class' => array('get'))
+      );
     }
     else {
       $rows[] = array(
@@ -1344,10 +1338,12 @@ function _filter_html_tips($filter, $format, $long = FALSE) {
  * Settings callback for URL filter.
  */
 function _filter_url_settings($form, &$form_state, $filter, $format, $defaults) {
+  $filter->settings += $defaults;
+
   $settings['filter_url_length'] = array(
     '#type' => 'textfield',
     '#title' => t('Maximum link text length'),
-    '#default_value' => isset($filter->settings['filter_url_length']) ? $filter->settings['filter_url_length'] : $defaults['filter_url_length'],
+    '#default_value' => $filter->settings['filter_url_length'],
     '#size' => 5,
     '#maxlength' => 4,
     '#field_suffix' => t('characters'),
diff --git a/modules/filter/filter.test b/modules/filter/filter.test
index 8225d36838cfcb8d3a534843a04ef6f84f83acff..55d1117976d1cb0924ad7f2c573e387fffc97d30 100644
--- a/modules/filter/filter.test
+++ b/modules/filter/filter.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.test,v 1.80 2010/10/23 02:26:11 webchick Exp $
+// $Id: filter.test,v 1.82 2010/12/01 00:00:21 webchick Exp $
 
 /**
  * Tests for text format and filter CRUD operations.
@@ -169,8 +169,8 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     parent::setUp();
 
     // Create users.
-    $filtered_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Filtered HTML'))->fetchObject();
-    $full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
+    $filtered_html_format = filter_format_load('filtered_html');
+    $full_html_format = filter_format_load('full_html');
     $this->admin_user = $this->drupalCreateUser(array(
       'administer filters',
       filter_permission_name($filtered_html_format),
@@ -185,33 +185,48 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     // Add text format.
     $this->drupalGet('admin/config/content/formats');
     $this->clickLink('Add text format');
+    $format_id = drupal_strtolower($this->randomName());
+    $name = $this->randomName();
     $edit = array(
-      'format' => drupal_strtolower($this->randomName()),
-      'name' => $this->randomName(),
+      'format' => $format_id,
+      'name' => $name,
     );
     $this->drupalPost(NULL, $edit, t('Save configuration'));
 
+    // Verify default weight of the text format.
+    $this->drupalGet('admin/config/content/formats');
+    $this->assertFieldByName("formats[$format_id][weight]", 0, t('Text format weight was saved.'));
+
+    // Change the weight of the text format.
+    $edit = array(
+      "formats[$format_id][weight]" => 5,
+    );
+    $this->drupalPost('admin/config/content/formats', $edit, t('Save changes'));
+    $this->assertFieldByName("formats[$format_id][weight]", 5, t('Text format weight was saved.'));
+
     // Edit text format.
-    $format = $this->getFormat($edit['name']);
     $this->drupalGet('admin/config/content/formats');
-    $this->assertRaw('admin/config/content/formats/' . $format->format);
-    $this->drupalGet('admin/config/content/formats/' . $format->format);
+    $this->assertLinkByHref('admin/config/content/formats/' . $format_id);
+    $this->drupalGet('admin/config/content/formats/' . $format_id);
     $this->drupalPost(NULL, array(), t('Save configuration'));
 
-    // Disable text format.
+    // Verify that the custom weight of the text format has been retained.
     $this->drupalGet('admin/config/content/formats');
-    $this->assertRaw('admin/config/content/formats/' . $format->format . '/disable');
-    $this->drupalGet('admin/config/content/formats/' . $format->format . '/disable');
+    $this->assertFieldByName("formats[$format_id][weight]", 5, t('Text format weight was retained.'));
+
+    // Disable text format.
+    $this->assertLinkByHref('admin/config/content/formats/' . $format_id . '/disable');
+    $this->drupalGet('admin/config/content/formats/' . $format_id . '/disable');
     $this->drupalPost(NULL, array(), t('Disable'));
 
     // Verify that disabled text format no longer exists.
-    $this->drupalGet('admin/config/content/formats/' . $format->format);
+    $this->drupalGet('admin/config/content/formats/' . $format_id);
     $this->assertResponse(404, t('Disabled text format no longer exists.'));
 
     // Attempt to create a format of the same machine name as the disabled
     // format but with a different human readable name.
     $edit = array(
-      'format' => $format->format,
+      'format' => $format_id,
       'name' => 'New format',
     );
     $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
@@ -221,10 +236,12 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     // disabled format but with a different machine name.
     $edit = array(
       'format' => 'new_format',
-      'name' => $format->name,
+      'name' => $name,
     );
     $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
-    $this->assertText('Text format names must be unique. A format named ' . check_plain($format->name) . ' already exists.');
+    $this->assertRaw(t('Text format names must be unique. A format named %name already exists.', array(
+      '%name' => $name,
+    )));
   }
 
   /**
@@ -236,10 +253,12 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     // Line filter.
     $second_filter = 'filter_autop';
 
-    list($filtered, $full, $plain) = $this->checkFilterFormats();
+    $filtered = 'filtered_html';
+    $full = 'full_html';
+    $plain = 'plain_text';
 
     // Check that the fallback format exists and cannot be disabled.
-    $this->assertTrue(!empty($plain) && $plain == filter_fallback_format(), t('The fallback format is set to plain text.'));
+    $this->assertTrue($plain == filter_fallback_format(), t('The fallback format is set to plain text.'));
     $this->drupalGet('admin/config/content/formats');
     $this->assertNoRaw('admin/config/content/formats/' . $plain . '/disable', t('Disable link for the fallback format not found.'));
     $this->drupalGet('admin/config/content/formats/' . $plain . '/disable');
@@ -297,7 +316,8 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
     $this->assertRaw(t('Added text format %format.', array('%format' => $edit['name'])), t('New filter created.'));
 
-    $format = $this->getFormat($edit['name']);
+    drupal_static_reset('filter_formats');
+    $format = filter_format_load($edit['format']);
     $this->assertNotNull($format, t('Format found in database.'));
 
     $this->assertFieldByName('roles[2]', '', t('Role found.'));
@@ -375,45 +395,6 @@ class FilterAdminTestCase extends DrupalWebTestCase {
     $this->assertFieldByName('filters[' . $second_filter . '][weight]', $edit['filters[' . $second_filter . '][weight]'], t('Changes reverted.'));
     $this->assertFieldByName('filters[' . $first_filter . '][weight]', $edit['filters[' . $first_filter . '][weight]'], t('Changes reverted.'));
   }
-
-  /**
-   * Query the database to get the three basic formats.
-   *
-   * @return
-   *   An array containing filtered, full, and plain text format ids.
-   */
-  function checkFilterFormats() {
-    $result = db_query('SELECT format, name FROM {filter_format}');
-
-    $filtered = -1;
-    $full = -1;
-    $plain = -1;
-    foreach ($result as $format) {
-      if ($format->name == 'Filtered HTML') {
-        $filtered = $format->format;
-      }
-      elseif ($format->name == 'Full HTML') {
-        $full = $format->format;
-      }
-      elseif ($format->name == 'Plain text') {
-        $plain = $format->format;
-      }
-    }
-
-    return array($filtered, $full, $plain);
-  }
-
-  /**
-   * Retrieve a text format object by name.
-   *
-   * @param $name
-   *   The name of a text format.
-   * @return
-   *   A text format object.
-   */
-  function getFormat($name) {
-    return db_query("SELECT * FROM {filter_format} WHERE name = :name", array(':name' => $name))->fetchObject();
-  }
 }
 
 class FilterFormatAccessTestCase extends DrupalWebTestCase {
@@ -452,8 +433,7 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
       );
       $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
       $this->resetFilterCaches();
-      $format_id = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
-      $formats[] = filter_format_load($format_id);
+      $formats[] = filter_format_load($edit['format']);
     }
     list($this->allowed_format, $this->disallowed_format) = $formats;
     $this->drupalLogout();
@@ -684,8 +664,7 @@ class FilterDefaultFormatTestCase extends DrupalWebTestCase {
       );
       $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
       $this->resetFilterCaches();
-      $format_id = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
-      $formats[] = filter_format_load($format_id);
+      $formats[] = filter_format_load($edit['format']);
     }
     list($first_format, $second_format) = $formats;
     $first_user = $this->drupalCreateUser(array(filter_permission_name($first_format), filter_permission_name($second_format)));
@@ -1716,7 +1695,7 @@ class FilterHooksTestCase extends DrupalWebTestCase {
     $this->assertRaw(t('Added text format %format.', array('%format' => $name)), t('New format created.'));
     $this->assertText('hook_filter_format_insert invoked.', t('hook_filter_format_insert was invoked.'));
 
-    $format_id = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $name))->fetchField();
+    $format_id = $edit['format'];
 
     // Update text format.
     $edit = array();
diff --git a/modules/forum/forum-icon.tpl.php b/modules/forum/forum-icon.tpl.php
index a191b5137ac513380fa119bbca3ff451612d9602..c98eee3e65519c3f478ab3b5a51b1c43c79cbc46 100644
--- a/modules/forum/forum-icon.tpl.php
+++ b/modules/forum/forum-icon.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum-icon.tpl.php,v 1.7 2010/10/03 00:41:14 dries Exp $
+// $Id: forum-icon.tpl.php,v 1.8 2010/11/22 08:07:57 webchick Exp $
 
 /**
  * @file
@@ -9,19 +9,17 @@
  * - $new_posts: Indicates whether or not the topic contains new posts.
  * - $icon: The icon to display. May be one of 'hot', 'hot-new', 'new',
  *   'default', 'closed', or 'sticky'.
+ * - $first_new: Indicates whether this is the first topic with new posts.
  *
  * @see template_preprocess_forum_icon()
  * @see theme_forum_icon()
  */
 ?>
 <div class="topic-status-<?php print $icon_class ?>" title="<?php print $icon_title ?>">
-<?php if ($new_posts): ?>
-  <a id="new">
+<?php if ($first_new): ?>
+  <a id="new"></a>
 <?php endif; ?>
 
   <span class="element-invisible"><?php print $icon_title ?></span>
 
-<?php if ($new_posts): ?>
-  </a>
-<?php endif; ?>
 </div>
diff --git a/modules/forum/forum.info b/modules/forum/forum.info
index 566f06cb9d7e6305faae5484552ccaead53cda79..2558d70fef82ad5d9f8bb667476f6ddbda7c4c59 100644
--- a/modules/forum/forum.info
+++ b/modules/forum/forum.info
@@ -1,4 +1,4 @@
-; $Id: forum.info,v 1.14 2010/09/05 02:21:38 dries Exp $
+; $Id: forum.info,v 1.15 2010/12/20 19:59:42 webchick Exp $
 name = Forum
 description = Provides discussion forums.
 dependencies[] = taxonomy
@@ -6,16 +6,12 @@ dependencies[] = comment
 package = Core
 version = VERSION
 core = 7.x
-files[] = forum.module
-files[] = forum.admin.inc
-files[] = forum.pages.inc
-files[] = forum.install
 files[] = forum.test
 configure = admin/structure/forum
 stylesheets[all][] = forum.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index 86ddb1bd6930a0b2cdec79167580c45cc89de69d..5c07e885c84394c1a828e2e297bb1e5362c04254 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.module,v 1.579 2010/10/06 13:38:40 dries Exp $
+// $Id: forum.module,v 1.582 2010/11/29 04:53:32 webchick Exp $
 
 /**
  * @file
@@ -71,7 +71,7 @@ function forum_theme() {
     ),
     'forum_icon' => array(
       'template' => 'forum-icon',
-      'variables' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0),
+      'variables' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0, 'first_new' => FALSE),
     ),
     'forum_submitted' => array(
       'template' => 'forum-submitted',
@@ -623,10 +623,12 @@ function forum_block_info() {
   $blocks['active'] = array(
     'info' => t('Active forum topics'),
     'cache' => DRUPAL_CACHE_CUSTOM,
+    'properties' => array('administrative' => TRUE),
   );
   $blocks['new'] = array(
     'info' => t('New forum topics'),
     'cache' => DRUPAL_CACHE_CUSTOM,
+    'properties' => array('administrative' => TRUE),
   );
   return $blocks;
 }
@@ -900,6 +902,7 @@ function forum_get_topics($tid, $sortby, $forum_per_page) {
   }
 
   $topics = array();
+  $first_new_found = FALSE;
   foreach ($result as $topic) {
     if ($user->uid) {
       // folder is new if topic is new or there are new comments since last visit
@@ -918,6 +921,13 @@ function forum_get_topics($tid, $sortby, $forum_per_page) {
       $topic->new = 0;
     }
 
+    // Make sure only one topic is indicated as the first new topic.
+    $topic->first_new = FALSE;
+    if ($topic->new != 0 && !$first_new_found) {
+      $topic->first_new = TRUE;
+      $first_new_found = TRUE;
+    }
+
     if ($topic->comment_count > 0) {
       $last_reply = new stdClass();
       $last_reply->created = $topic->last_comment_timestamp;
@@ -980,7 +990,7 @@ function template_preprocess_forums(&$variables) {
 
     if ($variables['tid'] && !in_array($variables['tid'], variable_get('forum_containers', array()))) {
       $variables['topics'] = theme('forum_topic_list', $variables);
-      drupal_add_feed('taxonomy/term/' . $variables['tid'] . '/0/feed', 'RSS - ' . $title);
+      drupal_add_feed('taxonomy/term/' . $variables['tid'] . '/feed', 'RSS - ' . $title);
     }
     else {
       $variables['topics'] = '';
@@ -1079,7 +1089,7 @@ function template_preprocess_forum_topic_list(&$variables) {
   if (!empty($variables['topics'])) {
     $row = 0;
     foreach ($variables['topics'] as $id => $topic) {
-      $variables['topics'][$id]->icon = theme('forum_icon', array('new_posts' => $topic->new, 'num_posts' => $topic->comment_count, 'comment_mode' => $topic->comment_mode, 'sticky' => $topic->sticky));
+      $variables['topics'][$id]->icon = theme('forum_icon', array('new_posts' => $topic->new, 'num_posts' => $topic->comment_count, 'comment_mode' => $topic->comment_mode, 'sticky' => $topic->sticky, 'first_new' => $topic->first_new));
       $variables['topics'][$id]->zebra = $row % 2 == 0 ? 'odd' : 'even';
       $row++;
 
@@ -1128,6 +1138,7 @@ function template_preprocess_forum_topic_list(&$variables) {
  * - $num_posts = 0
  * - $comment_mode = 0
  * - $sticky = 0
+ * - $first_new
  *
  * @see forum-icon.tpl.php
  * @see theme_forum_icon()
diff --git a/modules/help/help.info b/modules/help/help.info
index d3bd19166b4ffd07b8cca99bced71c92670589bb..dd45bb54e22562396abad3d0768ee0d60362d0e4 100644
--- a/modules/help/help.info
+++ b/modules/help/help.info
@@ -1,15 +1,13 @@
-; $Id: help.info,v 1.8 2009/06/08 09:23:52 dries Exp $
+; $Id: help.info,v 1.9 2010/12/20 19:59:42 webchick Exp $
 name = Help
 description = Manages the display of online help.
 package = Core
 version = VERSION
 core = 7.x
-files[] = help.module
-files[] = help.admin.inc
 files[] = help.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/help/help.test b/modules/help/help.test
index 532ce6446ef0350edc2c22c229e2a68e5e7dc368..3725a1a492587ea813231923124f43e546abac2c 100644
--- a/modules/help/help.test
+++ b/modules/help/help.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: help.test,v 1.21 2010/08/05 23:53:38 webchick Exp $
+// $Id: help.test,v 1.22 2010/11/27 20:25:44 dries Exp $
 
 class HelpTestCase extends DrupalWebTestCase {
   protected $big_user;
@@ -22,7 +22,7 @@ class HelpTestCase extends DrupalWebTestCase {
     $this->getModuleList();
 
     // Create users.
-    $this->big_user = $this->drupalCreateUser(array('access administration pages', 'administer permissions'));
+    $this->big_user = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer permissions'));
     $this->any_user = $this->drupalCreateUser(array());
   }
 
diff --git a/modules/image/image.admin.inc b/modules/image/image.admin.inc
index 4aae2d2f5c93cac32242213efba804707b42b4df..74002bb9361110cd0763286294a4cb0be17be74e 100644
--- a/modules/image/image.admin.inc
+++ b/modules/image/image.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.admin.inc,v 1.27 2010/10/21 20:50:43 webchick Exp $
+// $Id: image.admin.inc,v 1.28 2010/11/21 07:24:53 webchick Exp $
 
 /**
  * @file
@@ -700,10 +700,10 @@ function theme_image_style_effects($variables) {
   $rows = array();
 
   foreach (element_children($form) as $key) {
+    $row = array();
+    $form[$key]['weight']['#attributes']['class'] = array('image-effect-order-weight');
     if (is_numeric($key)) {
-      $form[$key]['weight']['#attributes']['class'] = array('image-effect-order-weight');
       $summary = drupal_render($form[$key]['summary']);
-      $row = array();
       $row[] = drupal_render($form[$key]['label']) . (empty($summary) ? '' : ' ' . $summary);
       $row[] = drupal_render($form[$key]['weight']);
       $row[] = drupal_render($form[$key]['configure']);
@@ -711,8 +711,6 @@ function theme_image_style_effects($variables) {
     }
     else {
       // Add the row for adding a new image effect.
-      $form['new']['weight']['#attributes']['class'] = array('image-effect-order-weight');
-      $row = array();
       $row[] = '<div class="image-style-new">' . drupal_render($form['new']['new']) . drupal_render($form['new']['add']) . '</div>';
       $row[] = drupal_render($form['new']['weight']);
       $row[] = array('data' => '', 'colspan' => 2);
@@ -721,7 +719,7 @@ function theme_image_style_effects($variables) {
     if (!isset($form[$key]['#access']) || $form[$key]['#access']) {
       $rows[] = array(
         'data' => $row,
-        'class' => !empty($form[$key]['weight']['#access']) ? array('draggable') : array(),
+        'class' => !empty($form[$key]['weight']['#access']) || $key == 'new' ? array('draggable') : array(),
       );
     }
   }
diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc
index d73ee5998121668afaa8d8d8d89556ddf218d645..a65407f7abd17dcb3f250e71fadd8916a2cba524 100644
--- a/modules/image/image.field.inc
+++ b/modules/image/image.field.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.field.inc,v 1.33 2010/10/22 00:42:42 dries Exp $
+// $Id: image.field.inc,v 1.34 2010/10/31 12:12:00 dries Exp $
 
 /**
  * @file
@@ -335,7 +335,7 @@ function image_field_widget_process($element, &$form_state, $form) {
   $item = $element['#value'];
   $item['fid'] = $element['fid']['#value'];
 
-  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
+  $instance = field_widget_instance($element, $form_state);
 
   $settings = $instance['settings'];
   $widget_settings = $instance['widget']['settings'];
diff --git a/modules/image/image.info b/modules/image/image.info
index 16c5cb8c35d86532d42b41b86a0b2f01ddbb68e3..ba007eb84d6c7e80f60131bde78241d862d4f535 100644
--- a/modules/image/image.info
+++ b/modules/image/image.info
@@ -1,20 +1,15 @@
-; $Id: image.info,v 1.5 2009/11/17 21:24:18 dries Exp $
+; $Id: image.info,v 1.6 2010/12/20 19:59:42 webchick Exp $
 name = Image
 description = Provides image manipulation tools.
 package = Core
 version = VERSION
 core = 7.x
 dependencies[] = file
-files[] = image.module
-files[] = image.admin.inc
-files[] = image.effects.inc
-files[] = image.field.inc
-files[] = image.install
 files[] = image.test
 configure = admin/config/media/image-styles
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/image/image.install b/modules/image/image.install
index 53123887f9dbd04e57f260b6fdaf1944000ccf57..07032763a2599d2b34952e853434cd290ac36849 100644
--- a/modules/image/image.install
+++ b/modules/image/image.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.install,v 1.13 2010/09/04 15:40:51 dries Exp $
+// $Id: image.install,v 1.14 2010/11/21 09:24:41 webchick Exp $
 
 /**
  * @file
@@ -114,7 +114,7 @@ function image_field_schema($field) {
   return array(
     'columns' => array(
       'fid' => array(
-        'description' => 'The {files}.fid being referenced in this field.',
+        'description' => 'The {file_managed}.fid being referenced in this field.',
         'type' => 'int',
         'not null' => FALSE,
         'unsigned' => TRUE,
@@ -135,6 +135,12 @@ function image_field_schema($field) {
     'indexes' => array(
       'fid' => array('fid'),
     ),
+    'foreign keys' => array(
+      'fid' => array(
+        'table' => 'file_managed',
+        'columns' => array('fid' => 'fid'),
+      ),
+    ),
   );
 }
 
diff --git a/modules/image/image.module b/modules/image/image.module
index 3260031ebba83ad6a0a1d58bd239ff6e9ebf6b50..8afed87906f87c2d5270fc8d1d52277bd6e804d8 100644
--- a/modules/image/image.module
+++ b/modules/image/image.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.module,v 1.53 2010/10/03 05:14:58 webchick Exp $
+// $Id: image.module,v 1.54 2010/11/18 05:36:27 dries Exp $
 
 /**
  * @file
@@ -49,7 +49,7 @@ function image_help($path, $arg) {
       $output .= '<dd>' . t('With the Image module you can scale, crop, resize, rotate and desaturate images without affecting the original image using <a href="@image">image styles</a>. When you change an image style, the module automatically refreshes all created images. Every image style must have a name, which will be used in the URL of the generated images. There are two common approaches to naming image styles (which you use will depend on how the image style is being applied):',array('@image' => url('admin/config/media/image-styles')));
       $output .= '<ul><li>' . t('Based on where it will be used: eg. <em>profile-picture</em>') . '</li>';
       $output .= '<li>' . t('Describing its appearance: eg. <em>square-85x85</em>') . '</li></ul>';
-      $output .=  t('After you create an image style, you can add effects: crop, scale, resize, rotate, desaturate, and rotate (other contributed modules provide additional effects). For example, by combining effects as crop, scale, and desaturate, you can create square, grayscale thumbnails.') . '<dd>';
+      $output .=  t('After you create an image style, you can add effects: crop, scale, resize, rotate, and desaturate (other contributed modules provide additional effects). For example, by combining effects as crop, scale, and desaturate, you can create square, grayscale thumbnails.') . '<dd>';
       $output .= '<dt>' . t('Attaching images to content as fields') . '</dt>';
       $output .= '<dd>' . t("Image module also allows you to attach images to content as fields. To add an image field to a <a href='@content-type'>content type</a>, go to the content type's <em>manage fields</em> page, and add a new field of type <em>Image</em>. Attaching images to content this way allows image styles to be applied and maintained, and also allows you more flexibility when theming.", array('@content-type' => url('admin/structure/types'))) . '</dd>';
       $output .= '</dl>';
diff --git a/modules/image/sample.png b/modules/image/sample.png
index c0d9cc4795387015d151074b1e5a50da1cfe0002..f22e0df98448bbaff3282f86ea5d14fdb256551c 100644
Binary files a/modules/image/sample.png and b/modules/image/sample.png differ
diff --git a/modules/image/tests/image_module_test.info b/modules/image/tests/image_module_test.info
index 748c21b377e481a4b8ab1fe6c62f5f4a5b0f0ce7..8186eb8139ad401c6577b830aecb4e53fe72d48a 100644
--- a/modules/image/tests/image_module_test.info
+++ b/modules/image/tests/image_module_test.info
@@ -7,8 +7,8 @@ core = 7.x
 files[] = image_module_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index 6398b680c40fed22c93edd7f13687e4ce6c8c973..be511ef5855619dfda110cf9288fa6c1f7ccd782 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.admin.inc,v 1.20 2010/10/20 01:31:07 dries Exp $
+// $Id: locale.admin.inc,v 1.23 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -7,8 +7,12 @@
  */
 
 /**
- * @defgroup locale-language-overview Language overview functionality
+ * @defgroup locale-language-administration Language administration interface
  * @{
+ * Administration interface for languages.
+ *
+ * These functions provide the user interface to show, add, edit and
+ * delete languages as well as providing options for language negotiation.
  */
 
 /**
@@ -107,7 +111,9 @@ function theme_locale_languages_overview_form($variables) {
 function locale_languages_overview_form_submit($form, &$form_state) {
   $languages = language_list();
   $default = language_default();
+  $url_prefixes = variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) == LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX;
   $enabled_count = 0;
+
   foreach ($languages as $langcode => $language) {
     if ($form_state['values']['site_default'] == $langcode || $default->language == $langcode) {
       // Automatically enable the default language and the language
@@ -115,6 +121,16 @@ function locale_languages_overview_form_submit($form, &$form_state) {
       // value from that disabled checkbox).
       $form_state['values']['enabled'][$langcode] = 1;
     }
+
+    // If language URL prefixes are enabled we must clear language domains and
+    // assign a valid prefix to each non-default language.
+    if ($url_prefixes) {
+      $language->domain = '';
+      if (empty($language->prefix) && $form_state['values']['site_default'] != $langcode) {
+        $language->prefix = $langcode;
+      }
+    }
+
     if ($form_state['values']['enabled'][$langcode]) {
       $enabled_count++;
       $language->enabled = 1;
@@ -122,19 +138,25 @@ function locale_languages_overview_form_submit($form, &$form_state) {
     else {
       $language->enabled = 0;
     }
+
     $language->weight = $form_state['values']['weight'][$langcode];
+
     db_update('languages')
       ->fields(array(
         'enabled' => $language->enabled,
         'weight' => $language->weight,
+        'prefix' => $language->prefix,
+        'domain' => $language->domain,
       ))
       ->condition('language', $langcode)
       ->execute();
+
     $languages[$langcode] = $language;
   }
-  drupal_set_message(t('Configuration saved.'));
+
   variable_set('language_default', $languages[$form_state['values']['site_default']]);
   variable_set('language_count', $enabled_count);
+  drupal_set_message(t('Configuration saved.'));
 
   // Changing the language settings impacts the interface.
   cache_clear_all('*', 'cache_page', TRUE);
@@ -143,14 +165,6 @@ function locale_languages_overview_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/language';
   return;
 }
-/**
- * @} End of "locale-language-overview"
- */
-
-/**
- * @defgroup locale-language-add-edit Language addition and editing functionality
- * @{
- */
 
 /**
  * User interface for the language addition screen.
@@ -403,14 +417,6 @@ function locale_languages_edit_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/language';
   return;
 }
-/**
- * @} End of "locale-language-add-edit"
- */
-
-/**
- * @defgroup locale-language-delete Language deletion functionality
- * @{
- */
 
 /**
  * User interface for the language deletion confirmation screen.
@@ -474,14 +480,6 @@ function locale_languages_delete_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/language';
   return;
 }
-/**
- * @} End of "locale-language-add-edit"
- */
-
-/**
- * @defgroup locale-languages-negotiation Language negotiation options
- * @{
- */
 
 /**
  * Setting for language negotiation options
@@ -741,12 +739,16 @@ function locale_language_providers_session_form($form, &$form_state) {
 }
 
 /**
- * @} End of "locale-languages-negotiation"
+ * @} End of "locale-language-administration"
  */
 
 /**
- * @defgroup locale-translate-overview Translation overview screen.
+ * @defgroup locale-translate-administration-screens Translation administration screens
  * @{
+ * Screens for translation administration.
+ *
+ * These functions provide various screens as administration interface
+ * to import, export and view translations.
  */
 
 /**
@@ -785,14 +787,6 @@ function locale_translate_overview_screen() {
 
   return theme('table', array('header' => $headers, 'rows' => $rows));
 }
-/**
- * @} End of "locale-translate-overview"
- */
-
-/**
- * @defgroup locale-translate-seek Translation search screen.
- * @{
- */
 
 /**
  * String search screen.
@@ -929,15 +923,6 @@ function locale_translation_filter_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/translate/translate';
 }
 
-/**
- * @} End of "locale-translate-seek"
- */
-
-/**
- * @defgroup locale-translate-import Translation import screen.
- * @{
- */
-
 /**
  * User interface for the translation import screen.
  */
@@ -1027,14 +1012,6 @@ function locale_translate_import_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/translate';
   return;
 }
-/**
- * @} End of "locale-translate-import"
- */
-
-/**
- * @defgroup locale-translate-export Translation export screen.
- * @{
- */
 
 /**
  * User interface for the translation export screen.
@@ -1114,12 +1091,16 @@ function locale_translate_export_po_form_submit($form, &$form_state) {
   _locale_export_po($language, _locale_export_po_generate($language, _locale_export_get_strings($language, $form_state['values']['group'])));
 }
 /**
- * @} End of "locale-translate-export"
+ * @} End of "locale-translate-administration-screens"
  */
 
 /**
- * @defgroup locale-translate-edit Translation text editing
+ * @defgroup locale-translate-edit-delete Translation editing/deletion interface
  * @{
+ * Edit and delete translation strings.
+ *
+ * These functions provide the user interface to edit and delete
+ * translation strings.
  */
 
 /**
@@ -1254,14 +1235,6 @@ function locale_translate_edit_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/translate/translate';
   return;
 }
-/**
- * @} End of "locale-translate-edit"
- */
-
-/**
- * @defgroup locale-translate-delete Translation delete interface.
- * @{
- */
 
 /**
  * String deletion confirmation page.
@@ -1300,7 +1273,7 @@ function locale_translate_delete_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/config/regional/translate/translate';
 }
 /**
- * @} End of "locale-translate-delete"
+ * @} End of "locale-translate-edit-delete"
  */
 
 /**
diff --git a/modules/locale/locale.info b/modules/locale/locale.info
index 6556d6f35e19ec612e5255a93206f6c37f4b65dc..976fff45762b20fab09e3debf7d3493ef52ec769 100644
--- a/modules/locale/locale.info
+++ b/modules/locale/locale.info
@@ -1,17 +1,14 @@
-; $Id: locale.info,v 1.15 2010/03/25 11:46:21 dries Exp $
+; $Id: locale.info,v 1.16 2010/12/20 19:59:42 webchick Exp $
 name = Locale
 description = Adds language handling functionality and enables the translation of the user interface to languages other than English.
 package = Core
 version = VERSION
 core = 7.x
-files[] = locale.module
-files[] = locale.install
-files[] = locale.admin.inc
 files[] = locale.test
 configure = admin/config/regional/language
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/locale/locale.install b/modules/locale/locale.install
index a9dc2306354af0124c63d3ced11a8348b18d4bf8..3f7d99b8f9ad65f2002ec3a8d9a5b3ffb15a3407 100644
--- a/modules/locale/locale.install
+++ b/modules/locale/locale.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.install,v 1.69 2010/10/20 00:37:20 dries Exp $
+// $Id: locale.install,v 1.72 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -28,7 +28,7 @@ function locale_install() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Locale updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -113,7 +113,21 @@ function locale_update_7001() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
+ * Updates URL language negotiation by adding the URL fallback detection method.
+ */
+function locale_update_7002() {
+  // language.inc may not have been included during bootstrap if there is not
+  // more than one language currently enabled.
+  require_once DRUPAL_ROOT . '/includes/language.inc';
+  $language_types_info = language_types_info();
+  $info = $language_types_info[LANGUAGE_TYPE_URL];
+  if (isset($info['fixed'])) {
+    language_negotiation_set(LANGUAGE_TYPE_URL, array_flip($info['fixed']));
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
 
 /**
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 9ecf90f531a70812adcfe66a8a191c94ee6c60c2..8a82d1b02e18d52527d4a9809b3f7f4bb080d22b 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.module,v 1.303 2010/10/09 17:38:41 webchick Exp $
+// $Id: locale.module,v 1.307 2010/11/21 07:02:46 webchick Exp $
 
 /**
  * @file
@@ -30,7 +30,7 @@ function locale_help($path, $arg) {
       $output .= '<dd>' . t('Translations of text in the Drupal interface may be provided by:');
       $output .= '<ul>';
       $output .= '<li>' . t("Translating within your site, using the Locale module's integrated <a href='@translate'>translation interface</a>.", array('@translate' => url('admin/config/regional/translate'))) . '</li>';
-      $output .= '<li>' . t('Importing files from a set of existing translations, known as a translation package. A translation package enables the display of a specific version of Drupal in a specific language, and contains files in the Gettext Portable Object (<em>.po</em>) format. Although not all languages are available for every version of Drupal, translation packages for many languages are available for download from the <a href="@translations">Drupal translations page</a>.', array('@translations' => 'http://drupal.org/project/translations')) . '</li>';
+      $output .= '<li>' . t('Importing files from a set of existing translations, known as a translation package. A translation package enables the display of a specific version of Drupal in a specific language, and contains files in the Gettext Portable Object (<em>.po</em>) format. Although not all languages are available for every version of Drupal, translation packages for many languages are available for download from the <a href="@translations">Drupal translations page</a>.', array('@translations' => 'http://localize.drupal.org')) . '</li>';
       $output .= '<li>' . t("If an existing translation package does not meet your needs, the Gettext Portable Object (<em>.po</em>) files within a package may be modified, or new <em>.po</em> files may be created, using a desktop Gettext editor. The Locale module's <a href='@import'>import</a> feature allows the translated strings from a new or modified <em>.po</em> file to be added to your site. The Locale module's <a href='@export'>export</a> feature generates files from your site's translated strings, that can either be shared with others or edited offline by a Gettext translation editor.", array('@import' => url('admin/config/regional/translate/import'), '@export' => url('admin/config/regional/translate/export'))) . '</li>';
       $output .= '</ul></dd>';
       $output .= '<dt>' . t('Configuring a multilingual site') . '</dt>';
@@ -38,7 +38,7 @@ function locale_help($path, $arg) {
       $output .= '</dl>';
       return $output;
     case 'admin/config/regional/language':
-      $output = '<p>' . t('With multiple languages enabled, interface text can be translated, registered users may select their preferred language, and authors can assign a specific language to content. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://drupal.org/project/translations')) . '</p>';
+      $output = '<p>' . t('With multiple languages enabled, interface text can be translated, registered users may select their preferred language, and authors can assign a specific language to content. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '</p>';
       return $output;
     case 'admin/config/regional/language/add':
       return '<p>' . t('Add a language to be supported by your site. If your desired language is not available in the <em>Language name</em> drop-down, click <em>Custom language</em> and provide a language code and other details manually. When providing a language code manually, be sure to enter a standardized language code, since this code may be used by browsers to determine an appropriate display language.') . '</p>';
@@ -54,7 +54,7 @@ function locale_help($path, $arg) {
       return $output;
     case 'admin/config/regional/translate/import':
       $output = '<p>' . t('This page imports the translated strings contained in an individual Gettext Portable Object (<em>.po</em>) file. Normally distributed as part of a translation package (each translation package may contain several <em>.po</em> files), a <em>.po</em> file may need to be imported after offline editing in a Gettext translation editor. Importing an individual <em>.po</em> file may be a lengthy process.') . '</p>';
-      $output .= '<p>' . t('Note that the <em>.po</em> files within a translation package are imported automatically (if available) when new modules or themes are enabled, or as new languages are added. Since this page only allows the import of one <em>.po</em> file at a time, it may be simpler to download and extract a translation package into your Drupal installation directory and <a href="@language-add">add the language</a> (which automatically imports all <em>.po</em> files within the package). Translation packages are available for download on the <a href="@translations">Drupal translation page</a>.', array('@language-add' => url('admin/config/regional/language/add'), '@translations' => 'http://drupal.org/project/translations')) . '</p>';
+      $output .= '<p>' . t('Note that the <em>.po</em> files within a translation package are imported automatically (if available) when new modules or themes are enabled, or as new languages are added. Since this page only allows the import of one <em>.po</em> file at a time, it may be simpler to download and extract a translation package into your Drupal installation directory and <a href="@language-add">add the language</a> (which automatically imports all <em>.po</em> files within the package). Translation packages are available for download on the <a href="@translations">Drupal translation page</a>.', array('@language-add' => url('admin/config/regional/language/add'), '@translations' => 'http://localize.drupal.org')) . '</p>';
       return $output;
     case 'admin/config/regional/translate/export':
       return '<p>' . t('This page exports the translated strings used by your site. An export file may be in Gettext Portable Object (<em>.po</em>) form, which includes both the original string and the translation (used to share translations with others), or in Gettext Portable Object Template (<em>.pot</em>) form, which includes the original strings only (used to create new translations with a Gettext translation editor).') . '</p>';
@@ -503,8 +503,8 @@ function locale_entity_info_alter(&$entity_info) {
  *   language negotiated value. It is used by the Field API to determine the
  *   display language for fields if no explicit value is specified.
  * - URL language is by default non-configurable and is determined through the
- *   URL language provider. It is used by l() as the default language if none is
- *   specified.
+ *   URL language provider or the URL fallback provider if no language can be
+ *   detected. It is used by l() as the default language if none is specified.
  */
 function locale_language_types_info() {
   require_once DRUPAL_ROOT . '/includes/locale.inc';
@@ -517,7 +517,7 @@ function locale_language_types_info() {
       'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_INTERFACE),
     ),
     LANGUAGE_TYPE_URL => array(
-      'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_URL),
+      'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_URL, LOCALE_LANGUAGE_NEGOTIATION_URL_FALLBACK),
     ),
   );
 }
@@ -582,6 +582,15 @@ function locale_language_negotiation_info() {
     'description' => t('Use the detected interface language.'),
   );
 
+  $providers[LOCALE_LANGUAGE_NEGOTIATION_URL_FALLBACK] = array(
+    'types' => array(LANGUAGE_TYPE_URL),
+    'callbacks' => array('language' => 'locale_language_url_fallback'),
+    'file' => $file,
+    'weight' => 8,
+    'name' => t('URL fallback'),
+    'description' => t('Use an already detected language for URLs if none is found.'),
+  );
+
   return $providers;
 }
 
@@ -844,7 +853,7 @@ function locale_js_alter(&$javascript) {
   }
 }
 
-/*
+/**
  * Implements hook_css_alter().
  *
  * This function checks all CSS files currently added via drupal_add_css() and
@@ -923,7 +932,8 @@ function locale_block_view($type) {
     $path = drupal_is_front_page() ? '<front>' : $_GET['q'];
     $links = language_negotiation_get_switch_links($type, $path);
 
-    if (isset($links->links) && count($links->links > 1)) {
+    if (isset($links->links)) {
+      drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
       $class = "language-switcher-{$links->provider}";
       $variables = array('links' => $links->links, 'attributes' => array('class' => array($class)));
       $block['content'] = theme('links__locale_block', $variables);
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 7f716ba7fb806c6e36f454fdf66604540dcde7a0..f18ad41b94966946fe8e0029e7979a033d34f191 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.test,v 1.81 2010/10/09 13:46:08 dries Exp $
+// $Id: locale.test,v 1.88 2010/11/30 01:05:24 dries Exp $
 
 /**
  * @file
@@ -90,6 +90,11 @@ class LocaleConfigurationTest extends DrupalWebTestCase {
     $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
     $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
 
+    // Check if a valid language prefix is added after changing the default
+    // language.
+    $this->drupalGet('admin/config/regional/language/edit/en');
+    $this->assertFieldByXPath('//input[@name="prefix"]', 'en', t('A valid path prefix has been added to the previous default language.'));
+
     // Ensure we can't delete the default language.
     $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
     $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
@@ -582,7 +587,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
       'name' => 'Translation import',
-      'description' => 'Tests the importation of locale files.',
+      'description' => 'Tests the import of locale files.',
       'group' => 'Locale',
     );
   }
@@ -600,7 +605,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
   }
 
   /**
-   * Test importation of standalone .po files.
+   * Test import of standalone .po files.
    */
   function testStandalonePoFile() {
     // Try importing a .po file.
@@ -612,7 +617,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
     $this->assertRaw(t('The language %language has been created.', array('%language' => 'French')), t('The language has been automatically created.'));
 
     // The import should have created 7 strings.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 7, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 9, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
 
     // This import should have saved plural forms to have 2 variants.
     $this->assert(db_query("SELECT plurals FROM {languages} WHERE language = 'fr'")->fetchField() == 2, t('Plural number initialized.'));
@@ -698,8 +703,8 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
   }
 
   /**
-   * Test automatic importation of a module's translation files when a language
-   * is enabled.
+   * Test automatic import of a module's translation files when a language is
+   * enabled.
    */
   function testAutomaticModuleTranslationImportLanguageEnable() {
     // Code for the language - manually set to match the test translation file.
@@ -737,8 +742,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
   }
 
   /**
-   * Test automatic importation of a module's translation files when a language
-   * is enabled.
+   * Test msgctxt context support.
    */
   function testLanguageContext() {
     // Try importing a .po file.
@@ -750,6 +754,43 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
     $this->assertIdentical(t('May', array(), array('langcode' => 'hr')), 'Svi.', t('Default context is working.'));
   }
 
+  /**
+   * Test empty msgstr at end of .po file see #611786.
+   */
+  function testEmptyMsgstr() {
+    $langcode = 'hu';
+
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFileWithMsgstr(), array(
+      'langcode' => $langcode,
+    ));
+
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+    $this->assertIdentical(t('Operations', array(), array('langcode' => $langcode)), 'Műveletek', t('String imported and translated.'));
+
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFileWithEmptyMsgstr(), array(
+      'langcode' => $langcode,
+      'mode' => 0,
+    ));
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 0, '%delete' => 1)), t('The translation file was successfully imported.'));
+    // This is the language indicator on the translation search screen for
+    // untranslated strings. Copied straight from locale.inc.
+    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+    $str = "Operations";
+    $search = array(
+      'string' => $str,
+      'language' => 'all',
+      'translation' => 'all',
+      'group' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // assertText() seems to remove the input field where $str always could be
+    // found, so this is not a false assert.
+    $this->assertText($str, t('Search found the string.'));
+    $this->assertRaw($language_indicator, t('String is untranslated again.'));
+  }
+
   /**
    * Helper function: import a standalone .po file in a given language.
    *
@@ -773,12 +814,17 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
     return <<< EOF
 msgid ""
 msgstr ""
-"Project-Id-Version: Drupal 6\\n"
+"Project-Id-Version: Drupal 7\\n"
 "MIME-Version: 1.0\\n"
 "Content-Type: text/plain; charset=UTF-8\\n"
 "Content-Transfer-Encoding: 8bit\\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
 
+msgid "One sheep"
+msgid_plural "@count sheep"
+msgstr[0] "un mouton"
+msgstr[1] "@count moutons"
+
 msgid "Monday"
 msgstr "lundi"
 
@@ -809,7 +855,7 @@ EOF;
     return <<< EOF
 msgid ""
 msgstr ""
-"Project-Id-Version: Drupal 6\\n"
+"Project-Id-Version: Drupal 7\\n"
 "MIME-Version: 1.0\\n"
 "Content-Type: text/plain; charset=UTF-8\\n"
 "Content-Transfer-Encoding: 8bit\\n"
@@ -835,7 +881,7 @@ EOF;
     return <<< EOF
 msgid ""
 msgstr ""
-"Project-Id-Version: Drupal 6\\n"
+"Project-Id-Version: Drupal 7\\n"
 "MIME-Version: 1.0\\n"
 "Content-Type: text/plain; charset=UTF-8\\n"
 "Content-Transfer-Encoding: 8bit\\n"
@@ -858,7 +904,7 @@ EOF;
     return <<< EOF
 msgid ""
 msgstr ""
-"Project-Id-Version: Drupal 6\\n"
+"Project-Id-Version: Drupal 7\\n"
 "MIME-Version: 1.0\\n"
 "Content-Type: text/plain; charset=UTF-8\\n"
 "Content-Transfer-Encoding: 8bit\\n"
@@ -873,6 +919,45 @@ msgstr "Svi."
 EOF;
   }
 
+  /**
+   * Helper function that returns a .po file with an empty last item.
+   */
+  function getPoFileWithEmptyMsgstr() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 7\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Operations"
+msgstr ""
+
+EOF;
+  }
+  /**
+   * Helper function that returns a .po file with an empty last item.
+   */
+  function getPoFileWithMsgstr() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 7\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Operations"
+msgstr "Műveletek"
+
+msgid "Will not appear in Drupal core, so we can ensure the test passes"
+msgstr ""
+
+EOF;
+  }
 
 }
 
@@ -1492,7 +1577,58 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
     $this->drupalGet($prefix . '/' . $custom_language_path);
     $this->assertText($node->title, t('Custom language alias works.'));
 
-    $this->drupalLogout();
+    // Create a custom path.
+    $custom_path = $this->randomName(8);
+
+    // Check priority of language for alias by source path.
+    $edit = array(
+      'source'   => 'node/' . $node->nid,
+      'alias'    => $custom_path,
+      'language' => LANGUAGE_NONE,
+    );
+    path_save($edit);
+    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, 'en');
+    $this->assertEqual($english_path, $lookup_path, t('English language alias has priority.'));
+    // Same check for language 'xx'.
+    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, $prefix);
+    $this->assertEqual($custom_language_path, $lookup_path, t('Custom language alias has priority.'));
+    path_delete($edit);
+
+    // Create language nodes to check priority of aliases.
+    $first_node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+    $second_node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+
+    // Assign a custom path alias to the first node with the English language.
+    $edit = array(
+      'source'   => 'node/' . $first_node->nid,
+      'alias'    => $custom_path,
+      'language' => 'en',
+    );
+    path_save($edit);
+
+    // Assign a custom path alias to second node with LANGUAGE_NONE.
+    $edit = array(
+      'source'   => 'node/' . $second_node->nid,
+      'alias'    => $custom_path,
+      'language' => LANGUAGE_NONE,
+    );
+    path_save($edit);
+
+    // Test that both node titles link to our path alias.
+    $this->drupalGet('<front>');
+    $custom_path_url = base_path() . (variable_get('clean_url', 0) ? $custom_path : '?q=' . $custom_path);
+    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $first_node->title));
+    $this->assertTrue(!empty($elements), t('First node links to the path alias.'));
+    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $second_node->title));
+    $this->assertTrue(!empty($elements), t('Second node links to the path alias.'));
+
+    // Confirm that the custom path leads to the first node.
+    $this->drupalGet($custom_path);
+    $this->assertText($first_node->title, t('Custom alias returns first node.'));
+
+    // Confirm that the custom path with prefix leads to the second node.
+    $this->drupalGet($prefix . '/' . $custom_path);
+    $this->assertText($second_node->title, t('Custom alias with prefix returns second node.'));
   }
 }
 
@@ -1581,12 +1717,12 @@ class LocaleContentFunctionalTest extends DrupalWebTestCase {
     $this->drupalLogin($web_user);
     $this->drupalGet('node/add/article');
     // Verify language select list is not present.
-    $this->assertNoFieldByName('language', '', t('Language select not present on add article form.'));
+    $this->assertNoFieldByName('language', NULL, t('Language select not present on add article form.'));
 
     // Verify language selection appears on add "Basic page" form.
     $this->drupalGet('node/add/page');
     // Verify language select list is present.
-    $this->assertFieldByName('language', '', t('Language select present on add Basic page form.'));
+    $this->assertFieldByName('language', NULL, t('Language select present on add Basic page form.'));
     // Ensure enabled language appears.
     $this->assertText($name, t('Enabled language present.'));
     // Ensure disabled language doesn't appear.
@@ -1655,15 +1791,14 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
     parent::setUp('locale', 'locale_test');
     require_once DRUPAL_ROOT . '/includes/language.inc';
     drupal_load('module', 'locale');
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));
+    $this->drupalLogin($admin_user);
   }
 
   /**
    * Tests for language switching by URL path.
    */
   function testUILanguageNegotiation() {
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
-    $this->drupalLogin($admin_user);
-
     // A few languages to switch to.
     // This one is unknown, should get the default lang version.
     $language_unknown = 'blah-blah';
@@ -1817,6 +1952,132 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
     $this->drupalGet($test['path'], array(), $test['http_header']);
     $this->assertText($test['expect'], $test['message']);
   }
+
+  /**
+   * Test URL language detection when the requested URL has no language.
+   */
+  function testUrlLanguageFallback() {
+    // Add the Italian language.
+    $language_browser_fallback = 'it';
+    locale_add_language($language_browser_fallback);
+    $languages = language_list();
+
+    // Enable the path prefix for the default language: this way any unprefixed
+    // URL must have a valid fallback value.
+    $edit = array('prefix' => 'en');
+    $this->drupalPost('admin/config/regional/language/edit/en', $edit, t('Save language'));
+
+    // Enable browser and URL language detection.
+    $edit = array(
+      'language[enabled][locale-browser]' => TRUE,
+      'language[enabled][locale-url]' => TRUE,
+      'language[weight][locale-browser]' => -8,
+      'language[weight][locale-url]' => -10,
+    );
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+    $this->drupalGet('admin/config/regional/language/configure');
+
+    // Enable the language switcher block.
+    $edit = array('blocks[locale_language][region]' => 'sidebar_first');
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+
+    // Access the front page without specifying any valid URL language prefix
+    // and having as browser language preference a non-default language.
+    $http_header = array("Accept-Language: $language_browser_fallback;q=1");
+    $this->drupalGet('', array(), $http_header);
+
+    // Check that the language switcher active link matches the given browser
+    // language.
+    $args = array(':url' => base_path() . (!empty($GLOBALS['conf']['clean_url']) ? $language_browser_fallback : "?q=$language_browser_fallback"));
+    $fields = $this->xpath('//div[@id="block-locale-language"]//a[@class="language-link active" and @href=:url]', $args);
+    $this->assertTrue($fields[0] == $languages[$language_browser_fallback]->native, t('The browser language is the URL active language'));
+
+    // Check that URLs are rewritten using the given browser language.
+    $fields = $this->xpath('//div[@id="site-name"]//a[@rel="home" and @href=:url]//span', $args);
+    $this->assertTrue($fields[0] == 'Drupal', t('URLs are rewritten using the browser language.'));
+  }
+}
+
+/**
+ * Test that URL rewriting works as expected.
+ */
+class LocaleUrlRewritingTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'URL rewriting',
+      'description' => 'Test that URL rewriting works as expected.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+
+    // Create and login user.
+    $this->web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // Install French language.
+    $edit = array();
+    $edit['langcode'] = 'fr';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Install Italian language.
+    $edit = array();
+    $edit['langcode'] = 'it';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Disable Italian language.
+    $edit = array('enabled[it]' => FALSE);
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+
+    // Enable URL language detection and selection.
+    $edit = array('language[enabled][locale-url]' => 1);
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+
+    // Reset static caching.
+    drupal_static_reset('language_list');
+    drupal_static_reset('locale_url_outbound_alter');
+    drupal_static_reset('locale_language_url_rewrite_url');
+  }
+
+  /**
+   * Check that disabled or non-installed languages are not considered.
+   */
+  function testUrlRewritingEdgeCases() {
+    // Check URL rewriting with a disabled language.
+    $languages = language_list();
+    $this->checkUrl($languages['it'], t('Path language is ignored if language is disabled.'), t('URL language negotiation does not work with disabled languages'));
+
+    // Check URL rewriting with a non-installed language.
+    $non_existing = language_default();
+    $non_existing->language = $this->randomName();
+    $non_existing->prefix = $this->randomName();
+    $this->checkUrl($non_existing, t('Path language is ignored if language is not installed.'), t('URL language negotiation does not work with non-installed languages'));
+  }
+
+  /**
+   * Check URL rewriting for the given language.
+   *
+   * The test is performed with a fixed URL (the default front page) to simply
+   * check that language prefixes are not added to it and that the prefixed URL
+   * is actually not working.
+   */
+  private function checkUrl($language, $message1, $message2) {
+    $options = array('language' => $language);
+    $base_path = trim(base_path(), '/');
+    $rewritten_path = trim(str_replace(array('?q=', $base_path), '', url('node', $options)), '/');
+    $segments = explode('/', $rewritten_path, 2);
+    $prefix = $segments[0];
+    $path = isset($segments[1]) ? $segments[1] : $prefix;
+    // If the rewritten URL has not a language prefix we pick the right one from
+    // the language object so we can always check the prefixed URL.
+    if ($this->assertNotEqual($language->prefix, $prefix, $message1)) {
+      $prefix = $language->prefix;
+    }
+    $this->drupalGet("$prefix/$path");
+    $this->assertResponse(404, $message2);
+  }
 }
 
 /**
@@ -2088,4 +2349,3 @@ class LocaleDateFormatsFunctionalTest 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 1acc5b89c3803a448c17981faa4978a8d7286951..551f1d5616a98f5dcbafa62d693aa541a48f914b 100644
--- a/modules/locale/tests/locale_test.info
+++ b/modules/locale/tests/locale_test.info
@@ -1,14 +1,13 @@
-; $Id: locale_test.info,v 1.2 2009/04/26 15:14:55 dries Exp $
+; $Id: locale_test.info,v 1.3 2010/12/20 19:59:42 webchick Exp $
 name = "Locale Test"
 description = "Support module for the locale layer tests."
 core = 7.x
 package = Testing
-files[] = locale_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/menu/menu.info b/modules/menu/menu.info
index 172857dd280276ceaed962c0bcda275d5ea10f7f..0d6bf53084b862ccea16d62eb920e68c82b0ed49 100644
--- a/modules/menu/menu.info
+++ b/modules/menu/menu.info
@@ -1,17 +1,14 @@
-; $Id: menu.info,v 1.10 2009/11/17 21:24:18 dries Exp $
+; $Id: menu.info,v 1.11 2010/12/20 19:59:42 webchick Exp $
 name = Menu
 description = Allows administrators to customize the site navigation menu.
 package = Core
 version = VERSION
 core = 7.x
-files[] = menu.module
-files[] = menu.admin.inc
-files[] = menu.install
 files[] = menu.test
 configure = admin/structure/menu
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/menu/menu.js b/modules/menu/menu.js
index 10f1fac819ee17a02df802faad0bad58ddc4cce0..8123ecef27cd548ac6777ba41356cf1adabd49bc 100644
--- a/modules/menu/menu.js
+++ b/modules/menu/menu.js
@@ -1,12 +1,12 @@
-// $Id: menu.js,v 1.6 2010/04/09 12:24:53 dries Exp $
+// $Id: menu.js,v 1.7 2010/11/05 19:47:20 dries Exp $
 
 (function ($) {
 
 Drupal.behaviors.menuFieldsetSummaries = {
   attach: function (context) {
     $('fieldset.menu-link-form', context).drupalSetSummary(function (context) {
-      if ($('#edit-menu-enabled', context).attr('checked')) {
-        return Drupal.checkPlain($('#edit-menu-link-title', context).val());
+      if ($('.form-item-menu-enabled input', context).is(':checked')) {
+        return Drupal.checkPlain($('.form-item-menu-link-title input', context).val());
       }
       else {
         return Drupal.t('Not in menu');
@@ -20,44 +20,46 @@ Drupal.behaviors.menuFieldsetSummaries = {
  */
 Drupal.behaviors.menuLinkAutomaticTitle = {
   attach: function (context) {
-    // Try to find menu settings widget elements as well as a 'title' field in
-    // the form, but play nicely with user permissions and form alterations.
-    var $checkbox = $('fieldset.menu-link-form #edit-menu-enabled', context);
-    var $link_title = $('#edit-menu-link-title', context);
-    var $title = $('#edit-title', context);
-    // Bail out if we do not have all required fields.
-    if (!($checkbox.length && $link_title.length && $title.length)) {
-      return;
-    }
-    // If there is a link title already, mark it as overridden. The user expects
-    // that toggling the checkbox twice will take over the node's title.
-    if ($checkbox.attr('checked') && $link_title.val().length) {
-      $link_title.data('menuLinkAutomaticTitleOveridden', true);
-    }
-    // Whenever the value is changed manually, disable this behavior.
-    $link_title.keyup(function () {
-      $link_title.data('menuLinkAutomaticTitleOveridden', true);
-    });
-    // Global trigger on checkbox (do not fill-in a value when disabled).
-    $checkbox.change(function () {
-      if ($checkbox.attr('checked')) {
-        if (!$link_title.data('menuLinkAutomaticTitleOveridden')) {
-          $link_title.val($title.val());
-        }
-      }
-      else {
-        $link_title.val('');
-        $link_title.removeData('menuLinkAutomaticTitleOveridden');
+    $('fieldset.menu-link-form', context).each(function () {
+      // Try to find menu settings widget elements as well as a 'title' field in
+      // the form, but play nicely with user permissions and form alterations.
+      var $checkbox = $('.form-item-menu-enabled input', this);
+      var $link_title = $('.form-item-menu-link-title input', context);
+      var $title = $(this).closest('form').find('.form-item-title input');
+      // Bail out if we do not have all required fields.
+      if (!($checkbox.length && $link_title.length && $title.length)) {
+        return;
       }
-      $checkbox.closest('fieldset.vertical-tabs-pane').trigger('summaryUpdated');
-      $checkbox.trigger('formUpdated');
-    });
-    // Take over any title change.
-    $title.keyup(function () {
-      if (!$link_title.data('menuLinkAutomaticTitleOveridden') && $checkbox.attr('checked')) {
-        $link_title.val($title.val());
-        $link_title.val($title.val()).trigger('formUpdated');
+      // If there is a link title already, mark it as overridden. The user expects
+      // that toggling the checkbox twice will take over the node's title.
+      if ($checkbox.is(':checked') && $link_title.val().length) {
+        $link_title.data('menuLinkAutomaticTitleOveridden', true);
       }
+      // Whenever the value is changed manually, disable this behavior.
+      $link_title.keyup(function () {
+        $link_title.data('menuLinkAutomaticTitleOveridden', true);
+      });
+      // Global trigger on checkbox (do not fill-in a value when disabled).
+      $checkbox.change(function () {
+        if ($checkbox.is(':checked')) {
+          if (!$link_title.data('menuLinkAutomaticTitleOveridden')) {
+            $link_title.val($title.val());
+          }
+        }
+        else {
+          $link_title.val('');
+          $link_title.removeData('menuLinkAutomaticTitleOveridden');
+        }
+        $checkbox.closest('fieldset.vertical-tabs-pane').trigger('summaryUpdated');
+        $checkbox.trigger('formUpdated');
+      });
+      // Take over any title change.
+      $title.keyup(function () {
+        if (!$link_title.data('menuLinkAutomaticTitleOveridden') && $checkbox.is(':checked')) {
+          $link_title.val($title.val());
+          $link_title.val($title.val()).trigger('formUpdated');
+        }
+      });
     });
   }
 };
diff --git a/modules/node/node.admin.inc b/modules/node/node.admin.inc
index a1dfad52096c6a15ac0f5760712faafe2ef75ab9..795e8a71a5abe147d080fb448676579c8248ccae 100644
--- a/modules/node/node.admin.inc
+++ b/modules/node/node.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.admin.inc,v 1.101 2010/10/20 01:31:07 dries Exp $
+// $Id: node.admin.inc,v 1.103 2010/12/09 02:16:21 dries Exp $
 
 /**
  * @file
@@ -288,6 +288,8 @@ function node_mass_update($nodes, $updates) {
  */
 function _node_mass_update_helper($nid, $updates) {
   $node = node_load($nid, NULL, TRUE);
+  // For efficiency manually save the original node before applying any changes.
+  $node->original = clone $node;
   foreach ($updates as $name => $value) {
     $node->$name = $value;
   }
@@ -593,7 +595,7 @@ function node_multiple_delete_confirm_submit($form, &$form_state) {
     node_delete_multiple(array_keys($form_state['values']['nodes']));
     $count = count($form_state['values']['nodes']);
     watchdog('content', 'Deleted @count posts.', array('@count' => $count));
-    drupal_set_message(t('Deleted @count posts.', array('@count' => $count)));
+    drupal_set_message(format_plural($count, 'Deleted 1 post.', 'Deleted @count posts.'));
   }
   $form_state['redirect'] = 'admin/content';
 }
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index 980a748ea1f5cfa86ed72463f14367ae59e385b4..8e3c0b0d382c8c29d3a3c430f48a9395bc69258f 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.api.php,v 1.78 2010/10/22 00:35:35 dries Exp $
+// $Id: node.api.php,v 1.83 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -9,9 +9,7 @@
 /**
  * @defgroup node_api_hooks Node API Hooks
  * @{
- * The Node API allows modules to define content types, to modify content
- * types created in the user interface, and to modify content types created by
- * other modules.
+ * Functions to define and modify content types.
  *
  * Each content type is maintained by a primary module, which is either
  * node.module (for content types created in the user interface) or the
@@ -143,6 +141,38 @@
  * module's responsibility to provide appropriate realms to limit access to
  * unpublished content.
  *
+ * Node access records are stored in the {node_access} table and define which
+ * grants are required to access a node. There is a special case for the view
+ * operation -- a record with node ID 0 corresponds to a "view all" grant for
+ * the realm and grant ID of that record. If there are no node access modules
+ * enabled, the core node module adds a node ID 0 record for realm 'all'. Node
+ * access modules can also grant "view all" permission on their custom realms;
+ * for example, a module could create a record in {node_access} with:
+ * @code
+ * $record = array(
+ *   'nid' => 0,
+ *   'gid' => 888,
+ *   'realm' => 'example_realm',
+ *   'grant_view' => 1,
+ *   'grant_update' => 0,
+ *   'grant_delete' => 0,
+ * );
+ * drupal_write_record('node_access', $record);
+ * @endcode
+ * And then in its hook_node_grants() implementation, it would need to return:
+ * @code
+ * if ($op == 'view') {
+ *   $grants['example_realm'] = array(888);
+ * }
+ * @endcode
+ * If you decide to do this, be aware that the node_access_rebuild() function
+ * will erase any node ID 0 entry when it is called, so you will need to make
+ * sure to restore your {node_access} record after node_access_rebuild() is
+ * called.
+ *
+ * @see node_access_view_all_nodes()
+ * @see node_access_rebuild()
+ *
  * @param $account
  *   The user object whose grants are requested.
  * @param $op
@@ -759,6 +789,8 @@ function hook_node_submit($node, $form, &$form_state) {
  * @param $langcode
  *   The language code used for rendering.
  *
+ * @see hook_entity_view()
+ *
  * @ingroup node_api_hooks
  */
 function hook_node_view($node, $view_mode, $langcode) {
@@ -785,6 +817,7 @@ function hook_node_view($node, $view_mode, $langcode) {
  *   A renderable array representing the node content.
  *
  * @see node_view()
+ * @see hook_entity_view_alter()
  *
  * @ingroup node_api_hooks
  */
@@ -841,8 +874,6 @@ function hook_node_view_alter(&$build) {
  * 'locked') can be edited by a site administrator. This includes the
  * machine-readable name of a node type, if 'locked' is set to FALSE.
  *
- * For a detailed usage example, see node_example.module.
- *
  * @ingroup node_api_hooks
  */
 function hook_node_info() {
@@ -1221,7 +1252,7 @@ function hook_view($node, $view_mode) {
   }
 
   $node->content['myfield'] = array(
-    '#value' => theme('mymodule_myfield', $node->myfield),
+    '#markup' => theme('mymodule_myfield', $node->myfield),
     '#weight' => 1,
   );
 
diff --git a/modules/node/node.info b/modules/node/node.info
index 81d485de1407926f396757023931bd4eca1918a7..86e60d158a7f6e671981ae533f07a7f3d5956831 100644
--- a/modules/node/node.info
+++ b/modules/node/node.info
@@ -1,22 +1,17 @@
-; $Id: node.info,v 1.14 2010/09/05 02:21:38 dries Exp $
+; $Id: node.info,v 1.15 2010/12/20 19:59:42 webchick Exp $
 name = Node
 description = Allows content to be submitted to the site and displayed on pages.
 package = Core
 version = VERSION
 core = 7.x
 files[] = node.module
-files[] = content_types.inc
-files[] = node.admin.inc
-files[] = node.pages.inc
-files[] = node.install
 files[] = node.test
-files[] = node.tokens.inc
 required = TRUE
 configure = admin/structure/types
 stylesheets[all][] = node.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/node/node.install b/modules/node/node.install
index 1f429760dc6131d854e5e94feb9674f4c5f59f2e..fe6661cdaaafacb928585b4fde1f8470299cc19b 100644
--- a/modules/node/node.install
+++ b/modules/node/node.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.install,v 1.60 2010/10/07 00:28:20 webchick Exp $
+// $Id: node.install,v 1.62 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -446,7 +446,7 @@ function _update_7000_node_get_types() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x System updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -521,7 +521,7 @@ function node_update_7004() {
 
   // Map old preview setting to new values order.
   $original_preview ? $original_preview = 2 : $original_preview = 1;
-  drupal_static_reset('_node_types_build');
+  node_type_cache_reset();
 
   // Apply original settings to all types.
   foreach (_update_7000_node_get_types() as $type => $type_object) {
@@ -552,7 +552,7 @@ function node_update_7006(&$sandbox) {
   $sandbox['#finished'] = 0;
 
   // Get node type info for every invocation.
-  drupal_static_reset('_node_types_build');
+  node_type_cache_reset();
 
   if (!isset($sandbox['total'])) {
     // Initial invocation.
@@ -804,6 +804,5 @@ function node_update_7010() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/node/node.js b/modules/node/node.js
index 872729faeb658230e5d629f329d00d4d59c34f09..a5961f9793d3afb2d26710869c44c7a0314b02a0 100644
--- a/modules/node/node.js
+++ b/modules/node/node.js
@@ -1,31 +1,39 @@
-// $Id: node.js,v 1.6 2010/05/04 16:03:34 dries Exp $
+// $Id: node.js,v 1.8 2010/12/15 03:42:25 webchick Exp $
 
 (function ($) {
 
 Drupal.behaviors.nodeFieldsetSummaries = {
   attach: function (context) {
-    $('fieldset#edit-revision-information', context).drupalSetSummary(function (context) {
-      return $('#edit-revision', context).is(':checked') ?
-        Drupal.t('New revision') :
-        Drupal.t('No revision');
+    $('fieldset.node-form-revision-information', context).drupalSetSummary(function (context) {
+      var revisionCheckbox = $('.form-item-revision input', context);
+
+      // Return 'New revision' if the 'Create new revision' checkbox is checked,
+      // or if the checkbox doesn't exist, but the revision log does. For users
+      // without the "Administer content" permission the checkbox won't appear,
+      // but the revision log will if the content type is set to auto-revision.
+      if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $('.form-item-log textarea', context).length)) {
+        return Drupal.t('New revision');
+      }
+
+      return Drupal.t('No revision');
     });
 
-    $('fieldset#edit-author', context).drupalSetSummary(function (context) {
-      var name = $('#edit-name').val() || Drupal.settings.anonymous,
-        date = $('#edit-date').val();
+    $('fieldset.node-form-author', context).drupalSetSummary(function (context) {
+      var name = $('.form-item-name input', context).val() || Drupal.settings.anonymous,
+        date = $('.form-item-date input', context).val();
       return date ?
         Drupal.t('By @name on @date', { '@name': name, '@date': date }) :
         Drupal.t('By @name', { '@name': name });
     });
 
-    $('fieldset#edit-options', context).drupalSetSummary(function (context) {
+    $('fieldset.node-form-options', context).drupalSetSummary(function (context) {
       var vals = [];
 
       $('input:checked', context).parent().each(function () {
         vals.push(Drupal.checkPlain($.trim($(this).text())));
       });
 
-      if (!$('#edit-status', context).is(':checked')) {
+      if (!$('.form-item-status input', context).is(':checked')) {
         vals.unshift(Drupal.t('Not published'));
       }
       return vals.join(', ');
diff --git a/modules/node/node.module b/modules/node/node.module
index acf4d1d9a7ec548429bcf027f62c95eefdce9f12..bafb54f33aa1318cba1c03ed892782930fe593ce 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.module,v 1.1309 2010/10/20 08:15:33 webchick Exp $
+// $Id: node.module,v 1.1336 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -255,16 +255,18 @@ function node_uri($node) {
  * Implements hook_admin_paths().
  */
 function node_admin_paths() {
-  $paths = array(
-    'node/*/edit' => TRUE,
-    'node/*/delete' => TRUE,
-    'node/*/revisions' => TRUE,
-    'node/*/revisions/*/revert' => TRUE,
-    'node/*/revisions/*/delete' => TRUE,
-    'node/add' => TRUE,
-    'node/add/*' => TRUE,
-  );
-  return $paths;
+  if (variable_get('node_admin_theme')) {
+    $paths = array(
+      'node/*/edit' => TRUE,
+      'node/*/delete' => TRUE,
+      'node/*/revisions' => TRUE,
+      'node/*/revisions/*/revert' => TRUE,
+      'node/*/revisions/*/delete' => TRUE,
+      'node/add' => TRUE,
+      'node/add/*' => TRUE,
+    );
+    return $paths;
+  }
 }
 
 /**
@@ -376,7 +378,7 @@ function _node_extract_type($node) {
  * See _node_types_build() for details.
  *
  * @return
- *   An array of node types, keyed by the type.
+ *   An array of node types, as objects, keyed by the type.
  *
  * @see node_type_get_type()
  */
@@ -533,7 +535,7 @@ function node_type_save($info) {
   }
 
   // Clear the node type cache.
-  drupal_static_reset('_node_types_build');
+  node_type_cache_reset();
 
   return $status;
 }
@@ -624,7 +626,7 @@ function node_type_delete($type) {
   module_invoke_all('node_type_delete', $info);
 
   // Clear the node type cache.
-  drupal_static_reset('_node_types_build');
+  node_type_cache_reset();
 }
 
 /**
@@ -669,14 +671,20 @@ function node_type_update_nodes($old_type, $type) {
  *   type object by $type->disabled being set to TRUE.
  */
 function _node_types_build($rebuild = FALSE) {
+  $cid = 'node_types:' . $GLOBALS['language']->language;
+
   if (!$rebuild) {
     $_node_types = &drupal_static(__FUNCTION__);
-    if (is_object($_node_types)) {
+    if (isset($_node_types)) {
+      return $_node_types;
+    }
+    if ($cache = cache_get($cid)) {
+      $_node_types = $cache->data;
       return $_node_types;
     }
   }
 
-  $_node_types = (object)array('types' => array(), 'names' => array());
+  $_node_types = (object) array('types' => array(), 'names' => array());
 
   foreach (module_implements('node_info') as $module) {
     $info_array = module_invoke($module, 'node_info');
@@ -703,10 +711,10 @@ function _node_types_build($rebuild = FALSE) {
     // Types defined by the node module in the database (rather than by a separate
     // module using hook_node_info) have a base value of 'node_content'. The isset()
     // check prevents errors on old (pre-Drupal 7) databases.
-    if (isset($type_object->base) && $type_object->base != 'node_content' && empty($info_array[$type_db])) {
+    if (isset($type_object->base) && $type_object->base != 'node_content' && empty($_node_types->types[$type_db])) {
       $type_object->disabled = TRUE;
     }
-    if (isset($info_array[$type_db])) {
+    if (isset($_node_types->types[$type_db])) {
       $type_object->disabled = FALSE;
     }
     if (!isset($_node_types->types[$type_db]) || $type_object->modified) {
@@ -732,9 +740,19 @@ function _node_types_build($rebuild = FALSE) {
 
   asort($_node_types->names);
 
+  cache_set($cid, $_node_types);
+
   return $_node_types;
 }
 
+/**
+ * Clears the node type cache.
+ */
+function node_type_cache_reset() {
+  cache_clear_all('node_types:', 'cache', TRUE);
+  drupal_static_reset('_node_types_build');
+}
+
 /**
  * Set the default values for a node type.
  *
@@ -746,33 +764,26 @@ function _node_types_build($rebuild = FALSE) {
  *   An object or array containing values to override the defaults.
  *
  * @return
- *  A node type object.
+ *   A node type object.
  */
 function node_type_set_defaults($info = array()) {
-  $type = &drupal_static(__FUNCTION__);
-
-  if (!isset($type)) {
-    $type = new stdClass();
-    $type->type = '';
-    $type->name = '';
-    $type->base = '';
-    $type->description = '';
-    $type->help = '';
-    $type->custom = 0;
-    $type->modified = 0;
-    $type->locked = 1;
-    $type->disabled = 0;
-    $type->is_new = 1;
-
-    $type->has_title = 1;
-    $type->title_label = 'Title';
-  }
-
-  $new_type = clone $type;
   $info = (array) $info;
-  foreach ($info as $key => $data) {
-    $new_type->$key = $data;
-  }
+  $new_type = $info + array(
+    'type' => '',
+    'name' => '',
+    'base' => '',
+    'description' => '',
+    'help' => '',
+    'custom' => 0,
+    'modified' => 0,
+    'locked' => 1,
+    'disabled' => 0,
+    'is_new' => 1,
+    'has_title' => 1,
+    'title_label' => 'Title',
+  );
+  $new_type = (object) $new_type;
+
   // If the type has no title, set an empty label.
   if (!$new_type->has_title) {
     $new_type->title_label = '';
@@ -875,16 +886,23 @@ function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
  * database access if loaded again during the same page request.
  *
  * @see entity_load()
+ * @see EntityFieldQuery
  *
  * @param $nids
  *   An array of node IDs.
  * @param $conditions
- *   An array of conditions on the {node} table in the form 'field' => $value.
+ *   (deprecated) An associative array of conditions on the {node}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have. Instead, it is preferable to use
+ *   EntityFieldQuery to retrieve a list of entity IDs loadable by
+ *   this function.
  * @param $reset
  *   Whether to reset the internal node_load cache.
  *
  * @return
  *   An array of node objects indexed by nid.
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function node_load_multiple($nids = array(), $conditions = array(), $reset = FALSE) {
   return entity_load('node', $nids, $conditions, $reset);
@@ -1014,6 +1032,11 @@ function node_save($node) {
   $transaction = db_transaction();
 
   try {
+    // Load the stored entity, if any.
+    if (!empty($node->nid) && !isset($node->original)) {
+      $node->original = entity_load_unchanged('node', $node->nid);
+    }
+
     field_attach_presave('node', $node);
     global $user;
 
@@ -1035,6 +1058,7 @@ function node_save($node) {
 
     // Let modules modify the node before it is saved to the database.
     module_invoke_all('node_presave', $node);
+    module_invoke_all('entity_presave', $node, 'node');
 
     if ($node->is_new || !empty($node->revision)) {
       // When inserting either a new node or a new node revision, $node->log
@@ -1117,13 +1141,16 @@ function node_save($node) {
 
     // Clear internal properties.
     unset($node->is_new);
+    unset($node->original);
+    // Clear the static loading cache.
+    entity_get_controller('node')->resetCache(array($node->nid));
 
     // Ignore slave server temporarily to give time for the
     // saved node to be propagated to the slave.
     db_ignore_slave();
   }
   catch (Exception $e) {
-    $transaction->rollback('node');
+    $transaction->rollback();
     watchdog_exception('node', $e);
     throw $e;
   }
@@ -1132,8 +1159,7 @@ function node_save($node) {
 /**
  * Helper function to save a revision with the uid of the current user.
  *
- * Node is taken by reference, because drupal_write_record() updates the
- * $node with the revision id, and we need to pass that back to the caller.
+ * The resulting revision ID is available afterward in $node->vid.
  */
 function _node_save_revision($node, $uid, $update = NULL) {
   $temp_uid = $node->uid;
@@ -1144,6 +1170,7 @@ function _node_save_revision($node, $uid, $update = NULL) {
   else {
     drupal_write_record('node_revision', $node);
   }
+  // Have node object still show node owner's uid, not revision author's.
   $node->uid = $temp_uid;
 }
 
@@ -1164,41 +1191,48 @@ function node_delete($nid) {
  *   An array of node IDs.
  */
 function node_delete_multiple($nids) {
+  $transaction = db_transaction();
   if (!empty($nids)) {
     $nodes = node_load_multiple($nids, array());
 
-    foreach ($nodes as $nid => $node) {
-      // Call the node-specific callback (if any):
-      node_invoke($node, 'delete');
-      module_invoke_all('node_delete', $node);
-      module_invoke_all('entity_delete', $node, 'node');
-      field_attach_delete('node', $node);
-
-      // Remove this node from the search index if needed.
-      // This code is implemented in node module rather than in search module,
-      // because node module is implementing search module's API, not the other
-      // way around.
-      if (module_exists('search')) {
-        search_reindex($nid, 'node');
+    try {
+      foreach ($nodes as $nid => $node) {
+        // Call the node-specific callback (if any):
+        node_invoke($node, 'delete');
+        module_invoke_all('node_delete', $node);
+        module_invoke_all('entity_delete', $node, 'node');
+        field_attach_delete('node', $node);
+
+        // Remove this node from the search index if needed.
+        // This code is implemented in node module rather than in search module,
+        // because node module is implementing search module's API, not the other
+        // way around.
+        if (module_exists('search')) {
+          search_reindex($nid, 'node');
+        }
       }
-    }
 
-    // Delete after calling hooks so that they can query node tables as needed.
-    db_delete('node')
-      ->condition('nid', $nids, 'IN')
-      ->execute();
-    db_delete('node_revision')
-      ->condition('nid', $nids, 'IN')
-      ->execute();
-    db_delete('history')
-      ->condition('nid', $nids, 'IN')
-      ->execute();
-    db_delete('node_access')
-      ->condition('nid', $nids, 'IN')
-      ->execute();
+      // Delete after calling hooks so that they can query node tables as needed.
+      db_delete('node')
+        ->condition('nid', $nids, 'IN')
+        ->execute();
+      db_delete('node_revision')
+        ->condition('nid', $nids, 'IN')
+        ->execute();
+      db_delete('history')
+        ->condition('nid', $nids, 'IN')
+        ->execute();
+      db_delete('node_access')
+       ->condition('nid', $nids, 'IN')
+       ->execute();
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('node', $e);
+      throw $e;
+    }
 
     // Clear the page and block and node_load_multiple caches.
-    cache_clear_all();
     entity_get_controller('node')->resetCache();
   }
 }
@@ -1270,7 +1304,8 @@ function node_view($node, $view_mode = 'full', $langcode = NULL) {
   }
 
   // Allow modules to modify the structured node.
-  drupal_alter('node_view', $build);
+  $type = 'node';
+  drupal_alter(array('node_view', 'entity_view'), $build, $type);
 
   return $build;
 }
@@ -1328,21 +1363,29 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
   // Always display a read more link on teasers because we have no way
   // to know when a teaser view is different than a full view.
   $links = array();
+  $node->content['links'] = array(
+    '#theme' => 'links__node',
+    '#pre_render' => array('drupal_pre_render_links'),
+    '#attributes' => array('class' => array('links', 'inline')),
+  );
   if ($view_mode == 'teaser') {
+    $node_title_stripped = strip_tags($node->title);
     $links['node-readmore'] = array(
-      'title' => t('Read more'),
+      'title' => t('Read more<span class="element-invisible"> about @title</span>', array('@title' => $node_title_stripped)),
       'href' => 'node/' . $node->nid,
-      'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
+      'html' => TRUE,
+      'attributes' => array('rel' => 'tag', 'title' => $node_title_stripped),
     );
   }
-  $node->content['links'] = array(
-    '#theme' => 'links__node',
+  $node->content['links']['node'] = array(
+    '#theme' => 'links__node__node',
     '#links' => $links,
     '#attributes' => array('class' => array('links', 'inline')),
   );
 
   // Allow modules to make their own additions to the node.
   module_invoke_all('node_view', $node, $view_mode, $langcode);
+  module_invoke_all('entity_view', $node, 'node', $view_mode, $langcode);
 }
 
 /**
@@ -1425,10 +1468,12 @@ function template_preprocess_node(&$variables) {
   // Display post information only on certain node types.
   if (variable_get('node_submitted_' . $node->type, TRUE)) {
     $variables['display_submitted'] = TRUE;
+    $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['name'], '!datetime' => $variables['date']));
     $variables['user_picture'] = theme_get_setting('toggle_node_user_picture') ? theme('user_picture', array('account' => $node)) : '';
   }
   else {
     $variables['display_submitted'] = FALSE;
+    $variables['submitted'] = '';
     $variables['user_picture'] = '';
   }
 
@@ -1460,6 +1505,11 @@ function template_preprocess_node(&$variables) {
  */
 function node_permission() {
   $perms = array(
+    'bypass node access' => array(
+      'title' => t('Bypass content access control'),
+      'description' => t('View, edit and delete all content regardless of permission restrictions.'),
+      'restrict access' => TRUE,
+    ),
     'administer content types' => array(
       'title' => t('Administer content types'),
       'restrict access' => TRUE,
@@ -1468,16 +1518,14 @@ function node_permission() {
       'title' => t('Administer content'),
       'restrict access' => TRUE,
     ),
-    'access content' => array(
-      'title' => t('View published content'),
-    ),
     'access content overview' => array(
       'title' => t('Access the content overview page'),
     ),
-    'bypass node access' => array(
-      'title' => t('Bypass content access control'),
-      'description' => t('View, edit and delete all content regardless of permission restrictions.'),
-      'restrict access' => TRUE,
+    'access content' => array(
+      'title' => t('View published content'),
+    ),
+    'view own unpublished content' => array(
+      'title' => t('View own unpublished content'),
     ),
     'view revisions' => array(
       'title' => t('View content revisions'),
@@ -1488,9 +1536,6 @@ function node_permission() {
     'delete revisions' => array(
       'title' => t('Delete content revisions'),
     ),
-    'view own unpublished content' => array(
-      'title' => t('View own unpublished content'),
-    ),
   );
 
   // Generate standard node permissions for all applicable node types.
@@ -1640,6 +1685,7 @@ function node_search_execute($keys = NULL, $conditions = NULL) {
       'extra' => $extra,
       'score' => $item->calculated_score,
       'snippet' => search_excerpt($keys, $node->rendered),
+      'language' => $node->language,
     );
   }
   return $results;
@@ -1834,7 +1880,6 @@ function node_menu() {
   );
   $items['admin/content/node'] = array(
     'title' => 'Content',
-    'description' => "Administer content",
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'weight' => -10,
   );
@@ -1893,16 +1938,13 @@ function node_menu() {
   $items['node'] = array(
     'page callback' => 'node_page_default',
     'access arguments' => array('access content'),
-    // Required to make 'node/add' appear on the top-level of 'navigation' menu.
-    'menu_name' => '',
+    'menu_name' => 'navigation',
     'type' => MENU_CALLBACK,
   );
   $items['node/add'] = array(
     'title' => 'Add content',
     'page callback' => 'node_add_page',
     'access callback' => '_node_add_access',
-    'menu_name' => 'navigation',
-    'theme callback' => '_node_custom_theme',
     'file' => 'node.pages.inc',
   );
   $items['rss.xml'] = array(
@@ -1914,7 +1956,7 @@ function node_menu() {
   // @todo Remove this loop when we have a 'description callback' property.
   // Reset internal static cache of _node_types_build(), forces to rebuild the
   // node type information.
-  drupal_static_reset('_node_types_build');
+  node_type_cache_reset();
   foreach (node_type_get_types() as $type) {
     $type_url_str = str_replace('_', '-', $type->type);
     $items['node/add/' . $type_url_str] = array(
@@ -1949,7 +1991,6 @@ function node_menu() {
     'page arguments' => array(1),
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
-    'theme callback' => '_node_custom_theme',
     'weight' => 0,
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
@@ -1961,7 +2002,6 @@ function node_menu() {
     'page arguments' => array('node_delete_confirm', 1),
     'access callback' => 'node_access',
     'access arguments' => array('delete', 1),
-    'theme callback' => '_node_custom_theme',
     'weight' => 1,
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_INLINE,
@@ -1973,7 +2013,6 @@ function node_menu() {
     'page arguments' => array(1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1),
-    'theme callback' => '_node_custom_theme',
     'weight' => 2,
     'type' => MENU_LOCAL_TASK,
     'file' => 'node.pages.inc',
@@ -1993,7 +2032,6 @@ function node_menu() {
     'page arguments' => array('node_revision_revert_confirm', 1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1, 'update'),
-    'theme callback' => '_node_custom_theme',
     'file' => 'node.pages.inc',
   );
   $items['node/%node/revisions/%/delete'] = array(
@@ -2003,7 +2041,6 @@ function node_menu() {
     'page arguments' => array('node_revision_delete_confirm', 1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1, 'delete'),
-    'theme callback' => '_node_custom_theme',
     'file' => 'node.pages.inc',
   );
   return $items;
@@ -2039,17 +2076,6 @@ function node_page_title($node) {
   return $node->title;
 }
 
-/**
- * Theme callback for creating and editing nodes.
- */
-function _node_custom_theme() {
-  // Use the administration theme if the site is configured to use it for
-  // nodes.
-  if (variable_get('node_admin_theme')) {
-    return variable_get('admin_theme');
-  }
-}
-
 function node_last_changed($nid) {
   return db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetch()->changed;
 }
@@ -2076,6 +2102,7 @@ function node_block_info() {
   $blocks['syndicate']['cache'] = DRUPAL_NO_CACHE;
 
   $blocks['recent']['info'] = t('Recent content');
+  $blocks['recent']['properties']['administrative'] = TRUE;
 
   return $blocks;
 }
@@ -2521,8 +2548,8 @@ function node_page_default() {
     $nodes = node_load_multiple($nids);
     $build = node_view_multiple($nodes);
 
-    $feed_url = url('rss.xml', array('absolute' => TRUE));
-    drupal_add_feed($feed_url, variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
+    // 'rss.xml' is a path, not a file, registered in node_menu().
+    drupal_add_feed('rss.xml', variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
     $build['pager'] = array(
       '#theme' => 'pager',
       '#weight' => 5,
@@ -2660,12 +2687,15 @@ function node_form_search_form_alter(&$form, $form_state) {
       '#value' => t('Advanced search'),
       '#prefix' => '<div class="action">',
       '#suffix' => '</div>',
+      '#weight' => 100,
     );
 
     // Languages:
     $language_options = array();
     foreach (language_list('language') as $key => $entity) {
-      $language_options[$key] = $entity->name;
+      if ($entity->enabled) {
+        $language_options[$key] = $entity->name;
+      }
     }
     if (count($language_options) > 1) {
       $form['advanced']['language'] = array(
@@ -2701,8 +2731,11 @@ function node_search_validate($form, &$form_state) {
   if (isset($form_state['values']['term']) && is_array($form_state['values']['term']) && count($form_state['values']['term'])) {
     $keys = search_expression_insert($keys, 'term', implode(',', $form_state['values']['term']));
   }
-  if (isset($form_state['values']['language']) && is_array($form_state['values']['language']) && count($form_state['values']['language'])) {
-    $keys = search_expression_insert($keys, 'language', implode(',', array_filter($form_state['values']['language'])));
+  if (isset($form_state['values']['language']) && is_array($form_state['values']['language'])) {
+    $languages = array_filter($form_state['values']['language']);
+    if (count($languages)) {
+      $keys = search_expression_insert($keys, 'language', implode(',', $languages));
+    }
   }
   if ($form_state['values']['or'] != '') {
     if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_state['values']['or'], $matches)) {
@@ -2923,19 +2956,19 @@ function node_list_permissions($type) {
   // Build standard list of node permissions for this type.
   $perms = array(
     "create $type content" => array(
-      'title' => t('Create new %type_name content', array('%type_name' => $info->name)),
+      'title' => t('%type_name: Create new content', array('%type_name' => $info->name)),
     ),
     "edit own $type content" => array(
-      'title' => t('Edit own %type_name content', array('%type_name' => $info->name)),
+      'title' => t('%type_name: Edit own content', array('%type_name' => $info->name)),
     ),
     "edit any $type content" => array(
-      'title' => t('Edit any %type_name content', array('%type_name' => $info->name)),
+      'title' => t('%type_name: Edit any content', array('%type_name' => $info->name)),
     ),
     "delete own $type content" => array(
-      'title' => t('Delete own %type_name content', array('%type_name' => $info->name)),
+      'title' => t('%type_name: Delete own content', array('%type_name' => $info->name)),
     ),
     "delete any $type content" => array(
-      'title' => t('Delete any %type_name content', array('%type_name' => $info->name)),
+      'title' => t('%type_name: Delete any content', array('%type_name' => $info->name)),
     ),
   );
 
@@ -3004,42 +3037,68 @@ function node_access_grants($op, $account = NULL) {
 }
 
 /**
- * Determine whether the user has a global viewing grant for all nodes.
+ * Determines whether the user has a global viewing grant for all nodes.
+ *
+ * Checks to see whether any module grants global 'view' access to a user
+ * account; global 'view' access is encoded in the {node_access} table as a
+ * grant with nid=0. If no node access modules are enabled, node.module defines
+ * such a global 'view' access grant.
+ *
+ * This function is called when a node listing query is tagged with
+ * 'node_access'; when this function returns TRUE, no node access joins are
+ * added to the query.
+ *
+ * @param $account
+ *   The user object for the user whose access is being checked. If omitted,
+ *   the current user is used.
+ *
+ * @return
+ *   TRUE if 'view' access to all nodes is granted, FALSE otherwise.
+ *
+ * @see hook_node_grants()
+ * @see _node_query_node_access_alter()
  */
-function node_access_view_all_nodes() {
-  $access = &drupal_static(__FUNCTION__);
+function node_access_view_all_nodes($account = NULL) {
+  global $user;
+  if (!$account) {
+    $account = $user;
+  }
 
-  if (!isset($access)) {
-    // If no modules implement the node access system, access is always true.
-    if (!module_implements('node_grants')) {
-      $access = TRUE;
-    }
-    else {
-      $query = db_select('node_access');
-      $query->addExpression('COUNT(*)');
-      $query
-        ->condition('nid', 0)
-        ->condition('grant_view', 1, '>=');
+  // Statically cache results in an array keyed by $account->uid.
+  $access = &drupal_static(__FUNCTION__);
+  if (isset($access[$account->uid])) {
+    return $access[$account->uid];
+  }
 
-      $grants = db_or();
-      foreach (node_access_grants('view') as $realm => $gids) {
-        foreach ($gids as $gid) {
-          $grants->condition(db_and()
-            ->condition('gid', $gid)
-            ->condition('realm', $realm)
-          );
-        }
-      }
-      if (count($grants) > 0 ) {
-        $query->condition($grants);
-      }
-      $access = $query
-        ->execute()
-        ->fetchField();
+  // If no modules implement the node access system, access is always TRUE.
+  if (!module_implements('node_grants')) {
+    $access[$account->uid] = TRUE;
+  }
+  else {
+    $query = db_select('node_access');
+    $query->addExpression('COUNT(*)');
+    $query
+      ->condition('nid', 0)
+      ->condition('grant_view', 1, '>=');
+
+    $grants = db_or();
+    foreach (node_access_grants('view', $account) as $realm => $gids) {
+      foreach ($gids as $gid) {
+        $grants->condition(db_and()
+          ->condition('gid', $gid)
+          ->condition('realm', $realm)
+        );
       }
+    }
+    if (count($grants) > 0 ) {
+      $query->condition($grants);
+    }
+    $access[$account->uid] = $query
+      ->execute()
+      ->fetchField();
   }
 
-  return $access;
+  return $access[$account->uid];
 }
 
 
@@ -3090,14 +3149,18 @@ function _node_query_node_access_alter($query, $base_table, $type) {
     $op = 'view';
   }
 
-  // If $account can bypass node access, or there are no node access
-  // modules, we don't need to alter the query.
+  // If $account can bypass node access, or there are no node access modules,
+  // or the operation is 'view' and the $acount has a global view grant (i.e.,
+  // a view grant for node ID 0), we don't need to alter the query.
   if (user_access('bypass node access', $account)) {
     return;
   }
   if (!count(module_implements('node_grants'))) {
     return;
   }
+  if ($op == 'view' && node_access_view_all_nodes($account)) {
+    return;
+  }
 
   // Prevent duplicate records.
   $query->distinct();
@@ -3174,13 +3237,12 @@ function _node_query_node_access_alter($query, $base_table, $type) {
   if ($type == 'entity' && count($entity_conditions->conditions())) {
     // All the node access conditions are only for field values belonging to
     // nodes.
-    $etid = variable_get('field_sql_storage_node_etid');
-    $entity_conditions->condition("$base_alias.etid", $etid);
+    $entity_conditions->condition("$base_alias.entity_type", 'node');
     $or = db_or();
     $or->condition($entity_conditions);
     // If the field value belongs to a non-node entity type then this function
     // does not do anything with it.
-    $or->condition("$base_alias.etid", $etid, '<>');
+    $or->condition("$base_alias.entity_type", 'node', '<>');
     // Add the compiled set of rules to the query.
     $query->condition($or);
   }
@@ -3429,8 +3491,9 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
 
 
 /**
- * @defgroup node_content Hook implementations for user-created content types.
+ * @defgroup node_content Hook implementations for user-created content types
  * @{
+ * Functions that implement hooks for user-created content types.
  */
 
 /**
@@ -3792,7 +3855,10 @@ class NodeController extends DrupalDefaultEntityController {
         $function($nodes_of_type);
       }
     }
-    $this->hookLoadArguments[] = array_keys($typed_nodes);
+    // Besides the list of nodes, pass one additional argument to
+    // hook_node_load(), containing a list of node types that were loaded.
+    $argument = array_keys($typed_nodes);
+    $this->hookLoadArguments = array($argument);
     parent::attachLoad($nodes, $revision_id);
   }
 
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index 7d98fdf574b00e1e9fc61ce3b8a34282d8760f48..1b0e3fd03f71f41781a6d159c9eb70b042ce12ee 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.pages.inc,v 1.132 2010/09/09 23:01:48 dries Exp $
+// $Id: node.pages.inc,v 1.136 2010/11/26 19:23:01 dries Exp $
 
 /**
  * @file
@@ -56,21 +56,15 @@ function theme_node_add_list($variables) {
 
 
 /**
- * Present a node submission form or a set of links to such forms.
+ * Returns a node submission form.
  */
 function node_add($type) {
   global $user;
 
   $types = node_type_get_types();
-  $type = isset($type) ? str_replace('-', '_', $type) : NULL;
-  // 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);
-
-    drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
-    $output = drupal_get_form($type . '_node_form', $node);
-  }
+  $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);
 
   return $output;
 }
@@ -144,7 +138,9 @@ function node_form($form, &$form_state, $node) {
   if (function_exists($function) && ($extra = $function($node, $form_state))) {
     $form = array_merge_recursive($form, $extra);
   }
-  if (!isset($form['title']['#weight'])) {
+  // If the node type has a title, and the node type form defined no special
+  // weight for it, we default to a weight of -5 for consistency.
+  if (isset($form['title']) && !isset($form['title']['#weight'])) {
     $form['title']['#weight'] = -5;
   }
   // @todo D8: Remove. Modules should access the node using $form_state['node'].
@@ -164,6 +160,9 @@ function node_form($form, &$form_state, $node) {
     // Collapsed by default when "Create new revision" is unchecked
     '#collapsed' => !$node->revision,
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('node-form-revision-information'),
+    ),
     '#attached' => array(
       'js' => array(drupal_get_path('module', 'node') . '/node.js'),
     ),
@@ -202,6 +201,9 @@ function node_form($form, &$form_state, $node) {
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('node-form-author'),
+    ),
     '#attached' => array(
       'js' => array(
         drupal_get_path('module', 'node') . '/node.js',
@@ -238,6 +240,9 @@ function node_form($form, &$form_state, $node) {
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('node-form-options'),
+    ),
     '#attached' => array(
       'js' => array(drupal_get_path('module', 'node') . '/node.js'),
     ),
@@ -295,9 +300,7 @@ function node_form($form, &$form_state, $node) {
   }
   $form += array('#submit' => array());
 
-  $form['#builder_function'] = 'node_form_submit_build_node';
   field_attach_form('node', $node, $form, $form_state, $node->language);
-
   return $form;
 }
 
@@ -316,7 +319,7 @@ function node_form_delete_submit($form, &$form_state) {
 
 
 function node_form_build_preview($form, &$form_state) {
-  $node = $form['#builder_function']($form, $form_state);
+  $node = node_form_submit_build_node($form, $form_state);
   $form_state['node_preview'] = node_preview($node);
   $form_state['rebuild'] = TRUE;
 }
@@ -399,7 +402,7 @@ function theme_node_preview($variables) {
 }
 
 function node_form_submit($form, &$form_state) {
-  $node = $form['#builder_function']($form, $form_state);
+  $node = node_form_submit_build_node($form, $form_state);
   $insert = empty($node->nid);
   node_save($node);
   $node_link = l(t('view'), 'node/' . $node->nid);
@@ -432,7 +435,7 @@ function node_form_submit($form, &$form_state) {
 /**
  * Updates the form state's node entity by processing this submission's values.
  *
- * This is the default #builder_function for the node form. It is called
+ * This is the default builder function for the node form. It is called
  * during the "Save" and "Preview" submit handlers to retrieve the entity to
  * save or preview. This function can also be called by a "Next" button of a
  * wizard to update the form state's entity with the current step's values
diff --git a/modules/node/node.test b/modules/node/node.test
index b27ba4f0513989354396e3a507a57bbbd01ea051..4c189a8306b9f0a839ebab0bdd9f932b50311e97 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.test,v 1.98 2010/10/07 17:31:39 webchick Exp $
+// $Id: node.test,v 1.106 2010/12/17 19:28:14 webchick Exp $
 
 /**
  * Test the node_load_multiple() function.
@@ -81,6 +81,50 @@ class NodeLoadMultipleUnitTest extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests for the hooks invoked during node_load().
+ */
+class NodeLoadHooksTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Node load hooks',
+      'description' => 'Test the hooks invoked when a node is being loaded.',
+      'group' => 'Node',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('node_test');
+  }
+
+  /**
+   * Test that hook_node_load() is invoked correctly.
+   */
+  function testHookNodeLoad() {
+    // Create some sample articles and pages.
+    $node1 = $this->drupalCreateNode(array('type' => 'article', 'status' => NODE_PUBLISHED));
+    $node2 = $this->drupalCreateNode(array('type' => 'article', 'status' => NODE_PUBLISHED));
+    $node3 = $this->drupalCreateNode(array('type' => 'article', 'status' => NODE_NOT_PUBLISHED));
+    $node4 = $this->drupalCreateNode(array('type' => 'page', 'status' => NODE_NOT_PUBLISHED));
+
+    // Check that when a set of nodes that only contains articles is loaded,
+    // the properties added to the node by node_test_load_node() correctly
+    // reflect the expected values.
+    $nodes = node_load_multiple(array(), array('status' => NODE_PUBLISHED));
+    $loaded_node = end($nodes);
+    $this->assertEqual($loaded_node->node_test_loaded_nids, array($node1->nid, $node2->nid), t('hook_node_load() received the correct list of node IDs the first time it was called.'));
+    $this->assertEqual($loaded_node->node_test_loaded_types, array('article'), t('hook_node_load() received the correct list of node types the first time it was called.'));
+
+    // Now, as part of the same page request, load a set of nodes that contain
+    // both articles and pages, and make sure the parameters passed to
+    // node_test_node_load() are correctly updated.
+    $nodes = node_load_multiple(array(), array('status' => NODE_NOT_PUBLISHED));
+    $loaded_node = end($nodes);
+    $this->assertEqual($loaded_node->node_test_loaded_nids, array($node3->nid, $node4->nid), t('hook_node_load() received the correct list of node IDs the second time it was called.'));
+    $this->assertEqual($loaded_node->node_test_loaded_types, array('article', 'page'), t('hook_node_load() received the correct list of node types the second time it was called.'));
+  }
+}
+
 class NodeRevisionsTestCase extends DrupalWebTestCase {
   protected $nodes;
   protected $logs;
@@ -872,7 +916,7 @@ class NodeAccessRecordsUnitTest extends DrupalWebTestCase {
 
     // Create an unpromoted "Basic page" node.
     $node2 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0));
-    $this->assertTrue(node_load($node1->nid), t('Unpromoted basic page node created.'));
+    $this->assertTrue(node_load($node2->nid), t('Unpromoted basic page node created.'));
 
     // Check to see if grants added by node_test_node_access_records made it in.
     $records = db_query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', array(':nid' => $node2->nid))->fetchAll();
@@ -997,14 +1041,14 @@ class NodeSaveTestCase extends DrupalWebTestCase {
     $changed = $node->changed;
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->created, $created, t('Updating a node preserves "created" timestamp.'));
 
     // Programmatically set the timestamps using hook_node_presave.
     $node->title = 'testing_node_presave';
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle('testing_node_presave');
+    $node = $this->drupalGetNodeByTitle('testing_node_presave', TRUE);
     $this->assertEqual($node->created, 280299600, t('Saving a node uses "created" timestamp set in presave hook.'));
     $this->assertEqual($node->changed, 979534800, t('Saving a node uses "changed" timestamp set in presave hook.'));
 
@@ -1027,10 +1071,40 @@ class NodeSaveTestCase extends DrupalWebTestCase {
     $node->changed = 280299600;
 
     node_save($node);
-    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->created, 979534800, t('Updating a node uses user-set "created" timestamp.'));
     $this->assertNotEqual($node->changed, 280299600, t('Updating a node doesn\'t use user-set "changed" timestamp.'));
   }
+
+  /**
+   * Tests determing changes in hook_node_presave() and verifies the static node
+   * load cache is cleared upon save.
+   */
+  function testDeterminingChanges() {
+    // Initial creation.
+    $node = (object) array(
+      'uid' => $this->web_user->uid,
+      'type' => 'article',
+      'title' => 'test_changes',
+    );
+    node_save($node);
+
+    // Update the node without applying changes.
+    node_save($node);
+    $this->assertEqual($node->title, 'test_changes', 'No changes have been determined.');
+
+    // Apply changes.
+    $node->title = 'updated';
+    node_save($node);
+
+    // The hook implementations node_test_node_presave() and
+    // node_test_node_update() determine changes and change the title.
+    $this->assertEqual($node->title, 'updated_presave_update', 'Changes have been determined.');
+
+    // Test the static node load cache to be cleared.
+    $node = node_load($node->nid);
+    $this->assertEqual($node->title, 'updated_presave', 'Static cache has been cleared.');
+  }
 }
 
 /**
@@ -1146,6 +1220,54 @@ class NodeTypeTestCase extends DrupalWebTestCase {
     $this->drupalGet('node/add/bar');
     $this->assertNoRaw('Body', t('Body field was not found.'));
   }
+
+  /**
+   * Test that node_types_rebuild() correctly handles the 'disabled' flag.
+   */
+  function testNodeTypeStatus() {
+    // Enable all core node modules, and all types should be active.
+    module_enable(array('blog', 'book', 'poll'), FALSE);
+    node_types_rebuild();
+    $types = node_type_get_types();
+    foreach (array('blog', 'book', 'poll', 'article', 'page') as $type) {
+      $this->assertTrue(isset($types[$type]), t('%type is found in node types.', array('%type' => $type)));
+      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), t('%type type is enabled.', array('%type' => $type)));
+    }
+
+    // Disable poll module and the respective type should be marked as disabled.
+    module_disable(array('poll'), FALSE);
+    node_types_rebuild();
+    $types = node_type_get_types();
+    $this->assertTrue(!empty($types['poll']->disabled), t("Poll module's node type disabled."));
+    $this->assertTrue(isset($types['blog']) && empty($types['blog']->disabled), t("Blog module's node type still active."));
+
+    // Disable blog module and the respective type should be marked as disabled.
+    module_disable(array('blog'), FALSE);
+    node_types_rebuild();
+    $types = node_type_get_types();
+    $this->assertTrue(!empty($types['blog']->disabled), t("Blog module's node type disabled."));
+    $this->assertTrue(!empty($types['poll']->disabled), t("Poll module's node type still disabled."));
+
+    // Disable book module and the respective type should still be active, since
+    // it is not provided by hook_node_info().
+    module_disable(array('book'), FALSE);
+    node_types_rebuild();
+    $types = node_type_get_types();
+    $this->assertTrue(isset($types['book']) && empty($types['book']->disabled), t("Book module's node type still active."));
+    $this->assertTrue(!empty($types['blog']->disabled), t("Blog module's node type still disabled."));
+    $this->assertTrue(!empty($types['poll']->disabled), t("Poll module's node type still disabled."));
+    $this->assertTrue(isset($types['article']) && empty($types['article']->disabled), t("Article node type still active."));
+    $this->assertTrue(isset($types['page']) && empty($types['page']->disabled), t("Basic page node type still active."));
+
+    // Re-enable the modules and verify that the types are active again.
+    module_enable(array('blog', 'book', 'poll'), FALSE);
+    node_types_rebuild();
+    $types = node_type_get_types();
+    foreach (array('blog', 'book', 'poll', 'article', 'page') as $type) {
+      $this->assertTrue(isset($types[$type]), t('%type is found in node types.', array('%type' => $type)));
+      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), t('%type type is enabled.', array('%type' => $type)));
+    }
+  }
 }
 
 /**
@@ -1287,6 +1409,20 @@ class NodeAdminTestCase extends DrupalWebTestCase {
       $this->drupalCreateNode(array('title' => $prefix . $this->randomName(6)));
     }
 
+    // Test that the default sort by node.changed DESC actually fires properly.
+    $nodes_query = db_select('node', 'n')
+      ->fields('n', array('nid'))
+      ->orderBy('changed', 'DESC')
+      ->execute()
+      ->fetchCol();
+
+    $nodes_form = array();
+    $this->drupalGet('admin/content');
+    foreach ($this->xpath('//table/tbody/tr/td/div/input/@value') as $input) {
+      $nodes_form[] = $input;
+    }
+    $this->assertEqual($nodes_query, $nodes_form, 'Nodes are sorted in the form according to the default query.');
+
     // Compare the rendered HTML node list to a query for the nodes ordered by
     // title to account for possible database-dependent sort order.
     $nodes_query = db_select('node', 'n')
@@ -1295,6 +1431,7 @@ class NodeAdminTestCase extends DrupalWebTestCase {
       ->execute()
       ->fetchCol();
 
+    $nodes_form = array();
     $this->drupalGet('admin/content', array('query' => array('sort' => 'asc', 'order' => 'Title')));
     foreach ($this->xpath('//table/tbody/tr/td/div/input/@value') as $input) {
       $nodes_form[] = $input;
@@ -1712,6 +1849,7 @@ class NodeQueryAlter extends DrupalWebTestCase {
     // permission is implemented and granted by the node_access_test module.
     $this->accessUser = $this->drupalCreateUser(array('access content', 'node test view'));
     $this->noAccessUser = $this->drupalCreateUser(array('access content'));
+    $this->noAccessUser2 = $this->drupalCreateUser(array('access content'));
   }
 
   /**
@@ -1801,6 +1939,67 @@ class NodeQueryAlter extends DrupalWebTestCase {
       $this->fail(t('Altered query is malformed'));
     }
   }
+
+  /**
+   * Lower-level test of 'node_access' query alter override.
+   *
+   * Verifies that node_access_view_all_nodes() is called from
+   * node_query_node_access_alter().  We do this by checking that
+   * a user which normally would not have view privileges is able
+   * to view the nodes when we add a record to {node_access} paired
+   * with a corresponding privilege in hook_node_grants().
+   */
+  function testNodeQueryAlterOverride() {
+    $record = array(
+      'nid' => 0,
+      'gid' => 0,
+      'realm' => 'node_access_all',
+      'grant_view' => 1,
+      'grant_update' => 0,
+      'grant_delete' => 0,
+    );
+    drupal_write_record('node_access', $record);
+
+    // Test that the noAccessUser still doesn't have the 'view'
+    // privilege after adding the node_access record.
+    drupal_static_reset('node_access_view_all_nodes');
+    try {
+      $query = db_select('node', 'mytab')
+        ->fields('mytab');
+      $query->addTag('node_access');
+      $query->addMetaData('op', 'view');
+      $query->addMetaData('account', $this->noAccessUser);
+
+      $result = $query->execute()->fetchAll();
+      $this->assertEqual(count($result), 0, t('User view privileges are not overridden'));
+    }
+    catch (Exception $e) {
+      $this->fail(t('Altered query is malformed'));
+    }
+
+    // Have node_test_node_grants return a node_access_all privilege,
+    // to grant the noAccessUser 'view' access.  To verify that
+    // node_access_view_all_nodes is properly checking the specified
+    // $account instead of the global $user, we will log in as
+    // noAccessUser2.
+    $this->drupalLogin($this->noAccessUser2);
+    variable_set('node_test_node_access_all_uid', $this->noAccessUser->uid);
+    drupal_static_reset('node_access_view_all_nodes');
+    try {
+      $query = db_select('node', 'mytab')
+        ->fields('mytab');
+      $query->addTag('node_access');
+      $query->addMetaData('op', 'view');
+      $query->addMetaData('account', $this->noAccessUser);
+
+      $result = $query->execute()->fetchAll();
+      $this->assertEqual(count($result), 4, t('User view privileges are overridden'));
+    }
+    catch (Exception $e) {
+      $this->fail(t('Altered query is malformed'));
+    }
+    variable_del('node_test_node_access_all_uid');
+  }
 }
 
 
@@ -1918,7 +2117,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
     $tests['[node:url]'] = url('node/' . $node->nid, $url_options);
     $tests['[node:edit-url]'] = url('node/' . $node->nid . '/edit', $url_options);
     $tests['[node:author:uid]'] = $node->uid;
-    $tests['[node:author:name]'] = check_plain($account->name);
+    $tests['[node:author:name]'] = check_plain(format_username($account));
     $tests['[node:created:since]'] = format_interval(REQUEST_TIME - $node->created, 2, $language->language);
     $tests['[node:changed:since]'] = format_interval(REQUEST_TIME - $node->changed, 2, $language->language);
 
@@ -1935,7 +2134,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
     $tests['[node:body]'] = $node->body[$node->language][0]['value'];
     $tests['[node:summary]'] = $node->body[$node->language][0]['summary'];
     $tests['[node:language]'] = $node->language;
-    $tests['[node:author:name]'] = $account->name;
+    $tests['[node:author:name]'] = format_username($account);
 
     foreach ($tests as $input => $expected) {
       $output = token_replace($input, array('node' => $node), array('language' => $language, 'sanitize' => FALSE));
diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php
index 19b5f0cda7a329f42f358fbcb7dc215ea92cb898..a864bb8e650468b48e6e026d7f252656707ad4c6 100644
--- a/modules/node/node.tpl.php
+++ b/modules/node/node.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.tpl.php,v 1.33 2010/04/08 18:26:42 dries Exp $
+// $Id: node.tpl.php,v 1.34 2010/12/01 00:18:15 webchick Exp $
 
 /**
  * @file
@@ -16,7 +16,9 @@
  *   calling format_date() with the desired parameters on the $created variable.
  * - $name: Themed username of node author output from theme_username().
  * - $node_url: Direct url of the current node.
- * - $display_submitted: whether submission information should be displayed.
+ * - $display_submitted: Whether submission information should be displayed.
+ * - $submitted: Submission information created from $name and $date during
+ *   template_preprocess_node().
  * - $classes: String of classes that can be used to style contextually through
  *   CSS. It can be manipulated through the variable $classes_array from
  *   preprocess functions. The default values can be one or more of the
@@ -89,10 +91,7 @@
 
   <?php if ($display_submitted): ?>
     <div class="submitted">
-      <?php
-        print t('Submitted by !username on !datetime',
-          array('!username' => $name, '!datetime' => $date));
-      ?>
+      <?php print $submitted; ?>
     </div>
   <?php endif; ?>
 
diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info
index 645ffea1dd3183e1f7f8f3542cd61250f6d567de..38bd21d490c215ace8a9bda1e67b99afc6984a62 100644
--- a/modules/node/tests/node_access_test.info
+++ b/modules/node/tests/node_access_test.info
@@ -1,14 +1,13 @@
-; $Id: node_access_test.info,v 1.1 2010/02/15 19:00:30 webchick Exp $
+; $Id: node_access_test.info,v 1.2 2010/12/20 19:59:42 webchick Exp $
 name = "Node module access tests"
 description = "Support module for node permission testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = node_access_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/node/tests/node_access_test.module b/modules/node/tests/node_access_test.module
index d134694df9a6347771d2f79b4be5530335868bec..97defc5371a87d76cf7c8a5366b6bd823516c09b 100644
--- a/modules/node/tests/node_access_test.module
+++ b/modules/node/tests/node_access_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: node_access_test.module,v 1.2 2010/08/22 16:11:12 dries Exp $
+// $Id: node_access_test.module,v 1.4 2010/11/20 04:33:56 webchick Exp $
 
 /**
  * @file
@@ -16,6 +16,9 @@ function node_access_test_node_grants($account, $op) {
   if ($op == 'view' && user_access('node test view', $account)) {
     $grants['node_access_test'] = array(888);
   }
+  if ($op == 'view' && $account->uid == variable_get('node_test_node_access_all_uid', 0)) {
+    $grants['node_access_all'] = array(0);
+  }
   return $grants;
 }
 
diff --git a/modules/node/tests/node_presave_test.info b/modules/node/tests/node_presave_test.info
deleted file mode 100644
index 67d4075419bf549cf9569e113edae3b14b444b22..0000000000000000000000000000000000000000
--- a/modules/node/tests/node_presave_test.info
+++ /dev/null
@@ -1,14 +0,0 @@
-; $Id: node_presave_test.info,v 1.1 2010/04/20 09:17:20 webchick Exp $
-name = "Node module presave tests"
-description = "Support module for hook_node_presave testing."
-package = Testing
-version = VERSION
-core = 7.x
-files[] = node_presave_test.module
-hidden = TRUE
-
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
-project = "drupal"
-datestamp = "1287812130"
-
diff --git a/modules/node/tests/node_presave_test.module b/modules/node/tests/node_presave_test.module
deleted file mode 100644
index 4df0143e21a50c6c199a8061500b4ec627e68904..0000000000000000000000000000000000000000
--- a/modules/node/tests/node_presave_test.module
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-// $Id: node_presave_test.module,v 1.1 2010/04/20 09:17:20 webchick Exp $
-
-/**
- * @file
- * Dummy module implementing node related hooks to test API interaction with
- * the Node module.
- */
-
-/**
- * Implements hook_node_presave().
- */
-function node_presave_test_node_presave($node) {
-  if ($node->title == 'testing_node_presave') {
-    $node->created = 280299600; // Sun, 19 Nov 1978 05:00:00 GMT
-    $node->changed = 979534800; // Drupal 1.0 release.
-  }
-}
diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info
index e5c7db00f7814a52a63948087ba32d2d2e4bb163..7f8e9b53f95d13a7503cf44fd7690742e727b365 100644
--- a/modules/node/tests/node_test.info
+++ b/modules/node/tests/node_test.info
@@ -1,14 +1,13 @@
-; $Id: node_test.info,v 1.1 2009/04/02 20:47:54 dries Exp $
+; $Id: node_test.info,v 1.2 2010/12/20 19:59:42 webchick Exp $
 name = "Node module tests"
 description = "Support module for node related testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = node_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/node/tests/node_test.module b/modules/node/tests/node_test.module
index 23334d1edbe0a583f4444c4b2f87deff2beb2360..76c7074f9d14e348509d34bf6f967366cfa70c8d 100644
--- a/modules/node/tests/node_test.module
+++ b/modules/node/tests/node_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: node_test.module,v 1.12 2010/09/29 14:08:54 dries Exp $
+// $Id: node_test.module,v 1.14 2010/11/30 19:31:46 dries Exp $
 
 /**
  * @file
@@ -7,6 +7,22 @@
  * the Node module.
  */
 
+/**
+ * Implements hook_node_load().
+ */
+function node_test_node_load($nodes, $types) {
+  // Add properties to each loaded node which record the parameters that were
+  // passed in to this function, so the tests can check that (a) this hook was
+  // called, and (b) the parameters were what we expected them to be.
+  $nids = array_keys($nodes);
+  ksort($nids);
+  sort($types);
+  foreach ($nodes as $node) {
+    $node->node_test_loaded_nids = $nids;
+    $node->node_test_loaded_types = $types;
+  }
+}
+
 /**
  * Implements hook_node_view().
  */
@@ -115,4 +131,22 @@ function node_test_node_presave($node) {
     // Drupal 1.0 release.
     $node->changed = 979534800;
   }
+  // Determine changes.
+  if (!empty($node->original) && $node->original->title == 'test_changes') {
+    if ($node->original->title != $node->title) {
+      $node->title .= '_presave';
+    }
+  }
+}
+
+/**
+ * Implements hook_node_update().
+ */
+function node_test_node_update($node) {
+  // Determine changes on update.
+  if (!empty($node->original) && $node->original->title == 'test_changes') {
+    if ($node->original->title != $node->title) {
+      $node->title .= '_update';
+    }
+  }
 }
diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info
index 67ce0bce261c19741d242f77df96c08e88c3fbe0..54585b357d93b60b93f9fea05bb496bce1916621 100644
--- a/modules/node/tests/node_test_exception.info
+++ b/modules/node/tests/node_test_exception.info
@@ -1,14 +1,13 @@
-; $Id: node_test_exception.info,v 1.1 2009/11/19 04:00:47 webchick Exp $
+; $Id: node_test_exception.info,v 1.2 2010/12/20 19:59:42 webchick Exp $
 name = "Node module exception tests"
 description = "Support module for node related exception testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = node_test_exception.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/openid/login-bg.png b/modules/openid/login-bg.png
index ed46173eff5c735d83c544696be309a08d0978ce..532614ffa3db5915184bc2cc0ee5345708711ee5 100644
Binary files a/modules/openid/login-bg.png and b/modules/openid/login-bg.png differ
diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc
index 4c0d33a77502a1e90682d611d750f52a3c8c1df4..9e02f21335a0b7818aa40341cd5917aa96e26ccc 100644
--- a/modules/openid/openid.inc
+++ b/modules/openid/openid.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.inc,v 1.36 2010/08/22 22:00:16 dries Exp $
+// $Id: openid.inc,v 1.37 2010/10/28 02:27:09 dries Exp $
 
 /**
  * @file
@@ -501,7 +501,7 @@ function _openid_dh_rand($stop) {
   // Used as the key for the duplicate cache
   $rbytes = _openid_dh_long_to_binary($stop);
 
-  if (array_key_exists($rbytes, $duplicate_cache)) {
+  if (isset($duplicate_cache[$rbytes])) {
     list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
   }
   else {
diff --git a/modules/openid/openid.info b/modules/openid/openid.info
index d091b8f4b53896ffc14d89b08b8a24d2068c146d..9d5b134c213ecc789ec0432e6d871db7bff0ba8f 100644
--- a/modules/openid/openid.info
+++ b/modules/openid/openid.info
@@ -1,17 +1,13 @@
-; $Id: openid.info,v 1.8 2010/05/26 08:39:54 dries Exp $
+; $Id: openid.info,v 1.9 2010/12/20 19:59:42 webchick Exp $
 name = OpenID
 description = "Allows users to log into your site using OpenID."
 version = VERSION
 package = Core
 core = 7.x
-files[] = openid.module
-files[] = openid.inc
-files[] = openid.pages.inc
-files[] = openid.install
 files[] = openid.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/openid/openid.install b/modules/openid/openid.install
index 105725bd2a1baa3916f9ab36fff316c984c38d68..0e396b01f32d2f1d80ede78a30616d4b091f395c 100644
--- a/modules/openid/openid.install
+++ b/modules/openid/openid.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.install,v 1.12 2010/08/22 22:00:16 dries Exp $
+// $Id: openid.install,v 1.13 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -112,7 +112,7 @@ function openid_requirements($phase) {
 }
 
 /**
- * @defgroup updates-6.x-extra Extra openid updates for 6.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -150,6 +150,5 @@ function openid_update_6000() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-extra"
- * The next series of updates should start at 7000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index 0559b5b92e90658e81ee4cddba23608e053ec1c1..797ec6ac55da7e8fe692c295d6db71724bc2c1c9 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: openid.module,v 1.96 2010/09/24 00:37:43 dries Exp $
+// $Id: openid.module,v 1.98 2010/11/30 17:16:37 dries Exp $
 
 /**
  * @file
@@ -137,7 +137,7 @@ function openid_form_user_login_alter(&$form, &$form_state) {
 function _openid_user_login_form_alter(&$form, &$form_state) {
   $form['#attached']['css'][] = drupal_get_path('module', 'openid') . '/openid.css';
   $form['#attached']['js'][] = drupal_get_path('module', 'openid') . '/openid.js';
-  $form['#attached']['library'][] = array('system', 'cookie');
+  $form['#attached']['library'][] = array('system', 'jquery.cookie');
   if (!empty($form_state['input']['openid_identifier'])) {
     $form['name']['#required'] = FALSE;
     $form['pass']['#required'] = FALSE;
@@ -932,7 +932,7 @@ function openid_verify_assertion_return_url($service, $response) {
   // contains a number of other parameters added by the OpenID Provider.
   parse_str(isset($return_to_parts['query']) ? $return_to_parts['query'] : '', $return_to_query_parameters);
   foreach ($return_to_query_parameters as $name => $value) {
-    if (!array_key_exists($name, $_GET) || $_GET[$name] != $value) {
+    if (!isset($_GET[$name]) || $_GET[$name] != $value) {
       return FALSE;
     }
   }
diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info
index d16228bdf99933f18d72953f3392532aff664487..6b33162e9734d726903131912a755a008b3d9584 100644
--- a/modules/openid/tests/openid_test.info
+++ b/modules/openid/tests/openid_test.info
@@ -1,16 +1,14 @@
-; $Id: openid_test.info,v 1.1 2009/05/08 21:44:48 dries Exp $
+; $Id: openid_test.info,v 1.2 2010/12/20 19:59:42 webchick Exp $
 name = OpenID dummy provider
 description = "OpenID provider used for testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = openid_test.install
-files[] = openid_test.module
 dependencies[] = openid
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/overlay/images/background.png b/modules/overlay/images/background.png
index ca87d6aaad946d837226349bdf8c3efe7f1ec786..9be21936e15f1d7016e24e78fc2ab7af3e5d0d7d 100644
Binary files a/modules/overlay/images/background.png and b/modules/overlay/images/background.png differ
diff --git a/modules/overlay/images/close.png b/modules/overlay/images/close.png
index b76db1fcf7f303cb0e2be9b5f040c009cc96f200..436985e226fd080768ef3345691da20c72e38942 100755
Binary files a/modules/overlay/images/close.png and b/modules/overlay/images/close.png differ
diff --git a/modules/overlay/images/loading.gif b/modules/overlay/images/loading.gif
deleted file mode 100755
index 57e45b8573880a25996c32d590a5f2bd70764dd1..0000000000000000000000000000000000000000
Binary files a/modules/overlay/images/loading.gif and /dev/null differ
diff --git a/modules/overlay/overlay-child.css b/modules/overlay/overlay-child.css
index a50bb496f90219ec25f5db08a33c3d8262055fc8..0ee699c602064114c0cc47fbfeef1adfcad77000 100644
--- a/modules/overlay/overlay-child.css
+++ b/modules/overlay/overlay-child.css
@@ -1,4 +1,4 @@
-/* $Id: overlay-child.css,v 1.6 2010/07/28 01:26:00 dries Exp $ */
+/* $Id: overlay-child.css,v 1.8 2011/01/03 06:53:35 webchick Exp $ */
 
 html.js {
   background: transparent !important;
@@ -6,6 +6,8 @@ html.js {
 }
 html.js body {
   background: transparent !important;
+  margin-left: 0;
+  margin-right: 0;
   padding: 20px 0;
 }
 
@@ -66,11 +68,6 @@ html.js body {
   position: absolute;
   width: 26px;
 }
-#overlay-title:active,
-#overlay-close:hover,
-#overlay-close:focus {
-  padding: 0;
-}
 
 /**
  * Tabs on the overlay.
@@ -138,3 +135,26 @@ html.js body {
 * html #overlay-close:hover {
   position: absolute;
 }
+
+/**
+ * Disable message.
+ */
+#overlay-disable-message {
+  background-color: #fff;
+  margin: -20px auto 20px;
+  width: 80%;
+  -moz-border-radius: 0 0 8px 8px;
+  -webkit-border-bottom-left-radius: 8px;
+  -webkit-border-bottom-right-radius: 8px;
+  border-radius: 0 0 8px 8px;
+}
+.overlay-disable-message-focused {
+  padding: 0.5em;
+}
+.overlay-disable-message-focused a {
+  display: block;
+  float: left;
+}
+.overlay-disable-message-focused #overlay-dismiss-message {
+  float: right;
+}
diff --git a/modules/overlay/overlay-child.js b/modules/overlay/overlay-child.js
index 4072a71ce05923ca41f0dfcfa2e8c5b3efa1466e..468aa29a6b8391b06579c3eec38011a252d62410 100644
--- a/modules/overlay/overlay-child.js
+++ b/modules/overlay/overlay-child.js
@@ -1,4 +1,4 @@
-// $Id: overlay-child.js,v 1.10 2010/07/08 12:20:23 dries Exp $
+// $Id: overlay-child.js,v 1.11 2010/11/06 00:18:24 dries Exp $
 
 (function ($) {
 
@@ -57,6 +57,19 @@ Drupal.behaviors.overlayChild = {
 
     // Attach child related behaviors to the iframe document.
     Drupal.overlayChild.attachBehaviors(context, settings);
+
+    // There are two links within the message that informs people about the
+    // overlay and how to disable it. Make sure both links are visible when
+    // either one has focus and add a class to the wrapper for styling purposes.
+    $('#overlay-disable-message', context)
+      .focusin(function () {
+        $(this).addClass('overlay-disable-message-focused');
+        $('a.element-focusable', this).removeClass('element-invisible');
+      })
+      .focusout(function () {
+        $(this).removeClass('overlay-disable-message-focused');
+        $('a.element-focusable', this).addClass('element-invisible');
+      });
   }
 };
 
diff --git a/modules/overlay/overlay-parent.css b/modules/overlay/overlay-parent.css
index c72d26cb74246ae1478fb93e7c30b5b385565973..fc2902dd6899b25bc827915983731a33ae5e5e5d 100644
--- a/modules/overlay/overlay-parent.css
+++ b/modules/overlay/overlay-parent.css
@@ -1,4 +1,4 @@
-/* $Id: overlay-parent.css,v 1.15 2010/06/08 05:16:29 webchick Exp $ */
+/* $Id: overlay-parent.css,v 1.17 2010/11/06 00:18:24 dries Exp $ */
 
 html.overlay-open,
 html.overlay-open body {
@@ -11,7 +11,7 @@ html.overlay-open body {
 .overlay-element {
   height: 100%;
   left: 0;
-  position: fixed;
+  position: absolute;
   top: 0;
   width: 100%;
   z-index: 500;
@@ -37,12 +37,15 @@ html.overlay-open .displace-bottom {
 }
 
 /**
- * IE6 shows elements with position:fixed as position:static so replace
- * it with position:absolute;
+ * Within the overlay parent, the message about disabling the overlay is for
+ * screen-reader users only. It is always kept invisible with the
+ * element-invisible class, and removed from the tab order. Overlay-child.css
+ * contains styling for the same message appearing within the overlay, and
+ * intended for sighted users.
  */
-* html #overlay-container,
-* html .overlay-modal-background,
-* html .overlay-element
-{
-  position: absolute;
+#overlay-disable-message {
+  display: none;
+}
+html.overlay-open #overlay-disable-message {
+  display: block;
 }
diff --git a/modules/overlay/overlay-parent.js b/modules/overlay/overlay-parent.js
index bba953580fc7f1ead06da33d11a85a2d47b00937..27a937ff5b69d0c4f0d324f8660229ac1f587224 100644
--- a/modules/overlay/overlay-parent.js
+++ b/modules/overlay/overlay-parent.js
@@ -1,4 +1,4 @@
-// $Id: overlay-parent.js,v 1.55 2010/09/29 00:50:46 dries Exp $
+// $Id: overlay-parent.js,v 1.57 2010/11/06 00:18:24 dries Exp $
 
 (function ($) {
 
@@ -7,6 +7,10 @@
  */
 Drupal.behaviors.overlayParent = {
   attach: function (context, settings) {
+    if (Drupal.overlay.isOpen) {
+      Drupal.overlay.makeDocumentUntabbable(context);
+    }
+
     if (this.processed) {
       return;
     }
@@ -79,6 +83,7 @@ Drupal.overlay.open = function (url) {
   this.isOpening = false;
   this.isOpen = true;
   $(document.documentElement).addClass('overlay-open');
+  this.makeDocumentUntabbable();
 
   // Allow other scripts to respond to this event.
   $(document).trigger('drupalOverlayOpen');
@@ -121,8 +126,7 @@ Drupal.overlay.create = function () {
     .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRefreshPage'))
     .bind('drupalOverlayBeforeClose' + eventClass +
           ' drupalOverlayBeforeLoad' + eventClass +
-          ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent'))
-    .bind('keydown' + eventClass, $.proxy(this, 'eventhandlerRestrictKeyboardNavigation'));
+          ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent'));
 
   if ($('.overlay-displace-top, .overlay-displace-bottom').length) {
     $(document)
@@ -158,8 +162,6 @@ Drupal.overlay.load = function (url) {
   // entry using URL fragments.
   iframeDocument.location.replace(url);
 
-  // Immediately move the focus to the iframe.
-  this.inactiveFrame.focus();
   return true;
 };
 
@@ -188,6 +190,7 @@ Drupal.overlay.close = function () {
   $(document.documentElement).removeClass('overlay-open');
   // Restore the original document title.
   document.title = this.originalTitle;
+  this.makeDocumentTabbable();
 
   // Allow other scripts to respond to this event.
   $(document).trigger('drupalOverlayClose');
@@ -206,8 +209,6 @@ Drupal.overlay.close = function () {
  */
 Drupal.overlay.destroy = function () {
   $([document, window]).unbind('.drupal-overlay-open');
-  this.$iframeA.unbind('.drupal-overlay');
-  this.$iframeB.unbind('.drupal-overlay');
   this.$container.remove();
 
   this.$container = null;
@@ -271,7 +272,7 @@ Drupal.overlay.loadChild = function (event) {
 
   this.isLoading = false;
   $(document.documentElement).removeClass('overlay-loading');
-  event.data.sibling.removeClass('overlay-active');
+  event.data.sibling.removeClass('overlay-active').attr({ 'tabindex': -1 });
 
   // Only continue when overlay is still open and not closing.
   if (this.isOpen && !this.isClosing) {
@@ -283,12 +284,18 @@ Drupal.overlay.loadChild = function (event) {
       this.activeFrame = $(iframe)
         .addClass('overlay-active')
         // Add a title attribute to the iframe for accessibility.
-        .attr('title', Drupal.t('@title dialog', { '@title': iframeWindow.jQuery('#overlay-title').text() }));
+        .attr('title', Drupal.t('@title dialog', { '@title': iframeWindow.jQuery('#overlay-title').text() })).removeAttr('tabindex');
       this.inactiveFrame = event.data.sibling;
 
       // Load an empty document into the inactive iframe.
       (this.inactiveFrame[0].contentDocument || this.inactiveFrame[0].contentWindow.document).location.replace('about:blank');
 
+      // Move the focus to just before the "skip to main content" link inside
+      // the overlay.
+      this.activeFrame.focus();
+      var skipLink = iframeWindow.jQuery('a:first');
+      Drupal.overlay.setFocusBefore(skipLink, iframeWindow.document);
+
       // Allow other scripts to respond to this event.
       $(document).trigger('drupalOverlayLoad');
     }
@@ -301,6 +308,35 @@ Drupal.overlay.loadChild = function (event) {
   }
 };
 
+/**
+ * Creates a placeholder element to receive document focus.
+ *
+ * Setting the document focus to a link will make it visible, even if it's a
+ * "skip to main content" link that should normally be visible only when the
+ * user tabs to it. This function can be used to set the document focus to
+ * just before such an invisible link.
+ *
+ * @param $element
+ *   The jQuery element that should receive focus on the next tab press.
+ * @param document
+ *   The iframe window element to which the placeholder should be added. The
+ *   placeholder element has to be created inside the same iframe as the element
+ *   it precedes, to keep IE happy. (http://bugs.jquery.com/ticket/4059)
+ */
+Drupal.overlay.setFocusBefore = function ($element, document) {
+  // Create an anchor inside the placeholder document.
+  var placeholder = document.createElement('a');
+  var $placeholder = $(placeholder).addClass('element-invisible').attr('href', '#');
+  // Put the placeholder where it belongs, and set the document focus to it.
+  $placeholder.insertBefore($element);
+  $placeholder.focus();
+  // Make the placeholder disappear as soon as it loses focus, so that it
+  // doesn't appear in the tab order again.
+  $placeholder.one('blur', function () {
+    $(this).remove();
+  });
+}
+
 /**
  * Check if the given link is in the administrative section of the site.
  *
@@ -624,37 +660,6 @@ Drupal.overlay.eventhandlerRefreshPage = function (event) {
   }
 };
 
-/**
- * Event handler: makes sure that when the overlay is open no elements (except
- * for elements inside any displaced elements) of the parent document are
- * reachable through keyboard (TAB) navigation.
- *
- * @param event
- *   Event being triggered, with the following restrictions:
- *   - event.type: keydown
- *   - event.currentTarget: document
- */
-Drupal.overlay.eventhandlerRestrictKeyboardNavigation = function (event) {
-  if (!this.$tabbables) {
-    this.$tabbables = $(':tabbable');
-  }
-
-  if (event.keyCode && event.keyCode == $.ui.keyCode.TAB) {
-    // Whenever the focus is not inside the overlay (or a displaced element)
-    // move the focus along until it is.
-    var direction = event.shiftKey ? -1 : 1;
-    var current = this.$tabbables.index(event.target);
-    var $allowedParent = '#overlay-container, .overlay-displace-top, .overlay-displace-bottom';
-    if (current != -1 && this.$tabbables[current + direction] && !this.$tabbables.eq(current + direction).closest($allowedParent).length) {
-      while (this.$tabbables[current + direction] && !this.$tabbables.eq(current + direction).closest($allowedParent).length) {
-        current = current + direction;
-      }
-      // Move focus.
-      this.$tabbables.eq(current).focus();
-    }
-  }
-};
-
 /**
  * Event handler: dispatches events to the overlay document.
  *
@@ -812,6 +817,115 @@ Drupal.overlay.getDisplacement = function (region) {
   return displacement;
 };
 
+/**
+ * Makes elements outside the overlay unreachable via the tab key.
+ *
+ * @param context
+ *   The part of the DOM that should have its tabindexes changed. Defaults to
+ *   the entire page.
+ */
+Drupal.overlay.makeDocumentUntabbable = function (context) {
+  // Manipulating tabindexes for the entire document is unacceptably slow in IE6
+  // and IE7, so in those browsers, the underlying page will still be reachable
+  // via the tab key. However, we still make the links within the Disable
+  // message unreachable, because the same message also exists within the
+  // child document. The duplicate copy in the underlying document is only for
+  // assisting screen-reader users navigating the document with reading commands
+  // that follow markup order rather than tab order.
+  if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 8) {
+    $('#overlay-disable-message a', context).attr('tabindex', -1);
+    return;
+  }
+
+  context = context || document.body;
+  var $overlay, $tabbable, $hasTabindex;
+
+  // Determine which elements on the page already have a tabindex.
+  $hasTabindex = $('[tabindex] :not(.overlay-element)', context);
+  // Record the tabindex for each element, so we can restore it later.
+  $hasTabindex.each(Drupal.overlay._recordTabindex);
+  // Add the tabbable elements from the current context to any that we might
+  // have previously recorded.
+  Drupal.overlay._hasTabindex = $hasTabindex.add(Drupal.overlay._hasTabindex);
+
+  // Set tabindex to -1 on everything outside the overlay and toolbars, so that
+  // the underlying page is unreachable.
+
+  // By default, browsers make a, area, button, input, object, select, textarea,
+  // and iframe elements reachable via the tab key.
+  $tabbable = $('a, area, button, input, object, select, textarea, iframe');
+  // If another element (like a div) has a tabindex, it's also tabbable.
+  $tabbable = $tabbable.add($hasTabindex);
+  // Leave links inside the overlay and toolbars alone.
+  $overlay = $('.overlay-element, #overlay-container, .overlay-displace-top, .overlay-displace-bottom').find('*');
+  $tabbable = $tabbable.not($overlay);
+  // We now have a list of everything in the underlying document that could
+  // possibly be reachable via the tab key. Make it all unreachable.
+  $tabbable.attr('tabindex', -1);
+};
+
+/**
+ * Restores the original tabindex value of a group of elements.
+ *
+ * @param context
+ *   The part of the DOM that should have its tabindexes restored. Defaults to
+ *   the entire page.
+ */
+Drupal.overlay.makeDocumentTabbable = function (context) {
+  // Manipulating tabindexes is unacceptably slow in IE6 and IE7. In those
+  // browsers, the underlying page was never made unreachable via tab, so
+  // there is no work to be done here.
+  if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 8) {
+    return;
+  }
+
+  var $needsTabindex;
+  context = context || document.body;
+
+  // Make the underlying document tabbable again by removing all existing
+  // tabindex attributes.
+  var $tabindex = $('[tabindex]', context);
+  if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 8) {
+    // removeAttr('tabindex') is broken in IE6-7, but the DOM function
+    // removeAttribute works.
+    var i;
+    var length = $tabindex.length;
+    for (i = 0; i < length; i++) {
+      $tabindex[i].removeAttribute('tabIndex');
+    }
+  }
+  else {
+    $tabindex.removeAttr('tabindex');
+  }
+
+  // Restore the tabindex attributes that existed before the overlay was opened.
+  $needsTabindex = $(Drupal.overlay._hasTabindex, context);
+  $needsTabindex.each(Drupal.overlay._restoreTabindex);
+  Drupal.overlay._hasTabindex = Drupal.overlay._hasTabindex.not($needsTabindex);
+};
+
+/**
+ * Record the tabindex for an element, using $.data.
+ *
+ * Meant to be used as a jQuery.fn.each callback.
+ */
+Drupal.overlay._recordTabindex = function () {
+  var $element = $(this);
+  var tabindex = $(this).attr('tabindex');
+  $element.data('drupalOverlayOriginalTabIndex', tabindex);
+}
+
+/**
+ * Restore an element's original tabindex.
+ *
+ * Meant to be used as a jQuery.fn.each callback.
+ */
+Drupal.overlay._restoreTabindex = function () {
+  var $element = $(this);
+  var tabindex = $element.data('drupalOverlayOriginalTabIndex');
+  $element.attr('tabindex', tabindex);
+};
+
 /**
  * Theme function to create the overlay iframe element.
  */
diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info
index bb6d28aeee0b9e8d400550f3bb427f94c5307acf..8c324fff0a97e925372b48f96d43a0e3166ce40a 100644
--- a/modules/overlay/overlay.info
+++ b/modules/overlay/overlay.info
@@ -1,14 +1,12 @@
-; $Id: overlay.info,v 1.2 2009/12/02 07:28:22 webchick Exp $
+; $Id: overlay.info,v 1.3 2010/12/20 19:59:42 webchick Exp $
 name = Overlay
 description = Displays the Drupal administration interface in an overlay.
 package = Core
 version = VERSION
 core = 7.x
-files[] = overlay.module
-files[] = overlay.install
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module
index 6c71fee022967e7e18e7b2cee96b8f28e33e34a3..6d62c541c7da81273cde888e41f6fd9329f8961c 100644
--- a/modules/overlay/overlay.module
+++ b/modules/overlay/overlay.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: overlay.module,v 1.31 2010/08/31 15:04:09 webchick Exp $
+// $Id: overlay.module,v 1.34 2010/11/30 17:16:37 dries Exp $
 
 /**
  * @file
@@ -30,9 +30,28 @@ function overlay_menu() {
     'access arguments' => array('access overlay'),
     'type' => MENU_CALLBACK,
   );
+  $items['overlay/dismiss-message'] = array(
+    'title' => '',
+    'page callback' => 'overlay_user_dismiss_message',
+    'access arguments' => array('access overlay'),
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
+/**
+ * Implements hook_admin_paths().
+ */
+function overlay_admin_paths() {
+  $paths = array(
+    // This is marked as an administrative path so that if it is visited from
+    // within the overlay, the user will stay within the overlay while the
+    // callback is being processed.
+    'overlay/dismiss-message' => TRUE,
+  );
+  return $paths;
+}
+
 /**
  * Implements hook_permission().
  */
@@ -54,6 +73,9 @@ function overlay_theme() {
       'render element' => 'page',
       'template' => 'overlay',
     ),
+    'overlay_disable_message' => array(
+      'render element' => 'element',
+    ),
   );
 }
 
@@ -184,7 +206,7 @@ function overlay_library() {
     ),
     'dependencies' => array(
       array('system', 'ui'),
-      array('system', 'jquery-bbq'),
+      array('system', 'jquery.bbq'),
     ),
   );
   // Overlay child.
@@ -254,10 +276,127 @@ function overlay_page_alter(&$page) {
     }
   }
 
-  if (overlay_get_mode() == 'child') {
+  $mode = overlay_get_mode();
+  if ($mode == 'child') {
     // Add the overlay wrapper before the html wrapper.
     array_unshift($page['#theme_wrappers'], 'overlay');
   }
+  elseif ($mode == 'parent' && ($message = overlay_disable_message())) {
+    $page['page_top']['disable_overlay'] = $message;
+  }
+}
+
+/**
+ * Menu callback; dismisses the overlay accessibility message for this user.
+ */
+function overlay_user_dismiss_message() {
+  global $user;
+  // It's unlikely, but possible that "access overlay" permission is granted to
+  // the anonymous role. In this case, we do not display the message to disable
+  // the overlay, so there is nothing to dismiss. Also, protect against
+  // cross-site request forgeries by validating a token.
+  if (empty($user->uid) || !isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'overlay')) {
+    return MENU_ACCESS_DENIED;
+  }
+  else {
+    user_save(user_load($user->uid), array('data' => array('overlay_message_dismissed' => 1)));
+    drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.'));
+    // Destination is normally given. Go to the user profile as a fallback.
+    drupal_goto('user/' . $user->uid . '/edit');
+  }
+}
+
+/**
+ * Returns a renderable array representing a message for disabling the overlay.
+ *
+ * If the current user can access the overlay and has not previously indicated
+ * that this message should be dismissed, this function returns a message
+ * containing a link to disable the overlay. Nothing is returned for anonymous
+ * users, because the links control per-user settings. Therefore, because some
+ * screen readers are unable to properly read overlay contents, site builders
+ * are discouraged from granting the "access overlay" permission to the
+ * anonymous role. See http://drupal.org/node/890284.
+ */
+function overlay_disable_message() {
+  global $user;
+
+  if (!empty($user->uid) && empty($user->data['overlay_message_dismissed']) && (!isset($user->data['overlay']) || $user->data['overlay']) && user_access('access overlay')) {
+    $build = array(
+      '#theme' => 'overlay_disable_message',
+      '#weight' => -99,
+      // Link to the user's profile page, where the overlay can be disabled.
+      'profile_link' => array(
+        '#type' => 'link',
+        '#title' => t('If you have problems accessing administrative pages on this site, disable the overlay on your profile page.'),
+        '#href' => 'user/' . $user->uid . '/edit',
+        '#options' => array(
+          'query' => drupal_get_destination(),
+          'fragment' => 'edit-overlay-control',
+          'attributes' => array(
+            'id' => 'overlay-profile-link',
+            // Prevent the target page from being opened in the overlay.
+            'class' => array('overlay-exclude'),
+          ),
+        ),
+      ),
+      // Link to a menu callback that allows this message to be permanently
+      // dismissed for the current user.
+      'dismiss_message_link' => array(
+        '#type' => 'link',
+        '#title' => t('Dismiss this message.'),
+        '#href' => 'overlay/dismiss-message',
+        '#options' => array(
+          'query' => drupal_get_destination() + array(
+            // Add a token to protect against cross-site request forgeries.
+            'token' => drupal_get_token('overlay'),
+          ),
+          'attributes' => array(
+            'id' => 'overlay-dismiss-message',
+            // If this message is being displayed outside the overlay, prevent
+            // this link from opening the overlay.
+            'class' => (overlay_get_mode() == 'parent') ? array('overlay-exclude') : array(),
+          ),
+        ),
+      )
+    );
+  }
+  else {
+    $build = array();
+  }
+
+  return $build;
+}
+
+/**
+ * Returns the HTML for the message about how to disable the overlay.
+ *
+ * @see overlay_disable_message()
+ */
+function theme_overlay_disable_message($variables) {
+  $element = $variables['element'];
+
+  // Add CSS classes to hide the links from most sighted users, while keeping
+  // them accessible to screen-reader users and keyboard-only users. To assist
+  // screen-reader users, this message appears in both the parent and child
+  // documents, but only the one in the child document is part of the tab order.
+  foreach (array('profile_link', 'dismiss_message_link') as $key) {
+    $element[$key]['#options']['attributes']['class'][] = 'element-invisible';
+    if (overlay_get_mode() == 'child') {
+      $element[$key]['#options']['attributes']['class'][] = 'element-focusable';
+    }
+  }
+
+  // Render the links.
+  $output = drupal_render($element['profile_link']) . ' ' . drupal_render($element['dismiss_message_link']);
+
+  // Add a heading for screen-reader users. The heading doesn't need to be seen
+  // by sighted users.
+  $output = '<h3 class="element-invisible">' . t('Options for the administrative overlay') . '</h3>' . $output;
+
+  // Wrap in a container for styling.
+  $output = '<div id="overlay-disable-message" class="clearfix">' . $output . '</div>';
+
+  return $output;
 }
 
 /**
@@ -324,9 +463,9 @@ function overlay_preprocess_maintenance_page(&$variables) {
  * @see overlay.tpl.php
  */
 function template_preprocess_overlay(&$variables) {
-  $variables['tabs']              = menu_primary_local_tasks();
-  $variables['title']             = drupal_get_title();
-
+  $variables['tabs'] = menu_primary_local_tasks();
+  $variables['title'] = drupal_get_title();
+  $variables['disable_overlay'] = overlay_disable_message();
   $variables['content_attributes_array']['class'][] = 'clearfix';
 }
 
@@ -350,7 +489,7 @@ function template_process_overlay(&$variables) {
  */
 function overlay_preprocess_page(&$variables) {
   if (overlay_get_mode() == 'child') {
-    unset($variables['tabs'][0]);
+    unset($variables['tabs']['#primary']);
   }
 }
 
diff --git a/modules/overlay/overlay.tpl.php b/modules/overlay/overlay.tpl.php
index 0bf1336309f18dcbc72cd41ee619fcd331a1a886..fd48e0a8fbdeef28f8a5c3854aa5798858fe7e13 100644
--- a/modules/overlay/overlay.tpl.php
+++ b/modules/overlay/overlay.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: overlay.tpl.php,v 1.4 2010/09/16 19:47:45 dries Exp $
+// $Id: overlay.tpl.php,v 1.5 2010/11/06 00:18:24 dries Exp $
 
 /**
  * @file
@@ -21,6 +21,7 @@
  */
 ?>
 
+<?php print render($disable_overlay); ?>
 <div id="overlay" <?php print $attributes; ?>>
   <div id="overlay-titlebar" class="clearfix">
     <div id="overlay-title-wrapper" class="clearfix">
diff --git a/modules/path/path.api.php b/modules/path/path.api.php
index 847739e4967100a9f23efce379716c4a404ffd6f..d3b00eb42b947fa9de9846fa47f92ab56ecdc53b 100644
--- a/modules/path/path.api.php
+++ b/modules/path/path.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.api.php,v 1.1 2009/10/17 00:52:36 dries Exp $
+// $Id: path.api.php,v 1.2 2010/12/02 00:22:20 webchick Exp $
 
 /**
  * @file
@@ -13,30 +13,61 @@
 
 
 /**
- * The path has been inserted.
+ * Allow modules to respond to a path being inserted.
  *
  * @param $path
- *   The path array.
+ *   An associative array containing the following keys:
+ *   - source: The internal system path.
+ *   - alias: The URL alias.
+ *   - pid: Unique path alias identifier.
+ *   - language: The language of the alias.
+ *
+ * @see path_save()
  */
 function hook_path_insert($path) {
+  db_insert('mytable')
+    ->fields(array(
+      'alias' => $path['alias'],
+      'pid' => $path['pid'],
+    ))
+    ->execute();
 }
 
 /**
- * The path has been updated.
+ * Allow modules to respond to a path being updated.
  *
  * @param $path
- *   The path array.
+ *   An associative array containing the following keys:
+ *   - source: The internal system path.
+ *   - alias: The URL alias.
+ *   - pid: Unique path alias identifier.
+ *   - language: The language of the alias.
+ *
+ * @see path_save()
  */
 function hook_path_update($path) {
+  db_update('mytable')
+    ->fields(array('alias' => $path['alias']))
+    ->condition('pid', $path['pid'])
+    ->execute();
 }
 
 /**
- * The path has been deleted.
+ * Allow modules to respond to a path being deleted.
  *
  * @param $path
- *   The path array.
+ *   An associative array containing the following keys:
+ *   - source: The internal system path.
+ *   - alias: The URL alias.
+ *   - pid: Unique path alias identifier.
+ *   - language: The language of the alias.
+ *
+ * @see path_delete()
  */
 function hook_path_delete($path) {
+  db_delete('mytable')
+    ->condition('pid', $path['pid'])
+    ->execute();
 }
 
 /**
diff --git a/modules/path/path.info b/modules/path/path.info
index 95507c9343eda1e208530a09273294c642ef2c26..8c013ca959845214ff1e84cd4abc2c43bdbd3d7f 100644
--- a/modules/path/path.info
+++ b/modules/path/path.info
@@ -1,16 +1,14 @@
-; $Id: path.info,v 1.9 2009/11/17 21:24:18 dries Exp $
+; $Id: path.info,v 1.10 2010/12/20 19:59:42 webchick Exp $
 name = Path
 description = Allows users to rename URLs.
 package = Core
 version = VERSION
 core = 7.x
-files[] = path.module
-files[] = path.admin.inc
 files[] = path.test
 configure = admin/config/search/path
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/path/path.js b/modules/path/path.js
index bc8b5d64d618c10cd254db2eed6576a31207b416..681b5d0a7b8f6033f56727e68f312d93d5b40379 100644
--- a/modules/path/path.js
+++ b/modules/path/path.js
@@ -1,11 +1,11 @@
-// $Id: path.js,v 1.4 2010/04/09 12:24:53 dries Exp $
+// $Id: path.js,v 1.5 2010/11/05 19:47:20 dries Exp $
 
 (function ($) {
 
 Drupal.behaviors.pathFieldsetSummaries = {
   attach: function (context) {
-    $('fieldset#edit-path', context).drupalSetSummary(function (context) {
-      var path = $('#edit-path-alias').val();
+    $('fieldset.path-form', context).drupalSetSummary(function (context) {
+      var path = $('.form-item-path-alias input').val();
 
       return path ?
         Drupal.t('Alias: @alias', { '@alias': path }) :
diff --git a/modules/path/path.module b/modules/path/path.module
index 8b85d5e29b6264920a4dab79adcddef6c347f757..d214775327e35e71df5588336578f9f941309879 100644
--- a/modules/path/path.module
+++ b/modules/path/path.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.module,v 1.185 2010/09/24 00:37:44 dries Exp $
+// $Id: path.module,v 1.187 2010/12/01 00:31:38 webchick Exp $
 
 /**
  * @file
@@ -119,6 +119,9 @@ function path_form_node_form_alter(&$form, $form_state) {
     '#collapsible' => TRUE,
     '#collapsed' => empty($path['alias']),
     '#group' => 'additional_settings',
+    '#attributes' => array(
+      'class' => array('path-form'),
+    ),
     '#attached' => array(
       'js' => array(drupal_get_path('module', 'path') . '/path.js'),
     ),
@@ -134,7 +137,7 @@ function path_form_node_form_alter(&$form, $form_state) {
     '#maxlength' => 255,
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
-    '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
+    '#description' => t('Optionally specify an alternative URL by which this content can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
   );
   $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']);
   $form['path']['source'] = array('#type' => 'value', '#value' => $path['source']);
diff --git a/modules/php/php.info b/modules/php/php.info
index 8a6983ac83f301222969ec1320ed31b9a982faaa..1768e192e522d5f6b3b901a79bfb4da38b1c4f99 100644
--- a/modules/php/php.info
+++ b/modules/php/php.info
@@ -1,15 +1,13 @@
-; $Id: php.info,v 1.7 2009/06/08 09:23:53 dries Exp $
+; $Id: php.info,v 1.8 2010/12/20 19:59:42 webchick Exp $
 name = PHP filter
 description = Allows embedded PHP code/snippets to be evaluated.
 package = Core
 version = VERSION
 core = 7.x
-files[] = php.module
-files[] = php.install
 files[] = php.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/php/php.module b/modules/php/php.module
index f163b987dd284a237bec73bcb668bd25a2b08898..bd72a7294d12ab0ed179aeeefe77f9b2935b95d6 100644
--- a/modules/php/php.module
+++ b/modules/php/php.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: php.module,v 1.28 2010/03/21 21:20:43 dries Exp $
+// $Id: php.module,v 1.29 2010/12/01 00:31:38 webchick Exp $
 
 /**
  * @file
@@ -14,7 +14,7 @@ function php_help($path, $arg) {
     case 'admin/help#php':
       $output = '';
       $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The PHP filter module adds a PHP filter to your site, for use with <a href="@filter">text formats</a>. This filter adds the ability to execute PHP code in any text field that uses a text format (such as the body of a node or the text of a comment). <a href="@php-net">PHP</a> is a general-purpose scripting language widely-used for web development, and is the language with which Drupal has been developed. For more information, see the online handbook entry for the <a href="@php">PHP filter module</a>.', array('@filter' => url('admin/help/filter'), '@php-net' => 'http://www.php.net', '@php' => 'http://drupal.org/handbook/modules/php/')) . '</p>';
+      $output .= '<p>' . t('The PHP filter module adds a PHP filter to your site, for use with <a href="@filter">text formats</a>. This filter adds the ability to execute PHP code in any text field that uses a text format (such as the body of a content item or the text of a comment). <a href="@php-net">PHP</a> is a general-purpose scripting language widely-used for web development, and is the language with which Drupal has been developed. For more information, see the online handbook entry for the <a href="@php">PHP filter module</a>.', array('@filter' => url('admin/help/filter'), '@php-net' => 'http://www.php.net', '@php' => 'http://drupal.org/handbook/modules/php/')) . '</p>';
       $output .= '<h3>' . t('Uses') . '</h3>';
       $output .= '<dl>';
       $output .= '<dt>' . t('Enabling execution of PHP in text fields') . '</dt>';
diff --git a/modules/php/php.test b/modules/php/php.test
index 877c2e442236df64e0c3de3fc5426c66cfcd9c9e..24886c3f99997c47781115b8aaa3c9ea42686fa9 100644
--- a/modules/php/php.test
+++ b/modules/php/php.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: php.test,v 1.26 2010/08/05 23:53:38 webchick Exp $
+// $Id: php.test,v 1.27 2010/11/29 06:38:51 webchick Exp $
 
 /**
  * Base PHP test case class.
@@ -15,9 +15,9 @@ class PHPTestCase extends DrupalWebTestCase {
     $this->drupalLogin($admin_user);
 
     // Verify that the PHP code text format was inserted.
-    $php_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'PHP code'))->fetchField();
-    $php_format = filter_format_load($php_format_id);
-    $this->assertEqual($php_format->name, 'PHP code', t('PHP code text format was created.'));
+    $php_format_id = 'php_code';
+    $this->php_code_format = filter_format_load($php_format_id);
+    $this->assertEqual($this->php_code_format->name, 'PHP code', t('PHP code text format was created.'));
 
     // Verify that the format has the PHP code filter enabled.
     $filters = filter_list_format($php_format_id);
@@ -31,9 +31,6 @@ class PHPTestCase extends DrupalWebTestCase {
     $this->drupalGet('admin/config/content/formats/' . $php_format_id);
     $this->assertFieldByName('roles[1]', FALSE, t('Anonymous users do not have access to PHP code format.'));
     $this->assertFieldByName('roles[2]', FALSE, t('Authenticated users do not have access to PHP code format.'));
-
-    // Store the format ID of the PHP code text format for later use.
-    $this->php_code_format = $php_format_id;
   }
 
   /**
@@ -63,7 +60,7 @@ class PHPFilterTestCase extends PHPTestCase {
    */
   function testPHPFilter() {
     // Log in as a user with permission to use the PHP code text format.
-    $php_code_permission = filter_permission_name(filter_format_load($this->php_code_format));
+    $php_code_permission = filter_permission_name(filter_format_load('php_code'));
     $web_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content', $php_code_permission));
     $this->drupalLogin($web_user);
 
@@ -77,7 +74,7 @@ class PHPFilterTestCase extends PHPTestCase {
     // Change filter to PHP filter and see that PHP code is evaluated.
     $edit = array();
     $langcode = LANGUAGE_NONE;
-    $edit["body[$langcode][0][format]"] = $this->php_code_format;
+    $edit["body[$langcode][0][format]"] = $this->php_code_format->format;
     $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
     $this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node->title)), t('PHP code filter turned on.'));
 
@@ -114,6 +111,6 @@ class PHPAccessTestCase extends PHPTestCase {
 
     // Make sure that user doesn't have access to filter.
     $this->drupalGet('node/' . $node->nid . '/edit');
-    $this->assertNoRaw('<option value="' . $this->php_code_format . '">', t('PHP code format not available.'));
+    $this->assertNoRaw('<option value="' . $this->php_code_format->format . '">', t('PHP code format not available.'));
   }
 }
diff --git a/modules/poll/poll.info b/modules/poll/poll.info
index 26caaa01cce93e667a065a4f680410ce62855467..6c4be672b5a370c4d29b156a4cceece3d3ca9c76 100644
--- a/modules/poll/poll.info
+++ b/modules/poll/poll.info
@@ -1,18 +1,14 @@
-; $Id: poll.info,v 1.11 2010/09/05 02:21:38 dries Exp $
+; $Id: poll.info,v 1.12 2010/12/20 19:59:42 webchick Exp $
 name = Poll
 description = Allows your site to capture votes on different topics in the form of multiple choice questions.
 package = Core
 version = VERSION
 core = 7.x
-files[] = poll.module
-files[] = poll.pages.inc
-files[] = poll.install
 files[] = poll.test
-files[] = poll.tokens.inc
 stylesheets[all][] = poll.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 9b30fa296beac43ee464777aada0b553d50c9871..1a8ebe9d0f500b0afc7927d1099f79ef5a365b3a 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.module,v 1.358 2010/10/20 01:31:07 dries Exp $
+// $Id: poll.module,v 1.361 2010/11/20 09:25:30 webchick Exp $
 
 /**
  * @file
@@ -133,6 +133,7 @@ function _poll_menu_access($node, $perm, $inspect_allowvotes) {
  */
 function poll_block_info() {
   $blocks['recent']['info'] = t('Most recent poll');
+  $blocks['recent']['properties']['administrative'] = TRUE;
   return $blocks;
 }
 
@@ -279,16 +280,16 @@ function poll_form($node, &$form_state) {
   $weight = 0;
   if (isset($node->choice)) {
     $delta = count($node->choice);
-    $weight = -$delta;
     foreach ($node->choice as $chid => $choice) {
       $key = 'chid:' . $chid;
       $form['choice_wrapper']['choice'][$key] = _poll_choice_form($key, $choice['chid'], $choice['chtext'], $choice['chvotes'], $choice['weight'], $choice_count);
-      $weight = ($choice['weight'] > $weight) ? $choice['weight'] : $weight;
+      $weight = max($choice['weight'], $weight);
     }
   }
 
   // Add initial or additional choices.
   $existing_delta = $delta;
+  $weight++;
   for ($delta; $delta < $choice_count; $delta++) {
     $key = 'new:' . ($delta - $existing_delta);
     $form['choice_wrapper']['choice'][$key] = _poll_choice_form($key, NULL, '', 0, $weight, $choice_count);
@@ -378,6 +379,7 @@ function poll_more_choices_submit($form, &$form_state) {
 function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) {
   $form = array(
     '#tree' => TRUE,
+    '#weight' => $weight,
   );
 
   // We'll manually set the #parents property of these fields so that
@@ -637,6 +639,11 @@ function poll_block_latest_poll_view($node) {
 
   if (!empty($node->allowvotes)) {
     $node->content['poll_view_voting'] = drupal_get_form('poll_view_voting', $node, TRUE);
+    $node->content['links'] = array(
+      '#theme' => 'links',
+      '#links' => $node->links,
+      '#weight' => 5,
+    );
   }
   else {
     $node->content['poll_view_results'] = array('#markup' => poll_view_results($node, TRUE, TRUE));
@@ -790,6 +797,9 @@ function template_preprocess_poll_vote(&$variables) {
  * Generates a graphical representation of the results of a poll.
  */
 function poll_view_results($node, $view_mode, $block = FALSE) {
+  // Make sure that choices are ordered by their weight.
+  uasort($node->choice, 'drupal_sort_weight');
+
   // Count the votes and find the maximum
   $total_votes = 0;
   $max_votes = 0;
@@ -826,14 +836,14 @@ function theme_poll_choices($variables) {
 
   drupal_add_tabledrag('poll-choice-table', 'order', 'sibling', 'poll-weight');
 
+  $is_admin= user_access('administer nodes');
   $delta = 0;
   $rows = array();
-  $headers = array(
-    '',
-    t('Choice'),
-    t('Vote count'),
-    t('Weight'),
-  );
+  $headers = array('', t('Choice'));
+  if ($is_admin) {
+    $headers[] = t('Vote count');
+  }
+  $headers[] = t('Weight');
 
   foreach (element_children($form) as $key) {
     $delta++;
@@ -845,11 +855,13 @@ function theme_poll_choices($variables) {
       'data' => array(
         array('class' => array('choice-flag')),
         drupal_render($form[$key]['chtext']),
-        drupal_render($form[$key]['chvotes']),
-        drupal_render($form[$key]['weight']),
       ),
       'class' => array('draggable'),
     );
+    if ($is_admin) {
+      $row['data'][] = drupal_render($form[$key]['chvotes']);
+    }
+    $row['data'][] = drupal_render($form[$key]['weight']);
 
     // Add any additional classes set on the row.
     if (!empty($form[$key]['#attributes']['class'])) {
diff --git a/modules/poll/poll.test b/modules/poll/poll.test
index 2d14b8aa85b8617c37ce5384ed965a132e369aa9..a08090db18725327996d099ad07ca4aff028d8b2 100644
--- a/modules/poll/poll.test
+++ b/modules/poll/poll.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.test,v 1.38 2010/08/30 00:22:03 webchick Exp $
+// $Id: poll.test,v 1.39 2010/10/25 15:51:21 webchick Exp $
 
 /**
  * @file
@@ -11,36 +11,41 @@ class PollTestCase extends DrupalWebTestCase {
   /**
    * Creates a poll.
    *
-   * @param string $title The title of the poll.
-   * @param array $choices Choices.
-   * @param boolean $test_preview Whether to test if the preview is working or not.
-   * @return integer The nid of the created poll, or FALSE on error.
+   * @param string $title
+   *   The title of the poll.
+   * @param array $choices
+   *   A list of choice labels.
+   * @param boolean $preview
+   *   (optional) Whether to test if the preview is working or not. Defaults to
+   *   TRUE.
+   *
+   * @return
+   *   The node id of the created poll, or FALSE on error.
    */
-  function pollCreate($title, $choices, $test_preview = TRUE) {
+  function pollCreate($title, $choices, $preview = TRUE) {
     $this->assertTrue(TRUE, 'Create a poll');
 
     $web_user = $this->drupalCreateUser(array('create poll content', 'access content', 'edit own poll content'));
     $this->drupalLogin($web_user);
 
-    // Get the form first to initialize the state of the internal browser
+    // Get the form first to initialize the state of the internal browser.
     $this->drupalGet('node/add/poll');
 
-    // Prepare a form with two choices
+    // Prepare a form with two choices.
     list($edit, $index) = $this->_pollGenerateEdit($title, $choices);
 
+    // Re-submit the form until all choices are filled in.
     if (count($choices) > 2) {
-      // Re-submit the form while the choices are all in
       while ($index < count($choices)) {
         $this->drupalPost(NULL, $edit, t('More choices'));
+        $this->assertPollChoiceOrder($choices, $index);
         list($edit, $index) = $this->_pollGenerateEdit($title, $choices, $index);
       }
     }
 
-    if ($test_preview) {
+    if ($preview) {
       $this->drupalPost(NULL, $edit, t('Preview'));
-      foreach ($choices as $k => $choice_text) {
-        $this->assertRaw($choice_text, t('Choice @choice found was in preview.', array('@choice' => $k)));
-      }
+      $this->assertPollChoiceOrder($choices, $index, TRUE);
       list($edit, $index) = $this->_pollGenerateEdit($title, $choices, $index);
     }
 
@@ -52,20 +57,42 @@ class PollTestCase extends DrupalWebTestCase {
     return isset($node->nid) ? $node->nid : FALSE;
   }
 
-  function _pollGenerateEdit($title, $choices, $index = 0) {
-    $max_new_choices = $index == 0 ? 2 : 5;
+  /**
+   * Generates POST values for the poll node form, specifically poll choices.
+   *
+   * @param $title
+   *   The title for the poll node.
+   * @param $choices
+   *   An array containing poll choices, as generated by
+   *   PollTestCase::_generateChoices().
+   * @param $index
+   *   (optional) The amount/number of already submitted poll choices. Defaults
+   *   to 0.
+   *
+   * @return
+   *   An indexed array containing:
+   *   - The generated POST values, suitable for
+   *     DrupalWebTestCase::drupalPost().
+   *   - The number of poll choices contained in 'edit', for potential re-usage
+   *     in subsequent invocations of this function.
+   */
+  function _pollGenerateEdit($title, array $choices, $index = 0) {
+    $max_new_choices = ($index == 0 ? 2 : 5);
     $already_submitted_choices = array_slice($choices, 0, $index);
     $new_choices = array_values(array_slice($choices, $index, $max_new_choices));
 
-    $langcode = LANGUAGE_NONE;
     $edit = array(
-      "title" => $title
+      'title' => $title,
     );
     foreach ($already_submitted_choices as $k => $text) {
       $edit['choice[chid:' . $k . '][chtext]'] = $text;
     }
     foreach ($new_choices as $k => $text) {
       $edit['choice[new:' . $k . '][chtext]'] = $text;
+      // To test poll choice weights, every new choice is sorted in front of
+      // existing choices. Existing/already submitted choices should keep their
+      // weight.
+      $edit['choice[new:' . $k . '][weight]'] = (- $index - $k);
     }
     return array($edit, count($already_submitted_choices) + count($new_choices));
   }
@@ -78,6 +105,67 @@ class PollTestCase extends DrupalWebTestCase {
     return $choices;
   }
 
+  /**
+   * Assert correct poll choice order in the node form after submission.
+   *
+   * Verifies both the order in the DOM and in the 'weight' form elements.
+   *
+   * @param $choices
+   *   An array containing poll choices, as generated by
+   *   PollTestCase::_generateChoices().
+   * @param $index
+   *   (optional) The amount/number of already submitted poll choices. Defaults
+   *   to 0.
+   * @param $preview
+   *   (optional) Whether to also check the poll preview.
+   *
+   * @see PollTestCase::_pollGenerateEdit()
+   */
+  function assertPollChoiceOrder(array $choices, $index = 0, $preview = FALSE) {
+    $expected = array();
+    foreach ($choices as $id => $label) {
+      if ($id < $index) {
+        // The expected weight of each choice is exactly the negated id.
+        // @see PollTestCase::_pollGenerateEdit()
+        $weight = -$id;
+        // Directly assert the weight form element value for this choice.
+        $this->assertFieldByName('choice[chid:' . $id . '][weight]', $weight, t('Found choice @id with weight @weight.', array(
+          '@id' => $id,
+          '@weight' => $weight,
+        )));
+        // Append to our (to be reversed) stack of labels.
+        $expected[$weight] = $label;
+      }
+    }
+    ksort($expected);
+
+    // Verify DOM order of poll choices (i.e., #weight of form elements).
+    $elements = $this->xpath('//input[starts-with(@name, :prefix) and contains(@name, :suffix)]', array(
+      ':prefix' => 'choice[chid:',
+      ':suffix' => '][chtext]',
+    ));
+    $expected_order = $expected;
+    foreach ($elements as $element) {
+      $next_label = array_shift($expected_order);
+      $this->assertEqual((string) $element['value'], $next_label);
+    }
+
+    // If requested, also verify DOM order in preview.
+    if ($preview) {
+      $elements = $this->xpath('//div[contains(@class, :teaser)]/descendant::div[@class=:text]', array(
+        ':teaser' => 'node-teaser',
+        ':text' => 'text',
+      ));
+      $expected_order = $expected;
+      foreach ($elements as $element) {
+        $next_label = array_shift($expected_order);
+        $this->assertEqual((string) $element, $next_label, t('Found choice @label in preview.', array(
+          '@label' => $next_label,
+        )));
+      }
+    }
+  }
+
   function pollUpdate($nid, $title, $edit) {
     // Edit the poll node.
     $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
@@ -332,7 +420,6 @@ class PollJSAddChoice extends DrupalWebTestCase {
     $web_user = $this->drupalCreateUser(array('create poll content', 'access content'));
     $this->drupalLogin($web_user);
     $this->drupalGet('node/add/poll');
-    $langcode = LANGUAGE_NONE;
     $edit = array(
       "title" => $this->randomName(),
       'choice[new:0][chtext]' => $this->randomName(),
@@ -597,33 +684,33 @@ class PollExpirationTestCase extends PollTestCase {
     $title = $this->randomName();
     $choices = $this->_generateChoices(2);
     $poll_nid = $this->pollCreate($title, $choices, FALSE);
-    $this->assertTrue($poll_nid, t('Poll for auto-expire test created.'), t('Poll'));
+    $this->assertTrue($poll_nid, t('Poll for auto-expire test created.'));
 
     // Visit the poll edit page and verify that by default, expiration
     // is set to unlimited.
     $this->drupalGet("node/$poll_nid/edit");
-    $this->assertField('runtime', t('Poll expiration setting found.'), t('Poll'));
+    $this->assertField('runtime', t('Poll expiration setting found.'));
     $elements = $this->xpath('//select[@id="edit-runtime"]/option[@selected="selected"]');
-    $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == 0, t('Poll expiration set to unlimited.'), t('Poll'));
+    $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == 0, t('Poll expiration set to unlimited.'));
 
     // Set the expiration to one week.
     $edit = array();
     $poll_expiration = 604800; // One week.
     $edit['runtime'] = $poll_expiration;
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('Poll %title has been updated.', array('%title' => $title)), t('Poll expiration settings saved.'), t('Poll'));
+    $this->assertRaw(t('Poll %title has been updated.', array('%title' => $title)), t('Poll expiration settings saved.'));
 
     // Make sure that the changed expiration settings is kept.
     $this->drupalGet("node/$poll_nid/edit");
     $elements = $this->xpath('//select[@id="edit-runtime"]/option[@selected="selected"]');
-    $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == $poll_expiration, t('Poll expiration set to unlimited.'), t('Poll'));
+    $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == $poll_expiration, t('Poll expiration set to unlimited.'));
 
     // Force a cron run. Since the expiration date has not yet been reached,
     // the poll should remain active.
     drupal_cron_run();
     $this->drupalGet("node/$poll_nid/edit");
     $elements = $this->xpath('//input[@id="edit-active-1"]');
-    $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll is still active.'), t('Poll'));
+    $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll is still active.'));
 
     // Test expiration. Since REQUEST_TIME is a constant and we don't
     // want to keep SimpleTest waiting until the moment of expiration arrives,
@@ -638,6 +725,6 @@ class PollExpirationTestCase extends PollTestCase {
     drupal_cron_run();
     $this->drupalGet("node/$poll_nid/edit");
     $elements = $this->xpath('//input[@id="edit-active-0"]');
-    $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll has expired.'), t('Poll'));
+    $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll has expired.'));
   }
-}
\ No newline at end of file
+}
diff --git a/modules/poll/poll.tokens.inc b/modules/poll/poll.tokens.inc
index 28abeb3cfda616536e78d8fc2a2272dacc9774c5..26176e100456da0b496d6a815fd1591aff7d0aa1 100644
--- a/modules/poll/poll.tokens.inc
+++ b/modules/poll/poll.tokens.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.tokens.inc,v 1.5 2010/04/20 09:48:06 webchick Exp $
+// $Id: poll.tokens.inc,v 1.6 2010/12/01 00:31:38 webchick Exp $
 
 /**
  * @file
@@ -12,7 +12,7 @@
 function poll_token_info() {
   $node['poll-votes'] = array(
     'name' => t("Poll votes"),
-    'description' => t("The number of votes that have been cast on a poll node."),
+    'description' => t("The number of votes that have been cast on a poll."),
   );
   $node['poll-winner'] = array(
     'name' => t("Poll winner"),
@@ -28,7 +28,7 @@ function poll_token_info() {
   );
   $node['poll-duration'] = array(
     'name' => t("Poll duration"),
-    'description' => t("The length of time the poll node is set to run."),
+    'description' => t("The length of time the poll is set to run."),
   );
 
   return array(
diff --git a/modules/profile/profile.admin.inc b/modules/profile/profile.admin.inc
index 6c1c5e4dcd971fee17ff983e6ed32aac64ba9bca..b8e029a58df356aeaa2844302c9ac59c017aba1c 100644
--- a/modules/profile/profile.admin.inc
+++ b/modules/profile/profile.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: profile.admin.inc,v 1.43 2010/10/20 01:31:07 dries Exp $
+// $Id: profile.admin.inc,v 1.44 2010/10/28 02:27:09 dries Exp $
 
 /**
  * @file
@@ -126,7 +126,7 @@ function theme_profile_admin_overview($variables) {
   $category_number = 0;
   foreach (element_children($form) as $key) {
     // Don't take form control structures.
-    if (array_key_exists('category', $form[$key])) {
+    if (isset($form[$key]['category'])) {
       $field = &$form[$key];
       $category = $field['category']['#default_value'];
 
diff --git a/modules/profile/profile.info b/modules/profile/profile.info
index 151a64dad9c66dd2dc02b9b43c93a7c87a7fd990..ec50d073782677fe666f75360096c92f56ca4d58 100644
--- a/modules/profile/profile.info
+++ b/modules/profile/profile.info
@@ -1,18 +1,19 @@
-; $Id: profile.info,v 1.10 2009/11/17 21:24:18 dries Exp $
+; $Id: profile.info,v 1.12 2010/12/20 19:59:42 webchick Exp $
 name = Profile
 description = Supports configurable user profiles.
 package = Core
 version = VERSION
 core = 7.x
-files[] = profile.module
-files[] = profile.admin.inc
-files[] = profile.pages.inc
-files[] = profile.install
 files[] = profile.test
 configure = admin/config/people/profile
+; The Profile module is deprecated, and included in Drupal 7 for legacy
+; purposes only. By default, the module will be hidden from the UI unless you
+; are upgrading a site that uses the Profile module to extend user profiles.
+; See user_system_info_alter().
+hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/profile/profile.pages.inc b/modules/profile/profile.pages.inc
index 128c8845e0859e5796b8e7be61bfcccd92e6c355..993152a1b23872844484b0042d147ca2f5420b02 100644
--- a/modules/profile/profile.pages.inc
+++ b/modules/profile/profile.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: profile.pages.inc,v 1.27 2010/10/06 13:38:40 dries Exp $
+// $Id: profile.pages.inc,v 1.28 2010/11/12 02:57:15 dries Exp $
 
 /**
  * @file
@@ -38,7 +38,6 @@ function profile_browse() {
     $query
       ->fields('u', array('uid', 'access'))
       ->condition('v.fid', $field->fid)
-      ->condition('u.access', 0, '<>')
       ->condition('u.status', 0, '<>')
       ->orderBy('u.access', 'DESC');
 
@@ -99,7 +98,6 @@ function profile_browse() {
       ->fields('u', array('uid', 'access'))
       ->condition('u.uid', 0, '>')
       ->condition('u.status', 0, '>')
-      ->condition('u.access', 0, '>')
       ->orderBy('u.access', 'DESC')
       ->limit(20)
       ->execute()
diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info
index 00ed1e429efda0a3064939fe6b134cf22e761f2c..687129d7d58a59cea640e00df4bc8348333d9951 100644
--- a/modules/rdf/rdf.info
+++ b/modules/rdf/rdf.info
@@ -1,15 +1,13 @@
-; $Id: rdf.info,v 1.3 2009/11/18 04:44:19 webchick Exp $
+; $Id: rdf.info,v 1.4 2010/12/20 19:59:42 webchick Exp $
 name = RDF
 description = Enriches your content with metadata to let other applications (e.g. search engines, aggregators) better understand its relationships and attributes.
 package = Core
 version = VERSION
 core = 7.x
-files[] = rdf.install
-files[] = rdf.module
 files[] = rdf.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/rdf/rdf.module b/modules/rdf/rdf.module
index 26f71b259845658912b76192b0894bff4dd91537..26abe6295fc023fd01030a9213577028637358d3 100644
--- a/modules/rdf/rdf.module
+++ b/modules/rdf/rdf.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: rdf.module,v 1.46 2010/10/01 01:44:39 webchick Exp $
+// $Id: rdf.module,v 1.49 2010/12/11 02:38:24 dries Exp $
 
 /**
  * @file
@@ -223,7 +223,7 @@ function _rdf_mapping_load($type, $bundle) {
  * @return
  *   Status flag indicating the outcome of the operation.
  */
-function rdf_mapping_save(&$mapping) {
+function rdf_mapping_save($mapping) {
   // In the case where a field has a mapping defined in the default entity
   // mapping, but a mapping is not specified in the bundle-specific mapping,
   // then use the default mapping for that field.
@@ -499,16 +499,22 @@ function rdf_preprocess_node(&$variables) {
   if (!empty($variables['rdf_mapping']['created'])) {
     $date_attributes_array = rdf_rdfa_attributes($variables['rdf_mapping']['created'], $variables['created']);
     $variables['rdf_template_variable_attributes_array']['date'] = $date_attributes_array;
+    if ($variables['submitted']) {
+      $variables['rdf_template_variable_attributes_array']['submitted'] = $date_attributes_array;
+    }
   }
   // Adds RDFa markup for the relation between the node and its author.
   if (!empty($variables['rdf_mapping']['uid'])) {
     $variables['rdf_template_variable_attributes_array']['name']['rel'] = $variables['rdf_mapping']['uid']['predicates'];
+    if ($variables['submitted']) {
+      $variables['rdf_template_variable_attributes_array']['submitted']['rel'] = $variables['rdf_mapping']['uid']['predicates'];
+    }
   }
 
   // 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']['#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'];
@@ -518,7 +524,7 @@ function rdf_preprocess_node(&$variables) {
       // 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']['#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 of the HTML
@@ -679,10 +685,12 @@ function rdf_preprocess_comment(&$variables) {
     // cached as part of the entity.
     $date_attributes_array = $comment->rdf_data['date'];
     $variables['rdf_template_variable_attributes_array']['created'] = $date_attributes_array;
+    $variables['rdf_template_variable_attributes_array']['submitted'] = $date_attributes_array;
   }
   // Adds RDFa markup for the relation between the comment and its author.
   if (!empty($comment->rdf_mapping['uid'])) {
     $variables['rdf_template_variable_attributes_array']['author']['rel'] = $comment->rdf_mapping['uid']['predicates'];
+    $variables['rdf_template_variable_attributes_array']['submitted']['rel'] = $comment->rdf_mapping['uid']['predicates'];
   }
   if (!empty($comment->rdf_mapping['title'])) {
     // Adds RDFa markup to the subject of the comment. Because the RDFa markup
diff --git a/modules/rdf/rdf.test b/modules/rdf/rdf.test
index f0b83a58e85568d695f0f04813733ef5b8a77278..8a4a0f6b92b599c4bb5dbd60efc2db914db8cb5f 100644
--- a/modules/rdf/rdf.test
+++ b/modules/rdf/rdf.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: rdf.test,v 1.28 2010/10/05 06:17:28 webchick Exp $
+// $Id: rdf.test,v 1.30 2010/12/14 01:04:27 dries Exp $
 
 /**
  * @file
@@ -187,6 +187,25 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
     ));
 
     $this->assertTrue(!empty($image_rel), t('Attribute \'rel\' set on image field. Attribute \'resource\' is also set.'));
+
+    // Edits the node to add tags.
+    $tag1 = $this->randomName(8);
+    $tag2 = $this->randomName(8);
+    $edit = array();
+    $edit['field_tags[' . LANGUAGE_NONE . ']'] = "$tag1, $tag2";
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    // Ensures the RDFa markup for the relationship between the node and its
+    // tags is correct.
+    $term_rdfa_meta = $this->xpath('//div[@about=:node-url and contains(@typeof, "sioc:Item") and contains(@typeof, "foaf:Document")]//ul[@class="links"]/li[@rel="dc:subject"]/a[@typeof="skos:Concept" and text()=:term-name]', array(
+      ':node-url' => url('node/' . $node->nid),
+      ':term-name' => $tag1,
+    ));
+    $this->assertTrue(!empty($term_rdfa_meta), t('Property dc:subject is present for the tag1 field item.'));
+    $term_rdfa_meta = $this->xpath('//div[@about=:node-url and contains(@typeof, "sioc:Item") and contains(@typeof, "foaf:Document")]//ul[@class="links"]/li[@rel="dc:subject"]/a[@typeof="skos:Concept" and text()=:term-name]', array(
+      ':node-url' => url('node/' . $node->nid),
+      ':term-name' => $tag2,
+    ));
+    $this->assertTrue(!empty($term_rdfa_meta), t('Property dc:subject is present for the tag2 field item.'));
   }
 }
 
@@ -511,9 +530,9 @@ class RdfCommentAttributesTestCase extends CommentHelperCase {
     $comments[] = $this->postComment($this->node1, $this->randomName(), $this->randomName());
 
     // Tests the reply_of relationship of a first level comment.
-    $result = $this->xpath("id('comments')//div[@class='comment' and position()=0]//span[@rel='sioc:reply_of' and @resource=:node]", array(':node' => url("node/{$this->node1->nid}")));
+    $result = $this->xpath("(id('comments')//div[contains(@class,'comment ')])[position()=1]//span[@rel='sioc:reply_of' and @resource=:node]", array(':node' => url("node/{$this->node1->nid}")));
     $this->assertEqual(1, count($result), t('RDFa markup referring to the node is present.'));
-    $result = $this->xpath("id('comments')//div[@class='comment' and position()=0]//span[@rel='sioc:reply_of' and @resource=:comment]", array(':comment' => url('comment/1#comment-1')));
+    $result = $this->xpath("(id('comments')//div[contains(@class,'comment ')])[position()=1]//span[@rel='sioc:reply_of' and @resource=:comment]", array(':comment' => url('comment/1#comment-1')));
     $this->assertFalse($result, t('No RDFa markup referring to the comment itself is present.'));
 
     // Posts a reply to the first comment.
@@ -521,10 +540,11 @@ class RdfCommentAttributesTestCase extends CommentHelperCase {
     $comments[] = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
 
     // Tests the reply_of relationship of a second level comment.
-    $result = $this->xpath("id('comments')//div[@class='comment' and position()=1]//span[@rel='sioc:reply_of' and @resource=:node]", array(':node' => url("node/{$this->node1->nid}")));
+    $result = $this->xpath("(id('comments')//div[contains(@class,'comment ')])[position()=2]//span[@rel='sioc:reply_of' and @resource=:node]", array(':node' => url("node/{$this->node1->nid}")));
     $this->assertEqual(1, count($result), t('RDFa markup referring to the node is present.'));
-    $result = $this->xpath("id('comments')//div[@class='comment' and position()=1]//span[@rel='sioc:reply_of' and @resource=:comment]", array(':comment' => url('comment/1#comment-1')));
+    $result = $this->xpath("(id('comments')//div[contains(@class,'comment ')])[position()=2]//span[@rel='sioc:reply_of' and @resource=:comment]", array(':comment' => url('comment/1', array('fragment' => 'comment-1'))));
     $this->assertEqual(1, count($result), t('RDFa markup referring to the parent comment is present.'));
+    $comments = $this->xpath("(id('comments')//div[contains(@class,'comment ')])[position()=2]");
   }
 
   /**
diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info
index d1714652509c17e2f95ad335e5dda47dcd97d3b3..3d6ef437738140c9c7270483ee76672cabc4ba38 100644
--- a/modules/rdf/tests/rdf_test.info
+++ b/modules/rdf/tests/rdf_test.info
@@ -1,15 +1,13 @@
-; $Id: rdf_test.info,v 1.1 2009/10/19 18:28:15 dries Exp $
+; $Id: rdf_test.info,v 1.2 2010/12/20 19:59:42 webchick Exp $
 name = "RDF module tests"
 description = "Support module for RDF module testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = rdf_test.install
-files[] = rdf_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/search/search-block-form.tpl.php b/modules/search/search-block-form.tpl.php
index 3338fb1138d44898bd79ecd87a631f5cc14e2c5c..6ad23e9432a1088ec125ba88b771158aaaf72270 100644
--- a/modules/search/search-block-form.tpl.php
+++ b/modules/search/search-block-form.tpl.php
@@ -1,40 +1,37 @@
 <?php
-// $Id: search-block-form.tpl.php,v 1.4 2010/06/03 13:18:48 dries Exp $
+// $Id: search-block-form.tpl.php,v 1.6 2011/01/03 00:17:55 webchick Exp $
 
 /**
  * @file
- * Default theme implementation for displaying a search form within a block
- * region.
+ * Displays the search form block.
  *
  * Available variables:
  * - $search_form: The complete search form ready for print.
- * - $search: Array of keyed search elements. Can be used to print each form
- *   element separately.
+ * - $search: Associative array of search elements. Can be used to print each
+ *   form element separately.
  *
- * Default keys within $search:
+ * Default elements within $search:
  * - $search['search_block_form']: Text input area wrapped in a div.
- * - $search['submit']: Form submit button.
- * - $search['hidden']: Hidden form elements. Used to validate forms when submitted.
- *
- * Since $search is keyed, a direct print of the form element is possible.
- * Modules can add to the search form so it is recommended to check for their
- * existence before printing. The default keys will always exist.
+ * - $search['actions']: Rendered form buttons.
+ * - $search['hidden']: Hidden form elements. Used to validate forms when
+ *   submitted.
  *
+ * Modules can add to the search form, so it is recommended to check for their
+ * existence before printing. The default keys will always exist. To check for
+ * a module-provided field, use code like this:
+ * @code
  *   <?php if (isset($search['extra_field'])): ?>
  *     <div class="extra-field">
  *       <?php print $search['extra_field']; ?>
  *     </div>
  *   <?php endif; ?>
- *
- * To check for all available data within $search, use the code below.
- *
- *   <?php print '<pre>'. check_plain(print_r($search, 1)) .'</pre>'; ?>
+ * @endcode
  *
  * @see template_preprocess_search_block_form()
  */
 ?>
 <div class="container-inline">
-  <?php if (empty($variables['form']['#block']->title)) : ?>
+  <?php if (empty($variables['form']['#block']->subject)) : ?>
     <h2 class="element-invisible"><?php print t('Search form'); ?></h2>
   <?php endif; ?>
   <?php print $search_form; ?>
diff --git a/modules/search/search-result.tpl.php b/modules/search/search-result.tpl.php
index d6ebd5f4fa37939addd39b3d261bd0e824e09434..ea85c06f587650e0763aab6f0496f3b5fd9e4492 100644
--- a/modules/search/search-result.tpl.php
+++ b/modules/search/search-result.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: search-result.tpl.php,v 1.7 2010/08/18 18:40:50 dries Exp $
+// $Id: search-result.tpl.php,v 1.9 2010/11/21 20:36:36 dries Exp $
 
 /**
  * @file
@@ -18,9 +18,15 @@
  * - $info_split: Contains same data as $info, split into a keyed array.
  * - $module: The machine-readable name of the module (tab) being searched, such
  *   as "node" or "user".
+ * - $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.
  *
  * Default keys within $info_split:
- * - $info_split['type']: Node type.
+ * - $info_split['type']: Node type (or item type string supplied by module).
  * - $info_split['user']: Author of the node linked to users profile. Depends
  *   on permission.
  * - $info_split['date']: Last update of the node. Short formatted.
@@ -29,31 +35,45 @@
  * - $info_split['upload']: Number of attachments output as "% attachments", %
  *   being the count. Depends on upload.module.
  *
+ * Other variables:
+ * - $classes_array: Array of HTML class attribute values. It is flattened
+ *   into a string within the variable $classes.
+ * - $title_attributes_array: Array of HTML attributes for the title. It is
+ *   flattened into a string within the variable $title_attributes.
+ * - $content_attributes_array: Array of HTML attributes for the content. It is
+ *   flattened into a string within the variable $content_attributes.
+ *
  * Since $info_split is keyed, a direct print of the item is possible.
  * This array does not apply to user searches so it is recommended to check
- * for their existence before printing. The default keys of 'type', 'user' and
+ * for its existence before printing. The default keys of 'type', 'user' and
  * 'date' always exist for node searches. Modules may provide other data.
- *
+ * @code
  *   <?php if (isset($info_split['comment'])) : ?>
  *     <span class="info-comment">
  *       <?php print $info_split['comment']; ?>
  *     </span>
  *   <?php endif; ?>
+ * @endcode
  *
  * To check for all available data within $info_split, use the code below.
- *
+ * @code
  *   <?php print '<pre>'. check_plain(print_r($info_split, 1)) .'</pre>'; ?>
+ * @endcode
  *
+ * @see template_preprocess()
  * @see template_preprocess_search_result()
+ * @see template_process()
  */
 ?>
-<li>
-  <h3 class="title">
+<li class="<?php print $classes; ?>"<?php print $attributes; ?>>
+  <?php print render($title_prefix); ?>
+  <h3 class="title"<?php print $title_attributes; ?>>
     <a href="<?php print $url; ?>"><?php print $title; ?></a>
   </h3>
+  <?php print render($title_suffix); ?>
   <div class="search-snippet-info">
     <?php if ($snippet) : ?>
-      <p class="search-snippet"><?php print $snippet; ?></p>
+      <p class="search-snippet"<?php print $content_attributes; ?>><?php print $snippet; ?></p>
     <?php endif; ?>
     <?php if ($info) : ?>
       <p class="search-info"><?php print $info; ?></p>
diff --git a/modules/search/search.api.php b/modules/search/search.api.php
index 1be1fcd1f86c7853ac7b77236eaa37887a18e764..867756472d44d8fb01fd66757327a22d0bcf23f8 100644
--- a/modules/search/search.api.php
+++ b/modules/search/search.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.api.php,v 1.30 2010/09/27 01:08:40 dries Exp $
+// $Id: search.api.php,v 1.33 2010/11/21 20:36:36 dries Exp $
 
 /**
  * @file
@@ -169,7 +169,7 @@ function hook_search_admin() {
  * parameters to the search expression.
  *
  * See node_search_execute() for an example of a module that uses the search
- * index, and user_execute_search() for an example that doesn't ues the search
+ * index, and user_search_execute() for an example that doesn't ues the search
  * index.
  *
  * @param $keys
@@ -181,13 +181,14 @@ function hook_search_admin() {
  *   An array of search results. To use the default search result
  *   display, each item should have the following keys':
  *   - 'link': Required. The URL of the found item.
- *   - 'type': The type of item.
+ *   - 'type': The type of item (such as the content type).
  *   - 'title': Required. The name of the item.
  *   - 'user': The author of the item.
  *   - 'date': A timestamp when the item was last modified.
  *   - 'extra': An array of optional extra information items.
  *   - 'snippet': An excerpt or preview to show with the result (can be
  *     generated with search_excerpt()).
+ *   - 'language': Language code for the item (usually two characters).
  *
  * @ingroup search
  */
@@ -272,8 +273,8 @@ function hook_search_page($results) {
 
   foreach ($results as $entry) {
     $output[] = array(
-      '#theme' => 'search_result', 
-      '#result' => $entry, 
+      '#theme' => 'search_result',
+      '#result' => $entry,
       '#module' => 'my_module_name',
     );
   }
diff --git a/modules/search/search.extender.inc b/modules/search/search.extender.inc
index afb6c1f15c9f656fc3459db38f6e301ef28e0e4c..7a684a39038bd89e8e61e833a81152b8ea0f37be 100644
--- a/modules/search/search.extender.inc
+++ b/modules/search/search.extender.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.extender.inc,v 1.8 2010/09/24 21:24:14 webchick Exp $
+// $Id: search.extender.inc,v 1.10 2010/11/22 07:32:12 webchick Exp $
 
 /**
  * @file
@@ -22,8 +22,8 @@
  * The second portion of the query further refines this set by verifying
  * advanced text conditions (such as negative or phrase matches).
  *
- * The used query object has the tag 'search_$type' and can be further extended
- * with hook_query_alter().
+ * The used query object has the tag 'search_$module' and can be further
+ * extended with hook_query_alter().
  */
 class SearchQuery extends SelectQueryExtender {
   /**
@@ -34,9 +34,11 @@ class SearchQuery extends SelectQueryExtender {
   protected $searchExpression;
 
   /**
-   * Type of search.
+   * Type of search (search module).
    *
-   * This maps to the value of the type column in search_index.
+   * This maps to the value of the type column in search_index, and is equal
+   * to the machine-readable name of the module that implements
+   * hook_search_info().
    *
    * @var string
    */
@@ -50,7 +52,7 @@ class SearchQuery extends SelectQueryExtender {
   protected $keys = array('positive' => array(), 'negative' => array());
 
   /**
-   * Indicates if the first pass query requires complex conditions (LIKE).
+   * Indicates whether the first pass query requires complex conditions (LIKE).
    *
    * @var boolean.
    */
@@ -94,7 +96,7 @@ class SearchQuery extends SelectQueryExtender {
   protected $normalize;
 
   /**
-   * Indicates if the first pass query has been executed.
+   * Indicates whether the first pass query has been executed.
    *
    * @var boolean
    */
@@ -122,33 +124,35 @@ class SearchQuery extends SelectQueryExtender {
   protected $multiply = array();
 
   /**
-   * Search items for the given search query string and type.
+   * Sets up the search query expression.
    *
    * @param $query
-   *   A search query string, that can contain options.
-   * @param $type
-   *   The type of search, this maps to {search_index}.type.
+   *   A search query string, which can contain options.
+   * @param $module
+   *   The search module. This maps to {search_index}.type in the database.
+   *
    * @return
    *   The SearchQuery object.
    */
-  public function searchExpression($expression, $type) {
+  public function searchExpression($expression, $module) {
     $this->searchExpression = $expression;
-    $this->type = $type;
+    $this->type = $module;
 
     return $this;
   }
 
   /**
-   * Apply a search option and remove it from the search query string.
+   * Applies a search option and removes it from the search query string.
    *
    * These options are in the form option:value,value2,value3.
    *
    * @param $option
    *   Name of the option.
    * @param $column
-   *   Name of the db column to which the value should be applied.
+   *   Name of the database column to which the value should be applied.
+   *
    * @return
-   *   TRUE if at least a value for that option has been found, FALSE if not.
+   *   TRUE if a value for that option was found, FALSE if not.
    */
   public function setOption($option, $column) {
     if ($values = search_expression_extract($this->searchExpression, $option)) {
@@ -164,9 +168,9 @@ class SearchQuery extends SelectQueryExtender {
   }
 
   /**
-   * Parse a search query into SQL conditions.
+   * Parses the search query into SQL conditions.
    *
-   * We build two queries that matches the dataset bodies.
+   * We build two queries that match the dataset bodies.
    */
   protected function parseSearchExpression() {
     // Matchs words optionally prefixed by a dash. A word in this case is
@@ -188,7 +192,9 @@ class SearchQuery extends SelectQueryExtender {
         $phrase = TRUE;
         $this->simple = FALSE;
       }
-      // Simplify keyword according to indexing rules and external preprocessors.
+      // Simplify keyword according to indexing rules and external
+      // preprocessors. Use same process as during search indexing, so it
+      // will match search index.
       $words = search_simplify($match[2]);
       // Re-explode in case simplification added more words, except when
       // matching a phrase.
@@ -290,7 +296,6 @@ class SearchQuery extends SelectQueryExtender {
     foreach ($split as $s) {
       $num = is_numeric($s);
       if ($num || drupal_strlen($s) >= variable_get('minimum_word_size', 3)) {
-        $s = $num ? ((int)ltrim($s, '-0')) : $s;
         if (!isset($this->words[$s])) {
           $this->words[$s] = $s;
           $num_new_scores++;
@@ -303,10 +308,10 @@ class SearchQuery extends SelectQueryExtender {
   }
 
   /**
-   * Execute the first pass query.
+   * Executes the first pass query.
    *
    * This can either be done explicitly, so that additional scores and
-   * conditions can be applied to the second pass query or implicitly by
+   * conditions can be applied to the second pass query, or implicitly by
    * addScore() or execute().
    *
    * @return
@@ -362,7 +367,7 @@ class SearchQuery extends SelectQueryExtender {
   /**
    * Adds a custom score expression to the search query.
    *
-   * Each score expression can optionally use a multiplicator and multiple
+   * Each score expression can optionally use a multiplier, and multiple
    * expressions are combined.
    *
    * @param $score
@@ -388,15 +393,15 @@ class SearchQuery extends SelectQueryExtender {
   }
 
   /**
-   * Execute the search.
+   * Executes the search.
    *
-   * If not already done, this executes the first pass query, then the complex
+   * If not already done, this executes the first pass query. Then the complex
    * conditions are applied to the query including score expressions and
    * ordering.
    *
    * @return
-   *   FALSE if the first pass query returned no results and a database result
-   *   set if not.
+   *   FALSE if the first pass query returned no results, and a database result
+   *   set if there were results.
    */
   public function execute()
   {
@@ -447,10 +452,10 @@ class SearchQuery extends SelectQueryExtender {
   }
 
   /**
-   * Build the default count query for SearchQuery.
+   * Builds 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
+   * Since SearchQuery always uses GROUP BY, we can default to a subquery. We
+   * also add the same conditions as execute() because countQuery() is called
    * first.
    */
   public function countQuery() {
diff --git a/modules/search/search.info b/modules/search/search.info
index d99e2d9afc10f87ea46cf1f6fa599d15361d4bbd..32b6d2ddf5e3cdecd24c29973f06bc199310fc5d 100644
--- a/modules/search/search.info
+++ b/modules/search/search.info
@@ -1,20 +1,16 @@
-; $Id: search.info,v 1.12 2010/09/05 02:21:38 dries Exp $
+; $Id: search.info,v 1.13 2010/12/20 19:59:43 webchick Exp $
 name = Search
 description = Enables site-wide keyword searching.
 package = Core
 version = VERSION
 core = 7.x
-files[] = search.module
-files[] = search.admin.inc
-files[] = search.pages.inc
-files[] = search.install
-files[] = search.test
 files[] = search.extender.inc
+files[] = search.test
 configure = admin/config/search/settings
 stylesheets[all][] = search.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/search/search.module b/modules/search/search.module
index 9923dd2fdb4ed487e86f9844161e6e0fb56cf016..7cc149e874a5ea10cec6273e704a98909dd82e3a 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.module,v 1.365 2010/10/20 01:31:07 dries Exp $
+// $Id: search.module,v 1.371 2011/01/04 05:31:09 webchick Exp $
 
 /**
  * @file
@@ -143,6 +143,7 @@ function search_block_info() {
   $blocks['form']['info'] = t('Search form');
   // Not worth caching.
   $blocks['form']['cache'] = DRUPAL_NO_CACHE;
+  $blocks['form']['properties']['administrative'] = TRUE;
   return $blocks;
 }
 
@@ -209,6 +210,7 @@ function search_menu() {
       );
       $items["$path/%menu_tail"] = array(
         'title' => $search_info['title'],
+        'load arguments' => array('%map', '%index'),
         'page callback' => 'search_view',
         'page arguments' => array($module, 2),
         'access callback' => '_search_menu_access',
@@ -296,41 +298,44 @@ function _search_menu_access($name) {
 }
 
 /**
- * Wipes a part of or the entire search index.
+ * Clears a part of or the entire search index.
  *
  * @param $sid
- *  (optional) The SID of the item to wipe. If specified, $type must be passed
- *  too.
- * @param $type
- *  (optional) The type of item to wipe.
+ *   (optional) The ID of the item to remove from the search index. If
+ *   specified, $module must also be given. Omit both $sid and $module to clear
+ *   the entire search index.
+ * @param $module
+ *   (optional) The machine-readable name of the module for the item to remove
+ *   from the search index.
  */
-function search_reindex($sid = NULL, $type = NULL, $reindex = FALSE) {
-  if ($type == NULL && $sid == NULL) {
+function search_reindex($sid = NULL, $module = NULL, $reindex = FALSE) {
+  if ($module == NULL && $sid == NULL) {
     module_invoke_all('search_reset');
   }
   else {
     db_delete('search_dataset')
       ->condition('sid', $sid)
-      ->condition('type', $type)
+      ->condition('type', $module)
       ->execute();
     db_delete('search_index')
       ->condition('sid', $sid)
-      ->condition('type', $type)
+      ->condition('type', $module)
       ->execute();
     // Don't remove links if re-indexing.
     if (!$reindex) {
       db_delete('search_node_links')
         ->condition('sid', $sid)
-        ->condition('type', $type)
+        ->condition('type', $module)
         ->execute();
     }
   }
 }
 
 /**
- * Marks a word as dirty (or retrieves the list of dirty words). This is used
- * during indexing (cron). Words which are dirty have outdated total counts in
- * the search_total table, and need to be recounted.
+ * Marks a word as "dirty" (changed), or retrieves the list of dirty words.
+ *
+ * This is used during indexing (cron). Words that are dirty have outdated
+ * total counts in the search_total table, and need to be recounted.
  */
 function search_dirty($word = NULL) {
   $dirty = &drupal_static(__FUNCTION__, array());
@@ -345,8 +350,9 @@ function search_dirty($word = NULL) {
 /**
  * Implements hook_cron().
  *
- * Fires hook_update_index() in all modules and cleans up dirty words (see
- * search_dirty).
+ * Fires hook_update_index() in all modules and cleans up dirty words.
+ *
+ * @see search_dirty()
  */
 function search_cron() {
   // We register a shutdown function to ensure that search_total is always up
@@ -360,7 +366,9 @@ function search_cron() {
 }
 
 /**
- * This function is called on shutdown to ensure that search_total is always
+ * Updates the {search_total} database table.
+ *
+ * This function is called on shutdown to ensure that {search_total} is always
  * up to date (even if cron times out or otherwise fails).
  */
 function search_update_totals() {
@@ -392,6 +400,14 @@ function search_update_totals() {
 
 /**
  * Simplifies a string according to indexing rules.
+ *
+ * @param $text
+ *   Text to simplify.
+ *
+ * @return
+ *   Simplified text.
+ *
+ * @see hook_search_preprocess()
  */
 function search_simplify($text) {
   // Decode entities to UTF-8
@@ -429,6 +445,11 @@ function search_simplify($text) {
   // marks, spacers, etc, to be a word boundary.
   $text = preg_replace('/[' . PREG_CLASS_UNICODE_WORD_BOUNDARY . ']+/u', ' ', $text);
 
+  // Truncate everything to 50 characters.
+  $words = explode(' ', $text);
+  array_walk($words, '_search_index_truncate');
+  $text = implode(' ', $words);
+
   return $text;
 }
 
@@ -479,7 +500,7 @@ function search_expand_cjk($matches) {
 }
 
 /**
- * Splits a string into tokens for indexing.
+ * Simplifies and splits a string into tokens for indexing.
  */
 function search_index_split($text) {
   $last = &drupal_static(__FUNCTION__);
@@ -491,7 +512,6 @@ function search_index_split($text) {
   // Process words
   $text = search_simplify($text);
   $words = explode(' ', $text);
-  array_walk($words, '_search_index_truncate');
 
   // Save last keyword result
   $last = $text;
@@ -504,6 +524,9 @@ function search_index_split($text) {
  * Helper function for array_walk in search_index_split.
  */
 function _search_index_truncate(&$text) {
+  if (is_numeric($text)) {
+    $text = ltrim($text, '0');
+  }
   $text = truncate_utf8($text, 50);
 }
 
@@ -520,17 +543,16 @@ function search_invoke_preprocess(&$text) {
  * Update the full-text search index for a particular item.
  *
  * @param $sid
- *   A number identifying this particular item (e.g. node id).
- *
- * @param $type
- *   A string defining this type of item (e.g. 'node')
- *
+ *   An ID number identifying this particular item (e.g., node ID).
+ * @param $module
+ *   The machine-readable name of the module that this item comes from (a module
+ *   that implements hook_search_info()).
  * @param $text
- *   The content of this item. Must be a piece of HTML text.
+ *   The content of this item. Must be a piece of HTML or plain text.
  *
  * @ingroup search
  */
-function search_index($sid, $type, $text) {
+function search_index($sid, $module, $text) {
   $minimum_word_size = variable_get('minimum_word_size', 3);
 
   // Link matching
@@ -638,14 +660,8 @@ function search_index($sid, $type, $text) {
         foreach ($words as $word) {
           // Add word to accumulator
           $accum .= $word . ' ';
-          $num = is_numeric($word);
           // Check wordlength
-          if ($num || drupal_strlen($word) >= $minimum_word_size) {
-            // Normalize numbers
-            if ($num) {
-              $word = (int)ltrim($word, '-0');
-            }
-
+          if (is_numeric($word) || drupal_strlen($word) >= $minimum_word_size) {
             // Links score mainly for the target.
             if ($link) {
               if (!isset($results[$linknid])) {
@@ -677,13 +693,13 @@ function search_index($sid, $type, $text) {
     $tag = !$tag;
   }
 
-  search_reindex($sid, $type, TRUE);
+  search_reindex($sid, $module, TRUE);
 
   // Insert cleaned up data into dataset
   db_insert('search_dataset')
     ->fields(array(
       'sid' => $sid,
-      'type' => $type,
+      'type' => $module,
       'data' => $accum,
       'reindex' => 0,
     ))
@@ -698,7 +714,7 @@ function search_index($sid, $type, $text) {
       ->key(array(
         'word' => $word,
         'sid' => $sid,
-        'type' => $type,
+        'type' => $module,
       ))
       ->fields(array('score' => $score))
       ->expression('score', 'score + :score', array(':score' => $score))
@@ -710,7 +726,7 @@ function search_index($sid, $type, $text) {
   // Get all previous links from this item.
   $result = db_query("SELECT nid, caption FROM {search_node_links} WHERE sid = :sid AND type = :type", array(
     ':sid' => $sid,
-    ':type' => $type
+    ':type' => $module
   ), array('target' => 'slave'));
   $links = array();
   foreach ($result as $link) {
@@ -726,7 +742,7 @@ function search_index($sid, $type, $text) {
         db_update('search_node_links')
           ->fields(array('caption' => $caption))
           ->condition('sid', $sid)
-          ->condition('type', $type)
+          ->condition('type', $module)
           ->condition('nid', $nid)
           ->execute();
         search_touch_node($nid);
@@ -734,14 +750,14 @@ function search_index($sid, $type, $text) {
       // Unset the link to mark it as processed.
       unset($links[$nid]);
     }
-    elseif ($sid != $nid || $type != 'node') {
+    elseif ($sid != $nid || $module != 'node') {
       // Insert the existing link and mark the node for reindexing, but don't
       // reindex if this is a link in a node pointing to itself.
       db_insert('search_node_links')
         ->fields(array(
           'caption' => $caption,
           'sid' => $sid,
-          'type' => $type,
+          'type' => $module,
           'nid' => $nid,
         ))
         ->execute();
@@ -752,7 +768,7 @@ function search_index($sid, $type, $text) {
   foreach ($links as $nid => $caption) {
     db_delete('search_node_links')
       ->condition('sid', $sid)
-      ->condition('type', $type)
+      ->condition('type', $module)
       ->condition('nid', $nid)
       ->execute();
     search_touch_node($nid);
@@ -760,10 +776,10 @@ function search_index($sid, $type, $text) {
 }
 
 /**
- * Change a node's changed timestamp to 'now' to force reindexing.
+ * Changes a node's changed timestamp to 'now' to force reindexing.
  *
  * @param $nid
- *   The nid of the node that needs reindexing.
+ *   The node ID of the node that needs reindexing.
  */
 function search_touch_node($nid) {
   db_update('search_dataset')
@@ -903,15 +919,15 @@ function search_expression_insert($expression, $option, $value = NULL) {
  * for all of the search features to work.
  *
  * There are three ways to interact with the search system:
- * - Specifically for searching nodes, you can implement hook_node_update_index()
- *   and hook_node_search_result(). However, note that the search system already
- *   indexes all visible output of a node, i.e. everything displayed normally
- *   by hook_view() and hook_node_view(). This is usually sufficient. You should
- *   only use this mechanism if you want additional, non-visible data to be
- *   indexed.
- * - Implement hook_search_info(). This will create a search tab for your module on
- *   the /search page with a simple keyword search form. You will also need to
- *   implement hook_search_execute() to perform the search.
+ * - Specifically for searching nodes, you can implement
+ *   hook_node_update_index() and hook_node_search_result(). However, note that
+ *   the search system already indexes all visible output of a node; i.e.,
+ *   everything displayed normally by hook_view() and hook_node_view(). This is
+ *   usually sufficient. You should only use this mechanism if you want
+ *   additional, non-visible data to be indexed.
+ * - Implement hook_search_info(). This will create a search tab for your module
+ *   on the /search page with a simple keyword search form. You will also need
+ *   to implement hook_search_execute() to perform the search.
  * - Implement hook_update_index(). This allows your module to use Drupal's
  *   HTML indexing mechanism for searching full text efficiently.
  *
@@ -926,11 +942,11 @@ function search_expression_insert($expression, $option, $value = NULL) {
  *
  * @param $action
  *   Form action. Defaults to "search/$path", where $path is the search path
- *   associated with the $type module in its hook_search_info(). This will be
+ *   associated with the module in its hook_search_info(). This will be
  *   run through url().
  * @param $keys
  *   The search string entered by the user, containing keywords for the search.
- * @param $type
+ * @param $module
  *   The search module to render the form for: a module that implements
  *   hook_search_info(). If not supplied, the default search module is used.
  * @param $prompt
@@ -940,14 +956,14 @@ function search_expression_insert($expression, $option, $value = NULL) {
  * @return
  *   A Form API array for the search form.
  */
-function search_form($form, &$form_state, $action = '', $keys = '', $type = NULL, $prompt = NULL) {
+function search_form($form, &$form_state, $action = '', $keys = '', $module = NULL, $prompt = NULL) {
   $module_info = FALSE;
-  if (!$type) {
+  if (!$module) {
     $module_info = search_get_default_module_info();
   }
   else {
     $info = search_get_info();
-    $module_info = isset($info[$type]) ? $info[$type] : FALSE;
+    $module_info = isset($info[$module]) ? $info[$module] : FALSE;
   }
 
   // Sanity check.
@@ -967,7 +983,7 @@ function search_form($form, &$form_state, $action = '', $keys = '', $type = NULL
   // Record the $action for later use in redirecting.
   $form_state['action'] = $action;
   $form['#attributes']['class'][] = 'search-form';
-  $form['module'] = array('#type' => 'value', '#value' => $type);
+  $form['module'] = array('#type' => 'value', '#value' => $module);
   $form['basic'] = array('#type' => 'container', '#attributes' => array('class' => array('container-inline')));
   $form['basic']['keys'] = array(
     '#type' => 'textfield',
@@ -1020,6 +1036,16 @@ function search_box_form_submit($form, &$form_state) {
     unset($_GET['destination']);
   }
 
+  // Check to see if the form was submitted empty.
+  // If it is empty, display an error message.
+  // (This method is used instead of setting #required to TRUE for this field
+  // because that results in a confusing error message.  It would say a plain
+  // "field is required" because the search keywords field has no title.
+  // The error message would also complain about a missing #title field.)
+  if ($form_state['values']['search_block_form'] == '') {
+    form_set_error('keys', t('Please enter some keywords.'));
+  }
+
   $form_id = $form['form_id']['#value'];
   $info = search_get_default_module_info();
   if ($info) {
@@ -1116,12 +1142,13 @@ function search_excerpt($keys, $text) {
   array_walk($keys, '_search_excerpt_replace');
   $workkeys = $keys;
 
-  // Extract a fragment per keyword for at most 4 keywords.
+  // Extract fragments around keywords.
   // First we collect ranges of text around each keyword, starting/ending
-  // at spaces.
+  // at spaces, trying to get to 256 characters.
   // If the sum of all fragments is too short, we look for second occurrences.
   $ranges = array();
   $included = array();
+  $foundkeys = array();
   $length = 0;
   while ($length < 256 && count($workkeys)) {
     foreach ($workkeys as $k => $key) {
@@ -1138,10 +1165,26 @@ function search_excerpt($keys, $text) {
       if (!isset($included[$key])) {
         $included[$key] = 0;
       }
-      // Locate a keyword (position $p), then locate a space in front (position
-      // $q) and behind it (position $s)
+      // Locate a keyword (position $p, always >0 because $text starts with a
+      // space). First try bare keyword, but if that doesn't work, try to find a
+      // derived form from search_simplify().
+      $p = 0;
       if (preg_match('/' . $boundary . $key . $boundary . '/iu', $text, $match, PREG_OFFSET_CAPTURE, $included[$key])) {
         $p = $match[0][1];
+      }
+      else {
+        $info = search_simplify_excerpt_match($key, $text, $included[$key], $boundary);
+        if ($info['where']) {
+          $p = $info['where'];
+          if ($info['keyword']) {
+            $foundkeys[] = $info['keyword'];
+          }
+        }
+      }
+      // Now locate a space in front (position $q) and behind it (position $s),
+      // leaving about 60 characters extra before and after for context.
+      // Note that a space was added to the front and end of $text above.
+      if ($p) {
         if (($q = strpos(' ' . $text, ' ', max(0, $p - 61))) !== FALSE) {
           $end = substr($text . ' ', $p, 80);
           if (($s = strrpos($end, ' ')) !== FALSE) {
@@ -1207,6 +1250,10 @@ function search_excerpt($keys, $text) {
   $text = (isset($newranges[0]) ? '' : $dots[0]) . implode($dots[1], $out) . $dots[2];
   $text = check_plain($text);
 
+  // Slash-escape quotes in keys found in a derived form and merge with original keys.
+  array_walk($foundkeys, '_search_excerpt_replace');
+  $keys = array_merge($keys, $foundkeys);
+
   // Highlight keywords. Must be done at once to prevent conflicts ('strong' and '<strong>').
   $text = preg_replace('/' . $boundary . '(' . implode('|', $keys) . ')' . $boundary . '/iu', '<strong>\0</strong>', $text);
   return $text;
@@ -1223,6 +1270,76 @@ function _search_excerpt_replace(&$text) {
   $text = preg_quote($text, '/');
 }
 
+/**
+ * Find words in the original text that matched via search_simplify().
+ *
+ * This is called in search_excerpt() if an exact match is not found in the
+ * text, so that we can find the derived form that matches.
+ *
+ * @param $key
+ *   The keyword to find.
+ * @param $text
+ *   The text to search for the keyword.
+ * @param $offset
+ *   Offset position in $text to start searching at.
+ * @param $boundary
+ *   Text to include in a regular expression that will match a word boundary.
+ *
+ * @return
+ *   FALSE if no match is found. If a match is found, return an associative
+ *   array with element 'where' giving the position of the match, and element
+ *   'keyword' giving the actual word found in the text at that position.
+ */
+function search_simplify_excerpt_match($key, $text, $offset, $boundary) {
+  $pos = NULL;
+  $simplified_key = search_simplify($key);
+  $simplified_text = search_simplify($text);
+
+  // Check if we have a match after simplification in the text.
+  if (!preg_match('/' . $boundary . $simplified_key . $boundary . '/iu', $simplified_text, $match, PREG_OFFSET_CAPTURE, $offset)) {
+    return FALSE;
+  }
+
+  // If we get here, we have a match. Now find the exact location of the match
+  // and the original text that matched. Start by splitting up the text by all
+  // potential starting points of the matching text and iterating through them.
+  $split = array_filter(preg_split('/' . $boundary . '/iu', $text, -1, PREG_SPLIT_OFFSET_CAPTURE), '_search_excerpt_match_filter');
+  foreach ($split as $value) {
+    // Skip starting points before the offset.
+    if ($value[1] < $offset) {
+      continue;
+    }
+
+    // Check a window of 80 characters after the starting point for a match,
+    // based on the size of the excerpt window.
+    $window = substr($text, $value[1], 80);
+    $simplified_window = search_simplify($window);
+    if (strpos($simplified_window, $simplified_key) === 0) {
+      // We have a match in this window. Store the position of the match.
+      $pos = $value[1];
+      // Iterate through the text in the window until we find the full original
+      // matching text.
+      $length = strlen($window);
+      for ($i = 1; $i <= $length; $i++) {
+        $keyfound = substr($text, $value[1], $i);
+        if ($simplified_key == search_simplify($keyfound)) {
+          break;
+        }
+      }
+      break;
+    }
+  }
+
+  return $pos ? array('where' => $pos, 'keyword' => $keyfound) : FALSE;
+}
+
+/**
+ * Helper function for array_filter() in search_search_excerpt_match().
+ */
+function _search_excerpt_match_filter($var) {
+  return strlen(trim($var[0]));
+}
+
 /**
  * Implements hook_forms().
  */
diff --git a/modules/search/search.pages.inc b/modules/search/search.pages.inc
index 8356c9996008d57147032089645e07fea440d931..4cdec26acfbd7f0b22eba18abb3295d8d1ffc5de 100644
--- a/modules/search/search.pages.inc
+++ b/modules/search/search.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.pages.inc,v 1.23 2010/08/18 18:40:50 dries Exp $
+// $Id: search.pages.inc,v 1.25 2010/11/21 20:36:36 dries Exp $
 
 /**
  * @file
@@ -77,8 +77,9 @@ function search_view($module = NULL, $keys = '') {
  * Process variables for search-results.tpl.php.
  *
  * The $variables array contains the following arguments:
- * - $results
- * - $module
+ * - $results: Search results array.
+ * - $module: Module the search results came from (module implementing
+ *   hook_search_info()).
  *
  * @see search-results.tpl.php
  */
@@ -104,9 +105,15 @@ function template_preprocess_search_results(&$variables) {
  * @see search-result.tpl.php
  */
 function template_preprocess_search_result(&$variables) {
+  global $language;
+
   $result = $variables['result'];
   $variables['url'] = check_url($result['link']);
   $variables['title'] = check_plain($result['title']);
+  if (isset($result['language']) && $result['language'] != $language->language && $result['language'] != LANGUAGE_NONE) {
+    $variables['title_attributes_array']['xml:lang'] = $result['language'];
+    $variables['content_attributes_array']['xml:lang'] = $result['language'];
+  }
 
   $info = array();
   if (!empty($result['module'])) {
diff --git a/modules/search/search.test b/modules/search/search.test
index 986db177e75da862cadc9f736e1edad794f10e88..c21d5071ee9264fa8f19ca95ba0b1e42f87ed286 100644
--- a/modules/search/search.test
+++ b/modules/search/search.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.test,v 1.77 2010/10/20 01:15:58 dries Exp $
+// $Id: search.test,v 1.86 2011/01/04 05:31:09 webchick 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.
@@ -279,6 +279,13 @@ class SearchPageText extends DrupalWebTestCase {
     $this->drupalPost('search/user', $edit, t('Search'));
     $this->assertText(t('Search'));
     $this->assertTitle($title, 'Search page title is correct');
+
+    // Test that search keywords containing slashes are correctly loaded
+    // from the path and displayed in the search form.
+    $arg = $this->randomName() . '/' . $this->randomName();
+    $this->drupalGet('search/node/' . $arg);
+    $input = $this->xpath("//input[@id='edit-keys' and @value='{$arg}']");
+    $this->assertFalse(empty($input), 'Search keys with a / are correctly set as the default value in the search box.');
   }
 }
 
@@ -526,7 +533,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
 
     // See testRankings() above - build a node that will rank high for sticky.
     $settings = array(
-      'type' => 'page', 
+      'type' => 'page',
       'title' => 'Drupal rocks',
       'body' => array(LANGUAGE_NONE => array(array('value' => "Drupal's search rocks"))),
       'sticky' => 1,
@@ -610,6 +617,25 @@ class SearchBlockTestCase extends DrupalWebTestCase {
     $this->drupalPost('admin/structure/block/manage/search/form/configure', $edit, t('Save block'));
     $this->drupalPost('node', $terms, t('Search'));
     $this->assertText('Your search yielded no results');
+
+    // Confirm that the user is redirected to the search page.
+    $this->assertEqual(
+      $this->getUrl(),
+      url('search/node/' . $terms['search_block_form'], array('absolute' => TRUE)),
+      t('Redirected to correct url.')
+    );
+
+    // Test an empty search via the block form, from the front page.
+    $terms = array('search_block_form' => '');
+    $this->drupalPost('node', $terms, t('Search'));
+    $this->assertText('Please enter some keywords');
+
+    // Confirm that the user is redirected to the search page, when form is submitted empty.
+    $this->assertEqual(
+      $this->getUrl(),
+      url('search/node/', array('absolute' => TRUE)),
+      t('Redirected to correct url.')
+    );
   }
 }
 
@@ -693,7 +719,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
 
     // Create and log in an administrative user having access to the Full HTML
     // text format.
-    $full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
+    $full_html_format = filter_format_load('full_html');
     $permissions = array(
       'administer filters',
       filter_permission_name($full_html_format),
@@ -714,7 +740,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
 
     variable_set('comment_preview_article', DRUPAL_OPTIONAL);
     // Enable check_plain() for 'Filtered HTML' text format.
-    $filtered_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Filtered HTML'))->fetchField();
+    $filtered_html_format_id = 'filtered_html';
     $edit = array(
       'filters[filter_html_escape][status]' => TRUE,
     );
@@ -733,7 +759,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
     $edit_comment = array();
     $edit_comment['subject'] = 'Test comment subject';
     $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = '<h1>' . $comment_body . '</h1>';
-    $full_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchField();
+    $full_html_format_id = 'full_html';
     $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][format]'] = $full_html_format_id;
     $this->drupalPost('comment/reply/' . $node->nid, $edit_comment, t('Save'));
 
@@ -864,6 +890,42 @@ class SearchCommentTestCase extends DrupalWebTestCase {
     $this->{$method}($this->comment_subject, "Comment subject $verb in search results: " . $message);
   }
 
+  /**
+   * Verify that 'add new comment' does not appear in search results or index.
+   */
+  function testAddNewComment() {
+    // Create a node with a short body.
+    $settings = array(
+      'type' => 'article',
+      'title' => 'short title',
+      'body' => array(LANGUAGE_NONE => array(array('value' => 'short body text'))),
+    );
+
+    $user = $this->drupalCreateUser(array('search content', 'create article content', 'access content'));
+    $this->drupalLogin($user);
+
+    $node = $this->drupalCreateNode($settings);
+    // Verify that if you view the node on its own page, 'add new comment'
+    // is there.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertText(t('Add new comment'), t('Add new comment appears on node page'));
+
+    // Run cron to index this page.
+    $this->drupalLogout();
+    $this->cronRun();
+
+    // Search for 'comment'. Should be no results.
+    $this->drupalLogin($user);
+    $this->drupalPost('search/node', array('keys' => 'comment'), t('Search'));
+    $this->assertText(t('Your search yielded no results'), t('No results searching for the word comment'));
+
+    // Search for the node title. Should be found, and 'Add new comment' should
+    // not be part of the search snippet.
+    $this->drupalPost('search/node', array('keys' => 'short'), t('Search'));
+    $this->assertText($node->title, t('Search for keyword worked'));
+    $this->assertNoText(t('Add new comment'), t('Add new comment does not appear on search results page'));
+  }
+
 }
 
 /**
@@ -929,9 +991,9 @@ class SearchExpressionInsertExtractTestCase extends DrupalUnitTestCase {
 
 /**
  * Tests that comment count display toggles properly on comment status of node
- * 
+ *
  * Issue 537278
- * 
+ *
  * - Nodes with comment status set to Open should always how comment counts
  * - Nodes with comment status set to Closed should show comment counts
  *     only when there are comments
@@ -940,7 +1002,7 @@ class SearchExpressionInsertExtractTestCase extends DrupalUnitTestCase {
 class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
   protected $searching_user;
   protected $searchable_nodes;
-  
+
   public static function getInfo() {
     return array(
       'name' => 'Comment count toggle',
@@ -957,23 +1019,23 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
 
     // Create initial nodes.
     $node_params = array('type' => 'article', 'body' => array(LANGUAGE_NONE => array(array('value' => 'SearchCommentToggleTestCase'))));
-    
+
     $this->searchable_nodes['1 comment'] = $this->drupalCreateNode($node_params);
     $this->searchable_nodes['0 comments'] = $this->drupalCreateNode($node_params);
-    
+
     // Login with sufficient privileges.
     $this->drupalLogin($this->searching_user);
-    
+
     // Create a comment array
     $edit_comment = array();
     $edit_comment['subject'] = $this->randomName();
     $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
-    $filtered_html_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Filtered HTML'))->fetchField();
+    $filtered_html_format_id = 'filtered_html';
     $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][format]'] = $filtered_html_format_id;
-    
+
     // Post comment to the test node with comment
     $this->drupalPost('comment/reply/' . $this->searchable_nodes['1 comment']->nid, $edit_comment, t('Save'));
-    
+
     // First update the index. This does the initial processing.
     node_update_index();
 
@@ -996,13 +1058,13 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
     $this->drupalPost('', $edit, t('Search'));
     $this->assertText(t('0 comments'), t('Empty comment count displays for nodes with comment status set to Open'));
     $this->assertText(t('1 comment'), t('Non-empty comment count displays for nodes with comment status set to Open'));
-    
+
     // Test comment count display for nodes with comment status set to Closed
     $this->searchable_nodes['0 comments']->comment = COMMENT_NODE_CLOSED;
     node_save($this->searchable_nodes['0 comments']);
     $this->searchable_nodes['1 comment']->comment = COMMENT_NODE_CLOSED;
     node_save($this->searchable_nodes['1 comment']);
-    
+
     $this->drupalPost('', $edit, t('Search'));
     $this->assertNoText(t('0 comments'), t('Empty comment count does not display for nodes with comment status set to Closed'));
     $this->assertText(t('1 comment'), t('Non-empty comment count displays for nodes with comment status set to Closed'));
@@ -1011,8 +1073,8 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
     $this->searchable_nodes['0 comments']->comment = COMMENT_NODE_HIDDEN;
     node_save($this->searchable_nodes['0 comments']);
     $this->searchable_nodes['1 comment']->comment = COMMENT_NODE_HIDDEN;
-    node_save($this->searchable_nodes['1 comment']);    
-    
+    node_save($this->searchable_nodes['1 comment']);
+
     $this->drupalPost('', $edit, t('Search'));
     $this->assertNoText(t('0 comments'), t('Empty comment count does not display for nodes with comment status set to Hidden'));
     $this->assertNoText(t('1 comment'), t('Non-empty comment count does not display for nodes with comment status set to Hidden'));
@@ -1031,23 +1093,55 @@ class SearchSimplifyTestCase extends DrupalWebTestCase {
     );
   }
 
+  /**
+   * Tests that all Unicode characters simplify correctly.
+   */
   function testSearchSimplifyUnicode() {
+    // This test uses a file that was constructed so that the even lines are
+    // boundary characters, and the odd lines are valid word characters. (It
+    // was generated as a sequence of all the Unicode characters, and then the
+    // boundary chararacters (punctuation, spaces, etc.) were split off into
+    // their own lines).  So the even-numbered lines should simplify to nothing,
+    // and the odd-numbered lines we need to split into shorter chunks and
+    // verify that simplification doesn't lose any characters.
     $input = file_get_contents(DRUPAL_ROOT . '/modules/search/tests/UnicodeTest.txt');
-    $strings = explode(chr(10), $input);
-    foreach ($strings as $key => $string) {
-      $simplified = search_simplify($string);
-      if ($key % 2) {
+    $basestrings = explode(chr(10), $input);
+    $strings = array();
+    foreach ($basestrings as $key => $string) {
+      if ($key %2) {
+        // Even line - should simplify down to a space.
+        $simplified = search_simplify($string);
         $this->assertIdentical($simplified, ' ', "Line $key is excluded from the index");
       }
       else {
-        $this->assertTrue(drupal_strlen($simplified) >= drupal_strlen($string), "Nothing is removed on line $key.");
+        // Odd line, should be word characters.
+        // Split this into 30-character chunks, so we don't run into limits
+        // of truncation in search_simplify().
+        $start = 0;
+        while ($start < drupal_strlen($string)) {
+          $newstr = drupal_substr($string, $start, 30);
+          // Special case: leading zeros are removed from numeric strings,
+          // and there's one string in this file that is numbers starting with
+          // zero, so prepend a 1 on that string.
+          if (preg_match('/^[0-9]+$/', $newstr)) {
+            $newstr = '1' . $newstr;
+          }
+          $strings[] = $newstr;
+          $start += 30;
+        }
       }
     }
+    foreach ($strings as $key => $string) {
+      $simplified = search_simplify($string);
+      $this->assertTrue(drupal_strlen($simplified) >= drupal_strlen($string), "Nothing is removed from string $key.");
+    }
+
+    // Test the low-numbered ASCII control characters separately. They are not
+    // in the text file because they are problematic for diff, especially \0.
     $string = '';
     for ($i = 0; $i < 32; $i++) {
       $string .= chr($i);
     }
-    // Diff really does not like files starting with \0 so test it separately.
     $this->assertIdentical(' ', search_simplify($string), t('Search simplify works for ASCII control characters.'));
   }
 
@@ -1121,6 +1215,177 @@ class SearchKeywordsConditions extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests that numbers can be searched.
+ */
+class SearchNumbersTestCase extends DrupalWebTestCase {
+  protected $test_user;
+  protected $numbers;
+  protected $nodes;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Search numbers',
+      'description' => 'Check that numbers can be searched',
+      'group' => 'Search',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('search');
+
+    $this->test_user = $this->drupalCreateUser(array('search content', 'access content', 'administer nodes', 'access site reports'));
+    $this->drupalLogin($this->test_user);
+
+    // Create content with various numbers in it.
+    // Note: 50 characters is the current limit of the search index's word
+    // field.
+    $this->numbers = array(
+      'ISBN' => '978-0446365383',
+      'UPC' => '036000 291452',
+      'EAN bar code' => '5901234123457',
+      'negative' => '-123456.7890',
+      'quoted negative' => '"-123456.7890"',
+      'leading zero' => '0777777777',
+      'tiny' => '111',
+      'small' => '22222222222222',
+      'medium' => '333333333333333333333333333',
+      'large' => '444444444444444444444444444444444444444',
+      'gigantic' => '5555555555555555555555555555555555555555555555555',
+      'over fifty characters' => '666666666666666666666666666666666666666666666666666666666666',
+      'date', '01/02/2009',
+      'commas', '987,654,321',
+    );
+
+    foreach ($this->numbers as $doc => $num) {
+      $info = array(
+        'body' => array(LANGUAGE_NONE => array(array('value' => $num))),
+        'type' => 'page',
+        'language' => LANGUAGE_NONE,
+        'title' => $doc . ' number',
+      );
+      $this->nodes[$doc] = $this->drupalCreateNode($info);
+    }
+
+    // Run cron to ensure the content is indexed.
+    $this->cronRun();
+    $this->drupalGet('admin/reports/dblog');
+    $this->assertText(t('Cron run completed'), 'Log shows cron run completed');
+  }
+
+  /**
+   * Tests that all the numbers can be searched.
+   */
+  function testNumberSearching() {
+    $types = array_keys($this->numbers);
+
+    foreach ($types as $type) {
+      $number = $this->numbers[$type];
+      // If the number is negative, remove the - sign, because - indicates
+      // "not keyword" when searching.
+      $number = ltrim($number, '-');
+      $node = $this->nodes[$type];
+
+      // Verify that the node title does not appear on the search page
+      // with a dummy search.
+      $this->drupalPost('search/node',
+        array('keys' => 'foo'),
+        t('Search'));
+      $this->assertNoText($node->title, $type . ': node title not shown in dummy search');
+
+      // Verify that the node title does appear as a link on the search page
+      // when searching for the number.
+      $this->drupalPost('search/node',
+        array('keys' => $number),
+        t('Search'));
+      $this->assertText($node->title, $type . ': node title shown (search found the node) in search for number ' . $number);
+    }
+  }
+}
+
+/**
+ * Tests that numbers can be searched, with more complex matching.
+ */
+class SearchNumberMatchingTestCase extends DrupalWebTestCase {
+  protected $test_user;
+  protected $numbers;
+  protected $nodes;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Search number matching',
+      'description' => 'Check that numbers can be searched with more complex matching',
+      'group' => 'Search',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('search');
+
+    $this->test_user = $this->drupalCreateUser(array('search content', 'access content', 'administer nodes', 'access site reports'));
+    $this->drupalLogin($this->test_user);
+
+    // Define a group of numbers that should all match each other --
+    // numbers with internal punctuation should match each other, as well
+    // as numbers with and without leading zeros and leading/trailing
+    // . and -.
+    $this->numbers = array(
+      '123456789',
+      '12/34/56789',
+      '12.3456789',
+      '12-34-56789',
+      '123,456,789',
+      '-123456789',
+      '0123456789',
+    );
+
+    foreach ($this->numbers as $num) {
+      $info = array(
+        'body' => array(LANGUAGE_NONE => array(array('value' => $num))),
+        'type' => 'page',
+        'language' => LANGUAGE_NONE,
+      );
+      $this->nodes[] = $this->drupalCreateNode($info);
+    }
+
+    // Run cron to ensure the content is indexed.
+    $this->cronRun();
+    $this->drupalGet('admin/reports/dblog');
+    $this->assertText(t('Cron run completed'), 'Log shows cron run completed');
+  }
+
+  /**
+   * Tests that all the numbers can be searched.
+   */
+  function testNumberSearching() {
+    for ($i = 0; $i < count($this->numbers); $i++) {
+      $node = $this->nodes[$i];
+
+      // Verify that the node title does not appear on the search page
+      // with a dummy search.
+      $this->drupalPost('search/node',
+        array('keys' => 'foo'),
+        t('Search'));
+      $this->assertNoText($node->title, $i . ': node title not shown in dummy search');
+
+      // Now verify that we can find node i by searching for any of the
+      // numbers.
+      for ($j = 0; $j < count($this->numbers); $j++) {
+        $number = $this->numbers[$j];
+        // If the number is negative, remove the - sign, because - indicates
+        // "not keyword" when searching.
+        $number = ltrim($number, '-');
+
+        $this->drupalPost('search/node',
+          array('keys' => $number),
+          t('Search'));
+        $this->assertText($node->title, $i . ': node title shown (search found the node) in search for number ' . $number);
+      }
+    }
+
+  }
+}
+
 /**
  * Test config page.
  */
@@ -1184,7 +1449,7 @@ class SearchConfigSettingsForm extends DrupalWebTestCase {
    * Verify that you can disable individual search modules.
    */
   function testSearchModuleDisabling() {
-    // Array of search types to test: 'path' is the search path, 'title' is
+    // Array of search modules to test: 'path' is the search path, 'title' is
     // the tab title, 'keys' are the keywords to search for, and 'text' is
     // the text to assert is on the results page.
     $module_info = array(
@@ -1317,6 +1582,40 @@ class SearchExcerptTestCase extends DrupalUnitTestCase {
     $this->assertFalse(strpos($result, '&'), 'Entities are not present in excerpt');
     $this->assertTrue(strpos($result, 'í') > 0, 'Entities are converted in excerpt');
   }
+
+  /**
+   * Tests search_excerpt() with search keywords matching simplified words.
+   *
+   * Excerpting should handle keywords that are matched only after going through
+   * search_simplify(). This test passes keywords that match simplified words
+   * and compares them with strings that contain the original unsimplified word.
+   */
+  function testSearchExcerptSimplified() {
+    $lorem1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae arcu at leo cursus laoreet. Curabitur dui tortor, adipiscing malesuada tempor in, bibendum ac diam. Cras non tellus a libero pellentesque condimentum. What is a Drupalism? Suspendisse ac lacus libero. Ut non est vel nisl faucibus interdum nec sed leo. Pellentesque sem risus, vulputate eu semper eget, auctor in libero.';
+    $lorem2 = 'Ut fermentum est vitae metus convallis scelerisque. Phasellus pellentesque rhoncus tellus, eu dignissim purus posuere id. Quisque eu fringilla ligula. Morbi ullamcorper, lorem et mattis egestas, tortor neque pretium velit, eget eleifend odio turpis eu purus. Donec vitae metus quis leo pretium tincidunt a pulvinar sem. Morbi adipiscing laoreet mauris vel placerat. Nullam elementum, nisl sit amet scelerisque malesuada, dolor nunc hendrerit quam, eu ultrices erat est in orci.';
+
+    // Make some text with some keywords that will get simplified.
+    $text = $lorem1 . ' Number: 123456.7890 Hyphenated: one-two abc,def ' . $lorem2;
+    // Note: The search_excerpt() function adds some extra spaces -- not
+    // important for HTML formatting. Remove these for comparison.
+    $result = preg_replace('| +|', ' ', search_excerpt('123456.7890', $text));
+    $this->assertTrue(strpos($result, 'Number: <strong>123456.7890</strong>') !== FALSE, 'Numeric keyword is highlighted with exact match');
+
+    $result = preg_replace('| +|', ' ', search_excerpt('1234567890', $text));
+    $this->assertTrue(strpos($result, 'Number: <strong>123456.7890</strong>') !== FALSE, 'Numeric keyword is highlighted with simplified match');
+
+    $result = preg_replace('| +|', ' ', search_excerpt('Number 1234567890', $text));
+    $this->assertTrue(strpos($result, '<strong>Number</strong>: <strong>123456.7890</strong>') !== FALSE, 'Punctuated and numeric keyword is highlighted with simplified match');
+
+    $result = preg_replace('| +|', ' ', search_excerpt('"Number 1234567890"', $text));
+    $this->assertTrue(strpos($result, '<strong>Number: 123456.7890</strong>') !== FALSE, 'Phrase with punctuated and numeric keyword is highlighted with simplified match');
+
+    $result = preg_replace('| +|', ' ', search_excerpt('"Hyphenated onetwo"', $text));
+    $this->assertTrue(strpos($result, '<strong>Hyphenated: one-two</strong>') !== FALSE, 'Phrase with punctuated and hyphenated keyword is highlighted with simplified match');
+
+    $result = preg_replace('| +|', ' ', search_excerpt('"abc def"', $text));
+    $this->assertTrue(strpos($result, '<strong>abc,def</strong>') !== FALSE, 'Phrase with keyword simplified into two separate words is highlighted with simplified match');
+  }
 }
 
 /**
@@ -1579,3 +1878,68 @@ class SearchPageOverride extends DrupalWebTestCase {
     $this->assertText('Test page text is here', 'Page override is working');
   }
 }
+
+/**
+ * Test node search with multiple languages.
+ */
+class SearchLanguageTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Search language selection',
+      'description' => 'Tests advanced search with different languages enabled.',
+      'group' => 'Search',
+    );
+  }
+
+  /**
+   * Implementation setUp().
+   */
+  function setUp() {
+    parent::setUp('search', 'locale');
+
+    // Create and login user.
+    $test_user = $this->drupalCreateUser(array('access content', 'search content', 'use advanced search', 'administer nodes', 'administer languages', 'access administration pages'));
+    $this->drupalLogin($test_user);
+  }
+
+  function testLanguages() {
+    // Check that there are initially no languages displayed.
+    $this->drupalGet('search/node');
+    $this->assertNoText(t('Languages'), t('No languages to choose from.'));
+
+    // Add predefined language.
+    $edit = array('langcode' => 'fr');
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->assertText('fr', t('Language added successfully.'));
+
+    // Now we should have languages displayed.
+    $this->drupalGet('search/node');
+    $this->assertText(t('Languages'), t('Languages displayed to choose from.'));
+    $this->assertText(t('English'), t('English is a possible choice.'));
+    $this->assertText(t('French'), t('French is a possible choice.'));
+
+    // Ensure selecting no language does not make the query different.
+    $this->drupalPost('search/node', array(), t('Advanced search'));
+    $this->assertEqual($this->getUrl(), url('search/node/', array('absolute' => TRUE)), t('Correct page redirection, no language filtering.'));
+
+    // Pick French and ensure it is selected.
+    $edit = array('language[fr]' => TRUE);
+    $this->drupalPost('search/node', $edit, t('Advanced search'));
+    $this->assertFieldByXPath('//input[@name="keys"]', 'language:fr', t('Language filter added to query.'));
+
+    // Change the default language and disable English.
+    $path = 'admin/config/regional/language';
+    $this->drupalGet($path);
+    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+    $edit = array('site_default' => 'fr');
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+    $edit = array('enabled[en]' => FALSE);
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+    $this->assertNoFieldChecked('edit-enabled-en', t('Language disabled.'));
+
+    // Check that there are again no languages displayed.
+    $this->drupalGet('search/node');
+    $this->assertNoText(t('Languages'), t('No languages to choose from.'));
+  }
+}
diff --git a/modules/search/tests/search_embedded_form.info b/modules/search/tests/search_embedded_form.info
index 2c24356e63b25858a57060f20df5738e4d8fcbaa..1fd889dade364585b273b4ca2d9d0d4c77970dee 100644
--- a/modules/search/tests/search_embedded_form.info
+++ b/modules/search/tests/search_embedded_form.info
@@ -1,14 +1,13 @@
-; $Id: search_embedded_form.info,v 1.1 2010/08/11 14:21:39 dries Exp $
+; $Id: search_embedded_form.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Search embedded form"
 description = "Support module for search module testing of embedded forms."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = search_embedded_form.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/search/tests/search_extra_type.info b/modules/search/tests/search_extra_type.info
index 9d2930f5530bd722bb80c594c0d98ac6b349abb0..64120eb0a7f96949bd38b7d00ffcd625556a4b19 100644
--- a/modules/search/tests/search_extra_type.info
+++ b/modules/search/tests/search_extra_type.info
@@ -1,14 +1,13 @@
-; $Id: search_extra_type.info,v 1.1 2010/08/05 07:11:15 webchick Exp $
+; $Id: search_extra_type.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Test search type"
 description = "Support module for search module testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = search_extra_type.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/shortcut/shortcut.css b/modules/shortcut/shortcut.css
index 032544252683450d5b246f9c9b25310c98d1d839..d844056ed13de697a59c1013e00f1ed9c55dd962 100644
--- a/modules/shortcut/shortcut.css
+++ b/modules/shortcut/shortcut.css
@@ -1,4 +1,4 @@
-/* $Id: shortcut.css,v 1.9 2010/10/20 01:06:51 dries Exp $ */
+/* $Id: shortcut.css,v 1.10 2011/01/03 07:04:48 webchick Exp $ */
 div#toolbar a#edit-shortcuts {
   float: right;
   padding: 5px 10px 5px 5px;
@@ -23,9 +23,9 @@ div#toolbar div.toolbar-shortcuts ul {
 div#toolbar div.toolbar-shortcuts ul li a {
   padding: 0 5px 0 5px;
   margin-right: 5px;
-  border-radius: 5px;
   -moz-border-radius: 5px;
   -webkit-border-radius: 5px;
+  border-radius: 5px;
 }
 
 div#toolbar div.toolbar-shortcuts ul li a:focus,
@@ -45,9 +45,9 @@ div#toolbar div.toolbar-shortcuts span.icon {
   width: 30px;
   height: 30px;
   margin-right: 5px;
-  border-radius: 5px;
   -moz-border-radius: 5px;
   -webkit-border-radius: 5px;
+  border-radius: 5px;
 }
 
 div.add-or-remove-shortcuts {
@@ -90,12 +90,12 @@ div.add-or-remove-shortcuts a:hover span.text {
   display: block;
   padding-right: 6px;
   cursor: pointer;
-  border-top-right-radius: 5px;
-  border-bottom-right-radius: 5px;
-  -moz-border-radius-topright: 5px;
   -moz-border-radius-bottomright: 5px;
-  -webkit-border-top-right-radius: 5px;
+  -moz-border-radius-topright: 5px;
   -webkit-border-bottom-right-radius: 5px;
+  -webkit-border-top-right-radius: 5px;
+  border-bottom-right-radius: 5px;
+  border-top-right-radius: 5px;
 }
 
 #shortcut-set-switch .form-type-radios {
diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info
index 3b126c0ea321643f95d60c52326905d59b1ef0c8..095290da48f534213a198c38a2586223f3281aed 100644
--- a/modules/shortcut/shortcut.info
+++ b/modules/shortcut/shortcut.info
@@ -1,17 +1,14 @@
-; $Id: shortcut.info,v 1.4 2010/03/06 06:33:14 dries Exp $
+; $Id: shortcut.info,v 1.5 2010/12/20 19:59:43 webchick Exp $
 name = Shortcut
 description = Allows users to manage customizable lists of shortcut links.
 package = Core
 version = VERSION
 core = 7.x
-files[] = shortcut.module
-files[] = shortcut.admin.inc
-files[] = shortcut.install
 files[] = shortcut.test
 configure = admin/config/user-interface/shortcut
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/shortcut/shortcut.png b/modules/shortcut/shortcut.png
index e5b33873a277c7a8b57e56e20411a26cf5ff1a87..1d9567398e8a9825153bb464db6440b8a7bb1244 100644
Binary files a/modules/shortcut/shortcut.png and b/modules/shortcut/shortcut.png differ
diff --git a/modules/shortcut/shortcut.test b/modules/shortcut/shortcut.test
index bf02ea37655e761e541d1bee006cf9a240d344ba..458dfd69cd50acb88332646b041d3c6d491b88d2 100644
--- a/modules/shortcut/shortcut.test
+++ b/modules/shortcut/shortcut.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: shortcut.test,v 1.6 2010/10/15 04:21:02 webchick Exp $
+// $Id: shortcut.test,v 1.7 2010/11/27 20:25:44 dries Exp $
 
 /**
  * @file
@@ -34,7 +34,7 @@ class ShortcutTestCase extends DrupalWebTestCase {
   function setUp() {
     parent::setUp('toolbar', 'shortcut');
     // Create users.
-    $this->admin_user = $this->drupalCreateUser(array('access toolbar', 'administer shortcuts', 'create article content', 'create page content', 'access content overview'));
+    $this->admin_user = $this->drupalCreateUser(array('access toolbar', 'administer shortcuts', 'view the administration theme', 'create article content', 'create page content', 'access content overview'));
     $this->shortcut_user = $this->drupalCreateUser(array('customize shortcut links', 'switch shortcut sets'));
 
     // Create a node.
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 76c0248d3565c0fdbe928ec913389f963f60bf79..c58aa34defaee164feb744f197c44a5fe09e73c9 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.243 2010/10/23 02:26:11 webchick Exp $
+// $Id: drupal_web_test_case.php,v 1.257 2011/01/02 23:54:05 webchick Exp $
 
 /**
  * Global variable that holds information about the tests being run.
@@ -431,8 +431,17 @@ abstract class DrupalTestCase {
 
   /**
    * Run all tests in this class.
+   *
+   * Regardless of whether $methods are passed or not, only method names
+   * starting with "test" are executed.
+   *
+   * @param $methods
+   *   (optional) A list of method names in the test case class to run; e.g.,
+   *   array('testFoo', 'testBar'). By default, all methods of the class are
+   *   taken into account, but it can be useful to only run a few selected test
+   *   methods during debugging.
    */
-  public function run() {
+  public function run(array $methods = array()) {
     // Initialize verbose debugging.
     simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), get_class($this));
 
@@ -447,8 +456,13 @@ abstract class DrupalTestCase {
 
     set_error_handler(array($this, 'errorHandler'));
     $class = get_class($this);
-    // Iterate through all the methods in this class.
-    foreach (get_class_methods($class) as $method) {
+    // Iterate through all the methods in this class, unless a specific list of
+    // methods to run was passed.
+    $class_methods = get_class_methods($class);
+    if ($methods) {
+      $class_methods = array_intersect($class_methods, $methods);
+    }
+    foreach ($class_methods as $method) {
       // If the current method starts with "test", run it - it's a test.
       if (strtolower(substr($method, 0, 4)) == 'test') {
         // Insert a fail record. This will be deleted on completion to ensure
@@ -517,7 +531,8 @@ abstract class DrupalTestCase {
       'file' => $exception->getFile(),
     ));
     require_once DRUPAL_ROOT . '/includes/errors.inc';
-    $this->error(t('%type: %message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace));
+    // The exception message is run through check_plain() by _drupal_decode_exception().
+    $this->error(t('%type: !message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace));
   }
 
   /**
@@ -563,6 +578,55 @@ abstract class DrupalTestCase {
     }
     return $str;
   }
+
+  /**
+   * Converts a list of possible parameters into a stack of permutations.
+   *
+   * Takes a list of parameters containing possible values, and converts all of
+   * them into a list of items containing every possible permutation.
+   *
+   * Example:
+   * @code
+   * $parameters = array(
+   *   'one' => array(0, 1),
+   *   'two' => array(2, 3),
+   * );
+   * $permutations = $this->permute($parameters);
+   * // Result:
+   * $permutations == array(
+   *   array('one' => 0, 'two' => 2),
+   *   array('one' => 1, 'two' => 2),
+   *   array('one' => 0, 'two' => 3),
+   *   array('one' => 1, 'two' => 3),
+   * )
+   * @endcode
+   *
+   * @param $parameters
+   *   An associative array of parameters, keyed by parameter name, and whose
+   *   values are arrays of parameter values.
+   *
+   * @return
+   *   A list of permutations, which is an array of arrays. Each inner array
+   *   contains the full list of parameters that have been passed, but with a
+   *   single value only.
+   */
+  public static function generatePermutations($parameters) {
+    $all_permutations = array(array());
+    foreach ($parameters as $parameter => $values) {
+      $new_permutations = array();
+      // Iterate over all values of the parameter.
+      foreach ($values as $value) {
+        // Iterate over all existing permutations.
+        foreach ($all_permutations as $permutation) {
+          // Add the new parameter value to existing permutations.
+          $new_permutations[] = $permutation + array($parameter => $value);
+        }
+      }
+      // Replace the old permutations with the new permutations.
+      $all_permutations = $new_permutations;
+    }
+    return $all_permutations;
+  }
 }
 
 /**
@@ -596,8 +660,6 @@ class DrupalUnitTestCase extends DrupalTestCase {
     // Store necessary current values before switching to the test environment.
     $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
 
-    spl_autoload_register('db_autoload');
-
     // Reset all statics so that test is performed with a clean environment.
     drupal_static_reset();
 
@@ -786,12 +848,14 @@ class DrupalWebTestCase extends DrupalTestCase {
    *
    * @param title
    *   A node title, usually generated by $this->randomName().
+   * @param $reset
+   *   (optional) Whether to reset the internal node_load() cache.
    *
    * @return
    *   A node object matching $title.
    */
-  function drupalGetNodeByTitle($title) {
-    $nodes = node_load_multiple(array(), array('title' => $title));
+  function drupalGetNodeByTitle($title, $reset = FALSE) {
+    $nodes = node_load_multiple(array(), array('title' => $title), $reset);
     // Load the first node returned from the database.
     $returned_node = reset($nodes);
     return $returned_node;
@@ -1298,9 +1362,32 @@ class DrupalWebTestCase extends DrupalTestCase {
    * set up a clean environment for the current test run.
    */
   protected function preloadRegistry() {
+    // Use two separate queries, each with their own connections: copy the
+    // {registry} and {registry_file} tables over from the parent installation
+    // to the child installation.
     $original_connection = Database::getConnection('default', 'simpletest_original_default');
-    db_query('INSERT INTO {registry} SELECT * FROM ' . $original_connection->prefixTables('{registry}'));
-    db_query('INSERT INTO {registry_file} SELECT * FROM ' . $original_connection->prefixTables('{registry_file}'));
+    $test_connection = Database::getConnection();
+
+    foreach (array('registry', 'registry_file') as $table) {
+      // Find the records from the parent database.
+      $source_query = $original_connection
+        ->select($table, array(), array('fetch' => PDO::FETCH_ASSOC))
+        ->fields($table);
+
+      $dest_query = $test_connection->insert($table);
+
+      $first = TRUE;
+      foreach ($source_query->execute() as $row) {
+        if ($first) {
+          $dest_query->fields(array_keys($row));
+          $first = FALSE;
+        }
+        // Insert the records into the child database.
+        $dest_query->values($row);
+      }
+
+      $dest_query->execute();
+    }
   }
 
   /**
@@ -1311,16 +1398,22 @@ class DrupalWebTestCase extends DrupalTestCase {
    * are enabled later.
    */
   protected function resetAll() {
-    // Rebuild caches.
+    // Reset all static variables.
     drupal_static_reset();
+    // Reset the list of enabled modules.
+    module_list(TRUE);
+
+    // Reset cached schema for new database prefix. This must be done before
+    // drupal_flush_all_caches() so rebuilds can make use of the schema of
+    // modules enabled on the cURL side.
+    drupal_get_schema(NULL, TRUE);
+
+    // Perform rebuilds and flush remaining caches.
     drupal_flush_all_caches();
 
     // Reload global $conf array and permissions.
     $this->refreshVariables();
     $this->checkPermissions(array(), TRUE);
-
-    // Reset statically cached schema for new database prefix.
-    drupal_get_schema(NULL, TRUE);
   }
 
   /**
@@ -1363,7 +1456,6 @@ class DrupalWebTestCase extends DrupalTestCase {
 
     // Remove all prefixed tables (all the tables in the schema).
     $schema = drupal_get_schema(NULL, TRUE);
-    $ret = array();
     foreach ($schema as $name => $table) {
       db_drop_table($name);
     }
@@ -1584,7 +1676,8 @@ class DrupalWebTestCase extends DrupalTestCase {
     if (!$this->elements) {
       // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
       // them.
-      @$htmlDom = DOMDocument::loadHTML($this->drupalGetContent());
+      $htmlDom = new DOMDocument();
+      @$htmlDom->loadHTML($this->drupalGetContent());
       if ($htmlDom) {
         $this->pass(t('Valid HTML found on "@path"', array('@path' => $this->getUrl())), t('Browser'));
         // It's much easier to work with simplexml than DOM, luckily enough
@@ -1733,7 +1826,7 @@ class DrupalWebTestCase extends DrupalTestCase {
         $post = array();
         $upload = array();
         $submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
-        $action = isset($form['action']) ? $this->getAbsoluteUrl($form['action']) : $this->getUrl();
+        $action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl();
         if ($ajax) {
           $action = $this->getAbsoluteUrl(!empty($submit['path']) ? $submit['path'] : 'system/ajax');
           // AJAX callbacks verify the triggering element if necessary, so while
@@ -1856,7 +1949,8 @@ class DrupalWebTestCase extends DrupalTestCase {
       );
       // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
       // them.
-      @$dom = DOMDocument::loadHTML($content);
+      $dom = new DOMDocument();
+      @$dom->loadHTML($content);
       foreach ($return as $command) {
         switch ($command['command']) {
           case 'settings':
@@ -2186,7 +2280,11 @@ class DrupalWebTestCase extends DrupalTestCase {
   protected function xpath($xpath, array $arguments = array()) {
     if ($this->parse()) {
       $xpath = $this->buildXPathQuery($xpath, $arguments);
-      return $this->elements->xpath($xpath);
+      $result = $this->elements->xpath($xpath);
+      // Some combinations of PHP / libxml versions return an empty array
+      // instead of the documented FALSE. Forcefully convert any falsish values
+      // to an empty array to allow foreach(...) constructions.
+      return $result ? $result : array();
     }
     else {
       return FALSE;
@@ -2809,20 +2907,21 @@ class DrupalWebTestCase extends DrupalTestCase {
    * @param $xpath
    *   XPath used to find the field.
    * @param $value
-   *   Value of the field to assert.
+   *   (optional) Value of the field to assert.
    * @param $message
-   *   Message to display.
+   *   (optional) Message to display.
    * @param $group
-   *   The group this message belongs to.
+   *   (optional) The group this message belongs to.
+   *
    * @return
    *   TRUE on pass, FALSE on fail.
    */
-  protected function assertFieldByXPath($xpath, $value, $message = '', $group = 'Other') {
+  protected function assertFieldByXPath($xpath, $value = NULL, $message = '', $group = 'Other') {
     $fields = $this->xpath($xpath);
 
     // If value specified then check array for match.
     $found = TRUE;
-    if ($value) {
+    if (isset($value)) {
       $found = FALSE;
       if ($fields) {
         foreach ($fields as $field) {
@@ -2881,20 +2980,21 @@ class DrupalWebTestCase extends DrupalTestCase {
    * @param $xpath
    *   XPath used to find the field.
    * @param $value
-   *   Value of the field to assert.
+   *   (optional) Value of the field to assert.
    * @param $message
-   *   Message to display.
+   *   (optional) Message to display.
    * @param $group
-   *   The group this message belongs to.
+   *   (optional) The group this message belongs to.
+   *
    * @return
    *   TRUE on pass, FALSE on fail.
    */
-  protected function assertNoFieldByXPath($xpath, $value, $message = '', $group = 'Other') {
+  protected function assertNoFieldByXPath($xpath, $value = NULL, $message = '', $group = 'Other') {
     $fields = $this->xpath($xpath);
 
     // If value specified then check array for match.
     $found = TRUE;
-    if ($value) {
+    if (isset($value)) {
       $found = FALSE;
       if ($fields) {
         foreach ($fields as $field) {
@@ -3058,7 +3158,7 @@ class DrupalWebTestCase extends DrupalTestCase {
    *   TRUE on pass, FALSE on fail.
    */
   protected function assertField($field, $message = '', $group = 'Other') {
-    return $this->assertFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), '', $message, $group);
+    return $this->assertFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), NULL, $message, $group);
   }
 
   /**
@@ -3074,7 +3174,7 @@ class DrupalWebTestCase extends DrupalTestCase {
    *   TRUE on pass, FALSE on fail.
    */
   protected function assertNoField($field, $message = '', $group = 'Other') {
-    return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), '', $message, $group);
+    return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), NULL, $message, $group);
   }
 
   /**
diff --git a/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css b/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css
index 10c70a11572dd9ced088dbd0eca4f4281e1b9f19..1feb8f1bd7d36e7402c1803278b857233f82a1c0 100644
--- a/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css
+++ b/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css
@@ -1,3 +1 @@
-
-
 .test1{display:block;}html .clear-block{height:1%;}.clear-block{display:block;font:italic bold 12px/30px Georgia,serif;}.test2{display:block;}.bkslshv1{background-color:#C00;}.test3{display:block;}.test4{display:block;}.comment-in-double-quotes:before{content:"/* ";}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-double-quotes:after{content:" */";}.comment-in-single-quotes:before{content:'/*';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-single-quotes:after{content:'*/';}.comment-in-mixed-quotes:before{content:'"/*"';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-mixed-quotes:after{content:"'*/'";}.comment-in-quotes-with-escaped:before{content:'/* \" \' */';}.this_rule_must_stay{color:#F00;background-color:#FFF;}.comment-in-quotes-with-escaped:after{content:"*/ \" \ '";}
diff --git a/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css b/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css
index 96fb993143e67d7819e554581a6424b0a037d5fc..698d9aa6cab9498584bdfad19d8ebffa9c1ab562 100644
--- a/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css
+++ b/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css
@@ -1,6 +1,4 @@
-
 ul,select{font:1em/160% Verdana,sans-serif;color:#494949;}.ui-icon{background-image:url(images/icon.png);}
-
 p,select{font:1em/160% Verdana,sans-serif;color:#494949;}
 body{margin:0;padding:0;background:#edf5fa;font:76%/170% Verdana,sans-serif;color:#494949;}.this .is .a .test{font:1em/100% Verdana,sans-serif;color:#494949;}.this
 .is
diff --git a/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css b/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css
index c19251143514c7b2a1096f14a5bc786e763c2a39..c7bb9dcd17cdcebb4d706eb0b4de73e865a2f274 100644
--- a/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css
+++ b/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css
@@ -1,8 +1,3 @@
-
-
-
-
-
 body{margin:0;padding:0;background:#edf5fa;font:76%/170% Verdana,sans-serif;color:#494949;}.this .is .a .test{font:1em/100% Verdana,sans-serif;color:#494949;}.this
 .is
 .a
diff --git a/modules/simpletest/files/image-1.png b/modules/simpletest/files/image-1.png
index f2aac9800b4bcbc75414198883f85753b08f9cb3..09e64d6edbc2440d585bbf463c727f51f9b294b7 100644
Binary files a/modules/simpletest/files/image-1.png and b/modules/simpletest/files/image-1.png differ
diff --git a/modules/simpletest/files/image-2.jpg b/modules/simpletest/files/image-2.jpg
index 645c76b5051e2e120a5b9c857156ce8f1399bdf2..ace07d078a00bee3b0ab02f7f077e39c23f2aa03 100644
Binary files a/modules/simpletest/files/image-2.jpg and b/modules/simpletest/files/image-2.jpg differ
diff --git a/modules/simpletest/files/image-test.jpg b/modules/simpletest/files/image-test.jpg
index 8fe1e010d6d3b8c8160b12e9cd3f82aa4132bc7e..de4eace04ecaea499e70812df0797318d700ad9f 100644
Binary files a/modules/simpletest/files/image-test.jpg and b/modules/simpletest/files/image-test.jpg differ
diff --git a/modules/simpletest/files/image-test.png b/modules/simpletest/files/image-test.png
index 6ac818f9e19cff6968ddf7e1b939ca184c0df58e..39c041927e1d7e1ee2b7904763c78d7c9d5caaab 100644
Binary files a/modules/simpletest/files/image-test.png and b/modules/simpletest/files/image-test.png differ
diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info
index 99010a3270b224af4cb087d106aec0c7401326d2..adc405c35ee430bd378dd9b8cdcb429c96d11d90 100644
--- a/modules/simpletest/simpletest.info
+++ b/modules/simpletest/simpletest.info
@@ -1,12 +1,9 @@
-; $Id: simpletest.info,v 1.26 2010/10/22 16:36:14 webchick Exp $
+; $Id: simpletest.info,v 1.28 2010/12/20 19:59:43 webchick Exp $
 name = Testing
 description = Provides a framework for unit and functional testing.
 package = Core
 version = VERSION
 core = 7.x
-files[] = simpletest.module
-files[] = simpletest.pages.inc
-files[] = simpletest.install
 files[] = simpletest.test
 files[] = drupal_web_test_case.php
 configure = admin/config/development/testing/settings
@@ -31,6 +28,7 @@ files[] = tests/lock.test
 files[] = tests/mail.test
 files[] = tests/menu.test
 files[] = tests/module.test
+files[] = tests/password.test
 files[] = tests/path.test
 files[] = tests/registry.test
 files[] = tests/schema.test
@@ -47,8 +45,8 @@ files[] = tests/upgrade/upgrade.taxonomy.test
 files[] = tests/upgrade/upgrade.upload.test
 files[] = tests/upgrade/upgrade.locale.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/simpletest.install b/modules/simpletest/simpletest.install
index ef813caa665a34d0bf646cdd515a2f590c2ae4a5..e45ae9ca9fd80f29ae7e430d710504b5e3b7b337 100644
--- a/modules/simpletest/simpletest.install
+++ b/modules/simpletest/simpletest.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: simpletest.install,v 1.39 2010/10/15 23:40:21 webchick Exp $
+// $Id: simpletest.install,v 1.41 2011/01/03 06:40:49 webchick Exp $
 
 /**
  * @file
@@ -7,31 +7,12 @@
  */
 
 /**
- * Implements hook_uninstall().
+ * Minimum value of PHP memory_limit for SimpleTest.
  */
-function simpletest_uninstall() {
-  simpletest_clean_environment();
-
-  // Remove settings variables.
-  variable_del('simpletest_httpauth_method');
-  variable_del('simpletest_httpauth_username');
-  variable_del('simpletest_httpauth_password');
-  variable_del('simpletest_clear_results');
-  variable_del('simpletest_verbose');
-
-  // Remove generated files.
-  $path = 'public://simpletest';
-  $files = file_scan_directory($path, '/.*/');
-  foreach ($files as $file) {
-    file_unmanaged_delete($file->uri);
-  }
-  drupal_rmdir($path);
-}
+define('SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT', '64M');
 
 /**
  * Implements hook_requirements().
- *
- * Check that the cURL extension exists for PHP.
  */
 function simpletest_requirements($phase) {
   $requirements = array();
@@ -80,6 +61,14 @@ function simpletest_requirements($phase) {
     $requirements['php_open_basedir']['description'] = t('The testing framework requires the PHP <a href="@open_basedir-url">open_basedir</a> restriction to be disabled. Check your webserver configuration or contact your web host.', array('@open_basedir-url' => 'http://php.net/manual/en/ini.core.php#ini.open-basedir'));
   }
 
+  // Check the current memory limit. If it is set too low, SimpleTest will fail
+  // to load all tests and throw a fatal error.
+  $memory_limit = ini_get('memory_limit');
+  if ($memory_limit && $memory_limit != -1 && parse_size($memory_limit) < parse_size(SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT)) {
+    $requirements['php_memory_limit']['severity'] = REQUIREMENT_ERROR;
+    $requirements['php_memory_limit']['description'] = t('The testing framework requires the PHP memory limit to be at least %memory_minimum_limit. The current value is %memory_limit. <a href="@url">Follow these steps to continue</a>.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, '@url' => 'http://drupal.org/node/207036'));
+  }
+
   return $requirements;
 }
 
@@ -174,3 +163,20 @@ function simpletest_schema() {
   );
   return $schema;
 }
+
+/**
+ * Implements hook_uninstall().
+ */
+function simpletest_uninstall() {
+  simpletest_clean_environment();
+
+  // Remove settings variables.
+  variable_del('simpletest_httpauth_method');
+  variable_del('simpletest_httpauth_username');
+  variable_del('simpletest_httpauth_password');
+  variable_del('simpletest_clear_results');
+  variable_del('simpletest_verbose');
+
+  // Remove generated files.
+  file_unmanaged_delete_recursive('public://simpletest');
+}
diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module
index 60f79fd3069e252ff0eef4899b2f65cd785ea67b..ea64aeb01d917be38fe8511269e673e58f9ae1ac 100644
--- a/modules/simpletest/simpletest.module
+++ b/modules/simpletest/simpletest.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: simpletest.module,v 1.95 2010/10/10 11:34:22 dries Exp $
+// $Id: simpletest.module,v 1.97 2010/11/12 03:06:52 dries Exp $
 
 /**
  * @file
@@ -219,14 +219,13 @@ function _simpletest_batch_finished($success, $results, $operations, $elapsed) {
     list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
     simpletest_log_read($test_id, $last_prefix, $last_test_class);
 
-
     drupal_set_message(t('The test run did not successfully finish.'), 'error');
     drupal_set_message(t('Use the <em>Clean environment</em> button to clean-up temporary files and tables.'), 'warning');
   }
   module_invoke_all('test_group_finished');
 }
 
-/*
+/**
  * Get information about the last test that ran given a test ID.
  *
  * @param $test_id
@@ -318,13 +317,12 @@ function simpletest_test_get_all() {
     }
     else {
       // Select all clases in files ending with .test.
-      $classes = db_query("SELECT name FROM {registry} WHERE type = :type AND filename LIKE :name", array(':type' => 'class', ':name' => '%.test'));
+      $classes = db_query("SELECT name FROM {registry} WHERE type = :type AND filename LIKE :name", array(':type' => 'class', ':name' => '%.test'))->fetchCol();
 
       // Check that each class has a getInfo() method and store the information
       // in an array keyed with the group specified in the test information.
       $groups = array();
       foreach ($classes as $class) {
-        $class = $class->name;
         // Test classes need to implement getInfo() to be valid.
         if (class_exists($class) && method_exists($class, 'getInfo')) {
           $info = call_user_func(array($class, 'getInfo'));
diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test
index 736b93e4a50ea1996b5a959db4a7fa02c06fdc70..228199a162976565d21ae7ddfa4a942d7dcedb5f 100644
--- a/modules/simpletest/simpletest.test
+++ b/modules/simpletest/simpletest.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: simpletest.test,v 1.46 2010/09/28 02:30:32 dries Exp $
+// $Id: simpletest.test,v 1.48 2010/11/12 03:06:52 dries Exp $
 
 class SimpleTestFunctionalTest extends DrupalWebTestCase {
   /**
@@ -77,6 +77,43 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase {
     }
   }
 
+  /**
+   * Test validation of the User-Agent header we use to perform test requests.
+   */
+  function testUserAgentValidation() {
+    if (!$this->inCURL()) {
+      global $base_url;
+      $simpletest_path = $base_url . '/' . drupal_get_path('module', 'simpletest');
+      $HTTP_path = $simpletest_path .'/tests/http.php?q=node';
+      $https_path = $simpletest_path .'/tests/https.php?q=node';
+      // Generate a valid simpletest User-Agent to pass validation.
+      $this->assertTrue(preg_match('/simpletest\d+/', $this->databasePrefix, $matches), t('Database prefix contains simpletest prefix.'));
+      $test_ua = drupal_generate_test_ua($matches[0]);
+      $this->additionalCurlOptions = array(CURLOPT_USERAGENT => $test_ua);
+
+      // Test pages only available for testing.
+      $this->drupalGet($HTTP_path);
+      $this->assertResponse(200, t('Requesting http.php with a legitimate simpletest User-Agent returns OK.'));
+      $this->drupalGet($https_path);
+      $this->assertResponse(200, t('Requesting https.php with a legitimate simpletest User-Agent returns OK.'));
+
+      // Now slightly modify the HMAC on the header, which should not validate.
+      $this->additionalCurlOptions = array(CURLOPT_USERAGENT => $test_ua . 'X');
+      $this->drupalGet($HTTP_path);
+      $this->assertResponse(403, t('Requesting http.php with a bad simpletest User-Agent fails.'));
+      $this->drupalGet($https_path);
+      $this->assertResponse(403, t('Requesting https.php with a bad simpletest User-Agent fails.'));
+
+      // Use a real User-Agent and verify that the special files http.php and
+      // https.php can't be accessed.
+      $this->additionalCurlOptions = array(CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12');
+      $this->drupalGet($HTTP_path);
+      $this->assertResponse(403, t('Requesting http.php with a normal User-Agent fails.'));
+      $this->drupalGet($https_path);
+      $this->assertResponse(403, t('Requesting https.php with a normal User-Agent fails.'));
+    }
+  }
+
   /**
    * Make sure that tests selected through the web interface are run and
    * that the results are displayed correctly.
@@ -274,10 +311,7 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase {
    * Check if the test is being run from inside a CURL request.
    */
   function inCURL() {
-    // We cannot rely on drupal_static('drupal_test_info') here, because
-    // 'in_child_site' would be FALSE for the parent site when we are
-    // executing the tests. Default to direct detection of the HTTP headers.
-    return isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^simpletest\d+/", $_SERVER['HTTP_USER_AGENT']);
+    return (bool) drupal_valid_test_ua();
   }
 }
 
@@ -463,4 +497,3 @@ class SimpleTestMissingDependentModuleUnitTest extends DrupalUnitTestCase {
     $this->fail(t('Running test with missing required module.'));
   }
 }
-
diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info
index 2a72aafe31f38b3ee5bb50633db65bf2654cc1ec..e5642821c28ecb2ab646a327394190ebf7a52762 100644
--- a/modules/simpletest/tests/actions_loop_test.info
+++ b/modules/simpletest/tests/actions_loop_test.info
@@ -1,14 +1,13 @@
-; $Id: actions_loop_test.info,v 1.1 2009/08/22 16:16:19 webchick Exp $
+; $Id: actions_loop_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = Actions loop test
 description = Support module for action loop testing.
 package = Testing
 version = VERSION
 core = 7.x
-files[] = actions_loop_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test
index 028975e016d0849aa2af8c4a35e293a43b337510..b9fade22bd511614170576470fc6ace1077092cf 100644
--- a/modules/simpletest/tests/ajax.test
+++ b/modules/simpletest/tests/ajax.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: ajax.test,v 1.20 2010/10/21 19:31:39 dries Exp $
+// $Id: ajax.test,v 1.21 2010/11/29 03:00:50 webchick Exp $
 
 class AJAXTestCase extends DrupalWebTestCase {
   function setUp() {
@@ -211,6 +211,15 @@ class AJAXCommandsTestCase extends AJAXTestCase {
     );
     $this->assertCommand($commands, $expected, "'data' AJAX command issued with correct key and value");
 
+    // Tests the 'invoke' command.
+    $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX invoke command: Invoke addClass() method.")));
+    $expected = array(
+      'command' => 'invoke',
+      'method' => 'addClass',
+      'arguments' => array('error'),
+    );
+    $this->assertCommand($commands, $expected, "'invoke' AJAX command issued with correct method and argument");
+
     // Tests the 'html' command.
     $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX html: Replace the HTML in a selector.")));
     $expected = array(
diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info
index 9dff275cfc0171602fd80f936301e8fd0dfe174c..db131700f7d1fc66ae3d443fc0117b7cafdfc56e 100644
--- a/modules/simpletest/tests/ajax_forms_test.info
+++ b/modules/simpletest/tests/ajax_forms_test.info
@@ -1,14 +1,13 @@
-; $Id: ajax_forms_test.info,v 1.1 2009/11/18 04:56:18 webchick Exp $
+; $Id: ajax_forms_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "AJAX form test mock module"
 description = "Test for AJAX form calls."
 core = 7.x
 package = Testing
-files[] = ajax_forms_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/ajax_forms_test.module b/modules/simpletest/tests/ajax_forms_test.module
index 22cba5d677a535538b38869408097620a26c86aa..32146f93d45a6541368cf6963ddb8e428b4e0b65 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.8 2010/10/04 17:46:01 dries Exp $
+// $Id: ajax_forms_test.module,v 1.9 2010/11/29 03:00:50 webchick Exp $
 
 /**
  * @file
@@ -176,6 +176,16 @@ function ajax_forms_test_ajax_commands_form($form, &$form_state) {
     '#suffix' => '<div id="data_div">Data attached to this div.</div>',
   );
 
+  // Shows the AJAX 'invoke' command.
+  $form['invoke_command_example'] = array(
+    '#value' => t("AJAX invoke command: Invoke addClass() method."),
+    '#type' => 'submit',
+    '#ajax' => array(
+      'callback' => 'ajax_forms_test_advanced_commands_invoke_callback',
+    ),
+    '#suffix' => '<div id="invoke_div">Original contents</div>',
+  );
+
   // Shows the AJAX 'html' command.
   $form['html_command_example'] = array(
     '#value' => t("AJAX html: Replace the HTML in a selector."),
@@ -331,6 +341,15 @@ function ajax_forms_test_advanced_commands_data_callback($form, $form_state) {
   return array('#type' => 'ajax', '#commands' => $commands);
 }
 
+/**
+ * AJAX callback for 'invoke'.
+ */
+function ajax_forms_test_advanced_commands_invoke_callback($form, $form_state) {
+  $commands = array();
+  $commands[] = ajax_command_invoke('#invoke_div', 'addClass', array('error'));
+  return array('#type' => 'ajax', '#commands' => $commands);
+}
+
 /**
  * AJAX callback for 'html'.
  */
diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info
index 83d1d501cd7219e56b4d5458b858d424a36e3f8d..799c6d3722e265db70d5d3b7fb0d09eb43b28333 100644
--- a/modules/simpletest/tests/ajax_test.info
+++ b/modules/simpletest/tests/ajax_test.info
@@ -1,14 +1,13 @@
-; $Id: ajax_test.info,v 1.1 2009/10/18 05:14:39 webchick Exp $
+; $Id: ajax_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = AJAX Test
 description = Support module for AJAX framework tests.
 package = Testing
 version = VERSION
 core = 7.x
-files[] = ajax_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/batch.test b/modules/simpletest/tests/batch.test
index 1511209ee0434266ace9f63e267a1bbe72989ec3..48541426e4df0737eff4dec2e72894ffefd4aeb4 100644
--- a/modules/simpletest/tests/batch.test
+++ b/modules/simpletest/tests/batch.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: batch.test,v 1.15 2010/10/03 02:42:25 dries Exp $
+// $Id: batch.test,v 1.16 2010/11/27 20:25:44 dries Exp $
 
 /**
  * @file
@@ -299,12 +299,16 @@ class BatchPageTestCase extends DrupalWebTestCase {
     // is using a different theme than would normally be used by the batch API.
     variable_set('theme_default', 'bartik');
     variable_set('admin_theme', 'seven');
+    // Log in as an administrator who can see the administrative theme.
+    $admin_user = $this->drupalCreateUser(array('view the administration theme'));
+    $this->drupalLogin($admin_user);
     // Visit an administrative page that runs a test batch, and check that the
     // theme that was used during batch execution (which the batch callback
     // function saved as a variable) matches the theme used on the
     // administrative page.
     $this->drupalGet('admin/batch-test/test-theme');
-    // The stack should contain the name of the the used on the progress page.
+    // The stack should contain the name of the theme used on the progress
+    // page.
     $this->assertEqual(batch_test_stack(), array('seven'), t('A progressive batch correctly uses the theme of the page that started the batch.'));
   }
 }
diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info
index 659aeba64547ea09fa0220c7168498943ed7f81d..e33fb4c00f6617691702786c59770f9481fc1d4c 100644
--- a/modules/simpletest/tests/batch_test.info
+++ b/modules/simpletest/tests/batch_test.info
@@ -1,15 +1,13 @@
-; $Id: batch_test.info,v 1.1 2010/01/08 06:36:34 webchick Exp $
+; $Id: batch_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Batch API test"
 description = "Support module for Batch API tests."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = batch_test.module
-files[] = batch_test.callbacks.inc
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test
index 6d4bfb966b19cabc6a85889aee3eaa1a21ee49f9..a6c0aeaecfbc1834701509b5ab66a15e4dd5c437 100644
--- a/modules/simpletest/tests/bootstrap.test
+++ b/modules/simpletest/tests/bootstrap.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: bootstrap.test,v 1.33 2010/08/05 23:53:38 webchick Exp $
+// $Id: bootstrap.test,v 1.35 2010/11/23 03:08:34 dries Exp $
 
 class BootstrapIPAddressTestCase extends DrupalWebTestCase {
 
@@ -426,3 +426,75 @@ class BootstrapResettableStaticTestCase extends DrupalUnitTestCase {
     $this->assertEqual($var, 'foo', t('Variable was reset after second invocation of global reset.'));
   }
 }
+
+/**
+ * Test miscellaneous functions in bootstrap.inc.
+ */
+class BootstrapMiscTestCase extends DrupalUnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Miscellaneous bootstrap unit tests',
+      'description' => 'Test miscellaneous functions in bootstrap.inc.',
+      'group' => 'Bootstrap',
+    );
+  }
+
+  /**
+   * Test miscellaneous functions in bootstrap.inc.
+   */
+  function testMisc() {
+    // Test drupal_array_merge_deep().
+    $link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => 'X', 'class' => array('a', 'b')), 'language' => 'en');
+    $link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('c', 'd')), 'html' => TRUE);
+    $expected = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('a', 'b', 'c', 'd')), 'language' => 'en', 'html' => TRUE);
+    $this->assertIdentical(drupal_array_merge_deep($link_options_1, $link_options_2), $expected, t('drupal_array_merge_deep() returned a properly merged array.'));
+  }
+}
+
+/**
+ * Tests for overriding server variables via the API.
+ */
+class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Overriding server variables',
+      'description' => 'Test that drupal_override_server_variables() works correctly.',
+      'group' => 'Bootstrap',
+    );
+  }
+
+  /**
+   * Test providing a direct URL to to drupal_override_server_variables().
+   */
+  function testDrupalOverrideServerVariablesProvidedURL() {
+    $tests = array(
+      'http://example.com' => array(
+        'HTTP_HOST' => 'example.com',
+        'SCRIPT_NAME' => isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL,
+      ),
+      'http://example.com/index.php' => array(
+        'HTTP_HOST' => 'example.com',
+        'SCRIPT_NAME' => '/index.php',
+      ),
+      'http://example.com/subdirectory/index.php' => array(
+        'HTTP_HOST' => 'example.com',
+        'SCRIPT_NAME' => '/subdirectory/index.php',
+      ),
+    );
+    foreach ($tests as $url => $expected_server_values) {
+      // Remember the original value of $_SERVER, since the function call below
+      // will modify it.
+      $original_server = $_SERVER;
+      // Call drupal_override_server_variables() and ensure that all expected
+      // $_SERVER variables were modified correctly.
+      drupal_override_server_variables(array('url' => $url));
+      foreach ($expected_server_values as $key => $value) {
+        $this->assertIdentical($_SERVER[$key], $value);
+      }
+      // Restore the original value of $_SERVER.
+      $_SERVER = $original_server;
+    }
+  }
+}
+
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index 2c9bca895444ed1e196c463bfdc032cb9359425e..19dd70c26c902bce37ba57e2498662d3f94f7539 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: common.test,v 1.130 2010/10/08 15:36:12 dries Exp $
+// $Id: common.test,v 1.138 2010/12/15 04:21:39 webchick Exp $
 
 /**
  * @file
@@ -654,7 +654,7 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
    */
   function testRenderInlinePreprocess() {
     $css = 'body { padding: 0px; }';
-    $css_preprocessed = '<style type="text/css" media="all">' . drupal_load_stylesheet_content($css, TRUE) . '</style>';
+    $css_preprocessed = '<style type="text/css" media="all">' . "\n<!--/*--><![CDATA[/*><!--*/\n" . drupal_load_stylesheet_content($css, TRUE) . "\n/*]]>*/-->\n" . '</style>';
     drupal_add_css($css, array('type' => 'inline'));
     $styles = drupal_get_css();
     $this->assertEqual(trim($styles), $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.'));
@@ -680,7 +680,7 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
     $expected = 'body{font-size:254px;}';
 
     // Create a node, using the PHP filter that tests drupal_add_css().
-    $php_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'PHP code'))->fetchField();
+    $php_format_id = 'php_code';
     $settings = array(
       'type' => 'page',
       'body' => array(
@@ -881,17 +881,20 @@ class CascadingStylesheetsUnitTest extends DrupalUnitTestCase {
     foreach ($testfiles as $file) {
       $expected = file_get_contents("$path/$file.unoptimized.css");
       $unoptimized_output = drupal_load_stylesheet("$path/$file.unoptimized.css", FALSE);
-      $this->verbose('Expected:<pre>' . $expected . '</pre>'
-        . 'Actual:<pre>' . $unoptimized_output . '</pre>'
-      );
       $this->assertEqual($unoptimized_output, $expected, t('Unoptimized CSS file has expected contents (@file)', array('@file' => $file)));
 
       $expected = file_get_contents("$path/$file.optimized.css");
       $optimized_output = drupal_load_stylesheet("$path/$file", TRUE);
-      $this->verbose('Expected:<pre>' . $expected . '</pre>'
-        . 'Actual:<pre>' . $optimized_output . '</pre>'
-      );
       $this->assertEqual($optimized_output, $expected, t('Optimized CSS file has expected contents (@file)', array('@file' => $file)));
+
+      // Repeat the tests by accessing the stylesheets by URL.
+      $expected = file_get_contents("$path/$file.unoptimized.css");
+      $unoptimized_output_url = drupal_load_stylesheet($GLOBALS['base_url'] . "/$path/$file.unoptimized.css", FALSE);
+      $this->assertEqual($unoptimized_output, $expected, t('Unoptimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));
+
+      $expected = file_get_contents("$path/$file.optimized.css");
+      $optimized_output = drupal_load_stylesheet($GLOBALS['base_url'] . "/$path/$file", TRUE);
+      $this->assertEqual($optimized_output, $expected, t('Optimized CSS file (loaded from an URL) has expected contents (@file)', array('@file' => $file)));
     }
   }
 }
@@ -1192,11 +1195,34 @@ class JavaScriptTestCase extends DrupalWebTestCase {
    * Test drupal_get_js() for JavaScript settings.
    */
   function testHeaderSetting() {
-    drupal_add_js(array('testSetting' => 'testValue'), 'setting');
+    // Only the second of these two entries should appear in Drupal.settings.
+    drupal_add_js(array('commonTest' => 'commonTestShouldNotAppear'), 'setting');
+    drupal_add_js(array('commonTest' => 'commonTestShouldAppear'), 'setting');
+    // All three of these entries should appear in Drupal.settings.
+    drupal_add_js(array('commonTestArray' => array('commonTestValue0')), 'setting');
+    drupal_add_js(array('commonTestArray' => array('commonTestValue1')), 'setting');
+    drupal_add_js(array('commonTestArray' => array('commonTestValue2')), 'setting');
+    // Only the second of these two entries should appear in Drupal.settings.
+    drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting');
+    drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting');
+
     $javascript = drupal_get_js('header');
     $this->assertTrue(strpos($javascript, 'basePath') > 0, t('Rendered JavaScript header returns basePath setting.'));
-    $this->assertTrue(strpos($javascript, 'testSetting') > 0, t('Rendered JavaScript header returns custom setting.'));
     $this->assertTrue(strpos($javascript, 'misc/jquery.js') > 0, t('Rendered JavaScript header includes jQuery.'));
+
+    // Test whether drupal_add_js can be used to override a previous setting.
+    $this->assertTrue(strpos($javascript, 'commonTestShouldAppear') > 0, t('Rendered JavaScript header returns custom setting.'));
+    $this->assertTrue(strpos($javascript, 'commonTestShouldNotAppear') === FALSE, t('drupal_add_js() correctly overrides a custom setting.'));
+
+    // Test whether drupal_add_js can be used to add numerically indexed values
+    // to an array.
+    $array_values_appear = strpos($javascript, 'commonTestValue0') > 0 && strpos($javascript, 'commonTestValue1') > 0 && strpos($javascript, 'commonTestValue2') > 0;
+    $this->assertTrue($array_values_appear, t('drupal_add_js() correctly adds settings to the end of an indexed array.'));
+
+    // Test whether drupal_add_js can be used to override the entry for an
+    // existing key in an associative array.
+    $associative_array_override = strpos($javascript, 'commonTestNewValue') > 0 && strpos($javascript, 'commonTestOldValue') === FALSE;
+    $this->assertTrue($associative_array_override, t('drupal_add_js() correctly overrides settings within an associative array.'));
   }
 
   /**
@@ -1397,6 +1423,26 @@ class JavaScriptTestCase extends DrupalWebTestCase {
     $this->assertTrue(strpos($scripts, 'misc/farbtastic/farbtastic.js'), t('The attached_library property adds the additional libraries.'));
   }
 
+  /**
+   * Tests retrieval of libraries via drupal_get_library().
+   */
+  function testGetLibrary() {
+    // Retrieve all libraries registered by a module.
+    $libraries = drupal_get_library('common_test');
+    $this->assertTrue(isset($libraries['farbtastic']), t('Retrieved all module libraries.'));
+    // Retrieve all libraries for a module not implementing hook_library().
+    // Note: This test installs Locale module.
+    $libraries = drupal_get_library('locale');
+    $this->assertEqual($libraries, array(), t('Retrieving libraries from a module not implementing hook_library() returns an emtpy array.'));
+
+    // Retrieve a specific library by module and name.
+    $farbtastic = drupal_get_library('common_test', 'farbtastic');
+    $this->assertEqual($farbtastic['version'], '5.3', t('Retrieved a single library.'));
+    // Retrieve a non-existing library by module and name.
+    $farbtastic = drupal_get_library('common_test', 'foo');
+    $this->assertIdentical($farbtastic, FALSE, t('Retrieving a non-existing library returns FALSE.'));
+  }
+
   /**
    * Tests that the query string remains intact when adding JavaScript files
    *  that have query string parameters.
@@ -1973,6 +2019,66 @@ class ParseInfoFilesTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests for the drupal_system_listing() function.
+ */
+class DrupalSystemListingTestCase extends DrupalWebTestCase {
+  /**
+   * Use the testing profile; this is needed for testDirectoryPrecedence().
+   */
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Drupal system listing',
+      'description' => 'Tests the mechanism for scanning system directories in drupal_system_listing().',
+      'group' => 'System',
+    );
+  }
+
+  /**
+   * Test that files in different directories take precedence as expected.
+   */
+  function testDirectoryPrecedence() {
+    // Define the module files we will search for, and the directory precedence
+    // we expect.
+    $expected_directories = array(
+      // When the copy of the module in the profile directory is incompatible
+      // with Drupal core, the copy in the core modules directory takes
+      // precedence.
+      'drupal_system_listing_incompatible_test' => array(
+        'modules/simpletest/tests',
+        'profiles/testing/modules',
+      ),
+      // When both copies of the module are compatible with Drupal core, the
+      // copy in the profile directory takes precedence.
+      'drupal_system_listing_compatible_test' => array(
+        'profiles/testing/modules',
+        'modules/simpletest/tests',
+      ),
+    );
+
+    // This test relies on two versions of the same module existing in
+    // different places in the filesystem. Without that, the test has no
+    // meaning, so assert their presence first.
+    foreach ($expected_directories as $module => $directories) {
+      foreach ($directories as $directory) {
+        $filename = "$directory/$module/$module.module";
+        $this->assertTrue(file_exists(DRUPAL_ROOT . '/' . $filename), t('@filename exists.', array('@filename' => $filename)));
+      }
+    }
+
+    // Now scan the directories and check that the files take precedence as
+    // expected.
+    $files = drupal_system_listing('/\.module$/', 'modules', 'name', 1);
+    foreach ($expected_directories as $module => $directories) {
+      $expected_directory = array_shift($directories);
+      $expected_filename = "$expected_directory/$module/$module.module";
+      $this->assertEqual($files[$module]->uri, $expected_filename, t('Module @module was found at @filename.', array('@module' => $module, '@filename' => $expected_filename)));
+    }
+  }
+}
+
 /**
  * Tests for the format_date() function.
  */
@@ -2004,6 +2110,32 @@ class FormatDateUnitTest extends DrupalWebTestCase {
     $this->refreshVariables();
   }
 
+  /**
+   * Test admin-defined formats in format_date().
+   */
+  function testAdminDefinedFormatDate() {
+    // Create an admin user.
+    $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
+    $this->drupalLogin($this->admin_user);
+
+    // Add new date format.
+    $admin_date_format = 'j M y';
+    $edit = array('date_format' => $admin_date_format);
+    $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
+
+    // Add new date type.
+    $edit = array(
+      'date_type' => 'Example Style',
+      'machine_name' => 'example_style',
+      'date_format' => $admin_date_format,
+    );
+    $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
+
+    $timestamp = strtotime('2007-03-10T00:00:00+00:00');
+    $this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', t('Test format_date() using an admin-defined date type.'));
+    $this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'medium'), t('Test format_date() defaulting to medium when $type not found.'));
+  }
+
   /**
    * Tests for the format_date() function.
    */
@@ -2191,3 +2323,85 @@ class DrupalGetRdfNamespacesTestCase extends DrupalWebTestCase {
     $this->assertTrue(!isset($ns['dc']), t('A prefix with conflicting namespaces is discarded.'));
   }
 }
+
+/**
+ * Basic tests for drupal_add_feed().
+ */
+class DrupalAddFeedTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'drupal_add_feed() tests',
+      'description' => 'Make sure that drupal_add_feed() works correctly with various constructs.',
+      'group' => 'System',
+    );
+  }
+
+  /**
+   * Test drupal_add_feed() with paths, URLs, and titles.
+   */
+  function testBasicFeedAddNoTitle() {
+    $path = $this->randomName(12);
+    $external_url = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
+    $fully_qualified_local_url = url($this->randomName(12), array('absolute' => TRUE));
+
+    $path_for_title = $this->randomName(12);
+    $external_for_title = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
+    $fully_qualified_for_title = url($this->randomName(12), array('absolute' => TRUE));
+
+    // Possible permutations of drupal_add_feed() to test.
+    // - 'input_url': the path passed to drupal_add_feed(),
+    // - 'output_url': the expected URL to be found in the header.
+    // - 'title' == the title of the feed as passed into drupal_add_feed().
+    $urls = array(
+      'path without title' => array(
+        'input_url' => $path,
+        'output_url' => url($path, array('absolute' => TRUE)),
+        'title' => '',
+      ),
+      'external url without title' => array(
+        'input_url' => $external_url,
+        'output_url' => $external_url,
+        'title' => '',
+      ),
+      'local url without title' => array(
+        'input_url' => $fully_qualified_local_url,
+        'output_url' => $fully_qualified_local_url,
+        'title' => '',
+      ),
+      'path with title' => array(
+        'input_url' => $path_for_title,
+        'output_url' => url($path_for_title, array('absolute' => TRUE)),
+        'title' => $this->randomName(12),
+      ),
+      'external url with title' => array(
+        'input_url' => $external_for_title,
+        'output_url' => $external_for_title,
+        'title' => $this->randomName(12),
+      ),
+      'local url with title' => array(
+        'input_url' => $fully_qualified_for_title,
+        'output_url' => $fully_qualified_for_title,
+        'title' => $this->randomName(12),
+      ),
+    );
+
+    foreach ($urls as $description => $feed_info) {
+      drupal_add_feed($feed_info['input_url'], $feed_info['title']);
+    }
+
+    $this->drupalSetContent(drupal_get_html_head());
+    foreach ($urls as $description => $feed_info) {
+      $this->assertPattern($this->urlToRSSLinkPattern($feed_info['output_url'], $feed_info['title']), t('Found correct feed header for %description', array('%description' => $description)));
+    }
+  }
+
+  /**
+   * Create a pattern representing the RSS feed in the page.
+   */
+  function urlToRSSLinkPattern($url, $title = '') {
+    // Escape any regular expression characters in the url ('?' is the worst).
+    $url = preg_replace('/([+?.*])/', '[$0]', $url);
+    $generated_pattern = '%<link +rel="alternate" +type="application/rss.xml" +title="' . $title . '" +href="' . $url . '" */>%';
+    return $generated_pattern;
+  }
+}
diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info
index 8bbbb0cabbf096fc8497f79822a65b7cbfa7fdf3..b08a08470eae64f32a94adaf89770a332afb1a3d 100644
--- a/modules/simpletest/tests/common_test.info
+++ b/modules/simpletest/tests/common_test.info
@@ -1,16 +1,15 @@
-; $Id: common_test.info,v 1.2 2010/09/05 02:21:38 dries Exp $
+; $Id: common_test.info,v 1.3 2010/12/20 19:59:43 webchick Exp $
 name = "Common Test"
 description = "Support module for Common tests."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = common_test.module
 stylesheets[all][] = common_test.css
 stylesheets[print][] = common_test.print.css
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info
index 45a400334925476400e79365c3767782bf5783a0..a315617f94be8acb9953675371489f91acb9658c 100644
--- a/modules/simpletest/tests/database_test.info
+++ b/modules/simpletest/tests/database_test.info
@@ -1,15 +1,13 @@
-; $Id: database_test.info,v 1.2 2008/10/09 22:51:40 webchick Exp $
+; $Id: database_test.info,v 1.3 2010/12/20 19:59:43 webchick Exp $
 name = "Database Test"
 description = "Support module for Database layer tests."
 core = 7.x
 package = Testing
-files[] = database_test.module
-files[] = database_test.install
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test
index af96b3263db2d5756afc753e3e3ae98b9795db36..183e3b21c02470195c511052230c42f46e43d936 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.104 2010/10/15 04:34:15 webchick Exp $
+// $Id: database_test.test,v 1.110 2010/12/31 20:43:43 webchick Exp $
 
 /**
  * Dummy class for fetching into a class.
@@ -776,6 +776,25 @@ class DatabaseUpdateTestCase extends DatabaseTestCase {
     $this->assertIdentical($num_matches, '1', t('Updated fields successfully.'));
   }
 
+  /**
+   * Test updating with expressions.
+   */
+  function testExpressionUpdate() {
+    // Set age = 1 for a single row for this test to work.
+    db_update('test')
+      ->condition('id', 1)
+      ->fields(array('age' => 1))
+      ->execute();
+
+    // Ensure that expressions are handled properly.  This should set every
+    // record's age to a square of itself, which will change only three of the
+    // four records in the table since 1*1 = 1. That means only three records
+    // are modified, so we should get back 3, not 4, from execute().
+    $num_rows = db_update('test')
+      ->expression('age', 'age * age')
+      ->execute();
+    $this->assertIdentical($num_rows, 3, t('Number of affected rows are returned.'));
+  }
 }
 
 /**
@@ -1665,6 +1684,61 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
 
     $this->assertEqual(count($people), 2, t('Returned the correct number of rows.'));
   }
+
+  /**
+   * Test EXISTS subquery conditionals on SELECT statements.
+   */
+  function testExistsSubquerySelect() {
+    // Put George into {test_people}.
+    db_insert('test_people')
+      ->fields(array(
+        'name' => 'George',
+        'age' => 27,
+        'job' => 'Singer',
+      ))
+      ->execute();
+    // Base query to {test}.
+    $query = db_select('test', 't')
+      ->fields('t', array('name'));
+    // Subquery to {test_people}.
+    $subquery = db_select('test_people', 'tp')
+      ->fields('tp', array('name'))
+      ->condition('name', 'George');
+    $query->exists($subquery);
+    $result = $query->execute();
+
+    // Ensure that we got the right record.
+    $record = $result->fetch();
+    $this->assertEqual($record->name, 'George', t('Fetched name is correct using EXISTS query.'));
+  }
+
+  /**
+   * Test NOT EXISTS subquery conditionals on SELECT statements.
+   */
+  function testNotExistsSubquerySelect() {
+    // Put George into {test_people}.
+    db_insert('test_people')
+      ->fields(array(
+        'name' => 'George',
+        'age' => 27,
+        'job' => 'Singer',
+      ))
+      ->execute();
+
+    // Base query to {test}.
+    $query = db_select('test', 't')
+      ->fields('t', array('name'));
+    // Subquery to {test_people}.
+    $subquery = db_select('test_people', 'tp')
+      ->fields('tp', array('name'))
+      ->condition('name', 'George');
+    $query->notExists($subquery);
+    $result = $query->execute();
+
+    // Ensure that we got the right record.
+    $record = $result->fetch();
+    $this->assertFalse($record, t('NOT EXISTS query returned no results.'));
+  }
 }
 
 /**
@@ -1970,6 +2044,25 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
     $this->assertEqual($count, 4, t('Counted the correct number of records.'));
   }
 
+
+  /**
+   * Test that countQuery properly removes fields and expressions.
+   */
+  function testCountQueryFieldRemovals() {
+    // countQuery should remove all fields and expressions, so this can be
+    // tested by adding a non-existant field and expression: if it ends
+    // up in the query, an error will be thrown. If not, it will return the
+    // number of records, which in this case happens to be 4 (there are four
+    // records in the {test} table).
+    $query = db_select('test');
+    $query->fields('test', array('fail'));
+    $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), t('Count Query removed fields'));
+
+    $query = db_select('test');
+    $query->addExpression('fail');
+    $this->assertEqual(4, $query->countQuery()->execute()->fetchField(), t('Count Query removed expressions'));
+  }
+
   /**
    * Test that we can generate a count query from a query with distinct.
    */
@@ -1994,6 +2087,18 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
     $count = $query->countQuery()->execute()->fetchField();
 
     $this->assertEqual($count, 3, t('Counted the correct number of records.'));
+
+    // Use a column alias as, without one, the query can succeed for the wrong
+    // reason.
+    $query = db_select('test_task');
+    $pid_field = $query->addField('test_task', 'pid', 'pid_alias');
+    $query->addExpression('COUNT(test_task.task)', 'count');
+    $query->groupBy('pid_alias');
+    $query->orderBy('pid_alias', 'asc');
+
+    $count = $query->countQuery()->execute()->fetchField();
+
+    $this->assertEqual($count, 3, t('Counted the correct number of records.'));
   }
 
   /**
@@ -2750,6 +2855,33 @@ class DatabaseLoggingTestCase extends DatabaseTestCase {
   }
 }
 
+/**
+ * Query serialization tests.
+ */
+class DatabaseSerializeQueryTestCase extends DatabaseTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Serialize query',
+      'description' => 'Test serializing and unserializing a query.',
+      'group' => 'Database',
+    );
+  }
+
+  /**
+   * Confirm that a query can be serialized and unserialized.
+   */
+  function testSerializeQuery() {
+    $query = db_select('test');
+    $query->addField('test', 'age');
+    $query->condition('name', 'Ringo');
+    // If this doesn't work, it will throw an exception, so no need for an
+    // assertion.
+    $query = unserialize(serialize($query));
+    $results = $query->execute()->fetchCol();
+    $this->assertEqual($results[0], 28, t('Query properly executed after unserialization.'));
+  }
+}
+
 /**
  * Range query tests.
  */
diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..ef822558fe21d4e6f51f6b6a640f8766ee4c2e8c
--- /dev/null
+++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
@@ -0,0 +1,13 @@
+; $Id: drupal_system_listing_compatible_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
+name = "Drupal system listing compatible test"
+description = "Support module for testing the drupal_system_listing function."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
+project = "drupal"
+datestamp = "1294208756"
+
diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..4155b320357d25ee0d36ca6e9e1430d501ded96d
--- /dev/null
+++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module
@@ -0,0 +1,2 @@
+<?php
+// $Id: drupal_system_listing_compatible_test.module,v 1.1 2010/11/15 00:37:08 webchick Exp $
diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..0a082b09ffcd969fa5e970b0eba2464b4f36f39f
--- /dev/null
+++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
@@ -0,0 +1,13 @@
+; $Id: drupal_system_listing_incompatible_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
+name = "Drupal system listing incompatible test"
+description = "Support module for testing the drupal_system_listing function."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
+project = "drupal"
+datestamp = "1294208756"
+
diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..d5db920e6f8d0bfae75423f536e559e97ff59ecc
--- /dev/null
+++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
@@ -0,0 +1,2 @@
+<?php
+// $Id: drupal_system_listing_incompatible_test.module,v 1.1 2010/11/15 00:37:08 webchick Exp $
diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info
index e1ff7e3ca602408d51330502b6b38e354dc97f62..17e15afd04fa3d21edc96dd704cd90fc5a3825b9 100644
--- a/modules/simpletest/tests/entity_cache_test.info
+++ b/modules/simpletest/tests/entity_cache_test.info
@@ -1,15 +1,14 @@
-; $Id: entity_cache_test.info,v 1.1 2010/04/18 15:01:56 webchick Exp $
+; $Id: entity_cache_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Entity cache test"
 description = "Support module for testing entity cache."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = entity_cache_test.module
 dependencies[] = entity_cache_test_dependency
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info
index 08b039a7f6e0e2e50f6583147a4b2f65c1cbe4b3..f1217dfb8bc99f951140ed4864d9150db6564173 100644
--- a/modules/simpletest/tests/entity_cache_test_dependency.info
+++ b/modules/simpletest/tests/entity_cache_test_dependency.info
@@ -1,14 +1,13 @@
-; $Id: entity_cache_test_dependency.info,v 1.1 2010/04/18 15:01:56 webchick Exp $
+; $Id: entity_cache_test_dependency.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Entity cache test dependency"
 description = "Support dependency module for testing entity cache."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = entity_cache_test_dependency.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/entity_crud_hook_test.info b/modules/simpletest/tests/entity_crud_hook_test.info
index 7d6d2b7bce507e34e5cbb4ba9fba4d5ebf05d1fb..99bb8eb078e54703f3da2598af56f6875ebe6396 100644
--- a/modules/simpletest/tests/entity_crud_hook_test.info
+++ b/modules/simpletest/tests/entity_crud_hook_test.info
@@ -1,15 +1,13 @@
-; $Id: entity_crud_hook_test.info,v 1.1 2010/10/15 03:36:21 webchick Exp $
-
+; $Id: entity_crud_hook_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Entity CRUD Hooks Test"
 description = "Support module for CRUD hook tests."
 core = 7.x
 package = Testing
-files[] = entity_crud_hook_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/entity_crud_hook_test.module b/modules/simpletest/tests/entity_crud_hook_test.module
index 9b7f9d90645ba10e0f9f9d635b629169cf75f583..3aa9caccdfe8de37854abbc1a3a284fcce11c251 100644
--- a/modules/simpletest/tests/entity_crud_hook_test.module
+++ b/modules/simpletest/tests/entity_crud_hook_test.module
@@ -1,5 +1,58 @@
 <?php
-// $Id: entity_crud_hook_test.module,v 1.1 2010/10/15 03:36:21 webchick Exp $
+// $Id: entity_crud_hook_test.module,v 1.2 2010/12/15 03:39:42 webchick Exp $
+
+//
+// Presave hooks
+//
+
+/**
+ * Implements hook_entity_presave().
+ */
+function entity_crud_hook_test_entity_presave($entity, $type) {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
+}
+
+/**
+ * Implements hook_comment_presave().
+ */
+function entity_crud_hook_test_comment_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
+
+/**
+ * Implements hook_file_presave().
+ */
+function entity_crud_hook_test_file_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
+
+/**
+ * Implements hook_node_presave().
+ */
+function entity_crud_hook_test_node_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
+
+/**
+ * Implements hook_taxonomy_term_presave().
+ */
+function entity_crud_hook_test_taxonomy_term_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
+
+/**
+ * Implements hook_taxonomy_vocabulary_presave().
+ */
+function entity_crud_hook_test_taxonomy_vocabulary_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
+
+/**
+ * Implements hook_user_presave().
+ */
+function entity_crud_hook_test_user_presave() {
+  $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
+}
 
 //
 // Insert hooks
diff --git a/modules/simpletest/tests/entity_crud_hook_test.test b/modules/simpletest/tests/entity_crud_hook_test.test
index 21b10a43b7c82272a02f03a433365c160d5d6ec9..50cf720347e033cfbbeaf74050b2047a3afae74c 100644
--- a/modules/simpletest/tests/entity_crud_hook_test.test
+++ b/modules/simpletest/tests/entity_crud_hook_test.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: entity_crud_hook_test.test,v 1.1 2010/10/15 03:36:21 webchick Exp $
+// $Id: entity_crud_hook_test.test,v 1.2 2010/12/15 03:39:42 webchick Exp $
 
 /**
  * Test invocation of hooks when inserting, loading, updating or deleting an
@@ -81,6 +81,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     comment_save($comment);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
+    $this->assertHookMessage('entity_crud_hook_test_comment_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type comment');
     $this->assertHookMessage('entity_crud_hook_test_comment_insert called');
 
@@ -94,6 +96,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $comment->subject = 'New subject';
     comment_save($comment);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
+    $this->assertHookMessage('entity_crud_hook_test_comment_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type comment');
     $this->assertHookMessage('entity_crud_hook_test_comment_update called');
 
@@ -123,6 +127,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     file_save($file);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
+    $this->assertHookMessage('entity_crud_hook_test_file_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type file');
     $this->assertHookMessage('entity_crud_hook_test_file_insert called');
 
@@ -136,6 +142,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $file->filename = 'new.entity_crud_hook_test.file';
     file_save($file);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
+    $this->assertHookMessage('entity_crud_hook_test_file_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type file');
     $this->assertHookMessage('entity_crud_hook_test_file_update called');
 
@@ -165,6 +173,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     node_save($node);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
+    $this->assertHookMessage('entity_crud_hook_test_node_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type node');
     $this->assertHookMessage('entity_crud_hook_test_node_insert called');
 
@@ -178,6 +188,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $node->title = 'New title';
     node_save($node);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
+    $this->assertHookMessage('entity_crud_hook_test_node_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type node');
     $this->assertHookMessage('entity_crud_hook_test_node_update called');
 
@@ -209,6 +221,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     taxonomy_term_save($term);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
+    $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_term');
     $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_insert called');
 
@@ -222,6 +236,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $term->name = 'New name';
     taxonomy_term_save($term);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
+    $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_term');
     $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_update called');
 
@@ -245,6 +261,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     taxonomy_vocabulary_save($vocabulary);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
+    $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary');
     $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_insert called');
 
@@ -258,6 +276,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $vocabulary->name = 'New name';
     taxonomy_vocabulary_save($vocabulary);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
+    $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_vocabulary');
     $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_update called');
 
@@ -283,6 +303,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $_SESSION['entity_crud_hook_test'] = array();
     $account = user_save($account, $edit);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
+    $this->assertHookMessage('entity_crud_hook_test_user_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type user');
     $this->assertHookMessage('entity_crud_hook_test_user_insert called');
 
@@ -296,6 +318,8 @@ class EntityCrudHookTestCase extends DrupalWebTestCase {
     $edit['name'] = 'New name';
     $account = user_save($account, $edit);
 
+    $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
+    $this->assertHookMessage('entity_crud_hook_test_user_presave called');
     $this->assertHookMessage('entity_crud_hook_test_entity_update called for type user');
     $this->assertHookMessage('entity_crud_hook_test_user_update called');
 
diff --git a/modules/simpletest/tests/entity_query.test b/modules/simpletest/tests/entity_query.test
index da76b692dcad08c6875ddfc3bdfa53d3a06e0c5a..c1bc3dee51d0f98fa49e32ef845f15a34f8ac1f8 100644
--- a/modules/simpletest/tests/entity_query.test
+++ b/modules/simpletest/tests/entity_query.test
@@ -1,6 +1,6 @@
 <?php
 
-// $Id: entity_query.test,v 1.13 2010/10/06 13:57:47 dries Exp $
+// $Id: entity_query.test,v 1.15 2010/11/14 22:07:57 webchick Exp $
 
 /**
  * @file
@@ -113,7 +113,7 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
 
     $entity = new stdClass();
     $entity->ftid = 5;
-    $entity->fttype = 'bundle2';
+    $entity->fttype = 'test_entity_bundle';
     $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['shape'] = 'square';
     $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['color'] = 'red';
     $entity->{$this->field_names[1]}[LANGUAGE_NONE][1]['shape'] = 'circle';
@@ -164,6 +164,14 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
    * Tests EntityFieldQuery.
    */
   function testEntityFieldQuery() {
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle')
+      ->entityCondition('entity_id', '5');
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle', 5),
+    ), t('Test query on an entity type with a generated bundle.'));
+
     // Test entity_type condition.
     $query = new EntityFieldQuery();
     $query->entityCondition('entity_type', 'test_entity_bundle_key');
@@ -974,6 +982,7 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
     for ($i = 6; $i < 10; $i++) {
       $entity = new stdClass();
       $entity->ftid = $i;
+      $entity->fttype = 'test_entity_bundle';
       $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i - 5;
       drupal_write_record('test_entity_bundle', $entity);
       field_attach_insert('test_entity_bundle', $entity);
@@ -1095,6 +1104,238 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
     $this->assertTrue($pass, t('Cannot query across field storage engines.'));
   }
 
+  /**
+   * Tests the pager integration of EntityFieldQuery.
+   */
+  function testEntityFieldQueryPager() {
+    // Test pager in propertyQuery
+    $_GET['page'] = '0,1';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->propertyOrderBy('ftid', 'ASC')
+      ->pager(3, 0);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+    ), t('Test pager integration in propertyQuery: page 1.'), TRUE);
+
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->propertyOrderBy('ftid', 'ASC')
+      ->pager(3, 1);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+    ), t('Test pager integration in propertyQuery: page 2.'), TRUE);
+
+    // Test pager in field storage
+    $_GET['page'] = '0,1';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->propertyOrderBy('ftid', 'ASC')
+      ->pager(2, 0);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+    ), t('Test pager integration in field storage: page 1.'), TRUE);
+
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->propertyOrderBy('ftid', 'ASC')
+      ->pager(2, 1);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+    ), t('Test pager integration in field storage: page 2.'), TRUE);
+
+    unset($_GET['page']);
+  }
+
+  /**
+   * Tests the TableSort integration of EntityFieldQuery.
+   */
+  function testEntityFieldQueryTableSort() {
+    // Test TableSort in propertyQuery
+    $_GET['sort'] = 'asc';
+    $_GET['order'] = 'Id';
+    $header = array(
+      'id' => array('data' => 'Id', 'type' => 'property',  'specifier' => 'ftid'),
+      'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'),
+    );
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+    ), t('Test TableSort by property: ftid ASC in propertyQuery.'), TRUE);
+
+    $_GET['sort'] = 'desc';
+    $_GET['order'] = 'Id';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 1),
+    ), t('Test TableSort by property: ftid DESC in propertyQuery.'), TRUE);
+
+    $_GET['sort'] = 'asc';
+    $_GET['order'] = 'Type';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+    ), t('Test TableSort by entity: bundle ASC in propertyQuery.'), TRUE);
+
+    $_GET['sort'] = 'desc';
+    $_GET['order'] = 'Type';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+    ), t('Test TableSort by entity: bundle DESC in propertyQuery.'), TRUE);
+
+    // Test TableSort in field storage
+    $_GET['sort'] = 'asc';
+    $_GET['order'] = 'Id';
+    $header = array(
+      'id' => array('data' => 'Id', 'type' => 'property',  'specifier' => 'ftid'),
+      'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'),
+      'field' => array('data' => 'Field', 'type' => 'field', 'specifier' => array('field' => $this->field_names[0], 'column' => 'value')),
+    );
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+    ), t('Test TableSort by property: ftid ASC in field storage.'), TRUE);
+
+    $_GET['sort'] = 'desc';
+    $_GET['order'] = 'Id';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 1),
+    ), t('Test TableSort by property: ftid DESC in field storage.'), TRUE);
+
+    $_GET['sort'] = 'asc';
+    $_GET['order'] = 'Type';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header)
+      ->entityOrderBy('entity_id', 'DESC');
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 5),
+    ), t('Test TableSort by entity: bundle ASC in field storage.'), TRUE);
+
+    $_GET['sort'] = 'desc';
+    $_GET['order'] = 'Type';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header)
+      ->entityOrderBy('entity_id', 'ASC');
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+    ), t('Test TableSort by entity: bundle DESC in field storage.'), TRUE);
+
+    $_GET['sort'] = 'asc';
+    $_GET['order'] = 'Field';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 1),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 6),
+    ), t('Test TableSort by field ASC.'), TRUE);
+
+    $_GET['sort'] = 'desc';
+    $_GET['order'] = 'Field';
+    $query = new EntityFieldQuery();
+    $query
+      ->entityCondition('entity_type', 'test_entity_bundle_key')
+      ->fieldCondition($this->fields[0], 'value', 0, '>')
+      ->tableSort($header);
+    $this->assertEntityFieldQuery($query, array(
+      array('test_entity_bundle_key', 6),
+      array('test_entity_bundle_key', 5),
+      array('test_entity_bundle_key', 4),
+      array('test_entity_bundle_key', 3),
+      array('test_entity_bundle_key', 2),
+      array('test_entity_bundle_key', 1),
+    ), t('Test TableSort by field DESC.'), TRUE);
+
+    unset($_GET['sort']);
+    unset($_GET['order']);
+  }
+
   /**
    * Fetches the results of an EntityFieldQuery and compares.
    *
@@ -1112,15 +1353,20 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
    */
   function assertEntityFieldQuery($query, $intended_results, $message, $ordered = FALSE) {
     $results = array();
-    foreach ($query->execute() as $entity_type => $entity_ids) {
-      foreach ($entity_ids as $entity_id => $stub_entity) {
-        $results[] = array($entity_type, $entity_id);
+    try {
+      foreach ($query->execute() as $entity_type => $entity_ids) {
+        foreach ($entity_ids as $entity_id => $stub_entity) {
+          $results[] = array($entity_type, $entity_id);
+        }
+      }
+      if (!isset($ordered) || !$ordered) {
+        sort($results);
+        sort($intended_results);
       }
+      $this->assertEqual($results, $intended_results, $message);
     }
-    if (!isset($ordered) || !$ordered) {
-      sort($results);
-      sort($intended_results);
+    catch (Exception $e) {
+      $this->fail('Exception thrown: '. $e->getMessage());
     }
-    $this->assertEqual($results, $intended_results, $message);
   }
 }
diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info
index 219ffb89a1f83797afdc76653b6c716a95d14368..1cb85e0221ea15277aa3b0a1276bdf18cc3498b1 100644
--- a/modules/simpletest/tests/error_test.info
+++ b/modules/simpletest/tests/error_test.info
@@ -1,14 +1,13 @@
-; $Id: error_test.info,v 1.1 2009/05/22 15:03:46 webchick Exp $
+; $Id: error_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Error test"
 description = "Support module for error and exception testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = error_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test
index 369db87897db1b2905b68a92ce40af1ed8954612..467b599677507e22c2120d60b3e71d08440b0d7f 100644
--- a/modules/simpletest/tests/file.test
+++ b/modules/simpletest/tests/file.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: file.test,v 1.71 2010/10/05 06:23:18 webchick Exp $
+// $Id: file.test,v 1.72 2010/11/30 19:31:46 dries Exp $
 
 /**
  *  @file
@@ -1485,7 +1485,7 @@ class FileMoveTest extends FileHookTestCase {
     $this->assertEqual($contents, file_get_contents($result->uri), t('Contents of file correctly written.'));
 
     // Check that the correct hooks were called.
-    $this->assertFileHooksCalled(array('move', 'update'));
+    $this->assertFileHooksCalled(array('move', 'load', 'update'));
 
     // Make sure we got the same file back.
     $this->assertEqual($source->fid, $result->fid, t("Source file id's' %fid is unchanged after move.", array('%fid' => $source->fid)));
@@ -1517,7 +1517,7 @@ class FileMoveTest extends FileHookTestCase {
     $this->assertEqual($contents, file_get_contents($result->uri), t('Contents of file correctly written.'));
 
     // Check that the correct hooks were called.
-    $this->assertFileHooksCalled(array('move', 'update'));
+    $this->assertFileHooksCalled(array('move', 'load', 'update'));
 
     // Compare the returned value to what made it into the database.
     $this->assertFileUnchanged($result, file_load($result->fid, TRUE));
@@ -1891,7 +1891,7 @@ class FileSaveTest extends FileHookTestCase {
     $resaved_file = file_save($saved_file);
 
     // Check that the correct hooks were called.
-    $this->assertFileHooksCalled(array('update'));
+    $this->assertFileHooksCalled(array('load', 'update'));
 
     $this->assertEqual($resaved_file->fid, $saved_file->fid, t("The file ID of an existing file is not changed when updating the database."), 'File');
     $this->assertTrue($resaved_file->timestamp >= $saved_file->timestamp, t("Timestamp didn't go backwards."), 'File');
diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info
index 6bed847e30139c1cf29bbca388bba53f0a804978..38ca4ec01a7cc0600ff53e7b6079b6163b66fdd2 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-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info
index d6cc777667c6bfd6afdf46ddcba8747c190e4380..880451301086f54876693b0610f95eef709fe3a2 100644
--- a/modules/simpletest/tests/filter_test.info
+++ b/modules/simpletest/tests/filter_test.info
@@ -1,14 +1,13 @@
-; $Id: filter_test.info,v 1.1 2009/08/26 10:29:26 dries Exp $
+; $Id: filter_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = Filter test module
 description = Tests filter hooks and functions.
 package = Testing
 version = VERSION
 core = 7.x
-files[] = filter_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index 661fef9b6ba9cf6ce614e540e53abbcf662ff250..79ec0983b09849b314f7aff3ada808853521750e 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: form.test,v 1.72 2010/10/04 18:00:46 dries Exp $
+// $Id: form.test,v 1.79 2010/12/30 22:52:24 webchick Exp $
 
 /**
  * @file
@@ -369,6 +369,66 @@ class FormsTestCase extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests building and processing of core form elements.
+ */
+class FormElementTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Element processing',
+      'description' => 'Tests building and processing of core form elements.',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('form_test'));
+  }
+
+  /**
+   * Tests expansion of #options for #type checkboxes and radios.
+   */
+  function testOptions() {
+    $this->drupalGet('form-test/checkboxes-radios');
+
+    // Verify that all options appear in their defined order.
+    foreach (array('checkbox', 'radio') as $type) {
+      $elements = $this->xpath('//input[@type=:type]', array(':type' => $type));
+      $expected_values = array('0', 'foo', '1', 'bar', '>');
+      foreach ($elements as $element) {
+        $expected = array_shift($expected_values);
+        $this->assertIdentical((string) $element['value'], $expected);
+      }
+    }
+
+    // Enable customized option sub-elements.
+    $this->drupalGet('form-test/checkboxes-radios/customize');
+
+    // Verify that all options appear in their defined order, taking a custom
+    // #weight into account.
+    foreach (array('checkbox', 'radio') as $type) {
+      $elements = $this->xpath('//input[@type=:type]', array(':type' => $type));
+      $expected_values = array('0', 'foo', 'bar', '>', '1');
+      foreach ($elements as $element) {
+        $expected = array_shift($expected_values);
+        $this->assertIdentical((string) $element['value'], $expected);
+      }
+    }
+    // Verify that custom #description properties are output.
+    foreach (array('checkboxes', 'radios') as $type) {
+      $elements = $this->xpath('//input[@id=:id]/following-sibling::div[@class=:class]', array(
+        ':id' => 'edit-' . $type . '-foo',
+        ':class' => 'description',
+      ));
+      $this->assertTrue(count($elements), t('Custom %type option description found.', array(
+        '%type' => $type,
+      )));
+    }
+  }
+}
+
 /**
  * Test form alter hooks.
  */
@@ -461,16 +521,33 @@ class FormValidationTestCase extends DrupalWebTestCase {
    * Tests partial form validation through #limit_validation_errors.
    */
   function testValidateLimitErrors() {
-    $edit = array('test' => 'invalid');
+    $edit = array(
+      'test' => 'invalid', 
+      'test_numeric_index[0]' => 'invalid',
+      'test_substring[foo]' => 'invalid',
+    );
     $path = 'form-test/limit-validation-errors';
 
-    // Submit the form by pressing the button with #limit_validation_errors and
-    // ensure that the title field is not validated, but the #element_validate
-    // handler for the 'test' field is triggered.
+    // Submit the form by pressing the 'Partial validate' button (uses
+    // #limit_validation_errors) and ensure that the title field is not
+    // validated, but the #element_validate handler for the 'test' field
+    // is triggered.
     $this->drupalPost($path, $edit, t('Partial validate'));
     $this->assertNoText(t('!name field is required.', array('!name' => 'Title')));
     $this->assertText('Test element is invalid');
 
+    // Edge case of #limit_validation_errors containing numeric indexes: same
+    // thing with the 'Partial validate (numeric index)' button and the
+    // 'test_numeric_index' field.
+    $this->drupalPost($path, $edit, t('Partial validate (numeric index)'));
+    $this->assertNoText(t('!name field is required.', array('!name' => 'Title')));
+    $this->assertText('Test (numeric index) element is invalid');
+
+    // Ensure something like 'foobar' isn't considered "inside" 'foo'.
+    $this->drupalPost($path, $edit, t('Partial validate (substring)'));
+    $this->assertNoText(t('!name field is required.', array('!name' => 'Title')));
+    $this->assertText('Test (substring) foo element is invalid');
+
     // Ensure not validated values are not available to submit handlers.
     $this->drupalPost($path, array('title' => '', 'test' => 'valid'), t('Partial validate'));
     $this->assertText('Only validated values appear in the form values.');
@@ -757,6 +834,36 @@ class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase {
 
 }
 
+/**
+ * Test the vertical_tabs form element for expected behavior.
+ */
+class FormsElementsVerticalTabsFunctionalTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Vertical tabs form element type test',
+      'description' => 'Test the vertical_tabs element for expected behavior',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Ensures that vertical-tabs.js is included before collapse.js.
+   *
+   * Otherwise, collapse.js adds "SHOW" or "HIDE" labels to the tabs.
+   */
+  function testJavaScriptOrdering() {
+    $this->drupalGet('form_test/vertical-tabs');
+    $position1 = strpos($this->content, 'misc/vertical-tabs.js');
+    $position2 = strpos($this->content, 'misc/collapse.js');
+    $this->assertTrue($position1 !== FALSE && $position2 !== FALSE && $position1 < $position2, t('vertical-tabs.js is included before collapse.js'));
+  }
+}
+
 /**
  * Test the form storage on a multistep form.
  *
@@ -1115,6 +1222,15 @@ class FormsProgrammaticTestCase extends DrupalWebTestCase {
     $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => 2)), TRUE);
     $this->submitForm(array('textfield' => 'dummy value', 'checkboxes' => array(1 => NULL, 2 => NULL)), TRUE);
 
+    // Test that a programmatic form submission can correctly click a button
+    // that limits validation errors based on user input. Since we do not
+    // submit any values for "textfield" here and the textfield is required, we
+    // only expect form validation to pass when validation is limited to a
+    // different field.
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'all'), FALSE);
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'textfield'), FALSE);
+    $this->submitForm(array('op' => 'Submit with limited validation', 'field_to_validate' => 'field_to_validate'), TRUE);
+
     // Restore the current batch status.
     $batch = $current_batch;
   }
@@ -1352,3 +1468,84 @@ class FormsFileInclusionTestCase extends DrupalWebTestCase {
     $this->assertText('Submit callback called.');
   }
 }
+
+/**
+ * Tests checkbox element.
+ */
+class FormCheckboxTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Form API checkbox',
+      'description' => 'Tests form API checkbox handling of various combinations of #default_value and #return_value.',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  function testFormCheckbox() {
+    // Ensure that the checked state is determined and rendered correctly for
+    // tricky combinations of default and return values.
+    foreach (array(FALSE, NULL, TRUE, 0, '0', '', 1, '1', 'foobar', '1foobar') as $default_value) {
+      // Only values that can be used for array indeces are supported for
+      // #return_value, with the exception of integer 0, which is not supported.
+      // @see form_process_checkbox().
+      foreach (array('0', '', 1, '1', 'foobar', '1foobar') as $return_value) {
+        $form_array = drupal_get_form('form_test_checkbox_type_juggling', $default_value, $return_value);
+        $form = drupal_render($form_array);
+        if ($default_value === TRUE) {
+          $checked = TRUE;
+        }
+        elseif ($return_value === '0') {
+          $checked = ($default_value === '0');
+        }
+        elseif ($return_value === '') {
+          $checked = ($default_value === '');
+        }
+        elseif ($return_value === 1 || $return_value === '1') {
+          $checked = ($default_value === 1 || $default_value === '1');
+        }
+        elseif ($return_value === 'foobar') {
+          $checked = ($default_value === 'foobar');
+        }
+        elseif ($return_value === '1foobar') {
+          $checked = ($default_value === '1foobar');
+        }
+        $checked_in_html = strpos($form, 'checked') !== FALSE;
+        $message = t('#default_value is %default_value #return_value is %return_value.', array('%default_value' => var_export($default_value, TRUE), '%return_value' => var_export($return_value, TRUE)));
+        $this->assertIdentical($checked, $checked_in_html, $message);
+      }
+    }
+
+    // Ensure that $form_state['values'] is populated correctly for a checkboxes
+    // group that includes a 0-indexed array of options.
+    $results = json_decode($this->drupalPost('form-test/checkboxes-zero', array(), 'Save'));
+    $this->assertIdentical($results->checkbox_off, array(0, 0, 0), t('All three in checkbox_off are zeroes: off.'));
+    $this->assertIdentical($results->checkbox_zero_default, array('0', 0, 0), t('The first choice is on in checkbox_zero_default'));
+    $this->assertIdentical($results->checkbox_string_zero_default, array('0', 0, 0), t('The first choice is on in checkbox_string_zero_default'));
+    $edit = array('checkbox_off[0]' => '0');
+    $results = json_decode($this->drupalPost('form-test/checkboxes-zero', $edit, 'Save'));
+    $this->assertIdentical($results->checkbox_off, array('0', 0, 0), t('The first choice is on in checkbox_off but the rest is not'));
+
+    // Ensure that each checkbox is rendered correctly for a checkboxes group
+    // that includes a 0-indexed array of options.
+    $this->drupalPost('form-test/checkboxes-zero/0', array(), 'Save');
+    $checkboxes = $this->xpath('//input[@type="checkbox"]');
+    foreach ($checkboxes as $checkbox) {
+      $checked = isset($checkbox['checked']);
+      $name = (string) $checkbox['name'];
+      $this->assertIdentical($checked, $name == 'checkbox_zero_default[0]' || $name == 'checkbox_string_zero_default[0]', t('Checkbox %name correctly checked', array('%name' => $name)));
+    }
+    $edit = array('checkbox_off[0]' => '0');
+    $this->drupalPost('form-test/checkboxes-zero/0', $edit, 'Save');
+    $checkboxes = $this->xpath('//input[@type="checkbox"]');
+    foreach ($checkboxes as $checkbox) {
+      $checked = isset($checkbox['checked']);
+      $name = (string) $checkbox['name'];
+      $this->assertIdentical($checked, $name == 'checkbox_off[0]' || $name == 'checkbox_zero_default[0]' || $name == 'checkbox_string_zero_default[0]', t('Checkbox %name correctly checked', array('%name' => $name)));
+    }
+  }
+}
diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info
index 053bbf12cc90bfdeaadf83dd47267faece01870a..c839bcdac36621a0d98e9e5e6b2395ee27430556 100644
--- a/modules/simpletest/tests/form_test.info
+++ b/modules/simpletest/tests/form_test.info
@@ -1,15 +1,13 @@
-; $Id: form_test.info,v 1.2 2010/07/17 18:52:39 dries Exp $
+; $Id: form_test.info,v 1.3 2010/12/20 19:59:43 webchick Exp $
 name = "FormAPI Test"
 description = "Support module for Form API tests."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = form_test.module
-files[] = form_test.file.inc
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module
index 3ae8f65a6b7b68cee1a7c4d438de7ce9ca2b1443..c49b284668cb79c9635e8cdc46d2043cfde47349 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.52 2010/10/20 01:15:58 dries Exp $
+// $Id: form_test.module,v 1.59 2010/12/30 22:52:24 webchick Exp $
 
 /**
  * @file
@@ -61,6 +61,14 @@ function form_test_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  $items['form_test/vertical-tabs'] = array(
+    'title' => 'Vertical tabs tests',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('_form_test_vertical_tabs_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   $items['form_test/form-storage'] = array(
     'title' => 'Form storage test',
     'page callback' => 'drupal_get_form',
@@ -98,6 +106,12 @@ function form_test_menu() {
     'page arguments' => array('form_test_select'),
     'access callback' => TRUE,
   );
+  $items['form-test/checkboxes-radios'] = array(
+    'title' => t('Checkboxes, Radios'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_checkboxes_radios'),
+    'access callback' => TRUE,
+  );
 
   $items['form-test/disabled-elements'] = array(
     'title' => t('Form test'),
@@ -175,10 +189,25 @@ function form_test_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
+  $items['form-test/checkboxes-zero'] = array(
+    'title' => 'FAPI test involving checkboxes and zero',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_checkboxes_zero'),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
 
   return $items;
 }
 
+/**
+ * Form submit handler to return form values as JSON.
+ */
+function _form_test_submit_values_json($form, &$form_state) {
+  drupal_json_output($form_state['values']);
+  drupal_exit();
+}
+
 /**
  * Form builder for testing hook_form_alter() and hook_form_FORM_ID_alter().
  */
@@ -312,16 +341,53 @@ function form_test_limit_validation_errors_form($form, &$form_state) {
     '#title' => 'Title',
     '#required' => TRUE,
   );
+
   $form['test'] = array(
+    '#title' => 'Test',
+    '#type' => 'textfield',
+    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
+  );
+  $form['test_numeric_index'] = array(
+    '#tree' => TRUE,
+  );
+  $form['test_numeric_index'][0] = array(
+    '#title' => 'Test (numeric index)',
+    '#type' => 'textfield',
+    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
+  );
+
+  $form['test_substring'] = array(
+    '#tree' => TRUE,
+  );
+  $form['test_substring']['foo'] = array(
+    '#title' => 'Test (substring) foo',
+    '#type' => 'textfield',
+    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
+  );
+  $form['test_substring']['foobar'] = array(
+    '#title' => 'Test (substring) foobar',
     '#type' => 'textfield',
     '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
   );
+
   $form['actions']['partial'] = array(
     '#type' => 'submit',
     '#limit_validation_errors' => array(array('test')),
     '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
     '#value' => t('Partial validate'),
   );
+  $form['actions']['partial_numeric_index'] = array(
+    '#type' => 'submit',
+    '#limit_validation_errors' => array(array('test_numeric_index', 0)),
+    '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
+    '#value' => t('Partial validate (numeric index)'),
+  );
+  $form['actions']['substring'] = array(
+    '#type' => 'submit',
+    '#limit_validation_errors' => array(array('test_substring', 'foo')),
+    '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
+    '#value' => t('Partial validate (substring)'),
+  );
   $form['actions']['full'] = array(
     '#type' => 'submit',
     '#value' => t('Full validate'),
@@ -334,7 +400,7 @@ function form_test_limit_validation_errors_form($form, &$form_state) {
  */
 function form_test_limit_validation_errors_element_validate_test(&$element, &$form_state) {
   if ($element['#value'] == 'invalid') {
-    form_error($element, 'Test element is invalid');
+    form_error($element, t('@label element is invalid', array('@label' => $element['#title'])));
   }
 }
 
@@ -479,6 +545,36 @@ function _form_test_tableselect_js_select_form($form, $form_state, $action) {
   return _form_test_tableselect_form_builder($form, $form_state, $options);
 }
 
+/**
+ * Tests functionality of vertical tabs.
+ */
+function _form_test_vertical_tabs_form($form, &$form_state) {
+  $form['vertical_tabs'] = array(
+    '#type' => 'vertical_tabs',
+  );
+  $form['tab1'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Tab 1'),
+    '#collapsible' => TRUE,
+    '#group' => 'vertical_tabs',
+  );
+  $form['tab1']['field1'] = array(
+    '#title' => t('Field 1'),
+    '#type' => 'textfield',
+  );
+  $form['tab2'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Tab 2'),
+    '#collapsible' => TRUE,
+    '#group' => 'vertical_tabs',
+  );
+  $form['tab2']['field2'] = array(
+    '#title' => t('Field 2'),
+    '#type' => 'textfield',
+  );
+  return $form;
+}
+
 /**
  * A multistep form for testing the form storage.
  *
@@ -885,6 +981,65 @@ function form_test_select_submit($form, &$form_state) {
   exit();
 }
 
+/**
+ * Form constructor to test expansion of #type checkboxes and radios.
+ */
+function form_test_checkboxes_radios($form, &$form_state, $customize = FALSE) {
+  $form['#submit'] = array('_form_test_submit_values_json');
+
+  // Expand #type checkboxes, setting custom element properties for some but not
+  // all options.
+  $form['checkboxes'] = array(
+    '#type' => 'checkboxes',
+    '#title' => 'Checkboxes',
+    '#options' => array(
+      0 => 'Zero',
+      'foo' => 'Foo',
+      1 => 'One',
+      'bar' => 'Bar',
+      '>' => 'Special Char',
+    ),
+  );
+  if ($customize) {
+    $form['checkboxes'] += array(
+      'foo' => array(
+        '#description' => 'Enable to foo.',
+      ),
+      1 => array(
+        '#weight' => 10,
+      ),
+    );
+  }
+
+  // Expand #type radios, setting custom element properties for some but not
+  // all options.
+  $form['radios'] = array(
+    '#type' => 'radios',
+    '#title' => 'Radios',
+    '#options' => array(
+      0 => 'Zero',
+      'foo' => 'Foo',
+      1 => 'One',
+      'bar' => 'Bar',
+      '>' => 'Special Char',
+    ),
+  );
+  if ($customize) {
+    $form['radios'] += array(
+      'foo' => array(
+        '#description' => 'Enable to foo.',
+      ),
+      1 => array(
+        '#weight' => 10,
+      ),
+    );
+  }
+
+  $form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
+
+  return $form;
+}
+
 /**
  * Build a form to test disabled elements.
  */
@@ -1224,6 +1379,7 @@ function form_test_programmatic_form($form, &$form_state) {
     '#title' => 'Textfield',
     '#type' => 'textfield',
   );
+
   $form['checkboxes'] = array(
     '#type' => 'checkboxes',
     '#options' => array(
@@ -1235,6 +1391,39 @@ function form_test_programmatic_form($form, &$form_state) {
     '#default_value' => array(1, 2),
   );
 
+  $form['field_to_validate'] = array(
+    '#type' => 'radios',
+    '#title' => 'Field to validate (in the case of limited validation)',
+    '#description' => 'If the form is submitted by clicking the "Submit with limited validation" button, then validation can be limited based on the value of this radio button.',
+    '#options' => array(
+      'all' => 'Validate all fields',
+      'textfield' => 'Validate the "Textfield" field',
+      'field_to_validate' => 'Validate the "Field to validate" field',
+    ),
+    '#default_value' => 'all',
+  );
+
+  // The main submit button for the form.
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit',
+  );
+  // A secondary submit button that allows validation to be limited based on
+  // the value of the above radio selector.
+  $form['submit_limit_validation'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit with limited validation',
+    // Use the same submit handler for this button as for the form itself.
+    // (This must be set explicitly or otherwise the form API will ignore the
+    // #limit_validation_errors property.)
+    '#submit' => array('form_test_programmatic_form_submit'),
+  );
+  if (!empty($form_state['input']['field_to_validate']) && $form_state['input']['field_to_validate'] != 'all') {
+    $form['submit_limit_validation']['#limit_validation_errors'] = array(
+      array($form_state['input']['field_to_validate']),
+    );
+  }
+
   return $form;
 }
 
@@ -1391,7 +1580,49 @@ function form_test_load_include_custom($form, &$form_state) {
   // Specify the include file and enable form caching. That way the form is
   // cached when it is submitted, but needs to find the specified submit handler
   // in the include.
-  $form_state['build_info']['files'][] = array('module' => 'form_test', 'name' => 'form_test.file');
+  // Filename is a bit weird here: modules/simpletest/tests/form_test.file.inc
+  form_load_include($form_state, 'inc', 'form_test', 'form_test.file');
   $form_state['cache'] = TRUE;
   return $form;
 }
+
+function form_test_checkbox_type_juggling($form, $form_state, $default_value, $return_value) {
+  $form['checkbox'] = array(
+    '#type' => 'checkbox',
+    '#return_value' => $return_value,
+    '#default_value' => $default_value,
+  );
+  return $form;
+}
+
+function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) {
+  $form['checkbox_off'] = array(
+    '#type' => 'checkboxes',
+    '#options' => array('foo', 'bar', 'baz'),
+  );
+  $form['checkbox_zero_default'] = array(
+    '#type' => 'checkboxes',
+    '#options' => array('foo', 'bar', 'baz'),
+    '#default_value' => array(0),
+  );
+  $form['checkbox_string_zero_default'] = array(
+    '#type' => 'checkboxes',
+    '#options' => array('foo', 'bar', 'baz'),
+    '#default_value' => array('0'),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Save',
+  );
+  if ($json) {
+    $form['#submit'][] = '_form_test_checkbox_submit';
+  }
+  else {
+    $form['#submit'][] = '_form_test_checkboxes_zero_no_redirect';
+  }
+  return $form;
+}
+
+function _form_test_checkboxes_zero_no_redirect($form, &$form_state) {
+  $form_state['redirect'] = FALSE;
+}
diff --git a/modules/simpletest/tests/http.php b/modules/simpletest/tests/http.php
new file mode 100644
index 0000000000000000000000000000000000000000..5400bb8f281063bd74de9bf1a1120e19c35dc31a
--- /dev/null
+++ b/modules/simpletest/tests/http.php
@@ -0,0 +1,33 @@
+<?php
+// $Id: http.php,v 1.1 2010/11/05 19:05:02 dries Exp $
+
+/**
+ * @file
+ * Fake an HTTP request, for use during testing.
+ */
+
+// Set a global variable to indicate a mock HTTP request.
+$is_http_mock = !empty($_SERVER['HTTPS']);
+
+// Change to HTTP.
+$_SERVER['HTTPS'] = NULL;
+ini_set('session.cookie_secure', FALSE);
+foreach ($_SERVER as $key => $value) {
+  $_SERVER[$key] = str_replace('modules/simpletest/tests/http.php', 'index.php', $value);
+  $_SERVER[$key] = str_replace('https://', 'http://', $_SERVER[$key]);
+}
+
+// Change current directory to the Drupal root.
+chdir('../../..');
+define('DRUPAL_ROOT', getcwd());
+require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+
+// Make sure this file can only be used by simpletest.
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+if (!drupal_valid_test_ua()) {
+  header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+  exit;
+}
+
+drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+menu_execute_active_handler();
diff --git a/modules/simpletest/tests/https.php b/modules/simpletest/tests/https.php
index 8485e12c69014f5f180f51940bf75907ef936996..bbbaca346b833d500a791f4d4744694df2dacfcc 100644
--- a/modules/simpletest/tests/https.php
+++ b/modules/simpletest/tests/https.php
@@ -1,28 +1,32 @@
 <?php
-// $Id: https.php,v 1.2 2009/11/04 05:05:52 webchick Exp $
+// $Id: https.php,v 1.3 2010/11/05 19:05:02 dries Exp $
 
 /**
  * @file
  * Fake an https request, for use during testing.
  */
 
-// Negated copy of the condition in _drupal_bootstrap(). If the user agent is
-// not from simpletest then disallow access.
-if (!(isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE))) {
-  exit;
-}
-
 // Set a global variable to indicate a mock HTTPS request.
 $is_https_mock = empty($_SERVER['HTTPS']);
 
 // Change to https.
 $_SERVER['HTTPS'] = 'on';
-
-// Change to index.php.
-chdir('../../..');
 foreach ($_SERVER as $key => $value) {
   $_SERVER[$key] = str_replace('modules/simpletest/tests/https.php', 'index.php', $value);
   $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
 }
 
-require_once 'index.php';
+// Change current directory to the Drupal root.
+chdir('../../..');
+define('DRUPAL_ROOT', getcwd());
+require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+
+// Make sure this file can only be used by simpletest.
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+if (!drupal_valid_test_ua()) {
+  header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+  exit;
+}
+
+drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+menu_execute_active_handler();
diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info
index b90879ab1b82698e56a9fa333054cc4db1d866b1..9f6d0f4934de3959783fec9b4862156253eed11d 100644
--- a/modules/simpletest/tests/image_test.info
+++ b/modules/simpletest/tests/image_test.info
@@ -1,14 +1,13 @@
-; $Id: image_test.info,v 1.1 2009/03/09 11:44:54 dries Exp $
+; $Id: image_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Image test"
 description = "Support module for image toolkit tests."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = image_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test
index 0c002e2e9c5f4c7d5a2e4b2351cceac031296d36..ff7c7c4d7b60688a3dea96114f4e4117e3e953f4 100644
--- a/modules/simpletest/tests/menu.test
+++ b/modules/simpletest/tests/menu.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu.test,v 1.38 2010/10/15 04:46:58 webchick Exp $
+// $Id: menu.test,v 1.42 2010/12/02 17:34:24 webchick Exp $
 
 /**
  * @file
@@ -159,26 +159,35 @@ class MenuRouterTestCase extends DrupalWebTestCase {
   }
 
   /**
-   * Test that the result of hook_custom_theme() overrides the theme callback.
+   * Test that hook_custom_theme() can control the theme of a page.
    */
   function testHookCustomTheme() {
     // Trigger hook_custom_theme() to dynamically request the Stark theme for
     // the requested page.
     variable_set('menu_test_hook_custom_theme_name', 'stark');
+    theme_enable(array('stark'));
 
-    // Request a page whose theme callback returns the Seven theme. Since Stark
-    // is not a currently enabled theme, our above request should be ignored,
-    // and Seven should still be used.
-    $this->drupalGet('menu-test/theme-callback/use-admin-theme');
-    $this->assertText('Custom theme: seven. Actual theme: seven.', t('The result of hook_custom_theme() does not override a theme callback when it returns a theme that is not enabled.'));
-    $this->assertRaw('seven/style.css', t("The Seven theme's CSS appears on the page."));
+    // Visit a page that does not implement a theme callback. The above request
+    // should be honored.
+    $this->drupalGet('menu-test/no-theme-callback');
+    $this->assertText('Custom theme: stark. Actual theme: stark.', t('The result of hook_custom_theme() is used as the theme for the current page.'));
+    $this->assertRaw('stark/layout.css', t("The Stark theme's CSS appears on the page."));
+  }
 
-    // Now enable the Stark theme and request the same page as above. This
-    // time, we expect hook_custom_theme() to prevail.
+  /**
+   * Test that the theme callback wins out over hook_custom_theme().
+   */
+  function testThemeCallbackHookCustomTheme() {
+    // Trigger hook_custom_theme() to dynamically request the Stark theme for
+    // the requested page.
+    variable_set('menu_test_hook_custom_theme_name', 'stark');
     theme_enable(array('stark'));
+
+    // The menu "theme callback" should take precedence over a value set in
+    // hook_custom_theme().
     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
-    $this->assertText('Custom theme: stark. Actual theme: stark.', t('The result of hook_custom_theme() overrides what was set in a theme callback.'));
-    $this->assertRaw('stark/layout.css', t("The Stark theme's CSS appears on the page."));
+    $this->assertText('Custom theme: seven. Actual theme: seven.', t('The result of hook_custom_theme() does not override what was set in a theme callback.'));
+    $this->assertRaw('seven/style.css', t("The Seven theme's CSS appears on the page."));
   }
 
   /**
@@ -464,6 +473,283 @@ class MenuRouterTestCase extends DrupalWebTestCase {
     $asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no;
     $this->assertTitle($asserted_title . ' | Drupal', t('Menu title is') . ': ' . $asserted_title, 'Menu');
   }
+
+  /**
+   * Load the router for a given path.
+   */
+  protected function menuLoadRouter($router_path) {
+    return db_query('SELECT * FROM {menu_router} WHERE path = :path', array(':path' => $router_path))->fetchAssoc();
+  }
+
+  /**
+   * Tests inheritance of 'load arguments'.
+   */
+  function testMenuLoadArgumentsInheritance() {
+    $expected = array(
+      'menu-test/arguments/%/%' => array(
+        2 => array('menu_test_argument_load' => array(3)),
+        3 => NULL,
+      ),
+      // Arguments are inherited to normal children.
+      'menu-test/arguments/%/%/default' => array(
+        2 => array('menu_test_argument_load' => array(3)),
+        3 => NULL,
+      ),
+      // Arguments are inherited to tab children.
+      'menu-test/arguments/%/%/task' => array(
+        2 => array('menu_test_argument_load' => array(3)),
+        3 => NULL,
+      ),
+      // Arguments are only inherited to the same loader functions.
+      'menu-test/arguments/%/%/common-loader' => array(
+        2 => array('menu_test_argument_load' => array(3)),
+        3 => 'menu_test_other_argument_load',
+      ),
+      // Arguments are not inherited to children not using the same loader
+      // function.
+      'menu-test/arguments/%/%/different-loaders-1' => array(
+        2 => NULL,
+        3 => 'menu_test_argument_load',
+      ),
+      'menu-test/arguments/%/%/different-loaders-2' => array(
+        2 => 'menu_test_other_argument_load',
+        3 => NULL,
+      ),
+      'menu-test/arguments/%/%/different-loaders-3' => array(
+        2 => NULL,
+        3 => NULL,
+      ),
+      // Explicit loader arguments should not be overriden by parent.
+      'menu-test/arguments/%/%/explicit-arguments' => array(
+        2 => array('menu_test_argument_load' => array()),
+        3 => NULL,
+      ),
+    );
+
+    foreach ($expected as $router_path => $load_functions) {
+      $router_item = $this->menuLoadRouter($router_path);
+      $this->assertIdentical(unserialize($router_item['load_functions']), $load_functions, t('Expected load functions for router %router_path' , array('%router_path' => $router_path)));
+    }
+  }
+}
+
+/**
+ * Tests for menu links.
+ */
+class MenuLinksUnitTestCase extends DrupalWebTestCase {
+  // Use the lightweight testing profile for this test.
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Menu links',
+      'description' => 'Test handling of menu links hierarchies.',
+      'group' => 'Menu',
+    );
+  }
+
+  /**
+   * Create a simple hierarchy of links.
+   */
+  function createLinkHierarchy($module = 'menu_test') {
+    // First remove all the menu links.
+    db_truncate('menu_links')->execute();
+
+    // Then create a simple link hierarchy:
+    // - $parent
+    //   - $child-1
+    //      - $child-1-1
+    //      - $child-1-2
+    //   - $child-2
+    $base_options = array(
+      'link_title' => 'Menu link test',
+      'module' => $module,
+      'menu_name' => 'menu_test',
+    );
+
+    $links['parent'] = $base_options + array(
+      'link_path' => 'menu-test/parent',
+    );
+    menu_link_save($links['parent']);
+
+    $links['child-1'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1',
+      'plid' => $links['parent']['mlid'],
+    );
+    menu_link_save($links['child-1']);
+
+    $links['child-1-1'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1/child-1-1',
+      'plid' => $links['child-1']['mlid'],
+    );
+    menu_link_save($links['child-1-1']);
+
+    $links['child-1-2'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1/child-1-2',
+      'plid' => $links['child-1']['mlid'],
+    );
+    menu_link_save($links['child-1-2']);
+
+    $links['child-2'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-2',
+      'plid' => $links['parent']['mlid'],
+    );
+    menu_link_save($links['child-2']);
+
+    return $links;
+  }
+
+  /**
+   * Assert that at set of links is properly parented.
+   */
+  function assertMenuLinkParents($links, $expected_hierarchy) {
+    foreach ($expected_hierarchy as $child => $parent) {
+      $mlid = $links[$child]['mlid'];
+      $plid = $parent ? $links[$parent]['mlid'] : 0;
+
+      $menu_link = menu_link_load($mlid);
+      menu_link_save($menu_link);
+      $this->assertEqual($menu_link['plid'], $plid, t('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid)));
+    }
+  }
+
+  /**
+   * Test automatic reparenting of menu links.
+   */
+  function testMenuLinkReparenting($module = 'menu_test') {
+    // Check the initial hierarchy.
+    $links = $this->createLinkHierarchy($module);
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'parent',
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, and move child-1 under child-2, and check that all the
+    // childs of child-1 have been moved too.
+    $links = $this->createLinkHierarchy($module);
+    $links['child-1']['plid'] = $links['child-2']['mlid'];
+    menu_link_save($links['child-1']);
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'child-2',
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, and delete child-1, and check that the children of child-1
+    // have been reassigned to the parent. menu_link_delete() will cowardly
+    // refuse to delete a menu link defined by the system module, so skip the
+    // test in that case.
+    if ($module != 'system') {
+      $links = $this->createLinkHierarchy($module);
+      menu_link_delete($links['child-1']['mlid']);
+
+      $expected_hierarchy = array(
+        'parent' => FALSE,
+        'child-1-1' => 'parent',
+        'child-1-2' => 'parent',
+        'child-2' => 'parent',
+      );
+      $this->assertMenuLinkParents($links, $expected_hierarchy);
+    }
+
+    // Start over, forcefully delete child-1 from the database, simulating a
+    // database crash. Check that the children of child-1 have been reassigned
+    // to the parent, going up on the old path hierarchy stored in each of the
+    // links.
+    $links = $this->createLinkHierarchy($module);
+    // Don't do that at home.
+    db_delete('menu_links')
+      ->condition('mlid', $links['child-1']['mlid'])
+      ->execute();
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1-1' => 'parent',
+      'child-1-2' => 'parent',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, forcefully delete the parent from the database, simulating a
+    // database crash. Check that the children of parent are now top-level.
+    $links = $this->createLinkHierarchy($module);
+    // Don't do that at home.
+    db_delete('menu_links')
+      ->condition('mlid', $links['parent']['mlid'])
+      ->execute();
+
+    $expected_hierarchy = array(
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => FALSE,
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+  }
+
+  /**
+   * Test automatic reparenting of menu links derived from menu routers.
+   */
+  function testMenuLinkRouterReparenting() {
+    // Run all the standard parenting tests on menu links derived from
+    // menu routers.
+    $this->testMenuLinkReparenting('system');
+
+    // Additionnaly, test reparenting based on path.
+    $links = $this->createLinkHierarchy('system');
+
+    // Move child-1-2 has a child of child-2, making the link hierarchy
+    // inconsistent with the path hierarchy.
+    $links['child-1-2']['plid'] = $links['child-2']['mlid'];
+    menu_link_save($links['child-1-2']);
+
+    // Check the new hierarchy.
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'parent',
+      'child-1-1' => 'child-1',
+      'child-2' => 'parent',
+      'child-1-2' => 'child-2',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Now delete 'parent' directly from the database, simulating a database
+    // crash. 'child-1' and 'child-2' should get moved to the
+    // top-level.
+    // Don't do that at home.
+    db_delete('menu_links')
+      ->condition('mlid', $links['parent']['mlid'])
+      ->execute();
+    $expected_hierarchy = array(
+      'child-1' => FALSE,
+      'child-1-1' => 'child-1',
+      'child-2' => FALSE,
+      'child-1-2' => 'child-2',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Now delete 'child-2' directly from the database, simulating a database
+    // crash. 'child-1-2' will get reparented under 'child-1' based on its
+    // path.
+    // Don't do that at home.
+    db_delete('menu_links')
+      ->condition('mlid', $links['child-2']['mlid'])
+      ->execute();
+    $expected_hierarchy = array(
+      'child-1' => FALSE,
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+  }
 }
 
 /**
@@ -576,6 +862,19 @@ class MenuBreadcrumbTestCase extends DrupalWebTestCase {
     $perms = array_keys(module_invoke_all('permission'));
     $this->admin_user = $this->drupalCreateUser($perms);
     $this->drupalLogin($this->admin_user);
+
+    // This test puts menu links in the Navigation menu and then tests for
+    // their presence on the page, so we need to ensure that the Navigation
+    // block will be displayed in all active themes.
+    db_update('block')
+      ->fields(array(
+        // Use a region that is valid for all themes.
+        'region' => 'content',
+        'status' => 1,
+      ))
+      ->condition('module', 'system')
+      ->condition('delta', 'navigation')
+      ->execute();
   }
 
   /**
diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info
index 6a3dcc2d98b20c97dfb5c8178fbd0a002b33b0ac..b41da9b479ee244d805f7b0830b63d6b03beac55 100644
--- a/modules/simpletest/tests/menu_test.info
+++ b/modules/simpletest/tests/menu_test.info
@@ -1,14 +1,13 @@
-; $Id: menu_test.info,v 1.1 2008/12/28 18:27:14 dries Exp $
+; $Id: menu_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Hook menu tests"
 description = "Support module for menu hook testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = menu_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module
index 3565e119e2168a585a6d109d346e3965dd5029fe..2230756ac843a20c1c3a9e224dcd6056a00376ed 100644
--- a/modules/simpletest/tests/menu_test.module
+++ b/modules/simpletest/tests/menu_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: menu_test.module,v 1.18 2010/10/15 04:46:59 webchick Exp $
+// $Id: menu_test.module,v 1.21 2010/12/02 17:34:24 webchick Exp $
 
 /**
  * @file
@@ -58,6 +58,11 @@ function menu_test_menu() {
     'page arguments' => array(TRUE),
     'access arguments' => array('access content'),
   );
+  $items['menu-test/no-theme-callback'] = array(
+    'title' => 'Page that displays different themes without using a theme callback.',
+    'page callback' => 'menu_test_theme_page_callback',
+    'access arguments' => array('access content'),
+  );
   // Path containing "exotic" characters.
   $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
     "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
@@ -255,9 +260,74 @@ function menu_test_menu() {
    'page callback' => 'menu_test_callback',
   );
 
+  // Load arguments inheritance test.
+  $items['menu-test/arguments/%menu_test_argument/%'] = array(
+    'title' => 'Load arguments inheritance test',
+    'load arguments' => array(3),
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  $items['menu-test/arguments/%menu_test_argument/%/default'] = array(
+    'title' => 'Default local task',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['menu-test/arguments/%menu_test_argument/%/task'] = array(
+    'title' => 'Local task',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+    'type' => MENU_LOCAL_TASK,
+  );
+  // For this path, load arguments should be inherited for the first loader only.
+  $items['menu-test/arguments/%menu_test_argument/%menu_test_other_argument/common-loader'] = array(
+    'title' => 'Local task',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+    'type' => MENU_LOCAL_TASK,
+  );
+  // For these paths, no load arguments should be inherited.
+  // Not on the same position.
+  $items['menu-test/arguments/%/%menu_test_argument/different-loaders-1'] = array(
+    'title' => 'An item not sharing the same loader',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  // Not the same loader.
+  $items['menu-test/arguments/%menu_test_other_argument/%/different-loaders-2'] = array(
+    'title' => 'An item not sharing the same loader',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  // Not the same loader.
+  $items['menu-test/arguments/%/%/different-loaders-3'] = array(
+    'title' => 'An item not sharing the same loader',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  // Explict load arguments should not be overriden (even if empty).
+  $items['menu-test/arguments/%menu_test_argument/%/explicit-arguments'] = array(
+    'title' => 'An item defining explicit load arguments',
+    'load arguments' => array(),
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+
   return $items;
 }
 
+/**
+ * Dummy argument loader for hook_menu() to point to.
+ */
+function menu_test_argument_load($arg1) {
+  return FALSE;
+}
+
+/**
+ * Dummy argument loader for hook_menu() to point to.
+ */
+function menu_test_other_argument_load($arg1) {
+  return FALSE;
+}
+
 /**
  * Dummy callback for hook_menu() to point to.
  *
diff --git a/modules/simpletest/tests/module.test b/modules/simpletest/tests/module.test
index 88b2a9426f052537fdf1fd15cb950433ebe1d717..7461a406b834e6afee1108a79cd061401213b8b6 100644
--- a/modules/simpletest/tests/module.test
+++ b/modules/simpletest/tests/module.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: module.test,v 1.23 2010/08/05 23:53:38 webchick Exp $
+// $Id: module.test,v 1.26 2010/11/27 20:41:38 dries Exp $
 
 /**
  * @file
@@ -111,28 +111,107 @@ class ModuleUnitTest extends DrupalWebTestCase {
     $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.');
   }
 
+  /**
+   * Test that module_invoke() can load a hook defined in hook_hook_info().
+   */
+  function testModuleInvoke() {
+    module_enable(array('module_test'), FALSE);
+    $this->resetAll();
+    $this->drupalGet('module-test/hook-dynamic-loading-invoke');
+    $this->assertText('success!', t('module_invoke() dynamically loads a hook defined in hook_hook_info().'));
+  }
+
+  /**
+   * Test that module_invoke_all() can load a hook defined in hook_hook_info().
+   */
+  function testModuleInvokeAll() {
+    module_enable(array('module_test'), FALSE);
+    $this->resetAll();
+    $this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
+    $this->assertText('success!', t('module_invoke_all() dynamically loads a hook defined in hook_hook_info().'));
+  }
+
   /**
    * Test dependency resolution.
    */
   function testDependencyResolution() {
+    // Enable the test module, and make sure that other modules we are testing
+    // are not already enabled. (If they were, the tests below would not work
+    // correctly.)
     module_enable(array('module_test'), FALSE);
     $this->assertTrue(module_exists('module_test'), t('Test module is enabled.'));
+    $this->assertFalse(module_exists('forum'), t('Forum module is disabled.'));
+    $this->assertFalse(module_exists('poll'), t('Poll module is disabled.'));
+    $this->assertFalse(module_exists('php'), t('PHP module is disabled.'));
 
     // First, create a fake missing dependency. Forum depends on poll, which
     // depends on a made-up module, foo. Nothing should be installed.
     variable_set('dependency_test', 'missing dependency');
+    drupal_static_reset('system_rebuild_module_data');
     $result = module_enable(array('forum'));
     $this->assertFalse($result, t('module_enable() returns FALSE if dependencies are missing.'));
     $this->assertFalse(module_exists('forum'), t('module_enable() aborts if dependencies are missing.'));
 
-    // Now, fix the missing dependency. module_enable() should work.
+    // Now, fix the missing dependency. Forum module depends on poll, but poll
+    // depends on the PHP module. module_enable() should work.
     variable_set('dependency_test', 'dependency');
+    drupal_static_reset('system_rebuild_module_data');
     $result = module_enable(array('forum'));
     $this->assertTrue($result, t('module_enable() returns the correct value.'));
     // Verify that the fake dependency chain was installed.
     $this->assertTrue(module_exists('poll') && module_exists('php'), t('Dependency chain was installed by module_enable().'));
-    // Finally, verify that the original module was installed.
+    // Verify that the original module was installed.
     $this->assertTrue(module_exists('forum'), t('Module installation with unlisted dependencies succeeded.'));
+    // Finally, verify that the modules were enabled in the correct order.
+    $this->assertEqual(variable_get('test_module_enable_order', array()), array('php', 'poll', 'forum'), t('Modules were enabled in the correct order by module_enable().'));
+
+    // Now, disable the PHP module. Both forum and poll should be disabled as
+    // well, in the correct order.
+    module_disable(array('php'));
+    $this->assertTrue(!module_exists('forum') && !module_exists('poll'), t('Depedency chain was disabled by module_disable().'));
+    $this->assertFalse(module_exists('php'), t('Disabling a module with unlisted dependents succeeded.'));
+    $this->assertEqual(variable_get('test_module_disable_order', array()), array('forum', 'poll', 'php'), t('Modules were disabled in the correct order by module_disable().'));
+
+    // Disable a module that is listed as a dependency by the install profile.
+    // Make sure that the profile itself is not on the list of dependent
+    // modules to be disabled.
+    $profile = drupal_get_profile();
+    $info = install_profile_info($profile);
+    $this->assertTrue(in_array('comment', $info['dependencies']), t('Comment module is listed as a dependency of the install profile.'));
+    $this->assertTrue(module_exists('comment'), t('Comment module is enabled.'));
+    module_disable(array('comment'));
+    $this->assertFalse(module_exists('comment'), t('Comment module was disabled.'));
+    $disabled_modules = variable_get('test_module_disable_order', array());
+    $this->assertTrue(in_array('comment', $disabled_modules), t('Comment module is in the list of disabled modules.'));
+    $this->assertFalse(in_array($profile, $disabled_modules), t('The installation profile is not in the list of disabled modules.'));
+
+    // Try to uninstall the PHP module by itself. This should be rejected,
+    // since the modules which it depends on need to be uninstalled first, and
+    // that is too destructive to perform automatically.
+    $result = drupal_uninstall_modules(array('php'));
+    $this->assertFalse($result, t('Calling drupal_uninstall_modules() on a module whose dependents are not uninstalled fails.'));
+    foreach (array('forum', 'poll', 'php') as $module) {
+      $this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, t('The @module module was not uninstalled.', array('@module' => $module)));
+    }
+
+    // Now uninstall all three modules explicitly, but in the incorrect order,
+    // and make sure that drupal_uninstal_modules() uninstalled them in the
+    // correct sequence.
+    $result = drupal_uninstall_modules(array('poll', 'php', 'forum'));
+    $this->assertTrue($result, t('drupal_uninstall_modules() returns the correct value.'));
+    foreach (array('forum', 'poll', 'php') as $module) {
+      $this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, t('The @module module was uninstalled.', array('@module' => $module)));
+    }
+    $this->assertEqual(variable_get('test_module_uninstall_order', array()), array('forum', 'poll', 'php'), t('Modules were uninstalled in the correct order by drupal_uninstall_modules().'));
+
+    // Uninstall the profile module from above, and make sure that the profile
+    // itself is not on the list of dependent modules to be uninstalled.
+    $result = drupal_uninstall_modules(array('comment'));
+    $this->assertTrue($result, t('drupal_uninstall_modules() returns the correct value.'));
+    $this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, t('Comment module was uninstalled.'));
+    $uninstalled_modules = variable_get('test_module_uninstall_order', array());
+    $this->assertTrue(in_array('comment', $uninstalled_modules), t('Comment module is in the list of uninstalled modules.'));
+    $this->assertFalse(in_array($profile, $uninstalled_modules), t('The installation profile is not in the list of uninstalled modules.'));
   }
 }
 
diff --git a/modules/simpletest/tests/module_test.file.inc b/modules/simpletest/tests/module_test.file.inc
index b148183639fe3c6d58d5bb202ee0eeb427829923..323edc06b68fe396310ec909d87d5c0a6f06ffe9 100644
--- a/modules/simpletest/tests/module_test.file.inc
+++ b/modules/simpletest/tests/module_test.file.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: module_test.file.inc,v 1.2 2010/05/26 19:51:01 dries Exp $
+// $Id: module_test.file.inc,v 1.3 2010/11/27 20:41:38 dries Exp $
 
 /**
  * @file
@@ -10,5 +10,5 @@
  * Implements hook_test_hook().
  */
 function module_test_test_hook() {
-
+  return array('module_test' => 'success!');
 }
diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info
index 9f7b6a2eab6708c0261ee6eb3f9f021ebf25ffc8..e67742f4913812a434d699abcffd8b0ce60c50fc 100644
--- a/modules/simpletest/tests/module_test.info
+++ b/modules/simpletest/tests/module_test.info
@@ -1,15 +1,13 @@
-; $Id: module_test.info,v 1.2 2010/04/22 18:56:31 dries Exp $
+; $Id: module_test.info,v 1.3 2010/12/20 19:59:43 webchick Exp $
 name = "Module test"
 description = "Support module for module system testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = module_test.module
-files[] = module_test.file.inc
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/module_test.module b/modules/simpletest/tests/module_test.module
index a379ce956a2b809294e193d400318c6f16a1f834..e25a701a449bb5ff5322fc400a5594bc6b649ee9 100644
--- a/modules/simpletest/tests/module_test.module
+++ b/modules/simpletest/tests/module_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: module_test.module,v 1.8 2010/10/05 00:22:24 webchick Exp $
+// $Id: module_test.module,v 1.10 2010/11/27 20:41:38 dries Exp $
 
 /**
  * Implements hook_permission().
@@ -51,9 +51,68 @@ function module_test_hook_info() {
   return $hooks;
 }
 
+/**
+ * Implements hook_menu().
+ */
+function module_test_menu() {
+  $items['module-test/hook-dynamic-loading-invoke'] = array(
+    'title' => 'Test hook dynamic loading (invoke)',
+    'page callback' => 'module_test_hook_dynamic_loading_invoke',
+    'access arguments' => array('access content'),
+  );
+  $items['module-test/hook-dynamic-loading-invoke-all'] = array(
+    'title' => 'Test hook dynamic loading (invoke_all)',
+    'page callback' => 'module_test_hook_dynamic_loading_invoke_all',
+    'access arguments' => array('access content'),
+  );
+  return $items;
+}
+
+/**
+ * Page callback for 'hook dynamic loading' test.
+ *
+ * If the hook is dynamically loaded correctly, the menu callback should
+ * return 'success!'.
+ */
+function module_test_hook_dynamic_loading_invoke() {
+  $result = module_invoke('module_test', 'test_hook');
+  return $result['module_test'];
+}
+
+/**
+ * Page callback for 'hook dynamic loading' test.
+ *
+ * If the hook is dynamically loaded correctly, the menu callback should
+ * return 'success!'.
+ */
+function module_test_hook_dynamic_loading_invoke_all() {
+  $result = module_invoke_all('test_hook');
+  return $result['module_test'];
+}
+
 /**
  * Implements hook_modules_enabled().
  */
 function module_test_modules_enabled($modules) {
+  // Record the ordered list of modules that were passed in to this hook so we
+  // can check that the modules were enabled in the correct sequence.
   variable_set('test_module_enable_order', $modules);
 }
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function module_test_modules_disabled($modules) {
+  // Record the ordered list of modules that were passed in to this hook so we
+  // can check that the modules were disabled in the correct sequence.
+  variable_set('test_module_disable_order', $modules);
+}
+
+/**
+ * Implements hook_modules_uninstalled().
+ */
+function module_test_modules_uninstalled($modules) {
+  // Record the ordered list of modules that were passed in to this hook so we
+  // can check that the modules were uninstalled in the correct sequence.
+  variable_set('test_module_uninstall_order', $modules);
+}
diff --git a/modules/simpletest/tests/password.test b/modules/simpletest/tests/password.test
new file mode 100644
index 0000000000000000000000000000000000000000..2250ac3da26726201a0517fd81d018ff9f2713a5
--- /dev/null
+++ b/modules/simpletest/tests/password.test
@@ -0,0 +1,61 @@
+<?php
+// $Id: password.test,v 1.1 2010/12/18 00:56:18 dries Exp $
+
+/**
+ * @file
+ * Provides unit tests for password.inc.
+ */
+
+/**
+ * Unit tests for password hashing API.
+ */
+class PasswordHashingTest extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Password hashing',
+      'description' => 'Password hashing unit tests.',
+      'group' => 'System',
+    );
+  }
+
+  function setUp() {
+    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
+    parent::setUp();
+  }
+
+  /**
+   * Test password hashing.
+   */
+  function testPasswordHashing() {
+    // Set a log2 iteration count that is deliberately out of bounds to test
+    // that it is corrected to be within bounds.
+    variable_set('password_count_log2', 1);
+    // Set up a fake $account with a password 'baz', hashed with md5.
+    $password = 'baz';
+    $account = (object) array('name' => 'foo', 'pass' => md5($password));
+    // The md5 password should be flagged as needing an update.
+    $this->assertTrue(user_needs_new_hash($account), t('User with md5 password needs a new hash.'));
+    // Re-hash the password.
+    $old_hash = $account->pass;
+    $account->pass = user_hash_password($password);
+    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT, t('Re-hashed password has the minimum number of log2 iterations.'));
+    $this->assertTrue($account->pass != $old_hash, t('Password hash changed.'));
+    $this->assertTrue(user_check_password($password, $account), t('Password check succeeds.'));
+    // Since the log2 setting hasn't changed and the user has a valid password,
+    // user_needs_new_hash() should return FALSE.
+    $this->assertFalse(user_needs_new_hash($account), t('User does not need a new hash.'));
+    // Increment the log2 iteration to MIN + 1.
+    variable_set('password_count_log2', DRUPAL_MIN_HASH_COUNT + 1);
+    $this->assertTrue(user_needs_new_hash($account), t('User needs a new hash after incrementing the log2 count.'));
+    // Re-hash the password.
+    $old_hash = $account->pass;
+    $account->pass = user_hash_password($password);
+    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT + 1, t('Re-hashed password has the correct number of log2 iterations.'));
+    $this->assertTrue($account->pass != $old_hash, t('Password hash changed again.'));
+    // Now the hash should be OK.
+    $this->assertFalse(user_needs_new_hash($account), t('Re-hashed password does not need a new hash.'));
+    $this->assertTrue(user_check_password($password, $account), t('Password check succeeds with re-hashed password.'));
+  }
+}
diff --git a/modules/simpletest/tests/path.test b/modules/simpletest/tests/path.test
index 56f5a7e3709d5a555d5a7709f3d2671446f628e4..efb96cc8623bad14cf5a2d10a734084741ce54d9 100644
--- a/modules/simpletest/tests/path.test
+++ b/modules/simpletest/tests/path.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: path.test,v 1.7 2010/08/05 23:53:38 webchick Exp $
+// $Id: path.test,v 1.8 2010/11/30 01:05:24 dries Exp $
 
 /**
  * @file
@@ -236,3 +236,93 @@ class UrlAlterFunctionalTest extends DrupalWebTestCase {
     $this->assertIdentical($result, $final, t('Altered inbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
   }
 }
+
+/**
+ * Unit test for drupal_lookup_path().
+ */
+class PathLookupTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Path lookup'),
+      'description' => t('Tests that drupal_lookup_path() returns correct paths.'),
+      'group' => t('Path API'),
+    );
+  }
+
+  /**
+   * Test that drupal_lookup_path() returns the correct path.
+   */
+  function testDrupalLookupPath() {
+    $account = $this->drupalCreateUser();
+    $uid = $account->uid;
+    $name = $account->name;
+
+    // Test the situation where the source is the same for multiple aliases.
+    // Start with a language-neutral alias, which we will override.
+    $path = array(
+      'source' => "user/$uid",
+      'alias' => 'foo',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], t('Basic alias lookup works.'));
+    $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('Basic source lookup works.'));
+
+    // Create a language specific alias for the default language (English).
+    $path = array(
+      'source' => "user/$uid",
+      'alias' => "users/$name",
+      'language' => 'en',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], t('English alias overrides language-neutral alias.'));
+    $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('English source overrides language-neutral source.'));
+
+    // Create a language-neutral alias for the same path, again.
+    $path = array(
+      'source' => "user/$uid",
+      'alias' => 'bar',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", t('English alias still returned after entering a language-neutral alias.'));
+
+    // Create a language-specific (xx-lolspeak) alias for the same path.
+    $path = array(
+      'source' => "user/$uid",
+      'alias' => 'LOL',
+      'language' => 'xx-lolspeak',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", t('English alias still returned after entering a LOLspeak alias.'));
+    // The LOLspeak alias should be returned if we really want LOLspeak.
+    $this->assertEqual(drupal_lookup_path('alias', $path['source'], 'xx-lolspeak'), 'LOL', t('LOLspeak alias returned if we specify xx-lolspeak to drupal_lookup_path().'));
+
+    // Create a new alias for this path in English, which should override the
+    // previous alias for "user/$uid".
+    $path = array(
+      'source' => "user/$uid",
+      'alias' => 'users/my-new-path',
+      'language' => 'en',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], t('Recently created English alias returned.'));
+    $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('Recently created English source returned.'));
+
+    // Remove the English aliases, which should cause a fallback to the most
+    // recently created language-neutral alias, 'bar'.
+    db_delete('url_alias')
+      ->condition('language', 'en')
+      ->execute();
+    drupal_clear_path_cache();
+    $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar', t('Path lookup falls back to recently created language-neutral alias.'));
+
+    // Test the situation where the alias and language are the same, but
+    // the source differs. The newer alias record should be returned.
+    $account2 = $this->drupalCreateUser();
+    $path = array(
+      'source' => 'user/' . $account2->uid,
+      'alias' => 'bar',
+    );
+    path_save($path);
+    $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.'));
+  }
+}
diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info
index e383c1a606ab362489ec2f9a148441b6c0fa342f..e98368a557e6ec0dee16ef76ad69c8cd27266a5b 100644
--- a/modules/simpletest/tests/requirements1_test.info
+++ b/modules/simpletest/tests/requirements1_test.info
@@ -1,15 +1,13 @@
-; $Id: requirements1_test.info,v 1.1 2010/05/26 07:31:46 dries Exp $
+; $Id: requirements1_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = Requirements 1 Test
 description = "Tests that a module is not installed when it fails hook_requirements('install')."
 package = Core
 version = VERSION
 core = 7.x
-files[] = requirements1_test.install
-files[] = requirements1_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/requirements2_test.info b/modules/simpletest/tests/requirements2_test.info
index d69a3114d177837a5f363b3c03d53e1096b5282d..a058fd4a38d348116a618a682bd232a7a84865f7 100644
--- a/modules/simpletest/tests/requirements2_test.info
+++ b/modules/simpletest/tests/requirements2_test.info
@@ -1,4 +1,4 @@
-; $Id: requirements2_test.info,v 1.1 2010/05/26 07:31:46 dries Exp $
+; $Id: requirements2_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = Requirements 2 Test
 description = "Tests that a module is not installed when the one it depends on fails hook_requirements('install)."
 dependencies[] = requirements1_test
@@ -6,11 +6,10 @@ dependencies[] = comment
 package = Core
 version = VERSION
 core = 7.x
-files[] = requirements2_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/schema.test b/modules/simpletest/tests/schema.test
index 34731f5830274d7f0c8e6216908e56c1d79b6ad5..f9baaac7e4cde1b4bd038263bdab1a74493a56fe 100644
--- a/modules/simpletest/tests/schema.test
+++ b/modules/simpletest/tests/schema.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: schema.test,v 1.23 2010/10/22 15:18:56 webchick Exp $
+// $Id: schema.test,v 1.24 2010/12/08 06:38:59 webchick Exp $
 
 /**
  * @file
@@ -10,6 +10,11 @@
  * Unit tests for the Schema API.
  */
 class SchemaTestCase extends DrupalWebTestCase {
+  /**
+   * A global counter for table and field creation.
+   */
+  var $counter;
+
   public static function getInfo() {
     return array(
       'name' => 'Schema API',
@@ -215,4 +220,166 @@ class SchemaTestCase extends DrupalWebTestCase {
       return FALSE;
     }
   }
+
+  /**
+   * Test adding columns to an existing table.
+   */
+  function testSchemaAddField() {
+    // Test varchar types.
+    foreach (array(1, 32, 128, 256, 512) as $length) {
+      $base_field_spec = array(
+        'type' => 'varchar',
+        'length' => $length,
+      );
+      $variations = array(
+        array('not null' => FALSE),
+        array('not null' => FALSE, 'default' => '7'),
+        array('not null' => TRUE, 'initial' => 'd'),
+        array('not null' => TRUE, 'initial' => 'd', 'default' => '7'),
+      );
+
+      foreach ($variations as $variation) {
+        $field_spec = $variation + $base_field_spec;
+        $this->assertFieldAdditionRemoval($field_spec);
+      }
+    }
+
+    // Test int and float types.
+    foreach (array('int', 'float') as $type) {
+      foreach (array('tiny', 'small', 'medium', 'normal', 'big') as $size) {
+        $base_field_spec = array(
+          'type' => $type,
+          'size' => $size,
+        );
+        $variations = array(
+          array('not null' => FALSE),
+          array('not null' => FALSE, 'default' => 7),
+          array('not null' => TRUE, 'initial' => 1),
+          array('not null' => TRUE, 'initial' => 1, 'default' => 7),
+        );
+
+        foreach ($variations as $variation) {
+          $field_spec = $variation + $base_field_spec;
+          $this->assertFieldAdditionRemoval($field_spec);
+        }
+      }
+    }
+
+    // Test numeric types.
+    foreach (array(1, 5, 10, 40, 65) as $precision) {
+      foreach (array(0, 2, 10, 30) as $scale) {
+        if ($precision <= $scale) {
+          // Precision must be smaller then scale.
+          continue;
+        }
+
+        $base_field_spec = array(
+          'type' => 'numeric',
+          'scale' => $scale,
+          'precision' => $precision,
+        );
+        $variations = array(
+          array('not null' => FALSE),
+          array('not null' => FALSE, 'default' => 7),
+          array('not null' => TRUE, 'initial' => 1),
+          array('not null' => TRUE, 'initial' => 1, 'default' => 7),
+        );
+
+        foreach ($variations as $variation) {
+          $field_spec = $variation + $base_field_spec;
+          $this->assertFieldAdditionRemoval($field_spec);
+        }
+      }
+    }
+  }
+
+  /**
+   * Assert that a given field can be added and removed from a table.
+   *
+   * The addition test covers both defining a field of a given specification
+   * when initially creating at table and extending an existing table.
+   *
+   * @param $field_spec
+   *   The schema specification of the field.
+   */
+  protected function assertFieldAdditionRemoval($field_spec) {
+    // Try creating the field on a new table.
+    $table_name = 'test_table_' . ($this->counter++);
+    $table_spec = array(
+      'fields' => array(
+        'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
+        'test_field' => $field_spec,
+      ),
+      'primary key' => array('serial_column'),
+    );
+    db_create_table($table_name, $table_spec);
+    $this->pass(t('Table %table created.', array('%table' => $table_name)));
+
+    // Check the characteristics of the field.
+    $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec);
+
+    // Clean-up.
+    db_drop_table($table_name);
+
+    // Try adding a field to an existing table.
+    $table_name = 'test_table_' . ($this->counter++);
+    $table_spec = array(
+      'fields' => array(
+        'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
+      ),
+      'primary key' => array('serial_column'),
+    );
+    db_create_table($table_name, $table_spec);
+    $this->pass(t('Table %table created.', array('%table' => $table_name)));
+
+    // Insert some rows to the table to test the handling of initial values.
+    for ($i = 0; $i < 3; $i++) {
+      db_insert($table_name)
+        ->useDefaults(array('serial_column'))
+        ->execute();
+    }
+
+    db_add_field($table_name, 'test_field', $field_spec);
+    $this->pass(t('Column %column created.', array('%column' => 'test_field')));
+
+    // Check the characteristics of the field.
+    $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec);
+
+    // Clean-up.
+    db_drop_field($table_name, 'test_field');
+    db_drop_table($table_name);
+  }
+
+  /**
+   * Assert that a newly added field has the correct characteristics.
+   */
+  protected function assertFieldCharacteristics($table_name, $field_name, $field_spec) {
+    // Check that the initial value has been registered.
+    if (isset($field_spec['initial'])) {
+      // There should be no row with a value different then $field_spec['initial'].
+      $count = db_select($table_name)
+        ->fields($table_name, array('serial_column'))
+        ->condition($field_name, $field_spec['initial'], '<>')
+        ->countQuery()
+        ->execute()
+        ->fetchField();
+      $this->assertEqual($count, 0, t('Initial values filled out.'));
+    }
+
+    // Check that the default value has been registered.
+    if (isset($field_spec['default'])) {
+      // Try inserting a row, and check the resulting value of the new column.
+      $id = db_insert($table_name)
+        ->useDefaults(array('serial_column'))
+        ->execute();
+      $field_value = db_select($table_name)
+        ->fields($table_name, array($field_name))
+        ->condition('serial_column', $id)
+        ->execute()
+        ->fetchField();
+      $this->assertEqual($field_value, $field_spec['default'], t('Default value registered.'));
+    }
+
+    db_drop_field($table_name, $field_name);
+  }
 }
diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test
index 7c0bec088004f3349c5245747de5be0ea70238a8..d947c51d9e1c593925eff776439c0a6528f5b781 100644
--- a/modules/simpletest/tests/session.test
+++ b/modules/simpletest/tests/session.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: session.test,v 1.33 2010/10/15 04:15:41 webchick Exp $
+// $Id: session.test,v 1.35 2010/11/13 17:40:09 webchick Exp $
 
 /**
  * @file
@@ -222,6 +222,30 @@ class SessionTestCase extends DrupalWebTestCase {
     $this->assertNotEqual($times5->timestamp, $times4->timestamp, t('Sessions table was updated.'));
   }
 
+  /**
+   * Test that empty session IDs are not allowed.
+   */
+  function testEmptySessionID() {
+    $user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($user);
+    $this->drupalGet('session-test/is-logged-in');
+    $this->assertResponse(200, t('User is logged in.'));
+
+    // Reset the sid in {sessions} to a blank string. This may exist in the
+    // wild in some cases, although we normally prevent it from happening.
+    db_query("UPDATE {sessions} SET sid = '' WHERE uid = :uid", array(':uid' => $user->uid));
+    // Send a blank sid in the session cookie, and the session should no longer
+    // be valid. Closing the curl handler will stop the previous session ID
+    // from persisting.
+    $this->curlClose();
+    $this->additionalCurlOptions[CURLOPT_COOKIE] = rawurlencode($this->session_name) . '=;';
+    $this->drupalGet('session-test/id-from-cookie');
+    $this->assertRaw("session_id:\n", t('Session ID is blank as sent from cookie header.'));
+    // Assert that we have an anonymous session now.
+    $this->drupalGet('session-test/is-logged-in');
+    $this->assertResponse(403, t('An empty session ID is not allowed.'));
+  }
+
   /**
    * Reset the cookie file so that it refers to the specified user.
    *
@@ -316,7 +340,7 @@ class SessionHttpsTestCase extends DrupalWebTestCase {
     // Check insecure cookie is not set.
     $this->assertFalse(isset($this->cookies[$insecure_session_name]));
     $ssid = $this->cookies[$secure_session_name]['value'];
-    $this->assertSessionIds('', $ssid, 'Session has NULL for SID and a correct secure SID.');
+    $this->assertSessionIds($ssid, $ssid, 'Session has a non-empty SID and a correct secure SID.');
     $cookie = $secure_session_name . '=' . $ssid;
 
     // Verify that user is logged in on secure URL.
@@ -326,12 +350,36 @@ class SessionHttpsTestCase extends DrupalWebTestCase {
     $this->assertResponse(200);
 
     // Verify that user is not logged in on non-secure URL.
-    if (!$is_https) {
-      $this->curlClose();
-      $this->drupalGet('admin/config', array(), array('Cookie: ' . $cookie));
-      $this->assertNoText(t('Configuration'));
-      $this->assertResponse(403);
-    }
+    $this->curlClose();
+    $this->drupalGet($this->httpUrl('admin/config'), array(), array('Cookie: ' . $cookie));
+    $this->assertNoText(t('Configuration'));
+    $this->assertResponse(403);
+
+    // Verify that empty SID cannot be used on the non-secure site.
+    $this->curlClose();
+    $cookie = $insecure_session_name . '=';
+    $this->drupalGet($this->httpUrl('admin/config'), array(), array('Cookie: ' . $cookie));
+    $this->assertResponse(403);
+
+    // Test HTTP session handling by altering the form action to submit the
+    // login form through http.php, which creates a mock HTTP request on HTTPS
+    // test environments.
+    $this->curlClose();
+    $this->drupalGet('user');
+    $form = $this->xpath('//form[@id="user-login"]');
+    $form[0]['action'] = $this->httpUrl('user');
+    $edit = array('name' => $user->name, 'pass' => $user->pass_raw);
+    $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->drupalGet($this->httpUrl('admin/config'));
+    $this->assertResponse(200);
+    $sid = $this->cookies[$insecure_session_name]['value'];
+    $this->assertSessionIds($sid, '', 'Session has the correct SID and an empty secure SID.');
+
+    // Verify that empty secure SID cannot be used on the secure site.
+    $this->curlClose();
+    $cookie = $secure_session_name . '=';
+    $this->drupalGet($this->httpsUrl('admin/config'), array(), array('Cookie: ' . $cookie));
+    $this->assertResponse(403);
 
     // Clear browser cookie jar.
     $this->cookies = array();
@@ -458,9 +506,32 @@ class SessionHttpsTestCase extends DrupalWebTestCase {
     return $this->assertTrue(db_query('SELECT timestamp FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), $assertion_text);
   }
 
+  /**
+   * Builds a URL for submitting a mock HTTPS request to HTTP test environments.
+   *
+   * @param $url
+   *   A Drupal path such as 'user'.
+   *
+   * @return
+   *   An absolute URL.
+   */
   protected function httpsUrl($url) {
     global $base_url;
     return $base_url . '/modules/simpletest/tests/https.php?q=' . $url;
   }
+
+  /**
+   * Builds a URL for submitting a mock HTTP request to HTTPS test environments.
+   *
+   * @param $url
+   *   A Drupal path such as 'user'.
+   *
+   * @return
+   *   An absolute URL.
+   */
+  protected function httpUrl($url) {
+    global $base_url;
+    return $base_url . '/modules/simpletest/tests/http.php?q=' . $url;
+  }
 }
 
diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info
index e010c0f9fdbc9b6c765f979632390bce7c295f47..6f7c5305094f0bbfaa2cab5cbe9b9071ac50c5c3 100644
--- a/modules/simpletest/tests/session_test.info
+++ b/modules/simpletest/tests/session_test.info
@@ -1,14 +1,13 @@
-; $Id: session_test.info,v 1.1 2008/08/16 21:11:02 dries Exp $
+; $Id: session_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Session test"
 description = "Support module for session data testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = session_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/session_test.module b/modules/simpletest/tests/session_test.module
index b61616c3ce1f020cc8fbdbe26cc59188b61e6c38..62b3fbbe05ae741789a170d6a7da2c75c0824cd8 100644
--- a/modules/simpletest/tests/session_test.module
+++ b/modules/simpletest/tests/session_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: session_test.module,v 1.15 2009/12/04 16:49:47 dries Exp $
+// $Id: session_test.module,v 1.16 2010/11/13 17:40:09 webchick Exp $
 
 /**
  * Implements hook_menu().
@@ -17,6 +17,12 @@ function session_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['session-test/id-from-cookie'] = array(
+    'title' => 'Session ID from cookie',
+    'page callback' => '_session_test_id_from_cookie',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['session-test/set/%'] = array(
     'title' => 'Set session value',
     'page callback' => '_session_test_set',
@@ -49,6 +55,12 @@ function session_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['session-test/is-logged-in'] = array(
+    'title' => 'Check if user is logged in',
+    'page callback' => '_session_test_is_logged_in',
+    'access callback' => 'user_is_logged_in',
+    'type' => MENU_CALLBACK,
+  );
 
   return $items;
 }
@@ -103,6 +115,13 @@ function _session_test_id() {
   return 'session_id:' . session_id() . "\n";
 }
 
+/**
+ * Menu callback: print the current session ID as read from the cookie.
+ */
+function _session_test_id_from_cookie() {
+  return 'session_id:' . $_COOKIE[session_name()] . "\n";
+}
+
 /**
  * Menu callback, sets a message to me displayed on the following page.
  */
@@ -165,3 +184,10 @@ function session_test_drupal_goto_alter(&$path, &$options, &$http_response_code)
     $path = $base_insecure_url . '/' . $path;
   }
 }
+
+/**
+ * Menu callback, only available if current user is logged in.
+ */
+function _session_test_is_logged_in() {
+  return t('User is logged in.');
+}
diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info
index d2e3fe3a97fab0b2da1f0f466c226fbed3f492fe..141ca63649058da9a2b16cfb8e3402d6943a4bf3 100644
--- a/modules/simpletest/tests/system_dependencies_test.info
+++ b/modules/simpletest/tests/system_dependencies_test.info
@@ -1,15 +1,14 @@
-; $Id: system_dependencies_test.info,v 1.1 2009/12/08 06:39:34 webchick Exp $
+; $Id: system_dependencies_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "System dependency test"
 description = "Support module for testing system dependencies."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = system_dependencies_test.module
 hidden = TRUE
 dependencies[] = _missing_dependency
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/system_test.info b/modules/simpletest/tests/system_test.info
index 9dc6081027b06d2bf31ee795b3efb0ae501dc5ac..02ce4a1163ed6f92edac73026f0590fd4cbd2c5b 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-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/system_test.module b/modules/simpletest/tests/system_test.module
index f7833c45f859a34e1edef624b2c8bd75701919d6..583a5b70bb4829b9a818a1b85954e428aa86c66e 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.32 2010/08/01 23:35:01 dries Exp $
+// $Id: system_test.module,v 1.33 2010/12/01 00:23:36 webchick Exp $
 
 /**
  * Implements hook_menu().
@@ -16,6 +16,12 @@ function system_test_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
+  $items['system-test/authorize-init/%'] = array(
+    'page callback' => 'system_test_authorize_init_page',
+    'page arguments' => array(2),
+    'access arguments' => array('administer software updates'),
+    'type' => MENU_CALLBACK,
+  );
   $items['system-test/redirect/%'] = array(
     'title' => 'Redirect',
     'page callback' => 'system_test_redirect',
@@ -311,3 +317,45 @@ function _system_test_second_shutdown_function($arg1, $arg2) {
   throw new Exception('Drupal is <blink>awesome</blink>.');
 }
 
+/**
+ * Implements hook_filetransfer_info().
+ */
+function system_test_filetransfer_info() {
+  return array(
+    'system_test' => array(
+      'title' => t('System Test FileTransfer'),
+      'file' => 'system_test.module',  // Should be a .inc, but for test, ok.
+      'class' => 'SystemTestFileTransfer',
+      'weight' => -10,
+    ),
+  );
+}
+
+/**
+ * Mock FileTransfer object to test the settings form functionality.
+ */
+class SystemTestFileTransfer {
+  public static function factory() {
+    return new SystemTestFileTransfer;
+  }
+
+  public function getSettingsForm() {
+    $form = array();
+    $form['system_test_username'] = array(
+      '#type' => 'textfield',
+      '#title' => t('System Test Username'),
+    );
+    return $form;
+  }
+}
+
+/**
+ * Page callback to initialize authorize.php during testing.
+ *
+ * @see system_authorized_init().
+ */
+function system_test_authorize_init_page($page_title) {
+  $authorize_url = $GLOBALS['base_url'] . '/authorize.php';
+  system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
+  drupal_goto($authorize_url);
+}
diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info
index 85334834d15b8e11d9d0b8983fe2ddd012cdd284..e0b0fd8d4d65b30a77af597df6b1c3a2740569cb 100644
--- a/modules/simpletest/tests/taxonomy_test.info
+++ b/modules/simpletest/tests/taxonomy_test.info
@@ -1,15 +1,14 @@
-; $Id: taxonomy_test.info,v 1.3 2009/04/05 12:21:12 dries Exp $
+; $Id: taxonomy_test.info,v 1.4 2010/12/20 19:59:43 webchick Exp $
 name = "Taxonomy test module"
 description = "Tests functions and hooks not used in core".
 package = Testing
 version = VERSION
 core = 7.x
-files[] = taxonomy_test.module
 hidden = TRUE
 dependencies[] = taxonomy
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index 09e03d4517aa9653995e5efe0c908c08a2da4eb0..9e2f38775265d41e8b62c7ef5cb86477d6efcc9d 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: theme.test,v 1.22 2010/10/06 13:38:40 dries Exp $
+// $Id: theme.test,v 1.23 2010/11/14 21:04:45 webchick Exp $
 
 /**
  * @file
@@ -187,6 +187,117 @@ class ThemeItemListUnitTest extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Unit tests for theme_links().
+ */
+class ThemeLinksUnitTest extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Links',
+      'description' => 'Test the theme_links() function and rendering groups of links.',
+      'group' => 'Theme',
+    );
+  }
+
+  /**
+   * Test the use of drupal_pre_render_links() on a nested array of links.
+   */
+  function testDrupalPreRenderLinks() {
+    // Define the base array to be rendered, containing a variety of different
+    // kinds of links.
+    $base_array = array(
+      '#theme' => 'links',
+      '#pre_render' => array('drupal_pre_render_links'),
+      '#links' => array(
+        'parent_link' => array(
+          'title' => 'Parent link original',
+          'href' => 'parent-link-original',
+        ),
+      ),
+      'first_child' => array(
+        '#theme' => 'links',
+        '#links' => array(
+          // This should be rendered if 'first_child' is rendered separately,
+          // but ignored if the parent is being rendered (since it duplicates
+          // one of the parent's links).
+          'parent_link' => array(
+            'title' => 'Parent link copy',
+            'href' => 'parent-link-copy',
+          ),
+          // This should always be rendered.
+          'first_child_link' => array(
+            'title' => 'First child link',
+            'href' => 'first-child-link',
+          ),
+        ),
+      ),
+      // This should always be rendered as part of the parent.
+      'second_child' => array(
+        '#theme' => 'links',
+        '#links' => array(
+          'second_child_link' => array(
+            'title' => 'Second child link',
+            'href' => 'second-child-link',
+          ),
+        ),
+      ),
+      // This should never be rendered, since the user does not have access to
+      // it.
+      'third_child' => array(
+        '#theme' => 'links',
+        '#links' => array(
+          'third_child_link' => array(
+            'title' => 'Third child link',
+            'href' => 'third-child-link',
+          ),
+        ),
+        '#access' => FALSE,
+      ),
+    );
+
+    // Start with a fresh copy of the base array, and try rendering the entire
+    // thing. We expect a single <ul> with appropriate links contained within
+    // it.
+    $render_array = $base_array;
+    $html = drupal_render($render_array);
+    $dom = new DOMDocument();
+    $dom->loadHTML($html);
+    $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, t('One "ul" tag found in the rendered HTML.'));
+    $list_elements = $dom->getElementsByTagName('li');
+    $this->assertEqual($list_elements->length, 3, t('Three "li" tags found in the rendered HTML.'));
+    $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link original', t('First expected link found.'));
+    $this->assertEqual($list_elements->item(1)->nodeValue, 'First child link', t('Second expected link found.'));
+    $this->assertEqual($list_elements->item(2)->nodeValue, 'Second child link', t('Third expected link found.'));
+    $this->assertIdentical(strpos($html, 'Parent link copy'), FALSE, t('"Parent link copy" link not found.'));
+    $this->assertIdentical(strpos($html, 'Third child link'), FALSE, t('"Third child link" link not found.'));
+
+    // Now render 'first_child', followed by the rest of the links, and make
+    // sure we get two separate <ul>'s with the appropriate links contained
+    // within each.
+    $render_array = $base_array;
+    $child_html = drupal_render($render_array['first_child']);
+    $parent_html = drupal_render($render_array);
+    // First check the child HTML.
+    $dom = new DOMDocument();
+    $dom->loadHTML($child_html);
+    $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, t('One "ul" tag found in the rendered child HTML.'));
+    $list_elements = $dom->getElementsByTagName('li');
+    $this->assertEqual($list_elements->length, 2, t('Two "li" tags found in the rendered child HTML.'));
+    $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link copy', t('First expected link found.'));
+    $this->assertEqual($list_elements->item(1)->nodeValue, 'First child link', t('Second expected link found.'));
+    // Then check the parent HTML.
+    $dom = new DOMDocument();
+    $dom->loadHTML($parent_html);
+    $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, t('One "ul" tag found in the rendered parent HTML.'));
+    $list_elements = $dom->getElementsByTagName('li');
+    $this->assertEqual($list_elements->length, 2, t('Two "li" tags found in the rendered parent HTML.'));
+    $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link original', t('First expected link found.'));
+    $this->assertEqual($list_elements->item(1)->nodeValue, 'Second child link', t('Second expected link found.'));
+    $this->assertIdentical(strpos($parent_html, 'First child link'), FALSE, t('"First child link" link not found.'));
+    $this->assertIdentical(strpos($parent_html, 'Third child link'), FALSE, t('"Third child link" link not found.'));
+  }
+}
+
 /**
  * Functional test for initialization of the theme system in hook_init().
  */
diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info
index ddcbd56ef683850619e63b78fa2c592e3fd6913f..0a790f2a3f43115db089640418b4fa2388be6e1f 100644
--- a/modules/simpletest/tests/theme_test.info
+++ b/modules/simpletest/tests/theme_test.info
@@ -1,14 +1,13 @@
-; $Id: theme_test.info,v 1.1 2010/03/21 04:05:24 webchick Exp $
+; $Id: theme_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Theme test"
 description = "Support module for theme system testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = theme_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info
index 9e039b5379dbac9c25d4ffee0bb22a16a82470a3..ab67ad647a51ef363bfaf6d2f6549d8860bba6b0 100644
--- a/modules/simpletest/tests/update_test_1.info
+++ b/modules/simpletest/tests/update_test_1.info
@@ -1,15 +1,13 @@
-; $Id: update_test_1.info,v 1.1 2010/02/03 18:16:23 webchick Exp $
+; $Id: update_test_1.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Update test"
 description = "Support module for update testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = update_test_1.module
-files[] = update_test_1.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info
index ce44fb02fe3b52d988a26ec75fceb2257b3343d5..78ce4b6f8de9ff3116fbffcadbfd0472372f254c 100644
--- a/modules/simpletest/tests/update_test_2.info
+++ b/modules/simpletest/tests/update_test_2.info
@@ -1,15 +1,13 @@
-; $Id: update_test_2.info,v 1.1 2010/02/03 18:16:23 webchick Exp $
+; $Id: update_test_2.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Update test"
 description = "Support module for update testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = update_test_2.module
-files[] = update_test_2.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info
index 6cc3ac95e7022afbe38e7f84197811157a5a05f6..23d71ba4edee784b179a00051eef4fd9d2aab6ff 100644
--- a/modules/simpletest/tests/update_test_3.info
+++ b/modules/simpletest/tests/update_test_3.info
@@ -1,15 +1,13 @@
-; $Id: update_test_3.info,v 1.1 2010/02/03 18:16:23 webchick Exp $
+; $Id: update_test_3.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Update test"
 description = "Support module for update testing."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = update_test_3.module
-files[] = update_test_3.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/upgrade/drupal-6.filled.database.php b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
index 1a0f4643e04ee7167bcbbad0f6c6c88de418869a..5fd96f1fde7e879055d105d1a9c4e31826de330c 100644
--- a/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
+++ b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: drupal-6.filled.database.php,v 1.4 2010/10/04 14:51:16 webchick Exp $
+// $Id: drupal-6.filled.database.php,v 1.6 2010/12/30 03:44:39 webchick Exp $
 
 /**
  * @file
@@ -1034,6 +1034,12 @@ db_insert('filter_formats')->fields(array(
   'roles' => '',
   'cache' => '1',
 ))
+->values(array(
+  'format' => '3',
+  'name' => 'Escape HTML Filter',
+  'roles' => '',
+  'cache' => '1',
+))
 ->execute();
 
 db_create_table('filters', array(
@@ -19735,12 +19741,26 @@ db_insert('variable')->fields(array(
 ))
 ->values(array(
   'name' => 'file_directory_temp',
-  'value' => 's:26:"/Applications/MAMP/tmp/php";',
+  'value' => 's:29:"/drupal-6/file/directory/temp";',
+))
+->values(array(
+  'name' => 'file_directory_path',
+  'value' => 's:29:"/drupal-6/file/directory/path";',
+))
+->values(array(
+  'name' => 'file_downloads',
+  'value' => 'i:2;',
 ))
 ->values(array(
   'name' => 'filter_html_1',
   'value' => 'i:1;',
 ))
+// Add the Escape HTML filter to the custom input format 'Escape HTML Filter'
+// to test that the filter may be upgraded to its Drupal 7 equivalent.
+->values(array(
+  'name' => 'filter_html_3',
+  'value' => 'i:2;',
+))
 ->values(array(
   'name' => 'install_profile',
   'value' => 's:7:"default";',
diff --git a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
index 68ea00a4d4172193d2d4b674444e8416740db6ef..ef72861cbd39b27873f37db0aa180b5f3b308262 100644
--- a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
+++ b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: drupal-6.upload.database.php,v 1.1 2010/10/03 23:19:52 webchick Exp $
+// $Id: drupal-6.upload.database.php,v 1.2 2010/11/13 01:48:14 dries Exp $
 
 db_insert('files')->fields(array(
   'fid',
@@ -11,6 +11,10 @@ db_insert('files')->fields(array(
   'status',
   'timestamp',
 ))
+/*
+ * This entry is deliberately omitted to test the upgrade routine when facing
+ * possible data corruption.
+ *
 ->values(array(
   'fid' => '1',
   'uid' => '1',
@@ -20,7 +24,7 @@ db_insert('files')->fields(array(
   'filesize' => '1011',
   'status' => '1',
   'timestamp' => '1285700240',
-))
+)) */
 ->values(array(
   'fid' => '2',
   'uid' => '1',
@@ -132,14 +136,14 @@ db_insert('node')->fields(array(
 ))
 ->values(array(
   'nid' => '38',
-  'vid' => '51',
+  'vid' => '50',
   'type' => 'page',
   'language' => '',
-  'title' => 'node title 38 revision 51',
+  'title' => 'node title 38 revision 50',
   'uid' => '1',
   'status' => '1',
-  'created' => '1285700317',
-  'changed' => '1285700600',
+  'created' => '1285603317',
+  'changed' => '1285603317',
   'comment' => '0',
   'promote' => '0',
   'moderate' => '0',
@@ -152,7 +156,24 @@ db_insert('node')->fields(array(
   'vid' => '52',
   'type' => 'page',
   'language' => '',
-  'title' => 'node title 39 revision 53',
+  'title' => 'node title 39 revision 52',
+  'uid' => '1',
+  'status' => '1',
+  'created' => '1285700317',
+  'changed' => '1285700600',
+  'comment' => '0',
+  'promote' => '0',
+  'moderate' => '0',
+  'sticky' => '0',
+  'tnid' => '0',
+  'translate' => '0',
+))
+->values(array(
+  'nid' => '40',
+  'vid' => '53',
+  'type' => 'page',
+  'language' => '',
+  'title' => 'node title 40 revision 53',
   'uid' => '1',
   'status' => '1',
   'created' => '1285709012',
@@ -182,6 +203,17 @@ db_insert('node_revisions')->fields(array(
   'vid' => '50',
   'uid' => '1',
   'title' => 'node title 38 revision 50',
+  'body' => "Attachments:\r\npowered-blue-80x15.png",
+  'teaser' => "Attachments:\r\npowered-blue-80x15.png",
+  'log' => '',
+  'timestamp' => '1285603317',
+  'format' => '1',
+))
+->values(array(
+  'nid' => '39',
+  'vid' => '51',
+  'uid' => '1',
+  'title' => 'node title 39 revision 51',
   'body' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
   'teaser' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
   'log' => '',
@@ -189,10 +221,10 @@ db_insert('node_revisions')->fields(array(
   'format' => '1',
 ))
 ->values(array(
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'uid' => '1',
-  'title' => 'node title 38 revision 51',
+  'title' => 'node title 39 revision 52',
   'body' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
   'teaser' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
   'log' => '',
@@ -200,10 +232,10 @@ db_insert('node_revisions')->fields(array(
   'format' => '1',
 ))
 ->values(array(
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'uid' => '1',
-  'title' => 'node title 39 revision 53',
+  'title' => 'node title 40 revision 53',
   'body' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
   'teaser' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
   'log' => '',
@@ -276,81 +308,89 @@ db_insert('upload')->fields(array(
   'weight',
 ))
 ->values(array(
-  'fid' => '2',
+  'fid' => '1',
   'nid' => '38',
   'vid' => '50',
   'description' => 'powered-blue-80x15.png',
   'list' => '1',
   'weight' => '0',
 ))
+->values(array(
+  'fid' => '2',
+  'nid' => '39',
+  'vid' => '51',
+  'description' => 'powered-blue-80x15.png',
+  'list' => '1',
+  'weight' => '0',
+))
 ->values(array(
   'fid' => '3',
-  'nid' => '38',
-  'vid' => '50',
+  'nid' => '39',
+  'vid' => '51',
   'description' => 'powered-blue-88x31.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '4',
-  'nid' => '38',
-  'vid' => '50',
+  'nid' => '39',
+  'vid' => '51',
   'description' => 'powered-blue-135x42.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '3',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-blue-88x31.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '5',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-black-80x15.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '6',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-black-135x42.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '7',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-hot-new.png',
   'list' => '1',
   'weight' => '-4',
 ))
 ->values(array(
   'fid' => '8',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-hot.png',
   'list' => '1',
   'weight' => '-3',
 ))
 ->values(array(
   'fid' => '10',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-sticky.png',
   'list' => '1',
   'weight' => '-2',
 ))
 ->values(array(
   'fid' => '9',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-new.png',
   'list' => '1',
   'weight' => '-1',
diff --git a/modules/simpletest/tests/upgrade/upgrade.filter.test b/modules/simpletest/tests/upgrade/upgrade.filter.test
new file mode 100644
index 0000000000000000000000000000000000000000..e63fddb64ed02dcafc86dae18701c1952f765b16
--- /dev/null
+++ b/modules/simpletest/tests/upgrade/upgrade.filter.test
@@ -0,0 +1,56 @@
+<?php
+// $Id: upgrade.filter.test,v 1.1 2010/11/09 17:43:10 webchick Exp $
+
+/**
+ * Upgrade test for filter format identifiers.
+ *
+ * Filter format identifiers changed from sequential ids to machine names.
+ * Verify that filter formats and references to filter formats in core are
+ * converted properly.
+ */
+class FilterFormatUpgradePathTestCase extends UpgradePathTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Filter format upgrade path',
+      'description' => 'Verifies that filter formats and references to filter formats are converted properly.',
+      'group' => 'Upgrade path',
+    );
+  }
+
+  function setUp() {
+    // Path to the database dump.
+    $this->databaseDumpFiles = array(
+      drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.filled.database.php',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Test a successful upgrade.
+   */
+  function testFilterFormatUpgrade() {
+    $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.'));
+
+    $format = filter_format_load('1');
+    $this->assertTrue($format->format == '1', t('Filter format found.'));
+    $format->format = 'test_filter';
+    $format->name = 'Test filter';
+    filter_format_save($format);
+    $format = filter_format_load('test_filter');
+    $this->assertTrue($format->format == 'test_filter', t('Saved a filter format with machine name.'));
+
+    $account = user_load(4);
+    user_save($account, array('signature_format' => 'test_filter'));
+    $account = user_load(4);
+    $this->assertTrue($account->signature_format == 'test_filter', t('Signature format changed successfully to a filter format with machine name.'));
+
+    $delta = db_insert('block_custom')
+      ->fields(array(
+        'body' => 'Test block',
+        'info' => 'Test block',
+        'format' => 'test_filter',
+      ))
+      ->execute();
+    $this->assertTrue($delta > 0, t('Created a custom block using a filter format with machine name.'));
+  }
+}
diff --git a/modules/simpletest/tests/upgrade/upgrade.node.test b/modules/simpletest/tests/upgrade/upgrade.node.test
index d5d03b11c62c8a54610407470f78dcb46b46e208..2b79579ddd6426fe13cbebfcf292ad06d363a8fb 100644
--- a/modules/simpletest/tests/upgrade/upgrade.node.test
+++ b/modules/simpletest/tests/upgrade/upgrade.node.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: upgrade.node.test,v 1.3 2010/10/01 22:03:29 webchick Exp $
+// $Id: upgrade.node.test,v 1.4 2010/12/18 02:04:36 dries Exp $
 
 /**
  * Upgrade test for node bodies.
@@ -39,6 +39,10 @@ class NodeBodyUpgradePathTestCase extends UpgradePathTestCase {
     $revision = db_query_range("SELECT r.nid, r.vid FROM {node_revision} r JOIN {node} n ON n.nid = r.nid WHERE n.status = 0 AND n.type <> 'poll' AND n.vid <> r.vid", 0, 1)->fetch();
     $revision = node_load($revision->nid, $revision->vid);
     $this->assertTrue(!empty($revision->body), 'Unpublished non-current node revisions still have a node body.');
+
+    // Check that fields created during the upgrade can be edited and resaved
+    // in the UI.
+    $this->drupalPost('admin/structure/types/manage/story/fields/body', array(), t('Save settings'));
   }
 }
 
diff --git a/modules/simpletest/tests/upgrade/upgrade.test b/modules/simpletest/tests/upgrade/upgrade.test
index b72e91fadc90702927a620dbaae075a8f45dc5a9..4738e5d3a6f2976d7186652e7598f96c0e525393 100644
--- a/modules/simpletest/tests/upgrade/upgrade.test
+++ b/modules/simpletest/tests/upgrade/upgrade.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: upgrade.test,v 1.9 2010/10/08 18:19:11 webchick Exp $
+// $Id: upgrade.test,v 1.12 2010/12/28 21:46:23 webchick Exp $
 
 /**
  * Perform end-to-end tests of the upgrade path.
@@ -34,6 +34,9 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase {
   protected function setUp() {
     global $user, $language, $conf;
 
+    // Load the Update API.
+    require_once DRUPAL_ROOT . '/includes/update.inc';
+
     // Reset flags.
     $this->upgradedSite = FALSE;
     $this->upgradeErrors = array();
@@ -106,14 +109,20 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase {
     drupal_save_session(FALSE);
     $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject();
 
-    // Generate and set a session cookie.
+    // Generate and set a D6-compatible session cookie.
     $this->curlInitialize();
     $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
-    curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode($this->session_name) . '=' . rawurlencode($sid));
+    $session_name = update_get_d6_session_name();
+    curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode($session_name) . '=' . rawurlencode($sid));
 
     // Force our way into the session of the child site.
     drupal_save_session(TRUE);
+    // A session cannot be written without the ssid column which is missing on
+    // Drupal 6 sites.
+    db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
     _drupal_session_write($sid, '');
+    // Remove the temporarily added ssid column.
+    db_drop_field('sessions', 'ssid');
     drupal_save_session(FALSE);
 
     // Restore necessary variables.
@@ -369,6 +378,15 @@ class BasicUpgradePath extends UpgradePathTestCase {
       'pass_raw' => 'admin',
     ));
 
+    // The previous login should've triggered a password rehash, so login one
+    // more time to make sure the new hash is readable.
+    $this->drupalLogout();
+    $this->drupalLogin((object) array(
+      'uid' => 1,
+      'name' => 'admin',
+      'pass_raw' => 'admin',
+    ));
+
     // Test that the site name is correctly displayed.
     $this->assertText('Drupal 6', t('The site name is correctly displayed.'));
 
diff --git a/modules/simpletest/tests/upgrade/upgrade.upload.test b/modules/simpletest/tests/upgrade/upgrade.upload.test
index a758420328034ef551ba3a189cff94159500e083..dd02d3abbc14bd3e17180ef7edfca1ceb608c291 100644
--- a/modules/simpletest/tests/upgrade/upgrade.upload.test
+++ b/modules/simpletest/tests/upgrade/upgrade.upload.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: upgrade.upload.test,v 1.1 2010/10/03 23:19:52 webchick Exp $
+// $Id: upgrade.upload.test,v 1.3 2010/11/21 20:35:10 webchick Exp $
 
 /**
  * Upgrade test for comment.module.
@@ -20,6 +20,8 @@ class UploadUpgradePathTestCase extends UpgradePathTestCase {
       drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.upload.database.php',
     );
     parent::setUp();
+    // Set a small batch size to test multiple iterations of the batch.
+    $this->variable_set('upload_update_batch_size', 2);
 
     $this->uninstallModulesExcept(array('upload'));
   }
@@ -36,8 +38,11 @@ class UploadUpgradePathTestCase extends UpgradePathTestCase {
     $query->fieldCondition('upload');
     $entities = $query->execute();
     $revisions = $entities['node'];
-    // Node revisions 50-52 should have uploaded files.
-    $this->assertTrue((isset($revisions[50]) && isset($revisions[51]) && isset($revisions[52])), 'Nodes with uploaded files now contain filefield data.');
+    // Node revision 50 should not have uploaded files, as the entry in {files}
+    // is corrupted.
+    $this->assertFalse((isset($revisions[50])), 'Nodes with missing files do not contain filefield data.');
+    // Node revisions 51-53 should have uploaded files.
+    $this->assertTrue((isset($revisions[51]) && isset($revisions[52]) && isset($revisions[53])), 'Nodes with uploaded files now contain filefield data.');
     // The test database lists uploaded filenames in the body of each node with
     // uploaded files attached. Make sure all files are there in the same order.
     foreach ($revisions as $vid => $revision) {
@@ -58,9 +63,16 @@ class UploadUpgradePathTestCase extends UpgradePathTestCase {
       foreach ($files as $file) {
         $filenames[] = $file['filename'];
       }
-
-      $diff = array_diff($filenames, $recorded_filenames);
-      $this->assertTrue(empty($diff), 'The uploaded files are present in the same order after the upgrade.');
+      $this->assertIdentical($filenames, $recorded_filenames, 'The uploaded files are present in the same order after the upgrade.');
     }
+    // Make sure the file settings were properly migrated.
+    $d6_file_directory_temp = '/drupal-6/file/directory/temp';
+    $d6_file_directory_path = '/drupal-6/file/directory/path';
+    $d6_file_downloads = 2; // FILE_DOWNLOADS_PRIVATE
+
+    $this->assertNull(variable_get('file_directory_temp', NULL), "The 'file_directory_temp' variable was properly removed.");
+    $this->assertEqual(variable_get('file_temporary_path', 'drupal-7-bogus'), $d6_file_directory_temp, "The 'file_temporary_path' setting was properly migrated.");
+    $this->assertEqual(variable_get('file_default_scheme', 'drupal-7-bogus'), 'private', "The 'file_default_scheme' setting was properly migrated.");
+    $this->assertEqual(variable_get('file_private_path', 'drupal-7-bogus'), $d6_file_directory_path, "The 'file_private_path' setting was properly migrated.");
   }
 }
diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info
index db9ba131a6ab52da13cdfda11c4d994d6172138a..0455c0d50d9959a5ec8634820a519cdbd653b3fe 100644
--- a/modules/simpletest/tests/url_alter_test.info
+++ b/modules/simpletest/tests/url_alter_test.info
@@ -1,15 +1,13 @@
-; $Id: url_alter_test.info,v 1.1 2009/10/24 05:13:44 webchick Exp $
+; $Id: url_alter_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = Url_alter tests
 description = A support modules for url_alter hook testing.
 core = 7.x
 package = Testing
 version = VERSION
-files[] = url_alter_test.module
-files[] = url_alter_test.install
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info
index 15022f5bd8b6275de1d5b617170ba58a9cb6073d..7c94c7971954b499766e4a4be76268b584cf2ac8 100644
--- a/modules/simpletest/tests/xmlrpc_test.info
+++ b/modules/simpletest/tests/xmlrpc_test.info
@@ -1,14 +1,13 @@
-; $Id: xmlrpc_test.info,v 1.1 2008/08/09 12:41:22 dries Exp $
+; $Id: xmlrpc_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "XML-RPC Test"
 description = "Support module for XML-RPC tests according to the validator1 specification."
 package = Testing
 version = VERSION
 core = 7.x
-files[] = xmlrpc_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info
index b0147880006c0890859f54456fa6a7470c9e2321..1127b2fdaa0356bd9c893fc94c5b2f6f2d2fdbf0 100644
--- a/modules/statistics/statistics.info
+++ b/modules/statistics/statistics.info
@@ -1,19 +1,14 @@
-; $Id: statistics.info,v 1.11 2009/11/17 21:24:18 dries Exp $
+; $Id: statistics.info,v 1.12 2010/12/20 19:59:43 webchick Exp $
 name = Statistics
 description = Logs access statistics for your site.
 package = Core
 version = VERSION
 core = 7.x
-files[] = statistics.module
-files[] = statistics.admin.inc
-files[] = statistics.pages.inc
-files[] = statistics.install
 files[] = statistics.test
-files[] = statistics.tokens.inc
 configure = admin/config/system/statistics
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/statistics/statistics.install b/modules/statistics/statistics.install
index 649869dd4dfa98224883746afe425c0bea8ff33f..7654c2de45548f204779bf0332713b0d526c8dd1 100644
--- a/modules/statistics/statistics.install
+++ b/modules/statistics/statistics.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.install,v 1.27 2010/08/22 13:55:53 dries Exp $
+// $Id: statistics.install,v 1.29 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -34,7 +34,7 @@ function statistics_schema() {
       ),
       'sid' => array(
         'type' => 'varchar',
-        'length' => 64,
+        'length' => 128,
         'not null' => TRUE,
         'default' => '',
         'description' => 'Browser session ID of user that visited page.',
@@ -137,11 +137,23 @@ function statistics_schema() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x statistics updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * Update the {accesslog}.sid column to match the length of {sessions}.sid
+ */
+function statistics_update_7000() {
+  db_change_field('accesslog', 'sid', 'sid', array(
+    'type' => 'varchar',
+    'length' => 128,
+    'not null' => TRUE,
+    'default' => '',
+    'description' => 'Browser session ID of user that visited page.',
+  ));
+}
+
+/**
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index 23aac1f0a8a7f609d118d342dfa8857a5ca134d9..3d0344ec21e8f628741e37ef5b3c130d6b2c69a4 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.module,v 1.339 2010/09/24 00:37:44 dries Exp $
+// $Id: statistics.module,v 1.340 2010/11/14 21:04:45 webchick Exp $
 
 /**
  * @file
@@ -117,7 +117,12 @@ function statistics_node_view($node, $view_mode) {
     if (user_access('view post access counter')) {
       $statistics = statistics_get($node->nid);
       if ($statistics) {
-        $node->content['links']['#links']['statistics_counter']['title'] = format_plural($statistics['totalcount'], '1 read', '@count reads');
+        $links['statistics_counter']['title'] = format_plural($statistics['totalcount'], '1 read', '@count reads');
+        $node->content['links']['statistics'] = array(
+          '#theme' => 'links__node__statistics',
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
       }
     }
   }
diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test
index 80f26e74b70330ad1bf99429d5236a019951f5be..d80e03b5795dea6c67057281d337247dfa216b39 100644
--- a/modules/statistics/statistics.test
+++ b/modules/statistics/statistics.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.test,v 1.23 2010/09/24 00:37:44 dries Exp $
+// $Id: statistics.test,v 1.24 2010/12/08 06:43:07 webchick Exp $
 
 /**
  * Sets up a base class for the Statistics module.
@@ -61,6 +61,7 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
 
     // Ensure we have a node page to access.
     $this->node = $this->drupalCreateNode();
+    $this->auth_user = $this->drupalCreateUser();
 
     // Enable page caching.
     variable_set('cache', TRUE);
@@ -101,6 +102,16 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
     $this->assertEqual(array_intersect_key($log[1], $expected), $expected);
     $node_counter = statistics_get($this->node->nid);
     $this->assertIdentical($node_counter['totalcount'], '2');
+
+    // Test logging from authenticated users
+    $this->drupalLogin($this->auth_user);
+    $this->drupalGet($path);
+    $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
+    // Check the 6th item since login and account pages are also logged
+    $this->assertTrue(is_array($log) && count($log) == 6, t('Page request was logged.'));
+    $this->assertEqual(array_intersect_key($log[5], $expected), $expected);
+    $node_counter = statistics_get($this->node->nid);
+    $this->assertIdentical($node_counter['totalcount'], '3');
   }
 }
 
diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info
index 2a92390ad0dca01f7d695d3ebd95fe7ec7f76d31..72a6472ca690f6043b7f1ae36ca43d6e160d6aa0 100644
--- a/modules/syslog/syslog.info
+++ b/modules/syslog/syslog.info
@@ -1,14 +1,13 @@
-; $Id: syslog.info,v 1.6 2009/06/08 09:23:54 dries Exp $
+; $Id: syslog.info,v 1.7 2010/12/20 19:59:43 webchick Exp $
 name = Syslog
 description = Logs and records system events to syslog.
 package = Core
 version = VERSION
 core = 7.x
-files[] = syslog.module
 files[] = syslog.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/system/html.tpl.php b/modules/system/html.tpl.php
index 7ef8fc2027ccae0cecc51007715a2af771c9c8a1..89435a7d11fa8fb9f2a5f161e91b9be974207e7f 100644
--- a/modules/system/html.tpl.php
+++ b/modules/system/html.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: html.tpl.php,v 1.4 2010/05/26 10:47:20 dries Exp $
+// $Id: html.tpl.php,v 1.6 2010/11/24 03:30:59 webchick Exp $
 
 /**
  * @file
@@ -13,7 +13,15 @@
  *   $language->dir contains the language direction. It will either be 'ltr' or 'rtl'.
  * - $rdf_namespaces: All the RDF namespace prefixes used in the HTML document.
  * - $grddl_profile: A GRDDL profile allowing agents to extract the RDF data.
- * - $head_title: A modified version of the page title, for use in the TITLE tag.
+ * - $head_title: A modified version of the page title, for use in the TITLE
+ *   tag.
+ * - $head_title_array: (array) An associative array containing the string parts
+ *   that were used to generate the $head_title variable, already prepared to be
+ *   output as TITLE tag. The key/value pairs may contain one or more of the
+ *   following, depending on conditions:
+ *   - title: The title of the current page, if any.
+ *   - name: The name of the site.
+ *   - slogan: The slogan of the site, if any, and if there is no title.
  * - $head: Markup for the HEAD section (including meta tags, keyword tags, and
  *   so on).
  * - $styles: Style tags necessary to import all CSS files for the page.
@@ -45,7 +53,7 @@
 </head>
 <body class="<?php print $classes; ?>" <?php print $attributes;?>>
   <div id="skip-link">
-    <a href="#main-content"><?php print t('Skip to main content'); ?></a>
+    <a href="#main-content" class="element-invisible element-focusable"><?php print t('Skip to main content'); ?></a>
   </div>
   <?php print $page_top; ?>
   <?php print $page; ?>
diff --git a/modules/system/image.gd.inc b/modules/system/image.gd.inc
index 17befdea821f2c3aaf9a98c0bb0455927fd2197f..bd38c8cbeca9a1eb85c2b6fc50e6bcec726b840c 100644
--- a/modules/system/image.gd.inc
+++ b/modules/system/image.gd.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: image.gd.inc,v 1.17 2010/09/21 15:28:11 dries Exp $
+// $Id: image.gd.inc,v 1.18 2010/10/28 02:27:09 dries Exp $
 
 /**
  * @file
@@ -351,7 +351,7 @@ function image_gd_get_info(stdClass $image) {
 
   if (isset($data) && is_array($data)) {
     $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
-    $extension = array_key_exists($data[2], $extensions) ?  $extensions[$data[2]] : '';
+    $extension = isset($extensions[$data[2]]) ?  $extensions[$data[2]] : '';
     $details = array(
       'width'     => $data[0],
       'height'    => $data[1],
diff --git a/modules/system/maintenance-page.tpl.php b/modules/system/maintenance-page.tpl.php
index 84a57da6429b5db147e0a0127b6e1e87555472d5..ac34c52e1773884867e6d98861ba62c03a4e77bb 100644
--- a/modules/system/maintenance-page.tpl.php
+++ b/modules/system/maintenance-page.tpl.php
@@ -1,12 +1,12 @@
 <?php
-// $Id: maintenance-page.tpl.php,v 1.9 2010/02/23 05:02:02 webchick Exp $
+// $Id: maintenance-page.tpl.php,v 1.10 2010/11/24 03:30:59 webchick Exp $
 
 /**
  * @file
  * Default theme implementation to display a single Drupal page while offline.
  *
- * All the available variables are mirrored in page.tpl.php. Some may be left
- * blank but they are provided for consistency.
+ * All the available variables are mirrored in html.tpl.php and page.tpl.php.
+ * Some may be blank but they are provided for consistency.
  *
  * @see template_preprocess()
  * @see template_preprocess_maintenance_page()
diff --git a/modules/system/page.tpl.php b/modules/system/page.tpl.php
index 8bdb75d183905772a4b7314aad9df5022e401668..1092da04d5a97d89dddbf5bc9ebf4e435b64245f 100644
--- a/modules/system/page.tpl.php
+++ b/modules/system/page.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: page.tpl.php,v 1.46 2010/08/23 23:38:06 webchick Exp $
+// $Id: page.tpl.php,v 1.47 2010/11/05 01:25:33 dries Exp $
 
 /**
  * @file
@@ -104,8 +104,8 @@
 
     <?php if ($main_menu || $secondary_menu): ?>
       <div id="navigation"><div class="section">
-        <?php print theme('links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'clearfix')), 'heading' => t('Main menu'))); ?>
-        <?php print theme('links__system_secondary_menu', array('links' => $secondary_menu, 'attributes' => array('id' => 'secondary-menu', 'class' => array('links', 'clearfix')), 'heading' => t('Secondary menu'))); ?>
+        <?php print theme('links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu'))); ?>
+        <?php print theme('links__system_secondary_menu', array('links' => $secondary_menu, 'attributes' => array('id' => 'secondary-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Secondary menu'))); ?>
       </div></div> <!-- /.section, /#navigation -->
     <?php endif; ?>
 
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 108a1eb8c3a0b7667184756af6d549dc29c3ae66..1548977980f31f04878bcce9bdc78cc52a3195ee 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.admin.inc,v 1.323 2010/10/20 16:19:24 webchick Exp $
+// $Id: system.admin.inc,v 1.327 2011/01/04 04:02:29 webchick Exp $
 
 /**
  * @file
@@ -90,7 +90,7 @@ function system_admin_index() {
     // Only display a section if there are any available tasks.
     if ($admin_tasks = system_get_module_admin_tasks($module, $info->info)) {
       // Sort links by title.
-      uasort($admin_tasks, 'system_sort_by_title');
+      uasort($admin_tasks, 'drupal_sort_title');
       // Move 'Configure permissions' links to the bottom of each section.
       $permission_key = "admin/people/permissions#module-$module";
       if (isset($admin_tasks[$permission_key])) {
@@ -902,19 +902,6 @@ function system_modules($form, $form_state = array()) {
   return $form;
 }
 
-/**
- * Array sorting callback; sorts elements by 'title' key.
- */
-function system_sort_by_title($a, $b) {
-  if (!isset($b['title'])) {
-    return -1;
-  }
-  if (!isset($a['title'])) {
-    return 1;
-  }
-  return strcasecmp($a['title'], $b['title']);
-}
-
 /**
  * Array sorting callback; sorts modules or themes by their name.
  */
@@ -1226,30 +1213,42 @@ function system_modules_uninstall($form, $form_state = NULL) {
     return $confirm_form;
   }
 
-  // Pull all disabled modules from the system table.
-  $disabled_modules = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > :schema ORDER BY name", array(':schema' => SCHEMA_UNINSTALLED));
-  foreach ($disabled_modules as $module) {
-    // Grab the module info
-    $info = unserialize($module->info);
-
-    // Load the .install file, and check for an uninstall or schema hook.
-    // If the hook exists, the module can be uninstalled.
-    module_load_install($module->name);
-    if (module_hook($module->name, 'uninstall') || module_hook($module->name, 'schema')) {
-      $form['modules'][$module->name]['name'] = array('#markup' => $info['name'] ? $info['name'] : $module->name);
-      $form['modules'][$module->name]['description'] = array('#markup' => t($info['description']));
-      $options[$module->name] = '';
+  // Get a list of disabled, installed modules.
+  $all_modules = system_rebuild_module_data();
+  $disabled_modules = array();
+  foreach ($all_modules as $name => $module) {
+    if (empty($module->status) && $module->schema_version > SCHEMA_UNINSTALLED) {
+      $disabled_modules[$name] = $module;
+    }
+  }
+
+  // Only build the rest of the form if there are any modules available to
+  // uninstall.
+  if (!empty($disabled_modules)) {
+    $profile = drupal_get_profile();
+    uasort($disabled_modules, 'system_sort_modules_by_info_name');
+    $form['uninstall'] = array('#tree' => TRUE);
+    foreach ($disabled_modules as $module) {
+      $module_name = $module->info['name'] ? $module->info['name'] : $module->name;
+      $form['modules'][$module->name]['#module_name'] = $module_name;
+      $form['modules'][$module->name]['name']['#markup'] = $module_name;
+      $form['modules'][$module->name]['description']['#markup'] = t($module->info['description']);
+      $form['uninstall'][$module->name] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Uninstall @module module', array('@module' => $module_name)),
+        '#title_display' => 'invisible',
+      );
+      // All modules which depend on this one must be uninstalled first, before
+      // we can allow this module to be uninstalled. (The install profile is
+      // excluded from this list.)
+      foreach (array_keys($module->required_by) as $dependent) {
+        if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
+          $dependent_name = isset($all_modules[$dependent]->info['name']) ? $all_modules[$dependent]->info['name'] : $dependent;
+          $form['modules'][$module->name]['#required_by'][] = $dependent_name;
+          $form['uninstall'][$module->name]['#disabled'] = TRUE;
+        }
+      }
     }
-  }
-
-  // Only build the rest of the form if there are any modules available to uninstall.
-  if (!empty($options)) {
-    $form['uninstall'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Modules'),
-      '#title_display' => 'invisible',
-      '#options' => $options,
-    );
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -1696,13 +1695,13 @@ function system_performance_settings() {
   );
   $form['bandwidth_optimization']['preprocess_css'] = array(
     '#type' => 'checkbox',
-    '#title' => t('Aggregate and compress CSS files into one file.'),
+    '#title' => t('Aggregate and compress CSS files.'),
     '#default_value' => intval(variable_get('preprocess_css', 0) && $is_writable),
     '#disabled' => $disabled,
   );
   $form['bandwidth_optimization']['preprocess_js'] = array(
     '#type' => 'checkbox',
-    '#title' => t('Aggregate JavaScript files into one file.'),
+    '#title' => t('Aggregate JavaScript files.'),
     '#default_value' => intval(variable_get('preprocess_js', 0) && $is_writable),
     '#disabled' => $disabled,
   );
@@ -2040,7 +2039,6 @@ function theme_system_date_time_settings($variables) {
     $row = array();
     $row[] = $form['format'][$key]['#title'];
     $form['format'][$key]['#title_display'] = 'invisible';
-    $row[] = $form['format'][$key]['#title_display'];
     $row[] = array('data' => drupal_render($form['format'][$key]));
     $row[] = array('data' => drupal_render($form['delete'][$delete_key]));
     $rows[] = $row;
@@ -2599,10 +2597,20 @@ function theme_system_modules_uninstall($variables) {
   // Display table.
   $rows = array();
   foreach (element_children($form['modules']) as $module) {
+    if (!empty($form['modules'][$module]['#required_by'])) {
+      $disabled_message = format_plural(count($form['modules'][$module]['#required_by']),
+        'To uninstall @module, the following module must be uninstalled first: @required_modules',
+        'To uninstall @module, the following modules must be uninstalled first: @required_modules',
+        array('@module' => $form['modules'][$module]['#module_name'], '@required_modules' => implode(', ', $form['modules'][$module]['#required_by'])));
+      $disabled_message = '<div class="admin-requirements">' . $disabled_message . '</div>';
+    }
+    else {
+      $disabled_message = '';
+    }
     $rows[] = array(
       array('data' => drupal_render($form['uninstall'][$module]), 'align' => 'center'),
       '<strong><label for="' . $form['uninstall'][$module]['#id'] . '">' . drupal_render($form['modules'][$module]['name']) . '</label></strong>',
-      array('data' => drupal_render($form['modules'][$module]['description']), 'class' => array('description')),
+      array('data' => drupal_render($form['modules'][$module]['description']) . $disabled_message, 'class' => array('description')),
     );
   }
 
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index 5a8c3ecc04e7bdf9a8c462d15681a17601e9ba95..141f6aa61bd88b396d6253e73ada304dfe84cba6 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.api.php,v 1.205 2010/10/22 17:20:41 dries Exp $
+// $Id: system.api.php,v 1.225 2011/01/04 00:58:30 webchick Exp $
 
 /**
  * @file
@@ -88,10 +88,15 @@ function hook_hook_info_alter(&$hooks) {
  *     uri elements of the entity, e.g. 'path' and 'options'. The actual entity
  *     uri can be constructed by passing these elements to url().
  *   - label callback: (optional) A function taking an entity as argument and
- *     returning the label of the entity; e.g., $node->title or
- *     $comment->subject. A callback should be specified when the label is the
- *     result of complex logic. Otherwise, the 'label' property of the
- *     'entity keys' the property should be used.
+ *     returning the label of the entity. The entity label is the main string
+ *     associated with an entity; for example, the title of a node or the
+ *     subject of a comment. If there is an entity object property that defines
+ *     the label, use the 'label' element of the 'entity keys' return
+ *     value component to provide this information (see below). If more complex
+ *     logic is needed to determine the label of an entity, you can instead
+ *     specify a callback function here, which will be called to determine the
+ *     entity label. See also the entity_label() function, which implements this
+ *     logic.
  *   - fieldable: Set to TRUE if you want your entity type to be fieldable.
  *   - translation: An associative array of modules registered as field
  *     translation handlers. Array keys are the module names, array values
@@ -112,11 +117,11 @@ function hook_hook_info_alter(&$hooks) {
  *       omitted if this entity type exposes a single bundle (all entities have
  *       the same collection of fields). The name of this single bundle will be
  *       the same as the entity type.
- *     - label: The property name of the entity that contains the label. For
+ *     - label: The name of the property that contains the entity label. For
  *       example, if the entity's label is located in $entity->subject, then
- *       'subect' should be specified here. In case complex logic is required to
- *       build the label, a 'label callback' should be implemented instead. See
- *       entity_label() for details.
+ *       'subject' should be specified here. If complex logic is required to
+ *       build the label, a 'label callback' should be defined instead (see
+ *       the 'label callback' section above for details).
  *   - bundle keys: An array describing how the Field API can extract the
  *     information it needs from the bundle objects for this type (e.g
  *     $vocabulary objects for terms; not applicable for nodes). This entry can
@@ -275,6 +280,18 @@ function hook_entity_load($entities, $type) {
   }
 }
 
+/**
+ * Act on an entity before it is about to be created or updated.
+ *
+ * @param $entity
+ *   The entity object.
+ * @param $type
+ *   The type of entity being saved (i.e. node, user, comment).
+ */
+function hook_entity_presave($entity, $type) {
+  $entity->changed = REQUEST_TIME;
+}
+
 /**
  * Act on entities when inserted.
  *
@@ -286,7 +303,7 @@ function hook_entity_load($entities, $type) {
 function hook_entity_insert($entity, $type) {
   // Insert the new entity into a fictional table of all entities.
   $info = entity_get_info($type);
-  $id = reset(entity_extract_ids($type, $entity));
+  list($id) = entity_extract_ids($type, $entity);
   db_insert('example_entity')
     ->fields(array(
       'type' => $type,
@@ -308,7 +325,7 @@ function hook_entity_insert($entity, $type) {
 function hook_entity_update($entity, $type) {
   // Update the entity's entry in a fictional table of all entities.
   $info = entity_get_info($type);
-  $id = reset(entity_extract_ids($type, $entity));
+  list($id) = entity_extract_ids($type, $entity);
   db_update('example_entity')
     ->fields(array(
       'updated' => REQUEST_TIME,
@@ -329,7 +346,7 @@ function hook_entity_update($entity, $type) {
 function hook_entity_delete($entity, $type) {
   // Delete the entity's entry from a fictional table of all entities.
   $info = entity_get_info($type);
-  $id = reset(entity_extract_ids($type, $entity));
+  list($id) = entity_extract_ids($type, $entity);
   db_delete('example_entity')
     ->condition('type', $type)
     ->condition('id', $id)
@@ -350,11 +367,80 @@ function hook_entity_delete($entity, $type) {
  *   engines. Also, the default implementation presumes entities are stored in
  *   SQL, but the execute callback could instead query any other entity storage,
  *   local or remote.
+ *
+ *   Note the $query->altered attribute which is TRUE in case the query has
+ *   already been altered once. This happens with cloned queries.
+ *   If there is a pager, then such a cloned query will be executed to count
+ *   all elements. This query can be detected by checking for
+ *   ($query->pager && $query->count), allowing the driver to return 0 from
+ *   the count query and disable the pager.
  */
 function hook_entity_query_alter($query) {
   $query->executeCallback = 'my_module_query_callback';
 }
 
+/**
+ * Act on entities being assembled before rendering.
+ *
+ * @param $entity
+ *   The entity object.
+ * @param $type
+ *   The type of entity being rendered (i.e. node, user, comment).
+ * @param $view_mode
+ *   The view mode the entity is rendered in.
+ * @param $langcode
+ *   The language code used for rendering.
+ *
+ * The module may add elements to $entity->content prior to rendering. The
+ * structure of $entity->content is a renderable array as expected by
+ * drupal_render().
+ *
+ * @see hook_entity_view_alter()
+ * @see hook_comment_view()
+ * @see hook_node_view()
+ * @see hook_user_view()
+ */
+function hook_entity_view($entity, $type, $view_mode, $langcode) {
+  $entity->content['my_additional_field'] = array(
+    '#markup' => $additional_field,
+    '#weight' => 10,
+    '#theme' => 'mymodule_my_additional_field',
+  );
+}
+
+/**
+ * Alter the results of ENTITY_view().
+ *
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * entity content structure has been built.
+ *
+ * If a module wishes to act on the rendered HTML of the entity rather than the
+ * structured content array, it may use this hook to add a #post_render
+ * callback. Alternatively, it could also implement hook_preprocess_ENTITY().
+ * See drupal_render() and theme() for details.
+ *
+ * @param $build
+ *   A renderable array representing the entity content.
+ * @param $type
+ *   The type of entity being rendered (i.e. node, user, comment).
+ *
+ * @see hook_entity_view()
+ * @see hook_comment_view_alter()
+ * @see hook_node_view_alter()
+ * @see hook_taxonomy_term_view_alter()
+ * @see hook_user_view_alter()
+ */
+function hook_entity_view_alter(&$build, $type) {
+  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
+    // Change its weight.
+    $build['an_additional_field']['#weight'] = -10;
+
+    // Add a #post_render callback to act on the rendered HTML of the entity.
+    $build['#post_render'][] = 'my_module_node_post_render';
+  }
+}
+
 /**
  * Define administrative paths.
  *
@@ -780,6 +866,38 @@ function hook_page_build(&$page) {
   }
 }
 
+/**
+ * Alter a menu router item right after it has been retrieved from the database or cache.
+ *
+ * This hook is invoked by menu_get_item() and allows for run-time alteration of router
+ * information (page_callback, title, and so on) before it is translated and checked for
+ * access. The passed in $router_item is statically cached for the current request, so this
+ * hook is only invoked once for any router item that is retrieved via menu_get_item().
+ *
+ * Usually, modules will only want to inspect the router item and conditionally
+ * perform other actions (such as preparing a state for the current request).
+ * Note that this hook is invoked for any router item that is retrieved by
+ * menu_get_item(), which may or may not be called on the path itself, so implementations
+ * should check the $path parameter if the alteration should fire for the current request
+ * only.
+ *
+ * @param $router_item
+ *   The menu router item for $path.
+ * @param $path
+ *   The originally passed path, for which $router_item is responsible.
+ * @param $original_map
+ *   The path argument map, as contained in $path.
+ *
+ * @see menu_get_item()
+ */
+function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
+  // When retrieving the router item for the current path...
+  if ($path == $_GET['q']) {
+    // ...call a function that prepares something for this request.
+    mymodule_prepare_something();
+  }
+}
+
 /**
  * Define menu items and page callbacks.
  *
@@ -901,21 +1019,22 @@ function hook_page_build(&$page) {
  * $items['admin/config/foo'] = array(
  *   'title' => 'Foo settings',
  *   'type' => MENU_NORMAL_ITEM,
- *   // page callback, etc. need to be added here
+ *   // 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
+ *   // 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
+ *   // Page callback and theme callback will be inherited from
+ *   // 'admin/config/foo', if not specified here to override.
+ *   // Need to add access callback or access arguments.
  * );
  * @endcode
  *
@@ -940,19 +1059,31 @@ function hook_page_build(&$page) {
  *     item. Note that this function is called even if the access checks fail,
  *     so any custom delivery callback function should take that into account.
  *     See drupal_deliver_html_page() for an example.
- *   - "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 callback": A function returning TRUE if the user has access
+ *     rights to this menu item, and FALSE if not. It can also be a boolean
+ *     constant instead of a function, and you can also use numeric values
+ *     (will be cast to boolean). Defaults to user_access() unless a value is
+ *     inherited from the parent menu item; only MENU_DEFAULT_LOCAL_TASK items
+ *     can inherit access callbacks. To use the user_access() default callback,
+ *     you must specify the permission to check as 'access arguments' (see
+ *     below).
  *   - "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().
+ *     function, with path component substitution as described above. If the
+ *     access callback is inherited (see above), the access arguments will be
+ *     inherited with it, unless overridden in the child menu item.
+ *   - "theme callback": (optional) A function returning the machine-readable
+ *     name of the theme that will be used to render the page. If not provided,
+ *     the value will be inherited from a parent menu item. If there is no
+ *     theme callback, or if the function does not return the name of a current
+ *     active theme on the site, the theme for this page will be determined by
+ *     either hook_custom_theme() or the default theme instead. As a general
+ *     rule, the use of theme callback functions should be limited to pages
+ *     whose functionality is very closely tied to a particular theme, since
+ *     they can only be overridden by modules which specifically target those
+ *     pages in hook_menu_alter(). Modules implementing more generic theme
+ *     switching functionality (for example, a module which allows the theme to
+ *     be set dynamically based on the current user's role) should use
+ *     hook_custom_theme() instead.
  *   - "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;
@@ -1071,30 +1202,49 @@ function hook_menu_alter(&$items) {
  *
  * @param $item
  *   Associative array defining a menu link as passed into menu_link_save().
+ *
+ * @see hook_translated_menu_link_alter()
  */
 function hook_menu_link_alter(&$item) {
-  // Example 1 - make all new admin links hidden (a.k.a disabled).
+  // 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()
+  // Flag a link to be altered by hook_translated_menu_link_alter().
   if ($item['link_path'] == 'devel/cache/clear') {
     $item['options']['alter'] = TRUE;
   }
+  // Flag a link to be altered by hook_translated_menu_link_alter(), but only
+  // if it is derived from a menu router item; i.e., do not alter a custom
+  // menu link pointing to the same path that has been created by a user.
+  if ($item['link_path'] == 'user' && $item['module'] == 'system') {
+    $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().
+ * Alter a menu link after it has been translated and before it is rendered.
+ *
+ * This hook is invoked from _menu_link_translate() after a menu link has been
+ * translated; i.e., after dynamic path argument placeholders (%) have been
+ * replaced with actual values, the user access to the link's target page has
+ * been checked, and the link has been localized. It is only invoked if
+ * $item['options']['alter'] has been set to a non-empty value (e.g., TRUE).
+ * This flag should be set using hook_menu_link_alter().
+ *
+ * Implementations of this hook are able to alter any property of the menu link.
+ * For example, this hook may be used to add a page-specific query string to all
+ * menu links, or hide a certain link by setting:
+ * @code
+ *   'hidden' => 1,
+ * @endcode
  *
  * @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).
+ *
+ * @see hook_menu_link_alter()
  */
 function hook_translated_menu_link_alter(&$item, $map) {
   if ($item['href'] == 'devel/cache/clear') {
@@ -1356,13 +1506,13 @@ function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) {
  *
  * @code
  *   // Node body.
- *   $page['content']['nodes'][$nid]['body']
+ *   $page['content']['system_main']['nodes'][$nid]['body']
  *   // Array of links attached to the node (add comments, read more).
- *   $page['content']['nodes'][$nid]['links']
+ *   $page['content']['system_main']['nodes'][$nid]['links']
  *   // The node object itself.
- *   $page['content']['nodes'][$nid]['#node']
+ *   $page['content']['system_main']['nodes'][$nid]['#node']
  *   // The results pager.
- *   $page['content']['pager']
+ *   $page['content']['system_main']['pager']
  * @endcode
  *
  * Blocks may be referenced by their module/delta pair within a region:
@@ -1585,7 +1735,11 @@ function hook_boot() {
  * implement this hook, but declare these files in their .info file.
  */
 function hook_init() {
-  drupal_add_css(drupal_get_path('module', 'book') . '/book.css');
+  // Since this file should only be loaded on the front page, it cannot be
+  // declared in the info file.
+  if (drupal_is_front_page()) {
+    drupal_add_css(drupal_get_path('module', 'foo') . '/foo.css');
+  }
 }
 
 /**
@@ -1928,10 +2082,12 @@ function hook_theme_registry_alter(&$theme_registry) {
  * Return the machine-readable name of the theme to use for the current page.
  *
  * This hook can be used to dynamically set the theme for the current page
- * request. It overrides the default theme as well as any per-page or
- * per-section theme set by the theme callback function in hook_menu(). This
- * should be used by modules which need to override the theme based on dynamic
- * conditions.
+ * request. It should be used by modules which need to override the theme
+ * based on dynamic conditions (for example, a module which allows the theme to
+ * be set based on the current user's role). The return value of this hook will
+ * be used on all pages except those which have a valid per-page or per-section
+ * theme set via a theme callback function in hook_menu(); the themes on those
+ * pages can only be overridden using hook_menu_alter().
  *
  * Since only one theme can be used at a time, the last (i.e., highest
  * weighted) module which returns a valid theme name from this hook will
@@ -2107,31 +2263,28 @@ function hook_watchdog(array $log_entry) {
 /**
  * Prepare a message based on parameters; called from drupal_mail().
  *
+ * Note that hook_mail(), unlike hook_mail_alter(), is only called on the
+ * $module argument to drupal_mail(), not all modules.
+ *
  * @param $key
  *   An identifier of the mail.
  * @param $message
- *  An array to be filled in. Keys in this array include:
- *  - 'id':
- *     An id to identify the mail sent. Look at module source code
+ *   An array to be filled in. Elements in this array include:
+ *   - id: An ID to identify the mail sent. Look at module source code
  *     or drupal_mail() for possible id values.
- *  - 'to':
- *     The address or addresses the message will be sent to. The
+ *   - to: The address or addresses the message will be sent to. The
  *     formatting of this string must comply with RFC 2822.
- *  - 'subject':
- *     Subject of the e-mail to be sent. This must not contain any newline
- *     characters, or the mail may not be sent properly. drupal_mail() sets
- *     this to an empty string when the hook is invoked.
- *  - 'body':
- *     An array of lines containing the message to be sent. Drupal will format
- *     the correct line endings for you. drupal_mail() sets this to an empty
- *     array when the hook is invoked.
- *  - 'from':
- *     The address the message will be marked as being from, which is
+ *   - subject: Subject of the e-mail to be sent. This must not contain any
+ *     newline characters, or the mail may not be sent properly. drupal_mail()
+ *     sets this to an empty string when the hook is invoked.
+ *   - body: An array of lines containing the message to be sent. Drupal will
+ *     format the correct line endings for you. drupal_mail() sets this to an
+ *     empty array when the hook is invoked.
+ *   - from: The address the message will be marked as being from, which is
  *     set by drupal_mail() to either a custom address or the site-wide
  *     default email address when the hook is invoked.
- *  - 'headers':
- *     Associative array containing mail headers, such as From, Sender,
- *     MIME-Version, Content-Type, etc. drupal_mail() pre-fills
+ *   - headers: Associative array containing mail headers, such as From,
+ *     Sender, MIME-Version, Content-Type, etc. drupal_mail() pre-fills
  *     several headers in this array.
  * @param $params
  *   An array of parameters supplied by the caller of drupal_mail().
@@ -2408,7 +2561,7 @@ function hook_file_validate(&$file) {
 }
 
 /**
- * Respond to a file being added.
+ * Act on a file being inserted or updated.
  *
  * This hook is called when a file has been added to the database. The hook
  * doesn't distinguish between files created as a result of a copy or those
@@ -2419,6 +2572,23 @@ function hook_file_validate(&$file) {
  *
  * @see file_save()
  */
+function hook_file_presave($file) {
+  // Change the file timestamp to an hour prior.
+  $file->timestamp -= 3600;
+}
+
+/**
+ * Respond to a file being added.
+ *
+ * This hook is called before a file has been added to the database. The hook
+ * doesn't distinguish between files created as a result of a copy or those
+ * created by an upload.
+ *
+ * @param $file
+ *   The file that is about to be saved.
+ *
+ * @see file_save()
+ */
 function hook_file_insert($file) {
 
 }
@@ -2565,7 +2735,7 @@ function hook_file_url_alter(&$uri) {
     // 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)) {
+    if (isset($pathinfo['extension']) && in_array($pathinfo['extension'], $cdn_extensions)) {
       $uri = $cdn1 . '/' . $path;
     }
     else {
@@ -2573,7 +2743,8 @@ function hook_file_url_alter(&$uri) {
     }
   }
 }
-                                                                                                      /**
+
+/**
  * Check installation requirements and do status reporting.
  *
  * This hook has two closely related uses, determined by the $phase argument:
@@ -2607,24 +2778,25 @@ function hook_file_url_alter(&$uri) {
  * result in a notice on the the administration overview page.
  *
  * @param $phase
- *   The phase in which hook_requirements is run:
- *   - 'install': the module is being installed.
- *   - 'runtime': the runtime requirements are being checked and shown on the
- *              status report page.
+ *   The phase in which requirements are checked:
+ *   - install: The module is being installed.
+ *   - update: The module is enabled and update.php is run.
+ *   - runtime: The runtime requirements are being checked and shown on the
+ *     status report page.
  *
  * @return
  *   A keyed array of requirements. Each requirement is itself an array with
  *   the following items:
- *     - 'title': the name of the requirement.
- *     - 'value': the current value (e.g. version, time, level, ...). During
- *       install phase, this should only be used for version numbers, do not set
- *       it if not applicable.
- *     - 'description': description of the requirement/status.
- *     - 'severity': the requirement's result/severity level, one of:
- *         - REQUIREMENT_INFO:    For info only.
- *         - REQUIREMENT_OK:      The requirement is satisfied.
- *         - REQUIREMENT_WARNING: The requirement failed with a warning.
- *         - REQUIREMENT_ERROR:   The requirement failed with an error.
+ *   - title: The name of the requirement.
+ *   - value: The current value (e.g., version, time, level, etc). During
+ *     install phase, this should only be used for version numbers, do not set
+ *     it if not applicable.
+ *   - description: The description of the requirement/status.
+ *   - severity: The requirement's result/severity level, one of:
+ *     - REQUIREMENT_INFO: For info only.
+ *     - REQUIREMENT_OK: The requirement is satisfied.
+ *     - REQUIREMENT_WARNING: The requirement failed with a warning.
+ *     - REQUIREMENT_ERROR: The requirement failed with an error.
  */
 function hook_requirements($phase) {
   $requirements = array();
@@ -2934,6 +3106,9 @@ function hook_install() {
  * See the batch operations page for more information on how to use the batch API:
  * @link http://drupal.org/node/180528 http://drupal.org/node/180528 @endlink
  *
+ * @param $sandbox
+ *   Stores information for multipass updates. See above for more information.
+ *
  * @throws DrupalUpdateException, PDOException
  *   In case of error, update hooks should throw an instance of DrupalUpdateException
  *   with a meaningful message for the user. If a database query fails for whatever
@@ -3539,24 +3714,38 @@ function hook_archiver_info_alter(&$info) {
 }
 
 /**
- * Defines additional date types.
+ * Define additional date types.
  *
  * Next to the 'long', 'medium' and 'short' date types defined in core, any
- * module can define additional types that can be used when displaying dates. A
- * date type is a key which can be passed to format_date() to return a date in
- * the configured display format.
+ * module can define additional types that can be used when displaying dates,
+ * by implementing this hook. A date type is basically just a name for a date
+ * format.
+ *
+ * Date types are used in the administration interface: a user can assign
+ * date format types defined in hook_date_formats() to date types defined in
+ * this hook. Once a format has been assigned by a user, the machine name of a
+ * type can be used in the format_date() function to format a date using the
+ * chosen formatting.
+ *
+ * To define a date type in a module and make sure a format has been assigned to
+ * it, without requiring a user to visit the administrative interface, use
+ * @code variable_set('date_format_' . $type, $format); @endcode
+ * where $type is the machine-readable name defined here, and $format is a PHP
+ * date format string.
  *
  * To avoid namespace collisions with date types defined by other modules, it is
  * recommended that each date type starts with the module name. A date type
  * can consist of letters, numbers and underscores.
  *
  * @return
- *   A list of date types in 'key' => 'label' format.
+ *   An array of date types where the keys are the machine-readable names and
+ *   the values are the human-readable labels.
  *
  * @see hook_date_formats()
  * @see format_date()
  */
 function hook_date_format_types() {
+  // Define the core date format types.
   return array(
     'long' => t('Long'),
     'medium' => t('Medium'),
@@ -3565,72 +3754,67 @@ function hook_date_format_types() {
 }
 
 /**
- * Modify existing date format types.
+ * Modify existing date 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.
+ * 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 types, such as locking all date 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.
+ *   A list of date types. Each date type is keyed by the machine-readable name
+ *   and the values are associative arrays containing:
+ *   - is_new: Set to FALSE to override previous settings.
+ *   - module: The name of the module that created the date type.
+ *   - type: The machine-readable date type name.
+ *   - title: The human-readable date type name.
+ *   - 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;
+  foreach ($types as $name => $type) {
+    $types[$name]['locked'] = 1;
   }
 }
 
 /**
- * Defines additional date formats.
- *
- * Next to the 'long', 'medium' and 'short' date types defined in core, any
- * module can define additional types that can be used when displaying dates. A
- * date type is a key which can be passed to format_date() to return a date in
- * the configured displayed format. A date format is a string defining the date
- * and time elements to use. For example, a date type could be
- * 'mymodule_extra_long', while a date format is like 'Y-m-d'.
- *
- * New date types must first be declared using hook_date_format_types(). It is
- * then possible to define one or more date formats for each.
- *
- * A module may also extend the list date formats defined for a date type
- * provided by another module.
- *
- * There may be more than one format for the same locale. For example d/m/Y and
- * Y/m/d work equally well in some locales. It may also be necessary to define
- * multiple versions of the same date format, for example, one using AM, one
- * with PM and one without the time at all.
- *
- * However at the same time you may wish to define some additional date formats
- * that aren't specific to any one locale, for example, "Y m". For these cases
- * the locales field should be omitted.
+ * Define additional date formats.
+ *
+ * This hook is used to define the PHP date format strings that can be assigned
+ * to date types in the administrative interface. A module can provide date
+ * format strings for the core-provided date types ('long', 'medium', and
+ * 'short'), or for date types defined in hook_date_format_types() by itself
+ * or another module.
+ *
+ * Since date formats can be locale-specific, you can specify the locales that
+ * each date format string applies to. There may be more than one locale for a
+ * format. There may also be more than one format for the same locale. For
+ * example d/m/Y and Y/m/d work equally well in some locales. You may wish to
+ * define some additional date formats that aren't specific to any one locale,
+ * for example, "Y m". For these cases, the 'locales' component of the return
+ * value should be omitted.
+ *
+ * Providing a date format here does not normally assign the format to be
+ * used with the associated date type -- a user has to choose a format for each
+ * date type in the administrative interface. There is one exception: locale
+ * initialization chooses a locale-specific format for the three core-provided
+ * types (see locale_get_localized_date_format() for details). If your module
+ * needs to ensure that a date type it defines has a format associated with it,
+ * call @code variable_set('date_format_' . $type, $format); @endcode
+ * where $type is the machine-readable name defined in hook_date_format_types(),
+ * and $format is a PHP date format string.
  *
  * @return
- *   A list of date formats. Each date format is a keyed array
- *   consisting of three elements:
- *   - 'type': the date type is a key used to identify which date format to
- *     display. It consists of letters, numbers and underscores, e.g. 'long',
- *     'short', 'mymodule_extra_long'. It must first be declared in
- *     hook_date_format_types() unless extending a type provided by another
- *     module.
- *   - 'format': a string defining the date and time elements to use. It
+ *   A list of date formats to offer as choices in the administrative
+ *   interface. Each date format is a keyed array consisting of three elements:
+ *   - 'type': The date type name that this format can be used with, as
+ *     declared in an implementation of hook_date_format_types().
+ *   - 'format': A PHP date format string to use when formatting dates. It
  *     can contain any of the formatting options described at
  *     http://php.net/manual/en/function.date.php
- *   - 'locales': (optional) an array of 2 and 5 character language codes, for
- *     example, 'en', 'en-us'. The language codes are used to determine which
- *     date format to display for the user's current language. If more than one
- *     date format is suggested for the same date type and locale, then the
- *     first one will be used unless overridden via
- *     admin/config/regional/date-time/locale. If your date format is not
- *     language specific, leave this field empty.
+ *   - 'locales': (optional) An array of 2 and 5 character locale codes,
+ *     defining which locales this format applies to (for example, 'en',
+ *     'en-us', etc.). If your date format is not language-specific, leave this
+ *     array empty.
  *
  * @see hook_date_format_types()
  */
@@ -3655,7 +3839,7 @@ function hook_date_formats() {
 }
 
 /**
- * Alters date types and formats declared by another module.
+ * Alter date formats declared by another module.
  *
  * Called by _system_date_format_types_build() to allow modules to alter the
  * return values from implementations of hook_date_formats().
@@ -4147,52 +4331,6 @@ function hook_countries_alter(&$countries) {
   $countries['EB'] = 'Elbonia';
 }
 
-/**
- * Provide information on available file transfer backends.
- *
- * File transfer backends are used by modules to transfer files from remote
- * locations to Drupal sites. For instance, update.module uses a file transfer
- * backend to download new versions of modules and themes from drupal.org.
- *
- * @return
- *   An associative array of information about the file transfer backend(s).
- *   being provided. This array can contain the following keys:
- *   - title: Title of the backend to be shown to the end user.
- *   - class: Name of the PHP class which implements this backend.
- *   - settings_form: An optional callback function that provides additional
- *     configuration information required by this backend (for instance a port
- *     number.)
- *   - weight: Controls what order the backends are presented to the user.
- *
- * @see authorize.php
- * @see FileTransfer
- */
-function hook_filetransfer_backends() {
-  $backends = array();
-
-  // This is the default, will be available on most systems.
-  if (function_exists('ftp_connect')) {
-    $backends['ftp'] = array(
-      'title' => t('FTP'),
-      'class' => 'FileTransferFTP',
-      'settings_form' => 'system_filetransfer_backend_form_ftp',
-      'weight' => 0,
-    );
-  }
-
-  // SSH2 lib connection is only available if the proper PHP extension is
-  // installed.
-  if (function_exists('ssh2_connect')) {
-    $backends['ssh'] = array(
-      'title' => t('SSH'),
-      'class' => 'FileTransferSSH',
-      'settings_form' => 'system_filetransfer_backend_form_ssh',
-      'weight' => 20,
-    );
-  }
-  return $backends;
-}
-
 /**
  * Control site status before menu dispatching.
  *
@@ -4218,6 +4356,69 @@ function hook_menu_site_status_alter(&$menu_site_status, $path) {
   }
 }
 
+/**
+ * Register information about FileTransfer classes provided by a module.
+ *
+ * The FileTransfer class allows transfering files over a specific type of
+ * connection. Core provides classes for FTP and SSH. Contributed modules are
+ * free to extend the FileTransfer base class to add other connection types,
+ * and if these classes are registered via hook_filetransfer_info(), those
+ * connection types will be available to site administrators using the Update
+ * manager when they are redirected to the authorize.php script to authorize
+ * the file operations.
+ *
+ * @return array
+ *   Nested array of information about FileTransfer classes. Each key is a
+ *   FileTransfer type (not human readable, used for form elements and
+ *   variable names, etc), and the values are subarrays that define properties
+ *   of that type. The keys in each subarray are:
+ *   - 'title': Required. The human-readable name of the connection type.
+ *   - 'class': Required. The name of the FileTransfer class. The constructor
+ *     will always be passed the full path to the root of the site that should
+ *     be used to restrict where file transfer operations can occur (the $jail)
+ *     and an array of settings values returned by the settings form.
+ *   - 'file': Required. The include file containing the FileTransfer class.
+ *     This should be a separate .inc file, not just the .module file, so that
+ *     the minimum possible code is loaded when authorize.php is running.
+ *   - 'file path': Optional. The directory (relative to the Drupal root)
+ *     where the include file lives. If not defined, defaults to the base
+ *     directory of the module implementing the hook.
+ *   - 'weight': Optional. Integer weight used for sorting connection types on
+ *     the authorize.php form.
+ *
+ * @see FileTransfer
+ * @see authorize.php
+ * @see hook_filetransfer_info_alter()
+ * @see drupal_get_filetransfer_info()
+ */
+function hook_filetransfer_info() {
+  $info['sftp'] = array(
+    'title' => t('SFTP (Secure FTP)'),
+    'file' => 'sftp.filetransfer.inc',
+    'class' => 'FileTransferSFTP',
+    'weight' => 10,
+  );
+  return $info;
+}
+
+/**
+ * Alter the FileTransfer class registry.
+ *
+ * @param array $filetransfer_info
+ *   Reference to a nested array containing information about the FileTransfer
+ *   class registry.
+ *
+ * @see hook_filetransfer_info()
+ */
+function hook_filetransfer_info_alter(&$filetransfer_info) {
+  if (variable_get('paranoia', FALSE)) {
+    // Remove the FTP option entirely.
+    unset($filetransfer_info['ftp']);
+    // Make sure the SSH option is listed first.
+    $filetransfer_info['ssh']['weight'] = -10;
+  }
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/modules/system/system.archiver.inc b/modules/system/system.archiver.inc
index 963c7010c9a6b144ece6c3ab2d90e0e3b088d0aa..903e4688a98399c02ca65557d600b7d5421e4e8c 100644
--- a/modules/system/system.archiver.inc
+++ b/modules/system/system.archiver.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.archiver.inc,v 1.4 2010/02/01 19:14:14 dries Exp $
+// $Id: system.archiver.inc,v 1.6 2010/12/30 22:33:04 webchick Exp $
 
 /**
  * @file
@@ -28,7 +28,7 @@ class ArchiverTar implements ArchiverInterface {
     return $this;
   }
 
-  public function remove($path) {
+  public function remove($file_path) {
     // @todo Archive_Tar doesn't have a remove operation
     // so we'll have to simulate it somehow, probably by
     // creating a new archive with everything but the removed
@@ -99,14 +99,19 @@ class ArchiverZip implements ArchiverInterface {
     return $this;
   }
 
-  public function remove($path) {
+  public function remove($file_path) {
     $this->zip->deleteName($file_path);
 
     return $this;
   }
 
   public function extract($path, Array $files = array()) {
-    $this->zip->extractTo($path, $files);
+    if ($files) {
+      $this->zip->extractTo($path, $files);
+    }
+    else {
+      $this->zip->extractTo($path);
+    }
 
     return $this;
   }
diff --git a/modules/system/system.base.css b/modules/system/system.base.css
index 65924bcae4096002aa1f83e4da18fa335f96e7f7..3ed4e080f46ab2afa16e45d9258e9db058da9c2f 100644
--- a/modules/system/system.base.css
+++ b/modules/system/system.base.css
@@ -1,4 +1,4 @@
-/* $Id: system.base.css,v 1.3 2010/09/25 02:28:14 dries Exp $ */
+/* $Id: system.base.css,v 1.4 2011/01/03 07:04:48 webchick Exp $ */
 
 /**
  * @file
@@ -69,8 +69,8 @@ fieldset.collapsible .fieldset-legend {
   display: block;
   margin: 0;
   width: 100%;
-  -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
   box-sizing: border-box;
 }
 .resizable-textarea .grippie {
diff --git a/modules/system/system.info b/modules/system/system.info
index 2892740ad34d83a461ced6d8d99de38bf66e118b..cb84b7b29fe2a33d5e454472dd175d25068e7f9f 100644
--- a/modules/system/system.info
+++ b/modules/system/system.info
@@ -1,25 +1,20 @@
-; $Id: system.info,v 1.20 2009/12/15 08:37:18 dries Exp $
+; $Id: system.info,v 1.21 2010/12/20 19:59:43 webchick Exp $
 name = System
 description = Handles general site configuration for administrators.
 package = Core
 version = VERSION
 core = 7.x
-files[] = system.module
-files[] = system.admin.inc
 files[] = system.archiver.inc
+files[] = system.mail.inc
 files[] = system.queue.inc
-files[] = image.gd.inc
-files[] = system.install
-files[] = system.test
 files[] = system.tar.inc
-files[] = system.tokens.inc
 files[] = system.updater.inc
-files[] = system.mail.inc
+files[] = system.test
 required = TRUE
 configure = admin/config/system
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/system/system.install b/modules/system/system.install
index 0a5665dc90746ada304740b35d4444815ef30efa..fa2c3fe92270be1f797dd28bd611b848f58d5fd0 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.install,v 1.520 2010/10/20 00:47:44 dries Exp $
+// $Id: system.install,v 1.532 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -188,6 +188,19 @@ function system_requirements($phase) {
       $requirements['database_extensions']['value'] = $t('Enabled');
     }
   }
+  else {
+    // Database information.
+    $class = 'DatabaseTasks_' . Database::getConnection()->driver();
+    $tasks = new $class();
+    $requirements['database_system'] = array(
+      'title' => $t('Database system'),
+      'value' => $tasks->name(),
+    );
+    $requirements['database_system_version'] = array(
+      'title' => $t('Database system version'),
+      'value' => Database::getConnection()->version(),
+    );
+  }
 
   // Test PHP memory_limit
   $memory_limit = ini_get('memory_limit');
@@ -1469,14 +1482,13 @@ function system_schema() {
         'not null' => TRUE,
       ),
       'sid' => array(
-        'description' => "A session ID. The value is generated by PHP's Session API.",
+        'description' => "A session ID. The value is generated by Drupal's session handlers.",
         'type' => 'varchar',
         'length' => 128,
         'not null' => TRUE,
-        'default' => '',
       ),
       'ssid' => array(
-        'description' => "Secure session ID. The value is generated by PHP's Session API.",
+        'description' => "Secure session ID. The value is generated by Drupal's session handlers.",
         'type' => 'varchar',
         'length' => 128,
         'not null' => TRUE,
@@ -1618,7 +1630,7 @@ function system_schema() {
         'default' => '',
       ),
       'language' => array(
-        'description' => 'The language this alias is for; if blank, the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.',
+        'description' => "The language this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
@@ -1706,8 +1718,9 @@ function system_update_dependencies() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x System updates from 6.x to 7.x
+ * @defgroup updates-6.x-to-7.x Updates from 6.x to 7.x
  * @{
+ * Update functions from 6.x to 7.x.
  */
 
 /**
@@ -2085,10 +2098,10 @@ function system_update_7018() {
 }
 
 /**
- * Enable field module.
+ * Enable field and field_ui modules.
  */
 function system_update_7020() {
-  $module_list = array('field_sql_storage', 'field');
+  $module_list = array('field_sql_storage', 'field', 'field_ui');
   module_enable($module_list, FALSE);
 }
 
@@ -2102,21 +2115,6 @@ function system_update_7021() {
     ->execute();
 }
 
-/**
- * Add the substr_index() function to PostgreSQL.
- *
- * Note: this should go into the driver itself, but we have no support
- * for driver-specific updates yet.
- */
-function system_update_7024() {
-  if (db_driver() == 'pgsql') {
-    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);\'
-      LANGUAGE \'sql\''
-    );
-  }
-}
-
 /**
  * Enable field type modules.
  */
@@ -2158,7 +2156,7 @@ function system_update_7033() {
 }
 
 /**
- * Migrate the file_downloads setting and create the new {file_managed} table.
+ * Migrate the file path settings and create the new {file_managed} table.
  */
 function system_update_7034() {
   $files_directory = variable_get('file_directory_path', NULL);
@@ -2773,93 +2771,94 @@ function system_update_7061(&$sandbox) {
     $sandbox['max'] = db_query("SELECT COUNT(*) FROM {system_update_7061}")->fetchField();
   }
 
-  $node_revisions = array();
-
   // Determine vids for this batch.
   // Process all files attached to a given revision during the same batch.
-  $limit = 100;
+  $limit = variable_get('upload_update_batch_size', 100);
   $vids = db_query_range('SELECT vid FROM {system_update_7061} WHERE vid > :lastvid ORDER BY vid', 0, $limit, array(':lastvid' => $sandbox['last_vid_processed']))
     ->fetchCol();
 
   // Retrieve information on all the files attached to these revisions.
-  $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(':vids' => $vids));
-  foreach ($result as $record) {
-    // For each uploaded file, retrieve the corresponding data from the old
-    // files table (since upload doesn't know about the new entry in the
-    // file_managed table).
-    $file = db_select('files', 'f')
-      ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
-      ->condition('f.fid', $record->fid)
-      ->execute()
-      ->fetchAssoc();
-    if (!$file) {
-      continue;
-    }
-
-    // Add in the file information from the upload table.
-    $file['description'] = $record->description;
-    $file['display'] = $record->list;
-
-    // Create one record for each revision that contains all the uploaded files.
-    $node_revisions[$record->vid]['nid'] = $record->nid;
-    $node_revisions[$record->vid]['vid'] = $record->vid;
-    $node_revisions[$record->vid]['type'] = $record->type;
-    $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
-  }
-
-  // Now that we know which files belong to which revisions, update the files'
-  // database entries, and save a reference to each file in the upload field on
-  // their node revisions.
-  $basename = variable_get('file_directory_path', conf_path() . '/files');
-  $scheme = file_default_scheme() . '://';
-  foreach ($node_revisions as $vid => $revision) {
-    foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {
-      // We will convert filepaths to uri using the default scheme
-      // and stripping off the existing file directory path.
-      $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']);
-      $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
-      unset($file['filepath']);
-      // Insert into the file_managed table.
-      // Each fid should only be stored once in file_managed.
-      db_merge('file_managed')
-        ->key(array(
-          'fid' => $file['fid'],
-        ))
-        ->fields(array(
-          'uid' => $file['uid'],
-          'filename' => $file['filename'],
-          'uri' => $file['uri'],
-          'filemime' => $file['filemime'],
-          'filesize' => $file['filesize'],
-          'status' => $file['status'],
-          'timestamp' => $file['timestamp'],
-        ))
-        ->execute();
+  if (!empty($vids)) {
+    $node_revisions = array();
+    $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(':vids' => $vids));
+    foreach ($result as $record) {
+      // For each uploaded file, retrieve the corresponding data from the old
+      // files table (since upload doesn't know about the new entry in the
+      // file_managed table).
+      $file = db_select('files', 'f')
+        ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
+        ->condition('f.fid', $record->fid)
+        ->execute()
+        ->fetchAssoc();
+      if (!$file) {
+        continue;
+      }
 
-      // Add the usage entry for the file.
-      $file = (object) $file;
-      file_usage_add($file, 'file', 'node', $revision['nid']);
+      // Add in the file information from the upload table.
+      $file['description'] = $record->description;
+      $file['display'] = $record->list;
 
-      // Update the node revision's upload file field with the file data.
-      $revision['file'][LANGUAGE_NONE][$delta] = array('fid' => $file->fid, 'display' => $file->display, 'description' => $file->description);
+      // Create one record for each revision that contains all the uploaded
+      // files.
+      $node_revisions[$record->vid]['nid'] = $record->nid;
+      $node_revisions[$record->vid]['vid'] = $record->vid;
+      $node_revisions[$record->vid]['type'] = $record->type;
+      $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
     }
 
-    // Write the revision's upload field data into the field_upload tables.
-    $node = (object) $revision;
-    _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);
+    // Now that we know which files belong to which revisions, update the
+    // files'// database entries, and save a reference to each file in the
+    // upload field on their node revisions.
+    $basename = variable_get('file_directory_path', conf_path() . '/files');
+    $scheme = file_default_scheme() . '://';
+    foreach ($node_revisions as $vid => $revision) {
+      foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {
+        // We will convert filepaths to uri using the default scheme
+        // and stripping off the existing file directory path.
+        $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']);
+        $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
+        unset($file['filepath']);
+        // Insert into the file_managed table.
+        // Each fid should only be stored once in file_managed.
+        db_merge('file_managed')
+          ->key(array(
+            'fid' => $file['fid'],
+          ))
+          ->fields(array(
+            'uid' => $file['uid'],
+            'filename' => $file['filename'],
+            'uri' => $file['uri'],
+            'filemime' => $file['filemime'],
+            'filesize' => $file['filesize'],
+            'status' => $file['status'],
+            'timestamp' => $file['timestamp'],
+          ))
+          ->execute();
+
+        // Add the usage entry for the file.
+        $file = (object) $file;
+        file_usage_add($file, 'file', 'node', $revision['nid']);
+
+        // Update the node revision's upload file field with the file data.
+        $revision['file'][LANGUAGE_NONE][$delta] = array('fid' => $file->fid, 'display' => $file->display, 'description' => $file->description);
+      }
+
+      // Write the revision's upload field data into the field_upload tables.
+      $node = (object) $revision;
+      _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);
 
-    // Update our progress information for the batch update.
-    $sandbox['progress']++;
-    $sandbox['last_vid_processed'] = $vid;
+      // Update our progress information for the batch update.
+      $sandbox['progress']++;
+      $sandbox['last_vid_processed'] = $vid;
+    }
   }
 
   // If less than limit node revisions were processed, the update process is
   // finished.
-  if (count($node_revisions) < $limit) {
+  if (count($vids) < $limit) {
     $finished = TRUE;
   }
 
-
   // If there's no max value then there's nothing to update and we're finished.
   if (empty($sandbox['max']) || isset($finished)) {
     db_drop_table('upload');
@@ -2901,6 +2900,78 @@ function system_update_7064() {
   db_drop_field('menu_router', 'block_callback');
 }
 
+/**
+ * Remove the default value for sid.
+ */
+function system_update_7065() {
+  $spec = array(
+    'description' => "A session ID. The value is generated by Drupal's session handlers.",
+    'type' => 'varchar',
+    'length' => 128,
+    'not null' => TRUE,
+  );
+  db_drop_primary_key('sessions');
+  db_change_field('sessions', 'sid', 'sid', $spec, array('primary key' => array('sid', 'ssid')));
+  // Delete any sessions with empty session ID.
+  db_delete('sessions')->condition('sid', '')->execute();
+}
+
+/**
+ * Migrate the 'file_directory_temp' variable.
+ */
+function system_update_7066() {
+  $d6_file_directory_temp = variable_get('file_directory_temp', file_directory_temp());
+  variable_set('file_temporary_path', $d6_file_directory_temp);
+  variable_del('file_directory_temp');
+}
+
+/**
+ * Grant administrators permission to view the administration theme.
+ */
+function system_update_7067() {
+  // Users with access to administration pages already see the administration
+  // theme in some places (if one is enabled on the site), so we want them to
+  // continue seeing it.
+  $admin_roles = user_roles(FALSE, 'access administration pages');
+  foreach (array_keys($admin_roles) as $rid) {
+    _update_7000_user_role_grant_permissions($rid, array('view the administration theme'), 'system');
+  }
+  // The above check is not guaranteed to reach all administrative users of the
+  // site, so if the site is currently using an administration theme, display a
+  // message also.
+  if (variable_get('admin_theme')) {
+    if (empty($admin_roles)) {
+      drupal_set_message('The new "View the administration theme" permission is required in order to view your site\'s administration theme. You can grant this permission to your site\'s administrators on the <a href="' . url('admin/people/permissions', array('fragment' => 'module-system')) . '">permissions page</a>.');
+    }
+    else {
+      drupal_set_message('The new "View the administration theme" permission is required in order to view your site\'s administration theme. This permission has been automatically granted to the following roles: <em>' . check_plain(implode(', ', $admin_roles)) . '</em>. You can grant this permission to other roles on the <a href="' . url('admin/people/permissions', array('fragment' => 'module-system')) . '">permissions page</a>.');
+    }
+  }
+}
+
+/**
+ * Update {url_alias}.language description.
+ */
+function system_update_7068() {
+  $spec = array(
+    'description' => "The language this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
+    'type' => 'varchar',
+    'length' => 12,
+    'not null' => TRUE,
+    'default' => '',
+  );
+  db_change_field('url_alias', 'language', 'language', $spec);
+}
+
+/**
+ * Remove the obsolete 'site_offline' variable.
+ *
+ * @see update_fix_d7_requirements()
+ */
+function system_update_7069() {
+  variable_del('site_offline');
+}
+
 /**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
diff --git a/modules/system/system.menus.css b/modules/system/system.menus.css
index 98e8036642b46d1345020705ff84c5e1d3d6e888..a2b81b94542971e12eec60a60307cfd92b74e69d 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/09/25 02:28:14 dries Exp $ */
+/* $Id: system.menus.css,v 1.3 2010/11/05 01:25:33 dries Exp $ */
 
 /**
  * @file
@@ -44,14 +44,12 @@ td.menu-disabled {
 /**
  * Markup generated by theme_links().
  */
-ul.links {
-  margin: 0;
-  padding: 0;
-}
+ul.inline,
 ul.links.inline {
   display: inline;
+  padding-left: 0;
 }
-ul.links li {
+ul.inline li {
   display: inline;
   list-style-type: none;
   padding: 0 0.5em;
diff --git a/modules/system/system.module b/modules/system/system.module
index 0f219253a4fd9aa563734ed62973f1160e2cf8a8..383dc8a160550c441fa2effc0b2d06737f69c42d 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.module,v 1.983 2010/10/21 12:09:41 dries Exp $
+// $Id: system.module,v 1.1003 2011/01/04 00:56:23 webchick Exp $
 
 /**
  * @file
@@ -113,7 +113,7 @@ function system_help($path, $arg) {
       }
       return $output;
     case 'admin/modules/uninstall':
-      return '<p>' . t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it on the main <a href="@modules">Modules page</a>. Not all modules support this feature.', array('@modules' => url('admin/modules'))) . '</p>';
+      return '<p>' . t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it on the main <a href="@modules">Modules page</a>.', array('@modules' => url('admin/modules'))) . '</p>';
     case 'admin/structure/block/manage':
       if ($arg[4] == 'system' && $arg[5] == 'powered-by') {
         return '<p>' . t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') . '</p>';
@@ -124,6 +124,7 @@ function system_help($path, $arg) {
       if ($user->uid == 1) {
         return '<p>' . t('If you are upgrading to a newer version of Drupal or upgrading contributed modules or themes, you may need to run the <a href="@update-php">update script</a>.', array('@update-php' => $base_url . '/update.php')) . '</p>';
       }
+      break;
     case 'admin/config/system/actions':
     case 'admin/config/system/actions/manage':
       $output = '';
@@ -229,6 +230,10 @@ function system_permission() {
     'access site in maintenance mode' => array(
       'title' => t('Use the site in maintenance mode'),
     ),
+    'view the administration theme' => array(
+      'title' => t('View the administration theme'),
+      'description' => variable_get('admin_theme') ? '' : t('This is only used when the site is configured to use a separate administration theme on the <a href="@appearance-url">Appearance</a> page.', array('@appearance-url' => url('admin/appearance'))),
+    ),
     'access site reports' => array(
       'title' => t('View site reports'),
     ),
@@ -408,8 +413,8 @@ function system_element_info() {
   $types['checkbox'] = array(
     '#input' => TRUE,
     '#return_value' => 1,
-    '#process' => array('ajax_process_form'),
     '#theme' => 'checkbox',
+    '#process' => array('form_process_checkbox', 'ajax_process_form'),
     '#theme_wrappers' => array('form_element'),
     '#title_display' => 'after',
   );
@@ -543,8 +548,6 @@ function system_menu() {
     'page callback' => 'system_admin_menu_block_page',
     'weight' => 9,
     'menu_name' => 'management',
-    'theme callback' => 'variable_get',
-    'theme arguments' => array('admin_theme'),
     'file' => 'system.admin.inc',
   );
   $items['admin/compact'] = array(
@@ -1076,18 +1079,101 @@ function _system_batch_theme() {
  * Implements hook_library().
  */
 function system_library() {
+  // Drupal's AJAX framework.
+  $libraries['drupal.ajax'] = array(
+    'title' => 'Drupal AJAX',
+    'website' => 'http://api.drupal.org/api/drupal/includes--ajax.inc/group/ajax/7',
+    'version' => VERSION,
+    'js' => array(
+      'misc/ajax.js' => array('group' => JS_LIBRARY, 'weight' => 2),
+    ),
+    'dependencies' => array(
+      array('system', 'drupal.progress'),
+    ),
+  );
+
+  // Drupal's batch API.
+  $libraries['drupal.batch'] = array(
+    'title' => 'Drupal batch API',
+    'version' => VERSION,
+    'js' => array(
+      'misc/batch.js' => array('group' => JS_DEFAULT, 'cache' => FALSE),
+    ),
+    'dependencies' => array(
+      array('system', 'drupal.progress'),
+    ),
+  );
+
+  // Drupal's progress indicator.
+  $libraries['drupal.progress'] = array(
+    'title' => 'Drupal progress indicator',
+    'version' => VERSION,
+    'js' => array(
+      'misc/progress.js' => array('group' => JS_DEFAULT, 'cache' => FALSE),
+    ),
+  );
+
+  // Drupal's form library.
+  $libraries['drupal.form'] = array(
+    'title' => 'Drupal form library',
+    'version' => VERSION,
+    'js' => array(
+      'misc/form.js' => array('group' => JS_LIBRARY, 'weight' => 1),
+    ),
+  );
+
+  // Drupal's states library.
+  $libraries['drupal.states'] = array(
+    'title' => 'Drupal states',
+    'version' => VERSION,
+    'js' => array(
+      'misc/states.js' => array('group' => JS_LIBRARY, 'weight' => 1),
+    ),
+  );
+
+  // Drupal's collapsible fieldset.
+  $libraries['drupal.collapse'] = array(
+    'title' => 'Drupal collapsible fieldset',
+    'version' => VERSION,
+    'js' => array(
+      'misc/collapse.js' => array('group' => JS_DEFAULT),
+    ),
+    'dependencies' => array(
+      // collapse.js relies on drupalGetSummary in form.js
+      array('system', 'drupal.form'),
+    ),
+  );
+
+  // Drupal's resizable textarea.
+  $libraries['drupal.textarea'] = array(
+    'title' => 'Drupal resizable textarea',
+    'version' => VERSION,
+    'js' => array(
+      'misc/textarea.js' => array('group' => JS_DEFAULT),
+    ),
+  );
+
+  // Drupal's autocomplete widget.
+  $libraries['drupal.autocomplete'] = array(
+    'title' => 'Drupal autocomplete',
+    'version' => VERSION,
+    'js' => array(
+      'misc/autocomplete.js' => array('group' => JS_DEFAULT),
+    ),
+  );
+
   // jQuery.
   $libraries['jquery'] = array(
     'title' => 'jQuery',
     'website' => 'http://jquery.com',
-    'version' => '1.4.2',
+    'version' => '1.4.4',
     'js' => array(
       'misc/jquery.js' => array('group' => JS_LIBRARY, 'weight' => -20),
     ),
   );
 
   // jQuery Once.
-  $libraries['once'] = array(
+  $libraries['jquery.once'] = array(
     'title' => 'jQuery Once',
     'website' => 'http://plugins.jquery.com/project/once',
     'version' => '1.2',
@@ -1097,17 +1183,20 @@ function system_library() {
   );
 
   // jQuery Form Plugin.
-  $libraries['form'] = array(
+  $libraries['jquery.form'] = array(
     'title' => 'jQuery Form Plugin',
     'website' => 'http://malsup.com/jquery/form/',
-    'version' => '2.36',
+    'version' => '2.52',
     'js' => array(
       'misc/jquery.form.js' => array(),
     ),
+    'dependencies' => array(
+      array('system', 'jquery.cookie'),
+    ),
   );
 
   // jQuery BBQ plugin.
-  $libraries['jquery-bbq'] = array(
+  $libraries['jquery.bbq'] = array(
     'title' => 'jQuery BBQ',
     'website' => 'http://benalman.com/projects/jquery-bbq-plugin/',
     'version' => '1.2.1',
@@ -1117,7 +1206,7 @@ function system_library() {
   );
 
   // Vertical Tabs.
-  $libraries['vertical-tabs'] = array(
+  $libraries['drupal.vertical-tabs'] = array(
     'title' => 'Vertical Tabs',
     'website' => 'http://drupal.org/node/323112',
     'version' => '1.0',
@@ -1127,6 +1216,10 @@ function system_library() {
     'css' => array(
       'misc/vertical-tabs.css' => array(),
     ),
+    'dependencies' => array(
+      // Vertical tabs relies on drupalGetSummary in form.js
+      array('system', 'drupal.form'),
+    ),
   );
 
   // Farbtastic.
@@ -1143,7 +1236,7 @@ function system_library() {
   );
 
   // Cookie.
-  $libraries['cookie'] = array(
+  $libraries['jquery.cookie'] = array(
     'title' => 'Cookie',
     'website' => 'http://plugins.jquery.com/project/cookie',
     'version' => '1.0',
@@ -1156,7 +1249,7 @@ function system_library() {
   $libraries['ui'] = array(
     'title' => 'jQuery UI: Core',
     'website' => 'http://jqueryui.com',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -11),
     ),
@@ -1168,7 +1261,7 @@ function system_library() {
   $libraries['ui.accordion'] = array(
     'title' => 'jQuery UI: Accordion',
     'website' => 'http://jqueryui.com/demos/accordion/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.accordion.min.js' => array(),
     ),
@@ -1182,7 +1275,7 @@ function system_library() {
   $libraries['ui.autocomplete'] = array(
     'title' => 'jQuery UI: Autocomplete',
     'website' => 'http://jqueryui.com/demos/autocomplete/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.autocomplete.min.js' => array(),
     ),
@@ -1197,7 +1290,7 @@ function system_library() {
   $libraries['ui.button'] = array(
     'title' => 'jQuery UI: Button',
     'website' => 'http://jqueryui.com/demos/button/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.button.min.js' => array(),
     ),
@@ -1211,7 +1304,7 @@ function system_library() {
   $libraries['ui.datepicker'] = array(
     'title' => 'jQuery UI: Date Picker',
     'website' => 'http://jqueryui.com/demos/datepicker/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.datepicker.min.js' => array(),
     ),
@@ -1225,7 +1318,7 @@ function system_library() {
   $libraries['ui.dialog'] = array(
     'title' => 'jQuery UI: Dialog',
     'website' => 'http://jqueryui.com/demos/dialog/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.dialog.min.js' => array(),
     ),
@@ -1244,7 +1337,7 @@ function system_library() {
   $libraries['ui.draggable'] = array(
     'title' => 'jQuery UI: Draggable',
     'website' => 'http://jqueryui.com/demos/draggable/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.draggable.min.js' => array(),
     ),
@@ -1256,7 +1349,7 @@ function system_library() {
   $libraries['ui.droppable'] = array(
     'title' => 'jQuery UI: Droppable',
     'website' => 'http://jqueryui.com/demos/droppable/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.droppable.min.js' => array(),
     ),
@@ -1269,7 +1362,7 @@ function system_library() {
   $libraries['ui.mouse'] = array(
     'title' => 'jQuery UI: Droppable',
     'website' => 'http://docs.jquery.com/UI/Mouse',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.mouse.min.js' => array(),
     ),
@@ -1280,7 +1373,7 @@ function system_library() {
   $libraries['ui.position'] = array(
     'title' => 'jQuery UI: Position',
     'website' => 'http://jqueryui.com/demos/position/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.position.min.js' => array(),
     ),
@@ -1288,7 +1381,7 @@ function system_library() {
   $libraries['ui.progressbar'] = array(
     'title' => 'jQuery UI: Progress Bar',
     'website' => 'http://jqueryui.com/demos/progressbar/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.progressbar.min.js' => array(),
     ),
@@ -1302,7 +1395,7 @@ function system_library() {
   $libraries['ui.resizable'] = array(
     'title' => 'jQuery UI: Resizable',
     'website' => 'http://jqueryui.com/demos/resizable/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.resizable.min.js' => array(),
     ),
@@ -1317,7 +1410,7 @@ function system_library() {
   $libraries['ui.selectable'] = array(
     'title' => 'jQuery UI: Selectable',
     'website' => 'http://jqueryui.com/demos/selectable/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.selectable.min.js' => array(),
     ),
@@ -1332,7 +1425,7 @@ function system_library() {
   $libraries['ui.slider'] = array(
     'title' => 'jQuery UI: Slider',
     'website' => 'http://jqueryui.com/demos/slider/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.slider.min.js' => array(),
     ),
@@ -1347,7 +1440,7 @@ function system_library() {
   $libraries['ui.sortable'] = array(
     'title' => 'jQuery UI: Sortable',
     'website' => 'http://jqueryui.com/demos/sortable/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.sortable.min.js' => array(),
     ),
@@ -1359,7 +1452,7 @@ function system_library() {
   $libraries['ui.tabs'] = array(
     'title' => 'jQuery UI: Tabs',
     'website' => 'http://jqueryui.com/demos/tabs/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.tabs.min.js' => array(),
     ),
@@ -1373,7 +1466,7 @@ function system_library() {
   $libraries['ui.widget'] = array(
     'title' => 'jQuery UI: Widget',
     'website' => 'http://docs.jquery.com/UI/Widget',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.ui.widget.min.js' => array('group' => JS_LIBRARY, 'weight' => -10),
     ),
@@ -1384,7 +1477,7 @@ function system_library() {
   $libraries['effects'] = array(
     'title' => 'jQuery UI: Effects',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -9),
     ),
@@ -1392,7 +1485,7 @@ function system_library() {
   $libraries['effects.blind'] = array(
     'title' => 'jQuery UI: Effects Blind',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.blind.min.js' => array(),
     ),
@@ -1403,7 +1496,7 @@ function system_library() {
   $libraries['effects.bounce'] = array(
     'title' => 'jQuery UI: Effects Bounce',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.bounce.min.js' => array(),
     ),
@@ -1414,7 +1507,7 @@ function system_library() {
   $libraries['effects.clip'] = array(
     'title' => 'jQuery UI: Effects Clip',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.clip.min.js' => array(),
     ),
@@ -1425,7 +1518,7 @@ function system_library() {
   $libraries['effects.drop'] = array(
     'title' => 'jQuery UI: Effects Drop',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.drop.min.js' => array(),
     ),
@@ -1436,7 +1529,7 @@ function system_library() {
   $libraries['effects.explode'] = array(
     'title' => 'jQuery UI: Effects Explode',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.explode.min.js' => array(),
     ),
@@ -1447,7 +1540,7 @@ function system_library() {
   $libraries['effects.fade'] = array(
     'title' => 'jQuery UI: Effects Fade',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.fade.min.js' => array(),
     ),
@@ -1458,7 +1551,7 @@ function system_library() {
   $libraries['effects.fold'] = array(
     'title' => 'jQuery UI: Effects Fold',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.fold.min.js' => array(),
     ),
@@ -1469,7 +1562,7 @@ function system_library() {
   $libraries['effects.highlight'] = array(
     'title' => 'jQuery UI: Effects Highlight',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.highlight.min.js' => array(),
     ),
@@ -1480,7 +1573,7 @@ function system_library() {
   $libraries['effects.pulsate'] = array(
     'title' => 'jQuery UI: Effects Pulsate',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.pulsate.min.js' => array(),
     ),
@@ -1491,7 +1584,7 @@ function system_library() {
   $libraries['effects.scale'] = array(
     'title' => 'jQuery UI: Effects Scale',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.scale.min.js' => array(),
     ),
@@ -1502,7 +1595,7 @@ function system_library() {
   $libraries['effects.shake'] = array(
     'title' => 'jQuery UI: Effects Shake',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.shake.min.js' => array(),
     ),
@@ -1513,7 +1606,7 @@ function system_library() {
   $libraries['effects.slide'] = array(
     'title' => 'jQuery UI: Effects Slide',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.slide.min.js' => array(),
     ),
@@ -1524,7 +1617,7 @@ function system_library() {
   $libraries['effects.transfer'] = array(
     'title' => 'jQuery UI: Effects Transfer',
     'website' => 'http://jqueryui.com/demos/effect/',
-    'version' => '1.8',
+    'version' => '1.8.7',
     'js' => array(
       'misc/ui/jquery.effects.transfer.min.js' => array(),
     ),
@@ -1533,6 +1626,15 @@ function system_library() {
     ),
   );
 
+  // These library names are deprecated. Earlier versions of Drupal 7 didn't
+  // consistently namespace their libraries, so these names are included for
+  // backwards compatibility with those versions.
+  $libraries['once'] = &$libraries['jquery.once'];
+  $libraries['form'] = &$libraries['jquery.form'];
+  $libraries['jquery-bbq'] = &$libraries['jquery.bbq'];
+  $libraries['vertical-tabs'] = &$libraries['drupal.vertical-tabs'];
+  $libraries['cookie'] = &$libraries['jquery.cookie'];
+
   return $libraries;
 }
 
@@ -1626,7 +1728,7 @@ function _system_themes_access($theme) {
  *
  * @see authorize.php
  * @see FileTransfer
- * @see hook_filetransfer_backends()
+ * @see hook_filetransfer_info()
  */
 
 /**
@@ -1657,7 +1759,7 @@ function system_authorized_init($callback, $file, $arguments = array(), $page_ti
   // First, figure out what file transfer backends the site supports, and put
   // all of those in the SESSION so that authorize.php has access to all of
   // them via the class autoloader, even without a full bootstrap.
-  $_SESSION['authorize_filetransfer_backends'] = module_invoke_all('filetransfer_backends');
+  $_SESSION['authorize_filetransfer_info'] = drupal_get_filetransfer_info();
 
   // Now, define the callback to invoke.
   $_SESSION['authorize_operation'] = array(
@@ -1732,9 +1834,9 @@ function system_updater_info() {
 }
 
 /**
- * Implements hook_filetransfer_backends().
+ * Implements hook_filetransfer_info().
  */
-function system_filetransfer_backends() {
+function system_filetransfer_info() {
   $backends = array();
 
   // This is the default, will be available on most systems.
@@ -1742,7 +1844,8 @@ function system_filetransfer_backends() {
     $backends['ftp'] = array(
       'title' => t('FTP'),
       'class' => 'FileTransferFTP',
-      'settings_form' => 'system_filetransfer_backend_form_ftp',
+      'file' => 'ftp.inc',
+      'file path' => 'includes/filetransfer',
       'weight' => 0,
     );
   }
@@ -1753,85 +1856,14 @@ function system_filetransfer_backends() {
     $backends['ssh'] = array(
       'title' => t('SSH'),
       'class' => 'FileTransferSSH',
-      'settings_form' => 'system_filetransfer_backend_form_ssh',
+      'file' => 'ssh.inc',
+      'file path' => 'includes/filetransfer',
       'weight' => 20,
     );
   }
   return $backends;
 }
 
-/**
- *  Helper function to return a form for configuring a filetransfer backend.
- *
- * @param string $filetransfer_backend_name
- *   The name of the backend to return a form for.
- *
- * @param string $defaults
- *   An associative array of settings to pre-populate the form with.
- */
-function system_get_filetransfer_settings_form($filetransfer_backend_name, $defaults) {
-  $available_backends = module_invoke_all('filetransfer_backends');
-  $form = call_user_func($available_backends[$filetransfer_backend_name]['settings_form']);
-
-  foreach ($form as $name => &$element) {
-    if (isset($defaults[$name])) {
-      $element['#default_value'] = $defaults[$name];
-    }
-  }
-  return $form;
-}
-
-/**
- * Returns the form to configure the filetransfer class for FTP
- */
-function system_filetransfer_backend_form_ftp() {
-  $form = _system_filetransfer_backend_form_common();
-  $form['advanced']['port']['#default_value'] = 21;
-  return $form;
-}
-
-/**
- * Returns the form to configure the filetransfer class for SSH
- */
-function system_filetransfer_backend_form_ssh() {
-  $form = _system_filetransfer_backend_form_common();
-  $form['advanced']['port']['#default_value'] = 22;
-  return $form;
-}
-
-/**
- * Helper function because SSH and FTP backends share the same elements
- */
-function _system_filetransfer_backend_form_common() {
-  $form['username'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Username'),
-  );
-  $form['password'] = array(
-    '#type' => 'password',
-    '#title' => t('Password'),
-    '#description' => t('Your password is not saved in the database and is only used to establish a connection.'),
-  );
-  $form['advanced'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced settings'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $form['advanced']['hostname'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Host'),
-    '#default_value' => 'localhost',
-    '#description' => t('The connection will be created between your web server and the machine hosting the web server files. In the vast majority of cases, this will be the same machine, and "localhost" is correct.'),
-  );
-  $form['advanced']['port'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Port'),
-    '#default_value' => NULL,
-  );
-  return $form;
-}
-
 /**
  * Implements hook_init().
  */
@@ -1840,7 +1872,7 @@ function system_init() {
   // Add the CSS for this module. These aren't in system.info, because they
   // need to be in the CSS_SYSTEM group rather than the CSS_DEFAULT group.
   drupal_add_css($path . '/system.base.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
-  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit' || arg(2) == 'delete'))) {
+  if (path_is_admin(current_path())) {
     drupal_add_css($path . '/system.admin.css', array('group' => CSS_SYSTEM));
   }
   drupal_add_css($path . '/system.menus.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
@@ -1893,6 +1925,15 @@ function system_add_module_assets() {
   }
 }
 
+/**
+ * Implements hook_custom_theme().
+ */
+function system_custom_theme() {
+  if (user_access('view the administration theme') && path_is_admin(current_path())) {
+    return variable_get('admin_theme');
+  }
+}
+
 /**
  * Implements hook_form_FORM_ID_alter().
  */
@@ -2284,7 +2325,7 @@ function system_get_info($type, $name = NULL) {
  */
 function _system_rebuild_module_data() {
   // Find modules
-  $modules = drupal_system_listing('/\.module$/', 'modules', 'name', 0);
+  $modules = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0);
 
   // Include the install profile in modules that are loaded.
   $profile = drupal_get_profile();
@@ -2361,12 +2402,19 @@ function _system_rebuild_module_data() {
  *   Array of all available modules and their data.
  */
 function system_rebuild_module_data() {
-  $modules = _system_rebuild_module_data();
-  ksort($modules);
-  system_get_files_database($modules, 'module');
-  system_update_files_database($modules, 'module');
-  $modules = _module_build_dependencies($modules);
-  return $modules;
+  $modules_cache = &drupal_static(__FUNCTION__);
+  // Only rebuild once per request. $modules and $modules_cache cannot be
+  // combined into one variable, because the $modules_cache variable is reset by
+  // reference from system_list_reset() during the rebuild.
+  if (!isset($modules_cache)) {
+    $modules = _system_rebuild_module_data();
+    ksort($modules);
+    system_get_files_database($modules, 'module');
+    system_update_files_database($modules, 'module');
+    $modules = _module_build_dependencies($modules);
+    $modules_cache = $modules;
+  }
+  return $modules_cache;
 }
 
 /**
@@ -2404,12 +2452,13 @@ function _system_update_bootstrap_status() {
  */
 function _system_rebuild_theme_data() {
   // Find themes
-  $themes = drupal_system_listing('/\.info$/', 'themes');
+  $themes = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes');
   // Find theme engines
-  $engines = drupal_system_listing('/\.engine$/', 'themes/engines');
+  $engines = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.engine$/', 'themes/engines');
 
   // Set defaults for theme info.
   $defaults = array(
+    'engine' => 'phptemplate',
     'regions' => array(
       'sidebar_first' => 'Left sidebar',
       'sidebar_second' => 'Right sidebar',
@@ -2443,7 +2492,7 @@ function _system_rebuild_theme_data() {
     if (!empty($themes[$key]->info['base theme'])) {
       $sub_themes[] = $key;
     }
-    if (empty($themes[$key]->info['engine'])) {
+    if ($themes[$key]->info['engine'] == 'theme') {
       $filename = dirname($themes[$key]->uri) . '/' . $themes[$key]->name . '.theme';
       if (file_exists($filename)) {
         $themes[$key]->owner = $filename;
@@ -2883,7 +2932,7 @@ function system_get_module_admin_tasks($module, $info) {
           }
           if ($parent = menu_link_load($admin_tasks[$duplicate_path]['plid'])) {
             // Append the parent item's title to the duplicated task's title.
-            // We use $links[$duplicate_path] in case there are triplicates. 
+            // We use $links[$duplicate_path] in case there are triplicates.
             $admin_tasks[$duplicate_path]['title'] = t('@original_title (@parent_title)', array('@original_title' => $links[$duplicate_path]['title'], '@parent_title' => $parent['title']));
           }
         }
@@ -3413,22 +3462,34 @@ function system_run_automated_cron() {
 }
 
 /**
- * Get the list of available date types and attributes.
+ * Gets the list of available date types and attributes.
  *
  * @param $type
- *   The date type, e.g. 'short', 'medium', 'long', 'custom'. If empty, then
- *   all attributes for that type will be returned.
+ *   (optional) The date type name.
+ *
  * @return
- *   Array of date types.
+ *   An associative array of date type information keyed by the date type name.
+ *   Each date type information array has the following elements:
+ *   - type: The machine-readable name of the date type.
+ *   - title: The human-readable name of the date type.
+ *   - locked: A boolean indicating whether or not this date type should be
+ *     configurable from the user interface.
+ *   - module: The name of the module that defined this date type in its
+ *     hook_date_format_types(). An empty string if the date type was
+ *     user-defined.
+ *   - is_new: A boolean indicating whether or not this date type is as of yet
+ *     unsaved in the database.
+ *   If $type was defined, only a single associative array with the above
+ *   elements is returned.
  */
 function system_get_date_types($type = NULL) {
-  $date_format_types = &drupal_static(__FUNCTION__);
+  $types = &drupal_static(__FUNCTION__);
 
-  if (!isset($date_format_types)) {
-    $date_format_types = _system_date_format_types_build();
+  if (!isset($types)) {
+    $types = _system_date_format_types_build();
   }
 
-  return $type ? (isset($date_format_types[$type]) ? $date_format_types[$type] : FALSE) : $date_format_types;
+  return $type ? (isset($types[$type]) ? $types[$type] : FALSE) : $types;
 }
 
 /**
@@ -3444,12 +3505,6 @@ function system_date_format_types() {
 
 /**
  * Implements hook_date_formats().
- *
- * @return
- *   An array of date formats with attributes 'type' (short, medium or long),
- *   'format' (the format string) and 'locales'. The 'locales' attribute is an
- *   array of locales, which can include both 2 character language codes like
- *   'en', 'fr', but also 5 character language codes like 'en-gb' and 'en-us'.
  */
 function system_date_formats() {
   include_once DRUPAL_ROOT . '/includes/date.inc';
@@ -3457,13 +3512,29 @@ function system_date_formats() {
 }
 
 /**
- * Get the list of date formats for a particular format length.
+ * Gets the list of defined date formats and attributes.
  *
  * @param $type
- *   The date type: 'short', 'medium', 'long', 'custom'. If empty, then all
- *   available types will be returned.
+ *   (optional) The date type name.
+ *
  * @return
- *   Array of date formats.
+ *   An associative array of date formats. The top-level keys are the names of
+ *   the date types that the date formats belong to. The values are in turn
+ *   associative arrays keyed by the format string, with the following keys:
+ *   - dfid: The date format ID.
+ *   - format: The format string.
+ *   - type: The machine-readable name of the date type.
+ *   - locales: An array of language codes. This can include both 2 character
+ *     language codes like 'en and 'fr' and 5 character language codes like
+ *     'en-gb' and 'en-us'.
+ *   - locked: A boolean indicating whether or not this date type should be
+ *     configurable from the user interface.
+ *   - module: The name of the module that defined this date format in its
+ *     hook_date_formats(). An empty string if the format was user-defined.
+ *   - is_new: A boolean indicating whether or not this date type is as of yet
+ *     unsaved in the database.
+ *   If $type was defined, only the date formats associated with the given date
+ *   type are returned, in a single associative array keyed by format string.
  */
 function system_get_date_formats($type = NULL) {
   $date_formats = &drupal_static(__FUNCTION__);
@@ -3476,25 +3547,30 @@ function system_get_date_formats($type = NULL) {
 }
 
 /**
- * Get the format details for a particular id.
+ * Gets the format details for a particular format ID.
  *
  * @param $dfid
- *   Identifier of a date format string.
+ *   A date format ID.
+ *
  * @return
- *   Array of date format details.
+ *   A date format object with the following properties:
+ *   - dfid: The date format ID.
+ *   - format: The date format string.
+ *   - type: The name of the date type.
+ *   - locked: Whether the date format can be changed or not.
  */
 function system_get_date_format($dfid) {
   return db_query('SELECT df.dfid, df.format, df.type, df.locked FROM {date_formats} df WHERE df.dfid = :dfid', array(':dfid' => $dfid))->fetch();
 }
 
 /**
- * Resets the database cache of date formats and saves all new formats.
+ * Resets the database cache of date formats and saves all new date formats.
  */
 function system_date_formats_rebuild() {
   drupal_static_reset('system_get_date_formats');
   $date_formats = system_get_date_formats(NULL);
 
-  foreach ($date_formats as $format_type => $formats) {
+  foreach ($date_formats as $type => $formats) {
     foreach ($formats as $format => $info) {
       system_date_format_save($info);
     }
@@ -3508,15 +3584,20 @@ function system_date_formats_rebuild() {
 }
 
 /**
- * Get the appropriate date format for a type and locale.
+ * Gets the appropriate date format string for a date type and locale.
  *
  * @param $langcode
- *   Language code for the current locale. This can be a 2 character language
- *   code like 'en', 'fr', or a longer 5 character code like 'en-gb'.
+ *   (optional) Language code for the current locale. This can be a 2 character
+ *   language code like 'en' and 'fr' or a 5 character language code like
+ *   'en-gb' and 'en-us'.
  * @param $type
- *   Date type: short, medium, long, custom.
+ *   (optional) The date type name.
+ *
  * @return
- *   The format string, or NULL if no matching format found.
+ *   If $type and $langcode are specified, returns the corresponding date format
+ *   string. If only $langcode is specified, returns an array of all date
+ *   format strings for that locale, keyed by the date type. If neither is
+ *   specified, or if no matching formats are found, returns FALSE.
  */
 function system_date_format_locale($langcode = NULL, $type = NULL) {
   $formats = &drupal_static(__FUNCTION__);
@@ -3543,10 +3624,19 @@ function system_date_format_locale($langcode = NULL, $type = NULL) {
 }
 
 /**
- * Builds and returns the list of available date types.
+ * Builds and returns information about available date types.
  *
  * @return
- *   Array of date types.
+ *   An associative array of date type information keyed by name. Each date type
+ *   information array has the following elements:
+ *   - type: The machine-readable name of the date type.
+ *   - title: The human-readable name of the date type.
+ *   - locked: A boolean indicating whether or not this date type should be
+ *     configurable from the user interface.
+ *   - module: The name of the module that defined this format in its
+ *     hook_date_format_types(). An empty string if the format was user-defined.
+ *   - is_new: A boolean indicating whether or not this date type is as of yet
+ *     unsaved in the database.
  */
 function _system_date_format_types_build() {
   $types = array();
@@ -3562,7 +3652,8 @@ function _system_date_format_types_build() {
       $type['type'] = $module_type;
       $type['title'] = $type_title;
       $type['locked'] = 1;
-      $type['is_new'] = TRUE; // Will be over-ridden later if in the db.
+      // Will be over-ridden later if in the db.
+      $type['is_new'] = TRUE;
       $types[$module_type] = $type;
     }
   }
@@ -3570,7 +3661,7 @@ function _system_date_format_types_build() {
   // Get custom formats added to the database by the end user.
   $result = db_query('SELECT dft.type, dft.title, dft.locked FROM {date_format_type} dft ORDER BY dft.title');
   foreach ($result as $record) {
-    if (!in_array($record->type, $types)) {
+    if (!isset($types[$record->type])) {
       $type = array();
       $type['is_new'] = FALSE;
       $type['module'] = '';
@@ -3593,10 +3684,24 @@ function _system_date_format_types_build() {
 }
 
 /**
- * Builds and returns the list of available date formats.
+ * Builds and returns information about available date formats.
  *
  * @return
- *   Array of date formats.
+ *   An associative array of date formats. The top-level keys are the names of
+ *   the date types that the date formats belong to. The values are in turn
+ *   associative arrays keyed by format with the following keys:
+ *   - dfid: The date format ID.
+ *   - format: The PHP date format string.
+ *   - type: The machine-readable name of the date type the format belongs to.
+ *   - locales: An array of language codes. This can include both 2 character
+ *     language codes like 'en and 'fr' and 5 character language codes like
+ *     'en-gb' and 'en-us'.
+ *   - locked: A boolean indicating whether or not this date type should be
+ *     configurable from the user interface.
+ *   - module: The name of the module that defined this format in its
+ *     hook_date_formats(). An empty string if the format was user-defined.
+ *   - is_new: A boolean indicating whether or not this date type is as of yet
+ *     unsaved in the database.
  */
 function _system_date_formats_build() {
   $date_formats = array();
@@ -3611,7 +3716,8 @@ function _system_date_formats_build() {
   $module_formats = module_invoke_all('date_formats');
 
   foreach ($module_formats as $module_format) {
-    $module_format['locked'] = 1; // System types are locked.
+    // System types are locked.
+    $module_format['locked'] = 1;
     // If no date type is specified, assign 'custom'.
     if (!isset($module_format['type'])) {
       $module_format['type'] = 'custom';
@@ -3625,7 +3731,7 @@ function _system_date_formats_build() {
 
     // If another module already set this format, merge in the new settings.
     if (isset($date_formats[$module_format['type']][$module_format['format']])) {
-      $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $format);
+      $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $module_format);
     }
     else {
       // This setting will be overridden later if it already exists in the db.
@@ -3665,67 +3771,80 @@ function _system_date_formats_build() {
 }
 
 /**
- * Save a date type to the database.
+ * Saves a date type to the database.
  *
- * @param $date_format_type
- *   An array of attributes for a date type.
- */
-function system_date_format_type_save($date_format_type) {
-  $type = array();
-  $type['type'] = $date_format_type['type'];
-  $type['title'] = $date_format_type['title'];
-  $type['locked'] = $date_format_type['locked'];
+ * @param $type
+ *   A date type array containing the following keys:
+ *   - type: The machine-readable name of the date type.
+ *   - title: The human-readable name of the date type.
+ *   - locked: A boolean indicating whether or not this date type should be
+ *     configurable from the user interface.
+ *   - is_new: A boolean indicating whether or not this date type is as of yet
+ *     unsaved in the database.
+ */
+function system_date_format_type_save($type) {
+  $info = array();
+  $info['type'] = $type['type'];
+  $info['title'] = $type['title'];
+  $info['locked'] = $type['locked'];
 
   // Update date_format table.
-  if (!empty($date_format_type['is_new'])) {
-    drupal_write_record('date_format_type', $type);
+  if (!empty($type['is_new'])) {
+    drupal_write_record('date_format_type', $info);
   }
   else {
-    drupal_write_record('date_format_type', $type, 'type');
+    drupal_write_record('date_format_type', $info, 'type');
   }
 }
 
 /**
- * Delete a date type from the database.
+ * Deletes a date type from the database.
  *
- * @param $date_format_type
- *   The date type name.
+ * @param $type
+ *   The machine-readable name of the date type.
  */
-function system_date_format_type_delete($date_format_type) {
+function system_date_format_type_delete($type) {
   db_delete('date_formats')
-    ->condition('type', $date_format_type)
+    ->condition('type', $type)
     ->execute();
   db_delete('date_format_type')
-    ->condition('type', $date_format_type)
+    ->condition('type', $type)
     ->execute();
   db_delete('date_format_locale')
-    ->condition('type', $date_format_type)
+    ->condition('type', $type)
     ->execute();
 }
 
 /**
- * Save a date format to the database.
+ * Saves a date format to the database.
  *
  * @param $date_format
- *   An array of attributes for a date format.
+ *   A date format array containing the following keys:
+ *   - type: The name of the date type this format is associated with.
+ *   - format: The PHP date format string.
+ *   - locked: A boolean indicating whether or not this format should be
+ *     configurable from the user interface.
  * @param $dfid
- *   If set, replace an existing date format with a new string using this
- *   identifier.
+ *   If set, replace the existing date format having this ID with the
+ *   information specified in $date_format.
+ *
+ * @see system_get_date_types()
+ * @see http://php.net/date
  */
 function system_date_format_save($date_format, $dfid = 0) {
-  $format = array();
-  $format['dfid'] = $dfid;
-  $format['type'] = $date_format['type'];
-  $format['format'] = $date_format['format'];
-  $format['locked'] = $date_format['locked'];
+  $info = array();
+  $info['dfid'] = $dfid;
+  $info['type'] = $date_format['type'];
+  $info['format'] = $date_format['format'];
+  $info['locked'] = $date_format['locked'];
 
   // Update date_format table.
   if (!empty($date_format['is_new'])) {
-    drupal_write_record('date_formats', $format);
+    drupal_write_record('date_formats', $info);
   }
   else {
     $keys = ($dfid ? array('dfid') : array('format', 'type'));
-    drupal_write_record('date_formats', $format, $keys);
+    drupal_write_record('date_formats', $info, $keys);
   }
 
   $languages = language_list('enabled');
@@ -3751,10 +3870,10 @@ function system_date_format_save($date_format, $dfid = 0) {
 }
 
 /**
- * Delete a date format from the database.
+ * Deletes a date format from the database.
  *
- * @param $date_format_id
- *   The date format string identifier.
+ * @param $dfid
+ *   The date format ID.
  */
 function system_date_format_delete($dfid) {
   db_delete('date_formats')
@@ -3848,6 +3967,9 @@ function system_admin_paths() {
     'admin' => TRUE,
     'admin/*' => TRUE,
     'batch' => TRUE,
+    // This page should not be treated as administrative since it outputs its
+    // own content (outside of any administration theme).
+    'admin/reports/status/php' => FALSE,
   );
   return $paths;
 }
diff --git a/modules/system/system.queue.inc b/modules/system/system.queue.inc
index 28f2dd790f3cedb733017bb208b81961ce7efc73..3460241d513cf10d172046c241d14a5cd8dc5048 100644
--- a/modules/system/system.queue.inc
+++ b/modules/system/system.queue.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.queue.inc,v 1.13 2010/06/14 13:10:31 dries Exp $
+// $Id: system.queue.inc,v 1.14 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -9,6 +9,8 @@
 /**
  * @defgroup queue Queue operations
  * @{
+ * Queue items to allow later processing.
+ *
  * The queue system allows placing items in a queue and processing them later.
  * The system tries to ensure that only one consumer can process an item.
  *
diff --git a/modules/system/system.test b/modules/system/system.test
index 74b8109c9153f961ed3bb99ca1aceb099246b029..2043544dd060bbcdb3d67b3d7b75d98cca4a36f1 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.test,v 1.149 2010/10/16 00:00:17 webchick Exp $
+// $Id: system.test,v 1.153 2010/12/01 00:23:36 webchick Exp $
 
 /**
  * Helper class for module test cases.
@@ -350,6 +350,40 @@ class ModuleDependencyTestCase extends ModuleTestCase {
     // Check the actual order which is saved by module_test_modules_enabled().
     $this->assertIdentical(variable_get('test_module_enable_order', FALSE), $expected_order, t('Modules enabled in the correct order.'));
   }
+
+  /**
+   * Tests attempting to uninstall a module that has installed dependents.
+   */
+  function testUninstallDependents() {
+    // Enable the forum module.
+    $edit = array('modules[Core][forum][enable]' => 'forum');
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertModules(array('forum'), TRUE);
+
+    // Disable forum and taxonomy. Both should now be installed but disabled.
+    $edit = array('modules[Core][forum][enable]' => FALSE);
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertModules(array('forum'), FALSE);
+    $edit = array('modules[Core][taxonomy][enable]' => FALSE);
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->assertModules(array('taxonomy'), FALSE);
+
+    // Check that the taxonomy module cannot be uninstalled.
+    $this->drupalGet('admin/modules/uninstall');
+    $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[taxonomy]"]');
+    $this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the taxonomy module is disabled.'));
+
+    // Uninstall the forum module, and check that taxonomy now can also be
+    // uninstalled.
+    $edit = array('uninstall[forum]' => 'forum');
+    $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
+    $this->drupalPost(NULL, NULL, t('Uninstall'));
+    $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
+    $edit = array('uninstall[taxonomy]' => 'taxonomy');
+    $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
+    $this->drupalPost(NULL, NULL, t('Uninstall'));
+    $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
+  }
 }
 
 /**
@@ -1321,7 +1355,7 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase {
   function setUp() {
     parent::setUp();
 
-    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer themes', 'bypass node access'));
+    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer themes', 'bypass node access'));
     $this->drupalLogin($this->admin_user);
     $this->node = $this->drupalCreateNode();
   }
@@ -1578,7 +1612,7 @@ class TokenReplaceTestCase extends DrupalWebTestCase {
     $tests['[site:slogan]'] = check_plain(variable_get('site_slogan', ''));
     $tests['[site:mail]'] = 'simpletest@example.com';
     $tests['[site:url]'] = url('<front>', $url_options);
-    $tests['[site:url-brief]'] = preg_replace('!^https?://!', '', url('<front>', $url_options));
+    $tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options));
     $tests['[site:login-url]'] = url('user', $url_options);
 
     // Test to make sure that we generated something for each token.
@@ -2058,3 +2092,56 @@ class SystemAdminTestCase extends DrupalWebTestCase {
     $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], t('Compact mode persists on new requests.'));
   }
 }
+
+/**
+ * Tests authorize.php and related hooks.
+ */
+class SystemAuthorizeCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Authorize API',
+      'description' => 'Tests the authorize.php script and related API.',
+      'group' => 'System',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('system_test'));
+
+    variable_set('allow_authorize_operations', TRUE);
+
+    // Create an administrator user.
+    $this->admin_user = $this->drupalCreateUser(array('administer software updates'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Helper function to initialize authorize.php and load it via drupalGet().
+   *
+   * Initializing authorize.php needs to happen in the child Drupal
+   * installation, not the parent. So, we visit a menu callback provided by
+   * system_test.module which calls system_authorized_init() to initialize the
+   * $_SESSION inside the test site, not the framework site. This callback
+   * redirects to authorize.php when it's done initializing.
+   *
+   * @see system_authorized_init().
+   */
+  function drupalGetAuthorizePHP($page_title = 'system-test-auth') {
+    $this->drupalGet('system-test/authorize-init/' . $page_title);
+  }
+
+  /**
+   * Tests the FileTransfer hooks
+   */
+  function testFileTransferHooks() {
+    $page_title = $this->randomName(16);
+    $this->drupalGetAuthorizePHP($page_title);
+    $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)), 'authorize.php page title is correct.');
+    $this->assertNoText('It appears you have reached this page in error.');
+    $this->assertText('To continue, provide your server connection details');
+    // Make sure we see the new connection method added by system_test.
+    $this->assertRaw('System Test FileTransfer');
+    // Make sure the settings form callback works.
+    $this->assertText('System Test Username');
+  }
+}
diff --git a/modules/system/system.tokens.inc b/modules/system/system.tokens.inc
index 78d48e1b8c7d3fc6b0d6ebc2160689e9c3745326..d07c4d521c6ec63010b191ec8be78ea8904de308 100644
--- a/modules/system/system.tokens.inc
+++ b/modules/system/system.tokens.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.tokens.inc,v 1.12 2010/08/17 21:31:13 dries Exp $
+// $Id: system.tokens.inc,v 1.13 2010/10/28 01:33:41 dries Exp $
 
 /**
  * @file
@@ -165,7 +165,7 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
           break;
 
         case 'url-brief':
-          $replacements[$original] = preg_replace('!^https?://!', '', url('<front>', $url_options));
+          $replacements[$original] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options));
           break;
 
         case 'login-url':
diff --git a/modules/system/system.updater.inc b/modules/system/system.updater.inc
index 60b8be89078f8da7a52d5ffcdc72905f84518060..f3d6fb97734a6f175c8c35ff5e08ebf00bacc2ef 100644
--- a/modules/system/system.updater.inc
+++ b/modules/system/system.updater.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.updater.inc,v 1.8 2010/05/18 18:11:13 dries Exp $
+// $Id: system.updater.inc,v 1.12 2011/01/04 03:06:24 webchick Exp $
 
 /**
  * @file
@@ -39,7 +39,7 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
   }
 
   public static function canUpdateDirectory($directory) {
-    if (file_scan_directory($directory, '/.*\.module/')) {
+    if (file_scan_directory($directory, '/.*\.module$/')) {
       return TRUE;
     }
     return FALSE;
@@ -76,7 +76,8 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
 
   public function postInstallTasks() {
     return array(
-      l(t('Enable newly added modules in !project', array('!project' => $this->title)), 'admin/modules'),
+      l(t('Enable newly added modules'), 'admin/modules'),
+      l(t('Administration pages'), 'admin'),
     );
   }
 
@@ -120,7 +121,7 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
 
   static function canUpdateDirectory($directory) {
     // This is a lousy test, but don't know how else to confirm it is a theme.
-    if (file_scan_directory($directory, '/.*\.module/')) {
+    if (file_scan_directory($directory, '/.*\.module$/')) {
       return FALSE;
     }
     return TRUE;
@@ -135,17 +136,12 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
     clearstatcache();
     system_rebuild_theme_data();
 
-    // Active the theme
-    db_update('system')
-      ->fields(array('status' => 1))
-      ->condition('type', 'theme')
-      ->condition('name', $this->name)
-      ->execute();
   }
 
   public function postInstallTasks() {
     return array(
-      l(t('Set the !project theme as default', array('!project' => $this->title)), 'admin/appearance'),
+      l(t('Enable newly added themes'), 'admin/appearance'),
+      l(t('Administration pages'), 'admin'),
     );
   }
 }
diff --git a/modules/system/theme.api.php b/modules/system/theme.api.php
index b687ddb2d831a45fa24dbfef9822bc67d1a4fe1d..0699f53a5f5af75772a08bdaac4d498475a79418 100644
--- a/modules/system/theme.api.php
+++ b/modules/system/theme.api.php
@@ -1,11 +1,10 @@
 <?php
-// $Id: theme.api.php,v 1.4 2010/08/08 19:35:49 dries Exp $
+// $Id: theme.api.php,v 1.5 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @defgroup themeable Default theme implementations
  * @{
- * Functions and templates that present output to the user, and can be
- * implemented by themes.
+ * Functions and templates for the user interface to be implemented by themes.
  *
  * Drupal's presentation layer is a pluggable system known as the theme
  * layer. Each theme can take control over most of Drupal's output, and
diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc
index e81eebb97abb41c87d91354f75a5abcdce685ab2..ae5e85e499eb0470bccca71cf62ffa113808cf6b 100644
--- a/modules/taxonomy/taxonomy.admin.inc
+++ b/modules/taxonomy/taxonomy.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.admin.inc,v 1.114 2010/10/20 01:31:07 dries Exp $
+// $Id: taxonomy.admin.inc,v 1.116 2010/11/20 06:49:47 webchick Exp $
 
 /**
  * @file
@@ -642,7 +642,6 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
   $form['#term'] = (array) $term;
   $form['#term']['parent'] = $parent;
   $form['#vocabulary'] = $vocabulary;
-  $form['#builder_function'] = 'taxonomy_form_term_submit_builder';
 
   // Check for confirmation forms.
   if (isset($form_state['confirm_delete'])) {
@@ -792,7 +791,7 @@ function taxonomy_form_term_submit($form, &$form_state) {
     return;
   }
 
-  $term = $form['#builder_function']($form, $form_state);
+  $term = taxonomy_form_term_submit_build_taxonomy_term($form, $form_state);
 
   $status = taxonomy_term_save($term);
   switch ($status) {
@@ -835,7 +834,7 @@ function taxonomy_form_term_submit($form, &$form_state) {
 /**
  * Updates the form state's term entity by processing this submission's values.
  */
-function taxonomy_form_term_submit_builder($form, &$form_state) {
+function taxonomy_form_term_submit_build_taxonomy_term($form, &$form_state) {
   $term = $form_state['term'];
   entity_form_submit_build_entity('taxonomy_term', $term, $form, $form_state);
 
@@ -902,6 +901,7 @@ function taxonomy_term_confirm_delete_submit($form, &$form_state) {
   drupal_set_message(t('Deleted term %name.', array('%name' => $form_state['values']['name'])));
   watchdog('taxonomy', 'Deleted term %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
   $form_state['redirect'] = 'admin/structure/taxonomy';
+  cache_clear_all();
   return;
 }
 
@@ -941,6 +941,7 @@ function taxonomy_vocabulary_confirm_delete_submit($form, &$form_state) {
   drupal_set_message(t('Deleted vocabulary %name.', array('%name' => $form_state['values']['name'])));
   watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
   $form_state['redirect'] = 'admin/structure/taxonomy';
+  cache_clear_all();
   return;
 }
 
diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php
index 433a054d91d00ee92e9a3f0d358ac758f09bd01e..f4d4a03491704fa757d6997ccfe0ab4bc09837c7 100644
--- a/modules/taxonomy/taxonomy.api.php
+++ b/modules/taxonomy/taxonomy.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.api.php,v 1.10 2010/06/24 22:21:51 webchick Exp $
+// $Id: taxonomy.api.php,v 1.11 2010/10/23 15:30:34 webchick Exp $
 
 /**
  * @file
@@ -182,6 +182,34 @@ function hook_taxonomy_term_delete($term) {
   db_delete('term_synoynm')->condition('tid', $term->tid)->execute();
 }
 
+/**
+ * Alter the results of taxonomy_term_view().
+ *
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * taxonomy term content structure has been built.
+ *
+ * If the module wishes to act on the rendered HTML of the term rather than the
+ * structured content array, it may use this hook to add a #post_render
+ * callback. Alternatively, it could also implement
+ * hook_preprocess_taxonomy_term(). See drupal_render() and theme()
+ * documentation respectively for details.
+ *
+ * @param $build
+ *   A renderable array representing the node content.
+ *
+ * @see hook_entity_view_alter()
+ */
+function hook_taxonomy_term_view_alter(&$build) {
+  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
+    // Change its weight.
+    $build['an_additional_field']['#weight'] = -10;
+  }
+
+  // Add a #post_render callback to act on the rendered HTML of the term.
+  $build['#post_render'][] = 'my_module_node_post_render';
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info
index adbbcaec69aa9331cccaf4785cb98ffc245e1d46..bdb558cbdda09c3ba15bb8d0b2f225498ac218d9 100644
--- a/modules/taxonomy/taxonomy.info
+++ b/modules/taxonomy/taxonomy.info
@@ -1,19 +1,16 @@
-; $Id: taxonomy.info,v 1.11 2009/11/17 21:24:18 dries Exp $
+; $Id: taxonomy.info,v 1.13 2010/12/20 19:59:43 webchick Exp $
 name = Taxonomy
 description = Enables the categorization of content.
 package = Core
 version = VERSION
 core = 7.x
+dependencies[] = options
 files[] = taxonomy.module
-files[] = taxonomy.admin.inc
-files[] = taxonomy.pages.inc
-files[] = taxonomy.install
 files[] = taxonomy.test
-files[] = taxonomy.tokens.inc
 configure = admin/structure/taxonomy
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install
index 5624b196f8c26b8912006710f9d36c2e942067e4..d81d83709c48ca23469cb62f410b855e81aed27a 100644
--- a/modules/taxonomy/taxonomy.install
+++ b/modules/taxonomy/taxonomy.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.install,v 1.53 2010/10/20 15:57:42 webchick Exp $
+// $Id: taxonomy.install,v 1.56 2010/12/14 19:50:05 dries Exp $
 
 /**
  * @file
@@ -196,7 +196,6 @@ function taxonomy_schema() {
       'created' => array(
         'description' => 'The Unix timestamp when the node was created.',
         'type' => 'int',
-        'unsigned' => TRUE,
         'not null' => TRUE,
         'default'=> 0,
       ),
@@ -235,6 +234,12 @@ function taxonomy_field_schema($field) {
     'indexes' => array(
       'tid' => array('tid'),
     ),
+    'foreign keys' => array(
+      'tid' => array(
+        'table' => 'taxonomy_term_data',
+        'columns' => array('tid' => 'tid'),
+      ),
+    ),
   );
 }
 
@@ -542,7 +547,7 @@ function taxonomy_update_7005(&$sandbox) {
   //   in this array but a term_node relationship exists mapping a
   //   term in voc id to node of that type, the relationship is
   //   assigned to the taxonomymyextra field which allows terms of all
-  //   vocabularies. 
+  //   vocabularies.
   // - cursor[values], cursor[deltas]: The contents of $values and
   //   $deltas at the end of the previous call to this function. These
   //   need to be preserved across calls because a single batch of
@@ -595,8 +600,6 @@ function taxonomy_update_7005(&$sandbox) {
     }
   }
   else {
-    $etid = _field_sql_storage_etid('node');
-
     // We do each pass in batches of 1000.
     $batch = 1000;
 
@@ -682,8 +685,8 @@ function taxonomy_update_7005(&$sandbox) {
 
       // Column names and values in field storage are the same for current and
       // revision.
-      $columns = array('etid', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column);
-      $values = array($etid, $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid);
+      $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column);
+      $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid);
 
       // Insert rows into the revision table.
       db_insert($revision_name)->fields($columns)->values($values)->execute();
@@ -800,3 +803,16 @@ function taxonomy_update_7009() {
   ));
 }
 
+/**
+ * Change {taxonomy_index}.created to support signed int.
+*/
+function taxonomy_update_7010() {
+  db_change_field('taxonomy_index', 'created', 'created', array(
+    'description' => 'The Unix timestamp when the node was created.',
+    'type' => 'int',
+    'unsigned' => FALSE,
+    'not null' => TRUE,
+    'default'=> 0,
+  ));
+}
+
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index a0f0ef73f46c4220daccb758457a460749cae030..d3250c12e24d7fd9328190cf72ab7c49604a41dd 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.module,v 1.613 2010/10/15 05:25:32 webchick Exp $
+// $Id: taxonomy.module,v 1.625 2011/01/03 18:03:54 webchick Exp $
 
 /**
  * @file
@@ -356,6 +356,16 @@ function taxonomy_menu() {
   return $items;
 }
 
+/**
+ * Implements hook_admin_paths().
+ */
+function taxonomy_admin_paths() {
+  $paths = array(
+    'taxonomy/term/*/edit' => TRUE,
+  );
+  return $paths;
+}
+
 /**
  * Return edit access for a given term.
  */
@@ -378,9 +388,15 @@ function taxonomy_vocabulary_save($vocabulary) {
   if (!empty($vocabulary->name)) {
     $vocabulary->name = trim($vocabulary->name);
   }
-  // For existing vocabularies, make sure we can detect machine name changes.
-  if (!empty($vocabulary->vid) && !isset($vocabulary->old_machine_name)) {
-    $vocabulary->old_machine_name = db_query("SELECT machine_name FROM {taxonomy_vocabulary} WHERE vid = :vid", array(':vid' => $vocabulary->vid))->fetchField();
+  // Load the stored entity, if any.
+  if (!empty($vocabulary->vid)) {
+    if (!isset($vocabulary->original)) {
+      $vocabulary->original = entity_load_unchanged('taxonomy_vocabulary', $vocabulary->vid);
+    }
+    // Make sure machine name changes are easily detected.
+    // @todo: Remove in Drupal 8, as it is deprecated by directly reading from
+    // $vocabulary->original.
+    $vocabulary->old_machine_name = $vocabulary->original->machine_name;
   }
 
   if (!isset($vocabulary->module)) {
@@ -388,6 +404,7 @@ function taxonomy_vocabulary_save($vocabulary) {
   }
 
   module_invoke_all('taxonomy_vocabulary_presave', $vocabulary);
+  module_invoke_all('entity_presave', $vocabulary, 'taxonomy_vocabulary');
 
   if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {
     $status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');
@@ -404,8 +421,9 @@ function taxonomy_vocabulary_save($vocabulary) {
     module_invoke_all('entity_insert', $vocabulary, 'taxonomy_vocabulary');
   }
 
+  unset($vocabulary->original);
   cache_clear_all();
-  entity_get_controller('taxonomy_vocabulary')->resetCache();
+  entity_get_controller('taxonomy_vocabulary')->resetCache(array($vocabulary->vid));
 
   return $status;
 }
@@ -419,25 +437,33 @@ function taxonomy_vocabulary_save($vocabulary) {
  *   Constant indicating items were deleted.
  */
 function taxonomy_vocabulary_delete($vid) {
-  $vocabulary = (array) taxonomy_vocabulary_load($vid);
-
-  // Only load terms without a parent, child terms will get deleted too.
-  $result = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid = :vid AND th.parent = 0', array(':vid' => $vid))->fetchCol();
-  foreach ($result as $tid) {
-    taxonomy_term_delete($tid);
-  }
-  db_delete('taxonomy_vocabulary')
-    ->condition('vid', $vid)
-    ->execute();
+  $vocabulary = taxonomy_vocabulary_load($vid);
+
+  $transaction = db_transaction();
+  try {
+    // Only load terms without a parent, child terms will get deleted too.
+    $result = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid = :vid AND th.parent = 0', array(':vid' => $vid))->fetchCol();
+    foreach ($result as $tid) {
+      taxonomy_term_delete($tid);
+    }
+    db_delete('taxonomy_vocabulary')
+      ->condition('vid', $vid)
+      ->execute();
 
-  field_attach_delete_bundle('taxonomy_term', $vocabulary['machine_name']);
-  module_invoke_all('taxonomy_vocabulary_delete', $vocabulary);
-  module_invoke_all('entity_delete', $vocabulary, 'taxonomy_vocabulary');
+    field_attach_delete_bundle('taxonomy_term', $vocabulary->machine_name);
+    module_invoke_all('taxonomy_vocabulary_delete', $vocabulary);
+    module_invoke_all('entity_delete', $vocabulary, 'taxonomy_vocabulary');
 
-  cache_clear_all();
-  entity_get_controller('taxonomy_vocabulary')->resetCache();
+    cache_clear_all();
+    entity_get_controller('taxonomy_vocabulary')->resetCache();
 
-  return SAVED_DELETED;
+    return SAVED_DELETED;
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog_exception('taxonomy', $e);
+    throw $e;
+  }
 }
 
 /**
@@ -522,8 +548,14 @@ function taxonomy_term_save($term) {
     $term->vocabulary_machine_name = $vocabulary->machine_name;
   }
 
+  // Load the stored entity, if any.
+  if (!empty($term->tid) && !isset($term->original)) {
+    $term->original = entity_load_unchanged('taxonomy_term', $term->tid);
+  }
+
   field_attach_presave('taxonomy_term', $term);
   module_invoke_all('taxonomy_term_presave', $term);
+  module_invoke_all('entity_presave', $term, 'taxonomy_term');
 
   if (empty($term->tid)) {
     $op = 'insert';
@@ -575,6 +607,7 @@ function taxonomy_term_save($term) {
   // Invoke the taxonomy hooks.
   module_invoke_all("taxonomy_term_$op", $term);
   module_invoke_all("entity_$op", $term, 'taxonomy_term');
+  unset($term->original);
 
   return $status;
 }
@@ -588,41 +621,47 @@ function taxonomy_term_save($term) {
  *   Status constant indicating deletion.
  */
 function taxonomy_term_delete($tid) {
-  $tids = array($tid);
-  while ($tids) {
-    $children_tids = $orphans = array();
-    foreach ($tids as $tid) {
-      // See if any of the term's children are about to be become orphans:
-      if ($children = taxonomy_get_children($tid)) {
-        foreach ($children as $child) {
-          // If the term has multiple parents, we don't delete it.
-          $parents = taxonomy_get_parents($child->tid);
-          if (count($parents) == 1) {
-            $orphans[] = $child->tid;
+  $transaction = db_transaction();
+  try {
+    $tids = array($tid);
+    while ($tids) {
+      $children_tids = $orphans = array();
+      foreach ($tids as $tid) {
+        // See if any of the term's children are about to be become orphans:
+        if ($children = taxonomy_get_children($tid)) {
+          foreach ($children as $child) {
+            // If the term has multiple parents, we don't delete it.
+            $parents = taxonomy_get_parents($child->tid);
+            if (count($parents) == 1) {
+              $orphans[] = $child->tid;
+            }
           }
         }
-      }
 
-      if ($term = taxonomy_term_load($tid)) {
-        db_delete('taxonomy_term_data')
-          ->condition('tid', $tid)
-          ->execute();
-        db_delete('taxonomy_term_hierarchy')
-          ->condition('tid', $tid)
-          ->execute();
-
-        field_attach_delete('taxonomy_term', $term);
-        module_invoke_all('taxonomy_term_delete', $term);
-        module_invoke_all('entity_delete', $term, 'taxonomy_term');
-        taxonomy_terms_static_reset();
+        if ($term = taxonomy_term_load($tid)) {
+          db_delete('taxonomy_term_data')
+            ->condition('tid', $tid)
+            ->execute();
+          db_delete('taxonomy_term_hierarchy')
+            ->condition('tid', $tid)
+            ->execute();
+
+          field_attach_delete('taxonomy_term', $term);
+          module_invoke_all('taxonomy_term_delete', $term);
+          module_invoke_all('entity_delete', $term, 'taxonomy_term');
+          taxonomy_terms_static_reset();
+        }
       }
-    }
 
-    $tids = $orphans;
+      $tids = $orphans;
+    }
+    return SAVED_DELETED;
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog_exception('taxonomy', $e);
+    throw $e;
   }
-
-  cache_clear_all();
-  return SAVED_DELETED;
 }
 
 /**
@@ -665,6 +704,10 @@ function taxonomy_term_view($term, $view_mode = 'full', $langcode = NULL) {
 
   $build['#attached']['css'][] = drupal_get_path('module', 'taxonomy') . '/taxonomy.css';
 
+  // Allow modules to modify the structured term.
+  $type = 'taxonomy_term';
+  drupal_alter(array('taxonomy_term_view', 'entity_view'), $build, $type);
+
   return $build;
 }
 
@@ -1034,14 +1077,21 @@ class TaxonomyVocabularyController extends DrupalDefaultEntityController {
  * database access if loaded again during the same page request.
  *
  * @see entity_load()
+ * @see EntityFieldQuery
  *
  * @param $tids
- *  An array of taxonomy term IDs.
+ *   An array of taxonomy term IDs.
  * @param $conditions
- *  An array of conditions to add to the query.
+ *   (deprecated) An associative array of conditions on the {taxonomy_term}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have. Instead, it is preferable to use
+ *   EntityFieldQuery to retrieve a list of entity IDs loadable by
+ *   this function.
  *
  * @return
- *  An array of term objects, indexed by tid.
+ *   An array of term objects, indexed by tid.
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function taxonomy_term_load_multiple($tids = array(), $conditions = array()) {
   return entity_load('taxonomy_term', $tids, $conditions);
@@ -1438,6 +1488,7 @@ function taxonomy_field_widget_form(&$form, &$form_state, $field, $instance, $la
     '#default_value' => taxonomy_implode_tags($tags),
     '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'],
     '#size' => $instance['widget']['settings']['size'],
+    '#maxlength' => 1024,
     '#element_validate' => array('taxonomy_autocomplete_validate'),
   );
 
@@ -1453,7 +1504,7 @@ function taxonomy_autocomplete_validate($element, &$form_state) {
   $value = array();
   if ($tags = $element['#value']) {
     // Collect candidate vocabularies.
-    $field = $form_state['field'][$element['#field_name']][$element['#language']]['field'];
+    $field = field_widget_field($element, $form_state);
     $vocabularies = array();
     foreach ($field['settings']['allowed_values'] as $tree) {
       if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
@@ -1570,7 +1621,9 @@ function taxonomy_rdf_mapping() {
 }
 
 /**
- * @defgroup taxonomy indexing Taxonomy functions maintaining {taxonomy_index}.
+ * @defgroup taxonomy_index Taxonomy indexing
+ * @{
+ * Functions to maintain taxonomy indexing.
  *
  * Taxonomy uses default field storage to store canonical relationships
  * between terms and fieldable entities. However its most common use case
@@ -1583,7 +1636,6 @@ function taxonomy_rdf_mapping() {
  * field storage engines or alternative methods of denormalizing this data
  * you should set the variable 'taxonomy_maintain_index_table' to FALSE
  * to avoid unnecessary writes in SQL.
- * @{
  */
 
 /**
@@ -1673,5 +1725,5 @@ function taxonomy_taxonomy_term_delete($term) {
 }
 
 /**
- * @} End of "defgroup taxonomy indexing"
+ * @} End of "defgroup taxonomy_index"
  */
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
index 9fd841323aeb2bb67ae54bb18acfaf728334aac3..59dad6d606ddd4ec09288e4caaba13d183514e3a 100644
--- a/modules/taxonomy/taxonomy.pages.inc
+++ b/modules/taxonomy/taxonomy.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.pages.inc,v 1.56 2010/10/13 01:25:11 webchick Exp $
+// $Id: taxonomy.pages.inc,v 1.57 2010/11/23 02:56:10 dries Exp $
 
 /**
  * @file
@@ -45,7 +45,7 @@ function taxonomy_term_page($term) {
     $nodes = node_load_multiple($nids);
     $build += node_view_multiple($nodes);
     $build['pager'] = array(
-      '#markup' => theme('pager'),
+      '#theme' => 'pager',
       '#weight' => 5,
      );
   }
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index c622d6a12c72e68325326c84a153530c808b2dd6..a561a403b5dbb12a8fef82f0943f15bbc7533210 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.test,v 1.96 2010/10/13 13:43:21 dries Exp $
+// $Id: taxonomy.test,v 1.99 2010/12/07 05:20:08 webchick Exp $
 
 /**
  * @file
@@ -379,6 +379,43 @@ class TaxonomyTermUnitTest extends TaxonomyWebTestCase {
   }
 }
 
+/**
+ * Test for legacy node bug.
+ */
+class TaxonomyLegacyTestCase extends TaxonomyWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Test for legacy node bug.',
+      'description' => 'Posts an article with a taxonomy term and a date prior to 1970.',
+      'group' => 'Taxonomy',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('taxonomy');
+    $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'administer nodes', 'bypass node access'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Test taxonomy functionality with nodes prior to 1970.
+   */
+  function testTaxonomyLegacyNode() {
+    // Posts an article with a taxonomy term and a date prior to 1970.
+    $langcode = LANGUAGE_NONE;
+    $edit = array();
+    $edit['title'] = $this->randomName();
+    $edit['date'] = '1969-01-01 00:00:00 -0500';
+    $edit["body[$langcode][0][value]"] = $this->randomName();
+    $edit["field_tags[$langcode]"] = $this->randomName();
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+    // Checks that the node has been saved.
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $this->assertEqual($node->created, strtotime($edit['date']), t('Legacy node was saved with the right date.'));
+  }
+}
+
 /**
  * Tests for taxonomy term functions.
  */
@@ -1131,3 +1168,50 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
     }
   }
 }
+
+/**
+ * Tests for verifying that taxonomy pages use the correct theme.
+ */
+class TaxonomyThemeTestCase extends TaxonomyWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Taxonomy theme switching',
+      'description' => 'Verifies that various taxonomy pages use the expected theme.',
+      'group' => 'Taxonomy',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    // Make sure we are using distinct default and administrative themes for
+    // the duration of these tests.
+    variable_set('theme_default', 'bartik');
+    variable_set('admin_theme', 'seven');
+
+    // Create and log in as a user who has permission to add and edit taxonomy
+    // terms and view the administrative theme.
+    $admin_user = $this->drupalCreateUser(array('administer taxonomy', 'view the administration theme'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Test the theme used when adding, viewing and editing taxonomy terms.
+   */
+  function testTaxonomyTermThemes() {
+    // Adding a term to a vocabulary is considered an administrative action and
+    // should use the administrative theme.
+    $vocabulary = $this->createVocabulary();
+    $this->drupalGet('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add');
+    $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page for adding a taxonomy term."));
+
+    // Viewing a taxonomy term should use the default theme.
+    $term = $this->createTerm($vocabulary);
+    $this->drupalGet('taxonomy/term/' . $term->tid);
+    $this->assertRaw('bartik/css/style.css', t("The default theme's CSS appears on the page for viewing a taxonomy term."));
+
+    // Editing a taxonomy term should use the same theme as adding one.
+    $this->drupalGet('taxonomy/term/' . $term->tid . '/edit');
+    $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page for editing a taxonomy term."));
+  }
+}
diff --git a/modules/taxonomy/taxonomy.tokens.inc b/modules/taxonomy/taxonomy.tokens.inc
index 8066a2659e001b036901c51ddaec37cf2da238a2..6f1be1171deda3e0f07c6760bf72a9add5f61f0e 100644
--- a/modules/taxonomy/taxonomy.tokens.inc
+++ b/modules/taxonomy/taxonomy.tokens.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.tokens.inc,v 1.9 2010/08/08 02:06:56 dries Exp $
+// $Id: taxonomy.tokens.inc,v 1.10 2010/11/14 00:25:44 dries Exp $
 
 /**
  * @file
@@ -61,7 +61,7 @@ function taxonomy_token_info() {
     'description' => t("The number of nodes tagged with terms belonging to the taxonomy vocabulary."),
   );
   $vocabulary['term-count'] = array(
-    'name' => t("Node count"),
+    'name' => t("Term count"),
     'description' => t("The number of terms belonging to the taxonomy vocabulary."),
   );
 
diff --git a/modules/toolbar/toolbar.css b/modules/toolbar/toolbar.css
index 800518f7c9fe53e3aa7bb443fa6c0ef6d93025d8..b1ce4d8b2a04671addbf8f1aba9e8f7a3dfe017c 100644
--- a/modules/toolbar/toolbar.css
+++ b/modules/toolbar/toolbar.css
@@ -1,4 +1,4 @@
-/* $Id: toolbar.css,v 1.26 2010/09/11 14:45:23 dries Exp $ */
+/* $Id: toolbar.css,v 1.27 2011/01/03 07:04:48 webchick Exp $ */
 
 body.toolbar {
   padding-top: 2.2em;
@@ -42,9 +42,9 @@ body.toolbar-drawer {
   margin: 0 -20px;
   padding: 0 20px;
   z-index: 600;
-  box-shadow: 0 3px 20px #000;
   -moz-box-shadow: 0 3px 20px #000;
   -webkit-box-shadow: 0 3px 20px #000;
+  box-shadow: 0 3px 20px #000;
   filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
   -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
 }
diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info
index 680f0e2d346a7225751458897cf142420dcb49fb..4149ad6d3b6b493c7a3fd859ce92f4a59e74bf54 100644
--- a/modules/toolbar/toolbar.info
+++ b/modules/toolbar/toolbar.info
@@ -1,13 +1,12 @@
-; $Id: toolbar.info,v 1.4 2009/12/04 16:02:42 dries Exp $
+; $Id: toolbar.info,v 1.5 2010/12/20 19:59:43 webchick Exp $
 name = Toolbar
 description = Provides a toolbar that shows the top-level administration menu items and links from other modules.
 core = 7.x
 package = Core
 version = VERSION
-files[] = toolbar.module
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/toolbar/toolbar.js b/modules/toolbar/toolbar.js
index fb1788cb07809777ec7466cbee4ffc7ed06b30ca..c2a9cafe51d8f565b0d7fb63c1faf91557975c3d 100644
--- a/modules/toolbar/toolbar.js
+++ b/modules/toolbar/toolbar.js
@@ -1,4 +1,4 @@
-// $Id: toolbar.js,v 1.19 2010/06/08 05:16:29 webchick Exp $
+// $Id: toolbar.js,v 1.20 2010/12/01 07:05:26 webchick Exp $
 (function ($) {
 
 Drupal.toolbar = Drupal.toolbar || {};
@@ -42,7 +42,7 @@ Drupal.toolbar.init = function() {
  * Collapse the toolbar.
  */
 Drupal.toolbar.collapse = function() {
-  var toggle_text = Drupal.t('Open the drawer');
+  var toggle_text = Drupal.t('Show shortcuts');
   $('#toolbar div.toolbar-drawer').addClass('collapsed');
   $('#toolbar a.toggle')
     .removeClass('toggle-active')
@@ -64,7 +64,7 @@ Drupal.toolbar.collapse = function() {
  * Expand the toolbar.
  */
 Drupal.toolbar.expand = function() {
-  var toggle_text = Drupal.t('Close the drawer');
+  var toggle_text = Drupal.t('Hide shortcuts');
   $('#toolbar div.toolbar-drawer').removeClass('collapsed');
   $('#toolbar a.toggle')
     .addClass('toggle-active')
diff --git a/modules/toolbar/toolbar.module b/modules/toolbar/toolbar.module
index 930996e0cabe5dd1ec3f2e0f46808a58358174ce..3b86d61a5fb1d9f895d81ff806932c4ee468afd8 100644
--- a/modules/toolbar/toolbar.module
+++ b/modules/toolbar/toolbar.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: toolbar.module,v 1.46 2010/10/05 19:59:10 dries Exp $
+// $Id: toolbar.module,v 1.49 2010/12/15 03:04:38 webchick Exp $
 
 /**
  * @file
@@ -17,7 +17,7 @@ function toolbar_help($path, $arg) {
       $output .= '<h3>' . t('Uses') . '</h3>';
       $output .= '<dl>';
       $output .= '<dt>' . t('Displaying administrative links') . '</dt>';
-      $output .= '<dd>' . t('The Toolbar module displays a bar containing top-level administrative links across the top of the screen. Below that, the Toolbar module has a <em>drawer</em> section where it displays links provided by other modules, such as the core <a href="@shortcuts-help">Shortcut module</a>. The drawer can be hidden/shown by using the close/open drawer link at the end of the toolbar.', array('@shortcuts-help' => url('admin/help/shortcut'))) . '</dd>';
+      $output .= '<dd>' . t('The Toolbar module displays a bar containing top-level administrative links across the top of the screen. Below that, the Toolbar module has a <em>drawer</em> section where it displays links provided by other modules, such as the core <a href="@shortcuts-help">Shortcut module</a>. The drawer can be hidden/shown by using the show/hide shortcuts link at the end of the toolbar.', array('@shortcuts-help' => url('admin/help/shortcut'))) . '</dd>';
       $output .= '</dl>';
       return $output;
   }
@@ -90,14 +90,13 @@ function toolbar_toggle_page() {
  */
 function theme_toolbar_toggle($variables) {
   if ($variables['collapsed']) {
-    $toggle_text = t('Open the drawer');
-    return '<a href="' . url('toolbar/toggle', array('query' => drupal_get_destination())) . '" title="' . $toggle_text . '"' .  drupal_attributes($variables['attributes']) . '>' . $toggle_text . '</a>';
+    $toggle_text = t('Show shortcuts');
   }
   else {
-    $toggle_text = t('Close the drawer');
+    $toggle_text = t('Hide shortcuts');
     $variables['attributes']['class'][] = 'toggle-active';
-    return '<a href="' . url('toolbar/toggle', array('query' => drupal_get_destination())) . '" title="' . $toggle_text . '"' .  drupal_attributes($variables['attributes']) . '>' . $toggle_text . '</a>';
   }
+  return '<a href="' . url('toolbar/toggle', array('query' => drupal_get_destination())) . '" title="' . $toggle_text . '"' .  drupal_attributes($variables['attributes']) . '>' . $toggle_text . '</a>';
 }
 
 /**
@@ -188,7 +187,6 @@ function toolbar_view() {
     '#attached'=> array(
       'js' => array(
         $module_path . '/toolbar.js',
-        array('data' => 'misc/jquery.cookie.js', 'group' => JS_LIBRARY, 'weight' => 2),
         array(
           'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'),
           'type' => 'setting'
@@ -197,6 +195,7 @@ function toolbar_view() {
       'css' => array(
         $module_path . '/toolbar.css',
       ),
+      'library' => array(array('system', 'jquery.cookie')),
     ),
   );
 
diff --git a/modules/toolbar/toolbar.png b/modules/toolbar/toolbar.png
index f93e9f745f17899933ddc8a86f858d4b679bd4fd..f2c7f355a6d9d8acb478f25a74ec1670cde26445 100644
Binary files a/modules/toolbar/toolbar.png and b/modules/toolbar/toolbar.png differ
diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info
index 890725a009666ef8cec2106f13981cb48d97e4a4..9332162ab12d261c1e94853595d86a913df8067b 100644
--- a/modules/tracker/tracker.info
+++ b/modules/tracker/tracker.info
@@ -1,16 +1,14 @@
-; $Id: tracker.info,v 1.10 2009/11/23 02:45:42 webchick Exp $
+; $Id: tracker.info,v 1.11 2010/12/20 19:59:43 webchick Exp $
 name = Tracker
 description = Enables tracking of recent content for users.
 dependencies[] = comment
 package = Core
 version = VERSION
 core = 7.x
-files[] = tracker.module
-files[] = tracker.pages.inc
 files[] = tracker.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/tracker/tracker.install b/modules/tracker/tracker.install
index a47f5a1a5274358f5c944667cfbe4fe35c6aa6b7..3823542344b0024fbf45478ee460315542a7a720 100644
--- a/modules/tracker/tracker.install
+++ b/modules/tracker/tracker.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: tracker.install,v 1.5 2010/08/22 13:55:53 dries Exp $
+// $Id: tracker.install,v 1.6 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * Implements hook_uninstall().
@@ -114,7 +114,7 @@ function tracker_schema() {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Tracker updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -217,6 +217,5 @@ function tracker_update_7000() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/tracker/tracker.module b/modules/tracker/tracker.module
index a34d0adacb836631bd791b399cf51f95fe0a0785..5f410214601c368dee1335fd724019412af84540 100644
--- a/modules/tracker/tracker.module
+++ b/modules/tracker/tracker.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: tracker.module,v 1.171 2009/12/04 16:49:47 dries Exp $
+// $Id: tracker.module,v 1.175 2010/12/28 18:39:23 webchick Exp $
 
 /**
  * @file
@@ -139,7 +139,7 @@ function tracker_cron() {
       // Prepare a starting point for the next run.
       variable_set('tracker_index_nid', $last_nid - 1);
 
-      watchdog('tracker', t('Indexed %count nodes for tracking.', array('%count' => $count)));
+      watchdog('tracker', 'Indexed %count content items for tracking.', array('%count' => $count));
     }
     else {
       // If all nodes have been indexed, set to zero to skip future cron runs.
@@ -164,24 +164,29 @@ function _tracker_user_access($account) {
 }
 
 /**
- * Implements hook_nodeapi_insert().
+ * Implements hook_node_insert().
  */
 function tracker_node_insert($node, $arg = 0) {
   _tracker_add($node->nid, $node->uid, $node->changed);
 }
 
 /**
- * Implements hook_nodeapi_update().
+ * Implements hook_node_update().
  */
 function tracker_node_update($node, $arg = 0) {
   _tracker_add($node->nid, $node->uid, $node->changed);
 }
 
 /**
- * Implements hook_nodeapi_delete().
+ * Implements hook_node_delete().
  */
 function tracker_node_delete($node, $arg = 0) {
-  _tracker_remove($node->nid, $node->uid, $node->changed);
+  db_delete('tracker_node')
+    ->condition('nid', $node->nid)
+    ->execute();
+  db_delete('tracker_user')
+    ->condition('nid', $node->nid)
+    ->execute();
 }
 
 /**
diff --git a/modules/tracker/tracker.test b/modules/tracker/tracker.test
index 3518cc50e9273545424db72b476344d2bd99f7ad..6ff3712c74f2ab2e004f00709c4231d74ddd0935 100644
--- a/modules/tracker/tracker.test
+++ b/modules/tracker/tracker.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: tracker.test,v 1.21 2010/10/05 06:17:29 webchick Exp $
+// $Id: tracker.test,v 1.22 2010/12/28 18:39:23 webchick Exp $
 
 class TrackerTest extends DrupalWebTestCase {
   protected $user;
@@ -9,7 +9,7 @@ class TrackerTest extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
       'name' => 'Tracker',
-      'description' => 'Create nodes and check for their display in the tracker listings.',
+      'description' => 'Create and delete nodes and check for their display in the tracker listings.',
       'group' => 'Tracker'
     );
   }
@@ -44,6 +44,11 @@ class TrackerTest extends DrupalWebTestCase {
     $this->assertNoText($unpublished->title, t('Unpublished node do not show up in the tracker listing.'));
     $this->assertText($published->title, t('Published node show up in the tracker listing.'));
     $this->assertLink(t('My recent content'), 0, t('User tab shows up on the global tracker page.'));
+
+    // Delete a node and ensure it no longer appears on the tracker.
+    node_delete($published->nid);
+    $this->drupalGet('tracker');
+    $this->assertNoText($published->title, t('Deleted node do not show up in the tracker listing.'));
   }
 
   /**
diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info
index 78435978facd05318fd8f6a7fa422b0d694e2872..646007e6a735370daed7d61b54cc83556f1f8c26 100644
--- a/modules/translation/tests/translation_test.info
+++ b/modules/translation/tests/translation_test.info
@@ -1,14 +1,13 @@
-; $Id: translation_test.info,v 1.1 2010/10/09 03:22:30 webchick Exp $
+; $Id: translation_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Content Translation Test"
 description = "Support module for the content translation tests."
 core = 7.x
 package = Testing
-files[] = translation_test.module
 version = VERSION
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/translation/translation.info b/modules/translation/translation.info
index 7ebbc1e4c12e43e96c5fea6e81895f88c9232c79..751305f5a065db1f35a52f42f95ea24a1a096bc3 100644
--- a/modules/translation/translation.info
+++ b/modules/translation/translation.info
@@ -1,16 +1,14 @@
-; $Id: translation.info,v 1.5 2009/06/08 09:23:54 dries Exp $
+; $Id: translation.info,v 1.6 2010/12/20 19:59:43 webchick Exp $
 name = Content translation
 description = Allows content to be translated into different languages.
 dependencies[] = locale
 package = Core
 version = VERSION
 core = 7.x
-files[] = translation.module
-files[] = translation.pages.inc
 files[] = translation.test
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/translation/translation.module b/modules/translation/translation.module
index e236233c77e819ee9bba3310a0ee8db2c3d92668..599ff1faaa70f96e5ae2f3cbcd8634f371fbba32 100644
--- a/modules/translation/translation.module
+++ b/modules/translation/translation.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: translation.module,v 1.88 2010/10/09 17:38:41 webchick Exp $
+// $Id: translation.module,v 1.91 2010/11/27 20:25:44 dries Exp $
 
 /**
  * @file
@@ -65,7 +65,6 @@ function translation_menu() {
     'access arguments' => array(1),
     'type' => MENU_LOCAL_TASK,
     'weight' => 2,
-    'theme callback' => '_node_custom_theme',
     'file' => 'translation.pages.inc',
   );
   return $items;
@@ -89,10 +88,12 @@ function _translation_tab_access($node) {
  * Implements hook_admin_paths().
  */
 function translation_admin_paths() {
-  $paths = array(
-    'node/*/translate' => TRUE,
-  );
-  return $paths;
+  if (variable_get('node_admin_theme')) {
+    $paths = array(
+      'node/*/translate' => TRUE,
+    );
+    return $paths;
+  }
 }
 
 /**
@@ -251,7 +252,11 @@ function translation_node_view($node, $view_mode) {
       }
     }
 
-    $node->content['links']['#links'] += $links;
+    $node->content['links']['translation'] = array(
+      '#theme' => 'links__node__translation',
+      '#links' => $links,
+      '#attributes' => array('class' => array('links', 'inline')),
+    );
   }
 }
 
@@ -484,7 +489,7 @@ function translation_supported_type($type) {
 function translation_path_get_translations($path) {
   $paths = array();
   // Check for a node related path, and for its translations.
-  if ((preg_match("!^node/([0-9]+)(/.+|)$!", $path, $matches)) && ($node = node_load((int)$matches[1])) && !empty($node->tnid)) {
+  if ((preg_match("!^node/(\d+)(/.+|)$!", $path, $matches)) && ($node = node_load((int) $matches[1])) && !empty($node->tnid)) {
     foreach (translation_node_get_translations($node->tnid) as $language => $translation_node) {
       $paths[$language] = 'node/' . $translation_node->nid . $matches[2];
     }
@@ -499,18 +504,18 @@ function translation_path_get_translations($path) {
  */
 function translation_language_switch_links_alter(array &$links, $type, $path) {
   $language_type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
-  if ($type == $language_type && $paths = translation_path_get_translations($path)) {
-    $path = explode('/', $path);
-    $node = node_load($path[1]);
-    $translations = translation_node_get_translations($node->tnid);
+  if ($type == $language_type && preg_match("!^node/(\d+)(/.+|)!", $path, $matches) && ($node = node_load((int) $matches[1]))) {
+    $translations = $node->tnid ? translation_node_get_translations($node->tnid) : array($node->language => $node);
+
     foreach ($links as $langcode => $link) {
-      if (isset($paths[$langcode]) && $translations[$langcode]->status) {
+      if (isset($translations[$langcode]) && $translations[$langcode]->status) {
         // Translation in a different node.
-        $links[$langcode]['href'] = $paths[$langcode];
+        $links[$langcode]['href'] = 'node/' . $translations[$langcode]->nid . $matches[2];
       }
       else {
         // No translation in this language, or no permission to view.
-        unset($links[$langcode]);
+        unset($links[$langcode]['href']);
+        $links[$langcode]['attributes']['class'] = 'locale-untranslated';
       }
     }
   }
diff --git a/modules/translation/translation.pages.inc b/modules/translation/translation.pages.inc
index 66754a003fde638bf694dad6f4b0e9701c47fb60..0da7666df07246f03b3a14488df772e28a3111fc 100644
--- a/modules/translation/translation.pages.inc
+++ b/modules/translation/translation.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: translation.pages.inc,v 1.16 2010/07/17 11:31:36 dries Exp $
+// $Id: translation.pages.inc,v 1.18 2010/12/31 20:45:25 webchick Exp $
 
 /**
  * @file
@@ -13,6 +13,8 @@
  *   Node object.
  */
 function translation_node_overview($node) {
+  include_once DRUPAL_ROOT . '/includes/language.inc';
+
   if ($node->tnid) {
     // Already part of a set, grab that set.
     $tnid = $node->tnid;
@@ -24,18 +26,24 @@ function translation_node_overview($node) {
     $translations = array($node->language => $node);
   }
 
+  $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
   $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));
 
-  foreach (language_list() as $language) {
+  foreach (language_list() as $langcode => $language) {
     $options = array();
     $language_name = $language->name;
-    if (isset($translations[$language->language])) {
+    if (isset($translations[$langcode])) {
       // Existing translation in the translation set: display status.
       // We load the full node to check whether the user can edit it.
-      $translation_node = node_load($translations[$language->language]->nid);
-      $title = l($translation_node->title, 'node/' . $translation_node->nid);
+      $translation_node = node_load($translations[$langcode]->nid);
+      $path = 'node/' . $translation_node->nid;
+      $links = language_negotiation_get_switch_links($type, $path);
+      $title = empty($links->links[$langcode]) ? l($translation_node->title, $path) : l($translation_node->title, $links->links[$langcode]['href'], $links->links[$langcode]);
       if (node_access('update', $translation_node)) {
-        $options[] = l(t('edit'), "node/$translation_node->nid/edit");
+        $text = t('edit');
+        $path = 'node/' . $translation_node->nid . '/edit';
+        $links = language_negotiation_get_switch_links($type, $path);
+        $options[] = empty($links->links[$langcode]) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]);
       }
       $status = $translation_node->status ? t('Published') : t('Not published');
       $status .= $translation_node->translate ? ' - <span class="marker">' . t('outdated') . '</span>' : '';
@@ -47,7 +55,11 @@ function translation_node_overview($node) {
       // No such translation in the set yet: help user to create it.
       $title = t('n/a');
       if (node_access('create', $node)) {
-        $options[] = l(t('add translation'), 'node/add/' . str_replace('_', '-', $node->type), array('query' => array('translation' => $node->nid, 'target' => $language->language)));
+        $text = t('add translation');
+        $path = 'node/add/' . str_replace('_', '-', $node->type);
+        $links = language_negotiation_get_switch_links($type, $path);
+        $query = array('query' => array('translation' => $node->nid, 'target' => $langcode));
+        $options[] = empty($links->links[$langcode]) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
       }
       $status = t('Not translated');
     }
diff --git a/modules/translation/translation.test b/modules/translation/translation.test
index 646097cf73c2365aeaf3e12b645d6563cd3f7e55..d03acb500b6762cd2db988ffaa7c8821f3552d04 100644
--- a/modules/translation/translation.test
+++ b/modules/translation/translation.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: translation.test,v 1.32 2010/10/09 17:38:41 webchick Exp $
+// $Id: translation.test,v 1.35 2010/12/31 20:45:25 webchick Exp $
 
 class TranslationTestCase extends DrupalWebTestCase {
   protected $book;
@@ -16,7 +16,7 @@ class TranslationTestCase extends DrupalWebTestCase {
     parent::setUp('locale', 'translation', 'translation_test');
 
     // Setup users.
-    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
+    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
     $this->translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content'));
 
     $this->drupalLogin($this->admin_user);
@@ -24,14 +24,32 @@ class TranslationTestCase extends DrupalWebTestCase {
     // Add languages.
     $this->addLanguage('en');
     $this->addLanguage('es');
+    $this->addLanguage('it');
 
-    // Set "Basic page" content type to use multilingual support with translation.
+    // Disable Italian to test the translation behavior with disabled languages.
+    $edit = array('enabled[it]' => FALSE);
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+
+    // Set "Basic page" content type to use multilingual support with
+    // translation.
     $this->drupalGet('admin/structure/types/manage/page');
     $edit = array();
     $edit['language_content_type'] = 2;
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
     $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
 
+    // Enable the language switcher block.
+    $language_type = LANGUAGE_TYPE_INTERFACE;
+    $edit = array("blocks[locale_$language_type][region]" => 'sidebar_first');
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+
+    // Enable URL language detection and selection to make the language switcher
+    // block appear.
+    $edit = array('language[enabled][locale-url]' => TRUE);
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+    $this->assertRaw(t('Language negotiation configuration saved.'), t('URL language detection enabled.'));
+    $this->resetCaches();
+
     $this->drupalLogin($this->translator);
   }
 
@@ -45,14 +63,24 @@ class TranslationTestCase extends DrupalWebTestCase {
     $node_body =  $this->randomName();
     $node = $this->createPage($node_title, $node_body, 'en');
 
+    // Check that the "add translation" link uses a localized path.
+    $languages = language_list();
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->assertLinkByHref($languages['es']->prefix . '/node/add/' . str_replace('_', '-', $node->type), 0, t('The "add translation" link for %language points to the localized path of the target language.', array('%language' => $languages['es']->name)));
+
     // Submit translation in Spanish.
     $node_translation_title = $this->randomName();
     $node_translation_body = $this->randomName();
     $node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es');
 
+    // Check that the "edit translation" and "view node" links use localized
+    // paths.
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid . '/edit', 0, t('The "edit" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
+    $this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid, 0, t('The "view" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
+
     // Attempt to submit a duplicate translation by visiting the node/add page
     // with identical query string.
-    $languages = language_list();
     $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => 'es')));
     $this->assertRaw(t('A translation of %title in %language already exists', array('%title' => $node_title, '%language' => $languages['es']->name)), t('Message regarding attempted duplicate translation is displayed.'));
 
@@ -67,13 +95,15 @@ class TranslationTestCase extends DrupalWebTestCase {
     $this->assertEqual($duplicate->tnid, 0, t('The node does not have a tnid.'));
 
     // Update original and mark translation as outdated.
+    $node_body = $this->randomName();
+    $node->body[$node->language][0]['value'] = $node_body;
     $edit = array();
-    $edit["body[$node->language][0][value]"] = $this->randomName();
+    $edit["body[$node->language][0][value]"] = $node_body;
     $edit['translation[retranslate]'] = TRUE;
     $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
     $this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_title)), t('Original node updated.'));
 
-    // Check to make sure that interface shows translation as outdated
+    // Check to make sure that interface shows translation as outdated.
     $this->drupalGet('node/' . $node->nid . '/translate');
     $this->assertRaw('<span class="marker">' . t('outdated') . '</span>', t('Translation marked as outdated.'));
 
@@ -84,55 +114,114 @@ class TranslationTestCase extends DrupalWebTestCase {
     $this->drupalPost('node/' . $node_translation->nid . '/edit', $edit, t('Save'));
     $this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_translation_title)), t('Translated node updated.'));
 
-    $this->drupalLogin($this->admin_user);
+    // Confirm that disabled languages are an option for translators when
+    // creating nodes.
+    $this->drupalGet('node/add/page');
+    $this->assertFieldByXPath('//select[@name="language"]//option', 'it', t('Italian (disabled) is available in language selection.'));
+    $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
+    $this->assertRaw($translation_it->body['it'][0]['value'], t('Content created in Italian (disabled).'));
 
-    // Disable Spanish and confirm that links to the Spanish translations do
-    // not appear on the English node.
-    $edit = array();
-    $edit['enabled[es]'] = FALSE;
+    // Leave just one language enabled and check that the translation overview
+    // page is still accessible.
+    $this->drupalLogin($this->admin_user);
+    $edit = array('enabled[es]' => FALSE);
     $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
-    $this->drupalGet('node/' . $node->nid);
-    $languages = language_list();
-    $this->assertNoText($languages['es']->native);
+    $this->drupalLogin($this->translator);
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->assertRaw(t('Translations of %title', array('%title' => $node->title)), t('Translation overview page available with only one language enabled.'));
+  }
 
+  /**
+   * Check that language switch links behave properly.
+   */
+  function testLanguageSwitchLinks() {
+    // Create a Basic page in English and its translations in Spanish and
+    // Italian.
+    $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
+    $translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
+    $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
+
+    // Check that language switch links are correctly shown only for enabled
+    // languages.
+    $this->assertLanguageSwitchLinks($node, $translation_es);
+    $this->assertLanguageSwitchLinks($translation_es, $node);
+    $this->assertLanguageSwitchLinks($node, $translation_it, FALSE);
+
+    // Check that links to the displayed translation appear only in the language
+    // switcher block.
+    $this->assertLanguageSwitchLinks($node, $node, FALSE, 'node');
+    $this->assertLanguageSwitchLinks($node, $node, TRUE, 'block-locale');
+
+    // Unpublish the Spanish translation to check that the related language
+    // switch link is not shown.
+    $this->drupalLogin($this->admin_user);
+    $edit = array('status' => FALSE);
+    $this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
     $this->drupalLogin($this->translator);
+    $this->assertLanguageSwitchLinks($node, $translation_es, FALSE);
 
-    // Confirm that Spanish is still an option for translators when creating nodes.
-    $this->drupalGet('node/add/page');
-    $this->assertRaw('value="' . 'es' .'"', t('Spanish is available in language selection'));
+    // Check that content translation links are shown even when no language
+    // negotiation is configured.
+    $this->drupalLogin($this->admin_user);
+    $edit = array('language[enabled][locale-url]' => FALSE);
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+    $this->resetCaches();
+    $edit = array('status' => TRUE);
+    $this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
+    $this->drupalLogin($this->translator);
+    $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, 'node');
   }
 
   /**
-   * Check that content translation links behave properly.
+   * Test that the language switcher block alterations work as intended.
    */
-  function testContentTranslationLinks() {
-    // Create Basic page in English.
-    $node_title = $this->randomName();
-    $node_body = $this->randomName();
-    $node = $this->createPage($node_title, $node_body, 'en');
+  function testLanguageSwitcherBlockIntegration() {
+    // Enable Italian to have three items in the language switcher block.
+    $this->drupalLogin($this->admin_user);
+    $edit = array('enabled[it]' => TRUE);
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+    $this->drupalLogin($this->translator);
 
-    // Submit translation in Spanish.
-    $node_translation_title = $this->randomName();
-    $node_translation_body = $this->randomName();
-    $node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es');
+    // Create a Basic page in English.
+    $type = 'block-locale';
+    $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
+    $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $this->emptyNode('es'), TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
+
+    // Create the Spanish translation.
+    $translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
+    $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
+
+    // Create the Italian translation.
+    $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
+    $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
+    $this->assertLanguageSwitchLinks($node, $translation_it, TRUE, $type);
+  }
 
-    // Check that content translation links are shown even when no language
-    // negotiation is configured.
-    $languages = language_list();
-    $this->drupalGet("node/$node->nid");
-    $url = url("node/$node_translation->nid");
-    $this->assertContentByXPath('//a[@href=:url]', array(':url' => $url), $languages['es']->native, t('Spanish translation link found.'));
+  /**
+   * Reset static caches to make the test code match the client site behavior.
+   */
+  function resetCaches() {
+    drupal_static_reset('locale_url_outbound_alter');
+  }
 
-    $this->drupalGet("node/$node_translation->nid");
-    $url = url("node/$node->nid");
-    $this->assertContentByXPath('//a[@href=:url]', array(':url' => $url), $languages['en']->native, t('English translation link found.'));
+  /**
+   * Return an empty node data structure.
+   */
+  function emptyNode($langcode) {
+    return (object) array('nid' => NULL, 'language' => $langcode);
   }
 
   /**
    * Install a the specified language if it has not been already. Otherwise make sure that
    * the language is enabled.
    *
-   * @param string $language_code The language code the check.
+   * @param $language_code
+   *   The language code the check.
    */
   function addLanguage($language_code) {
     // Check to make sure that language has not already been installed.
@@ -144,7 +233,7 @@ class TranslationTestCase extends DrupalWebTestCase {
       $edit['langcode'] = $language_code;
       $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
 
-      // Make sure we're not using a stale list.
+      // Make sure we are not using a stale list.
       drupal_static_reset('language_list');
       $languages = language_list('language');
       $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
@@ -168,9 +257,12 @@ class TranslationTestCase extends DrupalWebTestCase {
   /**
    * Create a "Basic page" in the specified language.
    *
-   * @param string $title Title of basic page in specified language.
-   * @param string $body Body of basic page in specified language.
-   * @param string $language Language code.
+   * @param $title
+   *   Title of basic page in specified language.
+   * @param $body
+   *   Body of basic page in specified language.
+   * @param
+   *   $language Language code.
    */
   function createPage($title, $body, $language) {
     $edit = array();
@@ -188,6 +280,40 @@ class TranslationTestCase extends DrupalWebTestCase {
     return $node;
   }
 
+  /**
+   * Create a translation for the specified basic page in the specified
+   * language.
+   *
+   * @param $node
+   *   The basic page to create translation for.
+   * @param $title
+   *   Title of basic page in specified language.
+   * @param $body
+   *   Body of basic page in specified language.
+   * @param $language
+   *   Language code.
+   */
+  function createTranslation($node, $title, $body, $language) {
+    $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
+
+    $body_key = "body[$language][0][value]";
+    $this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
+    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[$node->language][0]['value'], "Original body value correctly populated.");
+
+    $edit = array();
+    $edit["title"] = $title;
+    $edit[$body_key] = $body;
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Translation created.'));
+
+    // Check to make sure that translation was successful.
+    $translation = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue($translation, t('Node found in database.'));
+    $this->assertTrue($translation->tnid == $node->nid, t('Translation set id correctly stored.'));
+
+    return $translation;
+  }
+
   /**
    * Assert that an element identified by the given XPath has the given content.
    *
@@ -208,6 +334,68 @@ class TranslationTestCase extends DrupalWebTestCase {
    *   TRUE on pass, FALSE on fail.
    */
   function assertContentByXPath($xpath, array $arguments = array(), $value = NULL, $message = '', $group = 'Other') {
+    $found = $this->findContentByXPath($xpath, $arguments, $value);
+    return $this->assertTrue($found, $message, $group);
+  }
+
+  /**
+   * Check that the specified language switch links are found/not found.
+   *
+   * @param $node
+   *   The node to display.
+   * @param $translation
+   *   The translation whose link has to be checked.
+   * @param $find
+   *   TRUE if the link must be present in the node page.
+   * @param $types
+   *   The page areas to be checked.
+   *
+   * @return
+   *   TRUE if the language switch links are found/not found.
+   */
+  function assertLanguageSwitchLinks($node, $translation, $find = TRUE, $types = NULL) {
+    if (empty($types)) {
+      $types = array('node', 'block-locale');
+    }
+    elseif (is_string($types)) {
+      $types = array($types);
+    }
+
+    $result = TRUE;
+    $languages = language_list();
+    $page_language = $languages[$node->language];
+    $translation_language = $languages[$translation->language];
+    $url = url("node/$translation->nid", array('language' => $translation_language));
+
+    $this->drupalGet("node/$node->nid", array('language' => $page_language));
+
+    foreach ($types as $type) {
+      $args = array('%translation_language' => $translation_language->native, '%page_language' => $page_language->native, '%type' => $type);
+      if ($find) {
+        $message = t('[%page_language] Language switch item found for %translation_language language in the %type page area.', $args);
+      }
+      else {
+        $message = t('[%page_language] Language switch item not found for %translation_language language in the %type page area.', $args);
+      }
+
+      if (!empty($translation->nid)) {
+        $xpath = '//div[contains(@class, :type)]//a[@href=:url]';
+      }
+      else {
+        $xpath = '//div[contains(@class, :type)]//span[@class="locale-untranslated"]';
+      }
+
+      $found = $this->findContentByXPath($xpath, array(':type' => $type, ':url' => $url), $translation_language->native);
+      $result = $this->assertTrue($found == $find, $message) && $result;
+    }
+
+    return $result;
+  }
+
+  /**
+   * Search for elements matching the given xpath and value.
+   */
+  function findContentByXPath($xpath, array $arguments = array(), $value = NULL) {
     $elements = $this->xpath($xpath, $arguments);
 
     $found = TRUE;
@@ -221,35 +409,6 @@ class TranslationTestCase extends DrupalWebTestCase {
       }
     }
 
-    return $this->assertTrue($elements && $found, $message, $group);
-  }
-
-  /**
-   * Create a translation for the specified basic page in the specified language.
-   *
-   * @param object $node The basic page to create translation for.
-   * @param string $title Title of basic page in specified language.
-   * @param string $body Body of basic page in specified language.
-   * @param string $language Language code.
-   */
-  function createTranslation($node, $title, $body, $language) {
-    $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
-
-    $body_key = "body[$language][0][value]";
-    $this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
-    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[$node->language][0]['value'], "Original body value correctly populated.");
-
-    $edit = array();
-    $edit["title"] = $title;
-    $edit[$body_key] = $body;
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Translation created.'));
-
-    // Check to make sure that translation was successful.
-    $translation = $this->drupalGetNodeByTitle($title);
-    $this->assertTrue($translation, t('Node found in database.'));
-    $this->assertTrue($translation->tnid == $node->nid, t('Translation set id correctly stored.'));
-
-    return $translation;
+    return $elements && $found;
   }
 }
diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info
index 1fdbb6ee948c4cdebb4bd075c1fb7b81805cf4e9..81543d732f13ee7c2b04185530c2994638806a38 100644
--- a/modules/trigger/tests/trigger_test.info
+++ b/modules/trigger/tests/trigger_test.info
@@ -1,13 +1,12 @@
-; $Id: trigger_test.info,v 1.1 2009/05/27 16:29:05 webchick Exp $
+; $Id: trigger_test.info,v 1.2 2010/12/20 19:59:43 webchick Exp $
 name = "Trigger Test"
 description = "Support module for Trigger tests."
 package = Testing
 core = 7.x
-files[] = trigger_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info
index b81c48517d29f7b64190071fddfc2c6358d19a1e..1eb79f1d1b6d564bce840df63b8953b5242a5498 100644
--- a/modules/trigger/trigger.info
+++ b/modules/trigger/trigger.info
@@ -1,17 +1,14 @@
-; $Id: trigger.info,v 1.7 2009/11/17 21:24:18 dries Exp $
+; $Id: trigger.info,v 1.8 2010/12/20 19:59:43 webchick Exp $
 name = Trigger
 description = Enables actions to be fired on certain system events, such as when new content is created.
 package = Core
 version = VERSION
 core = 7.x
-files[] = trigger.module
-files[] = trigger.admin.inc
-files[] = trigger.install
 files[] = trigger.test
 configure = admin/structure/trigger
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
index d684fac41c0003d2853e75fae228375e3003e307..23a8b094775a84eca60baf727792ae975824c1a8 100644
--- a/modules/trigger/trigger.module
+++ b/modules/trigger/trigger.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: trigger.module,v 1.65 2010/09/24 00:37:44 dries Exp $
+// $Id: trigger.module,v 1.66 2010/12/01 07:41:03 webchick Exp $
 
 /**
  * @file
@@ -11,29 +11,30 @@
  * Implements hook_help().
  */
 function trigger_help($path, $arg) {
-  $explanation = '<p>' . t('Triggers are events on your site, such as new content being added or a user logging in. The Trigger module associates these triggers with actions (functional tasks), such as unpublishing content containing certain keywords or e-mailing an administrator. The <a href="@url">Actions settings page</a> contains a list of existing actions and provides the ability to create and configure advanced actions (actions requiring configuration, such as an e-mail address or a list of banned words).', array('@url' => url('admin/config/system/actions'))) . '</p>';
-  switch ($path) {
-    case 'admin/structure/trigger/comment':
-      return $explanation . '<p>' . t('Below you can assign actions to run when certain comment-related triggers happen. For example, you could promote a post to the front page when a comment is added.') . '</p>';
-    case 'admin/structure/trigger/node':
-      return $explanation . '<p>' . t('Below you can assign actions to run when certain content-related triggers happen. For example, you could send an e-mail to an administrator when content is created or updated.') . '</p>';
-    case 'admin/structure/trigger/system':
-      return $explanation . '<p>' . t('Below you can assign actions to run during each pass of a <a href="@cron">cron maintenance task</a>.', array('@cron' => url('admin/reports/status'))) . '</p>';
-    case 'admin/structure/trigger/taxonomy':
-      return $explanation . '<p>' . t('Below you can assign actions to run when certain taxonomy-related triggers happen. For example, you could send an e-mail to an administrator when a term is deleted.') . '</p>';
-    case 'admin/structure/trigger/user':
-      return $explanation . '<p>' . t("Below you can assign actions to run when certain user-related triggers happen. For example, you could send an e-mail to an administrator when a user account is deleted.") . '</p>';
-
-    case 'admin/help#trigger':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Trigger module provides the ability to cause <em>actions</em> to run when certain <em>triggers</em> take place on your site. Triggers are events, such as new content being added to your site or a user logging in, and actions are tasks, such as unpublishing content or e-mailing an administrator. For more information, see the online handbook entry for <a href="@trigger">Trigger module</a>.', array('@trigger' => 'http://drupal.org/handbook/modules/trigger/')) . '</p>';
-      $output .= '<h3>' . t('Uses') . '</h3>';
-      $output .= '<dl>';
-      $output .= '<dt>' . t('Configuring triggers and actions') . '</dt>';
-      $output .= '<dd>' . t('The combination of actions and triggers can perform many useful tasks, such as e-mailing an administrator if a user account is deleted, or automatically unpublishing comments that contain certain words. To set up a trigger/action combination, first visit the <a href="@actions-page">Actions configuration page</a>, where you can either verify that the action you want is already listed, or create a new <em>advanced</em> action. You will need to set up an advanced action if there are configuration options in your trigger/action combination, such as specifying an e-mail address or a list of banned words. After configuring or verifying your action, visit the <a href="@triggers-page">Triggers configuration page</a> and choose the appropriate tab (Comment, Taxonomy, etc.), where you can assign the action to run when the trigger event occurs.', array('@triggers-page' => url('admin/structure/trigger'), '@actions-page' => url('admin/config/system/actions'))) . '</dd>';
-      $output .= '</dl>';
-      return $output;
+  // Generate help text for admin/structure/trigger/(module) tabs.
+  $matches = array();
+  if (preg_match('|^admin/structure/trigger/(.*)$|', $path, $matches)) {
+    $explanation = '<p>' . t('Triggers are events on your site, such as new content being added or a user logging in. The Trigger module associates these triggers with actions (functional tasks), such as unpublishing content containing certain keywords or e-mailing an administrator. The <a href="@url">Actions settings page</a> contains a list of existing actions and provides the ability to create and configure advanced actions (actions requiring configuration, such as an e-mail address or a list of banned words).', array('@url' => url('admin/config/system/actions'))) . '</p>';
+
+    $module = $matches[1];
+    $trigger_info = _trigger_tab_information();
+    if (!empty($trigger_info[$module])) {
+      $explanation .= '<p>' . t('There is a tab on this page for each module that defines triggers. On this tab you can assign actions to run when triggers from the <a href="@module-help">@module-name module</a> happen.', array('@module-help' => url('admin/help/' . $module), '@module-name' => $trigger_info[$module])) . '</p>';
+    }
+
+    return $explanation;
+  }
+
+  if ($path == 'admin/help#trigger') {
+    $output = '';
+    $output .= '<h3>' . t('About') . '</h3>';
+    $output .= '<p>' . t('The Trigger module provides the ability to cause <em>actions</em> to run when certain <em>triggers</em> take place on your site. Triggers are events, such as new content being added to your site or a user logging in, and actions are tasks, such as unpublishing content or e-mailing an administrator. For more information, see the online handbook entry for <a href="@trigger">Trigger module</a>.', array('@trigger' => 'http://drupal.org/handbook/modules/trigger/')) . '</p>';
+    $output .= '<h3>' . t('Uses') . '</h3>';
+    $output .= '<dl>';
+    $output .= '<dt>' . t('Configuring triggers and actions') . '</dt>';
+    $output .= '<dd>' . t('The combination of actions and triggers can perform many useful tasks, such as e-mailing an administrator if a user account is deleted, or automatically unpublishing comments that contain certain words. To set up a trigger/action combination, first visit the <a href="@actions-page">Actions configuration page</a>, where you can either verify that the action you want is already listed, or create a new <em>advanced</em> action. You will need to set up an advanced action if there are configuration options in your trigger/action combination, such as specifying an e-mail address or a list of banned words. After configuring or verifying your action, visit the <a href="@triggers-page">Triggers configuration page</a> and choose the appropriate tab (Comment, Taxonomy, etc.), where you can assign the action to run when the trigger event occurs.', array('@triggers-page' => url('admin/structure/trigger'), '@actions-page' => url('admin/config/system/actions'))) . '</dd>';
+    $output .= '</dl>';
+    return $output;
   }
 }
 
@@ -49,31 +50,18 @@ function trigger_menu() {
     'file' => 'trigger.admin.inc',
   );
 
-  // We want contributed modules to be able to describe
-  // their hooks and have actions assignable to them.
-  $trigger_info = module_invoke_all('trigger_info');
-  drupal_alter('trigger_info', $trigger_info);
-
-  foreach ($trigger_info as $module => $hooks) {
-    $info = db_select('system')
-      ->fields('system', array('info'))
-      ->condition('name', $module)
-      ->condition('status', 1)
-      ->execute()
-      ->fetchField();
-    if ($info) {
-      $info = unserialize($info);
-      $nice_name = $info['name'];
-      $items["admin/structure/trigger/$module"] = array(
-        'title' => $nice_name,
-        'page callback' => 'trigger_assign',
-        'page arguments' => array($module),
-        'access arguments' => array('administer actions'),
-        'type' => MENU_LOCAL_TASK,
-        'file' => 'trigger.admin.inc',
-      );
-    }
+  $trigger_info = _trigger_tab_information();
+  foreach ($trigger_info as $module => $module_name) {
+    $items["admin/structure/trigger/$module"] = array(
+      'title' => $module_name,
+      'page callback' => 'trigger_assign',
+      'page arguments' => array($module),
+      'access arguments' => array('administer actions'),
+      'type' => MENU_LOCAL_TASK,
+      'file' => 'trigger.admin.inc',
+    );
   }
+
   $items['admin/structure/trigger/unassign'] = array(
     'title' => 'Unassign',
     'description' => 'Unassign an action from a trigger.',
@@ -620,3 +608,25 @@ function _trigger_get_all_info() {
 
   return $triggers;
 }
+
+/**
+ * Gathers information about tabs on the triggers administration screen.
+ *
+ * @return
+ *   Array of modules that have triggers, with the keys being the
+ *   machine-readable name of the module, and the values being the
+ *   human-readable name of the module.
+ */
+function _trigger_tab_information() {
+  // Gather information about all triggers and modules.
+  $trigger_info = _trigger_get_all_info();
+  $modules = system_get_info('module');
+  $modules = array_intersect_key($modules, $trigger_info);
+
+  $return_info = array();
+  foreach ($modules as $name => $info) {
+    $return_info[$name] = $info['name'];
+  }
+
+  return $return_info;
+}
diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info
index 9b31a7af0bd7b153e24b432eeac53b7d4e242158..617d79a84536a3823e694aa8cf5c55b01cfba4d6 100644
--- a/modules/update/tests/aaa_update_test.info
+++ b/modules/update/tests/aaa_update_test.info
@@ -1,13 +1,12 @@
-; $Id: aaa_update_test.info,v 1.1 2009/10/01 19:23:21 dries Exp $
+; $Id: aaa_update_test.info,v 1.2 2010/12/20 19:59:44 webchick Exp $
 name = AAA Update test
 description = Support module for update module testing.
 package = Testing
 core = 7.x
-files[] = aaa_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/update/tests/aaa_update_test.tar.gz b/modules/update/tests/aaa_update_test.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..22c97191019b16e1392a29b988894bf870fdda25
Binary files /dev/null and b/modules/update/tests/aaa_update_test.tar.gz differ
diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info
index 12e5a654660480dafe73da90356d4b1cc9aa4b0c..805e56f3d95990591161a3fc526004e4485a14d8 100644
--- a/modules/update/tests/bbb_update_test.info
+++ b/modules/update/tests/bbb_update_test.info
@@ -1,13 +1,12 @@
-; $Id: bbb_update_test.info,v 1.1 2009/10/01 19:23:21 dries Exp $
+; $Id: bbb_update_test.info,v 1.2 2010/12/20 19:59:44 webchick Exp $
 name = BBB Update test
 description = Support module for update module testing.
 package = Testing
 core = 7.x
-files[] = bbb_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info
index 76f326eff61cc68f3c61c32583249631c4b07f07..cbe120162a02bbc61a3b35e6386a4b4da4419cb9 100644
--- a/modules/update/tests/ccc_update_test.info
+++ b/modules/update/tests/ccc_update_test.info
@@ -1,13 +1,12 @@
-; $Id: ccc_update_test.info,v 1.1 2009/10/01 19:23:21 dries Exp $
+; $Id: ccc_update_test.info,v 1.2 2010/12/20 19:59:44 webchick Exp $
 name = CCC Update test
 description = Support module for update module testing.
 package = Testing
 core = 7.x
-files[] = ccc_update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info
index 6fe5c5707f9c1aadae1aa04aa84e25ee4134c11e..4823b87b42c77b9b48cbd922d8760a99954d7ecc 100644
--- a/modules/update/tests/update_test.info
+++ b/modules/update/tests/update_test.info
@@ -1,14 +1,13 @@
-; $Id: update_test.info,v 1.1 2009/09/26 17:03:13 dries Exp $
+; $Id: update_test.info,v 1.2 2010/12/20 19:59:44 webchick Exp $
 name = Update test
 description = Support module for update module testing.
 package = Testing
 version = VERSION
 core = 7.x
-files[] = update_test.module
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/update/tests/update_test.module b/modules/update/tests/update_test.module
index 1ab30b0f785d87a19eb0ce32bc3f2b50e1fd8501..840133ab70bced0b57074399be00a3c81d5ab746 100644
--- a/modules/update/tests/update_test.module
+++ b/modules/update/tests/update_test.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: update_test.module,v 1.6 2010/10/05 02:17:44 dries Exp $
+// $Id: update_test.module,v 1.7 2011/01/03 02:41:33 webchick Exp $
 
 /**
  * Implements hook_menu().
@@ -112,3 +112,40 @@ function update_test_archiver_info() {
     ),
   );
 }
+
+/**
+ * Implements hook_filetransfer_info().
+ */
+function update_test_filetransfer_info() {
+  // Define a mock file transfer method, to ensure that there will always be
+  // at least one method available in the user interface (regardless of the
+  // environment in which the update manager tests are run).
+  return array(
+    'system_test' => array(
+      'title' => t('Update Test FileTransfer'),
+      // This should be in an .inc file, but for testing purposes, it is OK to
+      // leave it in the main module file.
+      'file' => 'update_test.module',
+      'class' => 'UpdateTestFileTransfer',
+      'weight' => -20,
+    ),
+  );
+}
+
+/**
+ * Mock FileTransfer object to test the settings form functionality.
+ */
+class UpdateTestFileTransfer {
+  public static function factory() {
+    return new UpdateTestFileTransfer;
+  }
+
+  public function getSettingsForm() {
+    $form = array();
+    $form['udpate_test_username'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Update Test Username'),
+    );
+    return $form;
+  }
+}
diff --git a/modules/update/update.api.php b/modules/update/update.api.php
index c1b2515785bcc5e17b0e052edab12c5cf2435e5b..b7349a19c9e9826e8b4a8f91c039f09f2d2708cc 100644
--- a/modules/update/update.api.php
+++ b/modules/update/update.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.api.php,v 1.5 2010/04/30 16:27:02 webchick Exp $
+// $Id: update.api.php,v 1.6 2010/12/06 06:50:08 webchick Exp $
 
 /**
  * @file
@@ -115,16 +115,18 @@ function hook_update_status_alter(&$projects) {
  *   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).
+ *   If there are any problems, return an array of error messages. If there are
+ *   no problems, return an empty array.
  *
  * @see update_manager_archive_verify()
  */
 function hook_verify_update_archive($project, $archive_file, $directory) {
+  $errors = array();
   if (!file_exists($directory)) {
-    return TRUE;
+    $errors[] = t('The %directory does not exist.', array('%directory' => $directory));
   }
   // Add other checks on the archive integrity here.
+  return $errors;
 }
 
 /**
diff --git a/modules/update/update.authorize.inc b/modules/update/update.authorize.inc
index 567ab4976a3e6c2251c72dce25258f359a5b3fc3..7265681a00caf6e794d364c4662b1c40c600ca45 100644
--- a/modules/update/update.authorize.inc
+++ b/modules/update/update.authorize.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.authorize.inc,v 1.4 2010/04/10 09:49:49 dries Exp $
+// $Id: update.authorize.inc,v 1.9 2011/01/03 02:53:07 webchick Exp $
 
 /**
  * @file
@@ -131,7 +131,7 @@ function update_authorize_batch_copy_project($project, $updater_name, $local_url
   unset($filetransfer->connection);
 
   if (!empty($context['results']['log'][$project]['#abort'])) {
-    $context['#finished'] = 1;
+    $context['finished'] = 1;
     return;
   }
 
@@ -176,14 +176,15 @@ function update_authorize_update_batch_finished($success, $results) {
       $success = FALSE;
     }
   }
-  $offline = variable_get('site_offline', FALSE);
+  $offline = variable_get('maintenance_mode', FALSE);
   if ($success) {
     // Now that the update completed, we need to clear the cache of available
     // update data and recompute our status, so prevent show bogus results.
     _update_authorize_clear_update_status();
 
-    if ($offline) {
-      variable_set('site_offline', FALSE);
+    // Take the site out of maintenance mode if it was previously that way.
+    if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
+      variable_set('maintenance_mode', FALSE);
       $page_message = array(
         'message' => t('Update was completed successfully. Your site has been taken out of maintenance mode.'),
         'type' => 'status',
@@ -213,11 +214,15 @@ function update_authorize_update_batch_finished($success, $results) {
   $results['tasks'][] = t('Your modules have been downloaded and updated.');
   $results['tasks'][] = t('<a href="@update">Run database updates</a>', array('@update' => base_path() . 'update.php'));
 
+  // Unset the variable since it is no longer needed.
+  unset($_SESSION['maintenance_mode']);
+
   // Set all these values into the SESSION so authorize.php can display them.
   $_SESSION['authorize_results']['success'] = $success;
   $_SESSION['authorize_results']['page_message'] = $page_message;
   $_SESSION['authorize_results']['messages'] = $results['log'];
   $_SESSION['authorize_results']['tasks'] = $results['tasks'];
+  $_SESSION['authorize_operation']['page_title'] = t('Update manager');
 }
 
 /**
@@ -233,19 +238,22 @@ function update_authorize_install_batch_finished($success, $results) {
       $success = FALSE;
     }
   }
-  $offline = variable_get('site_offline', FALSE);
-  if ($success && $offline) {
-    variable_set('site_offline', FALSE);
-    $page_message = array(
-      'message' => t('Installation was completed successfully. Your site has been taken out of maintenance mode.'),
-      'type' => 'status',
-    );
-  }
-  elseif ($success && !$offline) {
-    $page_message = array(
-      'message' => t('Installation was completed successfully.'),
-      'type' => 'status',
-    );
+  $offline = variable_get('maintenance_mode', FALSE);
+  if ($success) {
+    // Take the site out of maintenance mode if it was previously that way.
+    if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
+      variable_set('maintenance_mode', FALSE);
+      $page_message = array(
+        'message' => t('Installation was completed successfully. Your site has been taken out of maintenance mode.'),
+        'type' => 'status',
+      );
+    }
+    else {
+      $page_message = array(
+        'message' => t('Installation was completed successfully.'),
+        'type' => 'status',
+      );
+    }
   }
   elseif (!$success && !$offline) {
     $page_message = array(
@@ -260,11 +268,15 @@ function update_authorize_install_batch_finished($success, $results) {
     );
   }
 
+  // Unset the variable since it is no longer needed.
+  unset($_SESSION['maintenance_mode']);
+
   // Set all these values into the SESSION so authorize.php can display them.
   $_SESSION['authorize_results']['success'] = $success;
   $_SESSION['authorize_results']['page_message'] = $page_message;
   $_SESSION['authorize_results']['messages'] = $results['log'];
   $_SESSION['authorize_results']['tasks'] = $results['tasks'];
+  $_SESSION['authorize_operation']['page_title'] = t('Update manager');
 }
 
 /**
diff --git a/modules/update/update.info b/modules/update/update.info
index 24eb18ab367c611fae4dca1adf268c2129b6c9ae..f3f2a4cb0bb1a18ffc800df8c0dbc7dd93a8153f 100644
--- a/modules/update/update.info
+++ b/modules/update/update.info
@@ -1,22 +1,14 @@
-; $Id: update.info,v 1.9 2009/11/17 21:24:18 dries Exp $
+; $Id: update.info,v 1.10 2010/12/20 19:59:43 webchick Exp $
 name = Update manager
 description = Checks for available updates, and can securely install or update modules and themes via a web interface.
 version = VERSION
 package = Core
 core = 7.x
-files[] = update.install
-files[] = update.module
-files[] = update.authorize.inc
-files[] = update.compare.inc
-files[] = update.fetch.inc
-files[] = update.manager.inc
-files[] = update.report.inc
-files[] = update.settings.inc
 files[] = update.test
 configure = admin/reports/updates/settings
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/update/update.install b/modules/update/update.install
index 176973d5d04345152d17ad93483639fdde5777e1..69278bab072ade0c2131906a40a309ab3f338bcd 100644
--- a/modules/update/update.install
+++ b/modules/update/update.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.install,v 1.20 2010/10/03 22:44:48 dries Exp $
+// $Id: update.install,v 1.21 2011/01/02 17:26:39 webchick Exp $
 
 /**
  * @file
@@ -160,7 +160,7 @@ function _update_requirement_check($project, $type) {
 }
 
 /**
- * @defgroup updates-6.x-to-7.x Filter updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -187,6 +187,5 @@ function update_update_7001() {
 }
 
 /**
- * @} End of "defgroup updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/update/update.manager.inc b/modules/update/update.manager.inc
index 24a4cf26c770ee8326ab09888e2a5e6f3ab606c5..a6707bcc3bfe5ad223d5de04e5182c511514e88c 100644
--- a/modules/update/update.manager.inc
+++ b/modules/update/update.manager.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.manager.inc,v 1.24 2010/07/29 02:27:43 dries Exp $
+// $Id: update.manager.inc,v 1.34 2011/01/03 02:53:07 webchick Exp $
 
 /**
  * @file
@@ -37,8 +37,11 @@
  */
 
 /**
- * @defgroup update_manager_update Update manager for updating existing code.
+ * @defgroup update_manager_update Update manager: update
  * @{
+ * Update manager for updating existing code.
+ *
+ * Provides a user interface to update existing code.
  */
 
 /**
@@ -56,6 +59,10 @@
  *   The form array for selecting which projects to update.
  */
 function update_manager_update_form($form, $form_state = array(), $context) {
+  if (!_update_manager_check_backends($form, 'update')) {
+    return $form;
+  }
+
   $form['#theme'] = 'update_manager_update_form';
 
   $available = update_get_available(TRUE);
@@ -112,7 +119,7 @@ function update_manager_update_form($form, $form_state = array(), $context) {
     }
 
     $recommended_release = $project['releases'][$project['recommended']];
-    $recommended_version = $recommended_release['version'] . ' ' . l(t('(Release notes)'), $recommended_release['release_link'], array('attributes' => array('title' => t('Release notes for @project_name', array('@project_name' => $project_name)))));
+    $recommended_version = $recommended_release['version'] . ' ' . l(t('(Release notes)'), $recommended_release['release_link'], array('attributes' => array('title' => t('Release notes for @project_title', array('@project_title' => $project['title'])))));
     if ($recommended_release['version_major'] != $project['existing_major']) {
       $recommended_version .= '<div title="Major upgrade warning" class="update-major-version-warning">' . t('This update is a major version update which means that it may not be backwards compatible with your currently running version.  It is recommended that you read the release notes and proceed at your own risk.') . '</div>';
     }
@@ -351,13 +358,17 @@ function update_manager_download_batch_finished($success, $results) {
  * file transfer credentials and attempt to complete the update.
  */
 function update_manager_update_ready_form($form, &$form_state) {
+  if (!_update_manager_check_backends($form, 'update')) {
+    return $form;
+  }
+
   $form['backup'] = array(
     '#prefix' => '<strong>',
     '#markup' => t('Back up your database and site before you continue. <a href="@backup_url">Learn how</a>.', array('@backup_url' => url('http://drupal.org/node/22281'))),
     '#suffix' => '</strong>',
   );
 
-  $form['site_offline'] = array(
+  $form['maintenance_mode'] = array(
     '#title' => t('Perform updates with site in maintenance mode (strongly recommended)'),
     '#type' => 'checkbox',
     '#default_value' => TRUE,
@@ -386,8 +397,10 @@ function update_manager_update_ready_form($form, &$form_state) {
  * @see system_authorized_get_url()
  */
 function update_manager_update_ready_form_submit($form, &$form_state) {
-  if ($form_state['values']['site_offline'] == TRUE) {
-    variable_set('site_offline', TRUE);
+  // Store maintenance_mode setting so we can restore it when done.
+  $_SESSION['maintenance_mode'] = variable_get('maintenance_mode', FALSE);
+  if ($form_state['values']['maintenance_mode'] == TRUE) {
+    variable_set('maintenance_mode', TRUE);
   }
 
   if (!empty($_SESSION['update_manager_update_projects'])) {
@@ -425,7 +438,7 @@ function update_manager_update_ready_form_submit($form, &$form_state) {
     // credentials and invoke update_authorize_run_update() indirectly with
     // whatever FileTransfer object authorize.php creates for us.
     else {
-      system_authorized_init('update_authorize_run_update', drupal_get_path('module', 'update') . '/update.authorize.inc', array($updates));
+      system_authorized_init('update_authorize_run_update', drupal_get_path('module', 'update') . '/update.authorize.inc', array($updates), t('Update manager'));
       $form_state['redirect'] = system_authorized_get_url();
     }
   }
@@ -436,8 +449,11 @@ function update_manager_update_ready_form_submit($form, &$form_state) {
  */
 
 /**
- * @defgroup update_manager_install Update manager for installing new code.
+ * @defgroup update_manager_install Update manager: install
  * @{
+ * Update manager for installing new code.
+ *
+ * Provides a user interface to install new code.
  */
 
 /**
@@ -455,11 +471,18 @@ function update_manager_update_ready_form_submit($form, &$form_state) {
  *   The form array for selecting which project to install.
  */
 function update_manager_install_form($form, &$form_state, $context) {
-  $form = array();
+  if (!_update_manager_check_backends($form, 'install')) {
+    return $form;
+  }
 
   $form['help_text'] = array(
     '#prefix' => '<p>',
-    '#markup' => t('To install a new module or theme, either enter the URL of an archive file you wish to install, or upload the archive file that you have downloaded. You can find <a href="@module_url">modules</a> and <a href="@theme_url">themes</a> at <a href="@drupal_org_url">http://drupal.org</a>.<br/>The following archive extensions are supported: %extensions.', array('@module_url' => 'http://drupal.org/project/modules', '@theme_url' => 'http://drupal.org/project/themes', '@drupal_org_url' => 'http://drupal.org', '%extensions' => archiver_get_extensions())),
+    '#markup' => t('You can find <a href="@module_url">modules</a> and <a href="@theme_url">themes</a> on <a href="@drupal_org_url">drupal.org</a>. The following file extensions are supported: %extensions.', array(
+      '@module_url' => 'http://drupal.org/project/modules',
+      '@theme_url' => 'http://drupal.org/project/themes',
+      '@drupal_org_url' => 'http://drupal.org',
+      '%extensions' => archiver_get_extensions(),
+    )),
     '#suffix' => '</p>',
   );
 
@@ -490,6 +513,73 @@ function update_manager_install_form($form, &$form_state, $context) {
   return $form;
 }
 
+/**
+ * Checks for file transfer backends and prepares a form fragment about them.
+ *
+ * @param array $form
+ *   Reference to the form array we're building.
+ * @param string $operation
+ *   The Update manager operation we're in the middle of. Can be either
+ *   'update' or 'install'. Use to provide operation-specific interface text.
+ *
+ * @return
+ *   TRUE if the Update manager should continue to the next step in the
+ *   workflow, or FALSE if we've hit a fatal configuration and must halt the
+ *   workflow.
+ */
+function _update_manager_check_backends(&$form, $operation) {
+  // If file transfers will be performed locally, we do not need to display any
+  // warnings or notices to the user and should automatically continue the
+  // workflow, since we won't be using a FileTransfer backend that requires
+  // user input or a specific server configuration.
+  if (update_manager_local_transfers_allowed()) {
+    return TRUE;
+  }
+
+  // Otherwise, show the available backends.
+  $form['available_backends'] = array(
+    '#prefix' => '<p>',
+    '#suffix' => '</p>',
+  );
+
+  $available_backends = drupal_get_filetransfer_info();
+  if (empty($available_backends)) {
+    if ($operation == 'update') {
+      $form['available_backends']['#markup'] = t('Your server does not support updating modules and themes from this interface. Instead, update modules and themes by uploading the new versions directly to the server, as described in the <a href="@handbook_url">handbook</a>.', array('@handbook_url' => 'http://drupal.org/getting-started/install-contrib'));
+    }
+    else {
+      $form['available_backends']['#markup'] = t('Your server does not support installing modules and themes from this interface. Instead, install modules and themes by uploading them directly to the server, as described in the <a href="@handbook_url">handbook</a>.', array('@handbook_url' => 'http://drupal.org/getting-started/install-contrib'));
+    }
+    return FALSE;
+  }
+
+  $backend_names = array();
+  foreach ($available_backends as $backend) {
+    $backend_names[] = $backend['title'];
+  }
+  if ($operation == 'update') {
+    $form['available_backends']['#markup'] = format_plural(
+      count($available_backends),
+      'Updating modules and themes requires <strong>@backends access</strong> to your server. See the <a href="@handbook_url">handbook</a> for other update methods.',
+      'Updating modules and themes requires access to your server via one of the following methods: <strong>@backends</strong>. See the <a href="@handbook_url">handbook</a> for other update methods.',
+      array(
+        '@backends' => implode(', ', $backend_names),
+        '@handbook_url' => 'http://drupal.org/getting-started/install-contrib',
+      ));
+  }
+  else {
+    $form['available_backends']['#markup'] = format_plural(
+      count($available_backends),
+      'Installing modules and themes requires <strong>@backends access</strong> to your server. See the <a href="@handbook_url">handbook</a> for other installation methods.',
+      'Installing modules and themes requires access to your server via one of the following methods: <strong>@backends</strong>. See the <a href="@handbook_url">handbook</a> for other installation methods.',
+      array(
+        '@backends' => implode(', ', $backend_names),
+        '@handbook_url' => 'http://drupal.org/getting-started/install-contrib',
+      ));
+  }
+  return TRUE;
+}
+
 /**
  * Validate the form for installing a new project via the update manager.
  */
@@ -557,11 +647,16 @@ function update_manager_install_form_submit($form, &$form_state) {
   // Unfortunately, we can only use the directory name for this. :(
   $project = drupal_substr($files[0], 0, -1);
 
-  try {
-    update_manager_archive_verify($project, $local_cache, $directory);
-  }
-  catch (Exception $e) {
-    form_set_error($field, $e->getMessage());
+  $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
+  if (!empty($archive_errors)) {
+    form_set_error($field, array_shift($archive_errors));
+    // @todo: Fix me in D8: We need a way to set multiple errors on the same
+    // form element and have all of them appear!
+    if (!empty($archive_errors)) {
+      foreach ($archive_errors as $error) {
+        drupal_set_message($error, 'error');
+      }
+    }
     return;
   }
 
@@ -569,8 +664,21 @@ function update_manager_install_form_submit($form, &$form_state) {
   drupal_get_updaters();
 
   $project_location = $directory . '/' . $project;
-  $updater = Updater::factory($project_location);
-  $project_title = Updater::getProjectTitle($project_location);
+  try {
+    $updater = Updater::factory($project_location);
+  }
+  catch (Exception $e) {
+    form_set_error($field, $e->getMessage());
+    return;
+  }
+
+  try {
+    $project_title = Updater::getProjectTitle($project_location);
+  }
+  catch (Exception $e) {
+    form_set_error($field, $e->getMessage());
+    return;
+  }
 
   if (!$project_title) {
     form_set_error($field, t('Unable to determine %project name.', array('%project' => $project)));
@@ -602,7 +710,7 @@ function update_manager_install_form_submit($form, &$form_state) {
   // credentials and invoke update_authorize_run_install() indirectly with
   // whatever FileTransfer object authorize.php creates for us.
   else {
-    system_authorized_init('update_authorize_run_install', drupal_get_path('module', 'update') . '/update.authorize.inc', $arguments);
+    system_authorized_init('update_authorize_run_install', drupal_get_path('module', 'update') . '/update.authorize.inc', $arguments, t('Update manager'));
     $form_state['redirect'] = system_authorized_get_url();
   }
 }
@@ -612,8 +720,12 @@ function update_manager_install_form_submit($form, &$form_state) {
  */
 
 /**
- * @defgroup update_manager_file Update manager file management functions.
+ * @defgroup update_manager_file Update manager: file management
  * @{
+ * Update manager file management functions.
+ *
+ * These functions are used by the update manager to copy, extract
+ * and verify archive files.
  */
 
 /**
@@ -654,6 +766,18 @@ function update_manager_archive_extract($file, $directory) {
   if (!$archiver) {
     throw new Exception(t('Cannot extract %file, not a valid archive.', array ('%file' => $file)));
   }
+
+  // Remove the directory if it exists, otherwise it might contain a mixture of
+  // old files mixed with the new files (e.g. in cases where files were removed
+  // from a later release).
+  $files = $archiver->listContents();
+  // Unfortunately, we can only use the directory name for this. :(
+  $project = drupal_substr($files[0], 0, -1);
+  $extract_location = $directory . '/' . $project;
+  if (file_exists($extract_location)) {
+    file_unmanaged_delete_recursive($extract_location);
+  }
+
   $archiver->extract($directory);
   return $archiver;
 }
@@ -670,15 +794,13 @@ function update_manager_archive_extract($file, $directory) {
  * @param string $directory
  *   The directory that the archive was extracted into.
  *
- * @return void
- * @throws Exception on failure.
+ * @return array
+ *   An array of error messages to display if the archive was invalid. If
+ *   there are no errors, it will be an empty array.
  *
  */
 function update_manager_archive_verify($project, $archive_file, $directory) {
-  $failures = module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
-  if (!empty($failures)) {
-    throw new Exception(t('Unable to extract %file', array('%file' => $archive_file)));
-  }
+  return module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
 }
 
 /**
@@ -708,8 +830,8 @@ function update_manager_file_get($url) {
     mkdir($cache_directory);
   }
 
-  if (!file_exists($local)) {
-    return system_retrieve_file($url, $local);
+  if (!file_exists($local) || update_delete_file_if_stale($local)) {
+    return system_retrieve_file($url, $local, FALSE, FILE_EXISTS_REPLACE);
   }
   else {
     return $local;
@@ -758,11 +880,13 @@ function update_manager_batch_project_get($project, $url, &$context) {
   }
 
   // Verify it.
-  try {
-    update_manager_archive_verify($project, $local_cache, $extract_directory);
-  }
-  catch (Exception $e) {
-    $context['results']['errors'][$project] = $e->getMessage();
+  $archive_errors = update_manager_archive_verify($project, $local_cache, $extract_directory);
+  if (!empty($archive_errors)) {
+    // We just need to make sure our array keys don't collide, so use the
+    // numeric keys from the $archive_errors array.
+    foreach ($archive_errors as $key => $error) {
+      $context['results']['errors']["$project-$key"] = $error;
+    }
     return;
   }
 
@@ -771,6 +895,41 @@ function update_manager_batch_project_get($project, $url, &$context) {
   $context['finished'] = 1;
 }
 
+/**
+ * Determines if file transfers will be performed locally.
+ *
+ * If the server is configured such that webserver-created files have the same
+ * owner as the configuration directory (e.g. sites/default) where new code
+ * will eventually be installed, the Update manager can transfer files entirely
+ * locally, without changing their ownership (in other words, without prompting
+ * the user for FTP, SSH or other credentials).
+ *
+ * This server configuration is an inherent security weakness because it allows
+ * a malicious webserver process to append arbitrary PHP code and then execute
+ * it. However, it is supported here because it is a common configuration on
+ * shared hosting, and there is nothing Drupal can do to prevent it.
+ *
+ * @return
+ *   TRUE if local file transfers are allowed on this server, or FALSE if not.
+ *
+ * @see update_manager_update_ready_form_submit()
+ * @see update_manager_install_form_submit()
+ * @see install_check_requirements()
+ */
+function update_manager_local_transfers_allowed() {
+  // Compare the owner of a webserver-created temporary file to the owner of
+  // the configuration directory to determine if local transfers will be
+  // allowed.
+  $temporary_file = drupal_tempnam('temporary://', 'update_');
+  $local_transfers_allowed = fileowner($temporary_file) === fileowner(conf_path());
+
+  // Clean up. If this fails, we can ignore it (since this is just a temporary
+  // file anyway).
+  @drupal_unlink($temporary_file);
+
+  return $local_transfers_allowed;
+}
+
 /**
  * @} End of "defgroup update_manager_file".
  */
diff --git a/modules/update/update.module b/modules/update/update.module
index c4063b89ff2c5d6c5dad3416b173184fb433ec39..f7209c4c6dee04c74b4df0e25b4675f9bab6d891 100644
--- a/modules/update/update.module
+++ b/modules/update/update.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.module,v 1.70 2010/10/06 13:36:30 dries Exp $
+// $Id: update.module,v 1.75 2011/01/03 02:17:34 webchick Exp $
 
 /**
  * @file
@@ -301,6 +301,9 @@ function update_cron() {
     // missing data, and if so, try to fetch the data.
     update_get_available(TRUE);
   }
+
+  // Clear garbage from disk.
+  update_clear_update_disk_cache();
 }
 
 /**
@@ -640,9 +643,76 @@ function theme_update_last_check($variables) {
   return $output;
 }
 
+/**
+ * Implements hook_verify_update_archive().
+ *
+ * First, we ensure that the archive isn't a copy of Drupal core, which the
+ * Update manager does not yet support. @see http://drupal.org/node/606592
+ *
+ * Then, we make sure that at least one module included in the archive file has
+ * an .info file which claims that the code is compatible with the current
+ * version of Drupal core.
+ *
+ * @see drupal_system_listing()
+ * @see _system_rebuild_module_data()
+ */
+function update_verify_update_archive($project, $archive_file, $directory) {
+  $errors = array();
+
+  // Make sure this isn't a tarball of Drupal core.
+  if (
+    file_exists("$directory/$project/index.php")
+    && file_exists("$directory/$project/update.php")
+    && file_exists("$directory/$project/includes/bootstrap.inc")
+    && file_exists("$directory/$project/modules/node/node.module")
+    && file_exists("$directory/$project/modules/system/system.module")
+  ) {
+    return array(
+      'no-core' => t('Automatic updating of Drupal core is not supported. See the <a href="@upgrade-guide">upgrade guide</a> for information on how to update Drupal core manually.', array('@upgrade-guide' => 'http://drupal.org/upgrade')),
+    );
+  }
+
+  // Parse all the .info files and make sure at least one is compatible with
+  // this version of Drupal core. If one is compatible, then the project as a
+  // whole is considered compatible (since, for example, the project may ship
+  // with some out-of-date modules that are not necessary for its overall
+  // functionality).
+  $compatible_project = FALSE;
+  $incompatible = array();
+  $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', array('key' => 'name', 'min_depth' => 0));
+  foreach ($files as $key => $file) {
+    // Get the .info file for the module or theme this file belongs to.
+    $info = drupal_parse_info_file($file->uri);
+
+    // If the module or theme is incompatible with Drupal core, set an error.
+    if (empty($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
+      $incompatible[] = !empty($info['name']) ? $info['name'] : t('Unknown');
+    }
+    else {
+      $compatible_project = TRUE;
+      break;
+    }
+  }
+
+  if (empty($files)) {
+    $errors[] = t('%archive_file does not contain any .info files.', array('%archive_file' => basename($archive_file)));
+  }
+  elseif (!$compatible_project) {
+    $errors[] = format_plural(
+      count($incompatible),
+      '%archive_file contains a version of %names that is not compatible with Drupal !version.',
+      '%archive_file contains versions of modules or themes that are not compatible with Drupal !version: %names',
+      array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => basename($archive_file), '%names' => implode(', ', $incompatible))
+    );
+  }
+
+  return $errors;
+}
+
 /**
  * @defgroup update_status_cache Private update status cache system
  * @{
+ * Functions to manage the update status cache.
  *
  * We specifically do NOT use the core cache API for saving the fetched data
  * about available updates. It is vitally important that this cache is only
@@ -786,3 +856,46 @@ function update_flush_caches() {
 /**
  * @} End of "defgroup update_status_cache".
  */
+
+/**
+ * Clear the temporary files and directories based on file age from disk.
+ */
+function update_clear_update_disk_cache() {
+  // List of update module cache directories.
+  $directories = array(
+    'temporary://update-cache',
+    'temporary://update-extraction',
+  );
+
+  // Search for files and directories in base folder only without recursion.
+  foreach ($directories as $directory) {
+    file_scan_directory($directory, '/.*/', array('callback' => 'update_delete_file_if_stale', 'recurse' => FALSE));
+  }
+}
+
+/**
+ * Delete stale files and directories from the Update manager disk cache.
+ *
+ * Files and directories older than 6 hours and development snapshots older
+ * than 5 minutes are considered stale. We only cache development snapshots
+ * for 5 minutes since otherwise updated snapshots might not be downloaded as
+ * expected.
+ *
+ * When checking file ages, we need to use the ctime, not the mtime
+ * (modification time) since many (all?) tar implementations go out of their
+ * way to set the mtime on the files they create to the timestamps recorded
+ * in the tarball. We want to see the last time the file was changed on disk,
+ * which is left alone by tar and correctly set to the time the archive file
+ * was unpacked.
+ *
+ * @param $path
+ *   A string containing a file path or (streamwrapper) URI.
+ */
+function update_delete_file_if_stale($path) {
+  if (file_exists($path)) {
+    $filectime = filectime($path);
+    if (REQUEST_TIME - $filectime > DRUPAL_MAXIMUM_TEMP_FILE_AGE || (preg_match('/.*-dev\.(tar\.gz|zip)/i', $path) && REQUEST_TIME - $filectime > 300)) {
+      file_unmanaged_delete_recursive($path);
+    }
+  }
+}
diff --git a/modules/update/update.test b/modules/update/update.test
index 8f87c3431f4b44dbddac0f5213da00ad087e80af..6cb44914acf6dada05359195b81c58c34284cbbd 100644
--- a/modules/update/update.test
+++ b/modules/update/update.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.test,v 1.19 2010/10/06 13:36:30 dries Exp $
+// $Id: update.test,v 1.22 2011/01/03 02:41:33 webchick Exp $
 
 /**
  * @file
@@ -592,8 +592,12 @@ class UpdateTestUploadCase extends UpdateTestHelper {
    * Tests upload and extraction of a module.
    */
   public function testUploadModule() {
-    // Images are not valid archives, so get one and try to install it.
-    $invalidArchiveFile = reset($this->drupalGetTestFiles('image'));
+    // Images are not valid archives, so get one and try to install it. We
+    // need an extra variable to store the result of drupalGetTestFiles()
+    // since reset() takes an argument by reference and passing in a constant
+    // emits a notice in strict mode.
+    $imageTestFiles = $this->drupalGetTestFiles('image');
+    $invalidArchiveFile = reset($imageTestFiles);
     $edit = array(
       'files[project_upload]' => $invalidArchiveFile->uri,
     );
@@ -618,9 +622,9 @@ class UpdateTestUploadCase extends UpdateTestHelper {
   function testFileNameExtensionMerging() {
     $this->drupalGet('admin/modules/install');    
     // Make sure the bogus extension supported by update_test.module is there.
-    $this->assertPattern('/archive extensions are supported:.*update-test-extension/', t("Found 'update-test-extension' extension"));
+    $this->assertPattern('/file extensions are supported:.*update-test-extension/', t("Found 'update-test-extension' extension"));
     // Make sure it didn't clobber the first option from core.
-    $this->assertPattern('/archive extensions are supported:.*zip/', t("Found 'zip' extension"));
+    $this->assertPattern('/file extensions are supported:.*tar/', t("Found 'tar' extension"));
   }
 
   /**
diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..1fb6a9a1d602f95f3af92f5065880eb3a1342291
--- /dev/null
+++ b/modules/user/tests/user_form_test.info
@@ -0,0 +1,13 @@
+; $Id: user_form_test.info,v 1.2 2010/12/21 16:31:47 webchick Exp $
+name = "User module form tests"
+description = "Support module for user form testing."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
+project = "drupal"
+datestamp = "1294208756"
+
diff --git a/modules/user/tests/user_form_test.module b/modules/user/tests/user_form_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..ccb21f7f05a55966aa44f52698989727a16ef29d
--- /dev/null
+++ b/modules/user/tests/user_form_test.module
@@ -0,0 +1,65 @@
+<?php
+// $Id: user_form_test.module,v 1.1 2010/12/11 06:22:33 webchick Exp $
+
+/**
+ * @file
+ * Dummy module implementing a form to test user password validation
+ */
+
+/**
+ * Implements hook_menu().
+ *
+ * Sets up a form that allows a user to validate password.
+ */
+function user_form_test_menu() {
+  $items = array();
+  $items['user_form_test_current_password/%user'] = array(
+    'title' => 'User form test for current password validation',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('user_form_test_current_password',1),
+    'access arguments' => array('administer users'),
+    'type' => MENU_SUGGESTED_ITEM,
+  );
+  return $items;
+}
+
+/**
+ * A test form for user_validate_current_pass().
+ */
+function user_form_test_current_password($form, &$form_state, $account) {
+  $account->user_form_test_field = '';
+  $form['#user'] = $account;
+
+  $form['user_form_test_field'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Test field'),
+    '#description' => t('A field that would require a correct password to change.'),
+    '#required' => TRUE,
+  );
+  
+  $form['current_pass'] = array(
+    '#type' => 'password',
+    '#title' => t('Current password'),
+    '#size' => 25,
+    '#description' => t('Enter your current password'),
+  );
+
+  $form['current_pass_required_values'] = array(
+    '#type' => 'value',
+    '#value' => array('user_form_test_field' => t('Test field')),
+  );
+
+  $form['#validate'][] = 'user_validate_current_pass';
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Test'),
+  );
+  return $form;
+}
+
+/**
+ * Submit function for the test form for user_validate_current_pass().
+ */
+function user_form_test_current_password_submit($form, &$form_state) {
+  drupal_set_message(t('The password has been validated and the form submitted successfully.'));
+}
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index 9ced79d524e8f81f019fa2e7365af8ebe43e068c..4bfb3c12b4564e7d7e63d8e99224064cfa1f45cb 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.admin.inc,v 1.120 2010/10/20 01:31:07 dries Exp $
+// $Id: user.admin.inc,v 1.124 2010/12/15 02:59:01 webchick Exp $
 
 /**
  * @file
@@ -99,7 +99,7 @@ function user_filter_form() {
     );
   }
 
-  drupal_add_js('misc/form.js');
+  drupal_add_library('system', 'drupal.form');
 
   return $form;
 }
@@ -678,11 +678,11 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
   // display name.
   $modules = array();
   foreach (module_implements('permission') as $module) {
-    $modules[$module_info[$module]['name']] = $module;
+    $modules[$module] = $module_info[$module]['name'];
   }
-  ksort($modules);
+  asort($modules);
 
-  foreach ($modules as $display_name => $module) {
+  foreach ($modules as $module => $display_name) {
     if ($permissions = module_invoke($module, 'permission')) {
       $form['permission'][] = array(
         '#markup' => $module_info[$module]['name'],
@@ -767,7 +767,7 @@ function theme_user_admin_permissions($variables) {
         'class' => array('permission'),
       );
       foreach (element_children($form['checkboxes']) as $rid) {
-        $form['checkboxes'][$rid][$key]['#title'] = $roles[$rid] . ': ' . t($key);
+        $form['checkboxes'][$rid][$key]['#title'] = $roles[$rid] . ': ' . $form['permission'][$key]['#markup'];
         $form['checkboxes'][$rid][$key]['#title_display'] = 'invisible';
         $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'class' => array('checkbox'));
       }
@@ -878,6 +878,7 @@ function user_admin_roles_order_submit($form, &$form_state) {
     $role->weight = $role_values['weight'];
     user_role_save($role);
   }
+  drupal_set_message(t('The role settings have been updated.'));
 }
 
 /**
diff --git a/modules/user/user.api.php b/modules/user/user.api.php
index f2b7d390c3a8f103d3df6a55aa860307489ce556..437e01d6d3b4058c6f464299875ae6cefea41969 100644
--- a/modules/user/user.api.php
+++ b/modules/user/user.api.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.api.php,v 1.24 2010/10/03 01:15:34 dries Exp $
+// $Id: user.api.php,v 1.27 2010/12/11 19:16:42 webchick Exp $
 
 /**
  * @file
@@ -38,6 +38,9 @@ function hook_user_load($users) {
  * removed from the user tables in the database, and before
  * field_attach_delete() is called.
  *
+ * Modules should additionally implement hook_user_cancel() to process stored
+ * user data for other account cancellation methods.
+ *
  * @param $account
  *   The account that is being deleted.
  *
@@ -52,11 +55,17 @@ function hook_user_delete($account) {
 /**
  * Act on user account cancellations.
  *
- * The user account is being canceled. Depending on the account cancellation
- * method, the module should either do nothing, unpublish content, or anonymize
- * content.
+ * This hook is invoked from user_cancel() before a user account is canceled.
+ * Depending on the account cancellation method, the module should either do
+ * nothing, unpublish content, or anonymize content. See user_cancel_methods()
+ * for the list of default account cancellation methods provided by User module.
+ * Modules may add further methods via hook_user_cancel_methods_alter().
+ *
+ * This hook is NOT invoked for the 'user_cancel_delete' account cancellation
+ * method. To react on this method, implement hook_user_delete() instead.
  *
- * Expensive operations should be added to the global batch with batch_set().
+ * Expensive operations should be added to the global account cancellation batch
+ * by using batch_set().
  *
  * @param $edit
  *   The array of form values submitted by the user.
@@ -67,7 +76,6 @@ function hook_user_delete($account) {
  *
  * @see user_cancel_methods()
  * @see hook_user_cancel_methods_alter()
- * @see user_cancel()
  */
 function hook_user_cancel($edit, $account, $method) {
   switch ($method) {
@@ -284,8 +292,8 @@ function hook_user_update(&$edit, $account, $category) {
  */
 function hook_user_login(&$edit, $account) {
   // If the user has a NULL time zone, notify them to set a time zone.
-  if (!$user->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) {
-    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => url("user/$user->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
+  if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) {
+    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
   }
 }
 
@@ -316,6 +324,9 @@ function hook_user_logout($account) {
  *   View mode, e.g. 'full'.
  * @param $langcode
  *   The language code used for rendering.
+ *
+ * @see hook_user_view_alter()
+ * @see hook_entity_view()
  */
 function hook_user_view($account, $view_mode, $langcode) {
   if (user_access('create blog content', $account)) {
@@ -344,6 +355,7 @@ function hook_user_view($account, $view_mode, $langcode) {
  *   A renderable array representing the user.
  *
  * @see user_view()
+ * @see hook_entity_view_alter()
  */
 function hook_user_view_alter(&$build) {
   // Check for the existence of a field added by another module.
diff --git a/modules/user/user.info b/modules/user/user.info
index daea44507fb9ba78d663bd9759c1219439c90a5a..714d1fdfb415a2b9db51855151aebe625257a605 100644
--- a/modules/user/user.info
+++ b/modules/user/user.info
@@ -1,21 +1,17 @@
-; $Id: user.info,v 1.14 2010/09/05 02:21:38 dries Exp $
+; $Id: user.info,v 1.15 2010/12/20 19:59:44 webchick Exp $
 name = User
 description = Manages the user registration and login system.
 package = Core
 version = VERSION
 core = 7.x
 files[] = user.module
-files[] = user.admin.inc
-files[] = user.pages.inc
-files[] = user.install
 files[] = user.test
-files[] = user.tokens.inc
 required = TRUE
 configure = admin/config/people
 stylesheets[all][] = user.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/modules/user/user.install b/modules/user/user.install
index a6947277af103352d7221e040705ed96d475f073..6ee922649705975d734c9f87191da1a550299d74 100644
--- a/modules/user/user.install
+++ b/modules/user/user.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.install,v 1.68 2010/10/20 01:15:58 dries Exp $
+// $Id: user.install,v 1.69 2011/01/02 17:26:40 webchick Exp $
 
 /**
  * @file
@@ -393,7 +393,7 @@ function _update_7000_user_role_grant_permissions($rid, array $permissions, $mod
 }
 
 /**
- * @defgroup user-updates-6.x-to-7.x User updates from 6.x to 7.x
+ * @addtogroup updates-6.x-to-7.x
  * @{
  */
 
@@ -855,6 +855,5 @@ function user_update_7015() {
 }
 
 /**
- * @} End of "defgroup user-updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
+ * @} End of "addtogroup updates-6.x-to-7.x"
  */
diff --git a/modules/user/user.js b/modules/user/user.js
index 1336d44735da3f1e9139ee44fcf21712c63839e8..7549a302250667039ec7fe06525fe1dcafd3e3e5 100644
--- a/modules/user/user.js
+++ b/modules/user/user.js
@@ -1,4 +1,4 @@
-// $Id: user.js,v 1.24 2010/07/20 10:17:59 dries Exp $
+// $Id: user.js,v 1.25 2010/11/30 23:55:11 webchick Exp $
 (function ($) {
 
 /**
@@ -173,4 +173,25 @@ Drupal.evaluatePasswordStrength = function (password, translate) {
 
 };
 
+/**
+ * Field instance settings screen: force the 'Display on registration form'
+ * checkbox checked whenever 'Required' is checked.
+ */
+Drupal.behaviors.fieldUserRegistration = {
+  attach: function (context, settings) {
+    var $checkbox = $('form#field-ui-field-edit-form input#edit-instance-settings-user-register-form');
+
+    if ($checkbox.size()) {
+      $('input#edit-instance-required', context).once('user-register-form-checkbox', function () {
+        $(this).bind('change', function (e) {
+          if ($(this).attr('checked')) {
+            $checkbox.attr('checked', true);
+          }
+        });
+      });
+
+    }
+  }
+};
+
 })(jQuery);
diff --git a/modules/user/user.module b/modules/user/user.module
index cb3fc55dba227e922fee7cc387840f2305515451..934293562848f8e2ec05e193cd2aafa2d5c6c870 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.module,v 1.1212 2010/10/23 03:20:40 webchick Exp $
+// $Id: user.module,v 1.1229 2010/12/28 21:46:23 webchick Exp $
 
 /**
  * @file
@@ -176,6 +176,19 @@ function user_uri($user) {
   );
 }
 
+/**
+ * Implements hook_field_info_alter().
+ */
+function user_field_info_alter(&$info) {
+  // Add the 'user_register_form' instance setting to all field types.
+  foreach ($info as $field_type => &$field_type_info) {
+    $field_type_info += array('instance_settings' => array());
+    $field_type_info['instance_settings'] += array(
+      'user_register_form' => FALSE,
+    );
+  }
+}
+
 /**
  * Implements hook_field_extra_fields().
  */
@@ -235,11 +248,15 @@ function user_external_load($authname) {
  * @param $uids
  *   An array of user IDs.
  * @param $conditions
- *   An array of conditions to match against the {users} table. These
- *   should be supplied in the form array('field_name' => 'field_value').
+ *   (deprecated) An associative array of conditions on the {users}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have. Instead, it is preferable to use
+ *   EntityFieldQuery to retrieve a list of entity IDs loadable by
+ *   this function.
  * @param $reset
  *   A boolean indicating that the internal cache should be reset. Use this if
  *   loading a user object which has been altered during the page request.
+ *
  * @return
  *   An array of user objects, indexed by uid.
  *
@@ -247,6 +264,9 @@ function user_external_load($authname) {
  * @see user_load()
  * @see user_load_by_mail()
  * @see user_load_by_name()
+ * @see EntityFieldQuery
+ *
+ * @todo Remove $conditions in Drupal 8.
  */
 function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) {
   return entity_load('user', $uids, $conditions, $reset);
@@ -378,6 +398,8 @@ function user_load_by_name($name) {
  *
  * @return
  *   A fully-loaded $user object upon successful save or FALSE if the save failed.
+ *
+ * @todo D8: Drop $edit and fix user_save() to be consistent with others.
  */
 function user_save($account, $edit = array(), $category = 'account') {
   $transaction = db_transaction();
@@ -398,10 +420,10 @@ function user_save($account, $edit = array(), $category = 'account') {
       unset($edit['pass']);
     }
 
-    // Presave field allowing changing of $edit.
-    $edit = (object) $edit;
-    field_attach_presave('user', $edit);
-    $edit = (array) $edit;
+    // Load the stored entity, if any.
+    if (!empty($account->uid) && !isset($account->original)) {
+      $account->original = entity_load_unchanged('user', $account->uid);
+    }
 
     if (empty($account)) {
       $account = new stdClass();
@@ -414,15 +436,29 @@ function user_save($account, $edit = array(), $category = 'account') {
     if (!empty($account->data)) {
       $edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data;
     }
+
+    // Invoke hook_user_presave() for all modules.
     user_module_invoke('presave', $edit, $account, $category);
 
-    if (is_object($account) && !$account->is_new) {
-      // Consider users edited by an administrator as logged in, if they haven't
-      // already, so anonymous users can view the profile (if allowed).
-      if (empty($edit['access']) && empty($account->access) && user_access('administer users')) {
-        $edit['access'] = REQUEST_TIME;
+    // Invoke presave operations of Field Attach API and Entity API. Those APIs
+    // require a fully-fledged (and updated) entity object, so $edit is not
+    // necessarily sufficient, as it technically contains submitted form values
+    // only. Therefore, we need to clone $account into a new object and copy any
+    // new property values of $edit into it.
+    $account_updated = clone $account;
+    foreach ($edit as $key => $value) {
+      $account_updated->$key = $value;
+    }
+    field_attach_presave('user', $account_updated);
+    module_invoke_all('entity_presave', $account_updated, 'user');
+    // Update $edit with any changes modules might have applied to the account.
+    foreach ($account_updated as $key => $value) {
+      if (!property_exists($account, $key) || $value !== $account->$key) {
+        $edit[$key] = $value;
       }
+    }
 
+    if (is_object($account) && !$account->is_new) {
       // Process picture uploads.
       if (!$delete_previous_picture = empty($edit['picture']->fid)) {
         $picture = $edit['picture'];
@@ -502,6 +538,10 @@ function user_save($account, $edit = array(), $category = 'account') {
 
       // Refresh user object.
       $user = user_load($account->uid, TRUE);
+      // Make the original, unchanged user account available to update hooks.
+      if (isset($account->original)) {
+        $user->original = $account->original;
+      }
 
       // Send emails after we have the new user object.
       if (isset($edit['status']) && $edit['status'] != $account->status) {
@@ -512,6 +552,7 @@ function user_save($account, $edit = array(), $category = 'account') {
 
       user_module_invoke('update', $edit, $user, $category);
       module_invoke_all('entity_update', $user, 'user');
+      unset($user->original);
     }
     else {
       // Allow 'uid' to be set by the caller. There is no danger of writing an
@@ -523,12 +564,6 @@ function user_save($account, $edit = array(), $category = 'account') {
       if (!isset($edit['created'])) {
         $edit['created'] = REQUEST_TIME;
       }
-      // Consider users created by an administrator as already logged in, so
-      // anonymous users can view the profile (if allowed).
-      if (empty($edit['access']) && user_access('administer users')) {
-        $edit['access'] = REQUEST_TIME;
-      }
-
       $edit['mail'] = trim($edit['mail']);
       $success = drupal_write_record('users', $edit);
       if ($success === FALSE) {
@@ -879,7 +914,7 @@ function user_search_execute($keys = NULL, $conditions = NULL) {
   // Replace wildcards with MySQL/PostgreSQL wildcards.
   $keys = preg_replace('!\*+!', '%', $keys);
   $query = db_select('users')->extend('PagerDefault');
-  $query->fields('users', array('name', 'uid'));
+  $query->fields('users', array('uid'));
   if (user_access('administer users')) {
     // Administrators can also search in the otherwise private email field.
     $query->fields('users', array('mail'));
@@ -890,20 +925,25 @@ function user_search_execute($keys = NULL, $conditions = NULL) {
   else {
     $query->condition('name', '%' . db_like($keys) . '%', 'LIKE');
   }
-  $result = $query
+  $uids = $query
     ->limit(15)
-    ->execute();
-  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)));
+    ->execute()
+    ->fetchCol();
+  $accounts = user_load_multiple($uids);
+
+  $results = array();
+  foreach ($accounts as $account) {
+    $result = array(
+      'title' => format_username($account),
+      'link' => url('user/' . $account->uid, array('absolute' => TRUE)),
+    );
+    if (user_access('administer users')) {
+      $result['title'] .= ' (' . $account->mail . ')';
     }
+    $results[] = $result;
   }
-  return $find;
+
+  return $results;
 }
 
 /**
@@ -1127,8 +1167,6 @@ function user_account_form(&$form, &$form_state) {
  * @see user_account_form()
  */
 function user_validate_current_pass(&$form, &$form_state) {
-  global $user;
-
   $account = $form['#user'];
   foreach ($form_state['values']['current_pass_required_values'] as $key => $name) {
     // This validation only works for required textfields (like mail) or
@@ -1136,7 +1174,7 @@ function user_validate_current_pass(&$form, &$form_state) {
     // that prevent them from being empty if they are changed.
     if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
       require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
-      $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $user);
+      $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
       if ($current_pass_failed) {
         form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
         form_set_error($key);
@@ -1273,10 +1311,13 @@ function user_block_info() {
   $blocks['login']['cache'] = DRUPAL_NO_CACHE;
 
   $blocks['new']['info'] = t('Who\'s new');
+  $blocks['new']['properties']['administrative'] = TRUE;
 
   // Too dynamic to cache.
   $blocks['online']['info'] = t('Who\'s online');
   $blocks['online']['cache'] = DRUPAL_NO_CACHE;
+  $blocks['online']['properties']['administrative'] = TRUE;
+
   return $blocks;
 }
 
@@ -1461,7 +1502,6 @@ function user_register_access() {
   return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
 }
 
-
 /**
  * User view access callback.
  *
@@ -1469,7 +1509,6 @@ function user_register_access() {
  *   Can either be a full user object or a $uid.
  */
 function user_view_access($account) {
-
   $uid = is_object($account) ? $account->uid : (int) $account;
 
   // Never allow access to view the anonymous user account.
@@ -1483,7 +1522,7 @@ function user_view_access($account) {
       if (!is_object($account)) {
         $account = user_load($uid);
       }
-      return (is_object($account) && $account->access && $account->status);
+      return (is_object($account) && $account->status);
     }
   }
   return FALSE;
@@ -1933,7 +1972,7 @@ function user_page_title($account) {
  *   An associative array with module as key and username as value.
  */
 function user_get_authmaps($authname = NULL) {
-  $authmaps = db_query("SELECT authname, module FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed();
+  $authmaps = db_query("SELECT module, authname FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed();
   return count($authmaps) ? $authmaps : 0;
 }
 
@@ -2131,7 +2170,7 @@ function user_login_final_validate($form, &$form_state) {
 function user_authenticate($name, $password) {
   $uid = FALSE;
   if (!empty($name) && !empty($password)) {
-    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $name))->fetchObject();
+    $account = user_load_by_name($name);
     if ($account) {
       // Allow alternate password hashing schemes.
       require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
@@ -2141,13 +2180,7 @@ function user_authenticate($name, $password) {
 
         // Update user to new password scheme if needed.
         if (user_needs_new_hash($account)) {
-          $new_hash = user_hash_password($password);
-          if ($new_hash) {
-            db_update('users')
-              ->fields(array('pass' => $new_hash))
-              ->condition('uid', $account->uid)
-              ->execute();
-          }
+          user_save($account, array('pass' => $password));
         }
       }
     }
@@ -2372,23 +2405,30 @@ function user_delete_multiple(array $uids) {
   if (!empty($uids)) {
     $accounts = user_load_multiple($uids, array());
 
-    foreach ($accounts as $uid => $account) {
-      module_invoke_all('user_delete', $account);
-      module_invoke_all('entity_delete', $account, 'user');
-      field_attach_delete('user', $account);
-      drupal_session_destroy_uid($account->uid);
-    }
-
-    db_delete('users')
-      ->condition('uid', $uids, 'IN')
-      ->execute();
-    db_delete('users_roles')
-      ->condition('uid', $uids, 'IN')
-      ->execute();
-    db_delete('authmap')
-      ->condition('uid', $uids, 'IN')
-      ->execute();
+    $transaction = db_transaction();
+    try {
+      foreach ($accounts as $uid => $account) {
+        module_invoke_all('user_delete', $account);
+        module_invoke_all('entity_delete', $account, 'user');
+        field_attach_delete('user', $account);
+        drupal_session_destroy_uid($account->uid);
+      }
 
+      db_delete('users')
+        ->condition('uid', $uids, 'IN')
+        ->execute();
+      db_delete('users_roles')
+        ->condition('uid', $uids, 'IN')
+        ->execute();
+      db_delete('authmap')
+        ->condition('uid', $uids, 'IN')
+        ->execute();
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('user', $e);
+      throw $e;
+    }
     entity_get_controller('user')->resetCache();
   }
 }
@@ -2452,7 +2492,8 @@ function user_view($account, $view_mode = 'full', $langcode = NULL) {
   );
 
   // Allow modules to modify the structured user.
-  drupal_alter('user_view', $build);
+  $type = 'user';
+  drupal_alter(array('user_view', 'entity_view'), $build, $type);
 
   return $build;
 }
@@ -2483,6 +2524,7 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
 
   // Populate $account->content with a render() array.
   module_invoke_all('user_view', $account, $view_mode, $langcode);
+  module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode);
 }
 
 /**
@@ -2651,7 +2693,9 @@ Your account on [site:name] has been canceled.
   }
 
   if ($replace) {
-    return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens'));
+    // We do not sanitize the token replacement, since the output of this
+    // replacement is intended for an e-mail message, not a web browser.
+    return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE));
   }
 
   return $text;
@@ -3042,6 +3086,9 @@ function user_user_operations_block($accounts) {
   foreach ($accounts as $account) {
     // Skip blocking user if they are already blocked.
     if ($account !== FALSE && $account->status == 1) {
+      // For efficiency manually save the original account before applying any
+      // changes.
+      $account->original = clone $account;
       user_save($account, array('status' => 0));
     }
   }
@@ -3062,6 +3109,9 @@ function user_multiple_role_edit($accounts, $operation, $rid) {
         // Skip adding the role to the user if they already have it.
         if ($account !== FALSE && !isset($account->roles[$rid])) {
           $roles = $account->roles + array($rid => $role_name);
+          // For efficiency manually save the original account before applying
+          // any changes.
+          $account->original = clone $account;
           user_save($account, array('roles' => $roles));
         }
       }
@@ -3072,6 +3122,9 @@ function user_multiple_role_edit($accounts, $operation, $rid) {
         // Skip removing the role from the user if they already don't have it.
         if ($account !== FALSE && isset($account->roles[$rid])) {
           $roles = array_diff($account->roles, array($rid => $role_name));
+          // For efficiency manually save the original account before applying
+          // any changes.
+          $account->original = clone $account;
           user_save($account, array('roles' => $roles));
         }
       }
@@ -3507,6 +3560,55 @@ function user_block_user_action(&$entity, $context = array()) {
   watchdog('action', 'Blocked user %name.', array('%name' => $account->name));
 }
 
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Add a checkbox for the 'user_register_form' instance settings on the 'Edit
+ * field instance' form.
+ */
+function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
+  $instance = $form['#instance'];
+
+  if ($instance['entity_type'] == 'user') {
+    $form['instance']['settings']['user_register_form'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Display on user registration form.'),
+      '#description' => t("This is compulsory for 'required' fields."),
+      // Field instances created in D7 beta releases before the setting was
+      // introduced might be set as 'required' and 'not shown on user_register
+      // form'. We make sure the checkbox comes as 'checked' for those.
+      '#default_value' => $instance['settings']['user_register_form'] || $instance['required'],
+      // Display just below the 'required' checkbox.
+      '#weight' => $form['instance']['required']['#weight'] + .1,
+      // Disabled when the 'required' checkbox is checked.
+      '#states' => array(
+        'enabled' => array('input[name="instance[required]"]' => array('checked' => FALSE)),
+      ),
+      // Checked when the 'required' checkbox is checked. This is done through
+      // a custom behavior, since the #states system would also synchronize on
+      // uncheck.
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'user') . '/user.js'),
+      ),
+    );
+
+    array_unshift($form['#submit'], 'user_form_field_ui_field_edit_form_submit');
+  }
+}
+
+/**
+ * Additional submit handler for the 'Edit field instance' form.
+ *
+ * Make sure the 'user_register_form' setting is set for required fields.
+ */
+function user_form_field_ui_field_edit_form_submit($form, &$form_state) {
+  $instance = $form_state['values']['instance'];
+
+  if (!empty($instance['required'])) {
+    form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state);
+  }
+}
+
 /**
  * Form builder; the user registration form.
  *
@@ -3528,12 +3630,21 @@ function user_register_form($form, &$form_state) {
   $form['#user'] = drupal_anonymous_user();
   $form['#user_category'] = 'register';
 
-  $form['#attached']['library'][] = array('system', 'cookie');
+  $form['#attached']['library'][] = array('system', 'jquery.cookie');
   $form['#attributes']['class'][] = 'user-info-from-cookie';
 
   // Start with the default user account fields.
   user_account_form($form, $form_state);
 
+  // Attach field widgets, and hide the ones where the 'user_register_form'
+  // setting is not on.
+  field_attach_form('user', $form['#user'], $form, $form_state);
+  foreach (field_info_instances('user', 'user') as $field_name => $instance) {
+    if (empty($instance['settings']['user_register_form'])) {
+      $form[$field_name]['#access'] = FALSE;
+    }
+  }
+
   if ($admin) {
     // Redirect back to page which initiated the create request;
     // usually admin/people/create.
@@ -3546,12 +3657,20 @@ function user_register_form($form, &$form_state) {
     '#value' => t('Create new account'),
   );
 
+  $form['#validate'][] = 'user_register_validate';
   // Add the final user registration form submit handler.
   $form['#submit'][] = 'user_register_submit';
 
   return $form;
 }
 
+/**
+ * Validation function for the user registration form.
+ */
+function user_register_validate($form, &$form_state) {
+  entity_form_field_validate('user', $form, $form_state);
+}
+
 /**
  * Submit handler for the user registration form.
  *
@@ -3571,13 +3690,21 @@ function user_register_submit($form, &$form_state) {
   }
   $notify = !empty($form_state['values']['notify']);
 
+  // Remove unneeded values.
   form_state_values_clean($form_state);
 
   $form_state['values']['pass'] = $pass;
   $form_state['values']['init'] = $form_state['values']['mail'];
 
   $account = $form['#user'];
-  $account = user_save($account, $form_state['values']);
+
+  entity_form_submit_build_entity('user', $account, $form, $form_state);
+
+  // Populate $edit with the properties of $account, which have been edited on
+  // this form by taking over all values, which appear in the form values too.
+  $edit = array_intersect_key((array) $account, $form_state['values']);
+  $account = user_save($account, $edit);
+
   // Terminate if an error occurred during user_save().
   if (!$account) {
     drupal_set_message(t("Error saving user account."), 'error');
@@ -3734,13 +3861,13 @@ function user_file_download_access($field, $entity_type, $entity) {
  *
  * To prevent new Drupal 7 sites from installing Profile module, and
  * unwittingly ending up with two completely different and incompatible methods
- * of extending users, remove it from the available modules by setting it to
- * hidden if the profile_* tables are not already present.
+ * of extending users, only make the Profile module available if the profile_*
+ * tables are present.
  *
  * @todo: Remove in D8, pending upgrade path.
  */
 function user_system_info_alter(&$info, $file, $type) {
-  if ($type == 'module' && $file->name == 'profile' && !db_table_exists('profile_field')) {
-    $info['hidden'] = TRUE;
+  if ($type == 'module' && $file->name == 'profile' && db_table_exists('profile_field')) {
+    $info['hidden'] = FALSE;
   }
 }
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
index 0f60a3a69e16f24347b8de94babcbdd11d88e36e..d9ad3bebce190c635757c52cd59520a67929b3c4 100644
--- a/modules/user/user.pages.inc
+++ b/modules/user/user.pages.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.pages.inc,v 1.75 2010/08/27 11:28:45 webchick Exp $
+// $Id: user.pages.inc,v 1.78 2010/12/01 00:29:41 webchick Exp $
 
 /**
  * @file
@@ -260,11 +260,10 @@ function user_profile_form($form, &$form_state, $account, $category = 'account')
 
   if ($category == 'account') {
     user_account_form($form, $form_state);
+    // Attach field widgets.
+    field_attach_form('user', $account, $form, $form_state);
   }
 
-  // Attach field widgets.
-  field_attach_form('user', $account, $form, $form_state);
-
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
@@ -454,7 +453,7 @@ function user_cancel_confirm_form_submit($form, &$form_state) {
 /**
  * Helper function to return available account cancellation methods.
  *
- * Please refer to the documentation of hook_user_cancel_methods_alter().
+ * See documentation of hook_user_cancel_methods_alter().
  *
  * @return
  *   An array containing all account cancellation methods as form elements.
@@ -467,19 +466,19 @@ function user_cancel_confirm_form_submit($form, &$form_state) {
 function user_cancel_methods() {
   $methods = array(
     'user_cancel_block' => array(
-      'title' => t('Disable the account and keep all content.'),
+      'title' => t('Disable the account and keep its content.'),
       'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'),
     ),
     'user_cancel_block_unpublish' => array(
-      'title' => t('Disable the account and unpublish all content.'),
+      'title' => t('Disable the account and unpublish its content.'),
       'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'),
     ),
     'user_cancel_reassign' => array(
-      'title' => t('Delete the account and make all content belong to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
+      'title' => t('Delete the account and make its content belong to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
       'description' => t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
     ),
     'user_cancel_delete' => array(
-      'title' => t('Delete the account and all content.'),
+      'title' => t('Delete the account and its content.'),
       'description' => t('Your account will be removed and all account information deleted. All of your content will also be deleted.'),
       'access' => user_access('administer users'),
     ),
diff --git a/modules/user/user.test b/modules/user/user.test
index 0fca3f8ae40324413ec7c810208c47bd12482bc5..064b37e0cd15ecef4bd53e68758719fb1724b11d 100644
--- a/modules/user/user.test
+++ b/modules/user/user.test
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.test,v 1.104 2010/10/23 03:20:40 webchick Exp $
+// $Id: user.test,v 1.111 2010/12/18 00:56:18 dries Exp $
 
 class UserRegistrationTestCase extends DrupalWebTestCase {
   public static function getInfo() {
@@ -10,6 +10,10 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp('field_test');
+  }
+
   function testRegistrationWithEmailVerification() {
     // Require e-mail verification.
     variable_set('user_email_verification', TRUE);
@@ -137,6 +141,91 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
     $this->assertEqual($new_user->picture, '', t('Correct picture field.'));
     $this->assertEqual($new_user->init, $mail, t('Correct init field.'));
   }
+
+  /**
+   * Tests Field API fields on user registration forms.
+   */
+  function testRegistrationWithUserFields() {
+    // Create a field, and an instance on 'user' entity type.
+    $field = array(
+      'type' => 'test_field',
+      'field_name' => 'test_user_field',
+      'cardinality' => 1,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'test_user_field',
+      'entity_type' => 'user',
+      'label' => 'Some user field',
+      'bundle' => 'user',
+      'required' => TRUE,
+      'settings' => array('user_register_form' => FALSE),
+    );
+    field_create_instance($instance);
+
+    // Check that the field does not appear on the registration form.
+    $this->drupalGet('user/register');
+    $this->assertNoText($instance['label'], t('The field does not appear on user registration form'));
+
+    // Have the field appear on the registration form.
+    $instance['settings']['user_register_form'] = TRUE;
+    field_update_instance($instance);
+    $this->drupalGet('user/register');
+    $this->assertText($instance['label'], t('The field appears on user registration form'));
+
+    // Check that validation errors are correctly reported.
+    $edit = array();
+    $edit['name'] = $name = $this->randomName();
+    $edit['mail'] = $mail = $edit['name'] . '@example.com';
+    // Missing input in required field.
+    $edit['test_user_field[und][0][value]'] = '';
+    $this->drupalPost(NULL, $edit, t('Create new account'));
+    $this->assertRaw(t('@name field is required.', array('@name' => $instance['label'])), t('Field validation error was correctly reported.'));
+    // Invalid input.
+    $edit['test_user_field[und][0][value]'] = '-1';
+    $this->drupalPost(NULL, $edit, t('Create new account'));
+    $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $instance['label'])), t('Field validation error was correctly reported.'));
+
+    // Submit with valid data.
+    $value = rand(1, 255);
+    $edit['test_user_field[und][0][value]'] = $value;
+    $this->drupalPost(NULL, $edit, t('Create new account'));
+    // Check user fields.
+    $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
+    $new_user = reset($accounts);
+    $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('The field value was correclty saved.'));
+
+    // Check that the 'add more' button works.
+    $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
+    field_update_field($field);
+    foreach (array('js', 'nojs') as $js) {
+      $this->drupalGet('user/register');
+      // Add two inputs.
+      $value = rand(1, 255);
+      $edit = array();
+      $edit['test_user_field[und][0][value]'] = $value;
+      if ($js == 'js') {
+        $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
+        $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
+      }
+      else {
+        $this->drupalPost(NULL, $edit, t('Add another item'));
+        $this->drupalPost(NULL, $edit, t('Add another item'));
+      }
+      // Submit with three values.
+      $edit['test_user_field[und][1][value]'] = $value + 1;
+      $edit['test_user_field[und][2][value]'] = $value + 2;
+      $edit['name'] = $name = $this->randomName();
+      $edit['mail'] = $mail = $edit['name'] . '@example.com';
+      $this->drupalPost(NULL, $edit, t('Create new account'));
+      // Check user fields.
+      $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
+      $new_user = reset($accounts);
+      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('@js : The field value was correclty saved.', array('@js' => $js)));
+      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, t('@js : The field value was correclty saved.', array('@js' => $js)));
+      $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, t('@js : The field value was correclty saved.', array('@js' => $js)));
+    }
+  }
 }
 
 class UserValidationTestCase extends DrupalWebTestCase {
@@ -277,6 +366,31 @@ class UserLoginTestCase extends DrupalWebTestCase {
     $this->assertFailedLogin($user1, 'user');
   }
 
+  /**
+   * Test that user password is re-hashed upon login after changing $count_log2.
+   */
+  function testPasswordRehashOnLogin() {
+    // Load password hashing API.
+    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
+    // Set initial $count_log2 to the default, DRUPAL_HASH_COUNT.
+    variable_set('password_count_log2', DRUPAL_HASH_COUNT);
+    // Create a new user and authenticate.
+    $account = $this->drupalCreateUser(array());
+    $password = $account->pass_raw;
+    $this->drupalLogin($account);
+    $this->drupalLogout();
+    // Load the stored user. The password hash should reflect $count_log2.
+    $account = user_load($account->uid);
+    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT);
+    // Change $count_log2 and log in again.
+    variable_set('password_count_log2', DRUPAL_HASH_COUNT + 1);
+    $account->pass_raw = $password;
+    $this->drupalLogin($account);
+    // Load the stored user, which should have a different password hash now.
+    $account = user_load($account->uid, TRUE);
+    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT + 1);
+  }
+
   /**
    * Make an unsuccessful login attempt.
    *
@@ -1416,7 +1530,7 @@ class UserCreateTestCase extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
       'name' => 'User create',
-      'description' => 'Test the creat user administration page.',
+      'description' => 'Test the create user administration page.',
       'group' => 'User',
     );
   }
@@ -1549,8 +1663,8 @@ class UserSignatureTestCase extends DrupalWebTestCase {
     variable_set('user_signatures', 1);
 
     // Prefetch text formats.
-    $this->full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
-    $this->plain_text_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Plain text'))->fetchObject();
+    $this->full_html_format = filter_format_load('full_html');
+    $this->plain_text_format = filter_format_load('plain_text');
 
     // Create regular and administrative users.
     $this->web_user = $this->drupalCreateUser(array());
@@ -1658,7 +1772,7 @@ class UserRoleAdminTestCase extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
       'name' => 'User role administration',
-      'description' => 'Test adding, editing and deleting user roles.',
+      'description' => 'Test adding, editing and deleting user roles and changing role weights.',
       'group' => 'User',
     );
   }
@@ -1711,6 +1825,28 @@ class UserRoleAdminTestCase extends DrupalWebTestCase {
     $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_AUTHENTICATED_RID);
     $this->assertResponse(403, t('Access denied when trying to edit the built-in authenticated role.'));
   }
+
+  /**
+   * Test user role weight change operation.
+   */
+  function testRoleWeightChange() {
+    $this->drupalLogin($this->admin_user);
+
+    // Pick up a random role and get its weight.
+    $rid = array_rand(user_roles());
+    $role = user_role_load($rid);
+    $old_weight = $role->weight;
+
+    // Change the role weight and submit the form.
+    $edit = array('roles['. $rid .'][weight]' => $old_weight + 1);
+    $this->drupalPost('admin/people/permissions/roles', $edit, t('Save order'));
+    $this->assertText(t('The role settings have been updated.'), t('The role settings form submitted successfully.'));
+
+    // Retrieve the saved role and compare its weight.
+    $role = user_role_load($rid);
+    $new_weight = $role->weight;
+    $this->assertTrue(($old_weight + 1) == $new_weight, t('Role weight updated successfully.'));
+  }
 }
 
 /**
@@ -1743,12 +1879,12 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
     $this->drupalLogin($user2);
 
     $account = user_load($user1->uid);
-    global $user;
+    $global_account = user_load($GLOBALS['user']->uid);
 
     // Generate and test sanitized tokens.
     $tests = array();
     $tests['[user:uid]'] = $account->uid;
-    $tests['[user:name]'] = filter_xss($account->name);
+    $tests['[user:name]'] = check_plain(format_username($account));
     $tests['[user:mail]'] = check_plain($account->mail);
     $tests['[user:url]'] = url("user/$account->uid", $url_options);
     $tests['[user:edit-url]'] = url("user/$account->uid/edit", $url_options);
@@ -1756,7 +1892,7 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
     $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language);
     $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language);
     $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language);
-    $tests['[current-user:name]'] = check_plain($user->name);
+    $tests['[current-user:name]'] = check_plain(format_username($global_account));
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.'));
@@ -1767,9 +1903,9 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[user:name]'] = $account->name;
+    $tests['[user:name]'] = format_username($account);
     $tests['[user:mail]'] = $account->mail;
-    $tests['[current-user:name]'] = $user->name;
+    $tests['[current-user:name]'] = format_username($global_account);
 
     foreach ($tests as $input => $expected) {
       $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
@@ -1899,3 +2035,107 @@ class UserRolesAssignmentTestCase extends DrupalWebTestCase {
   }
 }
 
+
+/**
+ * Unit test for authmap assignment.
+ */
+class UserAuthmapAssignmentTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Authmap assignment'),
+      'description' => t('Tests that users can be assigned and unassigned authmaps.'),
+      'group' => t('User')
+    );
+  }
+
+  /**
+   * Test authmap assignment and retrieval.
+   */
+  function testAuthmapAssignment()  {
+    $account = $this->drupalCreateUser();
+
+    // Assign authmaps to the user.
+    $authmaps = array(
+      'authname_poll' => 'external username one',
+      'authname_book' => 'external username two',
+    );
+    user_set_authmaps($account, $authmaps);
+
+    // Test for expected authmaps.
+    $expected_authmaps = array(
+      'external username one' => array(
+        'poll' => 'external username one',
+      ),
+      'external username two' => array(
+        'book' => 'external username two',
+      ),
+    );
+    foreach ($expected_authmaps as $authname => $expected_output) {
+      $this->assertIdentical(user_get_authmaps($authname), $expected_output, t('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
+    }
+
+    // Remove authmap for module poll, add authmap for module blog.
+    $authmaps = array(
+      'authname_poll' => NULL,
+      'authname_blog' => 'external username three',
+    );
+    user_set_authmaps($account, $authmaps);
+
+    // Assert that external username one does not have authmaps.
+    $remove_username = 'external username one';
+    unset($expected_authmaps[$remove_username]);
+    $this->assertFalse(user_get_authmaps($remove_username), t('Authmap for %authname was removed.', array('%authname' => $remove_username)));
+
+    // Assert that a new authmap was created for external username three, and
+    // existing authmaps for external username two were unchanged.
+    $expected_authmaps['external username three'] = array('blog' => 'external username three');
+    foreach ($expected_authmaps as $authname => $expected_output) {
+      $this->assertIdentical(user_get_authmaps($authname), $expected_output, t('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
+    }
+  }
+}
+
+/**
+ * Tests user_validate_current_pass on a custom form.
+ */
+class UserValidateCurrentPassCustomForm extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User validate current pass custom form',
+      'description' => 'Test that user_validate_current_pass is usable on a custom form.',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * User with permission to view content.
+   */
+  protected $accessUser;
+
+  /**
+   * User permission to administer users.
+   */
+  protected $adminUser;
+
+  function setUp() {
+    parent::setUp('user_form_test');
+    // Create two users
+    $this->accessUser = $this->drupalCreateUser(array('access content'));
+    $this->adminUser = $this->drupalCreateUser(array('administer users'));
+  }
+
+  /**
+   * Tests that user_validate_current_pass can be reused on a custom form.
+   */
+  function testUserValidateCurrentPassCustomForm() {
+    $this->drupalLogin($this->adminUser);
+
+    // Submit the custom form with the admin user using the access user's password.
+    $edit = array();
+    $edit['user_form_test_field'] = $this->accessUser->name;
+    $edit['current_pass'] = $this->accessUser->pass_raw;
+    $this->drupalPost('user_form_test_current_password/' . $this->accessUser->uid, $edit, t('Test'));
+    $this->assertText(t('The password has been validated and the form submitted successfully.'));
+  }
+}
diff --git a/modules/user/user.tokens.inc b/modules/user/user.tokens.inc
index e49b88c19cee64d2b5e5cdaf82fc18c33f7dea9a..e17eacf7660db7cd5cf13772ba8dac6c146526ea 100644
--- a/modules/user/user.tokens.inc
+++ b/modules/user/user.tokens.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.tokens.inc,v 1.8 2010/10/16 20:09:17 webchick Exp $
+// $Id: user.tokens.inc,v 1.9 2010/12/09 08:01:56 webchick Exp $
 
 /**
  * @file
@@ -87,7 +87,7 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
 
         case 'name':
           $name = format_username($account);
-          $replacements[$original] = $sanitize ? filter_xss($name) : $name;
+          $replacements[$original] = $sanitize ? check_plain($name) : $name;
           break;
 
         case 'mail':
@@ -122,9 +122,10 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
       $replacements += token_generate('date', $registered_tokens, array('date' => $account->created), $options);
     }
   }
+
   if ($type == 'current-user') {
-    global $user;
-    $replacements += token_generate('user', $tokens, array('user' => $user), $options);
+    $account = user_load($GLOBALS['user']->uid);
+    $replacements += token_generate('user', $tokens, array('user' => $account), $options);
   }
 
   return $replacements;
diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info
index 3bc9fb568e6e1614ece2703656be714ad8147587..96404bc34a86b1e4c61ad69a345c661fd2238f2e 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-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info
index 904c4231a8a6e6233e0e69f8c8d358a13c928cee..9abd5fa585f5ad56eac6f80e6cd1da2e044202c9 100644
--- a/profiles/standard/standard.info
+++ b/profiles/standard/standard.info
@@ -1,4 +1,4 @@
-; $Id: standard.info,v 1.1 2010/01/04 23:08:34 webchick Exp $
+; $Id: standard.info,v 1.2 2010/10/25 15:48:41 webchick Exp $
 name = Standard
 description = Install with commonly used features pre-configured.
 version = VERSION
@@ -10,7 +10,10 @@ dependencies[] = contextual
 dependencies[] = dashboard
 dependencies[] = help
 dependencies[] = image
+dependencies[] = list
 dependencies[] = menu
+dependencies[] = number
+dependencies[] = options
 dependencies[] = path
 dependencies[] = taxonomy
 dependencies[] = dblog
@@ -23,8 +26,8 @@ dependencies[] = file
 dependencies[] = rdf
 files[] = standard.profile
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install
index 10900ce1bb62658b6ea387c29edecab9826d9ecf..8e0b47b1395edc68dd759d54c0bcd148e1beb37f 100644
--- a/profiles/standard/standard.install
+++ b/profiles/standard/standard.install
@@ -1,5 +1,5 @@
 <?php
-// $Id: standard.install,v 1.28 2010/10/21 04:22:34 webchick Exp $
+// $Id: standard.install,v 1.30 2011/01/04 18:24:24 webchick Exp $
 
 /**
  * Implements hook_install().
@@ -237,7 +237,6 @@ function standard_install() {
       'type' => 'node',
       'bundle' => 'article',
       'mapping' => array(
-        'rdftype' => array('sioc:Item', 'foaf:Document'),
         'field_image' => array(
           'predicates' => array('og:image', 'rdfs:seeAlso'),
           'type' => 'rel',
@@ -411,7 +410,7 @@ function standard_install() {
 
   // Create a Home link in the main menu.
   $item = array(
-    'link_title' => 'Home',
+    'link_title' => st('Home'),
     'link_path' => '<front>',
     'menu_name' => 'main-menu',
   );
diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..8745a56da814bd0b5ee76c71e7266e382e692ee5
--- /dev/null
+++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
@@ -0,0 +1,13 @@
+; $Id: drupal_system_listing_compatible_test.info,v 1.2 2010/12/21 16:31:47 webchick Exp $
+name = "Drupal system listing compatible test"
+description = "Support module for testing the drupal_system_listing function."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
+project = "drupal"
+datestamp = "1294208756"
+
diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..4155b320357d25ee0d36ca6e9e1430d501ded96d
--- /dev/null
+++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module
@@ -0,0 +1,2 @@
+<?php
+// $Id: drupal_system_listing_compatible_test.module,v 1.1 2010/11/15 00:37:08 webchick Exp $
diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..beba696fbf5ae0d54202173e5780a22993e4ddec
--- /dev/null
+++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
@@ -0,0 +1,16 @@
+; $Id: drupal_system_listing_incompatible_test.info,v 1.2 2010/12/21 16:31:47 webchick Exp $
+name = "Drupal system listing incompatible test"
+description = "Support module for testing the drupal_system_listing function."
+package = Testing
+version = VERSION
+; This deliberately has the wrong core version, to test that it does not take
+; precedence over the version of the same module that is in the
+; modules/simpletest/tests directory.
+core = 6.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
+project = "drupal"
+datestamp = "1294208756"
+
diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..d5db920e6f8d0bfae75423f536e559e97ff59ecc
--- /dev/null
+++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
@@ -0,0 +1,2 @@
+<?php
+// $Id: drupal_system_listing_incompatible_test.module,v 1.1 2010/11/15 00:37:08 webchick Exp $
diff --git a/profiles/testing/testing.info b/profiles/testing/testing.info
index e6a31cbe3414a6ce7b0979bb400e6e7866010ea8..82fad90580fcde772484436f5d363af3db9b4e57 100644
--- a/profiles/testing/testing.info
+++ b/profiles/testing/testing.info
@@ -5,8 +5,8 @@ version = VERSION
 core = 7.x
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/robots.txt b/robots.txt
index 14fd3b49681824f412926c39cb962c717a140537..a5490c6ec28d620705eb6a5686d3713f5c9e9170 100644
--- a/robots.txt
+++ b/robots.txt
@@ -1,4 +1,4 @@
-# $Id: robots.txt,v 1.14 2009/09/11 04:17:07 webchick Exp $
+# $Id: robots.txt,v 1.15 2010/12/29 04:05:07 webchick Exp $
 #
 # robots.txt
 #
@@ -41,7 +41,6 @@ Disallow: /xmlrpc.php
 # Paths (clean URLs)
 Disallow: /admin/
 Disallow: /comment/reply/
-Disallow: /contact/
 Disallow: /node/add/
 Disallow: /search/
 Disallow: /user/register/
@@ -51,7 +50,6 @@ Disallow: /user/logout/
 # Paths (no clean URLs)
 Disallow: /?q=admin/
 Disallow: /?q=comment/reply/
-Disallow: /?q=contact/
 Disallow: /?q=node/add/
 Disallow: /?q=search/
 Disallow: /?q=user/password/
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index 55fe830b18044bf26a3bb4c42444d175fcd78654..0c10d5dd390a53493de10645d7031228b7809a31 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -1,5 +1,5 @@
 <?php
-// $Id: run-tests.sh,v 1.42 2010/09/28 02:30:32 dries Exp $
+// $Id: run-tests.sh,v 1.43 2010/11/13 13:54:58 dries Exp $
 /**
  * @file
  * This script runs Drupal tests from command line.
@@ -87,9 +87,16 @@ simpletest_script_command($args['concurrency'], $test_id, implode(",", $test_lis
 list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
 simpletest_log_read($test_id, $last_prefix, $last_test_class);
 
+// Stop the timer.
+simpletest_script_reporter_timer_stop();
+
 // Display results before database is cleared.
 simpletest_script_reporter_display_results();
 
+if ($args['xml']) {
+  simpletest_script_reporter_write_xml_results();
+}
+
 // Cleanup our test results.
 simpletest_clean_results_table($test_id);
 
@@ -135,7 +142,11 @@ All arguments are long options.
   --file      Run tests identified by specific file names, instead of group names.
               Specify the path and the extension (i.e. 'modules/user/user.test').
 
-  --color     Output the results with color highlighting.
+  --xml       <path>
+
+              If provided, test results will be written as xml files to this path.
+
+  --color     Output text format results with color highlighting.
 
   --verbose   Output detailed assertion messages in addition to summary.
 
@@ -184,7 +195,8 @@ function simpletest_script_parse_args() {
     'test_names' => array(),
     // Used internally.
     'test-id' => NULL,
-    'execute-batch' => FALSE
+    'execute-batch' => FALSE,
+    'xml' => '',
   );
 
   // Override with set values.
@@ -264,7 +276,7 @@ function simpletest_script_init($server_software) {
   if (!empty($args['url'])) {
     $parsed_url = parse_url($args['url']);
     $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '');
-    $path = $parsed_url['path'];
+    $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
 
     // If the passed URL schema is 'https' then setup the $_SERVER variables
     // properly so that testing will run under https.
@@ -450,7 +462,13 @@ function simpletest_script_get_test_list() {
  * Initialize the reporter.
  */
 function simpletest_script_reporter_init() {
-  global $args, $all_tests, $test_list;
+  global $args, $all_tests, $test_list, $results_map;
+
+  $results_map = array(
+    'pass' => 'Pass',
+    'fail' => 'Fail',
+    'exception' => 'Exception'
+  );
 
   echo "\n";
   echo "Drupal test run\n";
@@ -480,15 +498,90 @@ function simpletest_script_reporter_init() {
 }
 
 /**
- * Display test results.
+ * Display jUnit XML test results.
  */
-function simpletest_script_reporter_display_results() {
+function simpletest_script_reporter_write_xml_results() {
   global $args, $test_id, $results_map;
 
+  $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
+
+  $test_class = '';
+  $xml_files = array();
+
+  foreach ($results as $result) {
+    if (isset($results_map[$result->status])) {
+      if ($result->test_class != $test_class) {
+        // We've moved onto a new class, so write the last classes results to a file:
+        if (isset($xml_files[$test_class])) {
+          file_put_contents($args['xml'] . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
+          unset($xml_files[$test_class]);
+        }
+        $test_class = $result->test_class;
+        if (!isset($xml_files[$test_class])) {
+          $doc = new DomDocument('1.0');
+          $root = $doc->createElement('testsuite');
+          $root = $doc->appendChild($root);
+          $xml_files[$test_class] = array('doc' => $doc, 'suite' => $root);
+        }
+      }
+
+      // For convenience:
+      $dom_document = &$xml_files[$test_class]['doc'];
+
+      // Create the XML element for this test case:
+      $case = $dom_document->createElement('testcase');
+      $case->setAttribute('classname', $test_class);
+      list($class, $name) = explode('->', $result->function, 2);
+      $case->setAttribute('name', $name);
+
+      // Passes get no further attention, but failures and exceptions get to add more detail:
+      if ($result->status == 'fail') {
+        $fail = $dom_document->createElement('failure');
+        $fail->setAttribute('type', 'failure');
+        $fail->setAttribute('message', $result->message_group);
+        $text = $dom_document->createTextNode($result->message);
+        $fail->appendChild($text);
+        $case->appendChild($fail);
+      }
+      elseif ($result->status == 'exception') {
+        // In the case of an exception the $result->function may not be a class
+        // method so we record the full function name:
+        $case->setAttribute('name', $result->function);
+
+        $fail = $dom_document->createElement('error');
+        $fail->setAttribute('type', 'exception');
+        $fail->setAttribute('message', $result->message_group);
+        $full_message = $result->message . "\n\nline: " . $result->line . "\nfile: " . $result->file;
+        $text = $dom_document->createTextNode($full_message);
+        $fail->appendChild($text);
+        $case->appendChild($fail);
+      }
+      // Append the test case XML to the test suite:
+      $xml_files[$test_class]['suite']->appendChild($case);
+    }
+  }
+  // The last test case hasn't been saved to a file yet, so do that now:
+  if (isset($xml_files[$test_class])) {
+    file_put_contents($args['xml'] . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
+    unset($xml_files[$test_class]);
+  }
+}
+
+/**
+ * Stop the test timer.
+ */
+function simpletest_script_reporter_timer_stop() {
   echo "\n";
   $end = timer_stop('run-tests');
   echo "Test run duration: " . format_interval($end['time'] / 1000);
   echo "\n";
+}
+
+/**
+ * Display test results.
+ */
+function simpletest_script_reporter_display_results() {
+  global $args, $test_id, $results_map;
 
   if ($args['verbose']) {
     // Report results.
@@ -496,12 +589,6 @@ function simpletest_script_reporter_display_results() {
     echo "----------------------\n";
     echo "\n";
 
-    $results_map = array(
-      'pass' => 'Pass',
-      'fail' => 'Fail',
-      'exception' => 'Exception'
-    );
-
     $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
     $test_class = '';
     foreach ($results as $result) {
diff --git a/themes/bartik/bartik.info b/themes/bartik/bartik.info
index 0de257cfb63f059854fcebaa02500a95d3eb877f..6f3521ccf7e15eb53763e77dde5e09b25fc3df7f 100644
--- a/themes/bartik/bartik.info
+++ b/themes/bartik/bartik.info
@@ -1,11 +1,10 @@
-; $Id: bartik.info,v 1.4 2010/09/05 02:21:38 dries Exp $
+; $Id: bartik.info,v 1.5 2010/11/07 00:27:20 dries Exp $
 
 name = Bartik
 description = A flexible, recolorable theme with many regions.
 package = Core
 version = VERSION
 core = 7.x
-engine = phptemplate
 
 stylesheets[all][] = css/layout.css
 stylesheets[all][] = css/style.css
@@ -36,8 +35,8 @@ regions[footer] = Footer
 settings[shortcut_module_link] = 0
 
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/bartik/color/base.png b/themes/bartik/color/base.png
new file mode 100644
index 0000000000000000000000000000000000000000..58cc088a49e9259fefc2282f1795a5450f884065
Binary files /dev/null and b/themes/bartik/color/base.png differ
diff --git a/themes/bartik/color/color.inc b/themes/bartik/color/color.inc
index a94c13a95a0f55c4e8fef2bc9a2c47d32dd6c58e..b66e560499d4ae66e794cf220ffd8373b9cf1a7b 100644
--- a/themes/bartik/color/color.inc
+++ b/themes/bartik/color/color.inc
@@ -1,5 +1,5 @@
 <?php
-// $Id: color.inc,v 1.6 2010/09/28 02:29:27 dries Exp $
+// $Id: color.inc,v 1.7 2010/12/14 19:53:14 dries Exp $
 
 // Put the logo path into JavaScript for the live preview.
 drupal_add_js(array('color' => array('logo' => theme_get_setting('logo', 'bartik'))), 'setting');
@@ -41,8 +41,8 @@ $info = array(
         'top' => '#cd2d2d',
         'bottom' => '#cf3535',
         'text' => '#3b3b3b',
-        'sidebar' => '#f1f1f1',
-        'sidebarborders' => '#c2c2c2',
+        'sidebar' => '#f1f4f0',
+        'sidebarborders' => '#ededed',
         'footer' => '#1f1d1c',
         'titleslogan' => '#fffeff',
       ),
@@ -69,8 +69,8 @@ $info = array(
         'top' => '#4c1c58',
         'bottom' => '#593662',
         'text' => '#301313',
-        'sidebar' => '#f8f3e7',
-        'sidebarborders' => '#e4e3d4',
+        'sidebar' => '#edede7',
+        'sidebarborders' => '#e7e7e7',
         'footer' => '#2c2c28',
         'titleslogan' => '#ffffff',
       ),
diff --git a/themes/bartik/color/preview.css b/themes/bartik/color/preview.css
index 05293338dfce97062e3962c55d309391e5495ad3..61f2035b494da826c155eb1f597f9b1731b1f659 100644
--- a/themes/bartik/color/preview.css
+++ b/themes/bartik/color/preview.css
@@ -1,62 +1,201 @@
-/* $Id: preview.css,v 1.1 2010/07/06 05:25:51 webchick Exp $ */
+/* $Id: preview.css,v 1.5 2010/12/14 02:50:24 dries Exp $ */
 
-/* Bring in the rest of the theme's CSS styles. */
-@import url("../css/style.css");
-
-/* From color.css. */
-#preview, #preview-header {
-  background-color: #000000;
+/* ---------- Color form ----------- */
+#color_scheme_form #palette .form-item {
+  width: 25em;
 }
-/* Undoing Seven's reset. */
-#preview #preview-header #preview-logo img {
-  border: 0;
+#color_scheme_form #palette .form-item label {
+  width: 15em;
 }
 
-/* ---------- Basic Preview Styles ----------- */
+/* ---------- Preview Styles ----------- */
 
+html.js #preview {
+  clear: both;
+  float: none !important;
+}
 #preview {
-  width: 640px;
+  background-color: #fff;
+  font-family: Georgia, "Times New Roman", Times, serif;
+  font-size: 14px;
+  line-height: 1.5;
   overflow: hidden;
-  font-size: 1em;
+  word-wrap: break-word;
+  margin-bottom: 10px;
+}
+#preview-header {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  position: relative;
+}
+#preview-logo {
+  float: left;
+  padding: 15px 15px 15px 10px;
+}
+#preview-site-name {
+  color: #686868;
+  font-weight: normal;
+  font-size: 1.821em;
+  line-height: 1;
+  margin-bottom: 30px;
+  margin-left: 15px;
+  padding-top: 34px;
+}
+#preview-main-menu {
+  clear: both;
+  padding: 0 15px 3px;
+}
+#preview-main-menu-links a {
+  color: #d9d9d9;
+  padding: 0.6em 1em 0.4em;
 }
-#preview #preview-header div.section,
-#preview #preview-navigation div.section,
-#preview #preview-featured div.section,
-#preview #preview-main {
-  width: 960px;
-  margin-left: auto;
-  margin-right: auto;
-  padding: 0 20px;
-}
-#preview #preview-content,
-#preview .sidebar {
+#preview-main-menu-links {
+  font-size: 0.929em;
+  margin: 0;
+  padding: 0;
+}
+#preview-main-menu-links a {
+  color: #333;
+  background: #ccc;
+  background: rgba(255, 255, 255, 0.7);
+  text-shadow: 0 1px #eee;
+  -khtml-border-radius-topleft: 8px;
+  -moz-border-radius-topleft: 8px;
+  -webkit-border-top-left-radius: 8px;
+  border-top-left-radius: 8px;
+  -khtml-border-radius-topright: 8px;
+  -moz-border-radius-topright: 8px;
+  -webkit-border-top-right-radius: 8px;
+  border-top-right-radius: 8px;
+}
+#preview-main-menu-links a:hover,
+#preview-main-menu-links a:focus {
+  background: #fff;
+  background: rgba(255, 255, 255, 0.95);
+}
+#preview-main-menu-links a:active {
+  background: #b3b3b3;
+  background: rgba(255, 255, 255, 1);
+}
+#preview-main-menu-links li a.active {
+  border-bottom: none;
+}
+#preview-main-menu-links li {
   display: inline;
-  float: left; /* LTR */
+  list-style-type: none;
+  padding: 0.6em 0 0.4em;
+}
+#preview-sidebar,
+#preview-content {
+  display: inline;
+  float: left;
   position: relative;
 }
-#preview #preview-content {
-  width: 720px;
+#preview-sidebar {
+  margin-left: 15px;
+  width: 210px;
 }
-#preview .sidebar {
-  width: 240px;
+#preview-content {
+  margin-left: 30px;
+  width: 26.5em;
 }
-#preview #preview-content .section,
-.sidebar .section {
-  padding: 0 10px;
+#preview-sidebar .preview-block {
+  border: 1px solid;
+  margin: 20px 0;
+  padding: 15px 20px;
 }
-#preview #footer-wrapper {
-  padding: 35px 20px 30px;
+#preview-sidebar h2 {
+  border-bottom: 1px solid #d6d6d6;
+  font-size: 1.071em;
+  font-weight: normal;
+  line-height: 1.2;
+  margin: 0 0 0.5em;
+  padding-bottom: 5px;
+  text-shadow: 0 1px 0 #fff;
 }
-#preview #footer-firstcolumn,
-#preview #footer-secondcolumn,
-#preview #footer-thirdcolumn,
-#preview #footer-fourthcolumn {
-  padding: 0 10px;
-  width: 220px;
+#preview .preview-block .preview-content {
+  margin-top: 1em;
+}
+#preview .preview-block-menu .preview-content,
+#preview .preview-block-menu .preview-content ul {
+  margin-top: 0;
+}
+#preview-main {
+  margin-bottom: 40px;
+  margin-top: 20px;
+}
+#preview-page-title {
+  font-size: 2em;
+  font-weight: normal;
+  line-height: 1;
+  margin: 1em 0 0.5em;
+}
+#preview-footer-wrapper {
+  color: #c0c0c0;
+  color: rgba(255, 255, 255, 0.65);
+  display: block !important;
+  font-size: 0.857em;
+  padding: 20px 20px 25px;
+}
+#preview-footer-wrapper a {
+  color: #fcfcfc;
+  color: rgba(255, 255, 255, 0.8);
+}
+#preview-footer-wrapper a:hover,
+#preview-footer-wrapper a:focus {
+  color: #fefefe;
+  color: rgba(255, 255, 255, 0.95);
+  text-decoration: underline;
+}
+#preview-footer-wrapper .preview-footer-column {
   display: inline;
-  float: left; /* LTR */
+  float: left;
+  padding: 0 10px;
   position: relative;
+  width: 220px;
+}
+#preview-footer-wrapper .preview-block {
+  border: 1px solid #444;
+  border-color: rgba(255, 255, 255, 0.1);
+  margin: 20px 0;
+  padding: 10px;
+}
+#preview-footer-columns .preview-block-menu {
+  border: none;
+  margin: 0;
+  padding: 0;
+}
+#preview-footer-columns h2 {
+  border-bottom: 1px solid #555;
+  border-color: rgba(255, 255, 255, 0.15);
+  font-size: 1em;
+  margin-bottom: 0;
+  padding-bottom: 3px;
+  text-transform: uppercase;
+}
+#preview-footer-columns .preview-content {
+  margin-top: 0;
+}
+#preview-footer-columns .preview-content ul {
+  margin-left: 0;
+  padding-left: 0;
+}
+#preview-footer-columns .preview-content li {
+  list-style: none;
+  list-style-image: none;
+  margin: 0;
+  padding: 0;
+}
+#preview-footer-columns .preview-content li a {
+  border-bottom: 1px solid #555;
+  border-color: rgba(255, 255, 255, 0.15);
+  display: block;
+  line-height: 1.2;
+  padding: 0.8em 2px 0.8em 20px;
+  text-indent: -15px;
 }
-#preview #footer {
-  width: 940px;
+#preview-footer-columns .preview-content li a:hover,
+#preview-footer-columns .preview-content li a:focus {
+  background-color: #1f1f21;
+  background-color: rgba(255, 255, 255, 0.05);
+  text-decoration: none;
 }
diff --git a/themes/bartik/color/preview.html b/themes/bartik/color/preview.html
index 13537edad15e89a85da8d3295a598fd69e8bcd25..52ea5664a404d9e18430067a2a061e3831a0307d 100644
--- a/themes/bartik/color/preview.html
+++ b/themes/bartik/color/preview.html
@@ -1,105 +1,65 @@
 <div id="preview">
+
   <div id="preview-header">
-    <div class="section clearfix">
-      <a href="/" title="Home" rel="home" id="preview-logo" name="logo"><img src="../../../themes/bartik/logo.png" alt="Home" /></a>
-      <div id="preview-name-and-slogan">
-        <div id="preview-site-name">
-          <strong><a href="#" title="Home" rel="home"><span>Bartik</span></a></strong>
-        </div>
-      </div><!-- /#name-and-slogan -->
+    <div id="preview-logo"><img src="../../../themes/bartik/logo.png" alt="Site Logo" /></div>
+    <div id="preview-site-name">Bartik</div>
+    <div id="preview-main-menu">
+      <ul id="preview-main-menu-links">
+        <li><a>Home</a></li>
+        <li><a>Te Quidne</a></li>
+        <li><a>Vel Torqueo Quae Erat</a></li>
+      </ul>
     </div>
-  </div><!-- /.section, /#header -->
-  <div id="preview-main-wrapper">
-    <div id="preview-main" class="clearfix">
-      <div id="preview-sidebar-first" class="column sidebar">
-        <div class="section">
-          <div class="region region-sidebar-first">
-            <div id="preview-block-user-login" class="block block-user first last even">
-              <h2>
-                Etiam est risus
-              </h2>
-              <div class="content">
-                <p>
-                  Maecenas id porttitor felis. Pellentesque mollis urna in nibh pharetra semper. Nulla erat odio, imperdiet quis cursus vitae, ultricies
-                  at diam.
-                </p>
-              </div>
-            </div>
-          </div>
+  </div>
+
+  <div id="preview-main" class="clearfix">
+    <div id="preview-sidebar">
+      <div id="preview-block" class="preview-block">
+        <h2>Etiam est risus</h2>
+        <div class="preview-content">
+          Maecenas id porttitor Ut enim ad minim veniam, quis nostrudfelis.
+          Laboris nisi ut aliquip ex ea.
         </div>
-      </div><!-- /.section, /#sidebar-first -->
-      <div id="preview-content" class="column">
-        <div class="section">
-          <a id="preview-main-content" name="main-content"></a>
-          <h1 class="title" id="preview-page-title">
-            Lorem ipsum dolor
-          </h1>
-          <div class="region region-content">
-            <div id="preview-block-system-main" class="block block-system first last even">
-              <div class="content">
-                <div id="preview-node-1" class="node node-page clearfix" about="/node/1" typeof="foaf:Document">
-                  <div class="content clearfix">
-                    <div class="field field-name-body field-type-text-with-summary field-label-hidden clearfix">
-                      <div class="field-items">
-                        <div class="field-item even" property="content:encoded">
-                          <p>
-                            Sit amet, <a href="#">consectetur adipisicing elit</a>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
-                            veniam, quis nostrud <a href="#">exercitation ullamco</a> laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
-                            in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
-                            sunt in culpa qui officia deserunt mollit anim id est laborum.
-                          </p>
-                        </div>
-                      </div>
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
+      </div>
+    </div>
+    <div id="preview-content">
+      <h1 id="preview-page-title">Lorem ipsum dolor</h1>
+      <div id="preview-node">
+        <div class="preview-content">
+          Sit amet, <a>consectetur adipisicing elit</a>, sed do eiusmod tempor
+          incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
+          nostrud <a>exercitation ullamco</a> laboris nisi ut aliquip ex ea
+          commodo consequat. Maecenas id porttitor Ut enim ad minim veniam, quis nostr udfelis.
         </div>
-      </div><!-- /.section, /#content -->
+      </div>
     </div>
-  </div><!-- /#main, /#main-wrapper -->
+  </div>
 
-  <div id="footer-wrapper"><div class="section">
-      <div id="footer-columns" class="clearfix">
-          <div id="footer-firstcolumn" class="region sitemap"><div class="section">
+  <div id="preview-footer-wrapper">
+    <div id="preview-footer-columns" class="clearfix">
+      <div class="preview-footer-column">
+        <div class="preview-block">
+          <h2>Etiam est risus</h2>
+          <div class="content">
+            Maecenas id porttitor Ut enim ad minim veniam, quis nostrudfelis.
+            Laboris nisi ut aliquip ex ea.
+          </div>
+        </div>
+      </div>
+      <div class="preview-footer-column">
+        <div class="preview-block preview-block-menu">
+          <h2>Erisus dolor</h2>
+          <div class="preview-content">
             <ul>
               <li><a>Donec placerat</a></li>
               <li><a>Nullam nibh dolor</a></li>
               <li><a>Blandit sed</a></li>
               <li><a>Fermentum id</a></li>
             </ul>
-          </div></div> <!-- /.section, /#footer-firstcolumn -->
-          <div id="footer-secondcolumn" class="region sitemap"><div class="section">
-            <ul>
-              <li><a>Imperdiet sit amet</a></li>
-              <li><a>Nam mollis</a></li>
-              <li><a>Ultrices justo</a></li>
-              <li><a>Sed tempor</a></li>
-              </ul>
-            <ul>
-          </div></div> <!-- /.section, /#footer-secondcolumn -->
-          <div id="footer-thirdcolumn" class="region sitemap"><div class="section">
-           <ul>
-              <li><a>Sit amet</a></li>
-              <li><a>Gravida eget</a></li>
-              <li><a>Porta at</a></li>
-              <li><a>Nam non</a></li>
-            </ul>
-          </div></div> <!-- /.section, /#footer-thirdcolumn -->
-          <div id="footer-fourthcolumn" class="region sitemap"><div class="section">
-            <ul>
-              <li><a>Sed vitae</a></li>
-              <li><a>Tellus</a></li>
-              <li><a>Etiam sem</a></li>
-              <li><a>Arcu eleifend</a></li>
-            </ul>
-          </div></div> <!-- /.section, /#footer-fourthcolumn -->
-      </div><!-- /#footer-columns -->
-      <div id="footer" class="clearfix">
-        Aliquam aliquet, est <a>a ullamcorper</a> condimentum.
-    </div><!-- /#footer -->
-  </div></div> <!-- /.section, /#footer-wrapper -->
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
 
-</div><!-- /#preview -->
+</div>
diff --git a/themes/bartik/color/preview.js b/themes/bartik/color/preview.js
index 6335a28d5c5d101f840af0421f0c8bab03cf8ea1..bf60cb3a5564282f2c7c2aa910d281c4132614af 100644
--- a/themes/bartik/color/preview.js
+++ b/themes/bartik/color/preview.js
@@ -1,4 +1,4 @@
-/* $Id: preview.js,v 1.1 2010/07/06 05:25:51 webchick Exp $ */
+// $Id: preview.js,v 1.5 2010/12/11 21:37:41 webchick Exp $
 
 (function ($) {
   Drupal.color = {
@@ -9,21 +9,24 @@
         $('#preview #preview-logo img').attr('src', Drupal.settings.color.logo);
         this.logoChanged = true;
       }
+      // Remove the logo if the setting is toggled off. 
+      if (Drupal.settings.color.logo == null) {
+        $('div').remove('#preview-logo');
+      }
 
       // Solid background.
       $('#preview', form).css('backgroundColor', $('#palette input[name="palette[bg]"]', form).val());
 
       // Text preview.
-      $('#preview #preview-main h2, #preview #preview-main p', form).css('color', $('#palette input[name="palette[text]"]', form).val());
+      $('#preview #preview-main h2, #preview .preview-content', form).css('color', $('#palette input[name="palette[text]"]', form).val());
       $('#preview #preview-content a', form).css('color', $('#palette input[name="palette[link]"]', form).val());
 
-      // Sidebar background.
-      $('#preview .sidebar .block', form).css('background-color', $('#palette input[name="palette[sidebar]"]', form).val());
-
-      // Footer background.
-      $('#preview #footer-wrapper', form).css('background-color', $('#palette input[name="palette[footer]"]', form).val());
+      // Sidebar block.
+      $('#preview #preview-sidebar #preview-block', form).css('background-color', $('#palette input[name="palette[sidebar]"]', form).val());
+      $('#preview #preview-sidebar #preview-block', form).css('border-color', $('#palette input[name="palette[sidebarborders]"]', form).val());
 
-      $('#preview .sidebar .block', form).css('border-color', $('#palette input[name="palette[sidebarborders]"]', form).val());
+      // Footer wrapper background.
+      $('#preview #preview-footer-wrapper', form).css('background-color', $('#palette input[name="palette[footer]"]', form).val());
 
       // CSS3 Gradients.
       var gradient_start = $('#palette input[name="palette[top]"]', form).val();
@@ -31,7 +34,7 @@
 
       $('#preview #preview-header', form).attr('style', "background-color: " + gradient_start + "; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(" + gradient_start + "), to(" + gradient_end + ")); background-image: -moz-linear-gradient(-90deg, " + gradient_start + ", " + gradient_end + ");");
 
-      $('#preview #preview-name-and-slogan a', form).css('color', $('#palette input[name="palette[titleslogan]"]', form).val());
+      $('#preview #preview-site-name', form).css('color', $('#palette input[name="palette[titleslogan]"]', form).val());
     }
   };
 })(jQuery);
diff --git a/themes/bartik/color/preview.png b/themes/bartik/color/preview.png
new file mode 100644
index 0000000000000000000000000000000000000000..58cc088a49e9259fefc2282f1795a5450f884065
Binary files /dev/null and b/themes/bartik/color/preview.png differ
diff --git a/themes/bartik/css/colors.css b/themes/bartik/css/colors.css
index 31c742d7734883f9d4d9e7376fdf106eec60163f..b937362c9a93670243b27271557f4ae99c8959d0 100644
--- a/themes/bartik/css/colors.css
+++ b/themes/bartik/css/colors.css
@@ -1,17 +1,16 @@
-/* $Id: colors.css,v 1.7 2010/10/05 01:48:11 dries Exp $ */
+/* $Id: colors.css,v 1.10 2011/01/04 05:24:13 webchick Exp $ */
 
 /* ---------- Color Module Styles ----------- */
 
-body {
-  background-color: #292929;
-  color: #ffffff;
-}
-#page-wrapper,
-#main,
+body,
 body.overlay {
-  background-color: #ffffff;
   color: #3b3b3b;
 }
+.comment .comment-arrow {
+  border-color: #ffffff;
+}
+#page,
+#main-wrapper,
 #main-menu-links li a.active,
 #main-menu-links li.active-trail a {
   background: #ffffff;
@@ -42,14 +41,15 @@ a:active {
   background-color: #f6f6f2;
   border-color: #f9f9f9;
 }
+#page-wrapper,
 #footer-wrapper {
   background: #292929;
 }
 .region-header,
 .region-header a,
 .region-header li a.active,
-#header #name-and-slogan,
-#header #name-and-slogan a,
+#name-and-slogan,
+#name-and-slogan a,
 #secondary-menu-links li a {
   color: #fffeff;
 }
diff --git a/themes/bartik/css/ie-rtl.css b/themes/bartik/css/ie-rtl.css
index bf92cb6e010651a64f622837f8087c1184dec927..b07c3fde8b3bb5d398b5b18faf4080d27f88a2e7 100644
--- a/themes/bartik/css/ie-rtl.css
+++ b/themes/bartik/css/ie-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: ie-rtl.css,v 1.4 2010/10/07 17:59:01 webchick Exp $ */
+/* $Id: ie-rtl.css,v 1.7 2011/01/04 02:59:37 webchick Exp $ */
 
 fieldset legend {
   left: 6px;
@@ -8,6 +8,13 @@ ul.action-links li a,
 #user-login li.openid-link a {
   zoom: 1;
 }
+.comment .attribution {
+  float: right;
+}
+.comment .comment-arrow {
+  position: absolute;
+  right: 25px;
+}
 .region-header .block,
 .region-header #block-user-login .form-item {
   float: none;
@@ -36,3 +43,7 @@ ul.action-links li a,
   margin: 0;
   zoom: 1;
 }
+#footer li {
+  display: inline;
+  float: none;
+}
diff --git a/themes/bartik/css/ie.css b/themes/bartik/css/ie.css
index 9ed85a84a1e135a99954028d03de70cb5ecaa3f9..aafaf19b279e504b276e7a364482f022abb81e1b 100644
--- a/themes/bartik/css/ie.css
+++ b/themes/bartik/css/ie.css
@@ -1,4 +1,4 @@
-/* $Id: ie.css,v 1.7 2010/10/08 03:36:03 webchick Exp $ */
+/* $Id: ie.css,v 1.12 2011/01/04 02:59:37 webchick Exp $ */
 
 .block {
   zoom: 1;
@@ -13,6 +13,16 @@ fieldset legend {
 #footer-wrapper #footer .block {
   height: 100%;
 }
+.comment .attribution {
+  display: inline-block;
+  position: relative;
+  float: left; /* LTR */
+  overflow: hidden;
+}
+.comment .comment-text {
+  display: inline-block;
+  width: auto;
+}
 #search-block-form input.form-submit,
 #search-form input.form-submit {
   text-transform: capitalize; /* Trigger text indent. */
@@ -36,3 +46,19 @@ fieldset legend {
 .contact-form .resizable-textarea .grippie {
   width: 76.3%;
 }
+#footer li {
+  float: left; /* LTR */
+}
+#footer-wrapper {
+  color: #c0c0c0;
+}
+#footer-wrapper a {
+  color: #fcfcfc;
+}
+#footer-wrapper a:hover,
+#footer-wrapper a:focus {
+  color: #fefefe;
+}
+.node-teaser {
+  margin-top: 10px;
+}
diff --git a/themes/bartik/css/ie6.css b/themes/bartik/css/ie6.css
index 9fbc9ce9f5fbf20e99c4dab86523e9cf493778fe..cb233a5170fcd130a0e953110791af74e2ec9a62 100644
--- a/themes/bartik/css/ie6.css
+++ b/themes/bartik/css/ie6.css
@@ -1,4 +1,4 @@
-/* $Id: ie6.css,v 1.4 2010/10/05 01:48:11 dries Exp $ */
+/* $Id: ie6.css,v 1.5 2010/12/02 23:54:56 dries Exp $ */
 
 #content {
   overflow: hidden;
@@ -7,17 +7,13 @@
   width: 50%;
 }
 .tabs ul.primary,
-.region-header .block-menu li a {
+.region-header .block-menu li a,
+.comment-form .form-item {
   zoom: 1;
 }
 #block-search-form .form-item-search-block-form input {
   width: 67%;
 }
-.node-sticky {
-  background: transparent;
-  border: none;
-  padding: 0 0 15px;
-}
 .node-teaser {
   border-bottom: 1px solid #d3d7d9;
 }
diff --git a/themes/bartik/css/layout-rtl.css b/themes/bartik/css/layout-rtl.css
index 6e9c934e92cadd00a8348dbe02f3d122013606b8..b1cb06bd88b5014ce1e076323f31eb74916a15a8 100644
--- a/themes/bartik/css/layout-rtl.css
+++ b/themes/bartik/css/layout-rtl.css
@@ -1,9 +1,10 @@
-/* $Id: layout-rtl.css,v 1.4 2010/10/05 01:48:11 dries Exp $ */
+/* $Id: layout-rtl.css,v 1.5 2010/11/30 17:43:52 dries Exp $ */
 
 /* ---------- Basic Layout RTL Styles ----------- */
 
 #content,
-.sidebar,
+#sidebar-first,
+#sidebar-second,
 .region-triptych-first,
 .region-triptych-middle,
 .region-triptych-last,
diff --git a/themes/bartik/css/layout.css b/themes/bartik/css/layout.css
index e3150f5308d5e134bcb3d38a531248553b9e3366..9f8227c92033d9412b6efbf19d660a0affaafbee 100644
--- a/themes/bartik/css/layout.css
+++ b/themes/bartik/css/layout.css
@@ -1,10 +1,19 @@
-/* $Id: layout.css,v 1.4 2010/10/05 01:48:11 dries Exp $ */
+/* $Id: layout.css,v 1.8 2011/01/04 05:24:13 webchick Exp $ */
 
 /* ---------- Basic Layout Styles ----------- */
 
+html,
+body,
+#page  {
+  height: 100%;
+}
+#page-wrapper {
+  min-height: 100%;
+  min-width: 960px;
+}
 #header div.section,
 #featured div.section,
-#messages,
+#messages div.section,
 #main,
 #triptych,
 #footer-columns,
@@ -33,7 +42,8 @@
   width: 480px;
 }
 #content,
-.sidebar,
+#sidebar-first,
+#sidebar-second,
 .region-triptych-first,
 .region-triptych-middle,
 .region-triptych-last,
@@ -55,13 +65,13 @@
   width: 960px;
   float: none;
 }
-.sidebar {
+#sidebar-first,
+#sidebar-second {
   width: 240px;
 }
 #main-wrapper {
-  min-height: 500px;
+  min-height: 300px;
 }
-#messages div.section,
 #content .section,
 .sidebar .section {
   padding: 0 15px;
diff --git a/themes/bartik/css/maintenance-page.css b/themes/bartik/css/maintenance-page.css
index 4b3b5fe914d7a702542f8880bfc9fdd083e96646..fb21ae4be3a830bfbafddb851bcc14cf40b5e5c6 100644
--- a/themes/bartik/css/maintenance-page.css
+++ b/themes/bartik/css/maintenance-page.css
@@ -1,4 +1,4 @@
-/* $Id: maintenance-page.css,v 1.5 2010/10/01 07:05:22 webchick Exp $ */
+/* $Id: maintenance-page.css,v 1.6 2010/11/26 11:00:37 webchick Exp $ */
 
 body.maintenance-page {
   background-color: #fff;
@@ -7,8 +7,9 @@ body.maintenance-page {
 .maintenance-page #page-wrapper {
   margin-left: auto;
   margin-right: auto;
+  min-width: 0;
   width: 800px;
-  border: 1px solid #cbcbcb;
+  border: 1px solid #ddd;
   margin-top: 40px;
 }
 .maintenance-page #page {
diff --git a/themes/bartik/css/style-rtl.css b/themes/bartik/css/style-rtl.css
index 2c26c2755202c8716af8f7b837e9a3e4ff35e2f6..5220c67f030ecd79f822391bef3b5fd251686dc0 100644
--- a/themes/bartik/css/style-rtl.css
+++ b/themes/bartik/css/style-rtl.css
@@ -1,4 +1,4 @@
-/* $Id: style-rtl.css,v 1.12 2010/10/07 17:59:01 webchick Exp $ */
+/* $Id: style-rtl.css,v 1.19 2011/01/04 06:23:29 dries Exp $ */
 
 /* ------------------ Reset Styles ------------------ */
 
@@ -7,7 +7,7 @@ th,
 td {
   text-align: right;
 }
-blockquote{
+blockquote {
   border-left: none;
   border-right: 4px solid #afafaf;
 }
@@ -30,6 +30,7 @@ blockquote:after {
 ul.tips {
   padding: 0 1.25em 0 0;
 }
+.block ol,
 .block ul {
   padding: 0 1em 0.25em 0;
 }
@@ -37,7 +38,7 @@ ul.tips {
 /* ------------------ Header ------------------ */
 
 #logo {
-  padding: 15px 10px 15px 30px;
+  padding: 15px 10px 15px 15px;
 }
 #logo,
 #name-and-slogan,
@@ -46,6 +47,9 @@ ul.tips {
 .region-header #block-user-login .item-list li {
   float: right;
 }
+#name-and-slogan {
+  margin: 0 15px 30px 0;
+}
 .region-header .form-text {
   margin-left: 2px;
   margin-right: 0;
@@ -84,13 +88,14 @@ ul.tips {
   margin-left: 5px;
   margin-right: 0;
 }
-.field-type-taxonomy-term-reference .field-label,
-.field-type-taxonomy-term-reference .field-items,
-.field-type-taxonomy-term-reference .field-item {
-  float: right;
-  padding-left: 10px;
+.field-type-taxonomy-term-reference .field-label {
+  padding-left: 5px;
   padding-right: 0;
 }
+.field-type-taxonomy-term-reference ul.links li {
+  padding: 0 0 0 1em;
+  float: right;
+}
 .link-wrapper {
   margin-right: 236px;
   margin-left: 0;
@@ -103,14 +108,12 @@ ul.tips {
 }
 .comment .attribution {
   float: right;
+  padding: 0 0 0 30px;
 }
 .comment .comment-arrow {
-  background: url(../images/comment-arrow-rtl.png);
-  margin-right: -45px;
-}
-.comment .comment-text {
-  margin-right: 140px;
+  background-image: url(../images/comment-arrow-rtl.gif);
   margin-left: 0;
+  margin-right: -47px;
 }
 .comment .indented {
   margin-right: 40px;
@@ -119,6 +122,11 @@ ul.tips {
 .comment ul.links li {
   padding: 0 0 0.5em;
 }
+.comment-unpublished {
+  margin-left: 5px;
+  margin-right: 0;
+  padding: 5px 5px 5px 2px;
+}
 
 /* -------------- Password Meter  ------------- */
 
@@ -140,7 +148,7 @@ ul.tips {
 input.form-submit,
 a.button {
   margin-right: 0;
-  margin-left: 1em;
+  margin-left: 0.6em;
 }
 
 /* --------------- Search Form ---------------- */
@@ -163,7 +171,7 @@ a.button {
 #footer li a {
   float: right;
   border-left: 1px solid #555;
-  border-color: rgba(255,255,255,0.15);  
+  border-color: rgba(255, 255, 255, 0.15);
   border-right: none;
 }
 #footer li.first a {
@@ -220,16 +228,18 @@ html.js input.throbbing {
 }
 
 /* Comment form */
-.comment-form .form-type-textfield label,
-.comment-form .form-type-item label {
+.comment-form label {
   float: right;
 }
-.comment-form .form-type-textfield input,
-.comment-form .form-item .username {
-  float: left;
-}
+.comment-form .form-type-checkbox,
+.comment-form .form-radios,
 .comment-form .form-item .description {
-  float: left;
+  margin-left: 0;
+  margin-right: 120px;
+}
+#edit-actions input {
+  margin-left: 0.6em;
+  margin-right: 0;
 }
 
 /* -------------- Shortcut Links ------------- */
diff --git a/themes/bartik/css/style.css b/themes/bartik/css/style.css
index 6000dcd80dec9af2861f7678e1a8c302c31b617f..d37754cabe127e4cf47efc2586921c7074002b3c 100644
--- a/themes/bartik/css/style.css
+++ b/themes/bartik/css/style.css
@@ -1,10 +1,8 @@
-/* $Id: style.css,v 1.26 2010/10/23 00:58:51 webchick Exp $ */
+/* $Id: style.css,v 1.53 2011/01/04 06:23:29 dries Exp $ */
 
 /* ---------- Overall Specifications ---------- */
 
-body,
-#preview {
-  background-color: #fff;
+body {
   line-height: 1.5;
   font-size: 87.5%;
   word-wrap: break-word;
@@ -19,7 +17,7 @@ a:visited {
 }
 a:hover,
 a:active,
-a:focus{
+a:focus {
   text-decoration: underline;
 }
 h1,
@@ -27,27 +25,18 @@ h2,
 h3,
 h4,
 h5,
-h6,
-#preview h1,
-#preview h2,
-#preview h3,
-#preview h4,
-#preview h5,
-#preview h6 {
+h6 {
   margin: 1.0em 0 0.5em;
   font-weight: inherit;
 }
-h1,
-#preview h1 {
+h1 {
   font-size: 1.357em;
   color: #000;
 }
-h2,
-#preview h2 {
+h2 {
   font-size: 1.143em;
 }
-p,
-#preview p {
+p {
   margin: 0 0 1.2em;
 }
 del {
@@ -56,22 +45,72 @@ del {
 tr.odd {
   background-color: #dddddd;
 }
-img,
-#preview img {
+img {
   outline: 0;
 }
+code,
+pre,
+kbd,
+samp,
+var {
+  padding: 0 0.4em;
+  font-size: 0.77em;
+  font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", "Nimbus Mono L", "DejaVu Sans Mono", monospace, "Courier New";
+}
+code {
+  background-color: #f2f2f2;
+  background-color: rgba(40, 40, 0, 0.06);
+}
+pre code,
+pre kbd,
+pre samp,
+pre var,
+kbd kbd,
+kbd samp,
+code var {
+  font-size: 100%;
+  background-color: transparent;
+}
+pre code,
+pre samp,
+pre var {
+  padding: 0;
+}
+.description code {
+  font-size: 1em;
+}
+kbd {
+  background-color: #f2f2f2;
+  border: 1px outset #575757;
+  margin: 0 3px;
+  color: #666;
+  display: inline-block;
+  padding: 0 6px;
+  -khtml-border-radius: 5px;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+  border-radius: 5px;
+}
+pre {
+  background-color: #f2f2f2;
+  background-color: rgba(40, 40, 0, 0.06);
+  margin: 10px 0;
+  overflow: hidden;
+  padding: 15px;
+  white-space: pre-wrap;
+}
+
 
 /* ------------------ Fonts ------------------ */
 
 body,
-#preview,
-#header #site-slogan,
-.ui-widget {
+#site-slogan,
+.ui-widget,
+.comment-form label {
   font-family: Georgia, "Times New Roman", Times, serif;
 }
 #header,
 #footer-wrapper,
-#preview #preview-header,
 #skip-link,
 ul.contextual-links,
 ul.links,
@@ -103,21 +142,21 @@ blockquote {
   border-left: 1px solid #bbb;
   font-style: italic;
   margin: 1.5em 10px;
-  padding: .5em 10px;
+  padding: 0.5em 10px;
 }
 blockquote:before {
   color: #bbb;
   content: "\201C";
   font-size: 3em;
-  line-height: .1em;
-  margin-right: .2em;
+  line-height: 0.1em;
+  margin-right: 0.2em;
   vertical-align: -.4em;
 }
 blockquote:after {
   color: #bbb;
   content: "\201D";
   font-size: 3em;
-  line-height: .1em;
+  line-height: 0.1em;
   vertical-align: -.45em;
 }
 blockquote :first-child {
@@ -131,10 +170,11 @@ a.feed-icon {
 /* ------------------ Table Styles ------------------ */
 
 table {
+  border: 0;
   border-spacing: 0;
-  width: 100%;
-  margin: 10px 0;
   font-size: 0.857em;
+  margin: 10px 0;
+  width: 100%;
 }
 table table {
   font-size: 1em;
@@ -143,15 +183,19 @@ table table {
   font-size: 1em;
 }
 table tr th {
-  background-color: #757575;
+  background: #757575;
+  background: rgba(0, 0, 0, 0.51);
   border-bottom-style: none;
 }
-table thead tr th,
-table thead tr th a,
-table thead tr th a:hover {
+table tr th,
+table tr th a,
+table tr th a:hover {
   color: #FFF;
   font-weight: bold;
 }
+table tbody tr th {
+  vertical-align: top;
+}
 tr td,
 tr th {
   padding: 4px 9px;
@@ -161,27 +205,29 @@ tr th {
 #footer-wrapper tr td,
 #footer-wrapper tr th {
   border-color: #555;
-  border-color: rgba(255,255,255,0.18);  
+  border-color: rgba(255, 255, 255, 0.18);
 }
 tr.odd {
-  background-color: #e4e4e4;
+  background: #e4e4e4;
+  background: rgba(0, 0, 0, 0.105);
 }
 tr,
 tr.even {
-  background-color: #efefef;
+  background: #efefef;
+  background: rgba(0, 0, 0, 0.063);
 }
 table ul.links {
   margin: 0;
   padding: 0;
   font-size: 1em;
 }
-}
 table ul.links li {
   padding: 0 1em 0 0;
 }
 
 /* ------------------ List Styles ------------------ */
 
+.block ol,
 .block ul {
   margin: 0;
   padding: 0 0 0.25em 1em; /* LTR */
@@ -220,7 +266,7 @@ ul.tips {
   margin-left: -5.25em;
   margin-top: 0;
   position: absolute;
-  width: auto !important;
+  width: auto;
   z-index: 50;
 }
 #skip-link a,
@@ -231,12 +277,9 @@ ul.tips {
   color: #fff;
   display: block;
   font-size: 0.94em;
-  height: 1px;
   line-height: 1.7;
-  position: absolute;
+  padding: 1px 10px 2px 10px;
   text-decoration: none;
-  top: -10000px;
-  width: 1px;
   -khtml-border-radius: 0 0 10px 10px;
   -moz-border-radius: 0 0 10px 10px;
   -webkit-border-top-left-radius: 0;
@@ -248,38 +291,26 @@ ul.tips {
 #skip-link a:hover,
 #skip-link a:active,
 #skip-link a:focus {
-  height: auto;
   outline: 0;
-  overflow: visible;
-  padding: 1px 10px 2px 10px;
-  position: static;
-  width: auto;
 }
-#logo,
-#preview #preview-header #preview-logo {
+#logo {
   float: left; /* LTR */
-  padding: 15px 30px 15px 10px; /* LTR */
+  padding: 15px 15px 15px 10px; /* LTR */
 }
 #name-and-slogan {
   float: left; /* LTR */
-}
-#name-and-slogan,
-#preview #preview-header #preview-name-and-slogan {
   padding-top: 34px;
-  margin-bottom: 30px;
+  margin: 0 0 30px 15px; /* LTR */
 }
-#site-name,
-#preview #preview-header #preview-site-name {
+#site-name {
   font-size: 1.821em;
   color: #686868;
   line-height: 1;
 }
-h1#site-name,
-#preview #preview-header h1#preview-site-name {
+h1#site-name {
   margin: 0;
 }
-#site-name a,
-#preview-header #preview-site-name a {
+#site-name a {
   font-weight: normal;
 }
 #site-slogan {
@@ -345,7 +376,7 @@ h1#site-name,
 .region-header .block-menu li a:focus,
 .region-header .block-menu li a:active {
   text-decoration: none;
-  background: rgba(255, 255, 255, 0.15)
+  background: rgba(255, 255, 255, 0.15);
 }
 .region-header .block-menu li.last a {
   border-bottom: 0;
@@ -395,7 +426,7 @@ h1#site-name,
 .region-header #block-user-login .form-actions {
   margin: 4px 0 0;
   padding: 0;
-  clear: both
+  clear: both;
 }
 .region-header #block-user-login input.form-submit {
   border: 1px solid;
@@ -435,10 +466,12 @@ h1#site-name,
 }
 #main-menu-links {
   font-size: 0.929em;
+  margin: 0;
   padding: 0 15px;
 }
 #main-menu-links li {
   float: left; /* LTR */
+  list-style: none;
   padding: 0 1px;
   margin: 0 1px;
 }
@@ -493,8 +526,7 @@ h1#site-name,
 
 /* ------------------- Main ------------------- */
 
-#main,
-#preview #preview-main {
+#main {
   margin-top: 20px;
   margin-bottom: 40px;
 }
@@ -509,6 +541,7 @@ h1#site-name,
   padding: 20px 0 45px;
   margin: 0;
   background: #f0f0f0;
+  background: rgba(30, 50, 10, 0.08);
   border-bottom: 1px solid #e7e7e7;
   text-shadow: 1px 1px #fff;
 }
@@ -521,21 +554,31 @@ h1#site-name,
   padding: 0;
 }
 
+/* --------------- Highlighted ---------------- */
+
+#highlighted {
+  border-bottom: 1px solid #d3d7d9;
+  font-size: 120%;
+}
+
+/* ------------------- Help ------------------- */
+
+.region-help {
+  border: 1px solid #d3d7d9;
+  padding: 0 1.5em;
+  margin-bottom: 30px;
+}
+
 /* ----------------- Content ------------------ */
 
 .content {
   margin-top: 10px;
 }
-#preview #preview-block-system-main {
-  line-height: 1.5;
-}
-h1#page-title,
-#preview h1#preview-page-title {
+h1#page-title {
   font-size: 2em;
   line-height: 1;
 }
-#content h2,
-#preview #preview-block-system-main h2 {
+#content h2 {
   margin-bottom: 2px;
   font-size: 1.429em;
   line-height: 1.4;
@@ -546,6 +589,10 @@ h1#page-title,
 .node-teaser .content {
   font-size: 1em;
 }
+.node-teaser h2 {
+  margin-top: 0;
+  padding-top: 0.5em;
+}
 .node-teaser h2 a {
   color: #181818;
 }
@@ -554,14 +601,18 @@ h1#page-title,
   margin-bottom: 30px;
   padding-bottom: 15px;
 }
-.node-teaser.node-sticky {
+.node-sticky {
   background: #f9f9f9;
   background: rgba(0, 0, 0, 0.024);
   border: 1px solid #d3d7d9;
   padding: 0 15px 15px;
 }
+.node-full {
+  background: none;
+  border: none;
+  padding: 0;
+}
 .node-teaser .content {
-  color: #3b3b3b;
   clear: none;
   line-height: 1.6;
 }
@@ -575,25 +626,31 @@ h1#page-title,
   height: 20px;
   margin: 1px 5px 0 0; /* LTR */
 }
-.field-type-taxonomy-term-reference .field-label,
-.field-type-taxonomy-term-reference .field-items,
-.field-type-taxonomy-term-reference .field-item {
-  display: inline;
-  float: left; /* LTR */
-  padding-right: 10px; /* LTR */
+.field-type-taxonomy-term-reference {
+  margin: 0 0 1.2em;
+}
+.field-type-taxonomy-term-reference .field-label {
   font-weight: normal;
+  margin: 0;
+  padding-right: 5px; /* LTR */
 }
-.field-type-taxonomy-term-reference div.field-label {
-  font-size: 0.857em;
-  color: #68696b;
+.field-type-taxonomy-term-reference .field-label,
+.field-type-taxonomy-term-reference ul.links {
+  font-size: 0.8em;
 }
-.field-type-taxonomy-term-reference .field-items,
-.field-type-taxonomy-term-reference .field-item {
-  font-size: 0.929em;
+.node-teaser .field-type-taxonomy-term-reference .field-label,
+.node-teaser .field-type-taxonomy-term-reference ul.links {
+  font-size: 0.821em;
 }
-.field-type-taxonomy-term-reference a:hover,
-.field-type-taxonomy-term-reference a:focus {
-  text-decoration: underline;
+.field-type-taxonomy-term-reference ul.links {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+}
+.field-type-taxonomy-term-reference ul.links li {
+  float: left; /* LTR */
+  padding: 0 1em 0 0; /* LTR */
+  white-space: nowrap;
 }
 .link-wrapper {
   text-align: right;
@@ -606,6 +663,14 @@ ul.links {
   color: #68696b;
   font-size: 0.821em;
 }
+.node-unpublished {
+  margin: -20px -15px 0;
+  padding: 20px 15px 0;
+}
+.node-unpublished .comment-text .comment-arrow {
+  border-left: 1px solid #fff4f4;
+  border-right: 1px solid #fff4f4;
+}
 
 /* ----------------- Comments ----------------- */
 
@@ -617,17 +682,22 @@ ul.links {
 }
 .comment {
   margin-bottom: 20px;
-  position: relative;
+  display: table;
+  vertical-align: top;
 }
 .comment .attribution {
-  padding-top: 20px;
-  float: left; /* LTR */
-  width: 110px;
+  display: table-cell;
+  padding: 0 30px 0 0; /* LTR */
+  vertical-align: top;
+  overflow: hidden;
 }
 .comment .attribution img {
   margin: 0;
   border: 1px solid #d3d7d9;
 }
+.comment .attribution .username {
+  white-space: nowrap;
+}
 .comment .submitted p {
   margin: 4px 0;
   font-size: 1.071em;
@@ -646,17 +716,22 @@ ul.links {
   line-height: 1.6;
 }
 .comment .comment-arrow {
-  background: url(../images/comment-arrow.png); /* LTR */
+  background: url(../images/comment-arrow.gif) no-repeat 0 center transparent; /* LTR */
+  border-left: 1px solid;
+  border-right: 1px solid;
   height: 40px;
-  width: 20px;
-  margin-left: -45px; /* LTR */
+  margin-left: -47px; /* LTR */
   margin-top: 10px;
   position: absolute;
+  width: 20px;
 }
 .comment .comment-text {
-  margin-left: 140px; /* LTR */
   padding: 10px 25px;
   border: 1px solid #d3d7d9;
+  display: table-cell;
+  vertical-align: top;
+  position: relative;
+  width: 100%;
 }
 .comment .indented {
   margin-left: 40px; /* LTR */
@@ -667,6 +742,14 @@ ul.links {
 .comment ul.links li {
   padding: 0 0.5em 0 0; /* LTR */
 }
+.comment-unpublished {
+  margin-right: 5px; /* LTR */
+  padding: 5px 2px 5px 5px; /* LTR */
+}
+.comment-unpublished .comment-text .comment-arrow {
+  border-left: 1px solid #fff4f4;
+  border-right: 1px solid #fff4f4;
+}
 
 /* ------------------ Sidebar ----------------- */
 .sidebar .section {
@@ -677,8 +760,7 @@ ul.links {
   padding: 15px 20px;
   margin: 0 0 20px;
 }
-.sidebar h2,
-#preview .sidebar h2 {
+.sidebar h2 {
   margin: 0 0 0.5em;
   border-bottom: 1px solid #d6d6d6;
   padding-bottom: 5px;
@@ -702,14 +784,15 @@ ul.links {
 /* ----------------- Triptych ----------------- */
 
 #triptych-wrapper {
-  background-color: #fafafa;
-  background: rgba(40,40,0,0.08);
+  background-color: #f0f0f0;
+  background: rgba(30, 50, 10, 0.08);
+  border-top: 1px solid #e7e7e7;
 }
 #triptych h2 {
   color: #000;
   font-size: 1.714em;
   margin-bottom: 0.8em;
-  text-shadow: 0px 1px 0 #fff;
+  text-shadow: 0 1px 0 #fff;
   text-align: center;
   line-height: 1;
 }
@@ -758,23 +841,23 @@ ul.links {
 
 #footer-wrapper {
   color: #c0c0c0;
-  color: rgba(255,255,255,0.65);  
+  color: rgba(255, 255, 255, 0.65);
   font-size: 0.857em;
 }
 #footer-wrapper a {
   color: #fcfcfc;
-  color: rgba(255,255,255,0.8);
+  color: rgba(255, 255, 255, 0.8);
 }
 #footer-wrapper a:hover,
 #footer-wrapper a:focus {
   color: #fefefe;
-  color: rgba(255,255,255,0.95);  
+  color: rgba(255, 255, 255, 0.95);
   text-decoration: underline;
 }
 #footer-wrapper .block {
   margin: 20px 0;
   border: 1px solid #444;
-  border-color: rgba(255,255,255,0.1);  
+  border-color: rgba(255, 255, 255, 0.1);
   padding: 10px;
 }
 #footer-columns .block-menu,
@@ -783,17 +866,19 @@ ul.links {
   padding: 0;
   border: none;
 }
-#footer .block,
+#footer .block {
+  margin: 0.5em 0;
+}
 #footer .block .content {
-  overflow: hidden;
-  margin: .5em 0;
+  padding: 0.5em 0;
+  margin-top: 0;
 }
 #footer .block h2 {
   margin: 0;
 }
 #footer-columns h2 {
   border-bottom: 1px solid #555;
-  border-color: rgba(255,255,255,0.15);  
+  border-color: rgba(255, 255, 255, 0.15);
   font-size: 1em;
   margin-bottom: 0;
   padding-bottom: 3px;
@@ -808,7 +893,7 @@ ul.links {
 #footer-columns .content ul {
   list-style: none;
   padding-left: 0; /* LTR */
-  margin-left: 0
+  margin-left: 0;
 }
 #footer-columns .content li {
   list-style: none;
@@ -818,7 +903,7 @@ ul.links {
 #footer-columns .content li a {
   display: block;
   border-bottom: 1px solid #555;
-  border-color: rgba(255,255,255,0.15);  
+  border-color: rgba(255, 255, 255, 0.15);
   line-height: 1.2;
   padding: 0.8em 2px 0.8em 20px; /* LTR */
   text-indent: -15px;
@@ -826,14 +911,14 @@ ul.links {
 #footer-columns .content li a:hover,
 #footer-columns .content li a:focus {
   background-color: #1f1f21;
-  background-color: rgba(255,255,255,.05);
+  background-color: rgba(255, 255, 255, 0.05);
   text-decoration: none;
 }
 #footer {
   letter-spacing: 0.2px;
   margin-top: 30px;
   border-top: 1px solid #555;
-  border-color: rgba(255,255,255,0.15);  
+  border-color: rgba(255, 255, 255, 0.15);
 }
 #footer .region {
   margin-top: 20px;
@@ -852,7 +937,7 @@ ul.links {
   padding: 0 12px;
   display: block;
   border-right: 1px solid #555; /* LTR */
-  border-color: rgba(255,255,255,0.15);  
+  border-color: rgba(255, 255, 255, 0.15);
 }
 #footer li.first a {
   padding-left: 0; /* LTR */
@@ -866,7 +951,7 @@ ul.links {
 }
 #footer-wrapper tr.even {
   background-color: #2c2c2c;
-  background-color: rgba(0,0,0,0.15)
+  background-color: rgba(0, 0, 0, 0.15);
 }
 
 /* --------------- System Tabs  --------------- */
@@ -929,7 +1014,7 @@ ul.links {
   padding-left: 0; /* LTR */
 }
 .tabs ul.secondary li a {
-  padding: .25em .5em;
+  padding: 0.25em 0.5em;
 }
 .tabs ul.secondary li a.active {
   background: #f2f2f2;
@@ -942,7 +1027,7 @@ ul.links {
 ul.action-links {
   list-style: none;
   margin: 5px;
-  padding: .5em 1em;
+  padding: 0.5em 1em;
 }
 ul.action-links li {
   display: inline-block;
@@ -960,8 +1045,12 @@ ul.action-links li a {
   padding: 20px 0 5px;
   margin: 0 auto;
 }
+.featured #messages {
+  background: #f0f0f0;
+  background: rgba(30, 50, 10, 0.08);
+}
 div.messages {
-  margin: 8px 0;
+  margin: 8px 15px;
 }
 
 /* -------------- Breadcrumbs   -------------- */
@@ -1013,7 +1102,7 @@ a.button {
   font-weight: normal;
   text-align: center;
   margin-bottom: 1em;
-  margin-right: 1em; /* LTR */
+  margin-right: 0.6em; /* LTR */
   padding: 4px 17px;
   -khtml-border-radius: 15px;
   -moz-border-radius: 20px;
@@ -1047,9 +1136,12 @@ fieldset {
 .fieldset-wrapper {
   margin-top: 25px;
 }
+.node-form .fieldset-wrapper {
+  margin-top: 0;
+}
 .filter-wrapper {
   top: 0;
-  padding-bottom: 10px;
+  padding: 1em 0 0.2em;
   -khtml-border-radius-topright: 0;
   -khtml-border-radius-topleft: 0;
   -moz-border-radius-topright: 0;
@@ -1059,6 +1151,19 @@ fieldset {
   border-top-left-radius: 0;
   border-top-right-radius: 0;
 }
+.filter-help a {
+  font-size: 0.857em;
+  padding: 2px 20px 0;
+}
+.filter-wrapper .form-item label {
+  margin-right: 10px;
+}
+.filter-wrapper .form-item {
+  padding: 0 0 0.5em 0.5em;
+}
+.filter-guidelines {
+  padding: 0 1.5em 0 0.5em;
+}
 fieldset.collapsed {
   background: transparent;
   -khtml-border-radius: 0;
@@ -1203,6 +1308,27 @@ fieldset .description {
   border-bottom-left-radius: 4px;
   border-bottom-right-radius: 4px;
 }
+
+/* Disabled form elements */
+input.form-button-disabled,
+input.form-button-disabled:hover,
+input.form-button-disabled:focus,
+input.form-button-disabled:active,
+.form-disabled input,
+.form-disabled select,
+.form-disabled textarea {
+  background: #ededed;
+  border-color: #bbb;
+  color: #717171;
+}
+.form-disabled .grippie {
+  background-color: #ededed;
+  border-color: #bbb;
+}
+.form-disabled label {
+  color: #717171;
+}
+
 /* Animated throbber */
 html.js input.form-autocomplete {
   background-position: 100% 4px; /* LTR */
@@ -1212,36 +1338,65 @@ html.js input.throbbing {
 }
 
 /* Comment form */
-.comment-form .form-item {
-  overflow: hidden;
-  margin-bottom: .8em;
-}
-.comment-form .form-type-textfield label,
-.comment-form .form-type-item label {
+.comment-form label {
   float: left; /* LTR */
+  font-size: 0.929em;
+  width: 120px;
 }
-.comment-form .form-type-textfield input,
-.comment-form .form-item .username {
-  float: right; /* LTR */
-  width: 75%;
+.comment-form input,
+.comment-form .form-select {
+  margin: 0;
   -khtml-border-radius: 4px;
   -moz-border-radius: 4px;
   -webkit-border-radius: 4px;
   border-radius: 4px;
 }
+.comment-form .form-type-textarea label {
+  float: none;
+}
+.comment-form .form-item,
+.comment-form .form-radios,
+.comment-form .form-type-checkbox,
+.comment-form .form-select {
+  margin-bottom: 10px;
+  overflow: hidden;
+}
+.comment-form .form-type-checkbox,
+.comment-form .form-radios {
+  margin-left: 120px; /* LTR */
+}
+.comment-form .form-type-checkbox label,
+.comment-form .form-radios label {
+  float: none;
+  margin-top: 0;
+}
+.comment-form input.form-file {
+  width: auto;
+}
+.no-sidebars .comment-form .form-text {
+  width: 800px;
+}
+.one-sidebar .comment-form .form-text {
+  width: 500px;
+}
+.two-sidebars .comment-form .form-text {
+  width: 320px;
+}
 .comment-form .form-item .description {
   font-size: 0.786em;
-  line-height: 1;
-  float: right; /* LTR */
-  width: 76%;
+  line-height: 1.2;
+  margin-left: 120px; /* LTR */
+}
+#content h2.comment-form {
+  margin-bottom: 0.5em;
 }
 .comment-form .form-textarea {
   -khtml-border-radius-topleft: 4px;
   -khtml-border-radius-topright: 4px;
-  -webkit-border-top-left-radius: 4px;
-  -webkit-border-top-right-radius: 4px;
   -moz-border-radius-topleft: 4px;
   -moz-border-radius-topright: 4px;
+  -webkit-border-top-left-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
   border-top-left-radius: 4px;
   border-top-right-radius: 4px;
 }
@@ -1250,9 +1405,22 @@ html.js input.throbbing {
   margin-top: 0;
   margin-bottom: 0;
 }
+.filter-wrapper label {
+  width: auto;
+  float: none;
+}
+.filter-wrapper .form-select {
+  min-width: 120px;
+}
 .comment-form fieldset.filter-wrapper .tips {
   font-size: 0.786em;
 }
+#comment-body-add-more-wrapper .form-type-textarea label {
+  margin-bottom: 0.4em;
+}
+#edit-actions input {
+  margin-right: 0.6em; /* LTR */
+}
 
 /* -------------- Other Overrides ------------- */
 
@@ -1315,6 +1483,24 @@ div.vertical-tabs .vertical-tabs-panes fieldset.vertical-tabs-pane {
   display: block;
 }
 
+/* --------------- Search Results ---------------- */
+ol.search-results {
+  padding-left: 0;
+}
+.search-results li {
+  border-bottom: 1px solid #d3d7d9;
+  padding-bottom: 0.4285em;
+  margin-bottom: 0.5em;
+}
+.search-results li:last-child {
+  border-bottom: none;
+  padding-bottom: none;
+  margin-bottom: 1em;
+}
+.search-results .search-snippet-info {
+  padding-left: 0;
+}
+
 /* -------------- Shortcut Links -------------- */
 
 .shortcut-wrapper {
@@ -1340,7 +1526,20 @@ div.add-or-remove-shortcuts {
   margin: 0;
 }
 .page-admin-structure-block-demo .block-region {
- color: #000000;
+  background: #ffff66;
+  border: 1px dotted #9f9e00;
+  color: #000;
+  font: 90% "Lucida Grande", "Lucida Sans Unicode", sans-serif;
+  margin: 5px;
+  padding: 5px;
+  text-align: center;
+  text-shadow: none;
+}
+.page-admin-structure-block-demo #featured .block-region {
+  font-size: 0.55em;
+}
+.page-admin-structure-block-demo #header .block-region {
+  width: 500px;
 }
 .page-admin #admin-dblog img {
   margin: 0 5px;
@@ -1362,7 +1561,7 @@ div.admin-panel {
   background: #fbfbfb;
   border: 1px solid #ccc;
   margin: 10px 0;
-  padding: 0px 5px 5px;
+  padding: 0 5px 5px;
 }
 div.admin-panel h3 {
   margin: 16px 7px;
@@ -1399,8 +1598,8 @@ div.admin-panel .description {
   display: none;
 }
 .overlay-processed .field-type-image {
- display: block;
- float: none;
+  display: block;
+  float: none;
 }
 .overlay #messages {
   width: auto;
@@ -1430,6 +1629,7 @@ div.admin-panel .description {
 }
 .poll .text {
   clear: right;
+  margin-right: 2.25em;
 }
 .poll .total {
   font-size: 0.929em;
@@ -1440,6 +1640,9 @@ div.admin-panel .description {
 .node .poll {
   margin: 1.8em 0 0;
 }
+.node .poll .text {
+  margin-right: 6.75em;
+}
 .node .poll #edit-choice {
   margin: 0 0 1.2em;
 }
@@ -1452,47 +1655,3 @@ div.admin-panel .description {
 #footer-wrapper .poll .bar .foreground {
   background-color: #ddd;
 }
-
-/* ---------- Color Form ----------- */
-
-.color-form #placeholder {
-  position: static;
-  width: 195px;
-}
-.overlay .color-form #placeholder {
-  position: absolute;
-}
-.color-form #palette {
-  margin-left: 20px; /* LTR */
-}
-.color-form .form-item {
-  border: 1px solid #fbfbfb;
-  margin: 0;
-  padding: .5em;
-  position: relative;
-  max-width: 350px;
-  -khtml-border-radius: 5px;
-  -moz-border-radius: 5px;
-  -webkit-border-radius: 5px;
-  border-radius: 5px;
-}
-.color-form .form-item label {
-  float: left; /* LTR */
-  font-size: 1em;
-  width: 150px;
-}
-.color-form .form-item.item-selected {
-  background-color: #eeeeee;
-  border: 1px solid #cfcfcf;
-}
-.color-form #palette .lock {
-  position: absolute;
-  top: 5px;
-  left: -20px; /* LTR */
-}
-.color-form #preview {
-  font-size: 0.857em;
-}
-.overlay #preview #footer-wrapper {
-  display: block;
-}
diff --git a/themes/bartik/images/add.png b/themes/bartik/images/add.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e167ebd0fea8015a4e6ecde15d4e99a99092a48
Binary files /dev/null and b/themes/bartik/images/add.png differ
diff --git a/themes/bartik/images/buttons.png b/themes/bartik/images/buttons.png
new file mode 100644
index 0000000000000000000000000000000000000000..c4b6df58d7cabaceb176375e99458ee4578b6b3e
Binary files /dev/null and b/themes/bartik/images/buttons.png differ
diff --git a/themes/bartik/images/comment-arrow-rtl.gif b/themes/bartik/images/comment-arrow-rtl.gif
new file mode 100644
index 0000000000000000000000000000000000000000..b597e6587f843d15946a8ce81545baea76617465
Binary files /dev/null and b/themes/bartik/images/comment-arrow-rtl.gif differ
diff --git a/themes/bartik/images/comment-arrow-rtl.png b/themes/bartik/images/comment-arrow-rtl.png
new file mode 100644
index 0000000000000000000000000000000000000000..892fb46698a9615f27ad7f250ff4de611ac58c15
Binary files /dev/null and b/themes/bartik/images/comment-arrow-rtl.png differ
diff --git a/themes/bartik/images/comment-arrow.gif b/themes/bartik/images/comment-arrow.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ce48d0ccd97af40058599b1536ee1878ecfef64c
Binary files /dev/null and b/themes/bartik/images/comment-arrow.gif differ
diff --git a/themes/bartik/images/comment-arrow.png b/themes/bartik/images/comment-arrow.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e908a0968f47fc7a67cd3768c91ada8815d9cf8
Binary files /dev/null and b/themes/bartik/images/comment-arrow.png differ
diff --git a/themes/bartik/images/search-button.png b/themes/bartik/images/search-button.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6e820ad9f6ac36bd158a4a2b96ed43d711c6bae
Binary files /dev/null and b/themes/bartik/images/search-button.png differ
diff --git a/themes/bartik/images/tabs-border.png b/themes/bartik/images/tabs-border.png
new file mode 100644
index 0000000000000000000000000000000000000000..25f95356a62c0a945bfd1bda9bd3325aef65c253
Binary files /dev/null and b/themes/bartik/images/tabs-border.png differ
diff --git a/themes/bartik/logo.png b/themes/bartik/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ada45326367a08cbf30ea75a79646aab2ac36aa
Binary files /dev/null and b/themes/bartik/logo.png differ
diff --git a/themes/bartik/screenshot.png b/themes/bartik/screenshot.png
new file mode 100644
index 0000000000000000000000000000000000000000..34734efa682951dcda3a9476e6edef9c42cef513
Binary files /dev/null and b/themes/bartik/screenshot.png differ
diff --git a/themes/bartik/template.php b/themes/bartik/template.php
index 657c3057c0819f86d6e787f2d4c16610806db81a..685331a7804b19a6ea396513c076297c4621046c 100644
--- a/themes/bartik/template.php
+++ b/themes/bartik/template.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: template.php,v 1.7 2010/10/05 19:59:10 dries Exp $
+// $Id: template.php,v 1.13 2010/12/14 01:04:27 dries Exp $
 
 /**
  * Add body classes if certain regions have content.
@@ -78,6 +78,9 @@ function bartik_process_page(&$variables) {
  * Implements hook_preprocess_maintenance_page().
  */
 function bartik_preprocess_maintenance_page(&$variables) {
+  if (!$variables['db_is_active']) {
+    unset($variables['site_name']);
+  }
   drupal_add_css(drupal_get_path('theme', 'bartik') . '/css/maintenance-page.css');
 }
 
@@ -99,6 +102,16 @@ function bartik_process_maintenance_page(&$variables) {
   }
 }
 
+/**
+ * Override or insert variables into the node template.
+ */
+function bartik_preprocess_node(&$variables) {
+  $variables['submitted'] = t('published by !username on !datetime', array('!username' => $variables['name'], '!datetime' => $variables['date']));
+  if ($variables['view_mode'] == 'full' && node_is_page($variables['node'])) {
+    $variables['classes_array'][] = 'node-full';
+  }
+}
+
 /**
  * Override or insert variables into the block template.
  */
@@ -108,3 +121,34 @@ function bartik_preprocess_block(&$variables) {
     $variables['title_attributes_array']['class'][] = 'element-invisible';
   }
 }
+
+/**
+ * Implements theme_menu_tree().
+ */
+function bartik_menu_tree($variables) {
+  return '<ul class="menu clearfix">' . $variables['tree'] . '</ul>';
+}
+
+/**
+ * Implements theme_field__field_type().
+ */
+function bartik_field__taxonomy_term_reference($variables) {
+  $output = '';
+
+  // Render the label, if it's not hidden.
+  if (!$variables['label_hidden']) {
+    $output .= '<h3 class="field-label">' . $variables['label'] . ': </h3>';
+  }
+
+  // Render the items.
+  $output .= ($variables['element']['#label_display'] == 'inline') ? '<ul class="links inline">' : '<ul class="links">';
+  foreach ($variables['items'] as $delta => $item) {
+    $output .= '<li class="taxonomy-term-reference-' . $delta . '"' . $variables['item_attributes'][$delta] . '>' . drupal_render($item) . '</li>';
+  }
+  $output .= '</ul>';
+
+  // Render the top-level DIV.
+  $output = '<div class="' . $variables['classes'] . (!in_array('clearfix', $variables['classes_array']) ? ' clearfix' : '') . '">' . $output . '</div>';
+
+  return $output;
+}
diff --git a/themes/bartik/templates/comment.tpl.php b/themes/bartik/templates/comment.tpl.php
index 920bd3b814316481524d9a2330066b29dc3efb4f..3135c65d15e18361082d9b9b45c97b7fcbedd504 100644
--- a/themes/bartik/templates/comment.tpl.php
+++ b/themes/bartik/templates/comment.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.tpl.php,v 1.3 2010/09/24 01:36:30 webchick Exp $
+// $Id: comment.tpl.php,v 1.4 2010/12/01 00:18:15 webchick Exp $
 
 /**
  * @file
@@ -19,6 +19,8 @@
  *   desired parameters on the $comment->changed variable.
  * - $new: New comment marker.
  * - $permalink: Comment permalink.
+ * - $submitted: Submission information created from $author and $created during
+ *   template_preprocess_comment().
  * - $picture: Authors picture.
  * - $signature: Authors signature.
  * - $status: Comment status. Possible values are:
diff --git a/themes/bartik/templates/maintenance-page.tpl.php b/themes/bartik/templates/maintenance-page.tpl.php
index 3fa2c1627e46abb401bfcb7465b6c2f2344b2516..9c35121a1bc309017b1ec3f2b10919d0ce63bb30 100644
--- a/themes/bartik/templates/maintenance-page.tpl.php
+++ b/themes/bartik/templates/maintenance-page.tpl.php
@@ -1,12 +1,11 @@
 <?php
-// $Id: maintenance-page.tpl.php,v 1.2 2010/07/28 01:40:39 dries Exp $
+// $Id: maintenance-page.tpl.php,v 1.4 2010/11/30 17:55:13 dries Exp $
 
 /**
  * @file
- * Bartik's theme implementation to display a single Drupal page while offline.
+ * Implementation to display a single Drupal page while offline.
  *
- * All the available variables are mirrored in page.tpl.php. Some may be left
- * blank but they are provided for consistency.
+ * All the available variables are mirrored in page.tpl.php.
  *
  * @see template_preprocess()
  * @see template_preprocess_maintenance_page()
@@ -16,7 +15,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" lang="<?php print $language->language; ?>" dir="<?php print $language->dir; ?>">
-
 <head>
   <?php print $head; ?>
   <title><?php print $head_title; ?></title>
@@ -24,70 +22,46 @@
   <?php print $scripts; ?>
 </head>
 <body class="<?php print $classes; ?>" <?php print $attributes;?>>
+
   <div id="skip-link">
-    <a href="#main-content"><?php print t('Skip to main content'); ?></a>
+    <a href="#main-content" class="element-invisible element-focusable"><?php print t('Skip to main content'); ?></a>
   </div>
-  <?php print $page_top; ?>
-
-<div id="page-wrapper"><div id="page">
 
-  <div id="header"><div class="section clearfix">
+  <div id="page-wrapper"><div id="page">
 
-    <?php if ($site_name || $site_slogan): ?>
-      <div id="name-and-slogan"<?php if ($hide_site_name && $hide_site_slogan) { print ' class="element-invisible"'; } ?>>
-
-        <?php if ($site_name): ?>
-          <?php if ($title): ?>
+    <div id="header"><div class="section clearfix">
+      <?php if ($site_name || $site_slogan): ?>
+        <div id="name-and-slogan"<?php if ($hide_site_name && $hide_site_slogan) { print ' class="element-invisible"'; } ?>>
+          <?php if ($site_name): ?>
             <div id="site-name"<?php if ($hide_site_name) { print ' class="element-invisible"'; } ?>>
               <strong>
                 <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a>
               </strong>
             </div>
-          <?php else: /* Use h1 when the content title is empty */ ?>
-            <h1 id="site-name"<?php if ($hide_site_name) { print ' class="element-invisible"'; } ?>>
-              <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a>
-            </h1>
           <?php endif; ?>
-        <?php endif; ?>
-
-        <?php if ($site_slogan): ?>
-          <div id="site-slogan"<?php if ($hide_site_slogan) { print ' class="element-invisible"'; } ?>>
-            <?php print $site_slogan; ?>
-          </div>
-        <?php endif; ?>
-
-      </div> <!-- /#name-and-slogan -->
-    <?php endif; ?>
-
-    <?php print $header; ?>
-
-  </div></div> <!-- /.section, /#header -->
-
-  <div id="main-wrapper"><div id="main" class="clearfix">
-
-    <div id="content" class="column"><div class="section">
-      <?php if ($highlighted): ?><div id="highlighted"><?php print $highlighted; ?></div><?php endif; ?>
-      <a id="main-content"></a>
-      <?php if ($title): ?>
-        <h1 class="title" id="page-title">
-          <?php print $title; ?>
-        </h1>
-      <?php endif; ?>
-      <?php print $content; ?>
-      
-      <?php if ($messages): ?>
-        <div id="messages"><div class="section clearfix">
-          <?php print $messages; ?>
-        </div></div> <!-- /.section, /#messages -->
+          <?php if ($site_slogan): ?>
+            <div id="site-slogan"<?php if ($hide_site_slogan) { print ' class="element-invisible"'; } ?>>
+              <?php print $site_slogan; ?>
+            </div>
+          <?php endif; ?>
+        </div> <!-- /#name-and-slogan -->
       <?php endif; ?>
+    </div></div> <!-- /.section, /#header -->
+
+    <div id="main-wrapper"><div id="main" class="clearfix">
+      <div id="content" class="column"><div class="section">
+        <a id="main-content"></a>
+        <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
+        <?php print $content; ?>
+        <?php if ($messages): ?>
+          <div id="messages"><div class="section clearfix">
+            <?php print $messages; ?>
+          </div></div> <!-- /.section, /#messages -->
+        <?php endif; ?>
+      </div></div> <!-- /.section, /#content -->
+    </div></div> <!-- /#main, /#main-wrapper -->
 
-    </div></div> <!-- /.section, /#content -->
-
-
-  </div></div> <!-- /#main, /#main-wrapper -->
-
-</div></div> <!-- /#page, /#page-wrapper -->
+  </div></div> <!-- /#page, /#page-wrapper -->
 
-  <?php print $page_bottom; ?>
 </body>
 </html>
diff --git a/themes/bartik/templates/node.tpl.php b/themes/bartik/templates/node.tpl.php
index 6961698e68369a20eb85dce620092d9402059512..f5907d9b45ef169201d2367bc584791a08929346 100644
--- a/themes/bartik/templates/node.tpl.php
+++ b/themes/bartik/templates/node.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.tpl.php,v 1.1 2010/07/06 05:25:51 webchick Exp $
+// $Id: node.tpl.php,v 1.2 2010/12/01 00:18:15 webchick Exp $
 
 /**
  * @file
@@ -16,7 +16,9 @@
  *   calling format_date() with the desired parameters on the $created variable.
  * - $name: Themed username of node author output from theme_username().
  * - $node_url: Direct url of the current node.
- * - $display_submitted: whether submission information should be displayed.
+ * - $display_submitted: Whether submission information should be displayed.
+ * - $submitted: Submission information created from $name and $date during
+ *   template_preprocess_node().
  * - $classes: String of classes that can be used to style contextually through
  *   CSS. It can be manipulated through the variable $classes_array from
  *   preprocess functions. The default values can be one or more of the
@@ -90,10 +92,7 @@
   <?php if ($display_submitted): ?>
     <div class="meta submitted">
       <?php print $user_picture; ?>
-      <?php
-        print t('published by !username on !datetime',
-          array('!username' => $name, '!datetime' => $date));
-      ?>
+      <?php print $submitted; ?>
     </div>
   <?php endif; ?>
 
diff --git a/themes/bartik/templates/page.tpl.php b/themes/bartik/templates/page.tpl.php
index fe36f06dcff3b066d75e010e4f4076799a57fadd..ed18127effae27edf2004ebd3acce9ccadfa2f71 100644
--- a/themes/bartik/templates/page.tpl.php
+++ b/themes/bartik/templates/page.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: page.tpl.php,v 1.7 2010/10/05 01:48:11 dries Exp $
+// $Id: page.tpl.php,v 1.9 2010/11/07 21:48:56 dries Exp $
 
 /**
  * @file
@@ -146,7 +146,7 @@
           'links' => $secondary_menu,
           'attributes' => array(
             'id' => 'secondary-menu-links',
-            'class' => array('links', 'clearfix'),
+            'class' => array('links', 'inline', 'clearfix'),
           ),
           'heading' => array(
             'text' => t('Secondary menu'),
diff --git a/themes/garland/color/base.png b/themes/garland/color/base.png
index 428c21221197dab468bf983b1279d0c7b6aa0365..983e0fe539a1dfea0bb2a96b0d5815da5a8243e7 100644
Binary files a/themes/garland/color/base.png and b/themes/garland/color/base.png differ
diff --git a/themes/garland/color/preview.png b/themes/garland/color/preview.png
index d80ad30f8a10d8cabc003c10a762383e1ac58f19..0dc5bf9c008953a8b67d305dc576e7bc0fb8a88b 100644
Binary files a/themes/garland/color/preview.png and b/themes/garland/color/preview.png differ
diff --git a/themes/garland/comment.tpl.php b/themes/garland/comment.tpl.php
index 783b259faefe895f200bc25b4e61214095dfaa84..d083ea9af2235bc62d1110e5f61b0167dbba7673 100644
--- a/themes/garland/comment.tpl.php
+++ b/themes/garland/comment.tpl.php
@@ -1,11 +1,11 @@
 <?php
-// $Id: comment.tpl.php,v 1.20 2010/01/04 03:57:19 webchick Exp $
+// $Id: comment.tpl.php,v 1.21 2010/12/01 00:18:15 webchick Exp $
 ?>
 <div class="<?php print $classes . ' ' . $zebra; ?>"<?php print $attributes; ?>>
 
   <div class="clearfix">
 
-    <span class="submitted"><?php print $created; ?> — <?php print $author; ?></span>
+    <span class="submitted"><?php print $submitted ?></span>
 
   <?php if ($new) : ?>
     <span class="new"><?php print drupal_ucfirst($new) ?></span>
diff --git a/themes/garland/garland.info b/themes/garland/garland.info
index b651e4cdb913b72f651b93d7d3e6c980bbba0ecf..31925c1ba21a6449c8da4b442940c12b26a65ea3 100644
--- a/themes/garland/garland.info
+++ b/themes/garland/garland.info
@@ -1,16 +1,15 @@
-; $Id: garland.info,v 1.9 2009/12/01 15:57:40 webchick Exp $
+; $Id: garland.info,v 1.10 2010/11/07 00:27:20 dries Exp $
 name = Garland
 description = A multi-column theme which can be configured to modify colors and switch between fixed and fluid width layouts.
 package = Core
 version = VERSION
 core = 7.x
-engine = phptemplate
 stylesheets[all][] = style.css
 stylesheets[print][] = print.css
 settings[garland_width] = fluid
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/garland/images/bg-bar-white.png b/themes/garland/images/bg-bar-white.png
index 256ea31b12a2bc151f4f3b3ce2523344aea32ff2..4549a5ffd1d7809852f8d84a8bbe252c68525fbb 100644
Binary files a/themes/garland/images/bg-bar-white.png and b/themes/garland/images/bg-bar-white.png differ
diff --git a/themes/garland/images/bg-content-left.png b/themes/garland/images/bg-content-left.png
index a64b346e650cecd1fec5ccb082fbf14c757670ce..8297f74848b0446d68a7e7cc291a0de57d5fa210 100644
Binary files a/themes/garland/images/bg-content-left.png and b/themes/garland/images/bg-content-left.png differ
diff --git a/themes/garland/images/bg-content-right.png b/themes/garland/images/bg-content-right.png
index f07ebb5cdef30d8c8d942d07981d23c7edf6aef9..9fe53439fa3a89a066dca1c0cc53ff522554a704 100644
Binary files a/themes/garland/images/bg-content-right.png and b/themes/garland/images/bg-content-right.png differ
diff --git a/themes/garland/images/bg-navigation-item.png b/themes/garland/images/bg-navigation-item.png
index d2452ac4f22e3e954c9a15b899a4cc75b0d73ce7..375d095d845740c035958020f49f27d40b207085 100644
Binary files a/themes/garland/images/bg-navigation-item.png and b/themes/garland/images/bg-navigation-item.png differ
diff --git a/themes/garland/images/body.png b/themes/garland/images/body.png
index b361e7b38058f271a77df9f99f6e84e4aed19da5..84bac9f1bb910cd19417aa8ce6bff24228c3e5d4 100644
Binary files a/themes/garland/images/body.png and b/themes/garland/images/body.png differ
diff --git a/themes/garland/images/gradient-inner.png b/themes/garland/images/gradient-inner.png
index 7ca1413f67f0114c541aa711076d1cc6be042cdb..ba403b37d042039b371f3be8a30c8fab700c6ae4 100644
Binary files a/themes/garland/images/gradient-inner.png and b/themes/garland/images/gradient-inner.png differ
diff --git a/themes/garland/images/menu-leaf.gif b/themes/garland/images/menu-leaf.gif
index b7811910ef8bc56ffd61757641c3a062353ef8ed..a55d802d53890bf6a517e197cbf689aa376ed426 100644
Binary files a/themes/garland/images/menu-leaf.gif and b/themes/garland/images/menu-leaf.gif differ
diff --git a/themes/garland/logo.png b/themes/garland/logo.png
index 3529fef3189a1291b19b0c727889504f9d1b3324..bef486513de1bc4a0027a51ca9eaa9f8215fc145 100644
Binary files a/themes/garland/logo.png and b/themes/garland/logo.png differ
diff --git a/themes/garland/node.tpl.php b/themes/garland/node.tpl.php
index 8c54eee6e31163d4c3694ebdf0063b61f9eaae55..50fb3c71dedfc765ea43ff5fc9accde8d28b2dff 100644
--- a/themes/garland/node.tpl.php
+++ b/themes/garland/node.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.tpl.php,v 1.23 2010/04/08 18:26:42 dries Exp $
+// $Id: node.tpl.php,v 1.24 2010/12/01 00:18:15 webchick Exp $
 ?>
 <div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
 
@@ -12,7 +12,7 @@
   <?php print render($title_suffix); ?>
 
   <?php if ($display_submitted): ?>
-    <span class="submitted"><?php print $date; ?> — <?php print $name; ?></span>
+    <span class="submitted"><?php print $submitted ?></span>
   <?php endif; ?>
 
   <div class="content clearfix"<?php print $content_attributes; ?>>
diff --git a/themes/garland/page.tpl.php b/themes/garland/page.tpl.php
index 02d3e0e1c9b2501b105d0f8053ee4643c94fb1c7..4857a67faca0d95f25279b7e49fe0789d7898390 100644
--- a/themes/garland/page.tpl.php
+++ b/themes/garland/page.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: page.tpl.php,v 1.47 2010/09/16 19:47:45 dries Exp $
+// $Id: page.tpl.php,v 1.48 2010/11/20 04:03:51 webchick Exp $
 ?>
   <?php print render($page['header']); ?>
 
@@ -47,8 +47,8 @@
             <h1<?php print $tabs ? ' class="with-tabs"' : '' ?>><?php print $title ?></h1>
           <?php endif; ?>
           <?php print render($title_suffix); ?>
-          <?php if ($tabs): ?><h2 class="element-invisible"><?php print t('Primary tabs'); ?></h2><ul class="tabs primary"><?php print render($tabs) ?></ul></div><?php endif; ?>
-          <?php if ($tabs2): ?><h2 class="element-invisible"><?php print t('Secondary tabs'); ?></h2><ul class="tabs secondary"><?php print render($tabs2) ?></ul><?php endif; ?>
+          <?php if ($tabs): ?><?php print render($tabs); ?></div><?php endif; ?>
+          <?php print render($tabs2); ?>
           <?php print $messages; ?>
           <?php print render($page['help']); ?>
           <?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?>
diff --git a/themes/garland/screenshot.png b/themes/garland/screenshot.png
index 3075fe0171d348402095340348d9c6b6924ef0cd..f34590e973a75b494ad8c20aa26b64457847432f 100644
Binary files a/themes/garland/screenshot.png and b/themes/garland/screenshot.png differ
diff --git a/themes/garland/style.css b/themes/garland/style.css
index 8b42a50ddad1af60da9fc4b4a717332b873b8b89..dc8fd8dfa4d7a5813608b1ad2a8b65935ba44f5d 100644
--- a/themes/garland/style.css
+++ b/themes/garland/style.css
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.86 2010/09/27 01:12:45 dries Exp $ */
+/* $Id: style.css,v 1.88 2011/01/03 07:04:48 webchick Exp $ */
 
 /**
  * Generic elements
@@ -312,29 +312,38 @@ span.form-required {
 /**
  * Skip link
  */
+#skip-link {
+  left: 50%;
+  margin-left: -5.25em;
+  margin-top: 0;
+  position: absolute;
+  width: auto;
+  z-index: 1000;
+}
+#skip-link a,
 #skip-link a:link,
 #skip-link a:visited {
-  font-weight: bold;
-  background: #fff;
-  padding: 0px 5px;
+  background: #444;
+  background: rgba(0, 0, 0, 0.6);
+  color: #fff;
+  display: block;
+  font-size: 0.94em;
+  line-height: 1.7;
+  margin-top: 1px;
+  padding: 2px 10px;
   text-decoration: none;
-  font-size: 80%;
-  text-align: right;
-  top: -99em;
-  left: auto;
-  position: absolute;
+  -khtml-border-radius: 0 0 2px 2px;
+  -moz-border-radius: 0 0 2px 2px;
+  -webkit-border-bottom-left-radius: 2px;
+  -webkit-border-bottom-right-radius: 2px;
+  -webkit-border-top-left-radius: 0;
+  -webkit-border-top-right-radius: 0;
+  border-radius: 0 0 2px 2px;
 }
-
 #skip-link a:hover,
-#skip-link a:focus,
-#skip-link a:active  {
-  height: auto;
-  width: auto;
-  overflow: visible;
-  top:0;
-  left:0;
-  position: fixed;
-  z-index: 1000;
+#skip-link a:active,
+#skip-link a:focus {
+  outline: 0;
 }
 
 /**
diff --git a/themes/garland/template.php b/themes/garland/template.php
index 6f33b339a1fe78b9595e1e1c294e8f386259f367..45818aaaadc654553b0c4a63a81c21fc2f4c5968 100644
--- a/themes/garland/template.php
+++ b/themes/garland/template.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: template.php,v 1.42 2010/10/05 19:59:10 dries Exp $
+// $Id: template.php,v 1.45 2010/12/01 00:18:15 webchick Exp $
 
 /**
  * Return a themed breadcrumb trail.
@@ -59,12 +59,18 @@ function garland_process_html(&$vars) {
  * Override or insert variables into the page template.
  */
 function garland_preprocess_page(&$vars) {
-  $vars['tabs2'] = menu_secondary_local_tasks();
+  // Move secondary tabs into a separate variable.
+  $vars['tabs2'] = array(
+    '#theme' => 'menu_local_tasks',
+    '#secondary' => $vars['tabs']['#secondary'],
+  );
+  unset($vars['tabs']['#secondary']);
+
   if (isset($vars['main_menu'])) {
     $vars['primary_nav'] = theme('links__system_main_menu', array(
       'links' => $vars['main_menu'],
       'attributes' => array(
-        'class' => array('links', 'main-menu'),
+        'class' => array('links', 'inline', 'main-menu'),
       ),
       'heading' => array(
         'text' => t('Main menu'),
@@ -80,7 +86,7 @@ function garland_preprocess_page(&$vars) {
     $vars['secondary_nav'] = theme('links__system_secondary_menu', array(
       'links' => $vars['secondary_menu'],
       'attributes' => array(
-        'class' => array('links', 'secondary-menu'),
+        'class' => array('links', 'inline', 'secondary-menu'),
       ),
       'heading' => array(
         'text' => t('Secondary menu'),
@@ -113,6 +119,20 @@ function garland_preprocess_page(&$vars) {
   $vars['site_name_and_slogan'] = $site_name_text . ' ' . $slogan_text;
 }
 
+/**
+ * Override or insert variables into the node template.
+ */
+function garland_preprocess_node(&$vars) {
+  $vars['submitted'] = $vars['date'] . ' — ' . $vars['name'];
+}
+
+/**
+ * Override or insert variables into the comment template.
+ */
+function garland_preprocess_comment(&$vars) {
+  $vars['submitted'] = $vars['created'] . ' — ' . $vars['author'];
+}
+
 /**
  * Override or insert variables into the block template.
  */
@@ -139,11 +159,3 @@ function garland_preprocess_region(&$vars) {
     $vars['classes_array'][] = 'clearfix';
   }
 }
-
-/**
- * Returns the rendered local tasks. The default implementation renders
- * them as tabs. Overridden to split the secondary tasks.
- */
-function garland_menu_local_tasks() {
-  return menu_primary_local_tasks();
-}
diff --git a/themes/seven/images/add.png b/themes/seven/images/add.png
index b427878b90d5fced47d0e3a3a1d56bb5be91d450..1a2faf656c9f547c349fd7a55ed7fe11d9ee2605 100644
Binary files a/themes/seven/images/add.png and b/themes/seven/images/add.png differ
diff --git a/themes/seven/images/arrow-asc.png b/themes/seven/images/arrow-asc.png
index 74f6fa34a2bb015f180305c6434c46fb10c58c10..d25b8dd75bef33da3b0a997f42e31f1f46b457fc 100644
Binary files a/themes/seven/images/arrow-asc.png and b/themes/seven/images/arrow-asc.png differ
diff --git a/themes/seven/images/arrow-desc.png b/themes/seven/images/arrow-desc.png
index dbcc8d9de1882dcd05e6649f2e60e62230d45bd7..2feade962ad44e142dffb90ded61511d8ee970d3 100644
Binary files a/themes/seven/images/arrow-desc.png and b/themes/seven/images/arrow-desc.png differ
diff --git a/themes/seven/images/arrow-next.png b/themes/seven/images/arrow-next.png
index 3f6a12c1a1e46226068bbf091584583c3a707806..ed551def21e8427302d56f722e4c02ba5ccbd6a6 100644
Binary files a/themes/seven/images/arrow-next.png and b/themes/seven/images/arrow-next.png differ
diff --git a/themes/seven/images/arrow-prev.png b/themes/seven/images/arrow-prev.png
index f43b68b0d8dfc44d659e9255c1c289a13fb133a2..64b2dac724c95ef5f7dcfce886bc8f7871f7fb13 100644
Binary files a/themes/seven/images/arrow-prev.png and b/themes/seven/images/arrow-prev.png differ
diff --git a/themes/seven/images/buttons.png b/themes/seven/images/buttons.png
index 5ef49fd5acda535d846cc884aff6347ca8abffd3..ae833d5f8f1750d4323f64aaa72e3e2e407c5b59 100644
Binary files a/themes/seven/images/buttons.png and b/themes/seven/images/buttons.png differ
diff --git a/themes/seven/images/fc.png b/themes/seven/images/fc.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac44b4190f55ad0e7fc4c0d248c860f04d28f297
Binary files /dev/null and b/themes/seven/images/fc.png differ
diff --git a/themes/seven/images/list-item.png b/themes/seven/images/list-item.png
index 1ec17c8432e21957567662bfcca563d579ca34e9..d598d6366bf14e5d44df9a519800d1fd6e3306e9 100644
Binary files a/themes/seven/images/list-item.png and b/themes/seven/images/list-item.png differ
diff --git a/themes/seven/images/task-check.png b/themes/seven/images/task-check.png
index 9dcb0bc63e8ef2845d2a57cc75c8f8b0fa0c3ea0..64fadf848a4e16827ebf59f624a382786facf728 100644
Binary files a/themes/seven/images/task-check.png and b/themes/seven/images/task-check.png differ
diff --git a/themes/seven/images/task-item.png b/themes/seven/images/task-item.png
index 88101d02f770fdc63d840062dd68c5108d02c2bc..c2f9bf099543230cd7aece817529d698906119a8 100644
Binary files a/themes/seven/images/task-item.png and b/themes/seven/images/task-item.png differ
diff --git a/themes/seven/images/ui-icons-222222-256x240.png b/themes/seven/images/ui-icons-222222-256x240.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a9606f7614c8bd5d0b9b147e47f719c90598070
Binary files /dev/null and b/themes/seven/images/ui-icons-222222-256x240.png differ
diff --git a/themes/seven/images/ui-icons-454545-256x240.png b/themes/seven/images/ui-icons-454545-256x240.png
new file mode 100644
index 0000000000000000000000000000000000000000..80cb644a58f9bb4d638d0d44b060caa8895ea48a
Binary files /dev/null and b/themes/seven/images/ui-icons-454545-256x240.png differ
diff --git a/themes/seven/images/ui-icons-800000-256x240.png b/themes/seven/images/ui-icons-800000-256x240.png
new file mode 100644
index 0000000000000000000000000000000000000000..7bf106b2b4d07cc47d45f96fa3fb473c85e8ee17
Binary files /dev/null and b/themes/seven/images/ui-icons-800000-256x240.png differ
diff --git a/themes/seven/images/ui-icons-888888-256x240.png b/themes/seven/images/ui-icons-888888-256x240.png
new file mode 100644
index 0000000000000000000000000000000000000000..8373712d13cf55efd105966a905ccd64cb4c5f59
Binary files /dev/null and b/themes/seven/images/ui-icons-888888-256x240.png differ
diff --git a/themes/seven/images/ui-icons-ffffff-256x240.png b/themes/seven/images/ui-icons-ffffff-256x240.png
new file mode 100644
index 0000000000000000000000000000000000000000..3086869dad620762d287816748955140410fe815
Binary files /dev/null and b/themes/seven/images/ui-icons-ffffff-256x240.png differ
diff --git a/themes/seven/jquery.ui.theme.css b/themes/seven/jquery.ui.theme.css
index 88e6dd1f5b297d7c5ccba90117415c32f5c5f601..c26046ae129a8621d2e6b41496d967852d0dfa00 100644
--- a/themes/seven/jquery.ui.theme.css
+++ b/themes/seven/jquery.ui.theme.css
@@ -305,8 +305,10 @@
   border-bottom: solid 1px #ccc;
   -moz-border-radius-bottomleft: 0;
   -webkit-border-bottom-left-radius: 0;
+  border-bottom-left-radius: 0;
   -moz-border-radius-bottomright: 0;
   -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
 }
 .ui-tabs .ui-tabs-nav li {
   padding: 0 1em 0 10px;
@@ -317,7 +319,8 @@
   float: none;
   padding: 0 10px;
   -moz-border-radius: 10px;
-  -webkit-border-radius: 7px;  
+  -webkit-border-radius: 10px;
+  border-radius: 10px;
 }
 .ui-tabs .ui-tabs-nav li.ui-tabs-selected a {
   color: #fff;
@@ -362,9 +365,9 @@
   border-left-color: #D2D2D2;
   border-right-color: #D2D2D2;
   background: url(images/buttons.png) 0 0 repeat-x;
-  border-radius: 20px;
   -moz-border-radius: 20px;
-  -webkit-border-radius: 15px;
+  -webkit-border-radius: 20px;
+  border-radius: 20px;
 }
 .ui-dialog .ui-dialog-buttonpane button:active {
   background: #666;
@@ -394,9 +397,9 @@
   border-left-color: #D2D2D2;
   border-right-color: #D2D2D2;
   background: url(images/buttons.png) 0 0 repeat-x;
-  border-radius: 4px;
-  -webkit-border-radius: 4px;
   -moz-border-radius: 4px;
+  -webkit-border-radius: 4px;
+  border-radius: 4px;
 }
 .ui-slider a.ui-state-active,
 .ui-slider .ui-slider-handle:active {
diff --git a/themes/seven/logo.png b/themes/seven/logo.png
index 6680e660f364d181cbdbe1c4855b97e2cef3be24..3b49a4ce78dc8b1ce754706f400b3b61a99857d1 100644
Binary files a/themes/seven/logo.png and b/themes/seven/logo.png differ
diff --git a/themes/seven/page.tpl.php b/themes/seven/page.tpl.php
index e337f5c39b4a0f6b788fbb480d20166a74007026..6327c0928cd65434418132165e29b2580e8a2909 100644
--- a/themes/seven/page.tpl.php
+++ b/themes/seven/page.tpl.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: page.tpl.php,v 1.14 2010/10/05 00:29:14 dries Exp $
+// $Id: page.tpl.php,v 1.15 2010/11/20 04:03:51 webchick Exp $
 ?>
   <div id="branding" class="clearfix">
     <?php print $breadcrumb; ?>
@@ -8,17 +8,11 @@
       <h1 class="page-title"><?php print $title; ?></h1>
     <?php endif; ?>
     <?php print render($title_suffix); ?>
-    <?php if ($primary_local_tasks): ?>
-      <h2 class="element-invisible"><?php print t('Primary tabs'); ?></h2>
-      <ul class="tabs primary"><?php print render($primary_local_tasks); ?></ul>
-    <?php endif; ?>
+    <?php print render($primary_local_tasks); ?>
   </div>
 
   <div id="page">
-    <?php if ($secondary_local_tasks): ?>
-      <h2 class="element-invisible"><?php print t('Secondary tabs'); ?></h2>
-      <ul class="tabs secondary"><?php print render($secondary_local_tasks); ?></ul>
-    <?php endif; ?>
+    <?php print render($secondary_local_tasks); ?>
 
     <div id="content" class="clearfix">
       <div class="element-invisible"><a id="main-content"></a></div>
diff --git a/themes/seven/reset.css b/themes/seven/reset.css
index 02be479f3eadd758db59727d27f6dfd3cb04ea1d..90ab4705aa9bd25750babea54021d4456cf1cf45 100644
--- a/themes/seven/reset.css
+++ b/themes/seven/reset.css
@@ -1,4 +1,4 @@
-/* $Id: reset.css,v 1.12 2010/08/14 03:01:11 dries Exp $ */
+/* $Id: reset.css,v 1.13 2010/12/19 04:58:13 webchick Exp $ */
 
 /**
  * Reset CSS styles.
@@ -180,7 +180,7 @@ textarea {
   font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
 textarea {
-  font-size: 0.923em;
+  font-size: 1em;
   line-height: 1.538em;
 }
 /**
diff --git a/themes/seven/screenshot.png b/themes/seven/screenshot.png
index cfafad3dab676d59f3434cdd59d625eb84eaf42d..3f0c36774c66b60449a12905b8c6b1b412f306d0 100644
Binary files a/themes/seven/screenshot.png and b/themes/seven/screenshot.png differ
diff --git a/themes/seven/seven.info b/themes/seven/seven.info
index e67bf55dd60b697c940f7e5e94c0ec904f7b71bd..10d306c1fb21c84857edd0385f2693c1f0a870bf 100644
--- a/themes/seven/seven.info
+++ b/themes/seven/seven.info
@@ -1,10 +1,9 @@
-; $Id: seven.info,v 1.5 2010/01/14 06:47:54 webchick Exp $
+; $Id: seven.info,v 1.6 2010/11/07 00:27:20 dries Exp $
 name = Seven
 description = A simple one-column, tableless, fluid width administration theme.
 package = Core
 version = VERSION
 core = 7.x
-engine = phptemplate
 stylesheets[screen][] = reset.css
 stylesheets[screen][] = style.css
 settings[shortcut_module_link] = 1
@@ -15,8 +14,8 @@ regions[page_bottom] = Page bottom
 regions[sidebar_first] = First sidebar
 regions_hidden[] = sidebar_first
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/seven/style.css b/themes/seven/style.css
index 5e293bfb3d748b6c81dc33a518798ea5d530aaaa..851d2d816af5bc416169b75c23bb5199930b53a6 100644
--- a/themes/seven/style.css
+++ b/themes/seven/style.css
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.80 2010/10/15 04:37:15 webchick Exp $ */
+/* $Id: style.css,v 1.86 2011/01/03 07:04:48 webchick Exp $ */
 
 /**
  * Generic elements.
@@ -158,31 +158,23 @@ pre {
 #skip-link a,
 #skip-link a:link,
 #skip-link a:visited {
-  position: absolute;
   display: block;
-  top: auto;
-  left: -10000px;
-  width: 1px;
-  height: 1px;
   background: #444;
   color: #fff;
   font-size: 0.94em;
+  padding: 1px 10px 2px 10px;
   text-decoration: none;
-  border-radius:0 0 10px 10px;
   -moz-border-radius: 0 0 10px 10px;
   -webkit-border-top-left-radius: 0;
   -webkit-border-top-right-radius: 0;
   -webkit-border-bottom-left-radius: 10px;
   -webkit-border-bottom-right-radius: 10px;
+  border-radius: 0 0 10px 10px;
 }
 #skip-link a:hover,
-#skip-link a:active,
-#skip-link a:focus {
-  position: static;
-  width: auto;
-  height: auto;
-  overflow: visible;
-  padding: 1px 10px 2px 10px;
+#skip-link a:focus,
+#skip-link a:active {
+  outline: 0;
 }
 
 /**
@@ -287,10 +279,10 @@ ul.primary li.active a {
   border-width: 1px 1px 0 1px;
   border-style: solid;
   border-color: #a6a7a2;
-  border-radius: 8px 8px 0 0;
   -moz-border-radius: 8px 8px 0 0;
   -webkit-border-top-left-radius: 8px;
   -webkit-border-top-right-radius: 8px;
+  border-radius: 8px 8px 0 0;
 }
 ul.primary li.active a,
 ul.primary li.active a.active,
@@ -327,9 +319,9 @@ ul.secondary li a:hover,
 ul.secondary li.active a,
 ul.secondary li.active a.active {
   padding: 2px 10px;
-  border-radius: 7px;
   -moz-border-radius: 7px;
   -webkit-border-radius: 7px;
+  border-radius: 7px;
 }
 ul.secondary li a:hover,
 ul.secondary li.active a,
@@ -361,9 +353,9 @@ ul.secondary li.active a.active {
   height: 55px;
   width: 80px;
   overflow: hidden;
-  border-radius: 5px;
   -moz-border-radius: 5px;
   -webkit-border-radius: 5px;
+  border-radius: 5px;
 }
 #secondary-links ul.links li a:hover {
   background: #999;
@@ -514,6 +506,13 @@ table.system-status-report tr.error {
   color: #8c2e0b;
   background-color: #fef5f1;
 }
+/**
+ * Exception for webkit bug with the right border of the last cell
+ * in some tables, since it's webkit only, we can use :last-child
+ */
+tr td:last-child {
+  border-right: 1px solid #BEBFB9;
+}
 
 
 /**
@@ -650,9 +649,9 @@ a.button {
   border-left-color: #D2D2D2;
   border-right-color: #D2D2D2;
   background: url(images/buttons.png) 0 0 repeat-x;
-  border-radius: 15px;
   -moz-border-radius: 20px;
-  -webkit-border-radius: 15px;
+  -webkit-border-radius: 20px;
+  border-radius: 20px;
 }
 a.button:link,
 a.button:visited,
@@ -683,12 +682,6 @@ input.form-button-disabled:active {
   text-shadow: none;
   color: #999;
 }
-form input#edit-delete {
-  background: #eee;
-  border-color: #fff #ddd #ccc;
-  text-shadow: none;
-  color: #999;
-}
 input.form-autocomplete,
 input.form-text,
 input.form-file,
@@ -877,7 +870,6 @@ ol.task-list li.done {
   background-color: #fff;
   padding-top: 15px;
 }
-.overlay .primary,
 .overlay #branding h1.page-title,
 .overlay #left,
 .overlay #footer {
@@ -979,3 +971,27 @@ div.add-or-remove-shortcuts {
 #user-login-form .openid-links .user-link {
   margin-left: 1.5em; /* LTR */
 }
+
+/* Disable overlay message */
+#overlay-disable-message {
+  background-color: #addafc;
+}
+#overlay-disable-message a,
+#overlay-disable-message a:visited {
+  color: #000;
+}
+#overlay-disable-message a:focus,
+#overlay-disable-message a:active {
+  outline: none;
+  text-decoration: underline;
+}
+.overlay-disable-message-focused a {
+  padding: 0.4em 0.6em;
+}
+.overlay-disable-message-focused #overlay-dismiss-message {
+  background-color: #59A0D8;
+  color: #fff;
+  -moz-border-radius: 8px;
+  -webkit-border-radius: 8px;
+  border-radius: 8px;
+}
diff --git a/themes/seven/template.php b/themes/seven/template.php
index a6149d7e142f090144c6e4a0d7d8bec680f316be..b01d8b91de5bd7fc114d3cfb787b8fa08647a58a 100644
--- a/themes/seven/template.php
+++ b/themes/seven/template.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: template.php,v 1.24 2010/10/05 19:59:10 dries Exp $
+// $Id: template.php,v 1.25 2010/11/20 04:03:51 webchick Exp $
 
 /**
  * Override or insert variables into the maintenance page template.
@@ -27,8 +27,12 @@ function seven_preprocess_html(&$vars) {
  * Override or insert variables into the page template.
  */
 function seven_preprocess_page(&$vars) {
-  $vars['primary_local_tasks'] = menu_primary_local_tasks();
-  $vars['secondary_local_tasks'] = menu_secondary_local_tasks();
+  $vars['primary_local_tasks'] = $vars['tabs'];
+  unset($vars['primary_local_tasks']['#secondary']);
+  $vars['secondary_local_tasks'] = array(
+    '#theme' => 'menu_local_tasks',
+    '#secondary' => $vars['tabs']['#secondary'],
+  );
 }
 
 /**
diff --git a/themes/seven/vertical-tabs.css b/themes/seven/vertical-tabs.css
index 55a50ee4cd342b8fb055aa7853af2f0414c65224..0de228b8eba8aea77b29c6f62ae2c522f0ff53ec 100644
--- a/themes/seven/vertical-tabs.css
+++ b/themes/seven/vertical-tabs.css
@@ -1,4 +1,4 @@
-/* $Id: vertical-tabs.css,v 1.9 2010/10/06 13:42:18 dries Exp $ */
+/* $Id: vertical-tabs.css,v 1.10 2010/11/19 20:45:04 dries Exp $ */
 
 /**
  * Override of misc/vertical-tabs.css.
@@ -49,6 +49,7 @@ div.vertical-tabs ul li.vertical-tab-button a:hover,
 div.vertical-tabs ul li.vertical-tab-button a:focus {
   background: #d5d5d5;
   text-decoration: none;
+  outline: 0;
 }
 div.vertical-tabs ul li.selected a,
 div.vertical-tabs ul li.selected a:hover,
@@ -57,12 +58,14 @@ div.vertical-tabs ul li.selected a:active {
   background: #fff;
   border-right-color: #fff;
   border-top: 1px solid #ccc;
-  outline: 0;
 }
 div.vertical-tabs ul li.first.selected a,
 div.vertical-tabs ul li.first.selected a:hover {
   border-top: 0;
 }
+div.vertical-tabs ul li.selected a:focus strong {
+  text-decoration: underline;
+}
 div.vertical-tabs .vertical-tabs-panes {
   margin: 0 0 0 265px;
   padding: 10px 15px 10px 0;
diff --git a/themes/stark/logo.png b/themes/stark/logo.png
index 00c907322a47920802e46b2bca339b77988d8f18..32332cf345707c6c575ea99c046c2436ffea9f47 100644
Binary files a/themes/stark/logo.png and b/themes/stark/logo.png differ
diff --git a/themes/stark/screenshot.png b/themes/stark/screenshot.png
index ca6f3c69e8033f5ddaac3142a6b26310399d40f9..6fe457f8add08b91b2ae34abb06d3d9382e5544c 100644
Binary files a/themes/stark/screenshot.png and b/themes/stark/screenshot.png differ
diff --git a/themes/stark/stark.info b/themes/stark/stark.info
index 0452cec70a098d6f50ab0072bcfb432d23cb5a3e..62251ade18668dc0c7bb28c0077027a9e1e03d63 100644
--- a/themes/stark/stark.info
+++ b/themes/stark/stark.info
@@ -1,14 +1,13 @@
-; $Id: stark.info,v 1.3 2009/12/20 19:43:10 dries Exp $
+; $Id: stark.info,v 1.4 2010/11/07 00:27:20 dries Exp $
 name = Stark
 description = This theme demonstrates Drupal's default HTML markup and CSS styles. To learn how to build your own theme and override Drupal's default code, see the <a href="http://drupal.org/theme-guide">Theming Guide</a>.
 package = Core
 version = VERSION
 core = 7.x
-engine = phptemplate
 stylesheets[all][] = layout.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/tests/test_theme/test_theme.info b/themes/tests/test_theme/test_theme.info
index 134a34a8091b3334ea8e8b82e9c11113ce790284..16938a7670af244e1675a23c41ffdc0bdb3d3cb7 100644
--- a/themes/tests/test_theme/test_theme.info
+++ b/themes/tests/test_theme/test_theme.info
@@ -1,8 +1,7 @@
-; $Id: test_theme.info,v 1.2 2010/10/03 05:11:16 webchick Exp $
+; $Id: test_theme.info,v 1.3 2010/11/07 00:27:20 dries Exp $
 name = Test theme
 description = Theme for testing the theme system
 core = 7.x
-engine = phptemplate
 hidden = TRUE
 
 ; Normally, themes may list CSS files like this, and if they exist in the theme
@@ -17,8 +16,8 @@ hidden = TRUE
 ; file within the theme folder.
 stylesheets[all][] = system.base.css
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/tests/update_test_basetheme/update_test_basetheme.info b/themes/tests/update_test_basetheme/update_test_basetheme.info
index 3977709d006c1cfd967dc59c4806fac19bdfc87a..27e6fb3f149a9d986a3cd12b0305a90934a5c7f8 100644
--- a/themes/tests/update_test_basetheme/update_test_basetheme.info
+++ b/themes/tests/update_test_basetheme/update_test_basetheme.info
@@ -1,12 +1,11 @@
-; $Id: update_test_basetheme.info,v 1.1 2009/10/08 15:40:34 dries Exp $
+; $Id: update_test_basetheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
 name = Update test base theme
 description = Test theme which acts as a base theme for other test subthemes.
 core = 7.x
-engine = phptemplate
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/themes/tests/update_test_subtheme/update_test_subtheme.info b/themes/tests/update_test_subtheme/update_test_subtheme.info
index 2ca1e2b53d6b3662c986d8074fd5eb2a4bae4cc8..2b21a98e8c8fb141c5a5184f117321255b03e2f6 100644
--- a/themes/tests/update_test_subtheme/update_test_subtheme.info
+++ b/themes/tests/update_test_subtheme/update_test_subtheme.info
@@ -1,13 +1,12 @@
-; $Id: update_test_subtheme.info,v 1.1 2009/10/08 15:40:34 dries Exp $
+; $Id: update_test_subtheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
 name = Update test subtheme
 description = Test theme which uses update_test_basetheme as the base theme.
 core = 7.x
-engine = phptemplate
 base theme = update_test_basetheme
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2010-10-23
-version = "7.0-beta2"
+; Information added by drupal.org packaging script on 2011-01-05
+version = "7.0"
 project = "drupal"
-datestamp = "1287812130"
+datestamp = "1294208756"
 
diff --git a/update.php b/update.php
index 588865f56889a22140fb126d8c32d1dce47a0437..b860b9645e873c85c91e6c4435198a62b385e483 100644
--- a/update.php
+++ b/update.php
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.php,v 1.325 2010/10/03 23:33:15 webchick Exp $
+// $Id: update.php,v 1.328 2011/01/04 05:57:26 webchick Exp $
 
 /**
  * Root directory of Drupal installation.
@@ -179,11 +179,11 @@ function update_results_page() {
 
   // Output a list of queries executed.
   if (!empty($_SESSION['update_results'])) {
-    $output .= '<div id="update-results">';
-    $output .= '<h2>The following updates returned messages</h2>';
+    $all_messages = '';
     foreach ($_SESSION['update_results'] as $module => $updates) {
       if ($module != '#abort') {
-        $output .= '<h3>' . $module . ' module</h3>';
+        $module_has_message = FALSE;
+        $query_messages = '';
         foreach ($updates as $number => $queries) {
           $messages = array();
           foreach ($queries as $query) {
@@ -191,6 +191,7 @@ function update_results_page() {
             if (empty($query['query'])) {
               continue;
             }
+
             if ($query['success']) {
               $messages[] = '<li class="success">' . $query['query'] . '</li>';
             }
@@ -200,14 +201,24 @@ function update_results_page() {
           }
 
           if ($messages) {
-            $output .= '<h4>Update #' . $number . "</h4>\n";
-            $output .= '<ul>' . implode("\n", $messages) . "</ul>\n";
+            $module_has_message = TRUE;
+            $query_messages .= '<h4>Update #' . $number . "</h4>\n";
+            $query_messages .= '<ul>' . implode("\n", $messages) . "</ul>\n";
           }
         }
-        $output .= '</ul>';
+
+        // If there were any messages in the queries then prefix them with the
+        // module name and add it to the global message list.
+        if ($module_has_message) {
+          $all_messages .= '<h3>' . $module . " module</h3>\n" . $query_messages;
+        }
       }
     }
-    $output .= '</div>';
+    if ($all_messages) {
+      $output .= '<div id="update-results"><h2>The following updates returned messages</h2>';
+      $output .= $all_messages;
+      $output .= '</div>';
+    }
   }
   unset($_SESSION['update_results']);
   unset($_SESSION['update_success']);
@@ -308,8 +319,8 @@ function update_extra_requirements($requirements = NULL) {
  * Check update requirements and report any errors.
  */
 function update_check_requirements() {
-  // Check the system module and update.php requirements only.
-  $requirements = module_invoke('system', 'requirements', 'update');
+  // Check requirements of all loaded modules.
+  $requirements = module_invoke_all('requirements', 'update');
   $requirements += update_extra_requirements();
   $severity = drupal_requirements_severity($requirements);
 
@@ -400,6 +411,9 @@ if (update_access_allowed()) {
 
   update_fix_compatibility();
 
+  // Check the update requirements for all modules.
+  update_check_requirements();
+
   $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
   switch ($op) {
     // update.php ops.