diff -Naur drupal-7.9/.editorconfig drupal-7.58/.editorconfig
--- drupal-7.9/.editorconfig	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/.editorconfig	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,14 @@
+# Drupal editor configuration normalization
+# @see http://editorconfig.org/
+
+# This is the top-most .editorconfig file; do not search in parent directories.
+root = true
+
+# All files.
+[*]
+end_of_line = LF
+indent_style = space
+indent_size = 2
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff -Naur drupal-7.9/.htaccess drupal-7.58/.htaccess
--- drupal-7.9/.htaccess	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/.htaccess	2018-03-27 21:28:19.000000000 +0200
@@ -3,8 +3,13 @@
 #
 
 # Protect files and directories from prying eyes.
-<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$">
-  Order allow,deny
+<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig\.save)$">
+  <IfModule mod_authz_core.c>
+    Require all denied
+  </IfModule>
+  <IfModule !mod_authz_core.c>
+    Order allow,deny
+  </IfModule>
 </FilesMatch>
 
 # Don't show directory listings for URLs which map to a directory.
@@ -20,7 +25,7 @@
 DirectoryIndex index.php index.html index.htm
 
 # Override PHP settings that cannot be changed at runtime. See
-# sites/default/default.settings.php and drupal_initialize_variables() in
+# sites/default/default.settings.php and drupal_environment_initialize() in
 # includes/bootstrap.inc for settings that can be changed at runtime.
 
 # PHP 5, Apache 1 and 2.
@@ -56,6 +61,17 @@
 <IfModule mod_rewrite.c>
   RewriteEngine on
 
+  # Set "protossl" to "s" if we were accessed via https://.  This is used later
+  # if you enable "www." stripping or enforcement, in order to ensure that
+  # you don't bounce between http and https.
+  RewriteRule ^ - [E=protossl]
+  RewriteCond %{HTTPS} on
+  RewriteRule ^ - [E=protossl:s]
+
+  # Make sure Authorization HTTP header is available to PHP
+  # even when running as CGI or FastCGI.
+  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+
   # Block access to "hidden" directories whose names begin with a period. This
   # includes directories used by version control systems such as Subversion or
   # Git to store control files. Files whose names begin with a period, as well
@@ -69,7 +85,7 @@
   # If you do not have mod_rewrite installed, you should remove these
   # directories from your webroot or otherwise protect them from being
   # downloaded.
-  RewriteRule "(^|/)\." - [F]
+  RewriteRule "/\.|^\.(?!well-known/)" - [F]
 
   # If your site can be accessed both with and without the 'www.' prefix, you
   # can use one of the following settings to redirect users to your preferred
@@ -78,14 +94,15 @@
   # To redirect all users to access the site WITH the 'www.' prefix,
   # (http://example.com/... will be redirected to http://www.example.com/...)
   # uncomment the following:
+  # RewriteCond %{HTTP_HOST} .
   # RewriteCond %{HTTP_HOST} !^www\. [NC]
-  # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
+  # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
   #
   # To redirect all users to access the site WITHOUT the 'www.' prefix,
   # (http://www.example.com/... will be redirected to http://example.com/...)
   # uncomment the following:
   # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
-  # RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301]
+  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
 
   # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
   # VirtualDocumentRoot and the rewrite rules are not working properly.
@@ -129,3 +146,9 @@
     </FilesMatch>
   </IfModule>
 </IfModule>
+
+# Add headers to all responses.
+<IfModule mod_headers.c>
+  # Disable content sniffing, since it's an attack vector.
+  Header always set X-Content-Type-Options nosniff
+</IfModule>
diff -Naur drupal-7.9/CHANGELOG.txt drupal-7.58/CHANGELOG.txt
--- drupal-7.9/CHANGELOG.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/CHANGELOG.txt	2018-03-27 21:28:19.000000000 +0200
@@ -1,4 +1,914 @@
 
+Drupal 7.58, 2018-03-28
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-002.
+
+Drupal 7.57, 2018-02-21
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-001.
+
+Drupal 7.56, 2017-06-21
+-----------------------
+- Fixed security issues (access bypass). See SA-CORE-2017-003.
+
+Drupal 7.55, 2017-06-07
+-----------------------
+- Fixed incompatibility with PHP versions 7.0.19 and 7.1.5 due to duplicate
+  DATE_RFC7231 definition.
+- Made Drupal core pass all automated tests on PHP 7.1.
+- Allowed services such as Let's Encrypt to work with Drupal on Apache, by
+  making Drupal's .htaccess file allow access to the .well-known directory
+  defined by RFC 5785.
+- Made new Drupal sites work correctly on Apache 2.4 when the mod_access_compat
+  Apache module is disabled.
+- Fixed Drupal's URL-generating functions to always encode '[' and ']' so that
+  the URLs will pass HTML5 validation.
+- Various additional bug fixes.
+- Various API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.54, 2017-02-01
+-----------------------
+- Modules are now able to define theme engines (API addition:
+  https://www.drupal.org/node/2826480).
+- Logging of searches can now be disabled (new option in the administrative
+  interface).
+- Added menu tree render structure to (pre-)process hooks for theme_menu_tree()
+  (API addition: https://www.drupal.org/node/2827134).
+- Added new function for determining whether an HTTPS request is being served
+  (API addition: https://www.drupal.org/node/2824590).
+- Fixed incorrect default value for short and medium date formats on the date
+  type configuration page.
+- File validation error message is now removed after subsequent upload of valid
+  file.
+- Numerous bug fixes.
+- Numerous API documentation improvements.
+- Additional performance improvements.
+- Additional automated test coverage.
+
+Drupal 7.53, 2016-12-07
+-----------------------
+- Fixed drag and drop support on newer Chrome/IE 11+ versions after 7.51 update
+  when jQuery is updated to 1.7-1.11.0.
+
+Drupal 7.52, 2016-11-16
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2016-005.
+
+Drupal 7.51, 2016-10-05
+-----------------------
+- The Update module now also checks for updates to a disabled theme that is
+  used as an admin theme.
+- Exceptions thrown in dblog_watchdog() are now caught and ignored.
+- Clarified the warning that appears when modules are missing or have moved.
+- Log messages are now XSS filtered on display.
+- Draggable tables now work on touch screen devices.
+- Added a setting for allowing double underscores in CSS identifiers
+  (https://www.drupal.org/node/2810369).
+- If a user navigates away from a page while an Ajax request is running they
+  will no longer get an error message saying "An Ajax HTTP request terminated
+  abnormally".
+- The system_region_list() API function now takes an optional third parameter
+  which allows region name translations to be skipped when they are not needed
+  (API addition: https://www.drupal.org/node/2810365).
+- Numerous performance improvements.
+- Numerous bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.50, 2016-07-07 
+-----------------------
+- Added a new "administer fields" permission for trusted users, which is
+  required in addition to other permissions to use the field UI
+  (https://www.drupal.org/node/2483307).
+- Added clickjacking protection to Drupal core by setting the X-Frame-Options
+  header to SAMEORIGIN by default (https://www.drupal.org/node/2735873).
+- Added support for full UTF-8 (emojis, Asian symbols, mathematical symbols) on
+  MySQL and other database drivers when the site and database are configured to
+  allow it (https://www.drupal.org/node/2761183).
+- Improved performance by avoiding a re-scan of directories when a file is
+  missing; instead, trigger a PHP warning (minor API change:
+  https://www.drupal.org/node/2581445).
+- Made it possible to use any PHP callable in Ajax form callbacks, form API
+  form-building functions, and form API wrapper callbacks (API addition:
+  https://www.drupal.org/node/2761169).
+- Fixed that following a password reset link while logged in leaves users unable
+  to change their password (minor user interface change:
+  https://www.drupal.org/node/2759023).
+- Implemented various fixes for automated test failures on PHP 5.4+ and PHP 7.
+  Drupal core automated tests now pass in these environments.
+- Improved support for PHP 7 by fixing various problems.
+- Fixed various bugs with PHP 5.5+ imagerotate(), including when incorrect
+  color indices are passed in.
+- Fixed a regression introduced in Drupal 7.43 that allowed files uploaded by
+  anonymous users to be lost after form validation errors, and that also caused
+  regressions with certain contributed modules.
+- Fixed a regression introduced in Drupal 7.36 which caused the default value
+  of hidden textarea fields to be ignored.
+- Fixed robots.txt to allow search engines to access CSS, JavaScript and image
+  files.
+- Changed wording on the Update Manager settings page to clarify that the
+  option to check for disabled module updates also applies to uninstalled
+  modules (administrative-facing translatable string change).
+- Changed the help text when editing menu links and configuring URL redirect
+  actions so that it does not reference "Drupal" or the drupal.org website
+  (administrative-facing translatable string change).
+- Fixed the locale safety check that is used to ensure that translations are
+  safe to allow for tokens in the href/src attributes of translated strings.
+- Fixed that URL generation only works on port 80 when using domain based
+  language negotation.
+- Made method="get" forms work inside the administrative overlay. The fix adds
+  a new hidden field to these forms when they appear inside the overlay (minor
+  data structure change).
+- Increased maxlength of menu link title input fields in the node form and
+  menu link form from 128 to 255 characters.
+- Removed meaningless post-check=0 and pre-check=0 cache control headers from
+  Drupal HTTP responses.
+- Added a .editorconfig file to auto-configure editors that support it.
+- Added --directory option to run-tests.sh for easier test discovery of all
+  tests within a project.
+- Made run-tests.sh exit with a failure code when there are test fails or
+  problems running the script.
+- Fixed that cookies from previous tests are still present when a new test
+  starts in DrupalWebTestCase.
+- Improved performance of queries on the {authmap} database table.
+- Fixed handling of missing files and functions inside the registry.
+- Fixed Ajax handling for tableselect form elements that use checkboxes.
+- Fixed a bug which caused ip_address() to return nothing when the client IP
+  address and proxy IP address are the same.
+- Added a new option to format_xml_elements() to allow for already encoded
+  values.
+- Changed the {history} table's node ID field to be an unsigned integer, to
+  match the same field in the {node} table and to prevent errors with very
+  large node IDs.
+- Added an explicit page callback to the "admin/people/create" menu item in the
+  User module (minor data structure change). Previously this automatically
+  inherited the page callback from the parent "admin/people" menu item, which
+  broke contributed modules that override the "admin/people" page.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.44, 2016-06-15
+-----------------------
+- Fixed security issues (privilege escalation). See SA-CORE-2016-002.
+
+Drupal 7.43, 2016-02-24
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2016-001.
+
+Drupal 7.42, 2016-02-03
+-----------------------
+- Stopped invoking hook_flush_caches() on every cron run, since some modules
+  use that hook for expensive operations that are only needed on cache clears.
+- Changed the default .htaccess and web.config to block Composer-related files.
+- Added static caching to module_load_include() to improve performance.
+- Fixed double-encoding bugs in select field widgets provided by the Options
+  module. The fix deprecates the 'strip_tags' property on option widgets and
+  replaces it with a new 'strip_tags_and_unescape' property (minor data
+  structure change).
+- Improved MySQL 5.7 support by changing the MySQL database driver to stop
+  using the ANSI SQL mode alias, which has different meanings for different
+  MySQL versions.
+- Fixed a regression introduced in Drupal 7.39 which prevented autocomplete
+  functionality from working on servers that are not configured to
+  automatically recognize index.php.
+- Updated the Archive_Tar PEAR package to the latest 1.4.0 release, to fix bugs
+  with tar file handling on various operating systems.
+- Fixed fatal errors on node preview when a field is displayed in the node
+  teaser but hidden in the full node view. The fix removes a
+  field_attach_prepare_view() call from the node_preview() function since it is
+  redundant with one in the node preview theme layer.
+- Improved the description of the "Trimmed" format option on text fields
+  (translatable string change, and minor UI and data structure change).
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.41, 2015-10-21
+-----------------------
+- Fixed security issues (open redirect). See SA-CORE-2015-004.
+
+Drupal 7.40, 2015-10-14
+-----------------------
+- Made Drupal's code for parsing .info files run much faster and use much less
+  memory.
+- Prevented drupal_http_request() from returning an error when it receives a
+  201 through 206 HTTP status code.
+- Added support for autoloading traits via the registry on sites running PHP
+  5.4 or higher.
+- Allowed the user-picture.tpl.php theme template to have HTML classes besides
+  the default "user-picture" class printed in it (markup change).
+- Fixed the URL text filter to convert e-mail addresses with plus signs into
+  mailto: links.
+- Added alternate text to file icons displayed by the File module, to improve
+  accessibility (string change, and minor API addition to theme_file_icon()).
+- Changed one-time login link failure messages to be displayed as errors or
+  warnings as appropriate, rather than as regular status messages (minor UI
+  change and data structure change).
+- Changed the default settings.php configuration to exclude private files from
+  the "404_fast_paths" behavior.
+- Changed the page that displays filter tips for a particular text format, for
+  example filter/tips/full_html, to return "page not found" or "access denied"
+  if the format does not exist or the user does not have access to it. This
+  change adds a new menu item to the Filter module's hook_menu() entry (minor
+  data structure change).
+- Added a new hook, hook_block_cid_parts_alter(), to allow modules to alter the
+  cache keys used for caching a particular block.
+- Made drupal_set_message() display and return messages when "0" is passed in
+  as the message to set.
+- Fixed non-functional "Files displayed by default" setting on file fields.
+- The "worker callback" provided in hook_cron_queue_info() and the "finished"
+  callback specified during batch processing can now be any PHP callable
+  instead of just functions.
+- Prevented drupal_set_time_limit() from decreasing the time limit in the case
+  where the PHP maximum execution time is already unlimited.
+- Changed the default thousand marker for numeric fields from a space ("1 000")
+  to nothing ("1000") (minor UI change: https://www.drupal.org/node/1388376).
+- Prevented malformed theme .info files (without a "name" key) from causing
+  exceptions during menu rebuilds. If an .info file without a "name" key is
+  found in a module or theme directory, Drupal will now use the module or
+  theme's machine name as the display name instead.
+- Made the format column in the {date_format_locale} database table
+  case-sensitive, to match the equivalent column in the {date_formats} table.
+- Fixed a bug in the Statistics module that caused JavaScript files attached to
+  a node while it is being viewed to be omitted from the page.
+- Added an optional 'project:' prefix that can be added to dependencies in a
+  module's .info file to indicate which project the dependency resides in (API
+  addition: https://www.drupal.org/node/2299747).
+- Fixed various bugs that occurred after hooks were invoked early in the Drupal
+  bootstrap and that caused module_implements() and drupal_alter() to cache an
+  incomplete set of hook implementations for later use.
+- Set the X-Content-Type-Options header to "nosniff" when possible, to prevent
+  certain web browsers from picking an unsafe MIME type.
+- Prevented the database API from executing multiple queries at once on MySQL,
+  if the site's PHP version is new enough to do so. This is a secondary defense
+  against SQL injection (API change: https://www.drupal.org/node/2463973).
+- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused the upgrade
+  to fail when there were multiple file records pointing to the same file.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.39, 2015-08-19
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2015-003.
+
+Drupal 7.38, 2015-06-17
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2015-002.
+
+Drupal 7.37, 2015-05-07
+-----------------------
+- Fixed a regression in Drupal 7.36 which caused certain kinds of content types
+  to become disabled if they were defined by a no-longer-enabled module.
+- Removed a confusing description regarding automatic time zone detection from
+  the user account form (minor UI and data structure change).
+- Allowed custom HTML tags with a dash in the name to pass through filter_xss()
+  when specified in the list of allowed tags.
+- Allowed hook_field_schema() implementations to specify indexes for fields
+  based on a fixed-length column prefix (rather than the entire column), as was
+  already allowed in hook_schema() implementations.
+- Fixed PDO exceptions on PostgreSQL when accessing invalid entity URLs.
+- Added a sites/all/libraries folder to the codebase, with instructions for
+  using it.
+- Added a description to the "Administer text formats and filters" permission
+  on the Permissions page (string change).
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.36, 2015-04-01
+-----------------------
+- Added a 'file_public_schema' variable which allows modules that define
+  publicly-accessible streams in hook_stream_wrappers() to bypass file download
+  access checks when processing managed file upload fields.
+- Fixed a bug that caused database query tags not to be added to search-related
+  database queries under many circumstances, and which prevented the
+  corresponding hook_query_TAG_alter() implementations from being called.
+- Fixed the "for" attribute on managed file upload field labels to improve
+  accessibility (minor markup change).
+- Added a 'javascript_always_use_jquery' variable which can be set to FALSE by
+  sites that may not need jQuery loaded on all pages, and a 'requires_jquery'
+  option to drupal_add_js() which modules can set to FALSE when adding
+  JavaScript files that have no dependency on jQuery (API addition:
+  https://www.drupal.org/node/2462717).
+- Fixed incorrect foreign keys in the User module's role_permission and
+  users_roles database tables.
+- Changed permission descriptions throughout Drupal core to consistently link
+  to relevant administrative pages, regardless of whether the user viewing the
+  Permissions page can view the page being linked to (minor UI change).
+- Fixed the drupal_add_region_content() function so that it actually adds
+  content to the page.
+- Added an 'image_suppress_itok_output' variable to allow sites already using
+  the existing 'image_allow_insecure_derivatives' variable to also prevent
+  security tokens from appearing in image derivative URLs.
+- Fixed double-escaping of theme names in the Block module administrative
+  interface (minor string change).
+- Added basic support for Xdebug when running automated tests.
+- Fixed a bug which caused previewing a node to remove elements from the node
+  being edited. With this fix, calling node_preview() will no longer modify the
+  passed-in node object (minor API change).
+- Added a user_has_role() function to check whether a user has a particular
+  role (API addition: https://www.drupal.org/node/2462411).
+- Fixed installation failures when an opcode cache is enabled.
+- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused private
+  files to be inaccessible.
+- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused user
+  pictures to be lost.
+- Fixed missing language code in hook_field_attach_view_alter() when it is
+  invoked from field_view_field().
+- Stopped sending ETag and Last-Modified headers for uncached page requests,
+  since they break caching for certain Varnish and Nginx configurations.
+- Changed the Simpletest module to allow PSR-4 test classes to be used in
+  Drupal 7.
+- Fixed a fatal error that occurred when using the Comment module's "Unpublish
+  comment containing keyword(s)" action.
+- Changed the "lang" attribute on language links to "xml:lang" so it validates
+  as XHTML (minor markup change).
+- Prevented the form API from allowing arrays to be submitted for various form
+  elements, such as textfields, textareas, and password fields (API change:
+  https://www.drupal.org/node/2462723).
+- Fixed a bug in the Contact module which caused the global user object to have
+  the incorrect name and e-mail address during the remainder of the page
+  request after the contact form is submitted.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.35, 2015-03-18
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2015-001.
+
+Drupal 7.34, 2014-11-19
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-006.
+
+Drupal 7.33, 2014-11-07
+-----------------------
+- Began storing the file modification time of each module and theme in the
+  {system} database table so that contributed modules can use it to identify
+  recently changed modules and themes (minor data structure change to the
+  return value of system_get_info() and other related functions).
+- Added a "Did you mean?" feature to the run-tests.sh script for running
+  automated tests from the command line, to help developers who are attempting
+  to run a particular test class or group.
+- Changed the date format used in various HTTP headers output by Drupal core
+  from RFC 1123 format to RFC 7231 format.
+- Added a "block_cache_bypass_node_grants" variable to allow sites which have
+  node access modules enabled to use the block cache if desired (API addition).
+- Made image derivative generation HTTP requests return a 404 error (rather
+  than a 500 error) when the source image does not exist.
+- Fixed a bug which caused user pictures to be removed from the user object
+  after saving, and resulted in data loss if the user account was subsequently
+  re-saved.
+- Fixed a bug in which field_has_data() did not return TRUE for fields that
+  only had data in older entity revisions, leading to loss of the field's data
+  when the field configuration was edited.
+- Fixed a bug which caused the Ajax progress throbber to appear misaligned in
+  many situatons (minor styling change).
+- Prevented the Bartik theme from lower-casing the "Permalink" link on
+  comments, for improved multilingual support (minor UI change).
+- Added a "preferred_menu_links" tag to the database query that is used by
+  menu_link_get_preferred() to find the preferred menu link for a given path,
+  to make it easier to alter.
+- Increased the maximum allowed length of block titles to 255 characters
+  (database schema change to the {block} table).
+- Removed the Field module's field_modules_uninstalled() function, since it did
+  not do anything when it was invoked.
+- Added a "theme_hook_original" variable to templates and theme functions and
+  an optional sitewide theme debug mode, to provide contextual information in
+  the page's HTML to theme developers. The theme debug mode is based on the one
+  used with Twig in Drupal 8 and can be accessed by setting the "theme_debug"
+  variable to TRUE (API addition).
+- Added an entity_view_mode_prepare() API function to allow entity-defining
+  modules to properly invoke hook_entity_view_mode_alter(), and used it
+  throughout Drupal core to fix bugs with the invocation of that hook (API
+  change: https://www.drupal.org/node/2369141).
+- Security improvement: Made the database API's orderBy() method sanitize the
+  sort direction ("ASC" or "DESC") for queries built with db_select(), so that
+  calling code does not have to.
+- Changed the RDF module to consistently output RDF metadata for nodes and
+  comments near where the node is rendered in the HTML (minor markup and data
+  structure change).
+- Added an HTML class to RDFa metatags throughout Drupal to prevent them from
+  accidentally affecting the site appearance (minor markup change).
+- Fixed a bug in the Unicode requirements check which prevented installing
+  Drupal on PHP 5.6.
+- Fixed a bug which caused drupal_get_bootstrap_phase() to abort the bootstrap
+  when called early in the page request.
+- Renamed the "Search result" view mode to "Search result highlighting input"
+  to better reflect how it is used (UI change).
+- Improved database queries generated by EntityFieldQuery in the case where
+  delta or language condition groups are used, to reduce the number of INNER
+  JOINs (this is a minor data structure change affecting code which implements
+  hook_query_alter() on these queries).
+- Removed special-case behavior for file uploads which allowed user #1 to
+  bypass maximum file size and user quota limits.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.32, 2014-10-15
+-----------------------
+- Fixed security issues (SQL injection). See SA-CORE-2014-005.
+
+Drupal 7.31, 2014-08-06
+-----------------------
+- Fixed security issues (denial of service). See SA-CORE-2014-004.
+
+Drupal 7.30, 2014-07-24
+-----------------------
+- Fixed a regression introduced in Drupal 7.29 that caused files or images
+  attached to taxonomy terms to be deleted when the taxonomy term was edited
+  and resaved (and other related bugs with contributed and custom modules).
+- Added a warning on the permissions page to recommend restricting access to
+  the "View site reports" permission to trusted administrators. See
+  DRUPAL-PSA-2014-002.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.29, 2014-07-16
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-003.
+
+Drupal 7.28, 2014-05-08
+-----------------------
+- Fixed a regression introduced in Drupal 7.27 that caused JavaScript to break
+  on older browsers (such as Internet Explorer 8 and earlier) when Ajax was
+  used.
+- Increased the timeout used by the Update Manager module when it fetches data
+  from drupal.org (from 5 seconds to 30 seconds), to work around a problem
+  which causes incomplete information about security updates to be presented to
+  site administrators. This fix may lead to a performance slowdown on the
+  Update Manager administration pages, when installing Drupal distributions,
+  and (for sites that use the automated cron feature) on occasional page loads
+  by site visitors.
+- Fixed the behavior of the token system's "[node:summary]" token when the body
+  field does not have a manual summary.
+- Changed the behavior of db_query_temporary() so that it works on SELECT
+  queries even when they have leading comments/whitespace. A side effect of
+  this fix is that db_query_temporary() will now fail with an error if it is
+  ever used on non-SELECT queries.
+- Added a "node_admin_filter" tag to the database query used to build the list
+  of nodes on the content administration page, to make it easier to alter.
+- Made the cron queue system log any exceptions that are thrown while an item
+  in the queue is being processed, rather than stopping the entire PHP request.
+- Improved screen reader support by adding an aria-live HTML attribute to file
+  upload fields when there is an error uploading the file (minor markup
+  change).
+- Made the pager on the Tracker module listing pages show the same number of
+  items as other pagers throughout Drupal core (minor UI change).
+- Fixed a bug which caused caches not to be properly cleared when a file entity
+  was saved or deleted.
+- Added several missing countries to the default list returned by
+  country_get_list() (string change).
+- Replaced the term "weight" with "influence" in the content ranking settings
+  for search, and added help text for administrators (string change).
+- Fixed untranslatable text strings in the administrative interface for the
+  "Crop" effect provided by the Image module (minor string change).
+- Fixed a bug in the Taxonomy module update function introduced in Drupal 7.26
+  that caused memory and CPU problems on sites with very large numbers of
+  unpublished nodes.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.27, 2014-04-16
+-----------------------
+- Fixed security issues (information disclosure). See SA-CORE-2014-002.
+
+Drupal 7.26, 2014-01-15
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-001.
+
+Drupal 7.25, 2014-01-02
+-----------------------
+- Fixed a bug in node_save() which prevented the saved node from being updated
+  in hook_node_insert() and other similar hooks.
+- Added a meta tag to install.php to prevent it from being indexed by search
+  engines even when Drupal is installed in a subfolder (minor markup change).
+- Fixed a bug in the database API that caused frequent deadlock errors when
+  running merge queries on some servers.
+- Performance improvement: Prevented block rehashing from writing blocks to the
+  database on every cache clear and cron run when the blocks have not changed.
+  This fix results in an extra 'saved' key which is added and set to TRUE for
+  each block returned by _block_rehash() that actually is saved to the database
+  (data structure change).
+- Added an optional 'skip on cron' parameter to hook_cron_queue_info() to allow
+  queues to avoid being automatically processed on cron runs (API addition).
+- Fixed a bug which caused hook_block_view_MODULE_DELTA_alter() to never be
+  invoked if the block delta had a hyphen in it. To implement the hook when the
+  block delta has a hyphen, modules should now replace hyphens with underscores
+  when constructing the function name for the hook implementation.
+- Fixed a bug which caused cached pages to sometimes be sent to the browser
+  with incorrect compression. The fix adds a new 'page_compressed' key to the
+  $cache->data array returned by drupal_page_get_cache() (minor data structure
+  change).
+- Fixed broken tests on PHP 5.5.
+- Made the File and Image modules more robust when saving entities that have
+  deleted files attached. The code in file_field_presave() will now remove the
+  record of the deleted file from the entity before saving (minor data
+  structure change).
+- Standardized menu callback functions throughout Drupal core to return
+  MENU_NOT_FOUND and MENU_ACCESS_DENIED rather than printing their own "page
+  not found" or "access denied" pages (minor API change in the return value of
+  these functions under some circumstances).
+- Fixed a bug in which caches were not properly cleared when a node was deleted
+  via the administrative interface.
+- Changed the Bartik theme to render content contained in <pre>, <code> and
+  similar tags in a larger font size, so it is easier to read.
+- Fixed a bug in the Search module that caused exceptions to be thrown during
+  searches if the server was not configured to represent decimal points as a
+  period.
+- Fixed a regression in the Image module that made image_style_url() not work
+  when a relative path (rather than a complete file URI) was passed to it.
+- Added an optional feature to the Statistics module to allow node views to be
+  tracked by Ajax requests rather than during the server-side generation of the
+  page. This allows the node counter to work on sites that use external page
+  caches (string change and new administrative option:
+  https://drupal.org/node/2164069).
+- Added a link to the drupal.org documentation page for cron to the Cron
+  settings page (string change).
+- Added a 'drupal_anonymous_user_object' variable to allow the anonymous user
+  object returned by drupal_anonymous_user() to be overridden with a classed
+  object (API addition).
+- Changed the database API to allow inserts based on a SELECT * query to work
+  correctly.
+- Changed the database schema of the {file_managed} table to allow Drupal to
+  manage files larger than 4 GB.
+- Changed the File module's hook_field_load() implementation to prevent file
+  entity properties which have the same name as file or image field properties
+  from overwriting the field properties (minor API change).
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.24, 2013-11-20
+-----------------------
+- Fixed security issues (multiple vulnerabilities), see SA-CORE-2013-003.
+
+Drupal 7.23, 2013-08-07
+-----------------------
+- Fixed a fatal error on PostgreSQL databases when updating the Taxonomy module
+  from Drupal 6 to Drupal 7.
+- Fixed the default ordering of CSS files for sites using right-to-left
+  languages, to consistently place the right-to-left override file immediately
+  after the CSS it is overriding (API change: https://drupal.org/node/2058463).
+- Added a drupal_check_memory_limit() API function to allow the memory limit to
+  be checked consistently (API addition).
+- Changed the default web.config file for IIS servers to allow favicon.ico
+  files which are present in the filesystem to be accessed.
+- Fixed inconsistent support for the 'tel' protocol in Drupal's URL filtering
+  functions.
+- Performance improvement: Allowed all hooks to be included in the
+  module_implements() cache, even those that are only invoked on HTTP POST
+  requests.
+- Made the database system replace truncate queries with delete queries when
+  inside a transaction, to fix issues with PostgreSQL and other databases.
+- Fixed a bug which caused nested contextual links to display improperly.
+- Fixed a bug which prevented cached image derivatives from being flushed for
+  private files and other non-default file schemes.
+- Fixed drupal_render() to always return an empty string when there is no
+  output, rather than sometimes returning NULL (minor API change).
+- Added protection to cache_clear_all() to ensure that non-cache tables cannot
+  be truncated (API addition: a new isValidBin() method has been added to the
+  default database cache implementation).
+- Changed the default .htaccess file to support HTTP authorization in CGI
+  environments.
+- Changed the password reset form to pre-fill the username when requested via a
+  URL query parameter, and used this in the error message that appears after a
+  failed login attempt (minor data structure and behavior change).
+- Fixed broken support for foreign keys in the field API.
+- Fixed "No active batch" error when a user cancels their own account.
+- Added a description to the "access content overview" permission on the
+  permissions page (string change).
+- Added a drupal_array_diff_assoc_recursive() function to allow associative
+  arrays to be compared recursively (API addition).
+- Added human-readable labels to image styles, in addition to the existing
+  machine-readable name (API change: https://drupal.org/node/2058503).
+- Moved the drupal_get_hash_salt() function to bootstrap.inc and used it in
+  additional places in the code, for added security in the case where there is
+  no hash salt in settings.php.
+- Fixed a regression in Drupal 7.22 that caused internal server errors for
+  sites running on very old Apache 1.x web servers.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.22, 2013-04-03
+-----------------------
+- Allowed the drupal_http_request() function to be overridden so that
+  additional HTTP request capabilities can be added by contributed modules.
+- Changed the Simpletest module to allow PSR-0 test classes to be used in
+  Drupal 7.
+- Removed an unnecessary "Content-Disposition" header from private file
+  downloads; it prevented many private files from being viewed inline in a web
+  browser.
+- Changed various field API functions to allow them to optionally act on a
+  single field within an entity (API addition: http://drupal.org/node/1825844).
+- Fixed a bug which prevented Drupal's file transfer functionality from working
+  on some PHP 5.4 systems.
+- Fixed incorrect log message when theme() is called for a theme hook that does
+  not exist (minor string change).
+- Fixed Drupal's token-replacement system to allow spaces in the token value.
+- Changed the default behavior after a user creates a node they do not have
+  access to view. The user will now be redirected to the front page rather than
+  an access denied page.
+- Fixed a bug which prevented empty HTTP headers (such as "0") from being set.
+  (Minor behavior change: Callers of drupal_add_http_header() must now set
+  FALSE explicitly to prevent a header from being sent at all; this was already
+  indicated in the function's documentation.)
+- Fixed OpenID errors when more than one module implements hook_openid(). The
+  behavior is now changed so that if more than one module tries to set the same
+  parameter, the last module's change takes effect.
+- Fixed a serious documentation bug: The $name variable in the
+  taxonomy-term.tpl.php theme template was incorrectly documented as being
+  sanitized when in fact it is not.
+- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
+  duplicate permission names in the User module's database tables.
+- Added an empty "datatype" attribute to taxonomy term and username links to
+  make the RDFa markup upward compatible with RDFa 1.1 (minor markup addition).
+- Fixed a bug which caused the denial-of-service protection added in Drupal
+  7.20 to break certain valid image URLs that had an extra slash in them.
+- Fixed a bug with update queries in the SQLite database driver that prevented
+  Drupal from being installed with SQLite on PHP 5.4.
+- Fixed enforced dependencies errors updating to recent versions of Drupal 7 on
+  certain non-MySQL databases.
+- Refactored the Field module's caching behavior to obtain large improvements
+  in memory usage for sites with many fields and instances (API addition:
+  http://drupal.org/node/1915646).
+- Fixed entity argument not being passed to implementations of
+  hook_file_download_access_alter(). The fix adds an additional context
+  parameter that can be passed when calling drupal_alter() for any hook (API
+  change: http://drupal.org/node/1882722).
+- Fixed broken support for translatable comment fields (API change:
+  http://drupal.org/node/1874724).
+- Added an assertThemeOutput() method to Simpletest to allow tests to check
+  that themed output matches an expected HTML string (API addition).
+- Added a link to "Install another module" after a module has been successfully
+  downloaded via the Update Manager (UI change).
+- Added an optional "exclusive" flag to installation profile .info files which
+  allows Drupal distributions to force a profile to be selected during
+  installation (API addition: http://drupal.org/node/1961012).
+- Fixed a bug which caused the database API to not properly close database
+  connections.
+- Added a link to the URL for running cron from outside the site to the Cron
+  settings page (UI change).
+- Fixed a bug which prevented image styles from being reverted on PHP 5.4.
+- Made the default .htaccess rules protocol sensitive to improve security for
+  sites which use HTTPS and redirect between "www" and non-"www" versions of
+  the page.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.21, 2013-03-06
+-----------------------
+- Allowed sites using the 'image_allow_insecure_derivatives' variable to still
+  have partial protection from the security issues fixed in Drupal 7.20.
+
+Drupal 7.20, 2013-02-20
+-----------------------
+- Fixed security issues (denial of service). See SA-CORE-2013-002.
+
+Drupal 7.19, 2013-01-16
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2013-001.
+
+Drupal 7.18, 2012-12-19
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2012-004.
+
+Drupal 7.17, 2012-11-07
+-----------------------
+- Changed the default value of the '404_fast_html' variable to have a DOCTYPE
+  declaration.
+- Made it possible to use associative arrays for the 'items' variable in
+  theme_item_list().
+- Fixed a bug which prevented required form elements without a title from being
+  given an "error" class when the form fails validation.
+- Prevented duplicate HTML IDs from appearing when two forms are displayed on
+  the same page and one of them is submitted with invalid data (minor markup
+  change).
+- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
+  stale data in the Upload module's database tables.
+- Fixed a bug in the States API which prevented certain types of form elements
+  from being disabled when requested.
+- Allowed aggregator feed items with author names longer than 255 characters to
+  have a truncated version saved to the database (rather than causing a fatal
+  error).
+- Allowed aggregator feed items to have URLs longer than 255 characters
+  (schema change which results in several columns in the Aggregator module's
+  database tables changing from VARCHAR to TEXT fields).
+- Added hook_taxonomy_term_view() and standardized the process for rendering
+  taxonomy terms to invoke hook_entity_view() and otherwise make it consistent
+  with other entities (API change: http://drupal.org/node/1808870).
+- Added hook_entity_view_mode_alter() to allow modules to change entity view
+  modes on display (API addition: http://drupal.org/node/1833086).
+- Fixed a bug which made database queries running a "LIKE" query on blob fields
+  fail on PostgreSQL databases. This caused errors during the Drupal 6 to
+  Drupal 7 upgrade.
+- Changed the hook_menu() entry for Drupal's rss.xml page to prevent extra path
+  components from being accidentally passed to the page callback function (data
+  structure change).
+- Removed a non-standard "name" attribute from Drupal's default Content-Type
+  header for file downloads.
+- Fixed the theme settings form to properly clean up submitted values in
+  $form_state['values'] when the form is submitted (data structure change).
+- Fixed an inconsistency by removing the colon from the end of the label on
+  multi-valued form fields (minor string change).
+- Added support for 'weight' in hook_field_widget_info() to allow modules to
+  control the order in which widgets are displayed in the Field UI.
+- Updated various tables in the OpenID and Book modules to use the default
+  "empty table" text pattern (string change).
+- Added proxy server support to drupal_http_request().
+- Added "lang" attributes to language links, to better support screen readers.
+- Fixed double occurrence of a "ul" HTML tag on secondary local tasks in the
+  Seven theme (markup change).
+- Fixed bugs which caused taxonomy vocabulary and shortcut set titles to be
+  double-escaped. The fix replaces the taxonomy vocabulary overview page and
+  "Edit shortcuts" menu items' title callback entries in hook_menu() with new
+  functions that do not escape HTML characters (data structure change).
+- Modified the Update manager module to allow drupal.org to collect usage
+  statistics for individual modules and themes, rather than only for entire
+  projects.
+- Modified the node listing database query on Drupal's default front page to
+  add table aliases for better query altering (this is a data structure change
+  affecting code which implements hook_query_alter() on this query).
+- Improved the translatability of the "Field type(s) in use" message on the
+  modules page (admin-facing string change).
+- Fixed a regression which caused a "call to undefined function
+  drupal_find_base_themes()" fatal error under rare circumstances.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.16, 2012-10-17
+-----------------------
+- Fixed security issues (Arbitrary PHP code execution and information
+  disclosure). See SA-CORE-2012-003.
+
+Drupal 7.15, 2012-08-01
+-----------------------
+- Introduced a 'user_password_reset_timeout' variable to allow the 24-hour
+  expiration for user password reset links to be adjusted (API addition).
+- Fixed database errors due to ambiguous column names that occurred when
+  EntityFieldQuery was used in certain situations.
+- Changed the drupal_array_get_nested_value() function to return a reference
+  (API addition).
+- Changed the System module's hook_block_info() implementation to assign the
+  "Main page content" and "System help" blocks to appropriate regions by
+  default and prevent error messages on the block administration page (data
+  structure change).
+- Fixed regression: Non-node entities couldn't be accessed with
+  EntityFieldQuery.
+- Fixed regression: Optional radio buttons with an empty, non-NULL default
+  value led to an illegal choice error when none were selected.
+- Reorganized the testing framework to split setUp() into specific sub-methods
+  and fix several regressions in the process.
+- Fixed bug which made it impossible to search for strings that have not been
+  translated into a particular language.
+- Renamed the "Field" column on the Manage Fields screen to "Field type", since
+  the former was confusing and inaccurate (UI change).
+- Performance improvement: Removed needless call to system_rebuild_module_data()
+  in field_sync_field_status(), greatly speeding up bulk module enable/disable.
+- Fixed bug which prevented notifications from being sent when core, module, and
+  theme updates are available.
+- Fixed bug which prevented sub-themes from inheriting the default values of
+  theme settings defined by the base theme.
+- Fixed bug which prevented the jQuery UI Datepicker from being localized.
+- Made Ajax alert dialogs respect error reporting settings.
+- Fixed bug which prevented image styles from being deleted on PHP 5.4.
+- Fixed bug: Language detection by domain only worked on port 80.
+- Fixed regression: The first plural index on a page was not calculated
+  correctly.
+- Introduced generic entity language support. Entities may now declare their
+  language property in hook_entity_info(), and modules working with entities
+  may access the language using entity_language() (API change:
+  http://drupal.org/node/1626346).
+- Added EntityFieldQuery support for taxonomy bundles.
+- Fixed issue where field form structure was incomplete if field_access()
+  returned FALSE. Instead of being incomplete, the form structure now has
+  #access set to FALSE and field form validation is skipped (data structure
+  change: http://drupal.org/node/1663020).
+- Fixed data loss issue due to field_has_data() returning inconsistent results.
+  The fix adds an optional DANGEROUS_ACCESS_CHECK_OPT_OUT tag to entity field
+  queries which field storage engines can respond to (API addition:
+  http://drupal.org/node/1597378).
+- Fixed notice: Undefined index: default_image in image_field_prepare_view()
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.14, 2012-05-02
+-----------------------
+- Fixed "integrity constraint" fatal errors when rebuilding registry.
+- Fixed custom logo and favicon functionality referencing incorrect paths.
+- Fixed DB Case Sensitivity: Allow BINARY attribute in MySQL.
+- Split field_bundle_settings out per bundle.
+- Improve UX for machine names for fields (UI change).
+- Fixed User pictures are not removed properly.
+- Fixed HTTPS sessions not working in all cases.
+- Fixed Regression: Required radios throw illegal choice error when none
+  selected.
+- Fixed allow autocompletion requests to include slashes.
+- Eliminate $user->cache and {session}.cache in favor of
+  $_SESSION['cache_expiration'][$bin] (Performance).
+- Fixed focus jumps to tab when pressing enter on a form element within tab.
+- Fixed race condition in locale() - duplicates in {locales_source}.
+- Fixed Missing "Default image" per field instance.
+- Quit clobbering people's work when they click the filter tips link
+- Form API #states: Fix conditionals to allow OR and XOR constructions.
+- Fixed Focus jumps to tab when pressing enter on a form element within tab.
+  (Accessibility)
+- Improved performance of node_access queries.
+- Fixed Fieldsets inside vertical tabs have no title and can't be collapsed.
+- Reduce size of cache_menu table (Performance).
+- Fixed unnecessary aggregation of CSS/JS (Performance).
+- Fixed taxonomy_autocomplete() produces SQL error for nonexistent field.
+- Fixed HTML filter is not run first by default, despite default weight.
+- Fixed Overlay does not work with prefixed URL paths.
+- Better debug info for field errors (string change).
+- Fixed Data corruption in comment IDs (results in broken threading on
+  PostgreSQL).
+- Fixed machine name not editable if every character is replaced.
+- Fixed user picture not appearing in comment preview (Markup change).
+- Added optional vid argument for taxonomy_get_term_by_name().
+- Fixed Invalid Unicode code range in PREG_CLASS_UNICODE_WORD_BOUNDARY fails
+  with PCRE 8.30.
+- Fixed {trigger_assignments()}.hook has only 32 characters, is too short.
+- Numerous fixes to run-tests.sh.
+- Fixed Tests in profiles/[name]/modules cannot be run and cannot use a
+  different profile for running tests.
+- Numerous JavaScript performance fixes.
+- Numerous documentation fixes.
+- Fixed All pager links have an 'active' CSS class.
+- Numerous upgrade path fixes; notably:
+  - system_update_7061() fails on inserting files with same name but different
+    case.
+  - system_update_7061() converts filepaths too aggressively.
+  - Trigger upgrade path: Node triggers removed when upgrading to 7-x from 6.25.
+
+Drupal 7.13, 2012-05-02
+-----------------------
+- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-002.
+
+Drupal 7.12, 2012-02-01
+-----------------------
+- Fixed bug preventing custom menus from receiving an active trail.
+- Fixed hook_field_delete() no longer invoked during field_purge_data().
+- Fixed bug causing entity info cache to not be cleared with the rest of caches.
+- Fixed file_unmanaged_copy() fails with Drupal 7.7+ and safe_mode() or
+  open_basedir().
+- Fixed Nested transactions throw exceptions when they got out of scope.
+- Fixed bugs with the Return-Path when sending mail on both Windows and
+  non-Windows systems.
+- Fixed bug with DrupalCacheArray property visibility preventing others from
+  extending it (API change: http://drupal.org/node/1422264).
+- Fixed bug with handling of non-ASCII characters in file names (API change:
+  http://drupal.org/node/1424840).
+- Reconciled field maximum length with database column size in image and
+  aggregator modules.
+- Fixes to various core JavaScript files to allow for minification and
+  aggregation.
+- Fixed Prevent tests from deleting main installation's tables when
+  parent::setUp() is not called.
+- Fixed several Poll module bugs.
+- Fixed several Shortcut module bugs.
+- Added new hook_system_theme_info() to provide ability for contributed modules
+  to test theme functionality.
+- Added ability to cancel mail sending from hook_mail_alter().
+- Added support for configurable PDO connection options, enabling master-master
+  database replication.
+- Numerous improvements to tests and test runner to pave the way for faster test
+  runs.
+- Expanded test coverage.
+- Numerous API documentation improvements.
+- Numerous performance improvements, including token replacement and render
+  cache.
+
+Drupal 7.11, 2012-02-01
+-----------------------
+- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-001.
+
+Drupal 7.10, 2011-12-05
+-----------------------
+- Fixed Content-Language HTTP header to not cause issues with Drush 5.x.
+- Reduce memory usage of theme registry (performance).
+- Fixed PECL upload progress bar for FileField
+- Fixed running update.php doesn't always clear the cache.
+- Fixed PDO exceptions on long titles.
+- Fixed Overlay redirect does not include query string.
+- Fixed D6 modules satisfy D7 module dependencies.
+- Fixed the ordering of module hooks when using module_implements_alter().
+- Fixed "floating" submit buttons during AJAX requests.
+- Fixed timezone selected on install not propogating to admin account.
+- Added msgctx context to JS translation functions, for feature parity with t().
+- Profiles' .install files now available during hook_install_tasks().
+- Added test coverage of 7.0 -> 7.x upgrade path.
+- Numerous notice fixes.
+- Numerous documentation improvements.
+- Additional automated test coverage.
+
 Drupal 7.9, 2011-10-26
 ----------------------
 - Critical fixes to OpenID to spec violations that could allow for
@@ -149,8 +1059,8 @@
       order can now be customized using the Views module.
     * Removed the 'related terms' feature from taxonomy module since this can
       now be achieved with Field API.
-    * Added additional features to the default install profile, and implemented
-      a "slimmed down" install profile designed for developers.
+    * Added additional features to the default installation profile, and
+      implemented a "slimmed down" profile designed for developers.
     * Added a built-in, automated cron run feature, which is triggered by site
       visitors.
     * Added an administrator role which is assigned all permissions for
@@ -334,7 +1244,7 @@
       requests.
 
 Drupal 6.23-dev, xxxx-xx-xx (development release)
------------------------
+---------------------------
 
 Drupal 6.22, 2011-05-25
 -----------------------
@@ -344,25 +1254,25 @@
 - Fixed a variety of other bugs.
 
 Drupal 6.21, 2011-05-25
-----------------------
+-----------------------
 - Fixed security issues (Cross site scripting), see SA-CORE-2011-001.
 
 Drupal 6.20, 2010-12-15
-----------------------
+-----------------------
 - Fixed a variety of small bugs, improved code documentation.
 
 Drupal 6.19, 2010-08-11
-----------------------
+-----------------------
 - Fixed a variety of small bugs, improved code documentation.
 
 Drupal 6.18, 2010-08-11
-----------------------
+-----------------------
 - Fixed security issues (OpenID authentication bypass, File download access
   bypass, Comment unpublishing bypass, Actions cross site scripting),
   see SA-CORE-2010-002.
 
 Drupal 6.17, 2010-06-02
-----------------------
+-----------------------
 - Improved PostgreSQL compatibility
 - Better PHP 5.3 and PHP 4 compatibility
 - Better browser compatibility of CSS and JS aggregation
@@ -371,24 +1281,24 @@
 - Fixed a variety of other bugs.
 
 Drupal 6.16, 2010-03-03
-----------------------
+-----------------------
 - Fixed security issues (Installation cross site scripting, Open redirection,
   Locale module cross site scripting, Blocked user session regeneration),
   see SA-CORE-2010-001.
 - Better support for updated jQuery versions.
 - Reduced resource usage of update.module.
-- Fixed several issues relating to support of install profiles and
+- Fixed several issues relating to support of installation profiles and
   distributions.
 - Added a locking framework to avoid data corruption on long operations.
 - Fixed a variety of other bugs.
 
 Drupal 6.15, 2009-12-16
-----------------------
+-----------------------
 - Fixed security issues (Cross site scripting), see SA-CORE-2009-009.
 - Fixed a variety of other bugs.
 
 Drupal 6.14, 2009-09-16
-----------------------
+-----------------------
 - Fixed security issues (OpenID association cross site request forgeries,
   OpenID impersonation and File upload), see SA-CORE-2009-008.
 - Changed the system modules page to not run all cache rebuilds; use the
@@ -397,18 +1307,18 @@
 - Fixed a variety of small bugs.
 
 Drupal 6.13, 2009-07-01
-----------------------
+-----------------------
 - Fixed security issues (Cross site scripting, Input format access bypass and
   Password leakage in URL), see SA-CORE-2009-007.
 - Fixed a variety of small bugs.
 
 Drupal 6.12, 2009-05-13
-----------------------
+-----------------------
 - Fixed security issues (Cross site scripting), see SA-CORE-2009-006.
 - Fixed a variety of small bugs.
 
 Drupal 6.11, 2009-04-29
-----------------------
+-----------------------
 - Fixed security issues (Cross site scripting and limited information
   disclosure), see SA-CORE-2009-005
 - Fixed performance issues with the menu router cache, the update
@@ -416,7 +1326,7 @@
 - Fixed a variety of small bugs.
 
 Drupal 6.10, 2009-02-25
-----------------------
+-----------------------
 - Fixed a security issue, (Local file inclusion on Windows),
   see SA-CORE-2009-003
 - Fixed node_feed() so custom fields can show up in RSS feeds.
@@ -495,7 +1405,7 @@
    * Expands the severity levels from 3 (Error, Warning, Notice) to the 8
      levels defined in RFC 3164.
    * The watchdog module is now called dblog, and is optional, but enabled by
-     default in the default install profile.
+     default in the default installation profile.
    * Extended the database log module so log messages can be filtered.
    * Added syslog module: useful for monitoring large Drupal installations.
 - Added optional e-mail notifications when users are approved, blocked, or
@@ -550,7 +1460,7 @@
     * Themed the installer with the Garland theme.
     * Added form to provide initial site information during installation.
     * Added ability to provide extra installation steps programmatically.
-    * Made it possible to import interface translations at install time.
+    * Made it possible to import interface translations during installation.
 - Added the HTML corrector filter:
     * Fixes faulty and chopped off HTML in postings.
     * Tags are now automatically closed at the end of the teaser.
@@ -729,7 +1639,7 @@
 - Added web-based installer which can:
     * Check installation and run-time requirements
     * Automatically generate the database configuration file
-    * Install pre-made 'install profiles' or distributions
+    * Install pre-made installation profiles or distributions
     * Import the database structure with automatic table prefixing
     * Be localized
 - Added new default Garland theme
@@ -789,7 +1699,7 @@
 - Removed the archive module.
 - Upgrade system:
     * Created space for update branches.
-- Forms API:
+- Form API:
     * Made it possible to programmatically submit forms.
     * Improved api for multistep forms.
 - Theme system:
@@ -812,7 +1722,7 @@
 - fixed a security issue (SQL injection), see SA-2007-031
 
 Drupal 4.7.8, 2007-10-17
-----------------------
+------------------------
 - fixed a security issue (HTTP response splitting), see SA-2007-024
 - fixed a security issue (Cross site scripting via uploads), see SA-2007-026
 - fixed a security issue (API handling of unpublished comment), see SA-2007-030
@@ -925,7 +1835,7 @@
 - Fixed security issue (DoS), see SA-2007-002
 
 Drupal 4.6.10, 2006-10-18
-------------------------
+-------------------------
 - Fixed security issue (XSS), see SA-2006-024
 - Fixed security issue (CSRF), see SA-2006-025
 - Fixed security issue (Form action attribute injection), see SA-2006-026
diff -Naur drupal-7.9/COPYRIGHT.txt drupal-7.58/COPYRIGHT.txt
--- drupal-7.9/COPYRIGHT.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/COPYRIGHT.txt	2018-03-27 21:28:19.000000000 +0200
@@ -1,5 +1,4 @@
-
-All Drupal code is Copyright 2001 - 2010 by the original authors.
+All Drupal code is Copyright 2001 - 2013 by the original authors.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,5 +20,25 @@
 according to the terms of the GNU General Public License or a compatible
 license, including:
 
-  jQuery - Copyright (c) 2008 - 2009 John Resig
+Javascript
+
+  Farbtastic - Copyright (c) 2010 Matt Farina
+
+  jQuery - Copyright (c) 2010 John Resig
+
+  jQuery BBQ - Copyright (c) 2010 "Cowboy" Ben Alman
+
+  jQuery Cookie - Copyright (c) 2006 Klaus Hartl
+
+  jQuery Form - Copyright (c) 2010 Mike Alsup
+
+  jQuery Once - Copyright (c) 2009 Konstantin K�fer
+
+  jQuery UI - Copyright (c) 2010 by the original authors
+    (http://jqueryui.com/about)
+
+  Sizzle.js - Copyright (c) 2010 The Dojo Foundation (http://sizzlejs.com/)
+
+PHP
 
+  ArchiveTar - Copyright (c) 1997 - 2008 Vincent Blavet
diff -Naur drupal-7.9/INSTALL.mysql.txt drupal-7.58/INSTALL.mysql.txt
--- drupal-7.9/INSTALL.mysql.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/INSTALL.mysql.txt	2018-03-27 21:28:19.000000000 +0200
@@ -18,20 +18,23 @@
   mysql -u username -p
 
 Again, you will be asked for the 'username' database password. At the MySQL
-prompt, enter following command:
+prompt, enter the following command:
 
-  GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
-  ON databasename.*
+  GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
+  CREATE TEMPORARY TABLES ON databasename.*
   TO 'username'@'localhost' IDENTIFIED BY 'password';
 
-where
+where:
 
  'databasename' is the name of your database
- 'username@localhost' is the username of your MySQL account
+ 'username' is the username of your MySQL account
+ 'localhost' is the web server host where Drupal is installed
  'password' is the password required for that username
 
-Note: Unless your database user has all of the privileges listed above, you will
-not be able to run Drupal.
+Note: Unless the database user/host combination for your Drupal installation
+has all of the privileges listed above (except possibly CREATE TEMPORARY TABLES,
+which is currently only used by Drupal core automated tests and some
+contributed modules), you will not be able to install or run Drupal.
 
 If successful, MySQL will reply with:
 
diff -Naur drupal-7.9/INSTALL.txt drupal-7.58/INSTALL.txt
--- drupal-7.9/INSTALL.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/INSTALL.txt	2018-03-27 21:28:19.000000000 +0200
@@ -20,8 +20,10 @@
   - MySQL 5.0.15 (or greater) (http://www.mysql.com/).
   - MariaDB 5.1.44 (or greater) (http://mariadb.org/). MariaDB is a fully
     compatible drop-in replacement for MySQL.
+  - Percona Server 5.1.70 (or greater) (http://www.percona.com/). Percona
+    Server is a backwards-compatible replacement for MySQL.
   - PostgreSQL 8.3 (or greater) (http://www.postgresql.org/).
-  - SQLite 3.4.2 (or greater) (http://www.sqlite.org/).
+  - SQLite 3.3.7 (or greater) (http://www.sqlite.org/).
 
 For more detailed information about Drupal requirements, including a list of
 PHP extensions and configurations that are required, see "System requirements"
@@ -89,8 +91,8 @@
    - Download a translation file for the correct Drupal version and language
      from the translation server: http://localize.drupal.org/translate/downloads
 
-   - Place the file into your installation profile's translations
-     directory. For instance, if you are using the Standard install profile,
+   - Place the file into your installation profile's translations directory.
+     For instance, if you are using the Standard installation profile,
      move the .po file into the directory:
 
        profiles/standard/translations/
diff -Naur drupal-7.9/MAINTAINERS.txt drupal-7.58/MAINTAINERS.txt
--- drupal-7.9/MAINTAINERS.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/MAINTAINERS.txt	2018-03-27 21:28:19.000000000 +0200
@@ -1,147 +1,163 @@
 
-Drupal core is maintained by the community.  To participate, go to
-
-  http://drupal.org/contribute
-
-The people listed here have agreed to do more quality assurance work for
-particular areas of Drupal.  All of them are subject to change.
-
+Drupal core is built and maintained by the Drupal project community. Everyone is
+encouraged to submit issues and changes (patches) to improve Drupal, and to
+contribute in other ways -- see https://www.drupal.org/contribute to find out
+how.
 
 Branch maintainers
 ------------------
 
-Drupal 7
-- Dries Buytaert 'dries' <http://drupal.org/user/1>
-- Angela Byron 'webchick' <http://drupal.org/user/24967>
+The Drupal Core branch maintainers oversee the development of Drupal as a whole.
+The branch maintainers for Drupal 7 are:
+
+- Dries Buytaert 'dries' https://www.drupal.org/u/dries
+- Angela Byron 'webchick' https://www.drupal.org/u/webchick
+- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
+- Stefan Ruijsenaars 'stefan.r' https://www.drupal.org/u/stefanr-0
 
 
 Component maintainers
 ---------------------
 
+The Drupal Core component maintainers oversee the development of Drupal
+subsystems. See https://www.drupal.org/contribute/core-maintainers for more
+information on their responsibilities, and to find out how to become a component
+maintainer. Current component maintainers for Drupal 7:
+
 Ajax system
-- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
-- Randy Fay 'rfay' <http://drupal.org/user/30906>
-- Earl Miles 'merlinofchaos' <http://drupal.org/user/26979>
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Earl Miles 'merlinofchaos' https://www.drupal.org/u/merlinofchaos
 
 Base system
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
-- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
-- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
 
 Batch system
-- Yves Chedemois 'yched' <http://drupal.org/user/39567>
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
 
 Cache system
-- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
-- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
 
 Cron system
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
-- Derek Wright 'dww' <http://drupal.org/user/46549>
+- Derek Wright 'dww' https://www.drupal.org/u/dww
 
 Database system
-- Larry Garfield 'Crell' <http://drupal.org/user/26398>
+- Larry Garfield 'Crell' https://www.drupal.org/u/crell
 
   - MySQL driver
-    - Larry Garfield 'Crell' <http://drupal.org/user/26398>
-    - David Strauss 'David Strauss' <http://drupal.org/user/93254>
+    - Larry Garfield 'Crell' https://www.drupal.org/u/crell
+    - David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
 
   - PostgreSQL driver
-    - Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
-    - Josh Waihi 'fiasco' <http://drupal.org/user/188162>
+    - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+    - Josh Waihi 'fiasco' https://www.drupal.org/u/josh-waihi
 
   - Sqlite driver
-    - Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
-    - Károly Négyesi 'chx' <http://drupal.org/user/9446>
+    - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
 
 Database update system
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
+- Ashok Modi 'BTMash' https://www.drupal.org/u/btmash
 
 Entity system
-- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
-- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
+- Wolfgang Ziegler 'fago' https://www.drupal.org/u/fago
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
 
 File system
-- Andrew Morton 'drewish' <http://drupal.org/user/34869>
-- Aaron Winborn 'aaron' <http://drupal.org/user/33420>
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
 
 Form system
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
-- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
-- Wolfgang Ziegler 'fago' <http://drupal.org/user/16747>
-- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
-- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Wolfgang Ziegler 'fago' https://www.drupal.org/u/fago
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
 
 Image system
-- Andrew Morton 'drewish' <http://drupal.org/user/34869>
-- Nathan Haug 'quicksketch' <http://drupal.org/user/35821>
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
 
 Install system
-- David Rothstein 'David_Rothstein' <http://drupal.org/user/124982>
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
 
 JavaScript
-- ?
+- Théodore Biadala 'nod_' https://www.drupal.org/u/nod_
+- Steve De Jonghe 'seutje' https://www.drupal.org/u/seutje
 
 Language system
-- Francesco Placella 'plach' <http://drupal.org/user/183211>
-- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
 
 Lock system
-- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
 
 Mail system
 - ?
 
 Markup
-- Jacine Luisi 'Jacine' <http://drupal.org/user/88931>
-- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
+- Jacine Luisi 'Jacine' https://www.drupal.org/u/jacine
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
 
 Menu system
-- Peter Wolanin 'pwolanin' <http://drupal.org/user/49851>
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
 
 Path system
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
-- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
 
 Render system
-- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
-- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
-- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
 
 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>
+- Earl Miles 'merlinofchaos' https://www.drupal.org/u/merlinofchaos
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Joon Park 'dvessel' https://www.drupal.org/u/dvessel
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
 
 Token system
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
 
 XML-RPC system
-- Frederic G. Marand 'fgm' <http://drupal.org/user/27985>
+- Frederic G. Marand 'fgm' https://www.drupal.org/u/fgm
 
 
 Topic coordinators
 ------------------
 
 Accessibility
-- Everett Zufelt 'Everett Zufelt' <http://drupal.org/user/406552>
-- Brandon Bowersox 'brandonojc' <http://drupal.org/user/186415> 
+- Everett Zufelt 'Everett Zufelt' https://www.drupal.org/u/everett-zufelt
+- Brandon Bowersox-Johnson 'bowersox' https://www.drupal.org/u/bowersox
 
 Documentation
-- Ariane Khachatourians 'arianek' <http://drupal.org/user/158886>
-- Jennifer Hodgdon 'jhodgdon' <http://drupal.org/user/155601>
-
-Security
-- Heine Deelstra 'Heine' <http://drupal.org/user/17943>
+- Jennifer Hodgdon 'jhodgdon' https://www.drupal.org/u/jhodgdon
 
 Translations
-- Gerhard Killesreiter 'killes' <http://drupal.org/user/83>
+- Gerhard Killesreiter 'killes' https://www.drupal.org/u/gerhard-killesreiter
 
 User experience and usability
-- Roy Scholten 'yoroy' <http://drupal.org/user/41502>
-- Bojhan Somers 'Bojhan' <http://drupal.org/user/87969>
+- Roy Scholten 'yoroy' https://www.drupal.org/u/yoroy
+- Bojhan Somers 'Bojhan' https://www.drupal.org/u/bojhan
+
+Node Access
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- Ken Rickard 'agentrickard' https://www.drupal.org/u/agentrickard
+
+
+Security team
+-----------------
+
+To report a security issue, see: https://www.drupal.org/security-team/report-issue
+
+The Drupal security team provides Security Advisories for vulnerabilities,
+assists developers in resolving security issues, and provides security
+documentation. See https://www.drupal.org/security-team for more information.
+The security team lead is:
+
+- Michael Hess 'mlhess' https://www.drupal.org/u/mlhess
 
 
 Module maintainers
@@ -151,144 +167,141 @@
 - ?
 
 Block module
-- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
 
 Blog module
 - ?
 
 Book module
-- Peter Wolanin 'pwolanin' <http://drupal.org/user/49851>
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
 
 Color module
 - ?
 
 Comment module
-- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
 
 Contact module
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
 
 Contextual module
-- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
 
 Dashboard module
 - ?
 
 Database logging module
-- Khalid Baheyeldin 'kbahey' <http://drupal.org/user/4063>
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
 
 Field module
-- Yves Chedemois 'yched' <http://drupal.org/user/39567>
-- Barry Jaspan 'bjaspan' <http://drupal.org/user/46413>
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
+- Barry Jaspan 'bjaspan' https://www.drupal.org/u/bjaspan
 
 Field UI module
-- Yves Chedemois 'yched' <http://drupal.org/user/39567>
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
 
 File module
-- Aaron Winborn 'aaron' <http://drupal.org/user/33420>
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
 
 Filter module
-- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
 
 Forum module
-- Lee Rowlands 'larowlan' <http://drupal.org/user/395439>
+- Lee Rowlands 'larowlan' https://www.drupal.org/u/larowlan
 
 Help module
 - ?
 
 Image module
-- Nathan Haug 'quicksketch' <http://drupal.org/user/35821>
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
 
 Locale module
-- Gábor Hojtsy 'Gábor Hojtsy' <http://drupal.org/user/4166>
+- Gábor Hojtsy 'Gábor Hojtsy' https://www.drupal.org/u/gábor-hojtsy
 
 Menu module
 - ?
 
 Node module
-- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
-- David Strauss 'David Strauss' <http://drupal.org/user/93254>
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
 
 OpenID module
-- Vojtech Kusy 'wojtha' <http://drupal.org/user/56154>
-- Heine Deelstra 'Heine' <http://drupal.org/user/17943>
-- Christian Schmidt 'c960657' <http://drupal.org/user/216078>
-- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
+- Vojtech Kusy 'wojtha' https://www.drupal.org/u/wojtha
+- Christian Schmidt 'c960657' https://www.drupal.org/u/c960657
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
 
 Overlay module
-- Katherine Senzee 'ksenzee' <http://drupal.org/user/139855>
+- Katherine Senzee 'ksenzee' https://www.drupal.org/u/ksenzee
 
 Path module
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
 
 PHP module
 - ?
 
 Poll module
-- ?
+- Andrei Mateescu 'amateescu' https://www.drupal.org/u/amateescu
 
 Profile module
 - ?
 
 RDF module
-- Stéphane Corlosquet 'scor' <http://drupal.org/user/52142>
+- Stéphane Corlosquet 'scor' https://www.drupal.org/u/scor
 
 Search module
-- Doug Green 'douggreen' <http://drupal.org/user/29191>
+- Doug Green 'douggreen' https://www.drupal.org/u/douggreen
 
 Shortcut module
-- David Rothstein 'David_Rothstein' <http://drupal.org/user/124982>
-- Kristof De Jaeger 'swentel' <http://drupal.org/user/107403>
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
 
 Simpletest module
-- Jimmy Berry 'boombatower' <http://drupal.org/user/214218>
-- Károly Négyesi 'chx' <http://drupal.org/user/9446>
+- Jimmy Berry 'boombatower' https://www.drupal.org/u/boombatower
 
 Statistics module
-- Dave Reid 'davereid' <http://drupal.org/user/53892>
+- Tim Millwood 'timmillwood' https://www.drupal.org/u/timmillwood
 
 Syslog module
-- Khalid Baheyeldin 'kbahey' <http://drupal.org/user/4063>
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
 
 System module
 - ?
 
 Taxonomy module
-- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
-- Benjamin Doherty 'bangpound' <http://drupal.org/user/100456>
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Benjamin Doherty 'bangpound' https://www.drupal.org/u/bangpound
 
 Toolbar module
 - ?
 
 Tracker module
-- David Strauss 'David Strauss' <http://drupal.org/user/93254>
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
 
 Translation module
-- Francesco Placella 'plach' <http://drupal.org/user/183211>
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
 
 Trigger module
 - ?
 
 Update module
-- Derek Wright 'dww' <http://drupal.org/user/46549>
+- Derek Wright 'dww' https://www.drupal.org/u/dww
 
 User module
-- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
-- David Strauss 'David Strauss' <http://drupal.org/user/93254>
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
 
 
 Theme maintainers
 -----------------
 
 Bartik theme
-- Jen Simmons 'jensimmons' <http://drupal.org/user/140882>
-- Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
+- Jen Simmons 'jensimmons' https://www.drupal.org/u/jensimmons
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
 
 Garland theme
-- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
 
 Seven theme
-- Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
 
 Stark theme
-- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
diff -Naur drupal-7.9/README.txt drupal-7.58/README.txt
--- drupal-7.9/README.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/README.txt	2018-03-27 21:28:19.000000000 +0200
@@ -4,6 +4,7 @@
 
  * About Drupal
  * Configuration and features
+ * Installation profiles
  * Appearance
  * Developing for Drupal
 
@@ -43,6 +44,40 @@
    http://drupal.org/project/modules
  * See also: "Developing for Drupal" for writing your own modules, below.
 
+INSTALLATION PROFILES
+---------------------
+
+Installation profiles define additional steps (such as enabling modules,
+defining content types, etc.) that run after the base installation provided
+by core when Drupal is first installed. There are two basic installation
+profiles provided with Drupal core.
+
+Installation profiles from the Drupal community modify the installation process
+to provide a website for a specific use case, such as a CMS for media
+publishers, a web-based project tracking tool, or a full-fledged CRM for
+non-profit organizations raising money and accepting donations. They can be
+distributed as bare installation profiles or as "distributions". Distributions
+include Drupal core, the installation profile, and all other required
+extensions, such as contributed and custom modules, themes, and third-party
+libraries. Bare installation profiles require you to download Drupal Core and
+the required extensions separately; place the downloaded profile in the
+/profiles directory before you start the installation process. Note that the
+contents of this directory may be overwritten during updates of Drupal core;
+it is advised to keep code backups or use a version control system.
+
+Additionally, modules and themes may be placed inside subdirectories in a
+specific installation profile such as profiles/your_site_profile/modules and
+profiles/your_site_profile/themes respectively to restrict their usage to only
+sites that were installed with that specific profile.
+
+More about installation profiles and distributions:
+ * Read about the difference between installation profiles and distributions:
+   http://drupal.org/node/1089736
+ * Download contributed installation profiles and distributions:
+   http://drupal.org/project/distributions
+ * Develop your own installation profile or distribution:
+   http://drupal.org/developing/distributions
+
 APPEARANCE
 ----------
 
diff -Naur drupal-7.9/UPGRADE.txt drupal-7.58/UPGRADE.txt
--- drupal-7.9/UPGRADE.txt	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/UPGRADE.txt	2018-03-27 21:28:19.000000000 +0200
@@ -64,6 +64,9 @@
    Sometimes an update includes changes to default.settings.php (this will be
    noted in the release notes). If that's the case, follow these steps:
 
+   - Locate your settings.php file in the /sites/* directory. (Typically
+     sites/default.)
+
    - Make a backup copy of your settings.php file, with a different file name.
 
    - Make a copy of the new default.settings.php file, and name the copy
@@ -74,6 +77,13 @@
      database information, and you will also want to copy in any other
      customizations you have added.
 
+   You can find the release notes for your version at
+   https://www.drupal.org/project/drupal. At bottom of the project page under
+   "Downloads" use the link for your version of Drupal to view the release
+   notes. If your version is not listed, use the 'View all releases' link. From
+   this page you can scroll down or use the filter to find your version and its
+   release notes.
+
 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.
@@ -141,15 +151,19 @@
    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).
+3. In addition to updating to the latest available version of Drupal 6.x core,
+   you must also upgrade all of your contributed modules for Drupal to their
+   latest Drupal 6.x versions.
+
+4. Log in as user ID 1 (the site maintenance user).
 
-4. Go to Administer > Site configuration > Site maintenance. Select
+5. 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
+6. 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
+7. 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.
@@ -158,21 +172,21 @@
    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
+8. 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
+9. 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.
 
-9. If you uninstalled any modules, remove them from the sites/all/modules and
+10. If you uninstalled any modules, remove them from the sites/all/modules and
    other sites/*/modules directories. Leave other modules in place, even though
    they are incompatible with Drupal 7.x.
 
-10. Download the latest Drupal 7.x release from http://drupal.org to a
+11. 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.
 
@@ -191,14 +205,14 @@
    from http://drupal.org using your web browser, extract it, and then use an
    FTP client to upload the files to your web root.
 
-11. Re-apply any modifications to files such as .htaccess or robots.txt.
+12. Re-apply any modifications to files such as .htaccess or robots.txt.
 
-12. Make your settings.php file writeable, so that the update process can
+13. Make your settings.php file writeable, so that the update process can
    convert it to the format of Drupal 7.x. settings.php is usually located in
 
      sites/default/settings.php
 
-13. Run update.php by visiting http://www.example.com/update.php (replace
+14. Run update.php by visiting http://www.example.com/update.php (replace
    www.example.com with your domain name). This will update the core database
    tables.
 
@@ -214,17 +228,17 @@
 
    - Once the upgrade is done, $update_free_access must be reverted to FALSE.
 
-14. Backup your database after the core upgrade has run.
+15. Backup your database after the core upgrade has run.
 
-15. Replace and update your non-core modules and themes, following the
+16. Replace and update your non-core modules and themes, following the
    procedures at http://drupal.org/node/948216
 
-16. Go to Administration > Reports > Status report. Verify that everything is
+17. Go to Administration > Reports > Status report. Verify that everything is
    working as expected.
 
-17. Ensure that $update_free_access is FALSE in settings.php.
+18. Ensure that $update_free_access is FALSE in settings.php.
 
-18. Go to Administration > Configuration > Development > Maintenance mode.
+19. Go to Administration > Configuration > Development > Maintenance mode.
    Disable the "Put site into maintenance mode" checkbox and save the
    configuration.
 
diff -Naur drupal-7.9/authorize.php drupal-7.58/authorize.php
--- drupal-7.9/authorize.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/authorize.php	2018-03-27 21:28:19.000000000 +0200
@@ -4,16 +4,16 @@
  * @file
  * Administrative script for running authorized file operations.
  *
- * Using this script, the site owner (the user actually owning the files on
- * the webserver) can authorize certain file-related operations to proceed
- * with elevated privileges, for example to deploy and upgrade modules or
- * themes. Users should not visit this page directly, but instead use an
- * administrative user interface which knows how to redirect the user to this
- * script as part of a multistep process. This script actually performs the
- * selected operations without loading all of Drupal, to be able to more
- * gracefully recover from errors. Access to the script is controlled by a
- * global killswitch in settings.php ('allow_authorize_operations') and via
- * the 'administer software updates' permission.
+ * Using this script, the site owner (the user actually owning the files on the
+ * webserver) can authorize certain file-related operations to proceed with
+ * elevated privileges, for example to deploy and upgrade modules or themes.
+ * Users should not visit this page directly, but instead use an administrative
+ * user interface which knows how to redirect the user to this script as part of
+ * a multistep process. This script actually performs the selected operations
+ * without loading all of Drupal, to be able to more gracefully recover from
+ * errors. Access to the script is controlled by a global killswitch in
+ * settings.php ('allow_authorize_operations') and via the 'administer software
+ * updates' permission.
  *
  * There are helper functions for setting up an operation to run via this
  * system in modules/system/system.module. For more information, see:
@@ -21,16 +21,17 @@
  */
 
 /**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
  */
 define('DRUPAL_ROOT', getcwd());
 
 /**
- * Global flag to identify update.php and authorize.php runs, and so
- * avoid various unwanted operations, such as hook_init() and
- * hook_exit() invokes, css/js preprocessing and translation, and
- * solve some theming issues. This flag is checked on several places
- * in Drupal code (not just authorize.php).
+ * Global flag to identify update.php and authorize.php runs.
+ *
+ * Identifies update.php and authorize.php runs, avoiding unwanted operations
+ * such as hook_init() and hook_exit() invokes, css/js preprocessing and
+ * translation, and solves some theming issues. The flag is checked in other
+ * places in Drupal code (not just authorize.php).
  */
 define('MAINTENANCE_MODE', 'update');
 
@@ -51,7 +52,7 @@
  * have access to the 'administer software updates' permission.
  *
  * @return
- *   TRUE if the current user can run authorize.php, otherwise FALSE.
+ *   TRUE if the current user can run authorize.php, and FALSE if not.
  */
 function authorize_access_allowed() {
   return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
@@ -60,7 +61,6 @@
 // *** Real work of the script begins here. ***
 
 require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-require_once DRUPAL_ROOT . '/includes/session.inc';
 require_once DRUPAL_ROOT . '/includes/common.inc';
 require_once DRUPAL_ROOT . '/includes/file.inc';
 require_once DRUPAL_ROOT . '/includes/module.inc';
diff -Naur drupal-7.9/includes/actions.inc drupal-7.58/includes/actions.inc
--- drupal-7.9/includes/actions.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/actions.inc	2018-03-27 21:28:19.000000000 +0200
@@ -22,7 +22,7 @@
  * - $a1, $a2: Optional additional information, which can be passed into
  *   actions_do() and will be passed along to the action function.
  *
- * @} End of "defgroup actions".
+ * @}
  */
 
 /**
@@ -48,6 +48,7 @@
  *   Passed along to the callback.
  * @param $a2
  *   Passed along to the callback.
+ *
  * @return
  *   An associative array containing the results of the functions that
  *   perform the actions, keyed on action ID.
@@ -149,6 +150,7 @@
  *
  * @param $reset
  *   Reset the action info static cache.
+ *
  * @return
  *   An associative array keyed on action function name, with the same format
  *   as the return value of hook_action_info(), containing all
@@ -176,9 +178,9 @@
  * function and the actions returned by actions_list() are partially
  * synchronized. Non-configurable actions from hook_action_info()
  * implementations are put into the database when actions_synchronize() is
- * called, which happens when admin/config/system/actions is visited. Configurable
- * actions are not added to the database until they are configured in the
- * user interface, in which case a database row is created for each
+ * called, which happens when admin/config/system/actions is visited.
+ * Configurable actions are not added to the database until they are configured
+ * in the user interface, in which case a database row is created for each
  * configuration of each action.
  *
  * @return
@@ -205,6 +207,7 @@
  *   An associative array with function names or action IDs as keys
  *   and associative arrays with keys 'label', 'type', etc. as values.
  *   This is usually the output of actions_list() or actions_get_all_actions().
+ *
  * @return
  *   An associative array whose keys are hashes of the input array keys, and
  *   whose corresponding values are associative arrays with components
@@ -223,7 +226,7 @@
 }
 
 /**
- * Given a hash of an action array key, returns the key (function or ID).
+ * Returns an action array key (function or ID), given its hash.
  *
  * Faster than actions_actions_map() when you only need the function name or ID.
  *
@@ -231,6 +234,7 @@
  *   Hash of a function name or action ID array key. The array key
  *   is a key into the return value of actions_list() (array key is the action
  *   function name) or actions_get_all_actions() (array key is the action ID).
+ *
  * @return
  *   The corresponding array key, or FALSE if no match is found.
  */
@@ -332,6 +336,7 @@
  *   to Jim'.
  * @param $aid
  *   The ID of this action. If omitted, a new action is created.
+ *
  * @return
  *   The ID of the action.
  */
@@ -361,6 +366,7 @@
  *
  * @param $aid
  *   The ID of the action to retrieve.
+ *
  * @return
  *   The appropriate action row from the database as an object.
  */
@@ -380,4 +386,3 @@
     ->execute();
   module_invoke_all('actions_delete', $aid);
 }
-
diff -Naur drupal-7.9/includes/ajax.inc drupal-7.58/includes/ajax.inc
--- drupal-7.9/includes/ajax.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/ajax.inc	2018-03-27 21:28:19.000000000 +0200
@@ -24,7 +24,8 @@
  * ajax_form_callback() and a defined #ajax['callback'] function.
  * However, you may optionally specify a different path to request or a
  * different callback function to invoke, which can return updated HTML or can
- * also return a richer set of @link ajax_commands Ajax framework commands @endlink.
+ * also return a richer set of
+ * @link ajax_commands Ajax framework commands @endlink.
  *
  * Standard form handling is as follows:
  *   - A form element has a #ajax property that includes #ajax['callback'] and
@@ -101,7 +102,7 @@
  * In the above example, the 'changethis' element is Ajax-enabled. The default
  * #ajax['event'] is 'change', so when the 'changethis' element changes,
  * an Ajax call is made. The form is submitted and reprocessed, and then the
- * callback is called.  In this case, the form has been automatically
+ * callback is called. In this case, the form has been automatically
  * built changing $form['replace_textfield']['#description'], so the callback
  * just returns that part of the form.
  *
@@ -167,7 +168,7 @@
  *   displayed while awaiting a response from the callback, and add an optional
  *   message. Possible keys: 'type', 'message', 'url', 'interval'.
  *   More information is available in the
- *   @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7 Form API Reference @endlink
+ *   @link forms_api_reference.html Form API Reference @endlink
  *
  * In addition to using Form API for doing in-form modification, Ajax may be
  * enabled by adding classes to buttons and links. By adding the 'use-ajax'
@@ -188,11 +189,11 @@
  * be converted to a JSON object and returned to the client, which will then
  * iterate over the array and process it like a macro language.
  *
- * Each command item is an associative array which will be converted to a command
- * object on the JavaScript side. $command_item['command'] is the type of
- * command, e.g. 'alert' or 'replace', and will correspond to a method in the
- * Drupal.ajax[command] space. The command array may contain any other data
- * that the command needs to process, e.g. 'method', 'selector', 'settings', etc.
+ * Each command item is an associative array which will be converted to a
+ * command object on the JavaScript side. $command_item['command'] is the type
+ * of command, e.g. 'alert' or 'replace', and will correspond to a method in the
+ * Drupal.ajax[command] space. The command array may contain any other data that
+ * the command needs to process, e.g. 'method', 'selector', 'settings', etc.
  *
  * Commands are usually created with a couple of helper functions, so they
  * look like this:
@@ -210,7 +211,7 @@
  *
  * When returning an Ajax command array, it is often useful to have
  * status messages rendered along with other tasks in the command array.
- * In that case the the Ajax commands array may be constructed like this:
+ * In that case the Ajax commands array may be constructed like this:
  * @code
  *   $commands = array();
  *   $commands[] = ajax_command_replace(NULL, $output);
@@ -222,13 +223,17 @@
  */
 
 /**
- * Render a commands array into JSON.
+ * Renders a commands array into JSON.
  *
  * @param $commands
  *   A list of macro commands generated by the use of ajax_command_*()
  *   functions.
  */
 function ajax_render($commands = array()) {
+  // Although ajax_deliver() does this, some contributed and custom modules
+  // render Ajax responses without using that delivery callback.
+  ajax_set_verification_header();
+
   // Ajax responses aren't rendered with html.tpl.php, so we have to call
   // drupal_get_css() and drupal_get_js() here, in order to have new files added
   // during this request to be loaded by the page. We only want to send back
@@ -250,8 +255,8 @@
       //   reliably diffed with array_diff_key(), since the number can change
       //   due to factors unrelated to the inline content, so for now, we strip
       //   the inline items from Ajax responses, and can add support for them
-      //   when drupal_add_css() and drupal_add_js() are changed to using md5()
-      //   or some other hash of the inline content.
+      //   when drupal_add_css() and drupal_add_js() are changed to use a hash
+      //   of the inline content as the array key.
       foreach ($items[$type] as $key => $item) {
         if (is_numeric($key)) {
           unset($items[$type][$key]);
@@ -262,26 +267,20 @@
     }
   }
 
-  // Settings are handled separately, later in this function, so that changes to
-  // the ajaxPageState setting that occur during drupal_get_css() and
-  // drupal_get_js() get included, and because the jQuery.extend() code produced
-  // by drupal_get_js() for adding settings isn't appropriate during an Ajax
-  // response, because it does not pass TRUE for the "deep" parameter, and
-  // therefore, can clobber existing settings on the page.
+  // Render the HTML to load these files, and add AJAX commands to insert this
+  // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the
+  // data from being altered again, as we already altered it above. Settings are
+  // handled separately, afterwards.
   if (isset($items['js']['settings'])) {
     unset($items['js']['settings']);
   }
-
-  // Render the HTML to load these files, and add Ajax commands to insert this
-  // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the
-  // data from being altered again, as we already altered it above.
   $styles = drupal_get_css($items['css'], TRUE);
   $scripts_footer = drupal_get_js('footer', $items['js'], TRUE);
   $scripts_header = drupal_get_js('header', $items['js'], TRUE);
 
   $extra_commands = array();
   if (!empty($styles)) {
-    $extra_commands[] = ajax_command_prepend('head', $styles);
+    $extra_commands[] = ajax_command_add_css($styles);
   }
   if (!empty($scripts_header)) {
     $extra_commands[] = ajax_command_prepend('head', $scripts_header);
@@ -293,12 +292,11 @@
     $commands = array_merge($extra_commands, $commands);
   }
 
+  // Now add a command to merge changes and additions to Drupal.settings.
   $scripts = drupal_add_js();
   if (!empty($scripts['settings'])) {
     $settings = $scripts['settings'];
-    // Automatically extract any settings added via drupal_add_js() and make
-    // them the first command.
-    array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
+    array_unshift($commands, ajax_command_settings(drupal_array_merge_deep_array($settings['data']), TRUE));
   }
 
   // Allow modules to alter any Ajax response.
@@ -308,16 +306,17 @@
 }
 
 /**
- * Get a form submitted via #ajax during an Ajax callback.
+ * Gets a form submitted via #ajax during an Ajax callback.
  *
  * This will load a form from the form cache used during Ajax operations. It
  * pulls the form info from $_POST.
  *
  * @return
- *   An array containing the $form and $form_state. Use the list() function
- *   to break these apart:
+ *   An array containing the $form, $form_state, $form_id, $form_build_id and an
+ *   initial list of Ajax $commands. Use the list() function to break these
+ *   apart:
  *   @code
- *     list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
+ *     list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
  *   @endcode
  */
 function ajax_get_form() {
@@ -337,6 +336,17 @@
     drupal_exit();
   }
 
+  // When a page level cache is enabled, the form-build id might have been
+  // replaced from within form_get_cache. If this is the case, it is also
+  // necessary to update it in the browser by issuing an appropriate Ajax
+  // command.
+  $commands = array();
+  if (isset($form['#build_id_old']) && $form['#build_id_old'] != $form['#build_id']) {
+    // If the form build ID has changed, issue an Ajax command to update it.
+    $commands[] = ajax_command_update_build_id($form);
+    $form_build_id = $form['#build_id'];
+  }
+
   // Since some of the submit handlers are run, redirects need to be disabled.
   $form_state['no_redirect'] = TRUE;
 
@@ -351,7 +361,7 @@
   $form_state['input'] = $_POST;
   $form_id = $form['#form_id'];
 
-  return array($form, $form_state, $form_id, $form_build_id);
+  return array($form, $form_state, $form_id, $form_build_id, $commands);
 }
 
 /**
@@ -368,9 +378,11 @@
  * #ajax['path']. If processing is required that cannot be accomplished with
  * a callback, re-implement this function and set #ajax['path'] to the
  * enhanced function.
+ *
+ * @see system_menu()
  */
 function ajax_form_callback() {
-  list($form, $form_state) = ajax_get_form();
+  list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
   drupal_process_form($form['#form_id'], $form, $form_state);
 
   // We need to return the part of the form (or some other content) that needs
@@ -382,8 +394,20 @@
   if (!empty($form_state['triggering_element'])) {
     $callback = $form_state['triggering_element']['#ajax']['callback'];
   }
-  if (!empty($callback) && function_exists($callback)) {
-    return $callback($form, $form_state);
+  if (!empty($callback) && is_callable($callback)) {
+    $result = $callback($form, $form_state);
+
+    if (!(is_array($result) && isset($result['#type']) && $result['#type'] == 'ajax')) {
+      // Turn the response into a #type=ajax array if it isn't one already.
+      $result = array(
+        '#type' => 'ajax',
+        '#commands' => ajax_prepare_response($result),
+      );
+    }
+
+    $result['#commands'] = array_merge($commands, $result['#commands']);
+
+    return $result;
   }
 }
 
@@ -403,6 +427,9 @@
  * of the page. Therefore, system_menu() sets the 'theme callback' for
  * 'system/ajax' to this function, and it is recommended that modules
  * implementing other generic Ajax paths do the same.
+ *
+ * @see system_menu()
+ * @see file_menu()
  */
 function ajax_base_page_theme() {
   if (!empty($_POST['ajax_page_state']['theme']) && !empty($_POST['ajax_page_state']['theme_token'])) {
@@ -421,7 +448,7 @@
 }
 
 /**
- * Package and send the result of a page callback to the browser as an Ajax response.
+ * Packages and sends the result of a page callback as an Ajax response.
  *
  * This function is the equivalent of drupal_deliver_html_page(), but for Ajax
  * requests. Like that function, it:
@@ -464,6 +491,9 @@
     }
   }
 
+  // Let ajax.js know that this response is safe to process.
+  ajax_set_verification_header();
+
   // Print the response.
   $commands = ajax_prepare_response($page_callback_result);
   $json = ajax_render($commands);
@@ -554,7 +584,30 @@
 }
 
 /**
- * Perform end-of-Ajax-request tasks.
+ * Sets a response header for ajax.js to trust the response body.
+ *
+ * It is not safe to invoke Ajax commands within user-uploaded files, so this
+ * header protects against those being invoked.
+ *
+ * @see Drupal.ajax.options.success()
+ */
+function ajax_set_verification_header() {
+  $added = &drupal_static(__FUNCTION__);
+
+  // User-uploaded files cannot set any response headers, so a custom header is
+  // used to indicate to ajax.js that this response is safe. Note that most
+  // Ajax requests bound using the Form API will be protected by having the URL
+  // flagged as trusted in Drupal.settings, so this header is used only for
+  // things like custom markup that gets Ajax behaviors attached.
+  if (empty($added)) {
+    drupal_add_http_header('X-Drupal-Ajax-Token', '1');
+    // Avoid sending the header twice.
+    $added = TRUE;
+  }
+}
+
+/**
+ * Performs end-of-Ajax-request tasks.
  *
  * This function is the equivalent of drupal_page_footer(), but for Ajax
  * requests.
@@ -577,7 +630,7 @@
 }
 
 /**
- * Form element process callback to handle #ajax.
+ * Form element processing handler for the #ajax form property.
  *
  * @param $element
  *   An associative array containing the properties of the element.
@@ -596,7 +649,7 @@
 }
 
 /**
- * Add Ajax information about an element to the page to communicate with JavaScript.
+ * Adds Ajax information about an element to communicate with JavaScript.
  *
  * If #ajax['path'] is set on an element, this additional JavaScript is added
  * to the page header to attach the Ajax behaviors. See ajax.js for more
@@ -741,7 +794,12 @@
 
     $element['#attached']['js'][] = array(
       'type' => 'setting',
-      'data' => array('ajax' => array($element['#id'] => $settings)),
+      'data' => array(
+        'ajax' => array($element['#id'] => $settings),
+        'urlIsAjaxTrusted' => array(
+          $settings['url'] => TRUE,
+        ),
+      ),
     );
 
     // Indicate that Ajax processing was successful.
@@ -837,7 +895,8 @@
  * @return
  *   An array suitable for use with the ajax_render() function.
  *
- * See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
+ * See
+ * @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
  */
 function ajax_command_replace($selector, $html, $settings = NULL) {
   return array(
@@ -1211,3 +1270,48 @@
   );
 }
 
+/**
+ * Creates a Drupal Ajax 'update_build_id' command.
+ *
+ * This command updates the value of a hidden form_build_id input element on a
+ * form. It requires the form passed in to have keys for both the old build ID
+ * in #build_id_old and the new build ID in #build_id.
+ *
+ * The primary use case for this Ajax command is to serve a new build ID to a
+ * form served from the cache to an anonymous user, preventing one anonymous
+ * user from accessing the form state of another anonymous users on Ajax enabled
+ * forms.
+ *
+ * @param $form
+ *   The form array representing the form whose build ID should be updated.
+ */
+function ajax_command_update_build_id($form) {
+  return array(
+    'command' => 'updateBuildId',
+    'old' => $form['#build_id_old'],
+    'new' => $form['#build_id'],
+  );
+}
+
+/**
+ * Creates a Drupal Ajax 'add_css' command.
+ *
+ * This method will add css via ajax in a cross-browser compatible way.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.add_css()
+ * defined in misc/ajax.js.
+ *
+ * @param $styles
+ *   A string that contains the styles to be added.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ *
+ * @see misc/ajax.js
+ */
+function ajax_command_add_css($styles) {
+  return array(
+    'command' => 'add_css',
+    'data' => $styles,
+  );
+}
diff -Naur drupal-7.9/includes/archiver.inc drupal-7.58/includes/archiver.inc
--- drupal-7.9/includes/archiver.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/archiver.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,61 +6,63 @@
  */
 
 /**
- * Common interface for all Archiver classes.
+ * Defines the common interface for all Archiver classes.
  */
 interface ArchiverInterface {
 
   /**
-   * Constructor for a new archiver instance.
+   * Constructs a new archiver instance.
    *
    * @param $file_path
-   *   The full system path of the archive to manipulate.  Only local files
-   *   are supported.  If the file does not yet exist, it will be created if
+   *   The full system path of the archive to manipulate. Only local files
+   *   are supported. If the file does not yet exist, it will be created if
    *   appropriate.
    */
   public function __construct($file_path);
 
   /**
-   * Add the specified file or directory to the archive.
+   * Adds the specified file or directory to the archive.
    *
    * @param $file_path
    *   The full system path of the file or directory to add. Only local files
    *   and directories are supported.
+   *
    * @return ArchiverInterface
    *   The called object.
    */
   public function add($file_path);
 
   /**
-   * Remove the specified file from the archive.
+   * Removes the specified file from the archive.
    *
    * @param $path
    *   The file name relative to the root of the archive to remove.
+   *
    * @return ArchiverInterface
    *   The called object.
    */
   public function remove($path);
 
   /**
-   * Extract multiple files in the archive to the specified path.
+   * Extracts multiple files in the archive to the specified path.
    *
    * @param $path
    *   A full system path of the directory to which to extract files.
    * @param $files
    *   Optionally specify a list of files to be extracted. Files are
    *   relative to the root of the archive. If not specified, all files
-   *   in the archive will be extracted
+   *   in the archive will be extracted.
+   *
    * @return ArchiverInterface
    *   The called object.
    */
-  public function extract($path, Array $files = array());
+  public function extract($path, array $files = array());
 
   /**
-   * List all files in the archive.
+   * Lists all files in the archive.
    *
    * @return
    *   An array of file names relative to the root of the archive.
    */
   public function listContents();
 }
-
diff -Naur drupal-7.9/includes/authorize.inc drupal-7.58/includes/authorize.inc
--- drupal-7.9/includes/authorize.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/authorize.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,13 +6,19 @@
  */
 
 /**
- * Build the form for choosing a FileTransfer type and supplying credentials.
+ * Form constructor for the file transfer authorization form.
+ *
+ * Allows the user to choose a FileTransfer type and supply credentials.
+ *
+ * @see authorize_filetransfer_form_validate()
+ * @see authorize_filetransfer_form_submit()
+ * @ingroup forms
  */
 function authorize_filetransfer_form($form, &$form_state) {
   global $base_url, $is_https;
   $form = array();
 
-  // If possible, we want to post this form securely via https.
+  // If possible, we want to post this form securely via HTTPS.
   $form['#https'] = TRUE;
 
   // CSS we depend on lives in modules/system/maintenance.css, which is loaded
@@ -127,10 +133,11 @@
 }
 
 /**
- * Generate the Form API array for the settings for a given connection backend.
+ * Generates the Form API array for a given connection backend's settings.
  *
  * @param $backend
  *   The name of the backend (e.g. 'ftp', 'ssh', etc).
+ *
  * @return
  *   Form API array of connection settings for the given backend.
  *
@@ -151,7 +158,7 @@
 }
 
 /**
- * Recursively fill in the default settings on a file transfer connection form.
+ * Sets the default settings on a file transfer connection form recursively.
  *
  * 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
@@ -165,8 +172,6 @@
  *   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
@@ -186,9 +191,10 @@
 }
 
 /**
- * Validate callback for the filetransfer authorization form.
+ * Form validation handler for authorize_filetransfer_form().
  *
  * @see authorize_filetransfer_form()
+ * @see authorize_filetransfer_submit()
  */
 function authorize_filetransfer_form_validate($form, &$form_state) {
   // Only validate the form if we have collected all of the user input and are
@@ -218,9 +224,10 @@
 }
 
 /**
- * Submit callback when a file transfer is being authorized.
+ * Form submission handler for authorize_filetransfer_form().
  *
  * @see authorize_filetransfer_form()
+ * @see authorize_filetransfer_validate()
  */
 function authorize_filetransfer_form_submit($form, &$form_state) {
   global $base_url;
@@ -280,7 +287,7 @@
 }
 
 /**
- * Run the operation specified in $_SESSION['authorize_operation']
+ * Runs the operation specified in $_SESSION['authorize_operation'].
  *
  * @param $filetransfer
  *   The FileTransfer object to use for running the operation.
@@ -298,12 +305,13 @@
 }
 
 /**
- * Get a FileTransfer class for a specific transfer method and settings.
+ * Gets a FileTransfer class for a specific transfer method and settings.
  *
  * @param $backend
  *   The FileTransfer backend to get the class for.
  * @param $settings
  *   Array of settings for the FileTransfer.
+ *
  * @return
  *   An instantiated FileTransfer object for the requested method and settings,
  *   or FALSE if there was an error finding or instantiating it.
diff -Naur drupal-7.9/includes/batch.inc drupal-7.58/includes/batch.inc
--- drupal-7.9/includes/batch.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/batch.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  * Batch processing API for processes to run in multiple HTTP requests.
@@ -21,6 +20,7 @@
  * @param $id
  *   The ID of the batch to load. When a progressive batch is being processed,
  *   the relevant ID is found in $_REQUEST['id'].
+ *
  * @return
  *   An array representing the batch, or FALSE if no batch was found.
  */
@@ -36,7 +36,7 @@
 }
 
 /**
- * State-based dispatcher for the batch processing page.
+ * Renders the batch processing page based on the current state of the batch.
  *
  * @see _batch_shutdown()
  */
@@ -94,7 +94,7 @@
 }
 
 /**
- * Initialize the batch processing.
+ * Initializes the batch processing.
  *
  * JavaScript-enabled clients are identified by the 'has_js' cookie set in
  * drupal.js. If no JavaScript-enabled page has been visited during the current
@@ -110,7 +110,7 @@
 }
 
 /**
- * Output a batch processing page with JavaScript support.
+ * Outputs a batch processing page with JavaScript support.
  *
  * This initializes the batch and error messages. Note that in JavaScript-based
  * processing, the batch processing page is displayed only once and updated via
@@ -144,7 +144,7 @@
 }
 
 /**
- * Do one execution pass in JavaScript-mode and return progress to the browser.
+ * Does one execution pass with JavaScript and returns progress to the browser.
  *
  * @see _batch_progress_page_js()
  * @see _batch_process()
@@ -164,7 +164,7 @@
 }
 
 /**
- * Output a batch processing page without JavaScript support.
+ * Outputs a batch processing page without JavaScript support.
  *
  * @see _batch_process()
  */
@@ -228,7 +228,7 @@
 }
 
 /**
- * Process sets in a batch.
+ * Processes sets in a batch.
  *
  * If the batch was marked for progressive execution (default), this executes as
  * many operations in batch sets until an execution time of 1 second has been
@@ -370,7 +370,7 @@
 }
 
 /**
- * Helper function for _batch_process(): returns the formatted percentage.
+ * Formats the percent completion for a batch set.
  *
  * @param $total
  *   The total number of operations.
@@ -379,11 +379,14 @@
  *   rather than an integer in the case of a multi-step operation that is not
  *   yet complete; in that case, the fractional part of $current represents the
  *   fraction of the operation that has been completed.
+ *
  * @return
  *   The properly formatted percentage, as a string. We output percentages
  *   using the correct number of decimal places so that we never print "100%"
  *   until we are finished, but we also never print more decimal places than
  *   are meaningful.
+ *
+ * @see _batch_process()
  */
 function _batch_api_percentage($total, $current) {
   if (!$total || $total == $current) {
@@ -410,7 +413,7 @@
 }
 
 /**
- * Return the batch set being currently processed.
+ * Returns the batch set being currently processed.
  */
 function &_batch_current_set() {
   $batch = &batch_get();
@@ -418,7 +421,7 @@
 }
 
 /**
- * Retrieve the next set in a batch.
+ * Retrieves the next set in a batch.
  *
  * If there is a subsequent set in this batch, assign it as the new set to
  * process and execute its form submit handler (if defined), which may add
@@ -442,7 +445,7 @@
 }
 
 /**
- * End the batch processing.
+ * Ends the batch processing.
  *
  * Call the 'finished' callback of each batch set to allow custom handling of
  * the results and resolve page redirection.
@@ -457,10 +460,10 @@
       if (isset($batch_set['file']) && is_file($batch_set['file'])) {
         include_once DRUPAL_ROOT . '/' . $batch_set['file'];
       }
-      if (function_exists($batch_set['finished'])) {
+      if (is_callable($batch_set['finished'])) {
         $queue = _batch_queue($batch_set);
         $operations = $queue->getAllItems();
-        $batch_set['finished']($batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
+        call_user_func($batch_set['finished'], $batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
       }
     }
   }
@@ -521,7 +524,10 @@
 }
 
 /**
- * Shutdown function; store the current batch data for the next request.
+ * Shutdown function: Stores the current batch data for the next request.
+ *
+ * @see _batch_page()
+ * @see drupal_register_shutdown_function()
  */
 function _batch_shutdown() {
   if ($batch = batch_get()) {
@@ -531,4 +537,3 @@
       ->execute();
   }
 }
-
diff -Naur drupal-7.9/includes/batch.queue.inc drupal-7.58/includes/batch.queue.inc
--- drupal-7.9/includes/batch.queue.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/batch.queue.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,24 +1,30 @@
 <?php
 
-
 /**
  * @file
  * Queue handlers used by the Batch API.
  *
- * Those implementations:
- * - ensure FIFO ordering,
- * - let an item be repeatedly claimed until it is actually deleted (no notion
- *   of lease time or 'expire' date), to allow multipass operations.
+ * These implementations:
+ * - Ensure FIFO ordering.
+ * - Allow an item to be repeatedly claimed until it is actually deleted (no
+ *   notion of lease time or 'expire' date), to allow multipass operations.
  */
 
 /**
- * Batch queue implementation.
+ * Defines a batch queue.
  *
  * Stale items from failed batches are cleaned from the {queue} table on cron
  * using the 'created' date.
  */
 class BatchQueue extends SystemQueue {
 
+  /**
+   * Overrides SystemQueue::claimItem().
+   *
+   * Unlike SystemQueue::claimItem(), this method provides a default lease
+   * time of 0 (no expiration) instead of 30. This allows the item to be
+   * claimed repeatedly until it is deleted.
+   */
   public function claimItem($lease_time = 0) {
     $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) {
@@ -29,9 +35,9 @@
   }
 
   /**
-   * Retrieve all remaining items in the queue.
+   * Retrieves all remaining items in the queue.
    *
-   * This is specific to Batch API and is not part of the DrupalQueueInterface,
+   * This is specific to Batch API and is not part of the DrupalQueueInterface.
    */
   public function getAllItems() {
     $result = array();
@@ -44,10 +50,17 @@
 }
 
 /**
- * Batch queue implementation used for non-progressive batches.
+ * Defines a batch queue for non-progressive batches.
  */
 class BatchMemoryQueue extends MemoryQueue {
 
+  /**
+   * Overrides MemoryQueue::claimItem().
+   *
+   * Unlike MemoryQueue::claimItem(), this method provides a default lease
+   * time of 0 (no expiration) instead of 30. This allows the item to be
+   * claimed repeatedly until it is deleted.
+   */
   public function claimItem($lease_time = 0) {
     if (!empty($this->queue)) {
       reset($this->queue);
@@ -57,9 +70,9 @@
   }
 
   /**
-   * Retrieve all remaining items in the queue.
+   * Retrieves all remaining items in the queue.
    *
-   * This is specific to Batch API and is not part of the DrupalQueueInterface,
+   * This is specific to Batch API and is not part of the DrupalQueueInterface.
    */
   public function getAllItems() {
     $result = array();
diff -Naur drupal-7.9/includes/bootstrap.inc drupal-7.58/includes/bootstrap.inc
--- drupal-7.9/includes/bootstrap.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/bootstrap.inc	2018-03-27 21:28:19.000000000 +0200
@@ -8,7 +8,7 @@
 /**
  * The current system version.
  */
-define('VERSION', '7.9');
+define('VERSION', '7.58');
 
 /**
  * Core API compatibility.
@@ -26,6 +26,21 @@
 define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
 
 /**
+ * Error reporting level: display no errors.
+ */
+define('ERROR_REPORTING_HIDE', 0);
+
+/**
+ * Error reporting level: display errors and warnings.
+ */
+define('ERROR_REPORTING_DISPLAY_SOME', 1);
+
+/**
+ * Error reporting level: display all messages.
+ */
+define('ERROR_REPORTING_DISPLAY_ALL', 2);
+
+/**
  * Indicates that the item should never be removed unless explicitly selected.
  *
  * The item may be removed using cache_clear_all() with a cache ID.
@@ -43,9 +58,9 @@
  * Logging severity levels as defined in RFC 3164.
  *
  * The WATCHDOG_* constant definitions correspond to the logging severity levels
- * defined in RFC 3164, section 4.1.1.  PHP supplies predefined LOG_* constants
+ * defined in RFC 3164, section 4.1.1. PHP supplies predefined LOG_* constants
  * for use in the syslog() function, but their values on Windows builds do not
- * correspond to RFC 3164.  The associated PHP bug report was closed with the
+ * correspond to RFC 3164. The associated PHP bug report was closed with the
  * comment, "And it's also not a bug, as Windows just have less log levels,"
  * and "So the behavior you're seeing is perfectly normal."
  *
@@ -68,32 +83,32 @@
 define('WATCHDOG_ALERT', 1);
 
 /**
- * Log message severity -- Critical: critical conditions.
+ * Log message severity -- Critical conditions.
  */
 define('WATCHDOG_CRITICAL', 2);
 
 /**
- * Log message severity -- Error: error conditions.
+ * Log message severity -- Error conditions.
  */
 define('WATCHDOG_ERROR', 3);
 
 /**
- * Log message severity -- Warning: warning conditions.
+ * Log message severity -- Warning conditions.
  */
 define('WATCHDOG_WARNING', 4);
 
 /**
- * Log message severity -- Notice: normal but significant condition.
+ * Log message severity -- Normal but significant conditions.
  */
 define('WATCHDOG_NOTICE', 5);
 
 /**
- * Log message severity -- Informational: informational messages.
+ * Log message severity -- Informational messages.
  */
 define('WATCHDOG_INFO', 6);
 
 /**
- * Log message severity -- Debug: debug-level messages.
+ * Log message severity -- Debug-level messages.
  */
 define('WATCHDOG_DEBUG', 7);
 
@@ -137,8 +152,7 @@
 define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
 
 /**
- * Final bootstrap phase: Drupal is fully loaded; validate and fix
- * input data.
+ * Final bootstrap phase: Drupal is fully loaded; validate and fix input data.
  */
 define('DRUPAL_BOOTSTRAP_FULL', 7);
 
@@ -153,8 +167,9 @@
 define('DRUPAL_AUTHENTICATED_RID', 2);
 
 /**
- * The number of bytes in a kilobyte. For more information, visit
- * http://en.wikipedia.org/wiki/Kilobyte.
+ * The number of bytes in a kilobyte.
+ *
+ * For more information, visit http://en.wikipedia.org/wiki/Kilobyte.
  */
 define('DRUPAL_KILOBYTE', 1024);
 
@@ -191,20 +206,28 @@
 define('LANGUAGE_RTL', 1);
 
 /**
- * For convenience, define a short form of the request time global.
+ * Time of the current request in seconds elapsed since the Unix Epoch.
+ *
+ * This differs from $_SERVER['REQUEST_TIME'], which is stored as a float
+ * since PHP 5.4.0. Float timestamps confuse most PHP functions
+ * (including date_create()).
  *
- * REQUEST_TIME is a float with microseconds since PHP 5.4.0, but float
- * timestamps confuses most of the PHP functions (including date_create()).
+ * @see http://php.net/manual/reserved.variables.server.php
+ * @see http://php.net/manual/function.time.php
  */
 define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
 
 /**
- * Flag for drupal_set_title(); text is not sanitized, so run check_plain().
+ * Flag used to indicate that text is not sanitized, so run check_plain().
+ *
+ * @see drupal_set_title()
  */
 define('CHECK_PLAIN', 0);
 
 /**
- * Flag for drupal_set_title(); text has already been sanitized.
+ * Flag used to indicate that text has already been sanitized.
+ *
+ * @see drupal_set_title()
  */
 define('PASS_THROUGH', -1);
 
@@ -221,11 +244,25 @@
 /**
  * Regular expression to match PHP function names.
  *
- * @see http://php.net/manual/en/language.functions.php
+ * @see http://php.net/manual/language.functions.php
  */
 define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*');
 
 /**
+ * A RFC7231 Compliant date.
+ *
+ * http://tools.ietf.org/html/rfc7231#section-7.1.1.1
+ *
+ * Example: Sun, 06 Nov 1994 08:49:37 GMT
+ *
+ * This constant was introduced in PHP 7.0.19 and PHP 7.1.5 but needs to be
+ * defined by Drupal for earlier PHP versions.
+ */
+if (!defined('DATE_RFC7231')) {
+  define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
+}
+
+/**
  * Provides a caching wrapper to be used in place of large array structures.
  *
  * This class should be extended by systems that need to cache large amounts
@@ -255,7 +292,7 @@
  * error, and $var will be populated with the contents of $object['foo'], but
  * that data will be passed by value, not reference. For more information on
  * the PHP limitation, see the note in the official PHP documentation at·
- * http://php.net/manual/en/arrayaccess.offsetget.php on
+ * http://php.net/manual/arrayaccess.offsetget.php on
  * ArrayAccess::offsetGet().
  *
  * By default, the class accounts for caches where calling functions might
@@ -275,7 +312,7 @@
  * means that assigning an offset via arrayAccess will only apply while the
  * object is in scope and will not be written back to the persistent cache.
  * This follows a similar pattern to static vs. persistent caching in
- * procedural code. Extending classes may wish to alter this behaviour, for
+ * procedural code. Extending classes may wish to alter this behavior, for
  * example by overriding offsetSet() and adding an automatic call to persist().
  *
  * @see SchemaCache
@@ -285,12 +322,12 @@
   /**
    * A cid to pass to cache_set() and cache_get().
    */
-  private $cid;
+  protected $cid;
 
   /**
    * A bin to pass to cache_set() and cache_get().
    */
-  private $bin;
+  protected $bin;
 
   /**
    * An array of keys to add to the cache at the end of the request.
@@ -303,7 +340,7 @@
   protected $storage = array();
 
   /**
-   * Constructor.
+   * Constructs a DrupalCacheArray object.
    *
    * @param $cid
    *   The cid for the array being cached.
@@ -319,10 +356,16 @@
     }
   }
 
+  /**
+   * Implements ArrayAccess::offsetExists().
+   */
   public function offsetExists($offset) {
     return $this->offsetGet($offset) !== NULL;
   }
 
+  /**
+   * Implements ArrayAccess::offsetGet().
+   */
   public function offsetGet($offset) {
     if (isset($this->storage[$offset]) || array_key_exists($offset, $this->storage)) {
       return $this->storage[$offset];
@@ -332,10 +375,16 @@
     }
   }
 
+  /**
+   * Implements ArrayAccess::offsetSet().
+   */
   public function offsetSet($offset, $value) {
     $this->storage[$offset] = $value;
   }
 
+  /**
+   * Implements ArrayAccess::offsetUnset().
+   */
   public function offsetUnset($offset) {
     unset($this->storage[$offset]);
   }
@@ -349,11 +398,11 @@
    * without necessarily writing back to the persistent cache at the end.
    *
    * @param $offset
-   *   The array offset that was request.
+   *   The array offset that was requested.
    * @param $persist
    *   Optional boolean to specify whether the offset should be persisted or
    *   not, defaults to TRUE. When called with $persist = FALSE the offset will
-   *   be unflagged so that it will not written at the end of the request.
+   *   be unflagged so that it will not be written at the end of the request.
    */
   protected function persist($offset, $persist = TRUE) {
     $this->keysToPersist[$offset] = $persist;
@@ -375,32 +424,31 @@
   abstract protected function resolveCacheMiss($offset);
 
   /**
-   * Immediately write a value to the persistent cache.
+   * Writes a value to the persistent cache immediately.
    *
-   * @param $cid
-   *   The cache ID.
-   * @param $bin
-   *   The cache bin.
    * @param $data
    *   The data to write to the persistent cache.
    * @param $lock
    *   Whether to acquire a lock before writing to cache.
    */
-  protected function set($cid, $data, $bin, $lock = TRUE) {
+  protected function set($data, $lock = TRUE) {
     // Lock cache writes to help avoid stampedes.
     // To implement locking for cache misses, override __construct().
-    $lock_name = $cid . ':' . $bin;
+    $lock_name = $this->cid . ':' . $this->bin;
     if (!$lock || lock_acquire($lock_name)) {
-      if ($cached = cache_get($cid, $bin)) {
+      if ($cached = cache_get($this->cid, $this->bin)) {
         $data = $cached->data + $data;
       }
-      cache_set($cid, $data, $bin);
+      cache_set($this->cid, $data, $this->bin);
       if ($lock) {
         lock_release($lock_name);
       }
     }
   }
 
+  /**
+   * Destructs the DrupalCacheArray object.
+   */
   public function __destruct() {
     $data = array();
     foreach ($this->keysToPersist as $offset => $persist) {
@@ -409,14 +457,16 @@
       }
     }
     if (!empty($data)) {
-      $this->set($this->cid, $data, $this->bin);
+      $this->set($data);
     }
   }
 }
 
 /**
- * Start the timer with the specified name. If you start and stop the same
- * timer multiple times, the measured intervals will be accumulated.
+ * Starts the timer with the specified name.
+ *
+ * If you start and stop the same timer multiple times, the measured intervals
+ * will be accumulated.
  *
  * @param $name
  *   The name of the timer.
@@ -429,7 +479,7 @@
 }
 
 /**
- * Read the current timer value without stopping the timer.
+ * Reads the current timer value without stopping the timer.
  *
  * @param $name
  *   The name of the timer.
@@ -453,7 +503,7 @@
 }
 
 /**
- * Stop the timer with the specified name.
+ * Stops the timer with the specified name.
  *
  * @param $name
  *   The name of the timer.
@@ -481,56 +531,11 @@
 }
 
 /**
- * Finds the appropriate configuration directory.
+ * Returns the appropriate configuration directory.
  *
- * Finds a matching configuration directory by stripping the website's
- * hostname from left to right and pathname from right to left. The first
- * configuration file found will be used and the remaining ones will be ignored.
- * If no configuration file is found, return a default value '$confdir/default'.
- *
- * With a site located at http://www.example.com:8080/mysite/test/, the file,
- * settings.php, is searched for in the following directories:
- *
- * - $confdir/8080.www.example.com.mysite.test
- * - $confdir/www.example.com.mysite.test
- * - $confdir/example.com.mysite.test
- * - $confdir/com.mysite.test
- *
- * - $confdir/8080.www.example.com.mysite
- * - $confdir/www.example.com.mysite
- * - $confdir/example.com.mysite
- * - $confdir/com.mysite
- *
- * - $confdir/8080.www.example.com
- * - $confdir/www.example.com
- * - $confdir/example.com
- * - $confdir/com
- *
- * - $confdir/default
- *
- * If a file named sites.php is present in the $confdir, it will be loaded
- * prior to scanning for directories. It should define an associative array
- * named $sites, which maps domains to directories. It should be in the form
- * of:
- * @code
- * $sites = array(
- *   'The url to alias' => 'A directory within the sites directory'
- * );
- * @endcode
- * For example:
- * @code
- * $sites = array(
- *   'devexample.com' => 'example.com',
- *   'localhost.example' => 'example.com',
- * );
- * @endcode
- * The above array will cause Drupal to look for a directory named
- * "example.com" in the sites directory whenever a request comes from
- * "example.com", "devexample.com", or "localhost/example". That is useful
- * on development servers, where the domain name may not be the same as the
- * domain of the live server. Since Drupal stores file paths into the database
- * (files, system table, etc.) this will ensure the paths are correct while
- * accessed on development servers.
+ * Returns the configuration path based on the site's hostname, port, and
+ * pathname. See default.settings.php for examples on how the URL is converted
+ * to a directory.
  *
  * @param bool $require_settings
  *   Only configuration directories with an existing settings.php file
@@ -543,6 +548,8 @@
  *
  * @return
  *   The path of the matching directory.
+ *
+ * @see default.settings.php
  */
 function conf_path($require_settings = TRUE, $reset = FALSE) {
   $conf = &drupal_static(__FUNCTION__, '');
@@ -578,7 +585,7 @@
 }
 
 /**
- * Set appropriate server variables needed for command line scripts to work.
+ * Sets appropriate server variables needed for command line scripts to work.
  *
  * This function can be called by command line scripts before bootstrapping
  * Drupal, to ensure that the page loads with the desired server parameters.
@@ -640,7 +647,7 @@
 }
 
 /**
- * Initialize PHP environment.
+ * Initializes the PHP environment.
  */
 function drupal_environment_initialize() {
   if (!isset($_SERVER['HTTP_REFERER'])) {
@@ -689,7 +696,8 @@
   ini_set('session.use_only_cookies', '1');
   ini_set('session.use_trans_sid', '0');
   // Don't send HTTP headers using PHP's session handler.
-  ini_set('session.cache_limiter', 'none');
+  // An empty string is used here to disable the cache limiter.
+  ini_set('session.cache_limiter', '');
   // Use httponly session cookies.
   ini_set('session.cookie_httponly', '1');
 
@@ -699,35 +707,50 @@
 }
 
 /**
- * Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
+ * Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
  *
  * @return
  *  TRUE if only containing valid characters, or FALSE otherwise.
  */
 function drupal_valid_http_host($host) {
-  return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
+  // Limit the length of the host name to 1000 bytes to prevent DoS attacks with
+  // long host names.
+  return strlen($host) <= 1000
+    // Limit the number of subdomains and port separators to prevent DoS attacks
+    // in conf_path().
+    && substr_count($host, '.') <= 100
+    && substr_count($host, ':') <= 100
+    && preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
+}
+
+/**
+ * Checks whether an HTTPS request is being served.
+ *
+ * @return bool
+ *   TRUE if the request is HTTPS, FALSE otherwise.
+ */
+function drupal_is_https() {
+  return isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
 }
 
 /**
- * Loads the configuration and sets the base URL, cookie domain, and
- * session name correctly.
+ * Sets the base URL, cookie domain, and session name from configuration.
  */
 function drupal_settings_initialize() {
   global $base_url, $base_path, $base_root;
 
-  // Export the following settings.php variables to the global namespace
+  // Export these settings.php variables to the global namespace.
   global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
   $conf = array();
 
   if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
     include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php';
   }
-  $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
+  $is_https = drupal_is_https();
 
   if (isset($base_url)) {
     // Parse fixed base URL from settings.php.
     $parts = parse_url($base_url);
-    $http_protocol = $parts['scheme'];
     if (!isset($parts['path'])) {
       $parts['path'] = '';
     }
@@ -736,7 +759,7 @@
     $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
   }
   else {
-    // Create base URL
+    // Create base URL.
     $http_protocol = $is_https ? 'https' : 'http';
     $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
 
@@ -762,7 +785,7 @@
   }
   else {
     // Otherwise use $base_url as session name, without the protocol
-    // to use the same session identifiers across http and https.
+    // to use the same session identifiers across HTTP and HTTPS.
     list( , $session_name) = explode('://', $base_url, 2);
     // HTTP_HOST can be modified by a visitor, but we already sanitized it
     // in drupal_settings_initialize().
@@ -796,13 +819,14 @@
 }
 
 /**
- * Returns and optionally sets the filename for a system item (module,
- * theme, etc.). The filename, whether provided, cached, or retrieved
- * from the database, is only returned if the file exists.
+ * Returns and optionally sets the filename for a system resource.
+ *
+ * The filename, whether provided, cached, or retrieved from the database, is
+ * only returned if the file exists.
  *
  * This function plays a key role in allowing Drupal's resources (modules
  * and themes) to be located in different places depending on a site's
- * configuration. For example, a module 'foo' may legally be be located
+ * configuration. For example, a module 'foo' may legally be located
  * in any of these three places:
  *
  * modules/foo/foo.module
@@ -813,93 +837,337 @@
  * the above, depending on where the module is located.
  *
  * @param $type
- *   The type of the item (i.e. theme, theme_engine, module, profile).
+ *   The type of the item (theme, theme_engine, module, profile).
  * @param $name
  *   The name of the item for which the filename is requested.
  * @param $filename
  *   The filename of the item if it is to be set explicitly rather
  *   than by consulting the database.
+ * @param bool $trigger_error
+ *   Whether to trigger an error when a file is missing or has unexpectedly
+ *   moved. This defaults to TRUE, but can be set to FALSE by calling code that
+ *   merely wants to check whether an item exists in the filesystem.
  *
  * @return
- *   The filename of the requested item.
- */
-function drupal_get_filename($type, $name, $filename = NULL) {
+ *   The filename of the requested item or NULL if the item is not found.
+ */
+function drupal_get_filename($type, $name, $filename = NULL, $trigger_error = TRUE) {
+  // The $files static variable will hold the locations of all requested files.
+  // We can be sure that any file listed in this static variable actually
+  // exists as all additions have gone through a file_exists() check.
   // The location of files will not change during the request, so do not use
   // drupal_static().
-  static $files = array(), $dirs = array();
+  static $files = array();
 
+  // Profiles are a special case: they have a fixed location and naming.
+  if ($type == 'profile') {
+    $profile_filename = "profiles/$name/$name.profile";
+    $files[$type][$name] = file_exists($profile_filename) ? $profile_filename : FALSE;
+  }
   if (!isset($files[$type])) {
     $files[$type] = array();
   }
 
   if (!empty($filename) && file_exists($filename)) {
+    // Prime the static cache with the provided filename.
     $files[$type][$name] = $filename;
   }
   elseif (isset($files[$type][$name])) {
-    // nothing
+    // This item had already been found earlier in the request, either through
+    // priming of the static cache (for example, in system_list()), through a
+    // lookup in the {system} table, or through a file scan (cached or not). Do
+    // nothing.
   }
-  // Verify that we have an active database connection, before querying
-  // the database. This is required because this function is called both
-  // before we have a database connection (i.e. during installation) and
-  // when a database connection fails.
   else {
+    // Look for the filename listed in the {system} table. Verify that we have
+    // an active database connection before doing so, since this function is
+    // called both before we have a database connection (i.e. during
+    // installation) and when a database connection fails.
+    $database_unavailable = TRUE;
     try {
       if (function_exists('db_query')) {
         $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
-        if (file_exists(DRUPAL_ROOT . '/' . $file)) {
+        if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) {
           $files[$type][$name] = $file;
         }
+        $database_unavailable = FALSE;
       }
     }
     catch (Exception $e) {
       // The database table may not exist because Drupal is not yet installed,
-      // or the database might be down. We have a fallback for this case so we
-      // hide the error completely.
+      // the database might be down, or we may have done a non-database cache
+      // flush while $conf['page_cache_without_database'] = TRUE and
+      // $conf['page_cache_invoke_hooks'] = TRUE. We have a fallback for these
+      // cases so we hide the error completely.
     }
-    // Fallback to searching the filesystem if the database could not find the
-    // file or the file returned by the database is not found.
+    // Fall back to searching the filesystem if the database could not find the
+    // file or the file does not exist at the path returned by the database.
     if (!isset($files[$type][$name])) {
-      // We have a consistent directory naming: modules, themes...
-      $dir = $type . 's';
-      if ($type == 'theme_engine') {
-        $dir = 'themes/engines';
-        $extension = 'engine';
-      }
-      elseif ($type == 'theme') {
-        $extension = 'info';
-      }
-      else {
-        $extension = $type;
-      }
+      $files[$type][$name] = _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable);
+    }
+  }
 
-      if (!isset($dirs[$dir][$extension])) {
-        $dirs[$dir][$extension] = TRUE;
-        if (!function_exists('drupal_system_listing')) {
-          require_once DRUPAL_ROOT . '/includes/common.inc';
-        }
-        // Scan the appropriate directories for all files with the requested
-        // 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("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
-        foreach ($matches as $matched_name => $file) {
-          $files[$type][$matched_name] = $file->uri;
+  if (isset($files[$type][$name])) {
+    return $files[$type][$name];
+  }
+}
+
+/**
+ * Performs a cached file system scan as a fallback when searching for a file.
+ *
+ * This function looks for the requested file by triggering a file scan,
+ * caching the new location if the file has moved and caching the miss
+ * if the file is missing. If a file had been marked as missing in a previous
+ * file scan, or if it has been marked as moved and is still in the last known
+ * location, no new file scan will be performed.
+ *
+ * @param string $type
+ *   The type of the item (theme, theme_engine, module, profile).
+ * @param string $name
+ *   The name of the item for which the filename is requested.
+ * @param bool $trigger_error
+ *   Whether to trigger an error when a file is missing or has unexpectedly
+ *   moved.
+ * @param bool $database_unavailable
+ *   Whether this function is being called because the Drupal database could
+ *   not be queried for the file's location.
+ *
+ * @return
+ *   The filename of the requested item or NULL if the item is not found.
+ *
+ * @see drupal_get_filename()
+ */
+function _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable) {
+  $file_scans = &_drupal_file_scan_cache();
+  $filename = NULL;
+
+  // If the cache indicates that the item is missing, or we can verify that the
+  // item exists in the location the cache says it exists in, use that.
+  if (isset($file_scans[$type][$name]) && ($file_scans[$type][$name] === FALSE || file_exists($file_scans[$type][$name]))) {
+    $filename = $file_scans[$type][$name];
+  }
+  // Otherwise, perform a new file scan to find the item.
+  else {
+    $filename = _drupal_get_filename_perform_file_scan($type, $name);
+    // Update the static cache, and mark the persistent cache for updating at
+    // the end of the page request. See drupal_file_scan_write_cache().
+    $file_scans[$type][$name] = $filename;
+    $file_scans['#write_cache'] = TRUE;
+  }
+
+  // If requested, trigger a user-level warning about the missing or
+  // unexpectedly moved file. If the database was unavailable, do not trigger a
+  // warning in the latter case, though, since if the {system} table could not
+  // be queried there is no way to know if the location found here was
+  // "unexpected" or not.
+  if ($trigger_error) {
+    $error_type = $filename === FALSE ? 'missing' : 'moved';
+    if ($error_type == 'missing' || !$database_unavailable) {
+      _drupal_get_filename_fallback_trigger_error($type, $name, $error_type);
+    }
+  }
+
+  // The cache stores FALSE for files that aren't found (to be able to
+  // distinguish them from files that have not yet been searched for), but
+  // drupal_get_filename() expects NULL for these instead, so convert to NULL
+  // before returning.
+  if ($filename === FALSE) {
+    $filename = NULL;
+  }
+  return $filename;
+}
+
+/**
+ * Returns the current list of cached file system scan results.
+ *
+ * @return
+ *   An associative array tracking the most recent file scan results for all
+ *   files that have had scans performed. The keys are the type and name of the
+ *   item that was searched for, and the values can be either:
+ *   - Boolean FALSE if the item was not found in the file system.
+ *   - A string pointing to the location where the item was found.
+ */
+function &_drupal_file_scan_cache() {
+  $file_scans = &drupal_static(__FUNCTION__, array());
+
+  // The file scan results are stored in a persistent cache (in addition to the
+  // static cache) but because this function can be called before the
+  // persistent cache is available, we must merge any items that were found
+  // earlier in the page request into the results from the persistent cache.
+  if (!isset($file_scans['#cache_merge_done'])) {
+    try {
+      if (function_exists('cache_get')) {
+        $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
+        if (!empty($cache->data)) {
+          // File scan results from the current request should take precedence
+          // over the results from the persistent cache, since they are newer.
+          $file_scans = drupal_array_merge_deep($cache->data, $file_scans);
         }
+        // Set a flag to indicate that the persistent cache does not need to be
+        // merged again.
+        $file_scans['#cache_merge_done'] = TRUE;
       }
     }
+    catch (Exception $e) {
+      // Hide the error.
+    }
   }
 
-  if (isset($files[$type][$name])) {
-    return $files[$type][$name];
+  return $file_scans;
+}
+
+/**
+ * Performs a file system scan to search for a system resource.
+ *
+ * @param $type
+ *   The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ *   The name of the item for which the filename is requested.
+ *
+ * @return
+ *   The filename of the requested item or FALSE if the item is not found.
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_perform_file_scan($type, $name) {
+  // The location of files will not change during the request, so do not use
+  // drupal_static().
+  static $dirs = array(), $files = array();
+
+  // We have a consistent directory naming: modules, themes...
+  $dir = $type . 's';
+  if ($type == 'theme_engine') {
+    $dir = 'themes/engines';
+    $extension = 'engine';
+  }
+  elseif ($type == 'theme') {
+    $extension = 'info';
+  }
+  else {
+    $extension = $type;
+  }
+
+  // Check if we had already scanned this directory/extension combination.
+  if (!isset($dirs[$dir][$extension])) {
+    // Log that we have now scanned this directory/extension combination
+    // into a static variable so as to prevent unnecessary file scans.
+    $dirs[$dir][$extension] = TRUE;
+    if (!function_exists('drupal_system_listing')) {
+      require_once DRUPAL_ROOT . '/includes/common.inc';
+    }
+    // Scan the appropriate directories for all files with the requested
+    // 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("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
+    foreach ($matches as $matched_name => $file) {
+      // Log the locations found in the file scan into a static variable.
+      $files[$type][$matched_name] = $file->uri;
+    }
+  }
+
+  // Return the results of the file system scan, or FALSE to indicate the file
+  // was not found.
+  return isset($files[$type][$name]) ? $files[$type][$name] : FALSE;
+}
+
+/**
+ * Triggers a user-level warning for missing or unexpectedly moved files.
+ *
+ * @param $type
+ *   The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ *   The name of the item for which the filename is requested.
+ * @param $error_type
+ *   The type of the error ('missing' or 'moved').
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_fallback_trigger_error($type, $name, $error_type) {
+  // Hide messages due to known bugs that will appear on a lot of sites.
+  // @todo Remove this in https://www.drupal.org/node/2383823
+  if (empty($name)) {
+    return;
+  }
+
+  // Make sure we only show any missing or moved file errors only once per
+  // request.
+  static $errors_triggered = array();
+  if (empty($errors_triggered[$type][$name][$error_type])) {
+    // Use _drupal_trigger_error_with_delayed_logging() here since these are
+    // triggered during low-level operations that cannot necessarily be
+    // interrupted by a watchdog() call.
+    if ($error_type == 'missing') {
+      _drupal_trigger_error_with_delayed_logging(format_string('The following @type is missing from the file system: %name. For information about how to fix this, see <a href="@documentation">the documentation page</a>.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+    }
+    elseif ($error_type == 'moved') {
+      _drupal_trigger_error_with_delayed_logging(format_string('The following @type has moved within the file system: %name. In order to fix this, clear caches or put the @type back in its original location. For more information, see <a href="@documentation">the documentation page</a>.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+    }
+    $errors_triggered[$type][$name][$error_type] = TRUE;
+  }
+}
+
+/**
+ * Invokes trigger_error() with logging delayed until the end of the request.
+ *
+ * This is an alternative to PHP's trigger_error() function which can be used
+ * during low-level Drupal core operations that need to avoid being interrupted
+ * by a watchdog() call.
+ *
+ * Normally, Drupal's error handler calls watchdog() in response to a
+ * trigger_error() call. However, this invokes hook_watchdog() which can run
+ * arbitrary code. If the trigger_error() happens in the middle of an
+ * operation such as a rebuild operation which should not be interrupted by
+ * arbitrary code, that could potentially break or trigger the rebuild again.
+ * This function protects against that by delaying the watchdog() call until
+ * the end of the current page request.
+ *
+ * This is an internal function which should only be called by low-level Drupal
+ * core functions. It may be removed in a future Drupal 7 release.
+ *
+ * @param string $error_msg
+ *   The error message to trigger. As with trigger_error() itself, this is
+ *   limited to 1024 bytes; additional characters beyond that will be removed.
+ * @param int $error_type
+ *   (optional) The type of error. This should be one of the E_USER family of
+ *   constants. As with trigger_error() itself, this defaults to E_USER_NOTICE
+ *   if not provided.
+ *
+ * @see _drupal_log_error()
+ */
+function _drupal_trigger_error_with_delayed_logging($error_msg, $error_type = E_USER_NOTICE) {
+  $delay_logging = &drupal_static(__FUNCTION__, FALSE);
+  $delay_logging = TRUE;
+  trigger_error($error_msg, $error_type);
+  $delay_logging = FALSE;
+}
+
+/**
+ * Writes the file scan cache to the persistent cache.
+ *
+ * This cache stores all files marked as missing or moved after a file scan
+ * to prevent unnecessary file scans in subsequent requests. This cache is
+ * cleared in system_list_reset() (i.e. after a module/theme rebuild).
+ */
+function drupal_file_scan_write_cache() {
+  // Only write to the persistent cache if requested, and if we know that any
+  // data previously in the cache was successfully loaded and merged in by
+  // _drupal_file_scan_cache().
+  $file_scans = &_drupal_file_scan_cache();
+  if (isset($file_scans['#write_cache']) && isset($file_scans['#cache_merge_done'])) {
+    unset($file_scans['#write_cache']);
+    cache_set('_drupal_file_scan_cache', $file_scans, 'cache_bootstrap');
   }
 }
 
 /**
- * Load the persistent variable table.
+ * Loads the persistent variable table.
  *
  * The variable table is composed of values that have been saved in the table
- * with variable_set() as well as those explicitly specified in the configuration
- * file.
+ * with variable_set() as well as those explicitly specified in the
+ * configuration file.
  */
 function variable_initialize($conf = array()) {
   // NOTE: caching the variables improves performance by 20% when serving
@@ -944,7 +1212,7 @@
  *   The default value to use if this variable has never been set.
  *
  * @return
- *   The value of the variable.
+ *   The value of the variable. Unserialization is taken care of as necessary.
  *
  * @see variable_del()
  * @see variable_set()
@@ -1006,7 +1274,7 @@
 }
 
 /**
- * Retrieve the current page from the cache.
+ * Retrieves the current page from the cache.
  *
  * Note: we do not serve cached pages to authenticated users, or to anonymous
  * users when $_SESSION is non-empty. $_SESSION may contain status messages
@@ -1038,10 +1306,10 @@
 }
 
 /**
- * Determine the cacheability of the current page.
+ * Determines the cacheability of the current page.
  *
  * @param $allow_caching
- *   Set to FALSE if you want to prevent this page to get cached.
+ *   Set to FALSE if you want to prevent this page from being cached.
  *
  * @return
  *   TRUE if the current page can be cached, FALSE otherwise.
@@ -1057,7 +1325,7 @@
 }
 
 /**
- * Invoke a bootstrap hook in all bootstrap modules that implement it.
+ * Invokes a bootstrap hook in all bootstrap modules that implement it.
  *
  * @param $hook
  *   The name of the bootstrap hook to invoke.
@@ -1079,8 +1347,9 @@
 }
 
 /**
- * Includes a file with the provided type and name. This prevents
- * including a theme, engine, module, etc., more than once.
+ * Includes a file with the provided type and name.
+ *
+ * This prevents including a theme, engine, module, etc., more than once.
  *
  * @param $type
  *   The type of item to load (i.e. theme, theme_engine, module).
@@ -1112,7 +1381,7 @@
 }
 
 /**
- * Set an HTTP response header for the current page.
+ * Sets an HTTP response header for the current page.
  *
  * Note: When sending a Content-Type header, always include a 'charset' type,
  * too. This is necessary to avoid security bugs (e.g. UTF-7 XSS).
@@ -1148,11 +1417,12 @@
 }
 
 /**
- * Get the HTTP response headers for the current page.
+ * Gets the HTTP response headers for the current page.
  *
  * @param $name
  *   An HTTP header name. If omitted, all headers are returned as name/value
  *   pairs. If an array value is FALSE, the header has been unset.
+ *
  * @return
  *   A string containing the header value, or FALSE if the header has been set,
  *   or NULL if the header has not been set.
@@ -1169,6 +1439,8 @@
 }
 
 /**
+ * Sets the preferred name for the HTTP header.
+ *
  * Header names are case-insensitive, but for maximum compatibility they should
  * follow "common form" (see RFC 2617, section 4.2).
  */
@@ -1182,14 +1454,16 @@
 }
 
 /**
- * Send the HTTP response headers previously set using drupal_add_http_header().
- * Add default headers, unless they have been replaced or unset using
- * drupal_add_http_header().
- *
- * @param $default_headers
- *   An array of headers as name/value pairs.
- * @param $single
- *   If TRUE and headers have already be sent, send only the specified header.
+ * Sends the HTTP response headers that were previously set, adding defaults.
+ *
+ * Headers are set in drupal_add_http_header(). Default headers are not set
+ * if they have been replaced or unset using drupal_add_http_header().
+ *
+ * @param array $default_headers
+ *   (optional) An array of headers as name/value pairs.
+ * @param bool $only_default
+ *   (optional) If TRUE and headers have already been sent, send only the
+ *   specified headers.
  */
 function drupal_send_headers($default_headers = array(), $only_default = FALSE) {
   $headers_sent = &drupal_static(__FUNCTION__, FALSE);
@@ -1212,36 +1486,23 @@
       header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value);
     }
     // Skip headers that have been unset.
-    elseif ($value) {
+    elseif ($value !== FALSE) {
       header($header_names[$name_lower] . ': ' . $value);
     }
   }
 }
 
 /**
- * Set HTTP headers in preparation for a page response.
+ * Sets HTTP headers in preparation for a page response.
  *
  * Authenticated users are always given a 'no-cache' header, and will fetch a
  * fresh page on every request. This prevents authenticated users from seeing
  * locally cached pages.
  *
- * Also give each page a unique ETag. This will force clients to include both
- * an If-Modified-Since header and an If-None-Match header when doing
- * conditional requests for the page (required by RFC 2616, section 13.3.4),
- * making the validation more robust. This is a workaround for a bug in Mozilla
- * Firefox that is triggered when Drupal's caching is enabled and the user
- * accesses Drupal via an HTTP proxy (see
- * https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an authenticated
- * user requests a page, and then logs out and requests the same page again,
- * Firefox may send a conditional request based on the page that was cached
- * locally when the user was logged in. If this page did not have an ETag
- * header, the request only contains an If-Modified-Since header. The date will
- * be recent, because with authenticated users the Last-Modified header always
- * refers to the time of the request. If the user accesses Drupal via a proxy
- * server, and the proxy already has a cached copy of the anonymous page with an
- * older Last-Modified date, the proxy may respond with 304 Not Modified, making
- * the client think that the anonymous and authenticated pageviews are
- * identical.
+ * ETag and Last-Modified headers are not set per default for authenticated
+ * users so that browsers do not send If-Modified-Since headers from
+ * authenticated user pages. drupal_serve_page_from_cache() will set appropriate
+ * ETag and Last-Modified headers for cached pages.
  *
  * @see drupal_page_set_cache()
  */
@@ -1254,15 +1515,17 @@
 
   $default_headers = array(
     'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
-    'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME),
-    'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
-    'ETag' => '"' . REQUEST_TIME . '"',
+    'Cache-Control' => 'no-cache, must-revalidate',
+    // Prevent browsers from sniffing a response and picking a MIME type
+    // different from the declared content-type, since that can lead to
+    // XSS and other vulnerabilities.
+    'X-Content-Type-Options' => 'nosniff',
   );
   drupal_send_headers($default_headers);
 }
 
 /**
- * Set HTTP headers in preparation for a cached page response.
+ * Sets HTTP headers in preparation for a cached page response.
  *
  * The headers allow as much as possible in proxies and browsers without any
  * particular knowledge about the pages. Modules can override these headers
@@ -1274,7 +1537,7 @@
  */
 function drupal_serve_page_from_cache(stdClass $cache) {
   // Negotiate whether to use compression.
-  $page_compression = variable_get('page_compression', TRUE) && extension_loaded('zlib');
+  $page_compression = !empty($cache->data['page_compressed']);
   $return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE;
 
   // Get headers set in hook_boot(). Keys are lower-case.
@@ -1324,7 +1587,7 @@
     drupal_add_http_header($name, $value);
   }
 
-  $default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created);
+  $default_headers['Last-Modified'] = gmdate(DATE_RFC7231, $cache->created);
 
   // HTTP/1.0 proxies does not support the Vary header, so prevent any caching
   // by sending an Expires date in the past. HTTP/1.1 clients ignores the
@@ -1365,7 +1628,7 @@
 }
 
 /**
- * Define the critical hooks that force modules to always be loaded.
+ * Defines the critical hooks that force modules to always be loaded.
  */
 function bootstrap_hooks() {
   return array('boot', 'exit', 'watchdog', 'language_init');
@@ -1405,6 +1668,7 @@
  * more information, including recommendations on how to break up or not
  * break up strings for translation.
  *
+ * @section sec_translating_vars Translating Variables
  * You should never use t() to translate variables, such as calling
  * @code t($text); @endcode, unless the text that the variable holds has been
  * passed through t() elsewhere (e.g., $text is one of several translated
@@ -1418,32 +1682,54 @@
  * $text = t("@name's blog", array('@name' => format_username($account)));
  * @endcode
  * Basically, you can put variables like @name into your string, and t() will
- * substitute their sanitized values at translation time (see $args below or
- * the Localization API pages referenced above for details). Translators can
- * then rearrange the string as necessary for the language (e.g., in Spanish,
- * it might be "blog de @name").
+ * substitute their sanitized values at translation time. (See the
+ * Localization API pages referenced above and the documentation of
+ * format_string() for details about how to define variables in your string.)
+ * Translators can then rearrange the string as necessary for the language
+ * (e.g., in Spanish, it might be "blog de @name").
  *
+ * @section sec_alt_funcs_install Use During Installation Phase
  * During the Drupal installation phase, some resources used by t() wil not be
  * available to code that needs localization. See st() and get_t() for
  * alternatives.
  *
+ * @section sec_context String context
+ * Matching source strings are normally only translated once, and the same
+ * translation is used everywhere that has a matching string. However, in some
+ * cases, a certain English source string needs to have multiple translations.
+ * One example of this is the string "May", which could be used as either a
+ * full month name or a 3-letter abbreviated month. In other languages where
+ * the month name for May has more than 3 letters, you would need to provide
+ * two different translations (one for the full name and one abbreviated), and
+ * the correct form would need to be chosen, depending on how "May" is being
+ * used. To facilitate this, the "May" string should be provided with two
+ * different contexts in the $options parameter when calling t(). For example:
+ * @code
+ * t('May', array(), array('context' => 'Long month name')
+ * t('May', array(), array('context' => 'Abbreviated month name')
+ * @endcode
+ * See https://localize.drupal.org/node/2109 for more information.
+ *
  * @param $string
  *   A string containing the English string to translate.
  * @param $args
- *   An associative array of replacements to make after translation.
- *   See format_string().
+ *   An associative array of replacements to make after translation. Based
+ *   on the first character of the key, the value is escaped and/or themed.
+ *   See format_string() for details.
  * @param $options
  *   An associative array of additional options, with the following elements:
  *   - 'langcode' (defaults to the current language): The language code to
  *     translate to a language other than what is used to display the page.
- *   - 'context' (defaults to the empty context): The context the source string
- *     belongs to.
+ *   - 'context' (defaults to the empty context): A string giving the context
+ *     that the source string belongs to. See @ref sec_context above for more
+ *     information.
  *
  * @return
  *   The translated string.
  *
  * @see st()
  * @see get_t()
+ * @see format_string()
  * @ingroup sanitization
  */
 function t($string, array $args = array(), array $options = array()) {
@@ -1482,21 +1768,34 @@
 }
 
 /**
- * Replace placeholders with sanitized values in a string.
+ * Formats a string for HTML display by replacing variable placeholders.
+ *
+ * This function replaces variable placeholders in a string with the requested
+ * values and escapes the values so they can be safely displayed as HTML. It
+ * should be used on any unknown text that is intended to be printed to an HTML
+ * page (especially text that may have come from untrusted users, since in that
+ * case it prevents cross-site scripting and other security problems).
+ *
+ * In most cases, you should use t() rather than calling this function
+ * directly, since it will translate the text (on non-English-only sites) in
+ * addition to formatting it.
  *
  * @param $string
  *   A string containing placeholders.
  * @param $args
  *   An associative array of replacements to make. Occurrences in $string of
- *   any key in $args are replaced with the corresponding value, after
- *   sanitization. The sanitization function depends on the first character of
- *   the key:
- *   - !variable: Inserted as is. Use this for text that has already been
- *     sanitized.
- *   - @variable: Escaped to HTML using check_plain(). Use this for anything
- *     displayed on a page on the site.
- *   - %variable: Escaped as a placeholder for user-submitted content using
- *     drupal_placeholder(), which shows up as <em>emphasized</em> text.
+ *   any key in $args are replaced with the corresponding value, after optional
+ *   sanitization and formatting. The type of sanitization and formatting
+ *   depends on the first character of the key:
+ *   - @variable: Escaped to HTML using check_plain(). Use this as the default
+ *     choice for anything displayed on a page on the site.
+ *   - %variable: Escaped to HTML and formatted using drupal_placeholder(),
+ *     which makes it display as <em>emphasized</em> text.
+ *   - !variable: Inserted as is, with no sanitization or formatting. Only use
+ *     this for text that has already been prepared for HTML display (for
+ *     example, user-supplied text that has already been run through
+ *     check_plain() previously, or is expected to contain some limited HTML
+ *     tags and has already been run through filter_xss() previously).
  *
  * @see t()
  * @ingroup sanitization
@@ -1524,17 +1823,18 @@
 }
 
 /**
- * Encode special characters in a plain-text string for display as HTML.
+ * Encodes special characters in a plain-text string for display as HTML.
  *
  * Also validates strings as UTF-8 to prevent cross site scripting attacks on
  * Internet Explorer 6.
  *
- * @param $text
+ * @param string $text
  *   The text to be checked or processed.
  *
- * @return
- *   An HTML safe version of $text, or an empty string if $text is not
- *   valid UTF-8.
+ * @return string
+ *   An HTML safe version of $text. If $text is not valid UTF-8, an empty string
+ *   is returned and, on PHP < 5.4, a warning may be issued depending on server
+ *   configuration (see @link https://bugs.php.net/bug.php?id=47494 @endlink).
  *
  * @see drupal_validate_utf8()
  * @ingroup sanitization
@@ -1563,6 +1863,7 @@
  *
  * @param $text
  *   The text to check.
+ *
  * @return
  *   TRUE if the text is valid UTF-8, FALSE if not.
  */
@@ -1604,7 +1905,7 @@
 }
 
 /**
- * Log an exception.
+ * Logs an exception.
  *
  * This is a wrapper function for watchdog() which automatically decodes an
  * exception.
@@ -1618,14 +1919,14 @@
  *   information about the passed-in exception is used.
  * @param $variables
  *   Array of variables to replace in the message on display. Defaults to the
- *   return value of drupal_decode_exception().
+ *   return value of _drupal_decode_exception().
  * @param $severity
  *   The severity of the message, as per RFC 3164.
  * @param $link
  *   A link to associate with the message.
  *
  * @see watchdog()
- * @see drupal_decode_exception()
+ * @see _drupal_decode_exception()
  */
 function watchdog_exception($type, Exception $exception, $message = NULL, $variables = array(), $severity = WATCHDOG_ERROR, $link = NULL) {
 
@@ -1645,7 +1946,7 @@
 }
 
 /**
- * Log a system message.
+ * Logs a system message.
  *
  * @param $type
  *   The category to which this message belongs. Can be any string, but the
@@ -1661,8 +1962,16 @@
  *   NULL if message is already translated or not possible to
  *   translate.
  * @param $severity
- *   The severity of the message, as per RFC 3164. Possible values are
- *   WATCHDOG_ERROR, WATCHDOG_WARNING, etc.
+ *   The severity of the message; one of the following values as defined in
+ *   @link http://www.faqs.org/rfcs/rfc3164.html RFC 3164: @endlink
+ *   - WATCHDOG_EMERGENCY: Emergency, system is unusable.
+ *   - WATCHDOG_ALERT: Alert, action must be taken immediately.
+ *   - WATCHDOG_CRITICAL: Critical conditions.
+ *   - WATCHDOG_ERROR: Error conditions.
+ *   - WATCHDOG_WARNING: Warning conditions.
+ *   - WATCHDOG_NOTICE: (default) Normal but significant conditions.
+ *   - WATCHDOG_INFO: Informational messages.
+ *   - WATCHDOG_DEBUG: Debug-level messages.
  * @param $link
  *   A link to associate with the message.
  *
@@ -1679,6 +1988,9 @@
   if (!$in_error_state && function_exists('module_implements')) {
     $in_error_state = TRUE;
 
+    // The user object may not exist in all conditions, so 0 is substituted if needed.
+    $user_uid = isset($user->uid) ? $user->uid : 0;
+
     // Prepare the fields to be logged
     $log_entry = array(
       'type'        => $type,
@@ -1687,10 +1999,12 @@
       'severity'    => $severity,
       'link'        => $link,
       'user'        => $user,
+      'uid'         => $user_uid,
       'request_uri' => $base_root . request_uri(),
       'referer'     => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
       'ip'          => ip_address(),
-      'timestamp'   => REQUEST_TIME,
+      // Request time isn't accurate for long processes, use time() instead.
+      'timestamp'   => time(),
     );
 
     // Call the logging hooks to log/process the message
@@ -1705,25 +2019,40 @@
 }
 
 /**
- * Set a message which reflects the status of the performed operation.
+ * Sets a message to display to the user.
  *
- * If the function is called with no arguments, this function returns all set
- * messages without clearing them.
+ * Messages are stored in a session variable and displayed in page.tpl.php via
+ * the $messages theme variable.
  *
- * @param $message
- *   The message to be displayed to the user. For consistency with other
- *   messages, it should begin with a capital letter and end with a period.
- * @param $type
- *   The type of the message. One of the following values are possible:
+ * Example usage:
+ * @code
+ * drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
+ * @endcode
+ *
+ * @param string $message
+ *   (optional) The translated message to be displayed to the user. For
+ *   consistency with other messages, it should begin with a capital letter and
+ *   end with a period.
+ * @param string $type
+ *   (optional) The message's type. Defaults to 'status'. These values are
+ *   supported:
  *   - 'status'
  *   - 'warning'
  *   - 'error'
- * @param $repeat
- *   If this is FALSE and the message is already set, then the message won't
- *   be repeated.
+ * @param bool $repeat
+ *   (optional) If this is FALSE and the message is already set, then the
+ *   message won't be repeated. Defaults to TRUE.
+ *
+ * @return array|null
+ *   A multidimensional array with keys corresponding to the set message types.
+ *   The indexed array values of each contain the set messages for that type.
+ *   Or, if there are no messages set, the function returns NULL.
+ *
+ * @see drupal_get_messages()
+ * @see theme_status_messages()
  */
 function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
-  if ($message) {
+  if ($message || $message === '0' || $message === 0) {
     if (!isset($_SESSION['messages'][$type])) {
       $_SESSION['messages'][$type] = array();
     }
@@ -1741,17 +2070,29 @@
 }
 
 /**
- * Return all messages that have been set.
+ * Returns all messages that have been set with drupal_set_message().
  *
- * @param $type
- *   (optional) Only return messages of this type.
- * @param $clear_queue
- *   (optional) Set to FALSE if you do not want to clear the messages queue
- * @return
- *   An associative array, the key is the message type, the value an array
- *   of messages. If the $type parameter is passed, you get only that type,
- *   or an empty array if there are no such messages. If $type is not passed,
- *   all message types are returned, or an empty array if none exist.
+ * @param string $type
+ *   (optional) Limit the messages returned by type. Defaults to NULL, meaning
+ *   all types. These values are supported:
+ *   - NULL
+ *   - 'status'
+ *   - 'warning'
+ *   - 'error'
+ * @param bool $clear_queue
+ *   (optional) If this is TRUE, the queue will be cleared of messages of the
+ *   type specified in the $type parameter. Otherwise the queue will be left
+ *   intact. Defaults to TRUE.
+ *
+ * @return array
+ *   A multidimensional array with keys corresponding to the set message types.
+ *   The indexed array values of each contain the set messages for that type.
+ *   The messages returned are limited to the type specified in the $type
+ *   parameter. If there are no messages of the specified type, an empty array
+ *   is returned.
+ *
+ * @see drupal_set_message()
+ * @see theme_status_messages()
  */
 function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
   if ($messages = drupal_set_message()) {
@@ -1774,7 +2115,9 @@
 }
 
 /**
- * Get the title of the current page, for display on the page and in the title bar.
+ * Gets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
  *
  * @return
  *   The current page's title.
@@ -1791,7 +2134,9 @@
 }
 
 /**
- * Set the title of the current page, for display on the page and in the title bar.
+ * Sets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
  *
  * @param $title
  *   Optional string value to assign to the page title; or if set to NULL
@@ -1816,7 +2161,7 @@
 }
 
 /**
- * Check to see if an IP address has been blocked.
+ * Checks to see if an IP address has been blocked.
  *
  * Blocked IP addresses are stored in the database by default. However for
  * performance reasons we allow an override in settings.php. This allows us
@@ -1825,6 +2170,7 @@
  *
  * @param $ip
  *   IP address to check.
+ *
  * @return bool
  *   TRUE if access is denied, FALSE if access is allowed.
  */
@@ -1850,7 +2196,7 @@
 }
 
 /**
- * Handle denied users.
+ * Handles denied users.
  *
  * @param $ip
  *   IP address to check. Prints a message and exits if access is denied.
@@ -1865,39 +2211,73 @@
 }
 
 /**
+ * Returns a URL-safe, base64 encoded string of highly randomized bytes (over the full 8-bit range).
+ *
+ * @param $byte_count
+ *   The number of random bytes to fetch and base64 encode.
+ *
+ * @return string
+ *   The base64 encoded result will have a length of up to 4 * $byte_count.
+ */
+function drupal_random_key($byte_count = 32) {
+  return drupal_base64_encode(drupal_random_bytes($byte_count));
+}
+
+/**
+ * Returns a URL-safe, base64 encoded version of the supplied string.
+ *
+ * @param $string
+ *   The string to convert to base64.
+ *
+ * @return string
+ */
+function drupal_base64_encode($string) {
+  $data = base64_encode($string);
+  // Modify the output so it's safe to use in URLs.
+  return strtr($data, array('+' => '-', '/' => '_', '=' => ''));
+}
+
+/**
  * Returns a string of highly randomized bytes (over the full 8-bit range).
  *
  * This function is better than simply calling mt_rand() or any other built-in
  * PHP function because it can return a long string of bytes (compared to < 4
- * bytes normally from mt_rand()) and uses the best available pseudo-random source.
+ * bytes normally from mt_rand()) and uses the best available pseudo-random
+ * source.
  *
  * @param $count
  *   The number of characters (bytes) to return in the string.
  */
 function drupal_random_bytes($count)  {
   // $random_state does not use drupal_static as it stores random bytes.
-  static $random_state, $bytes;
-  // Initialize on the first call. The contents of $_SERVER includes a mix of
-  // user-specific and system information that varies a little with each page.
-  if (!isset($random_state)) {
-    $random_state = print_r($_SERVER, TRUE);
-    if (function_exists('getmypid')) {
-      // Further initialize with the somewhat random PHP process ID.
-      $random_state .= getmypid();
-    }
-    $bytes = '';
-  }
-  if (strlen($bytes) < $count) {
-    // /dev/urandom is available on many *nix systems and is considered the
-    // best commonly available pseudo-random source.
-    if ($fh = @fopen('/dev/urandom', 'rb')) {
+  static $random_state, $bytes, $has_openssl;
+
+  $missing_bytes = $count - strlen($bytes);
+
+  if ($missing_bytes > 0) {
+    // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
+    // locking on Windows and rendered it unusable.
+    if (!isset($has_openssl)) {
+      $has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
+    }
+
+    // openssl_random_pseudo_bytes() will find entropy in a system-dependent
+    // way.
+    if ($has_openssl) {
+      $bytes .= openssl_random_pseudo_bytes($missing_bytes);
+    }
+
+    // Else, read directly from /dev/urandom, which is available on many *nix
+    // systems and is considered cryptographically secure.
+    elseif ($fh = @fopen('/dev/urandom', 'rb')) {
       // PHP only performs buffered reads, so in reality it will always read
       // at least 4096 bytes. Thus, it costs nothing extra to read and store
       // that much so as to speed any additional invocations.
-      $bytes .= fread($fh, max(4096, $count));
+      $bytes .= fread($fh, max(4096, $missing_bytes));
       fclose($fh);
     }
-    // If /dev/urandom is not available or returns no bytes, this loop will
+
+    // If we couldn't get enough entropy, this simple hash-based PRNG will
     // generate a good set of pseudo-random bytes on any system.
     // Note that it may be important that our $random_state is passed
     // through hash() prior to being rolled into $output, that the two hash()
@@ -1905,9 +2285,23 @@
     // the microtime() - is prepended rather than appended. This is to avoid
     // directly leaking $random_state via the $output stream, which could
     // allow for trivial prediction of further "random" numbers.
-    while (strlen($bytes) < $count) {
-      $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
-      $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+    if (strlen($bytes) < $count) {
+      // Initialize on the first call. The contents of $_SERVER includes a mix of
+      // user-specific and system information that varies a little with each page.
+      if (!isset($random_state)) {
+        $random_state = print_r($_SERVER, TRUE);
+        if (function_exists('getmypid')) {
+          // Further initialize with the somewhat random PHP process ID.
+          $random_state .= getmypid();
+        }
+        $bytes = '';
+      }
+
+      do {
+        $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
+        $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+      }
+      while (strlen($bytes) < $count);
     }
   }
   $output = substr($bytes, 0, $count);
@@ -1916,25 +2310,29 @@
 }
 
 /**
- * Calculate a base-64 encoded, URL-safe sha-256 hmac.
+ * Calculates a base-64 encoded, URL-safe sha-256 hmac.
  *
- * @param $data
+ * @param string $data
  *   String to be validated with the hmac.
- * @param $key
+ * @param string $key
  *   A secret string key.
  *
- * @return
+ * @return string
  *   A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
  *   any = padding characters removed.
  */
 function drupal_hmac_base64($data, $key) {
-  $hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+  // Casting $data and $key to strings here is necessary to avoid empty string
+  // results of the hash function if they are not scalar values. As this
+  // function is used in security-critical contexts like token validation it is
+  // important that it never returns an empty string.
+  $hmac = base64_encode(hash_hmac('sha256', (string) $data, (string) $key, TRUE));
   // Modify the hmac so it's safe to use in URLs.
   return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
 }
 
 /**
- * Calculate a base-64 encoded, URL-safe sha-256 hash.
+ * Calculates a base-64 encoded, URL-safe sha-256 hash.
  *
  * @param $data
  *   String to be hashed.
@@ -1977,7 +2375,8 @@
  * @see drupal_array_merge_deep_array()
  */
 function drupal_array_merge_deep() {
-  return drupal_array_merge_deep_array(func_get_args());
+  $args = func_get_args();
+  return drupal_array_merge_deep_array($args);
 }
 
 /**
@@ -2028,7 +2427,7 @@
  * @return Object - the user object.
  */
 function drupal_anonymous_user() {
-  $user = new stdClass();
+  $user = variable_get('drupal_anonymous_user_object', new stdClass);
   $user->uid = 0;
   $user->hostname = ip_address();
   $user->roles = array();
@@ -2038,20 +2437,34 @@
 }
 
 /**
- * A string describing a phase of Drupal to load. Each phase adds to the
- * previous one, so invoking a later phase automatically runs the earlier
- * phases too. The most important usage is that if you want to access the
- * Drupal database from a script without loading anything else, you can
- * include bootstrap.inc, and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
- *
- * @param $phase
- *   A constant. Allowed values are the DRUPAL_BOOTSTRAP_* constants.
- * @param $new_phase
+ * Ensures Drupal is bootstrapped to the specified phase.
+ *
+ * In order to bootstrap Drupal from another PHP script, you can use this code:
+ * @code
+ *   define('DRUPAL_ROOT', '/path/to/drupal');
+ *   require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+ *   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ * @endcode
+ *
+ * @param int $phase
+ *   A constant telling which phase to bootstrap to. When you bootstrap to a
+ *   particular phase, all earlier phases are run automatically. Possible
+ *   values:
+ *   - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
+ *   - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
+ *   - DRUPAL_BOOTSTRAP_DATABASE: Initializes the database layer.
+ *   - DRUPAL_BOOTSTRAP_VARIABLES: Initializes the variable system.
+ *   - DRUPAL_BOOTSTRAP_SESSION: Initializes session handling.
+ *   - DRUPAL_BOOTSTRAP_PAGE_HEADER: Sets up the page header.
+ *   - DRUPAL_BOOTSTRAP_LANGUAGE: Finds out the language of the page.
+ *   - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
+ *     data.
+ * @param boolean $new_phase
  *   A boolean, set to FALSE if calling drupal_bootstrap from inside a
  *   function called from drupal_bootstrap (recursion).
- * @return
- *   The most recently completed phase.
  *
+ * @return int
+ *   The most recently completed phase.
  */
 function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
   // Not drupal_static(), because does not depend on any run-time information.
@@ -2072,12 +2485,13 @@
   // bootstrap state.
   static $stored_phase = -1;
 
-  // When not recursing, store the phase name so it's not forgotten while
-  // recursing.
-  if ($new_phase) {
-    $final_phase = $phase;
-  }
   if (isset($phase)) {
+    // When not recursing, store the phase name so it's not forgotten while
+    // recursing but take care of not going backwards.
+    if ($new_phase && $phase >= $stored_phase) {
+      $final_phase = $phase;
+    }
+
     // Call a phase if it has not been called before and is below the requested
     // phase.
     while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
@@ -2130,7 +2544,7 @@
 }
 
 /**
- * Return the time zone of the current user.
+ * Returns the time zone of the current user.
  */
 function drupal_get_user_timezone() {
   global $user;
@@ -2145,7 +2559,20 @@
 }
 
 /**
- * Custom PHP error handler.
+ * Gets a salt useful for hardening against SQL injection.
+ *
+ * @return
+ *   A salt based on information in settings.php, not in the database.
+ */
+function drupal_get_hash_salt() {
+  global $drupal_hash_salt, $databases;
+  // If the $drupal_hash_salt variable is empty, a hash of the serialized
+  // database credentials is used as a fallback salt.
+  return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
+}
+
+/**
+ * Provides custom PHP error handling.
  *
  * @param $error_level
  *   The level of the error raised.
@@ -2156,7 +2583,8 @@
  * @param $line
  *   The line number the error was raised at.
  * @param $context
- *   An array that points to the active symbol table at the point the error occurred.
+ *   An array that points to the active symbol table at the point the error
+ *   occurred.
  */
 function _drupal_error_handler($error_level, $message, $filename, $line, $context) {
   require_once DRUPAL_ROOT . '/includes/errors.inc';
@@ -2164,7 +2592,7 @@
 }
 
 /**
- * Custom PHP exception handler.
+ * Provides custom PHP exception handling.
  *
  * Uncaught exceptions are those not enclosed in a try/catch block. They are
  * always fatal: the execution of the script will stop as soon as the exception
@@ -2192,7 +2620,7 @@
 }
 
 /**
- * Bootstrap configuration: Setup script environment and load settings.php.
+ * Sets up the script environment and loads settings.php.
  */
 function _drupal_bootstrap_configuration() {
   // Set the Drupal custom error handler.
@@ -2204,10 +2632,14 @@
   timer_start('page');
   // Initialize the configuration, including variables from settings.php.
   drupal_settings_initialize();
+
+  // Sanitize unsafe keys from the request.
+  require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc';
+  DrupalRequestSanitizer::sanitize();
 }
 
 /**
- * Bootstrap page cache: Try to serve a page from cache.
+ * Attempts to serve a page from the cache.
  */
 function _drupal_bootstrap_page_cache() {
   global $user;
@@ -2263,7 +2695,7 @@
 }
 
 /**
- * Bootstrap database: Initialize database system and register autoload functions.
+ * Initializes the database system and registers autoload functions.
  */
 function _drupal_bootstrap_database() {
   // Redirect the user to the installation script if Drupal has not been
@@ -2312,10 +2744,13 @@
   // the install or upgrade process.
   spl_autoload_register('drupal_autoload_class');
   spl_autoload_register('drupal_autoload_interface');
+  if (version_compare(PHP_VERSION, '5.4') >= 0) {
+    spl_autoload_register('drupal_autoload_trait');
+  }
 }
 
 /**
- * Bootstrap variables: Load system variables and all enabled bootstrap modules.
+ * Loads system variables and all enabled bootstrap modules.
  */
 function _drupal_bootstrap_variables() {
   global $conf;
@@ -2329,10 +2764,30 @@
   // Load bootstrap modules.
   require_once DRUPAL_ROOT . '/includes/module.inc';
   module_load_all(TRUE);
+
+  // Sanitize the destination parameter (which is often used for redirects) to
+  // prevent open redirect attacks leading to other domains. Sanitize both
+  // $_GET['destination'] and $_REQUEST['destination'] to protect code that
+  // relies on either, but do not sanitize $_POST to avoid interfering with
+  // unrelated form submissions. The sanitization happens here because
+  // url_is_external() requires the variable system to be available.
+  if (isset($_GET['destination']) || isset($_REQUEST['destination'])) {
+    require_once DRUPAL_ROOT . '/includes/common.inc';
+    // If the destination is an external URL, remove it.
+    if (isset($_GET['destination']) && url_is_external($_GET['destination'])) {
+      unset($_GET['destination']);
+      unset($_REQUEST['destination']);
+    }
+    // If there's still something in $_REQUEST['destination'] that didn't come
+    // from $_GET, check it too.
+    if (isset($_REQUEST['destination']) && (!isset($_GET['destination']) || $_REQUEST['destination'] != $_GET['destination']) && url_is_external($_REQUEST['destination'])) {
+      unset($_REQUEST['destination']);
+    }
+  }
 }
 
 /**
- * Bootstrap page header: Invoke hook_boot(), initialize locking system, and send default HTTP headers.
+ * Invokes hook_boot(), initializes locking system, and sends HTTP headers.
  */
 function _drupal_bootstrap_page_header() {
   bootstrap_invoke_all('boot');
@@ -2351,12 +2806,11 @@
  * @see drupal_bootstrap()
  */
 function drupal_get_bootstrap_phase() {
-  return drupal_bootstrap();
+  return drupal_bootstrap(NULL, FALSE);
 }
 
 /**
- * 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.
+ * Returns the test prefix if this is an internal request from SimpleTest.
  *
  * @return
  *   Either the simpletest prefix (the string "simpletest" followed by any
@@ -2364,7 +2818,6 @@
  *   HMAC and timestamp.
  */
 function drupal_valid_test_ua() {
-  global $drupal_hash_salt;
   // No reason to reset this.
   static $test_prefix;
 
@@ -2378,7 +2831,7 @@
     // 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__);
+    $key = drupal_get_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.
@@ -2388,21 +2841,21 @@
     }
   }
 
-  return FALSE;
+  $test_prefix = FALSE;
+  return $test_prefix;
 }
 
 /**
- * Generate a user agent string with a HMAC and timestamp for simpletest.
+ * Generates a user agent string with a HMAC and timestamp for simpletest.
  */
 function drupal_generate_test_ua($prefix) {
-  global $drupal_hash_salt;
   static $key;
 
   if (!isset($key)) {
     // 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__);
+    $key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
   }
   // Generate a moderately secure HMAC based on the database credentials.
   $salt = uniqid('', TRUE);
@@ -2443,7 +2896,7 @@
     $fast_paths = variable_get('404_fast_paths', FALSE);
     if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
       drupal_add_http_header('Status', '404 Not Found');
-      $fast_404_html = variable_get('404_fast_html', '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
+      $fast_404_html = variable_get('404_fast_html', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
       // Replace @path in the variable with the page path.
       print strtr($fast_404_html, array('@path' => check_plain(request_uri())));
       exit;
@@ -2452,7 +2905,7 @@
 }
 
 /**
- * Return TRUE if a Drupal installation is currently being attempted.
+ * Returns TRUE if a Drupal installation is currently being attempted.
  */
 function drupal_installation_attempted() {
   return defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'install';
@@ -2467,7 +2920,7 @@
  *
  * This would include implementations of hook_install(), which could run
  * during the Drupal installation phase, and might also be run during
- * non-installation time, such as while installing the module from the the
+ * non-installation time, such as while installing the module from the
  * module administration page.
  *
  * Example usage:
@@ -2495,10 +2948,9 @@
 }
 
 /**
- * Initialize all the defined language types.
+ * Initializes all the defined language types.
  */
 function drupal_language_initialize() {
-  global $language;
   $types = language_types();
 
   // Ensure the language is correctly returned, even without multilanguage
@@ -2518,13 +2970,10 @@
     // environments.
     bootstrap_invoke_all('language_init');
   }
-
-  // Send appropriate HTTP-Header for browsers and search engines.
-  header('Content-Language: ' . $language->language);
 }
 
 /**
- * The built-in language types.
+ * Returns a list of the built-in language types.
  *
  * @return
  *   An array of key-values pairs where the key is the language type and the
@@ -2539,7 +2988,10 @@
 }
 
 /**
- * Return true if there is more than one language enabled.
+ * Returns TRUE if there is more than one language enabled.
+ *
+ * @return
+ *   TRUE if more than one language is enabled.
  */
 function drupal_multilingual() {
   // The "language_count" variable stores the number of enabled languages to
@@ -2549,7 +3001,11 @@
 }
 
 /**
- * Return an array of the available language types.
+ * Returns an array of the available language types.
+ *
+ * @return
+ *   An array of all language types where the keys of each are the language type
+ *   name and its value is its configurability (TRUE/FALSE).
  */
 function language_types() {
   return array_keys(variable_get('language_types', drupal_language_types()));
@@ -2606,10 +3062,14 @@
 }
 
 /**
- * Default language used on the site
+ * Returns the default language, as an object, or one of its properties.
  *
  * @param $property
- *   Optional property of the language object to return
+ *   (optional) The property of the language object to return.
+ *
+ * @return
+ *   Either the language object for the default language used on the site,
+ *   or the property of that object named in the $property parameter.
  */
 function language_default($property = NULL) {
   $language = variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''));
@@ -2640,7 +3100,7 @@
     return $path;
   }
 
-  if (isset($_GET['q'])) {
+  if (isset($_GET['q']) && is_string($_GET['q'])) {
     // This is a request with a ?q=foo/bar query string. $_GET['q'] is
     // overwritten in drupal_path_initialize(), but request_path() is called
     // very early in the bootstrap process, so the original value is saved in
@@ -2676,16 +3136,16 @@
 }
 
 /**
- * Return a component of the current Drupal path.
+ * Returns a component of the current Drupal path.
  *
  * When viewing a page at the path "admin/structure/types", for example, arg(0)
  * returns "admin", arg(1) returns "structure", and arg(2) returns "types".
  *
- * Avoid use of this function where possible, as resulting code is hard to read.
- * In menu callback functions, attempt to use named arguments. See the explanation
- * in menu.inc for how to construct callbacks that take arguments. When attempting
- * to use this function to load an element from the current path, e.g. loading the
- * node on a node page, please use menu_get_object() instead.
+ * Avoid use of this function where possible, as resulting code is hard to
+ * read. In menu callback functions, attempt to use named arguments. See the
+ * explanation in menu.inc for how to construct callbacks that take arguments.
+ * When attempting to use this function to load an element from the current
+ * path, e.g. loading the node on a node page, use menu_get_object() instead.
  *
  * @param $index
  *   The index of the component, where each component is separated by a '/'
@@ -2725,6 +3185,8 @@
 }
 
 /**
+ * Returns the IP address of the client machine.
+ *
  * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
  * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of
  * the proxy server, and not the client's. The actual header name can be
@@ -2759,8 +3221,15 @@
         // Eliminate all trusted IPs.
         $untrusted = array_diff($forwarded, $reverse_proxy_addresses);
 
-        // The right-most IP is the most specific we can trust.
-        $ip_address = array_pop($untrusted);
+        if (!empty($untrusted)) {
+          // The right-most IP is the most specific we can trust.
+          $ip_address = array_pop($untrusted);
+        }
+        else {
+          // All IP addresses in the forwarded array are configured proxy IPs
+          // (and thus trusted). We take the leftmost IP.
+          $ip_address = array_shift($forwarded);
+        }
       }
     }
   }
@@ -2769,15 +3238,17 @@
 }
 
 /**
- * @ingroup schemaapi
+ * @addtogroup schemaapi
  * @{
  */
 
 /**
- * Get the schema definition of a table, or the whole database schema.
+ * Gets the schema definition of a table, or the whole database schema.
  *
  * The returned schema will include any modifications made by any
- * module that implements hook_schema_alter().
+ * module that implements hook_schema_alter(). To get the schema without
+ * modifications, use drupal_get_schema_unprocessed().
+ *
  *
  * @param $table
  *   The name of the table. If not given, the schema of all tables is returned.
@@ -2810,11 +3281,17 @@
  */
 class SchemaCache extends DrupalCacheArray {
 
+  /**
+   * Constructs a SchemaCache object.
+   */
   public function __construct() {
     // Cache by request method.
     parent::__construct('schema:runtime:' . ($_SERVER['REQUEST_METHOD'] == 'GET'), 'cache');
   }
 
+  /**
+   * Overrides DrupalCacheArray::resolveCacheMiss().
+   */
   protected function resolveCacheMiss($offset) {
     $complete_schema = drupal_get_complete_schema();
     $value = isset($complete_schema[$offset]) ? $complete_schema[$offset] :  NULL;
@@ -2825,7 +3302,7 @@
 }
 
 /**
- * Get the whole database schema.
+ * Gets the whole database schema.
  *
  * The returned schema will include any modifications made by any
  * module that implements hook_schema_alter().
@@ -2885,23 +3362,24 @@
 }
 
 /**
- * @} End of "ingroup schemaapi".
+ * @} End of "addtogroup schemaapi".
  */
 
 
 /**
- * @ingroup registry
+ * @addtogroup registry
  * @{
  */
 
 /**
- * Confirm that an interface is available.
+ * Confirms that an interface is available.
  *
  * This function is rarely called directly. Instead, it is registered as an
  * spl_autoload()  handler, and PHP calls it for us when necessary.
  *
  * @param $interface
  *   The name of the interface to check or load.
+ *
  * @return
  *   TRUE if the interface is currently available, FALSE otherwise.
  */
@@ -2910,13 +3388,14 @@
 }
 
 /**
- * Confirm that a class is available.
+ * Confirms that a class is available.
  *
  * This function is rarely called directly. Instead, it is registered as an
  * spl_autoload()  handler, and PHP calls it for us when necessary.
  *
  * @param $class
  *   The name of the class to check or load.
+ *
  * @return
  *   TRUE if the class is currently available, FALSE otherwise.
  */
@@ -2925,7 +3404,23 @@
 }
 
 /**
- * Helper to check for a resource in the registry.
+ * Confirms that a trait is available.
+ *
+ * This function is rarely called directly. Instead, it is registered as an
+ * spl_autoload() handler, and PHP calls it for us when necessary.
+ *
+ * @param string $trait
+ *   The name of the trait to check or load.
+ *
+ * @return bool
+ *   TRUE if the trait is currently available, FALSE otherwise.
+ */
+function drupal_autoload_trait($trait) {
+  return _registry_check_code('trait', $trait);
+}
+
+/**
+ * Checks for a resource in the registry.
  *
  * @param $type
  *   The type of resource we are looking up, or one of the constants
@@ -2934,6 +3429,7 @@
  * @param $name
  *   The name of the resource, or NULL if either of the REGISTRY_* constants
  *   is passed in.
+ *
  * @return
  *   TRUE if the resource was found, FALSE if not.
  *   NULL if either of the REGISTRY_* constants is passed in as $type.
@@ -2941,7 +3437,7 @@
 function _registry_check_code($type, $name = NULL) {
   static $lookup_cache, $cache_update_needed;
 
-  if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name)) {
+  if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name) || $type == 'trait' && trait_exists($name)) {
     return TRUE;
   }
 
@@ -2974,7 +3470,7 @@
   $cache_key = $type[0] . $name;
   if (isset($lookup_cache[$cache_key])) {
     if ($lookup_cache[$cache_key]) {
-      require_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
+      include_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
     }
     return (bool) $lookup_cache[$cache_key];
   }
@@ -2982,10 +3478,13 @@
   // This function may get called when the default database is not active, but
   // there is no reason we'd ever want to not use the default database for
   // this query.
-  $file = Database::getConnection('default', 'default')->query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array(
-      ':name' => $name,
-      ':type' => $type,
-    ))
+  $file = Database::getConnection('default', 'default')
+    ->select('registry', 'r', array('target' => 'default'))
+    ->fields('r', array('filename'))
+    // Use LIKE here to make the query case-insensitive.
+    ->condition('r.name', db_like($name), 'LIKE')
+    ->condition('r.type', $type)
+    ->execute()
     ->fetchField();
 
   // Flag that we've run a lookup query and need to update the cache.
@@ -2996,7 +3495,7 @@
   $lookup_cache[$cache_key] = $file;
 
   if ($file) {
-    require_once DRUPAL_ROOT . '/' . $file;
+    include_once DRUPAL_ROOT . '/' . $file;
     return TRUE;
   }
   else {
@@ -3005,7 +3504,7 @@
 }
 
 /**
- * Rescan all enabled modules and rebuild the registry.
+ * Rescans all enabled modules and rebuilds the registry.
  *
  * Rescans all code in modules or includes directories, storing the location of
  * each interface or class in the database.
@@ -3016,25 +3515,44 @@
 }
 
 /**
- * Update the registry based on the latest files listed in the database.
+ * Updates the registry based on the latest files listed in the database.
  *
  * This function should be used when system_rebuild_module_data() does not need
  * to be called, because it is already known that the list of files in the
  * {system} table matches those in the file system.
  *
+ * @return
+ *   TRUE if the registry was rebuilt, FALSE if another thread was rebuilding
+ *   in parallel and the current thread just waited for completion.
+ *
  * @see registry_rebuild()
  */
 function registry_update() {
+  // install_system_module() calls module_enable() which calls into this
+  // function during initial system installation, so the lock system is neither
+  // loaded nor does its storage exist yet.
+  $in_installer = drupal_installation_attempted();
+  if (!$in_installer && !lock_acquire(__FUNCTION__)) {
+    // Another request got the lock, wait for it to finish.
+    lock_wait(__FUNCTION__);
+    return FALSE;
+  }
+
   require_once DRUPAL_ROOT . '/includes/registry.inc';
   _registry_update();
+
+  if (!$in_installer) {
+    lock_release(__FUNCTION__);
+  }
+  return TRUE;
 }
 
 /**
- * @} End of "ingroup registry".
+ * @} End of "addtogroup registry".
  */
 
 /**
- * Central static variable storage.
+ * Provides central static variable storage.
  *
  * All functions requiring a static variable to persist or cache data within
  * a single page request are encouraged to use this function unless it is
@@ -3114,8 +3632,8 @@
  * However, the above line of code does not work, because PHP only allows static
  * variables to be initializied by literal values, and does not allow static
  * variables to be assigned to references.
- * - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static
- * - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.references
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.static
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.references
  * The example below shows the syntax needed to work around both limitations.
  * For benchmarks and more information, see http://drupal.org/node/619666.
  *
@@ -3140,11 +3658,9 @@
  * @param $default_value
  *   Optional default value.
  * @param $reset
- *   TRUE to reset a specific named variable, or all variables if $name is NULL.
- *   Resetting every variable should only be used, for example, for running
- *   unit tests with a clean environment. Should be used only though via
- *   function drupal_static_reset() and the return value should not be used in
- *   this case.
+ *   TRUE to reset one or all variables(s). This parameter is only used
+ *   internally and should not be passed in; use drupal_static_reset() instead.
+ *   (This function's return value should not be used when TRUE is passed in.)
  *
  * @return
  *   Returns a variable by reference.
@@ -3185,17 +3701,19 @@
 }
 
 /**
- * Reset one or all centrally stored static variable(s).
+ * Resets one or all centrally stored static variable(s).
  *
  * @param $name
  *   Name of the static variable to reset. Omit to reset all variables.
+ *   Resetting all variables should only be used, for example, for running unit
+ *   tests with a clean environment.
  */
 function drupal_static_reset($name = NULL) {
   drupal_static($name, NULL, TRUE);
 }
 
 /**
- * Detect whether the current script is running in a command-line environment.
+ * Detects whether the current script is running in a command-line environment.
  */
 function drupal_is_cli() {
   return (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
@@ -3203,7 +3721,8 @@
 
 /**
  * Formats text for emphasized display in a placeholder inside a sentence.
- * Used automatically by t().
+ *
+ * Used automatically by format_string().
  *
  * @param $text
  *   The text to format (plain-text).
@@ -3216,7 +3735,7 @@
 }
 
 /**
- * Register a function for execution on shutdown.
+ * Registers a function for execution on shutdown.
  *
  * Wrapper for register_shutdown_function() that catches thrown exceptions to
  * avoid "Exception thrown without a stack frame in Unknown".
@@ -3251,7 +3770,7 @@
 }
 
 /**
- * Internal function used to execute registered shutdown functions.
+ * Executes registered shutdown functions.
  */
 function _drupal_shutdown_function() {
   $callbacks = &drupal_register_shutdown_function();
@@ -3274,3 +3793,63 @@
     }
   }
 }
+
+/**
+ * Compares the memory required for an operation to the available memory.
+ *
+ * @param $required
+ *   The memory required for the operation, expressed as a number of bytes with
+ *   optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8bytes,
+ *   9mbytes).
+ * @param $memory_limit
+ *   (optional) The memory limit for the operation, expressed as a number of
+ *   bytes with optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G,
+ *   6GiB, 8bytes, 9mbytes). If no value is passed, the current PHP
+ *   memory_limit will be used. Defaults to NULL.
+ *
+ * @return
+ *   TRUE if there is sufficient memory to allow the operation, or FALSE
+ *   otherwise.
+ */
+function drupal_check_memory_limit($required, $memory_limit = NULL) {
+  if (!isset($memory_limit)) {
+    $memory_limit = ini_get('memory_limit');
+  }
+
+  // There is sufficient memory if:
+  // - No memory limit is set.
+  // - The memory limit is set to unlimited (-1).
+  // - The memory limit is greater than the memory required for the operation.
+  return ((!$memory_limit) || ($memory_limit == -1) || (parse_size($memory_limit) >= parse_size($required)));
+}
+
+/**
+ * Invalidates a PHP file from any active opcode caches.
+ *
+ * If the opcode cache does not support the invalidation of individual files,
+ * the entire cache will be flushed.
+ *
+ * @param string $filepath
+ *   The absolute path of the PHP file to invalidate.
+ */
+function drupal_clear_opcode_cache($filepath) {
+  if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
+    // Below PHP 5.3, clearstatcache does not accept any function parameters.
+    clearstatcache();
+  }
+  else {
+    clearstatcache(TRUE, $filepath);
+  }
+
+  // Zend OPcache.
+  if (function_exists('opcache_invalidate')) {
+    opcache_invalidate($filepath, TRUE);
+  }
+  // APC.
+  if (function_exists('apc_delete_file')) {
+    // apc_delete_file() throws a PHP warning in case the specified file was
+    // not compiled yet.
+    // @see http://php.net/apc-delete-file
+    @apc_delete_file($filepath);
+  }
+}
diff -Naur drupal-7.9/includes/cache-install.inc drupal-7.58/includes/cache-install.inc
--- drupal-7.9/includes/cache-install.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/cache-install.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * A stub cache implementation to be used during the installation process.
+ * Defines a stub cache implementation to be used during installation.
  *
  * The stub implementation is needed when database access is not yet available.
  * Because Drupal's caching system never requires that cached data be present,
@@ -15,17 +15,30 @@
  * normal operations would have a negative impact on performance.
  */
 class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterface {
+
+  /**
+   * Overrides DrupalDatabaseCache::get().
+   */
   function get($cid) {
     return FALSE;
   }
 
+  /**
+   * Overrides DrupalDatabaseCache::getMultiple().
+   */
   function getMultiple(&$cids) {
     return array();
   }
 
+  /**
+   * Overrides DrupalDatabaseCache::set().
+   */
   function set($cid, $data, $expire = CACHE_PERMANENT) {
   }
 
+  /**
+   * Overrides DrupalDatabaseCache::clear().
+   */
   function clear($cid = NULL, $wildcard = FALSE) {
     // If there is a database cache, attempt to clear it whenever possible. The
     // reason for doing this is that the database cache can accumulate data
@@ -52,6 +65,9 @@
     }
   }
 
+  /**
+   * Overrides DrupalDatabaseCache::isEmpty().
+   */
   function isEmpty() {
     return TRUE;
   }
diff -Naur drupal-7.9/includes/cache.inc drupal-7.58/includes/cache.inc
--- drupal-7.9/includes/cache.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/cache.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,18 +1,24 @@
 <?php
 
 /**
- * Get the cache object for a cache bin.
+ * @file
+ * Functions and interfaces for cache handling.
+ */
+
+/**
+ * Gets the cache object for a cache bin.
  *
  * By default, this returns an instance of the DrupalDatabaseCache class.
  * Classes implementing DrupalCacheInterface can register themselves both as a
  * default implementation and for specific bins.
  *
- * @see DrupalCacheInterface
- *
  * @param $bin
  *   The cache bin for which the cache object should be returned.
+ *
  * @return DrupalCacheInterface
  *   The cache object associated with the specified bin.
+ *
+ * @see DrupalCacheInterface
  */
 function _cache_get_object($bin) {
   // We do not use drupal_static() here because we do not want to change the
@@ -29,7 +35,7 @@
 }
 
 /**
- * Return data from the persistent cache
+ * Returns data from the persistent cache.
  *
  * Data may be stored as either plain text or as serialized data. cache_get
  * will automatically return unserialized objects and arrays.
@@ -44,19 +50,22 @@
  *
  * @return
  *   The cache or FALSE on failure.
+ *
+ * @see cache_set()
  */
 function cache_get($cid, $bin = 'cache') {
   return _cache_get_object($bin)->get($cid);
 }
 
 /**
- * Return data from the persistent cache when given an array of cache IDs.
+ * Returns data from the persistent cache when given an array of cache IDs.
  *
  * @param $cids
  *   An array of cache IDs for the data to retrieve. This is passed by
  *   reference, and will have the IDs successfully returned from cache removed.
  * @param $bin
  *   The cache bin where the data is stored.
+ *
  * @return
  *   An array of the items successfully returned from cache indexed by cid.
  */
@@ -65,50 +74,22 @@
 }
 
 /**
- * Store data in the persistent cache.
+ * Stores data in the persistent cache.
  *
  * The persistent cache is split up into several cache bins. In the default
  * cache implementation, each cache bin corresponds to a database table by the
  * same name. Other implementations might want to store several bins in data
  * structures that get flushed together. While it is not a problem for most
  * cache bins if the entries in them are flushed before their expire time, some
- * might break functionality or are extremely expensive to recalculate. These
- * will be marked with a (*). The other bins expired automatically by core.
- * Contributed modules can add additional bins and get them expired
- * automatically by implementing hook_flush_caches().
- *
- *  - cache: Generic cache storage bin (used for variables, theme registry,
- *  locale date, list of simpletest tests etc).
- *
- *  - cache_block: Stores the content of various blocks.
- *
- *  - cache field: Stores the field data belonging to a given object.
- *
- *  - cache_filter: Stores filtered pieces of content.
- *
- *  - cache_form(*): Stores multistep forms. Flushing this bin means that some
- *  forms displayed to users lose their state and the data already submitted
- *  to them.
- *
- *  - cache_menu: Stores the structure of visible navigation menus per page.
- *
- *  - cache_page: Stores generated pages for anonymous users. It is flushed
- *  very often, whenever a page changes, at least for every ode and comment
- *  submission. This is the only bin affected by the page cache setting on
- *  the administrator panel.
- *
- *  - cache path: Stores the system paths that have an alias.
- *
- *  - cache update(*): Stores available releases. The update server (for
- *  example, drupal.org) needs to produce the relevant XML for every project
- *  installed on the current site. As this is different for (almost) every
- *  site, it's very expensive to recalculate for the update server.
+ * might break functionality or are extremely expensive to recalculate. The
+ * other bins are expired automatically by core. Contributed modules can add
+ * additional bins and get them expired automatically by implementing
+ * hook_flush_caches().
  *
  * The reasons for having several bins are as follows:
- *
- * - smaller bins mean smaller database tables and allow for faster selects and
- *   inserts
- * - we try to put fast changing cache items and rather static ones into
+ * - Smaller bins mean smaller database tables and allow for faster selects and
+ *   inserts.
+ * - We try to put fast changing cache items and rather static ones into
  *   different bins. The effect is that only the fast changing bins will need a
  *   lot of writes to disk. The more static bins will also be better cacheable
  *   with MySQL's query cache.
@@ -117,44 +98,67 @@
  *   The cache ID of the data to store.
  * @param $data
  *   The data to store in the cache. Complex data types will be automatically
- *   serialized before insertion.
- *   Strings will be stored as plain text and not serialized.
+ *   serialized before insertion. Strings will be stored as plain text and are
+ *   not serialized. Some storage engines only allow objects up to a maximum of
+ *   1MB in size to be stored by default. When caching large arrays or similar,
+ *   take care to ensure $data does not exceed this size.
  * @param $bin
- *   The cache bin to store the data in. Valid core values are 'cache_block',
- *   'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
- *   'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default
- *   cache.
+ *   (optional) The cache bin to store the data in. Valid core values are:
+ *   - cache: (default) Generic cache storage bin (used for theme registry,
+ *     locale date, list of simpletest tests, etc.).
+ *   - cache_block: Stores the content of various blocks.
+ *   - cache_bootstrap: Stores the class registry, the system list of modules,
+ *     the list of which modules implement which hooks, and the Drupal variable
+ *     list.
+ *   - cache_field: Stores the field data belonging to a given object.
+ *   - cache_filter: Stores filtered pieces of content.
+ *   - cache_form: Stores multistep forms. Flushing this bin means that some
+ *     forms displayed to users lose their state and the data already submitted
+ *     to them. This bin should not be flushed before its expired time.
+ *   - cache_menu: Stores the structure of visible navigation menus per page.
+ *   - cache_page: Stores generated pages for anonymous users. It is flushed
+ *     very often, whenever a page changes, at least for every node and comment
+ *     submission. This is the only bin affected by the page cache setting on
+ *     the administrator panel.
+ *   - cache_path: Stores the system paths that have an alias.
  * @param $expire
- *   One of the following values:
+ *   (optional) Controls the maximum lifetime of this cache entry. Note that
+ *   caches might be subject to clearing at any time, so this setting does not
+ *   guarantee a minimum lifetime. With this in mind, the cache should not be
+ *   used for data that must be kept during a cache clear, like sessions.
+ *
+ *   Use one of the following values:
  *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
  *     explicitly told to using cache_clear_all() with a cache ID.
  *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
  *     general cache wipe.
  *   - A Unix timestamp: Indicates that the item should be kept at least until
  *     the given time, after which it behaves like CACHE_TEMPORARY.
+ *
+ * @see _update_cache_set()
+ * @see cache_get()
  */
 function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
   return _cache_get_object($bin)->set($cid, $data, $expire);
 }
 
 /**
- * Expire data from the cache.
+ * Expires data from the cache.
  *
- * If called without arguments, expirable entries will be cleared from the
- * cache_page and cache_block bins.
+ * If called with the arguments $cid and $bin set to NULL or omitted, then
+ * expirable entries will be cleared from the cache_page and cache_block bins,
+ * and the $wildcard argument is ignored.
  *
  * @param $cid
- *   If set, the cache ID to delete. Otherwise, all cache entries that can
- *   expire are deleted.
- *
+ *   If set, the cache ID or an array of cache IDs. Otherwise, all cache entries
+ *   that can expire are deleted. The $wildcard argument will be ignored if set
+ *   to NULL.
  * @param $bin
- *   If set, the bin $bin to delete from. Mandatory
- *   argument if $cid is set.
- *
+ *   If set, the cache bin to delete from. Mandatory argument if $cid is set.
  * @param $wildcard
- *   If $wildcard is TRUE, cache IDs starting with $cid are deleted in
- *   addition to the exact cache ID specified by $cid.  If $wildcard is
- *   TRUE and $cid is '*' then the entire bin $bin is emptied.
+ *   If TRUE, the $cid argument must contain a string value and cache IDs
+ *   starting with $cid are deleted in addition to the exact cache ID specified
+ *   by $cid. If $wildcard is TRUE and $cid is '*', the entire cache is emptied.
  */
 function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
   if (!isset($cid) && !isset($bin)) {
@@ -170,13 +174,14 @@
 }
 
 /**
- * Check if a cache bin is empty.
+ * Checks if a cache bin is empty.
  *
  * A cache bin is considered empty if it does not contain any valid data for any
  * cache ID.
  *
  * @param $bin
  *   The cache bin to check.
+ *
  * @return
  *   TRUE if the cache bin specified is empty.
  */
@@ -185,7 +190,7 @@
 }
 
 /**
- * Interface for cache implementations.
+ * Defines an interface for cache implementations.
  *
  * All cache implementations have to implement this interface.
  * DrupalDatabaseCache provides the default implementation, which can be
@@ -222,49 +227,52 @@
  * @see DrupalDatabaseCache
  */
 interface DrupalCacheInterface {
-  /**
-   * Constructor.
-   *
-   * @param $bin
-   *   The cache bin for which the object is created.
-   */
-  function __construct($bin);
 
   /**
-   * Return data from the persistent cache. Data may be stored as either plain
-   * text or as serialized data. cache_get will automatically return
-   * unserialized objects and arrays.
+   * Returns data from the persistent cache.
+   *
+   * Data may be stored as either plain text or as serialized data. cache_get()
+   * will automatically return unserialized objects and arrays.
    *
    * @param $cid
    *   The cache ID of the data to retrieve.
+   *
    * @return
    *   The cache or FALSE on failure.
    */
   function get($cid);
 
   /**
-   * Return data from the persistent cache when given an array of cache IDs.
+   * Returns data from the persistent cache when given an array of cache IDs.
    *
    * @param $cids
    *   An array of cache IDs for the data to retrieve. This is passed by
    *   reference, and will have the IDs successfully returned from cache
    *   removed.
+   *
    * @return
    *   An array of the items successfully returned from cache indexed by cid.
    */
    function getMultiple(&$cids);
 
   /**
-   * Store data in the persistent cache.
+   * Stores data in the persistent cache.
    *
    * @param $cid
    *   The cache ID of the data to store.
    * @param $data
    *   The data to store in the cache. Complex data types will be automatically
-   *   serialized before insertion.
-   *   Strings will be stored as plain text and not serialized.
+   *   serialized before insertion. Strings will be stored as plain text and not
+   *   serialized. Some storage engines only allow objects up to a maximum of
+   *   1MB in size to be stored by default. When caching large arrays or
+   *   similar, take care to ensure $data does not exceed this size.
    * @param $expire
-   *   One of the following values:
+   *   (optional) Controls the maximum lifetime of this cache entry. Note that
+   *   caches might be subject to clearing at any time, so this setting does not
+   *   guarantee a minimum lifetime. With this in mind, the cache should not be
+   *   used for data that must be kept during a cache clear, like sessions.
+   *
+   *   Use one of the following values:
    *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
    *     explicitly told to using cache_clear_all() with a cache ID.
    *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
@@ -276,21 +284,25 @@
 
 
   /**
-   * Expire data from the cache. If called without arguments, expirable
-   * entries will be cleared from the cache_page and cache_block bins.
+   * Expires data from the cache.
+   *
+   * If called without arguments, expirable entries will be cleared from the
+   * cache_page and cache_block bins.
    *
    * @param $cid
-   *   If set, the cache ID to delete. Otherwise, all cache entries that can
-   *   expire are deleted.
+   *   If set, the cache ID or an array of cache IDs. Otherwise, all cache
+   *   entries that can expire are deleted. The $wildcard argument will be
+   *   ignored if set to NULL.
    * @param $wildcard
-   *   If set to TRUE, the $cid is treated as a substring
-   *   to match rather than a complete ID. The match is a right hand
-   *   match. If '*' is given as $cid, the bin $bin will be emptied.
+   *   If TRUE, the $cid argument must contain a string value and cache IDs
+   *   starting with $cid are deleted in addition to the exact cache ID
+   *   specified by $cid. If $wildcard is TRUE and $cid is '*', the entire
+   *   cache is emptied.
    */
   function clear($cid = NULL, $wildcard = FALSE);
 
   /**
-   * Check if a cache bin is empty.
+   * Checks if a cache bin is empty.
    *
    * A cache bin is considered empty if it does not contain any valid data for
    * any cache ID.
@@ -302,7 +314,7 @@
 }
 
 /**
- * Default cache implementation.
+ * Defines a default cache implementation.
  *
  * This is Drupal's default cache implementation. It uses the database to store
  * cached data. Each cache bin corresponds to a database table by the same name.
@@ -310,16 +322,28 @@
 class DrupalDatabaseCache implements DrupalCacheInterface {
   protected $bin;
 
+  /**
+   * Constructs a DrupalDatabaseCache object.
+   *
+   * @param $bin
+   *   The cache bin for which the object is created.
+   */
   function __construct($bin) {
     $this->bin = $bin;
   }
 
+  /**
+   * Implements DrupalCacheInterface::get().
+   */
   function get($cid) {
     $cids = array($cid);
     $cache = $this->getMultiple($cids);
     return reset($cache);
   }
 
+  /**
+   * Implements DrupalCacheInterface::getMultiple().
+   */
   function getMultiple(&$cids) {
     try {
       // Garbage collection necessary when enforcing a minimum cache lifetime.
@@ -357,11 +381,31 @@
    *   The bin being requested.
    */
   protected function garbageCollection() {
-    global $user;
+    $cache_lifetime = variable_get('cache_lifetime', 0);
 
-    // Garbage collection necessary when enforcing a minimum cache lifetime.
+    // Clean-up the per-user cache expiration session data, so that the session
+    // handler can properly clean-up the session data for anonymous users.
+    if (isset($_SESSION['cache_expiration'])) {
+      $expire = REQUEST_TIME - $cache_lifetime;
+      foreach ($_SESSION['cache_expiration'] as $bin => $timestamp) {
+        if ($timestamp < $expire) {
+          unset($_SESSION['cache_expiration'][$bin]);
+        }
+      }
+      if (!$_SESSION['cache_expiration']) {
+        unset($_SESSION['cache_expiration']);
+      }
+    }
+
+    // Garbage collection of temporary items is only necessary when enforcing
+    // a minimum cache lifetime.
+    if (!$cache_lifetime) {
+      return;
+    }
+    // When cache lifetime is in force, avoid running garbage collection too
+    // often since this will remove temporary cache items indiscriminately.
     $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
-    if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
+    if ($cache_flush && ($cache_flush + $cache_lifetime <= REQUEST_TIME)) {
       // Reset the variable immediately to prevent a meltdown in heavy load situations.
       variable_set('cache_flush_' . $this->bin, 0);
       // Time to flush old cache data
@@ -373,13 +417,14 @@
   }
 
   /**
-   * Prepare a cached item.
+   * Prepares a cached item.
    *
    * Checks that items are either permanent or did not expire, and unserializes
    * data as appropriate.
    *
    * @param $cache
    *   An item loaded from cache_get() or cache_get_multiple().
+   *
    * @return
    *   The item with data unserialized as appropriate or FALSE if there is no
    *   valid item to load.
@@ -390,17 +435,16 @@
     if (!isset($cache->data)) {
       return FALSE;
     }
-    // If enforcing a minimum cache lifetime, validate that the data is
-    // currently valid for this user before we return it by making sure the cache
-    // entry was created before the timestamp in the current session's cache
-    // timer. The cache variable is loaded into the $user object by _drupal_session_read()
-    // in session.inc. If the data is permanent or we're not enforcing a minimum
-    // cache lifetime always return the cached data.
-    if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && $user->cache > $cache->created) {
-      // This cache data is too old and thus not valid for us, ignore it.
+    // If the cached data is temporary and subject to a per-user minimum
+    // lifetime, compare the cache entry timestamp with the user session
+    // cache_expiration timestamp. If the cache entry is too old, ignore it.
+    if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin]) && $_SESSION['cache_expiration'][$this->bin] > $cache->created) {
+      // Ignore cache data that is too old and thus not valid for this user.
       return FALSE;
     }
 
+    // If the data is permanent or not subject to a minimum cache lifetime,
+    // unserialize and return the cached data.
     if ($cache->serialized) {
       $cache->data = unserialize($cache->data);
     }
@@ -408,6 +452,9 @@
     return $cache;
   }
 
+  /**
+   * Implements DrupalCacheInterface::set().
+   */
   function set($cid, $data, $expire = CACHE_PERMANENT) {
     $fields = array(
       'serialized' => 0,
@@ -434,16 +481,18 @@
     }
   }
 
+  /**
+   * Implements DrupalCacheInterface::clear().
+   */
   function clear($cid = NULL, $wildcard = FALSE) {
     global $user;
 
     if (empty($cid)) {
       if (variable_get('cache_lifetime', 0)) {
-        // We store the time in the current user's $user->cache variable which
-        // will be saved into the sessions bin by _drupal_session_write(). We then
-        // simulate that the cache was flushed for this user by not returning
-        // cached data that was cached before the timestamp.
-        $user->cache = REQUEST_TIME;
+        // We store the time in the current user's session. We then simulate
+        // that the cache was flushed for this user by not returning cached
+        // data that was cached before the timestamp.
+        $_SESSION['cache_expiration'][$this->bin] = REQUEST_TIME;
 
         $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
         if ($cache_flush == 0) {
@@ -471,7 +520,16 @@
     else {
       if ($wildcard) {
         if ($cid == '*') {
-          db_truncate($this->bin)->execute();
+          // Check if $this->bin is a cache table before truncating. Other
+          // cache_clear_all() operations throw a PDO error in this situation,
+          // so we don't need to verify them first. This ensures that non-cache
+          // tables cannot be truncated accidentally.
+          if ($this->isValidBin()) {
+            db_truncate($this->bin)->execute();
+          }
+          else {
+            throw new Exception(t('Invalid or missing cache bin specified: %bin', array('%bin' => $this->bin)));
+          }
         }
         else {
           db_delete($this->bin)
@@ -496,6 +554,9 @@
     }
   }
 
+  /**
+   * Implements DrupalCacheInterface::isEmpty().
+   */
   function isEmpty() {
     $this->garbageCollection();
     $query = db_select($this->bin);
@@ -505,4 +566,25 @@
       ->fetchField();
     return empty($result);
   }
+
+  /**
+   * Checks if $this->bin represents a valid cache table.
+   *
+   * This check is required to ensure that non-cache tables are not truncated
+   * accidentally when calling cache_clear_all().
+   *
+   * @return boolean
+   */
+  function isValidBin() {
+    if ($this->bin == 'cache' || substr($this->bin, 0, 6) == 'cache_') {
+      // Skip schema check for bins with standard table names.
+      return TRUE;
+    }
+    // These fields are required for any cache table.
+    $fields = array('cid', 'data', 'expire', 'created', 'serialized');
+    // Load the table schema.
+    $schema = drupal_get_schema($this->bin);
+    // Confirm that all fields are present.
+    return isset($schema['fields']) && !array_diff($fields, array_keys($schema['fields']));
+  }
 }
diff -Naur drupal-7.9/includes/common.inc drupal-7.58/includes/common.inc
--- drupal-7.9/includes/common.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/common.inc	2018-03-27 21:28:19.000000000 +0200
@@ -70,8 +70,7 @@
 define('CSS_THEME', 100);
 
 /**
- * The default group for JavaScript libraries, settings or jQuery plugins added
- * to the page.
+ * The default group for JavaScript and jQuery libraries added to the page.
  */
 define('JS_LIBRARY', -100);
 
@@ -86,20 +85,27 @@
 define('JS_THEME', 100);
 
 /**
- * Error code indicating that the request made by drupal_http_request() exceeded
- * the specified timeout.
+ * Error code indicating that the request exceeded the specified timeout.
+ *
+ * @see drupal_http_request()
  */
 define('HTTP_REQUEST_TIMEOUT', -1);
 
 /**
- * Constants defining cache granularity for blocks and renderable arrays.
+ * @defgroup block_caching Block Caching
+ * @{
+ * Constants that define each block's caching state.
  *
- * Modules specify the caching patterns for their blocks using binary
- * combinations of these constants in their hook_block_info():
- *   $block[delta]['cache'] = DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE;
- * DRUPAL_CACHE_PER_ROLE is used as a default when no caching pattern is
- * specified. Use DRUPAL_CACHE_CUSTOM to disable standard block cache and
- * implement
+ * Modules specify how their blocks can be cached in their hook_block_info()
+ * implementations. Caching can be turned off (DRUPAL_NO_CACHE), managed by the
+ * module declaring the block (DRUPAL_CACHE_CUSTOM), or managed by the core
+ * Block module. If the Block module is managing the cache, you can specify that
+ * the block is the same for every page and user (DRUPAL_CACHE_GLOBAL), or that
+ * it can change depending on the page (DRUPAL_CACHE_PER_PAGE) or by user
+ * (DRUPAL_CACHE_PER_ROLE or DRUPAL_CACHE_PER_USER). Page and user settings can
+ * be combined with a bitwise-binary or operator; for example,
+ * DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE means that the block can change
+ * depending on the user role or page it is on.
  *
  * The block cache is cleared in cache_clear_all(), and uses the same clearing
  * policy than page cache (node, comment, user, taxonomy added or updated...).
@@ -110,31 +116,35 @@
  */
 
 /**
- * The block should not get cached. This setting should be used:
- * - for simple blocks (notably those that do not perform any db query),
- * where querying the db cache would be more expensive than directly generating
- * the content.
- * - for blocks that change too frequently.
+ * The block should not get cached.
+ *
+ * This setting should be used:
+ * - For simple blocks (notably those that do not perform any db query), where
+ *   querying the db cache would be more expensive than directly generating the
+ *   content.
+ * - For blocks that change too frequently.
  */
 define('DRUPAL_NO_CACHE', -1);
 
 /**
- * The block is handling its own caching in its hook_block_view(). From the
- * perspective of the block cache system, this is equivalent to DRUPAL_NO_CACHE.
- * Useful when time based expiration is needed or a site uses a node access
- * which invalidates standard block cache.
+ * The block is handling its own caching in its hook_block_view().
+ *
+ * This setting is useful when time based expiration is needed or a site uses a
+ * node access which invalidates standard block cache.
  */
 define('DRUPAL_CACHE_CUSTOM', -2);
 
 /**
- * The block or element can change depending on the roles the user viewing the
- * page belongs to. This is the default setting for blocks, used when the block
- * does not specify anything.
+ * The block or element can change depending on the user's roles.
+ *
+ * This is the default setting for blocks, used when the block does not specify
+ * anything.
  */
 define('DRUPAL_CACHE_PER_ROLE', 0x0001);
 
 /**
- * The block or element can change depending on the user viewing the page.
+ * The block or element can change depending on the user.
+ *
  * This setting can be resource-consuming for sites with large number of users,
  * and thus should only be used when DRUPAL_CACHE_PER_ROLE is not sufficient.
  */
@@ -146,12 +156,16 @@
 define('DRUPAL_CACHE_PER_PAGE', 0x0004);
 
 /**
- * The block or element is the same for every user on every page where it is visible.
+ * The block or element is the same for every user and page that it is visible.
  */
 define('DRUPAL_CACHE_GLOBAL', 0x0008);
 
 /**
- * Add content to a specified region.
+ * @} End of "defgroup block_caching".
+ */
+
+/**
+ * Adds content to a specified region.
  *
  * @param $region
  *   Page region the content is added to.
@@ -168,7 +182,7 @@
 }
 
 /**
- * Get assigned content for a given region.
+ * Gets assigned content for a given region.
  *
  * @param $region
  *   A specified region to fetch content for. If NULL, all regions will be
@@ -194,16 +208,16 @@
 }
 
 /**
- * Get the name of the currently active install profile.
+ * Gets the name of the currently active installation profile.
  *
  * When this function is called during Drupal's initial installation process,
  * the name of the profile that's about to be installed is stored in the global
  * installation state. At all other times, the standard Drupal systems variable
- * table contains the name of the current profile, and we can call variable_get()
- * to determine what one is active.
+ * table contains the name of the current profile, and we can call
+ * variable_get() to determine what one is active.
  *
  * @return $profile
- *   The name of the install profile.
+ *   The name of the installation profile.
  */
 function drupal_get_profile() {
   global $install_state;
@@ -220,7 +234,7 @@
 
 
 /**
- * Set the breadcrumb trail for the current page.
+ * Sets the breadcrumb trail for the current page.
  *
  * @param $breadcrumb
  *   Array of links, starting with "home" and proceeding up to but not including
@@ -236,7 +250,7 @@
 }
 
 /**
- * Get the breadcrumb trail for the current page.
+ * Gets the breadcrumb trail for the current page.
  */
 function drupal_get_breadcrumb() {
   $breadcrumb = drupal_set_breadcrumb();
@@ -265,9 +279,9 @@
 }
 
 /**
- * Add output to the head tag of the HTML page.
+ * Adds output to the HEAD tag of the HTML page.
  *
- * This function can be called as long the headers aren't sent. Pass no
+ * This function can be called as long as the headers aren't sent. Pass no
  * arguments (or NULL for both) to retrieve the currently stored elements.
  *
  * @param $data
@@ -333,7 +347,7 @@
 }
 
 /**
- * Retrieve output to be displayed in the HEAD tag of the HTML page.
+ * Retrieves output to be displayed in the HEAD tag of the HTML page.
  */
 function drupal_get_html_head() {
   $elements = drupal_add_html_head();
@@ -342,7 +356,7 @@
 }
 
 /**
- * Add a feed URL for the current page.
+ * Adds a feed URL for the current page.
  *
  * This function can be called as long the HTML header hasn't been sent.
  *
@@ -370,7 +384,7 @@
 }
 
 /**
- * Get the feed URLs for the current page.
+ * Gets the feed URLs for the current page.
  *
  * @param $delimiter
  *   A delimiter to split feeds by.
@@ -387,7 +401,7 @@
  */
 
 /**
- * Process a URL query parameter array to remove unwanted elements.
+ * Processes a URL query parameter array to remove unwanted elements.
  *
  * @param $query
  *   (optional) An array to be processed. Defaults to $_GET.
@@ -432,19 +446,19 @@
 }
 
 /**
- * Split an URL-encoded query string into an array.
+ * Splits a URL-encoded query string into an array.
  *
  * @param $query
  *   The query string to split.
  *
  * @return
- *   An array of url decoded couples $param_name => $value.
+ *   An array of URL decoded couples $param_name => $value.
  */
 function drupal_get_query_array($query) {
   $result = array();
   if (!empty($query)) {
     foreach (explode('&', $query) as $param) {
-      $param = explode('=', $param);
+      $param = explode('=', $param, 2);
       $result[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
     }
   }
@@ -452,7 +466,7 @@
 }
 
 /**
- * Parse an array into a valid, rawurlencoded query string.
+ * Parses an array into a valid, rawurlencoded query string.
  *
  * This differs from http_build_query() as we need to rawurlencode() (instead of
  * urlencode()) all query parameters.
@@ -473,7 +487,7 @@
   $params = array();
 
   foreach ($query as $key => $value) {
-    $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
+    $key = $parent ? $parent . rawurlencode('[' . $key . ']') : rawurlencode($key);
 
     // Recurse into children.
     if (is_array($value)) {
@@ -493,13 +507,19 @@
 }
 
 /**
- * Prepare a 'destination' URL query parameter for use in combination with drupal_goto().
+ * Prepares a 'destination' URL query parameter for use with drupal_goto().
  *
  * Used to direct the user back to the referring page after completing a form.
  * By default the current URL is returned. If a destination exists in the
  * previous request, that destination is returned. As such, a destination can
  * persist across multiple pages.
  *
+ * @return
+ *   An associative array containing the key:
+ *   - destination: The path provided via the destination query string or, if
+ *     not available, the current path.
+ *
+ * @see current_path()
  * @see drupal_goto()
  */
 function drupal_get_destination() {
@@ -524,37 +544,32 @@
 }
 
 /**
- * Wrapper around parse_url() to parse a system URL string into an associative array, suitable for url().
+ * Parses a URL string into its path, query, and fragment components.
  *
- * This function should only be used for URLs that have been generated by the
- * system, resp. url(). It should not be used for URLs that come from external
- * sources, or URLs that link to external resources.
+ * This function splits both internal paths like @code node?b=c#d @endcode and
+ * external URLs like @code https://example.com/a?b=c#d @endcode into their
+ * component parts. See
+ * @link http://tools.ietf.org/html/rfc3986#section-3 RFC 3986 @endlink for an
+ * explanation of what the component parts are.
  *
- * The returned array contains a 'path' that may be passed separately to url().
- * For example:
- * @code
- *   $options = drupal_parse_url($_GET['destination']);
- *   $my_url = url($options['path'], $options);
- *   $my_link = l('Example link', $options['path'], $options);
- * @endcode
+ * Note that, unlike the RFC, when passed an external URL, this function
+ * groups the scheme, authority, and path together into the path component.
  *
- * This is required, because url() does not support relative URLs containing a
- * query string or fragment in its $path argument. Instead, any query string
- * needs to be parsed into an associative query parameter array in
- * $options['query'] and the fragment into $options['fragment'].
- *
- * @param $url
- *   The URL string to parse, f.e. $_GET['destination'].
+ * @param string $url
+ *   The internal path or external URL string to parse.
  *
- * @return
- *   An associative array containing the keys:
- *   - 'path': The path of the URL. If the given $url is external, this includes
- *     the scheme and host.
- *   - 'query': An array of query parameters of $url, if existent.
- *   - 'fragment': The fragment of $url, if existent.
+ * @return array
+ *   An associative array containing:
+ *   - path: The path component of $url. If $url is an external URL, this
+ *     includes the scheme, authority, and path.
+ *   - query: An array of query parameters from $url, if they exist.
+ *   - fragment: The fragment component from $url, if it exists.
  *
- * @see url()
  * @see drupal_goto()
+ * @see l()
+ * @see url()
+ * @see http://tools.ietf.org/html/rfc3986
+ *
  * @ingroup php_wrappers
  */
 function drupal_parse_url($url) {
@@ -621,7 +636,7 @@
 }
 
 /**
- * Send the user to a different Drupal page.
+ * Sends the user to a different page.
  *
  * This issues an on-site HTTP redirect. The function makes sure the redirected
  * URL is formatted correctly.
@@ -642,20 +657,23 @@
  * callback.
  *
  * @param $path
- *   A Drupal path or a full URL.
+ *   (optional) A Drupal path or a full URL, which will be passed to url() to
+ *   compute the redirect for the URL.
  * @param $options
- *   An associative array of additional URL options to pass to url().
+ *   (optional) An associative array of additional URL options to pass to url().
  * @param $http_response_code
- *   Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
- *   - 301 Moved Permanently (the recommended value for most redirects)
- *   - 302 Found (default in Drupal and PHP, sometimes used for spamming search
- *         engines)
- *   - 303 See Other
- *   - 304 Not Modified
- *   - 305 Use Proxy
- *   - 307 Temporary Redirect (alternative to "503 Site Down for Maintenance")
- *   Note: Other values are defined by RFC 2616, but are rarely used and poorly
- *   supported.
+ *   (optional) The HTTP status code to use for the redirection, defaults to
+ *   302. The valid values for 3xx redirection status codes are defined in
+ *   @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 RFC 2616 @endlink
+ *   and the
+ *   @link http://tools.ietf.org/html/draft-reschke-http-status-308-07 draft for the new HTTP status codes: @endlink
+ *   - 301: Moved Permanently (the recommended value for most redirects).
+ *   - 302: Found (default in Drupal and PHP, sometimes used for spamming search
+ *     engines).
+ *   - 303: See Other.
+ *   - 304: Not Modified.
+ *   - 305: Use Proxy.
+ *   - 307: Temporary Redirect.
  *
  * @see drupal_get_destination()
  * @see url()
@@ -670,6 +688,13 @@
     $options['fragment'] = $destination['fragment'];
   }
 
+  // In some cases modules call drupal_goto(current_path()). We need to ensure
+  // that such a redirect is not to an external URL.
+  if ($path === current_path() && empty($options['external']) && url_is_external($path)) {
+    // Force url() to generate a non-external URL.
+    $options['external'] = FALSE;
+  }
+
   drupal_alter('drupal_goto', $path, $options, $http_response_code);
 
   // The 'Location' HTTP header must be absolute.
@@ -686,7 +711,7 @@
 }
 
 /**
- * Deliver a "site is under maintenance" message to the browser.
+ * Delivers a "site is under maintenance" message to the browser.
  *
  * Page callback functions wanting to report a "site offline" message should
  * return MENU_SITE_OFFLINE instead of calling drupal_site_offline(). However,
@@ -698,7 +723,7 @@
 }
 
 /**
- * Deliver a "page not found" error to the browser.
+ * Delivers a "page not found" error to the browser.
  *
  * Page callback functions wanting to report a "page not found" message should
  * return MENU_NOT_FOUND instead of calling drupal_not_found(). However,
@@ -710,19 +735,20 @@
 }
 
 /**
- * Deliver a "access denied" error to the browser.
+ * Delivers an "access denied" error to the browser.
  *
  * Page callback functions wanting to report an "access denied" message should
  * return MENU_ACCESS_DENIED instead of calling drupal_access_denied(). However,
  * functions that are invoked in contexts where that return value might not
- * bubble up to menu_execute_active_handler() should call drupal_access_denied().
+ * bubble up to menu_execute_active_handler() should call
+ * drupal_access_denied().
  */
 function drupal_access_denied() {
   drupal_deliver_page(MENU_ACCESS_DENIED);
 }
 
 /**
- * Perform an HTTP request.
+ * Performs an HTTP request.
  *
  * This is a flexible and powerful HTTP client implementation. Correctly
  * handles GET, POST, PUT or any other HTTP requests. Handles redirects.
@@ -734,7 +760,8 @@
  *   - 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.
+ *     'param=value&param=value&...'; to generate this, use http_build_query().
+ *     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
@@ -759,8 +786,17 @@
  *     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.
+ *
+ * @see http_build_query()
  */
 function drupal_http_request($url, array $options = array()) {
+  // Allow an alternate HTTP client library to replace Drupal's default
+  // implementation.
+  $override_function = variable_get('drupal_http_request_function', FALSE);
+  if (!empty($override_function) && function_exists($override_function)) {
+    return $override_function($url, $options);
+  }
+
   $result = new stdClass();
 
   // Parse the URL and make sure we can handle the schema.
@@ -789,10 +825,51 @@
     'timeout' => 30.0,
     'context' => NULL,
   );
+
+  // Merge the default headers.
+  $options['headers'] += array(
+    'User-Agent' => 'Drupal (+http://drupal.org/)',
+  );
+
   // stream_socket_client() requires timeout to be a float.
   $options['timeout'] = (float) $options['timeout'];
 
+  // Use a proxy if one is defined and the host is not on the excluded list.
+  $proxy_server = variable_get('proxy_server', '');
+  if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
+    // Set the scheme so we open a socket to the proxy server.
+    $uri['scheme'] = 'proxy';
+    // Set the path to be the full URL.
+    $uri['path'] = $url;
+    // Since the URL is passed as the path, we won't use the parsed query.
+    unset($uri['query']);
+
+    // Add in username and password to Proxy-Authorization header if needed.
+    if ($proxy_username = variable_get('proxy_username', '')) {
+      $proxy_password = variable_get('proxy_password', '');
+      $options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
+    }
+    // Some proxies reject requests with any User-Agent headers, while others
+    // require a specific one.
+    $proxy_user_agent = variable_get('proxy_user_agent', '');
+    // The default value matches neither condition.
+    if ($proxy_user_agent === NULL) {
+      unset($options['headers']['User-Agent']);
+    }
+    elseif ($proxy_user_agent) {
+      $options['headers']['User-Agent'] = $proxy_user_agent;
+    }
+  }
+
   switch ($uri['scheme']) {
+    case 'proxy':
+      // Make the socket connection to a proxy server.
+      $socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
+      // The Host header still needs to match the real request.
+      $options['headers']['Host'] = $uri['host'];
+      $options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
+      break;
+
     case 'http':
     case 'feed':
       $port = isset($uri['port']) ? $uri['port'] : 80;
@@ -802,12 +879,14 @@
       // checking the host that do not take into account the port number.
       $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
       break;
+
     case 'https':
       // Note: Only works when PHP is compiled with OpenSSL support.
       $port = isset($uri['port']) ? $uri['port'] : 443;
       $socket = 'ssl://' . $uri['host'] . ':' . $port;
       $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
       break;
+
     default:
       $result->error = 'invalid schema ' . $uri['scheme'];
       $result->code = -1003;
@@ -832,7 +911,7 @@
     // Mark that this request failed. This will trigger a check of the web
     // server's ability to make outgoing HTTP requests the next time that
     // requirements checking is performed.
-    // See system_requirements()
+    // See system_requirements().
     variable_set('drupal_http_request_fails', TRUE);
 
     return $result;
@@ -844,11 +923,6 @@
     $path .= '?' . $uri['query'];
   }
 
-  // Merge the default headers.
-  $options['headers'] += array(
-    'User-Agent' => 'Drupal (+http://drupal.org/)',
-  );
-
   // Only add Content-Length if we actually have any content or if it is a POST
   // or PUT request. Some non-standard servers get confused by Content-Length in
   // at least HEAD/GET requests, and Squid always requires Content-Length in
@@ -860,7 +934,7 @@
 
   // If the server URL has a user then attempt to use basic authentication.
   if (isset($uri['user'])) {
-    $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ''));
+    $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':'));
   }
 
   // If the database prefix is being used by SimpleTest to run the tests in a copied
@@ -921,9 +995,10 @@
   $response = preg_split("/\r\n|\n|\r/", $response);
 
   // Parse the response status line.
-  list($protocol, $code, $status_message) = explode(' ', trim(array_shift($response)), 3);
-  $result->protocol = $protocol;
-  $result->status_message = $status_message;
+  $response_status_array = _drupal_parse_response_status(trim(array_shift($response)));
+  $result->protocol = $response_status_array['http_version'];
+  $result->status_message = $response_status_array['reason_phrase'];
+  $code = $response_status_array['response_code'];
 
   $result->headers = array();
 
@@ -992,6 +1067,12 @@
 
   switch ($code) {
     case 200: // OK
+    case 201: // Created
+    case 202: // Accepted
+    case 203: // Non-Authoritative Information
+    case 204: // No Content
+    case 205: // Reset Content
+    case 206: // Partial Content
     case 304: // Not modified
       break;
     case 301: // Moved permanently
@@ -1014,15 +1095,66 @@
       }
       break;
     default:
-      $result->error = $status_message;
+      $result->error = $result->status_message;
   }
 
   return $result;
 }
+
+/**
+ * Splits an HTTP response status line into components.
+ *
+ * See the @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html status line definition @endlink
+ * in RFC 2616.
+ *
+ * @param string $respone
+ *   The response status line, for example 'HTTP/1.1 500 Internal Server Error'.
+ *
+ * @return array
+ *   Keyed array containing the component parts. If the response is malformed,
+ *   all possible parts will be extracted. 'reason_phrase' could be empty.
+ *   Possible keys:
+ *   - 'http_version'
+ *   - 'response_code'
+ *   - 'reason_phrase'
+ */
+function _drupal_parse_response_status($response) {
+  $response_array = explode(' ', trim($response), 3);
+  // Set up empty values.
+  $result = array(
+    'reason_phrase' => '',
+  );
+  $result['http_version'] = $response_array[0];
+  $result['response_code'] = $response_array[1];
+  if (isset($response_array[2])) {
+    $result['reason_phrase'] = $response_array[2];
+  }
+  return $result;
+}
+
+/**
+ * Helper function for determining hosts excluded from needing a proxy.
+ *
+ * @return
+ *   TRUE if a proxy should be used for this host.
+ */
+function _drupal_http_use_proxy($host) {
+  $proxy_exceptions = variable_get('proxy_exceptions', array('localhost', '127.0.0.1'));
+  return !in_array(strtolower($host), $proxy_exceptions, TRUE);
+}
+
 /**
  * @} End of "HTTP handling".
  */
 
+/**
+ * Strips slashes from a string or array of strings.
+ *
+ * Callback for array_walk() within fix_gpx_magic().
+ *
+ * @param $item
+ *   An individual string or array of strings from superglobals.
+ */
 function _fix_gpc_magic(&$item) {
   if (is_array($item)) {
     array_walk($item, '_fix_gpc_magic');
@@ -1033,11 +1165,19 @@
 }
 
 /**
- * Helper function to strip slashes from $_FILES skipping over the tmp_name keys
- * since PHP generates single backslashes for file paths on Windows systems.
+ * Strips slashes from $_FILES items.
+ *
+ * Callback for array_walk() within fix_gpc_magic().
+ *
+ * The tmp_name key is skipped keys since PHP generates single backslashes for
+ * file paths on Windows systems.
  *
- * tmp_name does not have backslashes added see
- * http://php.net/manual/en/features.file-upload.php#42280
+ * @param $item
+ *   An item from $_FILES.
+ * @param $key
+ *   The key for the item within $_FILES.
+ *
+ * @see http://php.net/manual/features.file-upload.php#42280
  */
 function _fix_gpc_magic_files(&$item, $key) {
   if ($key != 'tmp_name') {
@@ -1051,7 +1191,10 @@
 }
 
 /**
- * Fix double-escaping problems caused by "magic quotes" in some PHP installations.
+ * Fixes double-escaping caused by "magic quotes" in some PHP installations.
+ *
+ * @see _fix_gpc_magic()
+ * @see _fix_gpc_magic_files()
  */
 function fix_gpc_magic() {
   static $fixed = FALSE;
@@ -1072,12 +1215,14 @@
  */
 
 /**
- * Verify the syntax of the given e-mail address.
+ * Verifies the syntax of the given e-mail address.
  *
- * Empty e-mail addresses are allowed. See RFC 2822 for details.
+ * This uses the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
  *
  * @param $mail
  *   A string containing an e-mail address.
+ *
  * @return
  *   TRUE if the address is in a valid format.
  */
@@ -1086,7 +1231,7 @@
 }
 
 /**
- * Verify the syntax of the given URL.
+ * Verifies the syntax of the given URL.
  *
  * This function should only be used on actual URLs. It should not be used for
  * Drupal menu paths, which can contain arbitrary characters.
@@ -1095,6 +1240,7 @@
  *   The URL to verify.
  * @param $absolute
  *   Whether the URL is absolute (beginning with a scheme such as "http:").
+ *
  * @return
  *   TRUE if the URL is in a valid format.
  */
@@ -1127,7 +1273,7 @@
  */
 
 /**
- * Register an event for the current visitor to the flood control mechanism.
+ * Registers an event for the current visitor to the flood control mechanism.
  *
  * @param $name
  *   The name of an event.
@@ -1154,7 +1300,7 @@
 }
 
 /**
- * Make the flood control mechanism forget about an event for the current visitor.
+ * Makes the flood control mechanism forget an event for the current visitor.
  *
  * @param $name
  *   The name of an event.
@@ -1172,7 +1318,7 @@
 }
 
 /**
- * Checks whether user is allowed to proceed with the specified event.
+ * Checks whether a user is allowed to proceed with the specified event.
  *
  * Events can have thresholds saying that each user can only do that event
  * a certain number of times in a time window. This function verifies that the
@@ -1266,7 +1412,7 @@
 }
 
 /**
- * Strips dangerous protocols (e.g. 'javascript:') from a URI and encodes it for output to an HTML attribute value.
+ * Strips dangerous protocols from a URI and encodes it for output to HTML.
  *
  * @param $uri
  *   A plain-text URI that might contain dangerous protocols.
@@ -1286,7 +1432,7 @@
 }
 
 /**
- * Very permissive XSS/HTML filter for admin-only use.
+ * Applies a very permissive XSS/HTML filter for admin-only use.
  *
  * Use only for fields where it is impractical to use the
  * whole filter system, but where some (mainly inline) mark-up
@@ -1300,7 +1446,7 @@
 }
 
 /**
- * Filters an HTML string to prevent cross-site-scripting (XSS) vulnerabilities.
+ * Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.
  *
  * Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
  * For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
@@ -1323,7 +1469,6 @@
  *   valid UTF-8.
  *
  * @see drupal_validate_utf8()
- * @ingroup sanitization
  */
 function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
   // Only operate on valid UTF-8 strings. This is necessary to prevent cross
@@ -1331,21 +1476,21 @@
   if (!drupal_validate_utf8($string)) {
     return '';
   }
-  // Store the text format
+  // Store the text format.
   _filter_xss_split($allowed_tags, TRUE);
-  // Remove NULL characters (ignored by some browsers)
+  // Remove NULL characters (ignored by some browsers).
   $string = str_replace(chr(0), '', $string);
-  // Remove Netscape 4 JS entities
+  // Remove Netscape 4 JS entities.
   $string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
 
-  // Defuse all HTML entities
+  // Defuse all HTML entities.
   $string = str_replace('&', '&amp;', $string);
-  // Change back only well-formed entities in our whitelist
-  // Decimal numeric entities
+  // Change back only well-formed entities in our whitelist:
+  // Decimal numeric entities.
   $string = preg_replace('/&amp;#([0-9]+;)/', '&#\1', $string);
-  // Hexadecimal numeric entities
+  // Hexadecimal numeric entities.
   $string = preg_replace('/&amp;#[Xx]0*((?:[0-9A-Fa-f]{2})+;)/', '&#x\1', $string);
-  // Named entities
+  // Named entities.
   $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]*;)/', '&\1', $string);
 
   return preg_replace_callback('%
@@ -1369,6 +1514,7 @@
  *   If $store is FALSE then the array has one element, the HTML tag to process.
  * @param $store
  *   Whether to store $m.
+ *
  * @return
  *   If the element isn't allowed, an empty string. Otherwise, the cleaned up
  *   version of the HTML element.
@@ -1384,16 +1530,16 @@
   $string = $m[1];
 
   if (substr($string, 0, 1) != '<') {
-    // We matched a lone ">" character
+    // We matched a lone ">" character.
     return '&gt;';
   }
   elseif (strlen($string) == 1) {
-    // We matched a lone "<" character
+    // We matched a lone "<" character.
     return '&lt;';
   }
 
-  if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
-    // Seriously malformed
+  if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
+    // Seriously malformed.
     return '';
   }
 
@@ -1407,7 +1553,7 @@
   }
 
   if (!isset($allowed_html[strtolower($elem)])) {
-    // Disallowed HTML element
+    // Disallowed HTML element.
     return '';
   }
 
@@ -1423,7 +1569,7 @@
   $attrlist = preg_replace('%(\s?)/\s*$%', '\1', $attrlist, -1, $count);
   $xhtml_slash = $count ? ' /' : '';
 
-  // Clean up attributes
+  // Clean up attributes.
   $attr2 = implode(' ', _filter_xss_attributes($attrlist));
   $attr2 = preg_replace('/[<>]/', '', $attr2);
   $attr2 = strlen($attr2) ? ' ' . $attr2 : '';
@@ -1448,7 +1594,7 @@
 
     switch ($mode) {
       case 0:
-        // Attribute name, href for instance
+        // Attribute name, href for instance.
         if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
           $attrname = strtolower($match[1]);
           $skip = ($attrname == 'style' || substr($attrname, 0, 2) == 'on');
@@ -1458,7 +1604,7 @@
         break;
 
       case 1:
-        // Equals sign or valueless ("selected")
+        // Equals sign or valueless ("selected").
         if (preg_match('/^\s*=\s*/', $attr)) {
           $working = 1; $mode = 2;
           $attr = preg_replace('/^\s*=\s*/', '', $attr);
@@ -1475,7 +1621,7 @@
         break;
 
       case 2:
-        // Attribute value, a URL after href= for instance
+        // Attribute value, a URL after href= for instance.
         if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) {
           $thisval = filter_xss_bad_protocol($match[1]);
 
@@ -1512,7 +1658,7 @@
     }
 
     if ($working == 0) {
-      // not well formed, remove and try again
+      // Not well formed; remove and try again.
       $attr = preg_replace('/
         ^
         (
@@ -1536,15 +1682,16 @@
 }
 
 /**
- * Processes an HTML attribute value and ensures it does not contain an URL with a disallowed protocol (e.g. javascript:).
+ * Processes an HTML attribute value and strips dangerous protocols from URLs.
  *
  * @param $string
  *   The string with the attribute value.
  * @param $decode
- *   (Deprecated) Whether to decode entities in the $string. Set to FALSE if the
+ *   (deprecated) Whether to decode entities in the $string. Set to FALSE if the
  *   $string is in plain text, TRUE otherwise. Defaults to TRUE. This parameter
  *   is deprecated and will be removed in Drupal 8. To process a plain-text URI,
  *   call drupal_strip_dangerous_protocols() or check_url() instead.
+ *
  * @return
  *   Cleaned up and HTML-escaped version of $string.
  */
@@ -1598,7 +1745,7 @@
 }
 
 /**
- * Format a single RSS item.
+ * Formats a single RSS item.
  *
  * Arbitrary elements may be added using the $args associative array.
  */
@@ -1614,7 +1761,7 @@
 }
 
 /**
- * Format XML elements.
+ * Formats XML elements.
  *
  * @param $array
  *   An array where each item represents an element and is either a:
@@ -1623,9 +1770,15 @@
  *     - 'key': element name
  *     - 'value': element contents
  *     - 'attributes': associative array of element attributes
+ *     - 'encoded': TRUE if 'value' is already encoded
  *
  * In both cases, 'value' can be a simple string, or it can be another array
  * with the same format as $array itself for nesting.
+ *
+ * If 'encoded' is TRUE it is up to the caller to ensure that 'value' is either
+ * entity-encoded or CDATA-escaped. Using this option is not recommended when
+ * working with untrusted user input, since failing to escape the data
+ * correctly has security implications.
  */
 function format_xml_elements($array) {
   $output = '';
@@ -1638,7 +1791,7 @@
         }
 
         if (isset($value['value']) && $value['value'] != '') {
-          $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : check_plain($value['value'])) . '</' . $value['key'] . ">\n";
+          $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : (!empty($value['encoded']) ? $value['value'] : check_plain($value['value']))) . '</' . $value['key'] . ">\n";
         }
         else {
           $output .= " />\n";
@@ -1653,7 +1806,7 @@
 }
 
 /**
- * Format a string containing a count of items.
+ * Formats a string containing a count of items.
  *
  * This function ensures that the string is pluralized correctly. Since t() is
  * called by this function, make sure not to pass already-localized strings to
@@ -1669,37 +1822,33 @@
  *   $output = format_plural($update_count,
  *     'Changed the content type of 1 post from %old-type to %new-type.',
  *     'Changed the content type of @count posts from %old-type to %new-type.',
- *     array('%old-type' => $info->old_type, '%new-type' => $info->new_type)));
+ *     array('%old-type' => $info->old_type, '%new-type' => $info->new_type));
  * @endcode
  *
  * @param $count
  *   The item count to display.
  * @param $singular
- *   The string for the singular case. Please make sure it is clear this is
- *   singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
- *   Do not use @count in the singular string.
+ *   The string for the singular case. Make sure it is clear this is singular,
+ *   to ease translation (e.g. use "1 new comment" instead of "1 new"). Do not
+ *   use @count in the singular string.
  * @param $plural
- *   The string for the plural case. Please make sure it is clear this is plural,
- *   to ease translation. Use @count in place of the item count, as in "@count
- *   new comments".
+ *   The string for the plural case. Make sure it is clear this is plural, to
+ *   ease translation. Use @count in place of the item count, as in
+ *   "@count new comments".
  * @param $args
- *   An associative array of replacements to make after translation. Incidences
+ *   An associative array of replacements to make after translation. Instances
  *   of any key in this array are replaced with the corresponding value.
- *   Based on the first character of the key, the value is escaped and/or themed:
- *    - !variable: inserted as is
- *    - @variable: escape plain text to HTML (check_plain)
- *    - %variable: escape text and theme as a placeholder for user-submitted
- *      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.
+ *   Based on the first character of the key, the value is escaped and/or
+ *   themed. See format_string(). Note that you do not need to include @count
+ *   in this array; this replacement is done automatically for the plural case.
  * @param $options
- *   An associative array of additional options, with the following keys:
- *     - 'langcode' (default to the current language) The language code to
- *       translate to a language other than what is used to display the page.
- *     - 'context' (default to the empty context) The context the source string
- *       belongs to.
+ *   An associative array of additional options. See t() for allowed keys.
+ *
  * @return
  *   A translated string.
+ *
+ * @see t()
+ * @see format_string()
  */
 function format_plural($count, $singular, $plural, array $args = array(), array $options = array()) {
   $args['@count'] = $count;
@@ -1709,7 +1858,8 @@
 
   // Get the plural index through the gettext formula.
   $index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
-  // Backwards compatibility.
+  // If the index cannot be computed, use the plural as a fallback (which
+  // allows for most flexiblity with the replaceable @count value).
   if ($index < 0) {
     return t($plural, $args, $options);
   }
@@ -1728,11 +1878,12 @@
 }
 
 /**
- * Parse a given byte count.
+ * Parses a given byte count.
  *
  * @param $size
  *   A size expressed as a number of bytes with optional SI or IEC binary unit
  *   prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8 bytes, 9mbytes).
+ *
  * @return
  *   An integer representation of the size in bytes.
  */
@@ -1749,13 +1900,14 @@
 }
 
 /**
- * Generate a string representation for the given byte count.
+ * Generates a string representation for the given byte count.
  *
  * @param $size
  *   A size in bytes.
  * @param $langcode
  *   Optional language code to translate to a language other than what is used
  *   to display the page.
+ *
  * @return
  *   A translated string representation of the size.
  */
@@ -1788,19 +1940,20 @@
 }
 
 /**
- * Format a time interval with the requested granularity.
+ * Formats a time interval with the requested granularity.
  *
- * @param $timestamp
+ * @param $interval
  *   The length of the interval in seconds.
  * @param $granularity
  *   How many different units to display in the string.
  * @param $langcode
  *   Optional language code to translate to a language other than
  *   what is used to display the page.
+ *
  * @return
  *   A translated string representation of the interval.
  */
-function format_interval($timestamp, $granularity = 2, $langcode = NULL) {
+function format_interval($interval, $granularity = 2, $langcode = NULL) {
   $units = array(
     '1 year|@count years' => 31536000,
     '1 month|@count months' => 2592000,
@@ -1813,9 +1966,9 @@
   $output = '';
   foreach ($units as $key => $value) {
     $key = explode('|', $key);
-    if ($timestamp >= $value) {
-      $output .= ($output ? ' ' : '') . format_plural(floor($timestamp / $value), $key[0], $key[1], array(), array('langcode' => $langcode));
-      $timestamp %= $value;
+    if ($interval >= $value) {
+      $output .= ($output ? ' ' : '') . format_plural(floor($interval / $value), $key[0], $key[1], array(), array('langcode' => $langcode));
+      $interval %= $value;
       $granularity--;
     }
 
@@ -1845,7 +1998,7 @@
  *   get interpreted as date format characters.
  * @param $timezone
  *   (optional) Time zone identifier, as described at
- *   http://php.net/manual/en/timezones.php Defaults to the time zone used to
+ *   http://php.net/manual/timezones.php Defaults to the time zone used to
  *   display the page.
  * @param $langcode
  *   (optional) Language code to translate to. Defaults to the language used to
@@ -1928,10 +2081,11 @@
 /**
  * Returns an ISO8601 formatted date based on the given date.
  *
- * Can be used as a callback for RDF mappings.
+ * Callback for use within hook_rdf_mapping() implementations.
  *
  * @param $date
  *   A UNIX timestamp.
+ *
  * @return string
  *   An ISO8601 formatted date.
  */
@@ -1942,7 +2096,9 @@
 }
 
 /**
- * Callback function for preg_replace_callback().
+ * Translates a formatted date string.
+ *
+ * Callback for preg_replace_callback() within format_date().
  */
 function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
   // We cache translations to avoid redundant and rather costly calls to t().
@@ -1978,6 +2134,9 @@
 /**
  * Format a username.
  *
+ * This is also the label callback implementation of
+ * callback_entity_info_label() for user_entity_info().
+ *
  * By default, the passed-in object's 'name' property is used if it exists, or
  * else, the site-defined value for the 'anonymous' variable. However, a module
  * may override this by implementing hook_username_alter(&$name, $account).
@@ -2009,8 +2168,9 @@
  * alternative than url().
  *
  * @param $path
- *   The internal path or external URL being linked to, such as "node/34" or
- *   "http://example.com/foo". A few notes:
+ *   (optional) The internal path or external URL being linked to, such as
+ *   "node/34" or "http://example.com/foo". The default value is equivalent to
+ *   passing in '<front>'. A few notes:
  *   - If you provide a full URL, it will be considered an external URL.
  *   - If you provide only the path (e.g. "node/34"), it will be
  *     considered an internal link. In this case, it should be a system URL,
@@ -2026,7 +2186,8 @@
  *     include them in $path, or use $options['query'] to let this function
  *     URL encode them.
  * @param $options
- *   An associative array of additional options, with the following elements:
+ *   (optional) An associative array of additional options, with the following
+ *   elements:
  *   - 'query': An array of query key/value-pairs (without any URL-encoding) to
  *     append to the URL.
  *   - 'fragment': A fragment identifier (named anchor) to append to the URL.
@@ -2042,7 +2203,7 @@
  *     for the URL. If $options['language'] is omitted, the global $language_url
  *     will be used.
  *   - 'https': Whether this URL should point to a secure location. If not
- *     defined, the current scheme is used, so the user stays on http or https
+ *     defined, the current scheme is used, so the user stays on HTTP or HTTPS
  *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
  *     only be enforced when the variable 'https' is set to TRUE.
  *   - 'base_url': Only used internally, to modify the base URL when a language
@@ -2057,8 +2218,8 @@
  *     Drupal on a web server that cannot be configured to automatically find
  *     index.php, then hook_url_outbound_alter() can be implemented to force
  *     this value to 'index.php'.
- *   - 'entity_type': The entity type of the object that called url(). Only set if
- *     url() is invoked by entity_uri().
+ *   - 'entity_type': The entity type of the object that called url(). Only
+ *     set if url() is invoked by entity_uri().
  *   - 'entity': The entity object (such as a node) for which the URL is being
  *     generated. Only set if url() is invoked by entity_uri().
  *
@@ -2075,14 +2236,11 @@
     'prefix' => ''
   );
 
+  // Determine whether this is an external link, but ensure that the current
+  // path is always treated as internal by default (to prevent external link
+  // injection vulnerabilities).
   if (!isset($options['external'])) {
-    // Return an external link if $path contains an allowed absolute URL. Only
-    // call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
-    // before any / ? or #. Note: we could use url_is_external($path) here, but
-    // that would require another function call, and performance inside url() is
-    // critical.
-    $colonpos = strpos($path, ':');
-    $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path);
+    $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path);
   }
 
   // Preserve the original path before altering or aliasing.
@@ -2120,6 +2278,11 @@
     return $path . $options['fragment'];
   }
 
+  // Strip leading slashes from internal paths to prevent them becoming external
+  // URLs without protocol. /example.com should not be turned into
+  // //example.com.
+  $path = ltrim($path, '/');
+
   global $base_url, $base_secure_url, $base_insecure_url;
 
   // The base_url might be rewritten from the language rewrite in domain mode.
@@ -2183,7 +2346,7 @@
 }
 
 /**
- * Return TRUE if a path is external to Drupal (e.g. http://example.com).
+ * Returns TRUE if a path is external to Drupal (e.g. http://example.com).
  *
  * If a path cannot be assessed by Drupal's menu handler, then we must
  * treat it as potentially insecure.
@@ -2191,19 +2354,31 @@
  * @param $path
  *   The internal path or external URL being linked to, such as "node/34" or
  *   "http://example.com/foo".
+ *
  * @return
  *   Boolean TRUE or FALSE, where TRUE indicates an external path.
  */
 function url_is_external($path) {
   $colonpos = strpos($path, ':');
-  // Avoid calling drupal_strip_dangerous_protocols() if there is any
-  // slash (/), hash (#) or question_mark (?) before the colon (:)
-  // occurrence - if any - as this would clearly mean it is not a URL.
-  return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path;
+  // Some browsers treat \ as / so normalize to forward slashes.
+  $path = str_replace('\\', '/', $path);
+  // If the path starts with 2 slashes then it is always considered an external
+  // URL without an explicit protocol part.
+  return (strpos($path, '//') === 0)
+    // Leading control characters may be ignored or mishandled by browsers, so
+    // assume such a path may lead to an external location. The \p{C} character
+    // class matches all UTF-8 control, unassigned, and private characters.
+    || (preg_match('/^\p{C}/u', $path) !== 0)
+    // Avoid calling drupal_strip_dangerous_protocols() if there is any slash
+    // (/), hash (#) or question_mark (?) before the colon (:) occurrence - if
+    // any - as this would clearly mean it is not a URL.
+    || ($colonpos !== FALSE
+      && !preg_match('![/?#]!', substr($path, 0, $colonpos))
+      && drupal_strip_dangerous_protocols($path) == $path);
 }
 
 /**
- * Format an attribute string for a HTTP header.
+ * Formats an attribute string for an HTTP header.
  *
  * @param $attributes
  *   An associative array of attributes such as 'rel'.
@@ -2225,7 +2400,7 @@
 }
 
 /**
- * Converts an associative array to an attribute string for use in XML/HTML tags.
+ * Converts an associative array to an XML/HTML tag attribute string.
  *
  * 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
@@ -2271,21 +2446,30 @@
 /**
  * Formats an internal or external URL link as an HTML anchor tag.
  *
- * This function correctly handles aliased paths, and adds an 'active' class
+ * This function correctly handles aliased paths and adds an 'active' class
  * attribute to links that point to the current page (for theming), so all
  * internal links output by modules should be generated by this function if
  * possible.
  *
- * @param $text
- *   The link text for the anchor tag.
- * @param $path
+ * However, for links enclosed in translatable text you should use t() and
+ * embed the HTML anchor tag directly in the translated string. For example:
+ * @code
+ * t('Visit the <a href="@url">settings</a> page', array('@url' => url('admin')));
+ * @endcode
+ * This keeps the context of the link title ('settings' in the example) for
+ * translators.
+ *
+ * @param string $text
+ *   The translated link text for the anchor tag.
+ * @param string $path
  *   The internal path or external URL being linked to, such as "node/34" or
  *   "http://example.com/foo". After the url() function is called to construct
  *   the URL from $path and $options, the resulting URL is passed through
  *   check_plain() before it is inserted into the HTML anchor tag, to ensure
  *   well-formed HTML. See url() for more information and notes.
  * @param array $options
- *   An associative array of additional options, with the following elements:
+ *   An associative array of additional options. Defaults to an empty array. It
+ *   may contain the following elements.
  *   - 'attributes': An associative array of HTML attributes to apply to the
  *     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
@@ -2301,8 +2485,10 @@
  *     well as the path must match). This element is also used by url().
  *   - Additional $options elements used by the url() function.
  *
- * @return
+ * @return string
  *   An HTML string containing a link to the given path.
+ *
+ * @see url()
  */
 function l($text, $path, array $options = array()) {
   global $language_url;
@@ -2338,7 +2524,7 @@
     // rendering.
     if (variable_get('theme_link', TRUE)) {
       drupal_theme_initialize();
-      $registry = theme_get_registry();
+      $registry = theme_get_registry(FALSE);
       // We don't want to duplicate functionality that's in theme(), so any
       // hint of a module or theme doing anything at all special with the 'link'
       // theme hook should simply result in theme() being called. This includes
@@ -2446,7 +2632,7 @@
 }
 
 /**
- * Package and send the result of a page callback to the browser as HTML.
+ * Packages and sends the result of a page callback to the browser as HTML.
  *
  * @param $page_callback_result
  *   The result of a page callback. Can be one of:
@@ -2466,6 +2652,19 @@
     drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
   }
 
+  // Send appropriate HTTP-Header for browsers and search engines.
+  global $language;
+  drupal_add_http_header('Content-Language', $language->language);
+
+  // By default, do not allow the site to be rendered in an iframe on another
+  // domain, but provide a variable to override this. If the code running for
+  // this page request already set the X-Frame-Options header earlier, don't
+  // overwrite it here.
+  $frame_options = variable_get('x_frame_options', 'SAMEORIGIN');
+  if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) {
+    drupal_add_http_header('X-Frame-Options', $frame_options);
+  }
+
   // Menu status constants are integers; page content is a string or array.
   if (is_int($page_callback_result)) {
     // @todo: Break these up into separate functions?
@@ -2481,7 +2680,10 @@
 
         // Keep old path for reference, and to allow forms to redirect to it.
         if (!isset($_GET['destination'])) {
-          $_GET['destination'] = $_GET['q'];
+          // Make sure that the current path is not interpreted as external URL.
+          if (!url_is_external($_GET['q'])) {
+            $_GET['destination'] = $_GET['q'];
+          }
         }
 
         $path = drupal_get_normal_path(variable_get('site_404', ''));
@@ -2510,7 +2712,10 @@
 
         // Keep old path for reference, and to allow forms to redirect to it.
         if (!isset($_GET['destination'])) {
-          $_GET['destination'] = $_GET['q'];
+          // Make sure that the current path is not interpreted as external URL.
+          if (!url_is_external($_GET['q'])) {
+            $_GET['destination'] = $_GET['q'];
+          }
         }
 
         $path = drupal_get_normal_path(variable_get('site_403', ''));
@@ -2551,7 +2756,7 @@
 }
 
 /**
- * Perform end-of-request tasks.
+ * Performs end-of-request tasks.
  *
  * This function sets the page cache if appropriate, and allows modules to
  * react to the closing of the page by calling hook_exit().
@@ -2574,11 +2779,12 @@
   _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
   drupal_cache_system_paths();
   module_implements_write_cache();
+  drupal_file_scan_write_cache();
   system_run_automated_cron();
 }
 
 /**
- * Perform end-of-request tasks.
+ * Performs end-of-request tasks.
  *
  * In some cases page requests need to end without calling drupal_page_footer().
  * In these cases, call drupal_exit() instead. There should rarely be a reason
@@ -2600,7 +2806,7 @@
 }
 
 /**
- * Form an associative array from a linear array.
+ * Forms an associative array from a linear array.
  *
  * This function walks through the provided array and constructs an associative
  * array out of it. The keys of the resulting array will be the values of the
@@ -2635,11 +2841,11 @@
  * into script execution a call such as set_time_limit(20) is made, the
  * script will run for a total of 45 seconds before timing out.
  *
- * It also means that it is possible to decrease the total time limit if
- * the sum of the new time limit and the current time spent running the
- * script is inferior to the original time limit. It is inherent to the way
- * set_time_limit() works, it should rather be called with an appropriate
- * value every time you need to allocate a certain amount of time
+ * If the current time limit is not unlimited it is possible to decrease the
+ * total time limit if the sum of the new time limit and the current time spent
+ * running the script is inferior to the original time limit. It is inherent to
+ * the way set_time_limit() works, it should rather be called with an
+ * appropriate value every time you need to allocate a certain amount of time
  * to execute a task than only once at the beginning of the script.
  *
  * Before calling set_time_limit(), we check if this function is available
@@ -2656,7 +2862,11 @@
  */
 function drupal_set_time_limit($time_limit) {
   if (function_exists('set_time_limit')) {
-    @set_time_limit($time_limit);
+    $current = ini_get('max_execution_time');
+    // Do not set time limit if it is currently unlimited.
+    if ($current != 0) {
+      @set_time_limit($time_limit);
+    }
   }
 }
 
@@ -2669,17 +2879,17 @@
  *   The name of the item for which the path is requested.
  *
  * @return
- *   The path to the requested item.
+ *   The path to the requested item or an empty string if the item is not found.
  */
 function drupal_get_path($type, $name) {
   return dirname(drupal_get_filename($type, $name));
 }
 
 /**
- * Return the base URL path (i.e., directory) of the Drupal installation.
+ * Returns the base URL path (i.e., directory) of the Drupal installation.
  *
- * base_path() prefixes and suffixes a "/" onto the returned path if the path is
- * not empty. At the very least, this will return "/".
+ * base_path() adds a "/" to the beginning and end of the returned path if the
+ * path is not empty. At the very least, this will return "/".
  *
  * Examples:
  * - http://example.com returns "/" because the path is empty.
@@ -2690,12 +2900,12 @@
 }
 
 /**
- * Add a LINK tag with a distinct 'rel' attribute to the page's HEAD.
+ * Adds a LINK tag with a distinct 'rel' attribute to the page's HEAD.
  *
- * This function can be called as long the HTML header hasn't been sent,
- * which on normal pages is up through the preprocess step of theme('html').
- * Adding a link will overwrite a prior link with the exact same 'rel' and
- * 'href' attributes.
+ * This function can be called as long the HTML header hasn't been sent, which
+ * on normal pages is up through the preprocess step of theme('html'). Adding
+ * a link will overwrite a prior link with the exact same 'rel' and 'href'
+ * attributes.
  *
  * @param $attributes
  *   Associative array of element attributes including 'href' and 'rel'.
@@ -2759,8 +2969,8 @@
  *     See drupal_get_css() where the overrides are performed. Also, if the
  *     direction of the current language is right-to-left (Hebrew, Arabic,
  *     etc.), the function will also look for an RTL CSS file and append it to
- *     the list. The name of this file should have an '-rtl.css' suffix.  For
- *     example a CSS file called 'mymodule-name.css' will have a
+ *     the list. The name of this file should have an '-rtl.css' suffix. For
+ *     example, a CSS file called 'mymodule-name.css' will have a
  *     'mymodule-name-rtl.css' file added to the list, if exists in the same
  *     directory. This CSS file should contain overrides for properties which
  *     should be reversed or otherwise different in a right-to-left display.
@@ -2785,7 +2995,7 @@
  *   - 'group': A number identifying the group in which to add the stylesheet.
  *     Available constants are:
  *     - CSS_SYSTEM: Any system-layer CSS.
- *     - CSS_DEFAULT: Any module-layer CSS.
+ *     - CSS_DEFAULT: (default) Any module-layer CSS.
  *     - CSS_THEME: Any theme-layer CSS.
  *     The group number serves as a weight: the markup for loading a stylesheet
  *     within a lower weight group is output to the page before the markup for
@@ -2837,6 +3047,13 @@
  */
 function drupal_add_css($data = NULL, $options = NULL) {
   $css = &drupal_static(__FUNCTION__, array());
+  $count = &drupal_static(__FUNCTION__ . '_count', 0);
+
+  // If the $css variable has been reset with drupal_static_reset(), there is
+  // no longer any CSS being tracked, so set the counter back to 0 also.
+  if (count($css) === 0) {
+    $count = 0;
+  }
 
   // Construct the options, taking the defaults into consideration.
   if (isset($options)) {
@@ -2872,7 +3089,8 @@
     }
 
     // Always add a tiny value to the weight, to conserve the insertion order.
-    $options['weight'] += count($css) / 1000;
+    $options['weight'] += $count / 1000;
+    $count++;
 
     // Add the data to the CSS array depending on the type.
     switch ($options['type']) {
@@ -2892,7 +3110,7 @@
 }
 
 /**
- * Returns a themed representation of all stylesheets that should be attached to the page.
+ * Returns a themed representation of all stylesheets to attach to the page.
  *
  * It loads the CSS in order, with 'module' first, then 'theme' afterwards.
  * This ensures proper cascading of styles so themes can easily override
@@ -2933,12 +3151,24 @@
   // Sort CSS items, so that they appear in the correct order.
   uasort($css, 'drupal_sort_css_js');
 
+  // Provide the page with information about the individual CSS files used,
+  // information not otherwise available when CSS aggregation is enabled. The
+  // setting is attached later in this function, but is set here, so that CSS
+  // files removed below are still considered "used" and prevented from being
+  // added in a later AJAX request.
+  // Skip if no files were added to the page or jQuery.extend() will overwrite
+  // the Drupal.settings.ajaxPageState.css object with an empty array.
+  if (!empty($css)) {
+    // Cast the array to an object to be on the safe side even if not empty.
+    $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
+  }
+
   // Remove the overridden CSS files. Later CSS files override former ones.
   $previous_item = array();
   foreach ($css as $key => $item) {
     if ($item['type'] == 'file') {
       // If defined, force a unique basename for this file.
-      $basename = isset($item['basename']) ? $item['basename'] : basename($item['data']);
+      $basename = isset($item['basename']) ? $item['basename'] : drupal_basename($item['data']);
       if (isset($previous_item[$basename])) {
         // Remove the previous item that shared the same base name.
         unset($css[$previous_item[$basename]]);
@@ -2953,20 +3183,32 @@
     '#items' => $css,
   );
 
-  // Provide the page with information about the individual CSS files used,
-  // information not otherwise available when CSS aggregation is enabled.
-  $setting['ajaxPageState']['css'] = array_fill_keys(array_keys($css), 1);
-  $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+  if (!empty($setting)) {
+    $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+  }
 
   return drupal_render($styles);
 }
 
 /**
- * Function used by uasort to sort the array structures returned by drupal_add_css() and drupal_add_js().
+ * Sorts CSS and JavaScript resources.
+ *
+ * Callback for uasort() within:
+ * - drupal_get_css()
+ * - drupal_get_js()
  *
  * This sort order helps optimize front-end performance while providing modules
  * and themes with the necessary control for ordering the CSS and JavaScript
  * appearing on a page.
+ *
+ * @param $a
+ *   First item for comparison. The compared items should be associative arrays
+ *   of member items from drupal_add_css() or drupal_add_js().
+ * @param $b
+ *   Second item for comparison.
+ *
+ * @see drupal_add_css()
+ * @see drupal_add_js()
  */
 function drupal_sort_css_js($a, $b) {
   // First order by group, so that, for example, all items in the CSS_SYSTEM
@@ -3033,6 +3275,7 @@
  *   'items' key, which is the subset of items from $css that are in the group.
  *
  * @see drupal_pre_render_styles()
+ * @see system_element_info()
  */
 function drupal_group_css($css) {
   $groups = array();
@@ -3115,6 +3358,7 @@
  *
  * @see drupal_group_css()
  * @see drupal_pre_render_styles()
+ * @see system_element_info()
  */
 function drupal_aggregate_css(&$css_groups) {
   $preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
@@ -3293,7 +3537,11 @@
             $import_batch = array_slice($import, 0, 31);
             $import = array_slice($import, 31);
             $element = $style_element_defaults;
-            $element['#value'] = implode("\n", $import_batch);
+            // This simplifies the JavaScript regex, allowing each line
+            // (separated by \n) to be treated as a completely different string.
+            // This means that we can use ^ and $ on one line at a time, and not
+            // worry about style tags since they'll never match the regex.
+            $element['#value'] = "\n" . implode("\n", $import_batch) . "\n";
             $element['#attributes']['media'] = $group['media'];
             $element['#browsers'] = $group['browsers'];
             $elements[] = $element;
@@ -3376,8 +3624,8 @@
  * in $css while the value is the cache file name. The cache file is generated
  * in two cases. First, if there is no file name value for the key, which will
  * happen if a new file name has been added to $css or after the lookup
- * variable is emptied to force a rebuild of the cache.  Second, the cache
- * file is generated if it is missing on disk. Old cache files are not deleted
+ * variable is emptied to force a rebuild of the cache. Second, the cache file
+ * is generated if it is missing on disk. Old cache files are not deleted
  * immediately when the lookup variable is emptied, but are deleted after a set
  * period by drupal_delete_file_if_stale(). This ensures that files referenced
  * by a cached page will still be available.
@@ -3392,7 +3640,13 @@
   $data = '';
   $uri = '';
   $map = variable_get('drupal_css_cache_files', array());
-  $key = hash('sha256', serialize($css));
+  // Create a new array so that only the file names are used to create the hash.
+  // This prevents new aggregates from being created unnecessarily.
+  $css_data = array();
+  foreach ($css as $css_file) {
+    $css_data[] = $css_file['data'];
+  }
+  $key = hash('sha256', serialize($css_data));
   if (isset($map[$key])) {
     $uri = $map[$key];
   }
@@ -3455,9 +3709,7 @@
 }
 
 /**
- * Helper function for drupal_build_css_cache().
- *
- * This function will prefix all paths within a CSS file.
+ * Prefixes all paths within a CSS file for drupal_build_css_cache().
  */
 function _drupal_build_css_path($matches, $base = NULL) {
   $_base = &drupal_static(__FUNCTION__);
@@ -3514,33 +3766,40 @@
   if ($basepath && !file_uri_scheme($file)) {
     $file = $basepath . '/' . $file;
   }
+  // Store the parent base path to restore it later.
+  $parent_base_path = $basepath;
+  // Set the current base path to process possible child imports.
   $basepath = dirname($file);
 
   // 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.
+  $content = '';
   if ($contents = @file_get_contents($file)) {
     // Return the processed stylesheet.
-    return drupal_load_stylesheet_content($contents, $_optimize);
+    $content = drupal_load_stylesheet_content($contents, $_optimize);
   }
 
-  return '';
+  // Restore the parent base path as the file and its childen are processed.
+  $basepath = $parent_base_path;
+  return $content;
 }
 
 /**
- * Process the contents of a stylesheet for aggregation.
+ * Processes the contents of a stylesheet for aggregation.
  *
  * @param $contents
  *   The contents of the stylesheet.
  * @param $optimize
  *   (optional) Boolean whether CSS contents should be minified. Defaults to
  *   FALSE.
+ *
  * @return
  *   Contents of the stylesheet including the imported stylesheets.
  */
 function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
   // Remove multiple charset declarations for standards compliance (and fixing Safari problems).
-  $contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
+  $contents = preg_replace('/^@charset\s+[\'"](\S*?)\b[\'"];/i', '', $contents);
 
   if ($optimize) {
     // Perform some safe CSS optimizations.
@@ -3559,7 +3818,7 @@
     // Remove certain whitespace.
     // There are different conditions for removing leading and trailing
     // whitespace.
-    // @see http://php.net/manual/en/regexp.reference.subpatterns.php
+    // @see http://php.net/manual/regexp.reference.subpatterns.php
     $contents = preg_replace('<
       # Strip leading and trailing whitespace.
         \s*([@{};,])\s*
@@ -3584,7 +3843,7 @@
 
   // Replaces @import commands with the actual stylesheet content.
   // This happens recursively but omits external files.
-  $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
+  $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
   return $contents;
 }
 
@@ -3608,7 +3867,7 @@
   // Alter all internal url() paths. Leave external paths alone. We don't need
   // to normalize absolute paths here (i.e. remove folder/... segments) because
   // that will be done later.
-  return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)/i', 'url(\1'. $directory, $file);
+  return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)([^\'")]+)([\'"]?)\s*\)/i', 'url(\1' . $directory . '\2\3)', $file);
 }
 
 /**
@@ -3630,7 +3889,7 @@
 }
 
 /**
- * Prepare a string for use as a valid CSS identifier (element, class or ID name).
+ * Prepares a string for use as a CSS identifier (element, class, or ID name).
  *
  * http://www.w3.org/TR/CSS21/syndata.html#characters shows the syntax for valid
  * CSS identifiers (including element names, classes, and IDs in selectors.)
@@ -3639,10 +3898,26 @@
  *   The identifier to clean.
  * @param $filter
  *   An array of string replacements to use on the identifier.
+ *
  * @return
  *   The cleaned identifier.
  */
 function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['allow_css_double_underscores'] = &drupal_static(__FUNCTION__ . ':allow_css_double_underscores');
+  }
+  $allow_css_double_underscores = &$drupal_static_fast['allow_css_double_underscores'];
+  if (!isset($allow_css_double_underscores)) {
+    $allow_css_double_underscores = variable_get('allow_css_double_underscores', FALSE);
+  }
+
+  // Preserve BEM-style double-underscores depending on custom setting.
+  if ($allow_css_double_underscores) {
+    $filter['__'] = '__';
+  }
+
   // By default, we filter using Drupal's coding standards.
   $identifier = strtr($identifier, $filter);
 
@@ -3660,22 +3935,30 @@
 }
 
 /**
- * Prepare a string for use as a valid class name.
+ * Prepares a string for use as a valid class name.
  *
  * Do not pass one string containing multiple classes as they will be
  * incorrectly concatenated with dashes, i.e. "one two" will become "one-two".
  *
  * @param $class
  *   The class name to clean.
+ *
  * @return
  *   The cleaned class name.
  */
 function drupal_html_class($class) {
-  return drupal_clean_css_identifier(drupal_strtolower($class));
+  // The output of this function will never change, so this uses a normal
+  // static instead of drupal_static().
+  static $classes = array();
+
+  if (!isset($classes[$class])) {
+    $classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
+  }
+  return $classes[$class];
 }
 
 /**
- * Prepare a string for use as a valid HTML ID and guarantee uniqueness.
+ * Prepares a string for use as a valid HTML ID and guarantees uniqueness.
  *
  * This function ensures that each passed HTML ID value only exists once on the
  * page. By tracking the already returned ids, this function enables forms,
@@ -3706,7 +3989,11 @@
   // be merged with content already on the base page. The HTML IDs must be
   // unique for the fully merged content. Therefore, initialize $seen_ids to
   // take into account IDs that are already in use on the base page.
-  $seen_ids_init = &drupal_static(__FUNCTION__ . ':init');
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast['seen_ids_init'])) {
+    $drupal_static_fast['seen_ids_init'] = &drupal_static(__FUNCTION__ . ':init');
+  }
+  $seen_ids_init = &$drupal_static_fast['seen_ids_init'];
   if (!isset($seen_ids_init)) {
     // Ideally, Drupal would provide an API to persist state information about
     // prior page requests in the database, and we'd be able to add this
@@ -3726,7 +4013,16 @@
       // requested id. $_POST['ajax_html_ids'] contains the ids as they were
       // returned by this function, potentially with the appended counter, so
       // we parse that to reconstruct the $seen_ids array.
-      foreach ($_POST['ajax_html_ids'] as $seen_id) {
+      if (isset($_POST['ajax_html_ids'][0]) && strpos($_POST['ajax_html_ids'][0], ',') === FALSE) {
+        $ajax_html_ids = $_POST['ajax_html_ids'];
+      }
+      else {
+        // jquery.form.js may send the server a comma-separated string as the
+        // first element of an array (see http://drupal.org/node/1575060), so
+        // we need to convert it to an array in that case.
+        $ajax_html_ids = explode(',', $_POST['ajax_html_ids'][0]);
+      }
+      foreach ($ajax_html_ids as $seen_id) {
         // We rely on '--' being used solely for separating a base id from the
         // counter, which this function ensures when returning an id.
         $parts = explode('--', $seen_id, 2);
@@ -3742,7 +4038,10 @@
       }
     }
   }
-  $seen_ids = &drupal_static(__FUNCTION__, $seen_ids_init);
+  if (!isset($drupal_static_fast['seen_ids'])) {
+    $drupal_static_fast['seen_ids'] = &drupal_static(__FUNCTION__, $seen_ids_init);
+  }
+  $seen_ids = &$drupal_static_fast['seen_ids'];
 
   $id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
 
@@ -3806,7 +4105,7 @@
  *   to tell the user that a new message arrived, by opening a pop up, alert
  *   box, etc.). This should only be used for JavaScript that cannot be executed
  *   from a file. When adding inline code, make sure that you are not relying on
- *   $() being the jQuery function.  Wrap your code in
+ *   $() being the jQuery function. Wrap your code in
  *   @code (function ($) {... })(jQuery); @endcode
  *   or use jQuery() instead of $().
  * - Add external JavaScript ('external'): Allows the inclusion of external
@@ -3852,7 +4151,8 @@
  * actually needed.
  *
  * @param $data
- *   (optional) If given, the value depends on the $options parameter:
+ *   (optional) If given, the value depends on the $options parameter, or
+ *   $options['type'] if $options is passed as an associative array:
  *   - 'file': Path to the file relative to base_path().
  *   - 'inline': The JavaScript code that should be placed in the given scope.
  *   - 'external': The absolute path to an external JavaScript file that is not
@@ -3925,8 +4225,15 @@
  *       else being the same, JavaScript added by a call to drupal_add_js() that
  *       happened later in the page request gets added to the page after one for
  *       which drupal_add_js() happened earlier in the page request.
- *   - defer: If set to TRUE, the defer attribute is set on the &lt;script&gt;
- *     tag.  Defaults to FALSE.
+ *   - requires_jquery: Set this to FALSE if the JavaScript you are adding does
+ *     not have a dependency on jQuery. Defaults to TRUE, except for JavaScript
+ *     settings where it defaults to FALSE. This is used on sites that have the
+ *     'javascript_always_use_jquery' variable set to FALSE; on those sites, if
+ *     all the JavaScript added to the page by drupal_add_js() does not have a
+ *     dependency on jQuery, then for improved front-end performance Drupal
+ *     will not add jQuery and related libraries and settings to the page.
+ *   - defer: If set to TRUE, the defer attribute is set on the <script>
+ *     tag. Defaults to FALSE.
  *   - cache: If set to FALSE, the JavaScript file is loaded anew on every page
  *     call; in other words, it is not cached. Used only when 'type' references
  *     a JavaScript file. Defaults to TRUE.
@@ -3942,6 +4249,14 @@
  */
 function drupal_add_js($data = NULL, $options = NULL) {
   $javascript = &drupal_static(__FUNCTION__, array());
+  $jquery_added = &drupal_static(__FUNCTION__ . ':jquery_added', FALSE);
+
+  // If the $javascript variable has been reset with drupal_static_reset(),
+  // jQuery and related files will have been removed from the list, so set the
+  // variable back to FALSE to indicate they have not yet been added.
+  if (empty($javascript)) {
+    $jquery_added = FALSE;
+  }
 
   // Construct the options, taking the defaults into consideration.
   if (isset($options)) {
@@ -3952,6 +4267,9 @@
   else {
     $options = array();
   }
+  if (isset($options['type']) && $options['type'] == 'setting') {
+    $options += array('requires_jquery' => FALSE);
+  }
   $options += drupal_js_defaults($data);
 
   // Preprocess can only be set if caching is enabled.
@@ -3962,14 +4280,18 @@
   $options['weight'] += count($javascript) / 1000;
 
   if (isset($data)) {
-    // Add jquery.js and drupal.js, as well as the basePath setting, the
-    // first time a JavaScript file is added.
-    if (empty($javascript)) {
+    // Add jquery.js, drupal.js, and related files and settings if they have
+    // not been added yet. However, if the 'javascript_always_use_jquery'
+    // variable is set to FALSE (indicating that the site does not want jQuery
+    // automatically added on all pages) then only add it if a file or setting
+    // that requires jQuery is being added also.
+    if (!$jquery_added && (variable_get('javascript_always_use_jquery', TRUE) || $options['requires_jquery'])) {
+      $jquery_added = TRUE;
       // url() generates the prefix using hook_url_outbound_alter(). Instead of
       // running the hook_url_outbound_alter() again here, extract the prefix
       // from url().
       url('', array('prefix' => &$prefix));
-      $javascript = array(
+      $default_javascript = array(
         'settings' => array(
           'data' => array(
             array('basePath' => base_path()),
@@ -3988,11 +4310,13 @@
           'group' => JS_LIBRARY,
           'every_page' => TRUE,
           'weight' => -1,
+          'requires_jquery' => TRUE,
           'preprocess' => TRUE,
           'cache' => TRUE,
           'defer' => FALSE,
         ),
       );
+      $javascript = drupal_array_merge_deep($javascript, $default_javascript);
       // Register all required libraries.
       drupal_add_library('system', 'jquery', TRUE);
       drupal_add_library('system', 'jquery.once', TRUE);
@@ -4023,6 +4347,7 @@
  *
  * @param $data
  *   (optional) The default data parameter for the JavaScript item array.
+ *
  * @see drupal_get_js()
  * @see drupal_add_js()
  */
@@ -4032,6 +4357,7 @@
     'group' => JS_DEFAULT,
     'every_page' => FALSE,
     'weight' => 0,
+    'requires_jquery' => TRUE,
     'scope' => 'header',
     'cache' => TRUE,
     'defer' => FALSE,
@@ -4066,8 +4392,10 @@
  *   (optional) If set to TRUE, this function skips calling drupal_alter() on
  *   $javascript, useful when the calling function passes a $javascript array
  *   that has already been altered.
+ *
  * @return
  *   All JavaScript code segments and includes for the scope as HTML tags.
+ *
  * @see drupal_add_js()
  * @see locale_js_alter()
  * @see drupal_js_defaults()
@@ -4076,7 +4404,12 @@
   if (!isset($javascript)) {
     $javascript = drupal_add_js();
   }
-  if (empty($javascript)) {
+
+  // If no JavaScript items have been added, or if the only JavaScript items
+  // that have been added are JavaScript settings (which don't do anything
+  // without any JavaScript code to use them), then no JavaScript code should
+  // be added to the page.
+  if (empty($javascript) || (isset($javascript['settings']) && count($javascript) == 1)) {
     return '';
   }
 
@@ -4230,8 +4563,8 @@
  *
  * Libraries, JavaScript, CSS and other types of custom structures are attached
  * 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:
+ * associative array, where the keys are 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'),
@@ -4239,7 +4572,7 @@
  * );
  * @endcode
  *
- * 'js', 'css', and 'library' are types that get special handling.  For any
+ * '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
@@ -4590,16 +4923,16 @@
 }
 
 /**
- * Assist in adding the tableDrag JavaScript behavior to a themed table.
+ * Assists in adding the tableDrag JavaScript behavior to a themed table.
  *
  * Draggable tables should be used wherever an outline or list of sortable items
  * needs to be arranged by an end-user. Draggable tables are very flexible and
  * can manipulate the value of form elements placed within individual columns.
  *
- * To set up a table to use drag and drop in place of weight select-lists or
- * in place of a form that contains parent relationships, the form must be
- * themed into a table. The table must have an id attribute set. If using
- * theme_table(), the id may be set as such:
+ * To set up a table to use drag and drop in place of weight select-lists or in
+ * place of a form that contains parent relationships, the form must be themed
+ * into a table. The table must have an ID attribute set. If using
+ * theme_table(), the ID may be set as follows:
  * @code
  * $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'my-module-table')));
  * return $output;
@@ -4614,8 +4947,8 @@
  * $form['my_elements'][$delta]['weight']['#attributes']['class'] = array('my-elements-weight');
  * @endcode
  *
- * Each row of the table must also have a class of "draggable" in order to enable the
- * drag handles:
+ * Each row of the table must also have a class of "draggable" in order to
+ * enable the drag handles:
  * @code
  * $row = array(...);
  * $rows[] = array(
@@ -4635,8 +4968,8 @@
  * @endcode
  *
  * In a more complex case where there are several groups in one column (such as
- * the block regions on the admin/structure/block page), a separate subgroup class
- * must also be added to differentiate the groups.
+ * the block regions on the admin/structure/block page), a separate subgroup
+ * class must also be added to differentiate the groups.
  * @code
  * $form['my_elements'][$region][$delta]['weight']['#attributes']['class'] = array('my-elements-weight', 'my-elements-weight-' . $region);
  * @endcode
@@ -4653,14 +4986,14 @@
  *
  * In a situation where tree relationships are present, adding multiple
  * subgroups is not necessary, because the table will contain indentations that
- * provide enough information about the sibling and parent relationships.
- * See theme_menu_overview_form() for an example creating a table containing
- * parent relationships.
- *
- * Please note that this function should be called from the theme layer, such as
- * in a .tpl.php file, theme_ function, or in a template_preprocess function,
- * not in a form declaration. Though the same JavaScript could be added to the
- * page using drupal_add_js() directly, this function helps keep template files
+ * provide enough information about the sibling and parent relationships. See
+ * theme_menu_overview_form() for an example creating a table containing parent
+ * relationships.
+ *
+ * Note that this function should be called from the theme layer, such as in a
+ * .tpl.php file, theme_ function, or in a template_preprocess function, not in
+ * a form declaration. Though the same JavaScript could be added to the page
+ * using drupal_add_js() directly, this function helps keep template files
  * clean and readable. It also prevents tabledrag.js from being added twice
  * accidentally.
  *
@@ -4733,8 +5066,8 @@
  * $files while the value is the cache file name. The cache file is generated
  * in two cases. First, if there is no file name value for the key, which will
  * happen if a new file name has been added to $files or after the lookup
- * variable is emptied to force a rebuild of the cache.  Second, the cache
- * file is generated if it is missing on disk. Old cache files are not deleted
+ * variable is emptied to force a rebuild of the cache. Second, the cache file
+ * is generated if it is missing on disk. Old cache files are not deleted
  * immediately when the lookup variable is emptied, but are deleted after a set
  * period by drupal_delete_file_if_stale(). This ensures that files referenced
  * by a cached page will still be available.
@@ -4749,7 +5082,13 @@
   $contents = '';
   $uri = '';
   $map = variable_get('drupal_js_cache_files', array());
-  $key = hash('sha256', serialize($files));
+  // Create a new array so that only the file names are used to create the hash.
+  // This prevents new aggregates from being created unnecessarily.
+  $js_data = array();
+  foreach ($files as $file) {
+    $js_data[] = $file['data'];
+  }
+  $key = hash('sha256', serialize($js_data));
   if (isset($map[$key])) {
     $uri = $map[$key];
   }
@@ -4800,14 +5139,29 @@
 /**
  * Converts a PHP variable into its JavaScript equivalent.
  *
- * We use HTML-safe strings, i.e. with <, > and & escaped.
+ * We use HTML-safe strings, with several characters escaped.
  *
  * @see drupal_json_decode()
+ * @see drupal_json_encode_helper()
  * @ingroup php_wrappers
  */
 function drupal_json_encode($var) {
-  // json_encode() does not escape <, > and &, so we do it with str_replace().
-  return str_replace(array('<', '>', '&'), array('\u003c', '\u003e', '\u0026'), json_encode($var));
+  // The PHP version cannot change within a request.
+  static $php530;
+
+  if (!isset($php530)) {
+    $php530 = version_compare(PHP_VERSION, '5.3.0', '>=');
+  }
+
+  if ($php530) {
+    // Encode <, >, ', &, and " using the json_encode() options parameter.
+    return json_encode($var, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
+  }
+
+  // json_encode() escapes <, >, ', &, and " using its options parameter, but
+  // does not support this parameter prior to PHP 5.3.0.  Use a helper instead.
+  include_once DRUPAL_ROOT . '/includes/json-encode.inc';
+  return drupal_json_encode_helper($var);
 }
 
 /**
@@ -4821,7 +5175,7 @@
 }
 
 /**
- * Return data in JSON format.
+ * Returns data in JSON format.
  *
  * This function should be used for JavaScript callback functions returning
  * data in JSON format. It sets the header for JavaScript output.
@@ -4839,44 +5193,43 @@
 }
 
 /**
- * Get a salt useful for hardening against SQL injection.
- *
- * @return
- *   A salt based on information in settings.php, not in the database.
- */
-function drupal_get_hash_salt() {
-  global $drupal_hash_salt, $databases;
-  // If the $drupal_hash_salt variable is empty, a hash of the serialized
-  // database credentials is used as a fallback salt.
-  return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
-}
-
-/**
- * Ensure the private key variable used to generate tokens is set.
+ * Ensures the private key variable used to generate tokens is set.
  *
  * @return
  *   The private key.
  */
 function drupal_get_private_key() {
   if (!($key = variable_get('drupal_private_key', 0))) {
-    $key = drupal_hash_base64(drupal_random_bytes(55));
+    $key = drupal_random_key();
     variable_set('drupal_private_key', $key);
   }
   return $key;
 }
 
 /**
- * Generate a token based on $value, the current user session and private key.
+ * Generates a token based on $value, the user session, and the private key.
  *
  * @param $value
  *   An additional value to base the token on.
+ *
+ * The generated token is based on the session ID of the current user. Normally,
+ * anonymous users do not have a session, so the generated token will be
+ * different on every page request. To generate a token for users without a
+ * session, manually start a session prior to calling this function.
+ *
+ * @return string
+ *   A 43-character URL-safe token for validation, based on the user session ID,
+ *   the hash salt provided from drupal_get_hash_salt(), and the
+ *   'drupal_private_key' configuration variable.
+ *
+ * @see drupal_get_hash_salt()
  */
 function drupal_get_token($value = '') {
   return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
 }
 
 /**
- * Validate a token based on $value, the current user session and private key.
+ * Validates a token based on $value, the user session, and the private key.
  *
  * @param $token
  *   The token to be validated.
@@ -4884,13 +5237,14 @@
  *   An additional value to base the token on.
  * @param $skip_anonymous
  *   Set to true to skip token validation for anonymous users.
+ *
  * @return
  *   True for a valid token, false for an invalid token. When $skip_anonymous
  *   is true, the return value will always be true for anonymous users.
  */
 function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
   global $user;
-  return (($skip_anonymous && $user->uid == 0) || ($token == drupal_get_token($value)));
+  return (($skip_anonymous && $user->uid == 0) || ($token === drupal_get_token($value)));
 }
 
 function _drupal_bootstrap_full() {
@@ -4921,8 +5275,17 @@
   fix_gpc_magic();
   // Load all enabled modules
   module_load_all();
+  // Reset drupal_alter() and module_implements() static caches as these
+  // include implementations for vital modules only when called early on
+  // in the bootstrap.
+  drupal_static_reset('drupal_alter');
+  drupal_static_reset('module_implements');
   // Make sure all stream wrappers are registered.
   file_get_stream_wrappers();
+  // Ensure mt_rand is reseeded, to prevent random values from one page load
+  // being exploited to predict random values in subsequent page loads.
+  $seed = unpack("L", drupal_random_bytes(4));
+  mt_srand($seed[1]);
 
   $test_info = &$GLOBALS['drupal_test_info'];
   if (!empty($test_info['in_child_site'])) {
@@ -4952,7 +5315,7 @@
 }
 
 /**
- * Store the current page in the cache.
+ * Stores the current page in the cache.
  *
  * If page_compression is enabled, a gzipped version of the page is stored in
  * the cache to avoid compressing the output on each request. The cache entry
@@ -4960,7 +5323,7 @@
  * client without gzip support.
  *
  * Page compression requires the PHP zlib extension
- * (http://php.net/manual/en/ref.zlib.php).
+ * (http://php.net/manual/ref.zlib.php).
  *
  * @see drupal_page_header()
  */
@@ -4968,6 +5331,10 @@
   global $base_root;
 
   if (drupal_page_is_cacheable()) {
+
+    // Check whether the current page might be compressed.
+    $page_compressed = variable_get('page_compression', TRUE) && extension_loaded('zlib');
+
     $cache = (object) array(
       'cid' => $base_root . request_uri(),
       'data' => array(
@@ -4975,6 +5342,9 @@
         'body' => ob_get_clean(),
         'title' => drupal_get_title(),
         'headers' => array(),
+        // We need to store whether page was compressed or not,
+        // because by the time it is read, the configuration might change.
+        'page_compressed' => $page_compressed,
       ),
       'expire' => CACHE_TEMPORARY,
       'created' => REQUEST_TIME,
@@ -4992,7 +5362,7 @@
     }
 
     if ($cache->data['body']) {
-      if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
+      if ($page_compressed) {
         $cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
       }
       cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire);
@@ -5004,16 +5374,17 @@
 /**
  * Executes a cron run when called.
  *
- * Do not call this function from test, use $this->cronRun() instead.
+ * Do not call this function from a test. Use $this->cronRun() instead.
  *
- * @return
- *   Returns TRUE if ran successfully
+ * @return bool
+ *   TRUE if cron ran successfully and FALSE if cron is already running.
  */
 function drupal_cron_run() {
   // Allow execution to continue even if the request gets canceled.
   @ignore_user_abort(TRUE);
 
   // Prevent session information from being saved while cron is running.
+  $original_session_saving = drupal_save_session();
   drupal_save_session(FALSE);
 
   // Force the current user to anonymous to ensure consistent permissions on
@@ -5040,8 +5411,6 @@
     foreach ($queues as $queue_name => $info) {
       DrupalQueue::get($queue_name)->createQueue();
     }
-    // Register shutdown callback
-    drupal_register_shutdown_function('drupal_cron_cleanup');
 
     // Iterate through the modules calling their cron handlers (if any):
     foreach (module_implements('cron') as $module) {
@@ -5054,7 +5423,7 @@
       }
     }
 
-    // Record cron time
+    // Record cron time.
     variable_set('cron_last', REQUEST_TIME);
     watchdog('cron', 'Cron run completed.', array(), WATCHDOG_NOTICE);
 
@@ -5066,30 +5435,47 @@
   }
 
   foreach ($queues as $queue_name => $info) {
-    $function = $info['worker callback'];
+    if (!empty($info['skip on cron'])) {
+      // Do not run if queue wants to skip.
+      continue;
+    }
+    $callback = $info['worker callback'];
     $end = time() + (isset($info['time']) ? $info['time'] : 15);
     $queue = DrupalQueue::get($queue_name);
     while (time() < $end && ($item = $queue->claimItem())) {
-      $function($item->data);
-      $queue->deleteItem($item);
+      try {
+        call_user_func($callback, $item->data);
+        $queue->deleteItem($item);
+      }
+      catch (Exception $e) {
+        // In case of exception log it and leave the item in the queue
+        // to be processed again later.
+        watchdog_exception('cron', $e);
+      }
     }
   }
   // Restore the user.
   $GLOBALS['user'] = $original_user;
-  drupal_save_session(TRUE);
+  drupal_save_session($original_session_saving);
 
   return $return;
 }
 
 /**
- * Shutdown function for cron cleanup.
+ * DEPRECATED: Shutdown function: Performs cron cleanup.
+ *
+ * This function is deprecated because the 'cron_semaphore' variable it
+ * references no longer exists. It is therefore no longer used as a shutdown
+ * function by Drupal core.
+ *
+ * @deprecated
  */
 function drupal_cron_cleanup() {
   // See if the semaphore is still locked.
   if (variable_get('cron_semaphore', FALSE)) {
     watchdog('cron', 'Cron run exceeded the time limit and was aborted.', array(), WATCHDOG_WARNING);
 
-    // Release cron semaphore
+    // Release cron semaphore.
     variable_del('cron_semaphore');
   }
 }
@@ -5105,7 +5491,7 @@
  * drupal_system_listing("/\.module$/", "modules", 'name', 0);
  * @endcode
  * this function will search the site-wide modules directory (i.e., /modules/),
- * your install profile's directory (i.e.,
+ * your installation profile's directory (i.e.,
  * /profiles/your_site_profile/modules/), the all-sites directory (i.e.,
  * /sites/all/modules/), and your site-specific directory (i.e.,
  * /sites/your_site_dir/modules/), in that order, and return information about
@@ -5145,8 +5531,6 @@
 function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1) {
   $config = conf_path();
 
-  $profile = drupal_get_profile();
-
   $searchdir = array($directory);
   $files = array();
 
@@ -5154,18 +5538,34 @@
   // themes as organized by a distribution. It is pristine in the same way
   // that /modules is pristine for core; users should avoid changing anything
   // there in favor of sites/all or sites/<domain> directories.
-  if (file_exists("profiles/$profile/$directory")) {
-    $searchdir[] = "profiles/$profile/$directory";
+  $profiles = array();
+  $profile = drupal_get_profile();
+  // For SimpleTest to be able to test modules packaged together with a
+  // distribution we need to include the profile of the parent site (in which
+  // test runs are triggered).
+  if (drupal_valid_test_ua()) {
+    $testing_profile = variable_get('simpletest_parent_profile', FALSE);
+    if ($testing_profile && $testing_profile != $profile) {
+      $profiles[] = $testing_profile;
+    }
+  }
+  // In case both profile directories contain the same extension, the actual
+  // profile always has precedence.
+  $profiles[] = $profile;
+  foreach ($profiles as $profile) {
+    if (file_exists("profiles/$profile/$directory")) {
+      $searchdir[] = "profiles/$profile/$directory";
+    }
   }
 
-  // Always search sites/all/* as well as the global directories
+  // Always search sites/all/* as well as the global directories.
   $searchdir[] = 'sites/all/' . $directory;
 
   if (file_exists("$config/$directory")) {
     $searchdir[] = "$config/$directory";
   }
 
-  // Get current list of items
+  // Get current list of items.
   if (!function_exists('file_scan_directory')) {
     require_once DRUPAL_ROOT . '/includes/file.inc';
   }
@@ -5201,7 +5601,7 @@
 }
 
 /**
- * Set the main page content value for later use.
+ * Sets the main page content value for later use.
  *
  * Given the nature of the Drupal page handling, this will be called once with
  * a string or array. We store that and return it later as the block is being
@@ -5209,6 +5609,7 @@
  *
  * @param $content
  *   A string or renderable array representing the body of the page.
+ *
  * @return
  *   If called without $content, a renderable array representing the body of
  *   the page.
@@ -5380,7 +5781,7 @@
  * @code
  * $node->content['links'] = array(
  *   '#theme' => 'links__node',
- *   '#pre_render' = array('drupal_pre_render_links'),
+ *   '#pre_render' => array('drupal_pre_render_links'),
  *   'comment' => array(
  *     '#theme' => 'links__node__comment',
  *     '#links' => array(
@@ -5459,13 +5860,13 @@
  * Note that if also a #theme is defined for the element, then the result of
  * the theme callback will override #children.
  *
- * @see drupal_render()
- *
  * @param $elements
  *   A structured array using the #markup key.
  *
  * @return
  *   The passed-in elements, but #markup appended to #children.
+ *
+ * @see drupal_render()
  */
 function drupal_pre_render_markup($elements) {
   $elements['#children'] = $elements['#markup'];
@@ -5478,8 +5879,10 @@
  * @param $page
  *   A string or array representing the content of a page. The array consists of
  *   the following keys:
- *   - #type: Value is always 'page'. This pushes the theming through page.tpl.php (required).
- *   - #show_messages: Suppress drupal_get_message() items. Used by Batch API (optional).
+ *   - #type: Value is always 'page'. This pushes the theming through
+ *     page.tpl.php (required).
+ *   - #show_messages: Suppress drupal_get_message() items. Used by Batch
+ *     API (optional).
  *
  * @see hook_page_alter()
  * @see element_info()
@@ -5535,8 +5938,9 @@
  * any children, it is the responsibility of the theme function to render
  * these children. For elements that are not allowed to have any children,
  * e.g. buttons or textfields, the theme function can be used to render the
- * element itself. If #theme is not present and the element has children, they
- * are rendered and concatenated into a string by drupal_render_children().
+ * element itself. If #theme is not present and the element has children, each
+ * child is itself rendered by a call to drupal_render(), and the results are
+ * concatenated.
  *
  * The #theme_wrappers property contains an array of theme functions which will
  * be called, in order, after #theme has run. These can be used to add further
@@ -5556,20 +5960,20 @@
  * drupal_render() can optionally cache the rendered output of elements to
  * improve performance. To use drupal_render() caching, set the element's #cache
  * property to an associative array with one or several of the following keys:
- *    - 'keys': An array of one or more keys that identify the element. If 'keys'
- *       is set, the cache ID is created automatically from these keys. See
- *       drupal_render_cid_create().
- *    - 'granularity' (optional): Define the cache granularity using binary
- *       combinations of the cache granularity constants, e.g. DRUPAL_CACHE_PER_USER
- *       to cache for each user separately or
- *       DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE to cache separately for each
- *       page and role. If not specified the element is cached globally for each
- *       theme and language.
- *    - 'cid': Specify the cache ID directly. Either 'keys' or 'cid' is required.
- *       If 'cid' is set, 'keys' and 'granularity' are ignored. Use only if you
- *       have special requirements.
- *    - 'expire': Set to one of the cache lifetime constants.
- *    - 'bin': Specify a cache bin to cache the element in. Defaults to 'cache'.
+ * - 'keys': An array of one or more keys that identify the element. If 'keys'
+ *   is set, the cache ID is created automatically from these keys. See
+ *   drupal_render_cid_create().
+ * - 'granularity' (optional): Define the cache granularity using binary
+ *   combinations of the cache granularity constants, e.g.
+ *   DRUPAL_CACHE_PER_USER to cache for each user separately or
+ *   DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE to cache separately for each
+ *   page and role. If not specified the element is cached globally for each
+ *   theme and language.
+ * - 'cid': Specify the cache ID directly. Either 'keys' or 'cid' is required.
+ *   If 'cid' is set, 'keys' and 'granularity' are ignored. Use only if you
+ *   have special requirements.
+ * - 'expire': Set to one of the cache lifetime constants.
+ * - 'bin': Specify a cache bin to cache the element in. Defaults to 'cache'.
  *
  * This function is usually called from within another function, like
  * drupal_get_form() or a theme function. Elements are sorted internally
@@ -5582,27 +5986,31 @@
  * array to be rendered independently and prevents them from being rendered
  * more than once on subsequent calls to drupal_render() (e.g., as part of a
  * larger array). If the same array or array element is passed more than once
- * to drupal_render(), it simply returns a NULL value.
+ * to drupal_render(), it simply returns an empty string.
  *
- * @param $elements
+ * @param array $elements
  *   The structured array describing the data to be rendered.
- * @return
+ *
+ * @return string
  *   The rendered HTML.
  */
 function drupal_render(&$elements) {
   // Early-return nothing if user does not have access.
   if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
-    return;
+    return '';
   }
 
   // Do not print elements twice.
   if (!empty($elements['#printed'])) {
-    return;
+    return '';
   }
 
   // Try to fetch the element's markup from cache and return.
-  if (isset($elements['#cache']) && $cached_output = drupal_render_cache_get($elements)) {
-    return $cached_output;
+  if (isset($elements['#cache'])) {
+    $cached_output = drupal_render_cache_get($elements);
+    if ($cached_output !== FALSE) {
+      return $cached_output;
+    }
   }
 
   // If #markup is set, ensure #type is set. This allows to specify just #markup
@@ -5630,7 +6038,7 @@
 
   // Allow #pre_render to abort rendering.
   if (!empty($elements['#printed'])) {
-    return;
+    return '';
   }
 
   // Get the children of the element, sorted by weight.
@@ -5699,16 +6107,18 @@
 }
 
 /**
- * Render children of an element and concatenate them.
+ * Renders children of an element and concatenates them.
  *
- * This renders all children of an element using drupal_render() and then
- * joins them together into a single string.
- *
- * @param $element
+ * @param array $element
  *   The structured array whose children shall be rendered.
- * @param $children_keys
- *   If the keys of the element's children are already known, they can be passed
- *   in to save another run of element_children().
+ * @param array $children_keys
+ *   (optional) If the keys of the element's children are already known, they
+ *   can be passed in to save another run of element_children().
+ *
+ * @return string
+ *   The rendered HTML of all children of the element.
+
+ * @see drupal_render()
  */
 function drupal_render_children(&$element, $children_keys = NULL) {
   if ($children_keys === NULL) {
@@ -5724,7 +6134,7 @@
 }
 
 /**
- * Render an element.
+ * Renders an element.
  *
  * This function renders an element using drupal_render(). The top level
  * element is shown with show() before rendering, so it will always be rendered
@@ -5753,7 +6163,7 @@
 }
 
 /**
- * Hide an element from later rendering.
+ * Hides an element from later rendering.
  *
  * The first time render() or drupal_render() is called on an element tree,
  * as each element in the tree is rendered, it is marked with a #printed flag
@@ -5779,7 +6189,7 @@
 }
 
 /**
- * Show a hidden element for later rendering.
+ * Shows a hidden element for later rendering.
  *
  * You can also use render($element), which shows the element while rendering
  * it.
@@ -5808,16 +6218,17 @@
 }
 
 /**
- * Get the rendered output of a renderable element from cache.
- *
- * @see drupal_render()
- * @see drupal_render_cache_set()
+ * Gets the rendered output of a renderable element from the cache.
  *
  * @param $elements
  *   A renderable array.
+ *
  * @return
  *   A markup string containing the rendered content of the element, or FALSE
  *   if no cached copy of the element is available.
+ *
+ * @see drupal_render()
+ * @see drupal_render_cache_set()
  */
 function drupal_render_cache_get($elements) {
   if (!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) || !$cid = drupal_render_cid_create($elements)) {
@@ -5838,17 +6249,17 @@
 }
 
 /**
- * Cache the rendered output of a renderable element.
+ * Caches the rendered output of a renderable element.
  *
- * This is called by drupal_render() if the #cache property is set on an element.
- *
- * @see drupal_render()
- * @see drupal_render_cache_get()
+ * This is called by drupal_render() if the #cache property is set on an
+ * element.
  *
  * @param $markup
  *   The rendered output string of $elements.
  * @param $elements
  *   A renderable array.
+ *
+ * @see drupal_render_cache_get()
  */
 function drupal_render_cache_set(&$markup, $elements) {
   // Create the cache ID for the element.
@@ -5874,7 +6285,7 @@
 }
 
 /**
- * Collect #attached for an element and all child elements into a single array.
+ * Collects #attached for an element and its children into a single array.
  *
  * When caching elements, it is necessary to collect all libraries, JavaScript
  * and CSS into a single array, from both the element itself and all child
@@ -5917,9 +6328,10 @@
 }
 
 /**
- * Prepare an element for caching based on a query. This smart caching strategy
- * saves Drupal from querying and rendering to HTML when the underlying query is
- * unchanged.
+ * Prepares an element for caching based on a query.
+ *
+ * This smart caching strategy saves Drupal from querying and rendering to HTML
+ * when the underlying query is unchanged.
  *
  * Expensive queries should use the query builder to create the query and then
  * call this function. Executing the query and formatting results should happen
@@ -5957,12 +6369,15 @@
 }
 
 /**
- * Helper function for building cache ids.
+ * Returns cache ID parts for building a cache ID.
  *
  * @param $granularity
- *   One or more cache granularity constants, e.g. DRUPAL_CACHE_PER_USER to cache
- *   for each user separately or DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE to
- *   cache separately for each page and role.
+ *   One or more cache granularity constants. For example, to cache separately
+ *   for each user, use DRUPAL_CACHE_PER_USER. To cache separately for each
+ *   page and role, use the expression:
+ *   @code
+ *   DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE
+ *   @endcode
  *
  * @return
  *   An array of cache ID parts, always containing the active theme. If the
@@ -5982,13 +6397,21 @@
   }
 
   if (!empty($granularity)) {
+    $cache_per_role = $granularity & DRUPAL_CACHE_PER_ROLE;
+    $cache_per_user = $granularity & DRUPAL_CACHE_PER_USER;
+    // User 1 has special permissions outside of the role system, so when
+    // caching per role is requested, it should cache per user instead.
+    if ($user->uid == 1 && $cache_per_role) {
+      $cache_per_user = TRUE;
+      $cache_per_role = FALSE;
+    }
     // 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a
     // resource drag for sites with many users, so when a module is being
     // equivocal, we favor the less expensive 'PER_ROLE' pattern.
-    if ($granularity & DRUPAL_CACHE_PER_ROLE) {
+    if ($cache_per_role) {
       $cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
     }
-    elseif ($granularity & DRUPAL_CACHE_PER_USER) {
+    elseif ($cache_per_user) {
       $cid_parts[] = "u.$user->uid";
     }
 
@@ -6001,7 +6424,7 @@
 }
 
 /**
- * Create the cache ID for a renderable element.
+ * Creates the cache ID for a renderable element.
  *
  * This creates the cache ID string, either by returning the #cache['cid']
  * property if present or by building the cache ID out of the #cache['keys']
@@ -6048,7 +6471,7 @@
 }
 
 /**
- * Retrieve the default properties for the defined element type.
+ * Retrieves the default properties for the defined element type.
  *
  * @param $type
  *   An element type as defined by hook_element_info().
@@ -6074,7 +6497,7 @@
 }
 
 /**
- * Retrieve a single property for the defined element type.
+ * Retrieves a single property for the defined element type.
  *
  * @param $type
  *   An element type as defined by hook_element_info().
@@ -6089,7 +6512,19 @@
 }
 
 /**
- * Function used by uasort to sort structured arrays by weight, without the property weight prefix.
+ * Sorts a structured array by the 'weight' element.
+ *
+ * Note that the sorting is by the 'weight' array element, not by the render
+ * element property '#weight'.
+ *
+ * Callback for uasort() used in various functions.
+ *
+ * @param $a
+ *   First item for comparison. The compared items should be associative arrays
+ *   that optionally include a 'weight' element. For items without a 'weight'
+ *   element, a default value of 0 will be used.
+ * @param $b
+ *   Second item for comparison.
  */
 function drupal_sort_weight($a, $b) {
   $a_weight = (is_array($a) && isset($a['weight'])) ? $a['weight'] : 0;
@@ -6114,21 +6549,21 @@
 }
 
 /**
- * Check if the key is a property.
+ * Checks if the key is a property.
  */
 function element_property($key) {
   return $key[0] == '#';
 }
 
 /**
- * Get properties of a structured array element. Properties begin with '#'.
+ * Gets properties of a structured array element (keys beginning with '#').
  */
 function element_properties($element) {
   return array_filter(array_keys((array) $element), 'element_property');
 }
 
 /**
- * Check if the key is a child.
+ * Checks if the key is a child.
  */
 function element_child($key) {
   return !isset($key[0]) || $key[0] != '#';
@@ -6144,6 +6579,7 @@
  *   The element array whose children are to be identified.
  * @param $sort
  *   Boolean to indicate whether the children should be sorted by weight.
+ *
  * @return
  *   The array keys of the element's children.
  */
@@ -6183,6 +6619,7 @@
  *
  * @param $elements
  *   The parent element.
+ *
  * @return
  *   The array keys of the element's visible children.
  */
@@ -6234,6 +6671,44 @@
 }
 
 /**
+ * Recursively computes the difference of arrays with additional index check.
+ *
+ * This is a version of array_diff_assoc() that supports multidimensional
+ * arrays.
+ *
+ * @param array $array1
+ *   The array to compare from.
+ * @param array $array2
+ *   The array to compare to.
+ *
+ * @return array
+ *   Returns an array containing all the values from array1 that are not present
+ *   in array2.
+ */
+function drupal_array_diff_assoc_recursive($array1, $array2) {
+  $difference = array();
+
+  foreach ($array1 as $key => $value) {
+    if (is_array($value)) {
+      if (!array_key_exists($key, $array2) || !is_array($array2[$key])) {
+        $difference[$key] = $value;
+      }
+      else {
+        $new_diff = drupal_array_diff_assoc_recursive($value, $array2[$key]);
+        if (!empty($new_diff)) {
+          $difference[$key] = $new_diff;
+        }
+      }
+    }
+    elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
+      $difference[$key] = $value;
+    }
+  }
+
+  return $difference;
+}
+
+/**
  * Sets a value in a nested array with variable depth.
  *
  * This helper function should be used when the depth of the array element you
@@ -6326,10 +6801,10 @@
  * $value = drupal_array_get_nested_value($form, $parents);
  * @endcode
  *
- * The return value will be NULL, regardless of whether the actual value is NULL
- * or whether the requested key does not exist. If it is required to know
- * whether the nested array key actually exists, pass a third argument that is
- * altered by reference:
+ * A return value of NULL is ambiguous, and can mean either that the requested
+ * key does not exist, or that the actual value is NULL. If it is required to
+ * know whether the nested array key actually exists, pass a third argument that
+ * is altered by reference:
  * @code
  * $key_exists = NULL;
  * $value = drupal_array_get_nested_value($form, $parents, $key_exists);
@@ -6361,7 +6836,7 @@
  *
  * @see drupal_array_set_nested_value()
  */
-function drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
+function &drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
   $ref = &$array;
   foreach ($parents as $parent) {
     if (is_array($ref) && array_key_exists($parent, $ref)) {
@@ -6369,7 +6844,8 @@
     }
     else {
       $key_exists = FALSE;
-      return NULL;
+      $null = NULL;
+      return $null;
     }
   }
   $key_exists = TRUE;
@@ -6377,7 +6853,7 @@
 }
 
 /**
- * Determines whether a nested array with variable depth contains all of the requested keys.
+ * Determines whether a nested array contains the requested keys.
  *
  * This helper function should be used when the depth of the array element to be
  * checked may vary (that is, the number of parent keys is variable). See
@@ -6413,11 +6889,11 @@
 }
 
 /**
- * Provide theme registration for themes across .inc files.
+ * Provides theme registration for themes across .inc files.
  */
 function drupal_common_theme() {
   return array(
-    // theme.inc
+    // From theme.inc.
     'html' => array(
       'render element' => 'page',
       'template' => 'html',
@@ -6493,7 +6969,7 @@
     'html_tag' => array(
       'render element' => 'element',
     ),
-    // from theme.maintenance.inc
+    // From theme.maintenance.inc.
     'maintenance_page' => array(
       'variables' => array('content' => NULL, 'show_messages' => TRUE),
       'template' => 'maintenance-page',
@@ -6513,7 +6989,7 @@
     'authorize_report' => array(
       'variables' => array('messages' => array()),
     ),
-    // from pager.inc
+    // From pager.inc.
     'pager' => array(
       'variables' => array('tags' => array(), 'element' => 0, 'parameters' => array(), 'quantity' => 9),
     ),
@@ -6532,7 +7008,7 @@
     'pager_link' => array(
       'variables' => array('text' => NULL, 'page_new' => NULL, 'element' => NULL, 'parameters' => array(), 'attributes' => array()),
     ),
-    // from menu.inc
+    // From menu.inc.
     'menu_link' => array(
       'render element' => 'element',
     ),
@@ -6548,7 +7024,7 @@
     'menu_local_tasks' => array(
       'variables' => array('primary' => array(), 'secondary' => array()),
     ),
-    // from form.inc
+    // From form.inc.
     'select' => array(
       'render element' => 'element',
     ),
@@ -6619,12 +7095,12 @@
 }
 
 /**
- * @ingroup schemaapi
+ * @addtogroup schemaapi
  * @{
  */
 
 /**
- * Creates all tables in a module's hook_schema() implementation.
+ * Creates all tables defined in a module's hook_schema().
  *
  * Note: This function does not pass the module's schema through
  * hook_schema_alter(). The module's tables will be created exactly as the
@@ -6643,7 +7119,7 @@
 }
 
 /**
- * Remove all tables that a module defines in its hook_schema().
+ * Removes all tables defined in a module's hook_schema().
  *
  * Note: This function does not pass the module's schema through
  * hook_schema_alter(). The module's tables will be created exactly as the
@@ -6651,6 +7127,7 @@
  *
  * @param $module
  *   The module for which the tables will be removed.
+ *
  * @return
  *   An array of arrays with the following key/value pairs:
  *    - success: a boolean indicating whether the query succeeded.
@@ -6674,7 +7151,8 @@
  * specification of a schema, as it was defined in a module's
  * hook_schema(). No additional default values will be set,
  * hook_schema_alter() is not invoked and these unprocessed
- * definitions won't be cached.
+ * definitions won't be cached. To retrieve the schema after
+ * hook_schema_alter() has been invoked use drupal_get_schema().
  *
  * This function can be used to retrieve a schema specification in
  * hook_schema(), so it allows you to derive your tables from existing
@@ -6706,7 +7184,7 @@
 }
 
 /**
- * Fill in required default values for table definitions returned by hook_schema().
+ * Fills in required default values for table definitions from hook_schema().
  *
  * @param $schema
  *   The schema definition array as it was returned by the module's
@@ -6737,7 +7215,27 @@
 }
 
 /**
- * Retrieve a list of fields from a table schema. The list is suitable for use in a SQL query.
+ * Retrieves the type for every field in a table schema.
+ *
+ * @param $table
+ *   The name of the table from which to retrieve type information.
+ *
+ * @return
+ *   An array of types, keyed by field name.
+ */
+function drupal_schema_field_types($table) {
+  $table_schema = drupal_get_schema($table);
+  $field_types = array();
+  foreach ($table_schema['fields'] as $field_name => $field_info) {
+    $field_types[$field_name] = isset($field_info['type']) ? $field_info['type'] : NULL;
+  }
+  return $field_types;
+}
+
+/**
+ * Retrieves a list of fields from a table schema.
+ *
+ * The returned list is suitable for use in an SQL query.
  *
  * @param $table
  *   The name of the table from which to retrieve fields.
@@ -6745,7 +7243,7 @@
  *   An optional prefix to to all fields.
  *
  * @return An array of fields.
- **/
+ */
 function drupal_schema_fields_sql($table, $prefix = NULL) {
   $schema = drupal_get_schema($table);
   $fields = array_keys($schema['fields']);
@@ -6764,6 +7262,10 @@
 /**
  * Saves (inserts or updates) a record to the database based upon the schema.
  *
+ * Do not use drupal_write_record() within hook_update_N() functions, since the
+ * database schema cannot be relied upon when a user is running a series of
+ * updates. Instead, use db_insert() or db_update() to save the record.
+ *
  * @param $table
  *   The name of the table; this must be defined by a hook_schema()
  *   implementation.
@@ -6919,7 +7421,7 @@
 }
 
 /**
- * @} End of "ingroup schemaapi".
+ * @} End of "addtogroup schemaapi".
  */
 
 /**
@@ -6931,7 +7433,16 @@
  * Information stored in a module .info file:
  * - name: The real name of the module for display purposes.
  * - description: A brief description of the module.
- * - dependencies: An array of shortnames of other modules this module requires.
+ * - dependencies: An array of dependency strings. Each is in the form
+ *   'project:module (versions)'; with the following meanings:
+ *   - project: (optional) Project shortname, recommended to ensure uniqueness,
+ *     if the module is part of a project hosted on drupal.org. If omitted,
+ *     also omit the : that follows. The project name is currently ignored by
+ *     Drupal core but is used for automated testing.
+ *   - module: (required) Module shortname within the project.
+ *   - (versions): Optional version information, consisting of one or more
+ *     comma-separated operator/value pairs or simply version numbers, which
+ *     can contain "x" as a wildcard. Examples: (>=7.22, <7.28), (7.x-3.x).
  * - package: The name of the package of modules this module belongs to.
  *
  * See forum.info for an example of a module .info file.
@@ -6973,7 +7484,7 @@
 }
 
 /**
- * Parse data in Drupal's .info format.
+ * Parses data in Drupal's .info format.
  *
  * Data should be in an .ini-like format to specify values. White-space
  * generally doesn't matter, except inside values:
@@ -7003,6 +7514,7 @@
  *
  * @param $data
  *   A string to parse.
+ *
  * @return
  *   The info array.
  *
@@ -7010,7 +7522,6 @@
  */
 function drupal_parse_info_format($data) {
   $info = array();
-  $constants = get_defined_constants();
 
   if (preg_match_all('
     @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
@@ -7026,19 +7537,19 @@
     )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
     @msx', $data, $matches, PREG_SET_ORDER)) {
     foreach ($matches as $match) {
-      // Fetch the key and value string
+      // Fetch the key and value string.
       $i = 0;
       foreach (array('key', 'value1', 'value2', 'value3') as $var) {
         $$var = isset($match[++$i]) ? $match[$i] : '';
       }
       $value = stripslashes(substr($value1, 1, -1)) . stripslashes(substr($value2, 1, -1)) . $value3;
 
-      // Parse array syntax
+      // Parse array syntax.
       $keys = preg_split('/\]?\[/', rtrim($key, ']'));
       $last = array_pop($keys);
       $parent = &$info;
 
-      // Create nested arrays
+      // Create nested arrays.
       foreach ($keys as $key) {
         if ($key == '') {
           $key = count($parent);
@@ -7050,11 +7561,11 @@
       }
 
       // Handle PHP constants.
-      if (isset($constants[$value])) {
-        $value = $constants[$value];
+      if (preg_match('/^\w+$/i', $value) && defined($value)) {
+        $value = constant($value);
       }
 
-      // Insert actual value
+      // Insert actual value.
       if ($last == '') {
         $last = count($parent);
       }
@@ -7066,11 +7577,12 @@
 }
 
 /**
- * Severity levels, as defined in RFC 3164: http://www.ietf.org/rfc/rfc3164.txt.
+ * Returns a list of severity levels, as defined in RFC 3164.
  *
  * @return
  *   Array of the possible severity levels for log messages.
  *
+ * @see http://www.ietf.org/rfc/rfc3164.txt
  * @see watchdog()
  * @ingroup logging_severity_levels
  */
@@ -7089,7 +7601,7 @@
 
 
 /**
- * Explode a string of given tags into an array.
+ * Explodes a string of tags into an array.
  *
  * @see drupal_implode_tags()
  */
@@ -7115,7 +7627,7 @@
 }
 
 /**
- * Implode an array of tags into a string.
+ * Implodes an array of tags into a string.
  *
  * @see drupal_explode_tags()
  */
@@ -7133,7 +7645,7 @@
 }
 
 /**
- * Flush all cached data on the site.
+ * Flushes all cached data on the site.
  *
  * Empties cache tables, rebuilds the menu cache and theme registries, and
  * invokes a hook so that other modules' cache data can be cleared as well.
@@ -7151,6 +7663,7 @@
   system_rebuild_theme_data();
   drupal_theme_rebuild();
 
+  entity_info_cache_clear();
   node_types_rebuild();
   // node_menu() defines menu items based on node types so it needs to come
   // after node types are rebuilt.
@@ -7174,10 +7687,10 @@
 }
 
 /**
- * Helper function to change query-strings on css/js files.
+ * Changes the dummy query string added to all CSS and JavaScript files.
  *
- * Changes the character added to all css/js files as dummy query-string, so
- * that all browsers are forced to reload fresh files.
+ * Changing the dummy query string appended to CSS and JavaScript files forces
+ * all browsers to reload fresh files.
  */
 function _drupal_flush_css_js() {
   // The timestamp is converted to base 36 in order to make it more compact.
@@ -7185,7 +7698,7 @@
 }
 
 /**
- * Debug function used for outputting debug information.
+ * Outputs debug information.
  *
  * The debug information is passed on to trigger_error() after being converted
  * to a string using _drupal_debug_message().
@@ -7210,10 +7723,16 @@
 }
 
 /**
- * Parse a dependency for comparison by drupal_check_incompatibility().
+ * Parses a dependency for comparison by drupal_check_incompatibility().
  *
  * @param $dependency
- *   A dependency string, for example 'foo (>=7.x-4.5-beta5, 3.x)'.
+ *   A dependency string, which specifies a module dependency, and optionally
+ *   the project it comes from and versions that are supported. Supported
+ *   formats include:
+ *   - 'module'
+ *   - 'project:module'
+ *   - 'project:module (>=version, version)'
+ *
  * @return
  *   An associative array with three keys:
  *   - 'name' includes the name of the thing to depend on (e.g. 'foo').
@@ -7227,6 +7746,12 @@
  * @see drupal_check_incompatibility()
  */
 function drupal_parse_dependency($dependency) {
+  $value = array();
+  // Split out the optional project name.
+  if (strpos($dependency, ':')) {
+    list($project_name, $dependency) = explode(':', $dependency);
+    $value['project'] = $project_name;
+  }
   // We use named subpatterns and support every op that version_compare
   // supports. Also, op is optional and defaults to equals.
   $p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
@@ -7235,7 +7760,6 @@
   $p_major = '(?P<major>\d+)';
   // By setting the minor version to x, branches can be matched.
   $p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
-  $value = array();
   $parts = explode('(', $dependency, 2);
   $value['name'] = trim($parts[0]);
   if (isset($parts[1])) {
@@ -7267,12 +7791,13 @@
 }
 
 /**
- * Check whether a version is compatible with a given dependency.
+ * Checks whether a version is compatible with a given dependency.
  *
  * @param $v
  *   The parsed dependency structure from drupal_parse_dependency().
  * @param $current_version
  *   The version to check against (like 4.2).
+ *
  * @return
  *   NULL if compatible, otherwise the original dependency version string that
  *   caused the incompatibility.
@@ -7292,12 +7817,12 @@
 /**
  * Get the entity info array of an entity type.
  *
- * @see hook_entity_info()
- * @see hook_entity_info_alter()
- *
  * @param $entity_type
  *   The entity type, e.g. node, for which the info shall be returned, or NULL
  *   to return an array with info about all types.
+ *
+ * @see hook_entity_info()
+ * @see hook_entity_info_alter()
  */
 function entity_get_info($entity_type = NULL) {
   global $language;
@@ -7349,6 +7874,7 @@
         // Prepare entity schema fields SQL info for
         // DrupalEntityControllerInterface::buildQuery().
         if (isset($entity_info[$name]['base table'])) {
+          $entity_info[$name]['base table field types'] = drupal_schema_field_types($entity_info[$name]['base table']);
           $entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
           if (isset($entity_info[$name]['revision table'])) {
             $entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
@@ -7385,12 +7911,13 @@
  *   The entity type; e.g. 'node' or 'user'.
  * @param $entity
  *   The entity from which to extract values.
+ *
  * @return
  *   A numerically indexed array (not a hash table) containing these
  *   elements:
- *   0: primary id of the entity
- *   1: revision id of the entity, or NULL if $entity_type is not versioned
- *   2: bundle name of the entity
+ *   - 0: Primary ID of the entity.
+ *   - 1: Revision ID of the entity, or NULL if $entity_type is not versioned.
+ *   - 2: Bundle name of the entity, or NULL if $entity_type has no bundles.
  */
 function entity_extract_ids($entity_type, $entity) {
   $info = entity_get_info($entity_type);
@@ -7423,13 +7950,12 @@
  * @param $entity_type
  *   The entity type; e.g. 'node' or 'user'.
  * @param $ids
- *   A numerically indexed array, as returned by entity_extract_ids(),
- *   containing these elements:
- *   0: primary id of the entity
- *   1: revision id of the entity, or NULL if $entity_type is not versioned
- *   2: bundle name of the entity, or NULL if $entity_type has no bundles
+ *   A numerically indexed array, as returned by entity_extract_ids().
+ *
  * @return
  *   An entity structure, initialized with the ids provided.
+ *
+ * @see entity_extract_ids()
  */
 function entity_create_stub_entity($entity_type, $ids) {
   $entity = new stdClass();
@@ -7459,11 +7985,6 @@
  * DrupalDefaultEntityController class. See node_entity_info() and the
  * NodeController in node.module as an example.
  *
- * @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
@@ -7481,6 +8002,11 @@
  *   found, an empty array is returned.
  *
  * @todo Remove $conditions in Drupal 8.
+ *
+ * @see hook_entity_info()
+ * @see DrupalEntityControllerInterface
+ * @see DrupalDefaultEntityController
+ * @see EntityFieldQuery
  */
 function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
   if ($reset) {
@@ -7500,7 +8026,7 @@
  * @param $entity_type
  *   The entity type to load, e.g. node or user.
  * @param $id
- *   The id of the entity to load.
+ *   The ID of the entity to load.
  *
  * @return
  *   The unchanged entity, or FALSE if the entity cannot be loaded.
@@ -7512,7 +8038,10 @@
 }
 
 /**
- * Get the entity controller class for an entity type.
+ * Gets the entity controller for an entity type.
+ *
+ * @return DrupalEntityControllerInterface
+ *   The entity controller object for the specified entity type.
  */
 function entity_get_controller($entity_type) {
   $controllers = &drupal_static(__FUNCTION__, array());
@@ -7537,7 +8066,6 @@
  * recursion. By convention, entity_prepare_view() is called after
  * field_attach_prepare_view() to allow entity level hooks to act on content
  * loaded by field API.
- * @see hook_entity_prepare_view()
  *
  * @param $entity_type
  *   The type of entity, i.e. 'node', 'user'.
@@ -7546,6 +8074,8 @@
  * @param $langcode
  *   (optional) A language code to be used for rendering. Defaults to the global
  *   content language of the current request.
+ *
+ * @see hook_entity_prepare_view()
  */
 function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
   if (!isset($langcode)) {
@@ -7572,16 +8102,66 @@
 }
 
 /**
- * Returns the uri elements of an entity.
+ * Invoke hook_entity_view_mode_alter().
+ *
+ * If adding a new entity similar to nodes, comments or users, you should invoke
+ * this function during the ENTITY_build_content() or ENTITY_view_multiple()
+ * phases of rendering to allow other modules to alter the view mode during this
+ * phase. This function needs to be called before field_attach_prepare_view() to
+ * ensure that the correct content is loaded by field API.
+ *
+ * @param $entity_type
+ *   The type of entity, i.e. 'node', 'user'.
+ * @param $entities
+ *   The entity objects which are being prepared for view, keyed by object ID.
+ * @param $view_mode
+ *   The original view mode e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (optional) A language code to be used for rendering. Defaults to the global
+ *   content language of the current request.
+ * @return
+ *   An associative array with arrays of entities keyed by view mode.
+ *
+ * @see hook_entity_view_mode_alter()
+ */
+function entity_view_mode_prepare($entity_type, $entities, $view_mode, $langcode = NULL) {
+  if (!isset($langcode)) {
+    $langcode = $GLOBALS['language_content']->language;
+  }
+
+  // To ensure hooks are never run after field_attach_prepare_view() only
+  // process items without the entity_view_prepared flag.
+  $entities_by_view_mode = array();
+  foreach ($entities as $id => $entity) {
+    $entity_view_mode = $view_mode;
+    if (empty($entity->entity_view_prepared)) {
+
+      // Allow modules to change the view mode.
+      $context = array(
+        'entity_type' => $entity_type,
+        'entity' => $entity,
+        'langcode' => $langcode,
+      );
+      drupal_alter('entity_view_mode', $entity_view_mode, $context);
+    }
+
+    $entities_by_view_mode[$entity_view_mode][$id] = $entity;
+  }
+
+  return $entities_by_view_mode;
+}
+
+/**
+ * Returns the URI elements of an entity.
  *
  * @param $entity_type
  *   The entity type; e.g. 'node' or 'user'.
  * @param $entity
  *   The entity for which to generate a path.
  * @return
- *   An array containing the 'path' and 'options' keys used to build the uri of
+ *   An array containing the 'path' and 'options' keys used to build the URI of
  *   the entity, and matching the signature of url(). NULL if the entity has no
- *   uri of its own.
+ *   URI of its own.
  */
 function entity_uri($entity_type, $entity) {
   $info = entity_get_info($entity_type);
@@ -7638,7 +8218,45 @@
 }
 
 /**
- * Helper function for attaching field API validation to entity forms.
+ * Returns the language of an entity.
+ *
+ * @param $entity_type
+ *   The entity type; e.g., 'node' or 'user'.
+ * @param $entity
+ *   The entity for which to get the language.
+ *
+ * @return
+ *   A valid language code or NULL if the entity has no language support.
+ */
+function entity_language($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+
+  // Invoke the callback to get the language. If there is no callback, try to
+  // get it from a property of the entity, otherwise NULL.
+  if (isset($info['language callback']) && function_exists($info['language callback'])) {
+    $langcode = $info['language callback']($entity_type, $entity);
+  }
+  elseif (!empty($info['entity keys']['language']) && isset($entity->{$info['entity keys']['language']})) {
+    $langcode = $entity->{$info['entity keys']['language']};
+  }
+  else {
+    // The value returned in D8 would be LANGUAGE_NONE, we cannot use it here to
+    // preserve backward compatibility. In fact this function has been
+    // introduced very late in the D7 life cycle, mainly as the proper default
+    // for field_attach_form(). By returning LANGUAGE_NONE when no language
+    // information is available, we would introduce a potentially BC-breaking
+    // API change, since field_attach_form() defaults to the default language
+    // instead of LANGUAGE_NONE. Moreover this allows us to distinguish between
+    // entities that have no language specified from ones that do not have
+    // language support at all.
+    $langcode = NULL;
+  }
+
+  return $langcode;
+}
+
+/**
+ * Attaches field API validation to entity forms.
  */
 function entity_form_field_validate($entity_type, $form, &$form_state) {
   // All field attach API functions act on an entity object, but during form
@@ -7651,7 +8269,7 @@
 }
 
 /**
- * Helper function for copying submitted values to entity properties for simple entity forms.
+ * Copies submitted values to entity properties for simple entity forms.
  *
  * 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
@@ -7777,11 +8395,12 @@
 }
 
 /**
- * Create the appropriate archiver for the specified file.
+ * Creates the appropriate archiver for the specified file.
  *
  * @param $file
- *   The full path of the archive file.  Note that stream wrapper
- *   paths are supported, but not remote ones.
+ *   The full path of the archive file. Note that stream wrapper paths are
+ *   supported, but not remote ones.
+ *
  * @return
  *   A newly created instance of the archiver class appropriate
  *   for the specified file, already bound to that file.
@@ -7810,14 +8429,14 @@
 }
 
 /**
- * Drupal Updater registry.
+ * Assembles the Drupal Updater registry.
  *
  * An Updater is a class that knows how to update various parts of the Drupal
  * file system, for example to update modules that have newer releases, or to
  * install a new theme.
  *
  * @return
- *   Returns the Drupal Updater class registry.
+ *   The Drupal Updater class registry.
  *
  * @see hook_updater_info()
  * @see hook_updater_info_alter()
@@ -7833,10 +8452,10 @@
 }
 
 /**
- * Drupal FileTransfer registry.
+ * Assembles the Drupal FileTransfer registry.
  *
  * @return
- *   Returns the Drupal FileTransfer class registry.
+ *   The Drupal FileTransfer class registry.
  *
  * @see FileTransfer
  * @see hook_filetransfer_info()
diff -Naur drupal-7.9/includes/database/database.inc drupal-7.58/includes/database/database.inc
--- drupal-7.9/includes/database/database.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/database.inc	2018-03-27 21:28:19.000000000 +0200
@@ -28,20 +28,23 @@
  * Most Drupal database SELECT queries are performed by a call to db_query() or
  * db_query_range(). Module authors should also consider using the PagerDefault
  * Extender for queries that return results that need to be presented on
- * multiple pages, and the Tablesort Extender for generating appropriate queries
- * for sortable tables.
+ * multiple pages (see https://drupal.org/node/508796), and the TableSort
+ * Extender for generating appropriate queries for sortable tables
+ * (see https://drupal.org/node/1848372).
  *
  * For example, one might wish to return a list of the most recent 10 nodes
  * authored by a given user. Instead of directly issuing the SQL query
  * @code
- * SELECT n.nid, n.title, n.created FROM node n WHERE n.uid = $uid LIMIT 0, 10;
+ * SELECT n.nid, n.title, n.created FROM node n WHERE n.uid = $uid
+ *   ORDER BY n.created DESC LIMIT 0, 10;
  * @endcode
  * one would instead call the Drupal functions:
  * @code
  * $result = db_query_range('SELECT n.nid, n.title, n.created
- *   FROM {node} n WHERE n.uid = :uid', 0, 10, array(':uid' => $uid));
+ *   FROM {node} n WHERE n.uid = :uid
+ *   ORDER BY n.created DESC', 0, 10, array(':uid' => $uid));
  * foreach ($result as $record) {
- *   // Perform operations on $node->title, etc. here.
+ *   // Perform operations on $record->title, etc. here.
  * }
  * @endcode
  * Curly braces are used around "node" to provide table prefixing via
@@ -167,7 +170,7 @@
  * }
  * @endcode
  *
- * @link http://drupal.org/developing/api/database
+ * @see http://drupal.org/developing/api/database
  */
 
 
@@ -179,7 +182,7 @@
  * concrete implementation of it to support special handling required by that
  * database.
  *
- * @see http://php.net/manual/en/book.pdo.php
+ * @see http://php.net/manual/book.pdo.php
  */
 abstract class DatabaseConnection extends PDO {
 
@@ -194,7 +197,7 @@
 
   /**
    * 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).
@@ -293,6 +296,20 @@
    */
   protected $prefixReplace = array();
 
+  /**
+   * List of escaped database, table, and field names, keyed by unescaped names.
+   *
+   * @var array
+   */
+  protected $escapedNames = array();
+
+  /**
+   * List of escaped aliases names, keyed by unescaped aliases.
+   *
+   * @var array
+   */
+  protected $escapedAliases = array();
+
   function __construct($dsn, $username, $password, $driver_options = array()) {
     // Initialize and prepare the connection prefix.
     $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
@@ -303,13 +320,29 @@
     // Call PDO::__construct and PDO::setAttribute.
     parent::__construct($dsn, $username, $password, $driver_options);
 
-    // Set a specific PDOStatement class if the driver requires that.
+    // Set a Statement class, unless the driver opted out.
     if (!empty($this->statementClass)) {
       $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
     }
   }
 
   /**
+   * Destroys this Connection object.
+   *
+   * PHP does not destruct an object if it is still referenced in other
+   * variables. In case of PDO database connection objects, PHP only closes the
+   * connection when the PDO object is destructed, so any references to this
+   * object may cause the number of maximum allowed connections to be exceeded.
+   */
+  public function destroy() {
+    // Destroy all references to this connection by setting them to NULL.
+    // The Statement class attribute only accepts a new value that presents a
+    // proper callable, so we reset it to PDOStatement.
+    $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
+    $this->schema = NULL;
+  }
+
+  /**
    * Returns the default query options for any given query.
    *
    * A given query can be customized with a number of option flags in an
@@ -607,7 +640,7 @@
    *   A sanitized version of the query comment string.
    */
   protected function filterComment($comment = '') {
-    return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
+    return strtr($comment, array('*' => ' * '));
   }
 
   /**
@@ -637,7 +670,7 @@
    * @return DatabaseStatementInterface
    *   This method will return one of: the executed statement, the number of
    *   rows affected by the query (not the number matched), or the generated
-   *   insert IT of the last query, depending on the value of
+   *   insert ID of the last query, depending on the value of
    *   $options['return']. Typically that value will be set by default or a
    *   query builder and should not be set by a user. If there is an error,
    *   this method will return NULL and may throw an exception if
@@ -717,7 +750,7 @@
     // to expand it out into a comma-delimited set of placeholders.
     foreach (array_filter($args, 'is_array') as $key => $data) {
       $new_keys = array();
-      foreach ($data as $i => $value) {
+      foreach (array_values($data) as $i => $value) {
         // This assumes that there are no other placeholders that use the same
         // name.  For example, if the array placeholder is defined as :example
         // and there is already an :example_2 placeholder, this will generate
@@ -900,11 +933,14 @@
    * For some database drivers, it may also wrap the table name in
    * database-specific escape characters.
    *
-   * @return
+   * @return string
    *   The sanitized table name string.
    */
   public function escapeTable($table) {
-    return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
+    if (!isset($this->escapedNames[$table])) {
+      $this->escapedNames[$table] = preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
+    }
+    return $this->escapedNames[$table];
   }
 
   /**
@@ -914,11 +950,14 @@
    * For some database drivers, it may also wrap the field name in
    * database-specific escape characters.
    *
-   * @return
+   * @return string
    *   The sanitized field name string.
    */
   public function escapeField($field) {
-    return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+    if (!isset($this->escapedNames[$field])) {
+      $this->escapedNames[$field] = preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+    }
+    return $this->escapedNames[$field];
   }
 
   /**
@@ -929,11 +968,14 @@
    * DatabaseConnection::escapeTable(), this doesn't allow the period (".")
    * because that is not allowed in aliases.
    *
-   * @return
+   * @return string
    *   The sanitized field name string.
    */
   public function escapeAlias($field) {
-    return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
+    if (!isset($this->escapedAliases[$field])) {
+      $this->escapedAliases[$field] = preg_replace('/[^A-Za-z0-9_]+/', '', $field);
+    }
+    return $this->escapedAliases[$field];
   }
 
   /**
@@ -988,6 +1030,9 @@
    * @param $name
    *   Optional name of the savepoint.
    *
+   * @return DatabaseTransaction
+   *   A DatabaseTransaction object.
+   *
    * @see DatabaseTransaction
    */
   public function startTransaction($name = '') {
@@ -1016,9 +1061,9 @@
       throw new DatabaseTransactionNoActiveException();
     }
     // A previous rollback to an earlier savepoint may mean that the savepoint
-    // in question has already been rolled back.
-    if (!in_array($savepoint_name, $this->transactionLayers)) {
-      return;
+    // in question has already been accidentally committed.
+    if (!isset($this->transactionLayers[$savepoint_name])) {
+      throw new DatabaseTransactionNoActiveException();
     }
 
     // We need to find the point we're rolling back to, all other savepoints
@@ -1096,8 +1141,12 @@
     if (!$this->supportsTransactions()) {
       return;
     }
+    // The transaction has already been committed earlier. There is nothing we
+    // need to do. If this transaction was part of an earlier out-of-order
+    // rollback, an exception would already have been thrown by
+    // Database::rollback().
     if (!isset($this->transactionLayers[$name])) {
-      throw new DatabaseTransactionNoActiveException();
+      return;
     }
 
     // Mark this layer as committable.
@@ -1287,6 +1336,39 @@
    *   also larger than the $existing_id if one was passed in.
    */
   abstract public function nextId($existing_id = 0);
+
+  /**
+   * Checks whether utf8mb4 support is configurable in settings.php.
+   *
+   * @return bool
+   */
+  public function utf8mb4IsConfigurable() {
+    // Since 4 byte UTF-8 is not supported by default, there is nothing to
+    // configure.
+    return FALSE;
+  }
+
+  /**
+   * Checks whether utf8mb4 support is currently active.
+   *
+   * @return bool
+   */
+  public function utf8mb4IsActive() {
+    // Since 4 byte UTF-8 is not supported by default, there is nothing to
+    // activate.
+    return FALSE;
+  }
+
+  /**
+   * Checks whether utf8mb4 support is available on the current database system.
+   *
+   * @return bool
+   */
+  public function utf8mb4IsSupported() {
+    // By default we assume that the database backend may not support 4 byte
+    // UTF-8.
+    return FALSE;
+  }
 }
 
 /**
@@ -1426,9 +1508,6 @@
   /**
    * Gets the connection object for the specified database key and target.
    *
-   * Note: do not use the setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE) on the
-   * returned object because of http://bugs.php.net/bug.php?id=43139.
-   *
    * @param $target
    *   The database target name.
    * @param $key
@@ -1623,8 +1702,8 @@
    */
   final public static function removeConnection($key) {
     if (isset(self::$databaseInfo[$key])) {
+      self::closeConnection(NULL, $key);
       unset(self::$databaseInfo[$key]);
-      unset(self::$connections[$key]);
       return TRUE;
     }
     else {
@@ -1690,11 +1769,24 @@
     if (!isset($key)) {
       $key = self::$activeKey;
     }
-    // To close the connection, we need to unset the static variable.
+    // To close a connection, it needs to be set to NULL and removed from the
+    // static variable. In all cases, closeConnection() might be called for a
+    // connection that was not opened yet, in which case the key is not defined
+    // yet and we just ensure that the connection key is undefined.
     if (isset($target)) {
+      if (isset(self::$connections[$key][$target])) {
+        self::$connections[$key][$target]->destroy();
+        self::$connections[$key][$target] = NULL;
+      }
       unset(self::$connections[$key][$target]);
     }
     else {
+      if (isset(self::$connections[$key])) {
+        foreach (self::$connections[$key] as $target => $connection) {
+          self::$connections[$key][$target]->destroy();
+          self::$connections[$key][$target] = NULL;
+        }
+      }
       unset(self::$connections[$key]);
     }
   }
@@ -1848,8 +1940,8 @@
    */
   protected $name;
 
-  public function __construct(DatabaseConnection &$connection, $name = NULL) {
-    $this->connection = &$connection;
+  public function __construct(DatabaseConnection $connection, $name = NULL) {
+    $this->connection = $connection;
     // If there is no transaction depth, then no transaction has started. Name
     // the transaction 'drupal_transaction'.
     if (!$depth = $connection->transactionDepth()) {
@@ -1953,7 +2045,7 @@
   /**
    * Sets the default fetch mode for this statement.
    *
-   * See http://php.net/manual/en/pdo.constants.php for the definition of the
+   * See http://php.net/manual/pdo.constants.php for the definition of the
    * constants used.
    *
    * @param $mode
@@ -1972,7 +2064,7 @@
   /**
    * Fetches the next row from a result set.
    *
-   * See http://php.net/manual/en/pdo.constants.php for the definition of the
+   * See http://php.net/manual/pdo.constants.php for the definition of the
    * constants used.
    *
    * @param $mode
@@ -2347,14 +2439,14 @@
 }
 
 /**
- * Executes a query string and saves the result set to a temporary table.
+ * Executes a SELECT query string and saves the result set to a temporary table.
  *
  * The execution of the query string happens against the active database.
  *
  * @param $query
- *   The prepared statement query to run. Although it will accept both named and
- *   unnamed placeholders, named placeholders are strongly preferred as they are
- *   more self-documenting.
+ *   The prepared SELECT statement query to run. Although it will accept both
+ *   named and unnamed placeholders, named placeholders are strongly preferred
+ *   as they are more self-documenting.
  * @param $args
  *   An array of values to substitute into the query. If the query uses named
  *   placeholders, this is an associative array in any order. If the query uses
@@ -2668,7 +2760,7 @@
 
 
 /**
- * @ingroup schemaapi
+ * @addtogroup schemaapi
  * @{
  */
 
@@ -2765,7 +2857,7 @@
  * Renames a table.
  *
  * @param $table
- *   The table to be renamed.
+ *   The current name of the table to be renamed.
  * @param $new_name
  *   The new name for the table.
  */
@@ -2796,7 +2888,7 @@
  *   will be set to the value of the key in all rows. This is most useful for
  *   creating NOT NULL columns with no default value in existing tables.
  * @param $keys_new
- *   Optional keys and indexes specification to be created on the table along
+ *   (optional) Keys and indexes specification to be created on the table along
  *   with adding the field. The format is the same as a table specification, but
  *   without the 'fields' element. If you are adding a type 'serial' field, you
  *   MUST specify at least one key or index including it in this array. See
@@ -2976,7 +3068,7 @@
  * @param $spec
  *   The field specification for the new field.
  * @param $keys_new
- *   Optional keys and indexes specification to be created on the table along
+ *   (optional) Keys and indexes specification to be created on the table along
  *   with changing the field. The format is the same as a table specification
  *   but without the 'fields' element.
  */
@@ -2985,7 +3077,7 @@
 }
 
 /**
- * @} End of "ingroup schemaapi".
+ * @} End of "addtogroup schemaapi".
  */
 
 /**
diff -Naur drupal-7.9/includes/database/log.inc drupal-7.58/includes/database/log.inc
--- drupal-7.9/includes/database/log.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/log.inc	2018-03-27 21:28:19.000000000 +0200
@@ -128,9 +128,10 @@
    * Determine the routine that called this query.
    *
    * We define "the routine that called this query" as the first entry in
-   * the call stack that is not inside includes/database. That makes the
-   * climbing logic very simple, and handles the variable stack depth caused
-   * by the query builders.
+   * the call stack that is not inside includes/database and does have a file
+   * (which excludes call_user_func_array(), anonymous functions and similar).
+   * That makes the climbing logic very simple, and handles the variable stack
+   * depth caused by the query builders.
    *
    * @link http://www.php.net/debug_backtrace
    * @return
@@ -144,7 +145,8 @@
     $stack = debug_backtrace();
     $stack_count = count($stack);
     for ($i = 0; $i < $stack_count; ++$i) {
-      if (strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
+      if (!empty($stack[$i]['file']) && strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
+        $stack[$i] += array('args' => array());
         return array(
           'file' => $stack[$i]['file'],
           'line' => $stack[$i]['line'],
diff -Naur drupal-7.9/includes/database/mysql/database.inc drupal-7.58/includes/database/mysql/database.inc
--- drupal-7.9/includes/database/mysql/database.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/mysql/database.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,18 +6,18 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
 class DatabaseConnection_mysql extends DatabaseConnection {
 
   /**
-   * Flag to indicate if we have registered the nextID cleanup function.
+   * Flag to indicate if the cleanup function in __destruct() should run.
    *
    * @var boolean
    */
-  protected $shutdownRegistered = FALSE;
+  protected $needsCleanup = FALSE;
 
   public function __construct(array $connection_options = array()) {
     // This driver defaults to transaction support, except if explicitly passed FALSE.
@@ -28,6 +28,12 @@
 
     $this->connectionOptions = $connection_options;
 
+    $charset = 'utf8';
+    // Check if the charset is overridden to utf8mb4 in settings.php.
+    if ($this->utf8mb4IsActive()) {
+      $charset = 'utf8mb4';
+    }
+
     // The DSN should use either a socket or a host/port.
     if (isset($connection_options['unix_socket'])) {
       $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
@@ -36,34 +42,63 @@
       // Default to TCP connection on port 3306.
       $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
     }
+    // Character set is added to dsn to ensure PDO uses the proper character
+    // set when escaping. This has security implications. See
+    // https://www.drupal.org/node/1201452 for further discussion.
+    $dsn .= ';charset=' . $charset;
     $dsn .= ';dbname=' . $connection_options['database'];
-    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
+    // Allow PDO options to be overridden.
+    $connection_options += array(
+      'pdo' => array(),
+    );
+    $connection_options['pdo'] += array(
       // So we don't have to mess around with cursors and unbuffered queries by default.
       PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
       // Because MySQL's prepared statements skip the query cache, because it's dumb.
       PDO::ATTR_EMULATE_PREPARES => TRUE,
-      // Force column names to lower case.
-      PDO::ATTR_CASE => PDO::CASE_LOWER,
-    ));
+    );
+    if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
+      // An added connection option in PHP 5.5.21+ to optionally limit SQL to a
+      // single statement like mysqli.
+      $connection_options['pdo'] += array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE);
+    }
+
+    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
 
     // Force MySQL to use the UTF-8 character set. Also set the collation, if a
     // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
     // for UTF-8.
     if (!empty($connection_options['collation'])) {
-      $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
+      $this->exec('SET NAMES ' . $charset . ' COLLATE ' . $connection_options['collation']);
     }
     else {
-      $this->exec('SET NAMES utf8');
+      $this->exec('SET NAMES ' . $charset);
+    }
+
+    // Set MySQL init_commands if not already defined.  Default Drupal's MySQL
+    // behavior to conform more closely to SQL standards.  This allows Drupal
+    // to run almost seamlessly on many different kinds of database systems.
+    // These settings force MySQL to behave the same as postgresql, or sqlite
+    // in regards to syntax interpretation and invalid data handling.  See
+    // http://drupal.org/node/344575 for further discussion. Also, as MySQL 5.5
+    // changed the meaning of TRADITIONAL we need to spell out the modes one by
+    // one.
+    $connection_options += array(
+      'init_commands' => array(),
+    );
+    $connection_options['init_commands'] += array(
+      'sql_mode' => "SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
+    );
+    // Execute initial commands.
+    foreach ($connection_options['init_commands'] as $sql) {
+      $this->exec($sql);
     }
+  }
 
-    // Force MySQL's behavior to conform more closely to SQL standards.
-    // This allows Drupal to run almost seamlessly on many different
-    // kinds of database systems. These settings force MySQL to behave
-    // the same as postgresql, or sqlite in regards to syntax interpretation
-    // and invalid data handling. See http://drupal.org/node/344575 for
-    // further discussion. Also, as MySQL 5.5 changed the meaning of
-    // TRADITIONAL we need to spell out the modes one by one.
-    $this->exec("SET sql_mode='ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'");
+  public function __destruct() {
+    if ($this->needsCleanup) {
+      $this->nextIdDelete();
+    }
   }
 
   public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
@@ -72,7 +107,7 @@
 
   public function queryTemporary($query, array $args = array(), array $options = array()) {
     $tablename = $this->generateTemporaryTableName();
-    $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY SELECT', $query), $args, $options);
+    $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY ' . $query, $args, $options);
     return $tablename;
   }
 
@@ -103,12 +138,7 @@
       $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
       $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
     }
-    if (!$this->shutdownRegistered) {
-      // Use register_shutdown_function() here to keep the database system
-      // independent of Drupal.
-      register_shutdown_function(array($this, 'nextIdDelete'));
-      $shutdownRegistered = TRUE;
-    }
+    $this->needsCleanup = TRUE;
     return $new_id;
   }
 
@@ -169,8 +199,11 @@
           // succeed for MySQL error code 1305 ("SAVEPOINT does not exist").
           if ($e->errorInfo[1] == '1305') {
             // If one SAVEPOINT was released automatically, then all were.
-            // Therefore, we keep just the topmost transaction.
-            $this->transactionLayers = array('drupal_transaction' => 'drupal_transaction');
+            // Therefore, clean the transaction stack.
+            $this->transactionLayers = array();
+            // We also have to explain to PDO that the transaction stack has
+            // been cleaned-up.
+            PDO::commit();
           }
           else {
             throw $e;
@@ -179,9 +212,45 @@
       }
     }
   }
+
+  public function utf8mb4IsConfigurable() {
+    return TRUE;
+  }
+
+  public function utf8mb4IsActive() {
+    return isset($this->connectionOptions['charset']) && $this->connectionOptions['charset'] === 'utf8mb4';
+  }
+
+  public function utf8mb4IsSupported() {
+    // Ensure that the MySQL driver supports utf8mb4 encoding.
+    $version = $this->getAttribute(PDO::ATTR_CLIENT_VERSION);
+    if (strpos($version, 'mysqlnd') !== FALSE) {
+      // The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
+      $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
+      if (version_compare($version, '5.0.9', '<')) {
+        return FALSE;
+      }
+    }
+    else {
+      // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
+      if (version_compare($version, '5.5.3', '<')) {
+        return FALSE;
+      }
+    }
+
+    // Ensure that the MySQL server supports large prefixes and utf8mb4.
+    try {
+      $this->query("CREATE TABLE {drupal_utf8mb4_test} (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB");
+    }
+    catch (Exception $e) {
+      return FALSE;
+    }
+    $this->query("DROP TABLE {drupal_utf8mb4_test}");
+    return TRUE;
+  }
 }
 
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/mysql/query.inc drupal-7.58/includes/database/mysql/query.inc
--- drupal-7.9/includes/database/mysql/query.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/mysql/query.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -51,7 +51,8 @@
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      $insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
+      return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
     }
 
     $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
@@ -86,22 +87,8 @@
   }
 }
 
-class TruncateQuery_mysql extends TruncateQuery {
-  public function __toString() {
-    // TRUNCATE is actually a DDL statement on MySQL, and DDL statements are
-    // not transactional, and result in an implicit COMMIT. When we are in a
-    // transaction, fallback to the slower, but transactional, DELETE.
-    if ($this->connection->inTransaction()) {
-      // Create a comment string to prepend to the query.
-      $comments = $this->connection->makeComment($this->comments);
-      return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
-    }
-    else {
-      return parent::__toString();
-    }
-  }
-}
+class TruncateQuery_mysql extends TruncateQuery { }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/mysql/schema.inc drupal-7.58/includes/database/mysql/schema.inc
--- drupal-7.9/includes/database/mysql/schema.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/mysql/schema.inc	2018-03-27 21:28:19.000000000 +0200
@@ -7,7 +7,7 @@
 
 
 /**
- * @ingroup schemaapi
+ * @addtogroup schemaapi
  * @{
  */
 
@@ -39,8 +39,8 @@
       $info['table'] = substr($table, ++$pos);
     }
     else {
-      $db_info = Database::getConnectionInfo();
-      $info['database'] = $db_info['default']['database'];
+      $db_info = $this->connection->getConnectionOptions();
+      $info['database'] = $db_info['database'];
       $info['table'] = $table;
     }
     return $info;
@@ -81,7 +81,8 @@
     // Provide defaults if needed.
     $table += array(
       'mysql_engine' => 'InnoDB',
-      'mysql_character_set' => 'utf8',
+      // Allow the default charset to be overridden in settings.php.
+      'mysql_character_set' => $this->connection->utf8mb4IsActive() ? 'utf8mb4' : 'utf8',
     );
 
     $sql = "CREATE TABLE {" . $name . "} (\n";
@@ -109,6 +110,13 @@
       $sql .= ' COLLATE ' . $info['collation'];
     }
 
+    // The row format needs to be either DYNAMIC or COMPRESSED in order to allow
+    // for the innodb_large_prefix setting to take effect, see
+    // https://dev.mysql.com/doc/refman/5.6/en/create-table.html
+    if ($this->connection->utf8mb4IsActive()) {
+      $sql .= ' ROW_FORMAT=DYNAMIC';
+    }
+
     // Add table comment.
     if (!empty($table['description'])) {
       $sql .= ' COMMENT ' . $this->prepareComment($table['description'], self::COMMENT_MAX_TABLE);
@@ -131,8 +139,13 @@
   protected function createFieldSql($name, $spec) {
     $sql = "`" . $name . "` " . $spec['mysql_type'];
 
-    if (in_array($spec['mysql_type'], array('VARCHAR', 'CHAR', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'TEXT')) && isset($spec['length'])) {
-      $sql .= '(' . $spec['length'] . ')';
+    if (in_array($spec['mysql_type'], array('VARCHAR', 'CHAR', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'TEXT'))) {
+      if (isset($spec['length'])) {
+        $sql .= '(' . $spec['length'] . ')';
+      }
+      if (!empty($spec['binary'])) {
+        $sql .= ' BINARY';
+      }
     }
     elseif (isset($spec['precision']) && isset($spec['scale'])) {
       $sql .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
@@ -296,10 +309,10 @@
 
   public function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
     }
 
     $info = $this->getPrefixInfo($new_name);
@@ -317,10 +330,10 @@
 
   public function addField($table, $field, $spec, $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)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
     }
 
     $fixnull = FALSE;
@@ -356,7 +369,7 @@
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     if (!isset($default)) {
@@ -371,7 +384,7 @@
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
@@ -381,15 +394,15 @@
     // Returns one row for each column in the index. Result is string or FALSE.
     // Details at http://dev.mysql.com/doc/refman/5.0/en/show-index.html
     $row = $this->connection->query('SHOW INDEX FROM {' . $table . "} WHERE key_name = '$name'")->fetchAssoc();
-    return isset($row['key_name']);
+    return isset($row['Key_name']);
   }
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
     }
     if ($this->indexExists($table, 'PRIMARY')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
@@ -406,10 +419,10 @@
 
   public function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
@@ -426,10 +439,10 @@
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
@@ -446,10 +459,10 @@
 
   public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      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)));
+      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)));
     }
 
     $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec));
@@ -527,5 +540,5 @@
 }
 
 /**
- * @} End of "ingroup schemaapi".
+ * @} End of "addtogroup schemaapi".
  */
diff -Naur drupal-7.9/includes/database/pgsql/database.inc drupal-7.58/includes/database/pgsql/database.inc
--- drupal-7.9/includes/database/pgsql/database.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/pgsql/database.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,12 +6,12 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
 /**
- * The name by which to obtain a lock for retrive the next insert id.
+ * The name by which to obtain a lock for retrieving the next insert id.
  */
 define('POSTGRESQL_NEXTID_LOCK', 1000);
 
@@ -47,22 +47,42 @@
     $this->connectionOptions = $connection_options;
 
     $dsn = 'pgsql:host=' . $connection_options['host'] . ' dbname=' . $connection_options['database'] . ' port=' . $connection_options['port'];
-    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
+
+    // Allow PDO options to be overridden.
+    $connection_options += array(
+      'pdo' => array(),
+    );
+    $connection_options['pdo'] += array(
       // Prepared statements are most effective for performance when queries
       // are recycled (used several times). However, if they are not re-used,
-      // prepared statements become ineffecient. Since most of Drupal's
+      // prepared statements become inefficient. Since most of Drupal's
       // prepared queries are not re-used, it should be faster to emulate
       // the preparation than to actually ready statements for re-use. If in
       // doubt, reset to FALSE and measure performance.
       PDO::ATTR_EMULATE_PREPARES => TRUE,
       // Convert numeric values to strings when fetching.
       PDO::ATTR_STRINGIFY_FETCHES => TRUE,
-      // Force column names to lower case.
-      PDO::ATTR_CASE => PDO::CASE_LOWER,
-    ));
+    );
+    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
 
     // Force PostgreSQL to use the UTF-8 character set by default.
     $this->exec("SET NAMES 'UTF8'");
+
+    // Execute PostgreSQL init_commands.
+    if (isset($connection_options['init_commands'])) {
+      $this->exec(implode('; ', $connection_options['init_commands']));
+    }
+  }
+
+  public function prepareQuery($query) {
+    // mapConditionOperator converts LIKE operations to ILIKE for consistency
+    // with MySQL. However, Postgres does not support ILIKE on bytea (blobs)
+    // fields.
+    // To make the ILIKE operator work, we type-cast bytea fields into text.
+    // @todo This workaround only affects bytea fields, but the involved field
+    //   types involved in the query are unknown, so there is no way to
+    //   conditionally execute this for affected queries only.
+    return parent::prepareQuery(preg_replace('/ ([^ ]+) +(I*LIKE|NOT +I*LIKE) /i', ' ${1}::text ${2} ', $query));
   }
 
   public function query($query, array $args = array(), $options = array()) {
@@ -126,7 +146,7 @@
 
   public function queryTemporary($query, array $args = array(), array $options = array()) {
     $tablename = $this->generateTemporaryTableName();
-    $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} AS SELECT', $query), $args, $options);
+    $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} AS ' . $query, $args, $options);
     return $tablename;
   }
 
@@ -155,14 +175,14 @@
   }
 
   /**
-   * Retrive a the next id in a sequence.
+   * Retrieve the next id in a sequence.
    *
    * PostgreSQL has built in sequences. We'll use these instead of inserting
    * and updating a sequences table.
    */
   public function nextId($existing = 0) {
 
-    // Retrive the name of the sequence. This information cannot be cached
+    // Retrieve the name of the sequence. This information cannot be cached
     // because the prefix may change, for example, like it does in simpletests.
     $sequence_name = $this->makeSequenceName('sequences', 'value');
 
@@ -174,7 +194,7 @@
     }
 
     // PostgreSQL advisory locks are simply locks to be used by an
-    // application such as Drupal. This will prevent other Drupal proccesses
+    // application such as Drupal. This will prevent other Drupal processes
     // from altering the sequence while we are.
     $this->query("SELECT pg_advisory_lock(" . POSTGRESQL_NEXTID_LOCK . ")");
 
@@ -189,15 +209,23 @@
     // Reset the sequence to a higher value than the existing id.
     $this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1));
 
-    // Retrive the next id. We know this will be as high as we want it.
+    // Retrieve the next id. We know this will be as high as we want it.
     $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
 
     $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")");
 
     return $id;
   }
+
+  public function utf8mb4IsActive() {
+    return TRUE;
+  }
+
+  public function utf8mb4IsSupported() {
+    return TRUE;
+  }
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/pgsql/install.inc drupal-7.58/includes/database/pgsql/install.inc
--- drupal-7.9/includes/database/pgsql/install.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/pgsql/install.inc	2018-03-27 21:28:19.000000000 +0200
@@ -165,7 +165,7 @@
         LANGUAGE \'sql\''
       );
 
-      // Using || to concatenate in Drupal is not recommeneded because there are
+      // Using || to concatenate in Drupal is not recommended because there are
       // database drivers for Drupal that do not support the syntax, however
       // they do support CONCAT(item1, item2) which we can replicate in
       // PostgreSQL. PostgreSQL requires the function to be defined for each
diff -Naur drupal-7.9/includes/database/pgsql/query.inc drupal-7.58/includes/database/pgsql/query.inc
--- drupal-7.9/includes/database/pgsql/query.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/pgsql/query.inc	2018-03-27 21:28:19.000000000 +0200
@@ -112,7 +112,8 @@
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      $insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
+      return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
     }
 
     $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
diff -Naur drupal-7.9/includes/database/pgsql/schema.inc drupal-7.58/includes/database/pgsql/schema.inc
--- drupal-7.9/includes/database/pgsql/schema.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/pgsql/schema.inc	2018-03-27 21:28:19.000000000 +0200
@@ -314,10 +314,10 @@
 
   function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
     }
 
     // Get the schema and tablename for the old table.
@@ -328,9 +328,9 @@
     // rename them when renaming the table.
     $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', array(':schema' => $old_schema, ':table' => $old_table_name));
     foreach ($indexes as $index) {
-      if (preg_match('/^' . preg_quote($old_full_name) . '_(.*)_idx$/', $index->indexname, $matches)) {
+      if (preg_match('/^' . preg_quote($old_full_name) . '_(.*)$/', $index->indexname, $matches)) {
         $index_name = $matches[1];
-        $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO {' . $new_name . '}_' . $index_name . '_idx');
+        $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO {' . $new_name . '}_' . $index_name);
       }
     }
 
@@ -351,10 +351,10 @@
 
   public function addField($table, $field, $spec, $new_keys = array()) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
     }
 
     $fixnull = FALSE;
@@ -393,7 +393,7 @@
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     if (!isset($default)) {
@@ -408,7 +408,7 @@
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
@@ -435,10 +435,10 @@
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
     }
     if ($this->constraintExists($table, 'pkey')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')');
@@ -455,10 +455,10 @@
 
   function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->constraintExists($table, $name . '_key')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
@@ -475,10 +475,10 @@
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $this->connection->query($this->_createIndexSql($table, $name, $fields));
@@ -495,10 +495,10 @@
 
   public function changeField($table, $field, $field_new, $spec, $new_keys = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      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)));
+      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)));
     }
 
     $spec = $this->processField($spec);
diff -Naur drupal-7.9/includes/database/pgsql/select.inc drupal-7.58/includes/database/pgsql/select.inc
--- drupal-7.9/includes/database/pgsql/select.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/pgsql/select.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -80,7 +80,7 @@
     }
 
     // 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
+    // result in an ambiguous 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) {
@@ -90,7 +90,7 @@
     }
 
     // If $field contains an characters which are not allowed in a field name
-    // it is considered an expression, these can't be handeld automatically
+    // it is considered an expression, these can't be handled automatically
     // either.
     if ($this->connection->escapeField($field) != $field) {
       return $return;
@@ -103,6 +103,6 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
 
diff -Naur drupal-7.9/includes/database/prefetch.inc drupal-7.58/includes/database/prefetch.inc
--- drupal-7.9/includes/database/prefetch.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/prefetch.inc	2018-03-27 21:28:19.000000000 +0200
@@ -9,7 +9,7 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -502,6 +502,6 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
 
diff -Naur drupal-7.9/includes/database/query.inc drupal-7.58/includes/database/query.inc
--- drupal-7.9/includes/database/query.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/query.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -22,6 +22,9 @@
    * parameters, they are taken as $field and $value with $operator having a
    * value of IN if $value is an array and = otherwise.
    *
+   * Do not use this method to test for NULL values. Instead, use
+   * QueryConditionInterface::isNull() or QueryConditionInterface::isNotNull().
+   *
    * @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().
@@ -36,6 +39,9 @@
    *
    * @return QueryConditionInterface
    *   The called object.
+   *
+   * @see QueryConditionInterface::isNull()
+   * @see QueryConditionInterface::isNotNull()
    */
   public function condition($field, $value = NULL, $operator = NULL);
 
@@ -77,7 +83,7 @@
 
   /**
    * Sets a condition that the specified subquery returns values.
-   * 
+   *
    * @param SelectQueryInterface $select
    *   The subquery that must contain results.
    *
@@ -85,10 +91,10 @@
    *   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.
    *
@@ -96,7 +102,7 @@
    *   The called object.
    */
   public function notExists(SelectQueryInterface $select);
-  
+
   /**
    * Gets a complete list of all conditions in this conditional clause.
    *
@@ -277,14 +283,14 @@
 
   /**
    * The target of the connection object.
-   * 
+   *
    * @var string
    */
   protected $connectionTarget;
 
   /**
    * The key of the connection object.
-   * 
+   *
    * @var string
    */
   protected $connectionKey;
@@ -704,10 +710,11 @@
       // first call to fields() does have an effect.
       $this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions())));
     }
-
-    // Don't execute query without fields.
-    if (count($this->insertFields) + count($this->defaultFields) == 0) {
-      throw new NoFieldsException('There are no fields available to insert with.');
+    else {
+      // Don't execute query without fields.
+      if (count($this->insertFields) + count($this->defaultFields) == 0) {
+        throw new NoFieldsException('There are no fields available to insert with.');
+      }
     }
 
     // If no values have been added, silently ignore this query. This can happen
@@ -798,7 +805,7 @@
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -838,8 +845,8 @@
   /**
    * Executes the DELETE query.
    *
-   * @return
-   *   The return value is dependent on the database connection.
+   * @return int
+   *   The number of rows affected by the delete query.
    */
   public function execute() {
     $values = array();
@@ -936,7 +943,17 @@
     // Create a sanitized comment string to prepend to the query.
     $comments = $this->connection->makeComment($this->comments);
 
-    return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
+    // In most cases, TRUNCATE is not a transaction safe statement as it is a
+    // DDL statement which results in an implicit COMMIT. When we are in a
+    // transaction, fallback to the slower, but transactional, DELETE.
+    // PostgreSQL also locks the entire table for a TRUNCATE strongly reducing
+    // the concurrency with other transactions.
+    if ($this->connection->inTransaction()) {
+      return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
+    }
+    else {
+      return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
+    }
   }
 }
 
@@ -1047,7 +1064,7 @@
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1225,7 +1242,7 @@
  * MergeQuery::updateFields() and MergeQuery::insertFields() needs to be called
  * instead. MergeQuery::fields() can also be called which calls both of these
  * methods as the common case is to use the same column-value pairs for both
- * INSERT and UPDATE. However, this is not mandatory. Another convinient
+ * INSERT and UPDATE. However, this is not mandatory. Another convenient
  * wrapper is MergeQuery::key() which adds the same column-value pairs to the
  * condition and the INSERT query part.
  *
@@ -1539,7 +1556,7 @@
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1589,55 +1606,43 @@
   }
 
   public function execute() {
-    // Wrap multiple queries in a transaction, if the database supports it.
-    $transaction = $this->connection->startTransaction();
-    try {
-      if (!count($this->condition)) {
-        throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
-      }
-      $select = $this->connection->select($this->conditionTable)
-        ->condition($this->condition)
-        ->forUpdate();
-      $select->addExpression('1');
-      if (!$select->execute()->fetchField()) {
-        try {
-          $insert = $this->connection->insert($this->table)->fields($this->insertFields);
-          if ($this->defaultFields) {
-            $insert->useDefaults($this->defaultFields);
-          }
-          $insert->execute();
-          return MergeQuery::STATUS_INSERT;
-        }
-        catch (Exception $e) {
-          // The insert query failed, maybe it's because a racing insert query
-          // beat us in inserting the same row. Retry the select query, if it
-          // returns a row, ignore the error and continue with the update
-          // query below.
-          if (!$select->execute()->fetchField()) {
-            throw $e;
-          }
+    if (!count($this->condition)) {
+      throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
+    }
+    $select = $this->connection->select($this->conditionTable)
+      ->condition($this->condition);
+    $select->addExpression('1');
+    if (!$select->execute()->fetchField()) {
+      try {
+        $insert = $this->connection->insert($this->table)->fields($this->insertFields);
+        if ($this->defaultFields) {
+          $insert->useDefaults($this->defaultFields);
         }
+        $insert->execute();
+        return self::STATUS_INSERT;
       }
-      if ($this->needsUpdate) {
-        $update = $this->connection->update($this->table)
-          ->fields($this->updateFields)
-          ->condition($this->condition);
-        if ($this->expressionFields) {
-          foreach ($this->expressionFields as $field => $data) {
-            $update->expression($field, $data['expression'], $data['arguments']);
-          }
+      catch (Exception $e) {
+        // The insert query failed, maybe it's because a racing insert query
+        // beat us in inserting the same row. Retry the select query, if it
+        // returns a row, ignore the error and continue with the update
+        // query below.
+        if (!$select->execute()->fetchField()) {
+          throw $e;
         }
-        $update->execute();
-        return MergeQuery::STATUS_UPDATE;
       }
     }
-    catch (Exception $e) {
-      // Something really wrong happened here, bubble up the exception to the
-      // caller.
-      $transaction->rollback();
-      throw $e;
-    }
-    // Transaction commits here where $transaction looses scope.
+    if ($this->needsUpdate) {
+      $update = $this->connection->update($this->table)
+        ->fields($this->updateFields)
+        ->condition($this->condition);
+      if ($this->expressionFields) {
+        foreach ($this->expressionFields as $field => $data) {
+          $update->expression($field, $data['expression'], $data['arguments']);
+        }
+      }
+      $update->execute();
+      return self::STATUS_UPDATE;
+     }
   }
 }
 
@@ -1689,7 +1694,7 @@
    * Implements Countable::count().
    *
    * 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
+   * size of its conditional array minus one, because one element is the
    * conjunction.
    */
   public function count() {
@@ -1756,14 +1761,14 @@
   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().
    */
@@ -1892,8 +1897,13 @@
   function __clone() {
     $this->changed = TRUE;
     foreach ($this->conditions as $key => $condition) {
-      if ($condition['field'] instanceOf QueryConditionInterface) {
-        $this->conditions[$key]['field'] = clone($condition['field']);
+      if ($key !== '#conjunction') {
+        if ($condition['field'] instanceOf QueryConditionInterface) {
+          $this->conditions[$key]['field'] = clone($condition['field']);
+        }
+        if ($condition['value'] instanceOf SelectQueryInterface) {
+          $this->conditions[$key]['value'] = clone($condition['value']);
+        }
       }
     }
   }
@@ -1949,5 +1959,5 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/schema.inc drupal-7.58/includes/database/schema.inc
--- drupal-7.9/includes/database/schema.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/schema.inc	2018-03-27 21:28:19.000000000 +0200
@@ -76,8 +76,13 @@
  *       the precision (total number of significant digits) and scale
  *       (decimal digits right of the decimal point). Both values are
  *       mandatory. Ignored for other field types.
+ *     - 'binary': A boolean indicating that MySQL should force 'char',
+ *       'varchar' or 'text' fields to use case-sensitive binary collation.
+ *       This has no effect on other database types for which case sensitivity
+ *       is already the default behavior.
  *     All parameters apart from 'type' are optional except that type
- *     'numeric' columns must specify 'precision' and 'scale'.
+ *     'numeric' columns must specify 'precision' and 'scale', and type
+ *     'varchar' must specify the 'length' parameter.
  *  - 'primary key': An array of one or more key column specifiers (see below)
  *    that form the primary key.
  *  - 'unique keys': An associative array of unique keys ('keyname' =>
@@ -87,7 +92,8 @@
  *    specification). Each specification is an array containing the name of
  *    the referenced table ('table'), and an array of column mappings
  *    ('columns'). Column mappings are defined by key pairs ('source_column' =>
- *    'referenced_column').
+ *    'referenced_column'). This key is for documentation purposes only; foreign
+ *    keys are not created in the database, nor are they enforced by Drupal.
  *  - 'indexes':  An associative array of indexes ('indexname' =>
  *    specification). Each specification is an array of one or more
  *    key column specifiers (see below) that form an index on the
@@ -139,6 +145,8 @@
  *   'unique keys' => array(
  *     'vid' => array('vid'),
  *   ),
+ *   // For documentation purposes only; foreign keys are not created in the
+ *   // database.
  *   'foreign keys' => array(
  *     'node_revision' => array(
  *       'table' => 'node_revision',
@@ -156,6 +164,9 @@
  * @see drupal_install_schema()
  */
 
+/**
+ * Base class for database schema definitions.
+ */
 abstract class DatabaseSchema implements QueryPlaceholderInterface {
 
   protected $connection;
@@ -283,7 +294,7 @@
   protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
     $info = $this->connection->getConnectionOptions();
 
-    // Retrive the table name and schema
+    // Retrieve the table name and schema
     $table_info = $this->getPrefixInfo($table_name, $add_prefix);
 
     $condition = new DatabaseCondition('AND');
@@ -411,7 +422,7 @@
    *   This is most useful for creating NOT NULL columns with no default
    *   value in existing tables.
    * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
+   *   (optional) Keys and indexes specification to be created on the
    *   table along with adding the field. The format is the same as a
    *   table specification but without the 'fields' element. If you are
    *   adding a type 'serial' field, you MUST specify at least one key
@@ -625,7 +636,7 @@
    * @param $spec
    *   The field specification for the new field.
    * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
+   *   (optional) Keys and indexes specification to be created on the
    *   table along with changing the field. The format is the same as a
    *   table specification but without the 'fields' element.
    *
@@ -649,7 +660,7 @@
    */
   public function createTable($name, $table) {
     if ($this->tableExists($name)) {
-      throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t('Table @name already exists.', array('@name' => $name)));
     }
     $statements = $this->createTableSql($name, $table);
     foreach ($statements as $statement) {
diff -Naur drupal-7.9/includes/database/select.inc drupal-7.58/includes/database/select.inc
--- drupal-7.9/includes/database/select.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/select.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -377,7 +377,8 @@
    * @param $field
    *   The field on which to order.
    * @param $direction
-   *   The direction to sort. Legal values are "ASC" and "DESC".
+   *   The direction to sort. Legal values are "ASC" and "DESC". Any other value
+   *   will be converted to "ASC".
    * @return SelectQueryInterface
    *   The called object.
    */
@@ -590,11 +591,13 @@
   }
 
   public function hasAllTags() {
-    return call_user_func_array(array($this->query, 'hasAllTags'), func_get_args());
+    $args = func_get_args();
+    return call_user_func_array(array($this->query, 'hasAllTags'), $args);
   }
 
   public function hasAnyTag() {
-    return call_user_func_array(array($this->query, 'hasAnyTags'), func_get_args());
+    $args = func_get_args();
+    return call_user_func_array(array($this->query, 'hasAnyTag'), $args);
   }
 
   public function addMetaData($key, $object) {
@@ -637,16 +640,16 @@
   /* Implementations of QueryConditionInterface for the HAVING clause. */
 
   public function havingCondition($field, $value = NULL, $operator = '=') {
-    $this->query->condition($field, $value, $operator, $num_args);
+    $this->query->havingCondition($field, $value, $operator);
     return $this;
   }
 
   public function &havingConditions() {
-    return $this->having->conditions();
+    return $this->query->havingConditions();
   }
 
   public function havingArguments() {
-    return $this->having->arguments();
+    return $this->query->havingArguments();
   }
 
   public function having($snippet, $args = array()) {
@@ -790,31 +793,7 @@
   }
 
   public function countQuery() {
-    // Create our new query object that we will mutate into a count query.
-    $count = clone($this);
-
-    // Zero-out existing fields and expressions.
-    $fields =& $count->getFields();
-    $fields = array();
-    $expressions =& $count->getExpressions();
-    $expressions = array();
-
-    // Also remove 'all_fields' statements, which are expanded into tablename.*
-    // when the query is executed.
-    $tables = &$count->getTables();
-    foreach ($tables as $alias => &$table) {
-      unset($table['all_fields']);
-    }
-
-    // Ordering a count query is a waste of cycles, and breaks on some
-    // databases anyway.
-    $orders = &$count->getOrderBy();
-    $orders = array();
-
-    // COUNT() is an expression, so we add that back in.
-    $count->addExpression('COUNT(*)');
-
-    return $count;
+    return $this->query->countQuery();
   }
 
   function isNull($field) {
@@ -836,7 +815,7 @@
     $this->query->notExists($select);
     return $this;
   }
-  
+
   public function __toString() {
     return (string) $this->query;
   }
@@ -1005,11 +984,13 @@
   }
 
   public function hasAllTags() {
-    return !(boolean)array_diff(func_get_args(), array_keys($this->alterTags));
+    $args = func_get_args();
+    return !(boolean)array_diff($args, array_keys($this->alterTags));
   }
 
   public function hasAnyTag() {
-    return (boolean)array_intersect(func_get_args(), array_keys($this->alterTags));
+    $args = func_get_args();
+    return (boolean)array_intersect($args, array_keys($this->alterTags));
   }
 
   public function addMetaData($key, $object) {
@@ -1088,7 +1069,7 @@
     $this->where->notExists($select);
     return $this;
   }
-  
+
   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
     $this->where->compile($connection, $queryPlaceholder);
     $this->having->compile($connection, $queryPlaceholder);
@@ -1172,17 +1153,17 @@
     $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;
@@ -1250,6 +1231,21 @@
 
     // Modules may alter all queries or only those having a particular tag.
     if (isset($this->alterTags)) {
+      // Many contrib modules assume that query tags used for access-checking
+      // purposes follow the pattern $entity_type . '_access'. But this is
+      // not the case for taxonomy terms, since core used to add term_access
+      // instead of taxonomy_term_access to its queries. Provide backwards
+      // compatibility by adding both tags here instead of attempting to fix
+      // all contrib modules in a coordinated effort.
+      // TODO:
+      // - Extract this mechanism into a hook as part of a public (non-security)
+      //   issue.
+      // - Emit E_USER_DEPRECATED if term_access is used.
+      //   https://www.drupal.org/node/2575081
+      $term_access_tags = array('term_access' => 1, 'taxonomy_term_access' => 1);
+      if (array_intersect_key($this->alterTags, $term_access_tags)) {
+        $this->alterTags += $term_access_tags;
+      }
       $hooks = array('query');
       foreach ($this->alterTags as $tag => $value) {
         $hooks[] = 'query_' . $tag;
@@ -1404,6 +1400,8 @@
   }
 
   public function orderBy($field, $direction = 'ASC') {
+    // Only allow ASC and DESC, default to ASC.
+    $direction = strtoupper($direction) == 'DESC' ? 'DESC' : 'ASC';
     $this->order[$field] = $direction;
     return $this;
   }
@@ -1451,17 +1449,20 @@
     $count = clone($this);
 
     $group_by = $count->getGroupBy();
+    $having = $count->havingConditions();
 
-    if (!$count->distinct) {
+    if (!$count->distinct && !isset($having[0])) {
       // When not executing a distinct query, we can zero-out existing fields
-      // and expressions that are not used by a GROUP BY.  Fields listed in
-      // the GROUP BY clause need to be present in the query.
+      // and expressions that are not used by a GROUP BY or HAVING. Fields
+      // listed in a GROUP BY or HAVING clause need to be present in the
+      // query.
       $fields =& $count->getFields();
       foreach (array_keys($fields) as $field) {
         if (empty($group_by[$field])) {
           unset($fields[$field]);
         }
       }
+
       $expressions =& $count->getExpressions();
       foreach (array_keys($expressions) as $field) {
         if (empty($group_by[$field])) {
@@ -1626,5 +1627,5 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/sqlite/database.inc drupal-7.58/includes/database/sqlite/database.inc
--- drupal-7.9/includes/database/sqlite/database.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/sqlite/database.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -37,7 +37,7 @@
   /**
    * 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();
@@ -46,10 +46,10 @@
    * 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;
@@ -59,16 +59,19 @@
     $this->statementClass = NULL;
 
     // This driver defaults to transaction support, except if explicitly passed FALSE.
-    $this->transactionSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
+    $this->transactionSupport = $this->transactionalDDLSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
 
     $this->connectionOptions = $connection_options;
 
-    parent::__construct('sqlite:' . $connection_options['database'], '', '', array(
-      // Force column names to lower case.
-      PDO::ATTR_CASE => PDO::CASE_LOWER,
+    // Allow PDO options to be overridden.
+    $connection_options += array(
+      'pdo' => array(),
+    );
+    $connection_options['pdo'] += array(
       // Convert numeric values to strings when fetching.
       PDO::ATTR_STRINGIFY_FETCHES => TRUE,
-    ));
+    );
+    parent::__construct('sqlite:' . $connection_options['database'], '', '', $connection_options['pdo']);
 
     // Attach one database for each registered prefix.
     $prefixes = $this->prefixes;
@@ -103,6 +106,11 @@
     $this->sqliteCreateFunction('substring', array($this, 'sqlFunctionSubstring'), 3);
     $this->sqliteCreateFunction('substring_index', array($this, 'sqlFunctionSubstringIndex'), 3);
     $this->sqliteCreateFunction('rand', array($this, 'sqlFunctionRand'));
+
+    // Execute sqlite init_commands.
+    if (isset($connection_options['init_commands'])) {
+      $this->exec(implode('; ', $connection_options['init_commands']));
+    }
   }
 
   /**
@@ -242,7 +250,7 @@
     $prefixes[$tablename] = '';
     $this->setPrefix($prefixes);
 
-    $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', $query), $args, $options);
+    $this->query('CREATE TEMPORARY TABLE ' . $tablename . ' AS ' . $query, $args, $options);
     return $tablename;
   }
 
@@ -370,6 +378,14 @@
     }
   }
 
+  public function utf8mb4IsActive() {
+    return TRUE;
+  }
+
+  public function utf8mb4IsSupported() {
+    return TRUE;
+  }
+
 }
 
 /**
@@ -507,5 +523,5 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/sqlite/install.inc drupal-7.58/includes/database/sqlite/install.inc
--- drupal-7.9/includes/database/sqlite/install.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/sqlite/install.inc	2018-03-27 21:28:19.000000000 +0200
@@ -14,8 +14,6 @@
 
   /**
    * Minimum engine version.
-   *
-   * @todo: consider upping to 3.6.8 in Drupal 8 to get SAVEPOINT support.
    */
   public function minimumVersion() {
     return '3.3.7';
diff -Naur drupal-7.9/includes/database/sqlite/query.inc drupal-7.58/includes/database/sqlite/query.inc
--- drupal-7.9/includes/database/sqlite/query.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/sqlite/query.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -41,7 +41,8 @@
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
+      $insert_fields_string = $this->insertFields ? ' (' . implode(', ', $this->insertFields) . ') ' : ' ';
+      return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
     }
 
     return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
@@ -57,39 +58,18 @@
  * we don't select those rows.
  *
  * A query like this one:
- *   UPDATE test SET name = 'newname' WHERE tid = 1
+ *   UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1
  * will become:
- *   UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
+ *   UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1 AND (col1 <> 'newcol1' OR col2 <> 'newcol2')
  */
 class UpdateQuery_sqlite extends UpdateQuery {
-  /**
-   * Helper function that removes the fields that are already in a condition.
-   *
-   * @param $fields
-   *   The fields.
-   * @param QueryConditionInterface $condition
-   *   A database condition.
-   */
-  protected function removeFieldsInCondition(&$fields, QueryConditionInterface $condition) {
-    foreach ($condition->conditions() as $child_condition) {
-      if ($child_condition['field'] instanceof QueryConditionInterface) {
-        $this->removeFieldsInCondition($fields, $child_condition['field']);
-      }
-      else {
-        unset($fields[$child_condition['field']]);
-      }
-    }
-  }
-
   public function execute() {
     if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
       return parent::execute();
     }
 
-    // Get the fields used in the update query, and remove those that are already
-    // in the condition.
+    // Get the fields used in the update query.
     $fields = $this->expressionFields + $this->fields;
-    $this->removeFieldsInCondition($fields, $this->condition);
 
     // Add the inverse of the fields to the condition.
     $condition = new DatabaseCondition('OR');
@@ -119,16 +99,15 @@
 
 /**
  * SQLite specific implementation of DeleteQuery.
- *
- * When the WHERE is omitted from a DELETE statement and the table being deleted
- * has no triggers, SQLite uses an optimization to erase the entire table content
- * without having to visit each row of the table individually.
- *
- * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
- * by that optimized "truncate" optimization.
  */
 class DeleteQuery_sqlite extends DeleteQuery {
   public function execute() {
+    // When the WHERE is omitted from a DELETE statement and the table being
+    // deleted has no triggers, SQLite uses an optimization to erase the entire
+    // table content without having to visit each row of the table individually.
+    // Prior to SQLite 3.6.5, SQLite does not return the actual number of rows
+    // deleted by that optimized "truncate" optimization. But we want to return
+    // the number of rows affected, so we calculate it directly.
     if (!count($this->condition)) {
       $total_rows = $this->connection->query('SELECT COUNT(*) FROM {' . $this->connection->escapeTable($this->table) . '}')->fetchField();
       parent::execute();
@@ -156,5 +135,5 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
diff -Naur drupal-7.9/includes/database/sqlite/schema.inc drupal-7.58/includes/database/sqlite/schema.inc
--- drupal-7.9/includes/database/sqlite/schema.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/sqlite/schema.inc	2018-03-27 21:28:19.000000000 +0200
@@ -232,10 +232,10 @@
 
   public function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
     }
 
     $schema = $this->introspectSchema($table);
@@ -244,7 +244,7 @@
     // database. So the syntax '...RENAME TO database.table' would fail.
     // So we must determine the full table name here rather than surrounding
     // the table with curly braces incase the db_prefix contains a reference
-    // to a database outside of our existsing database.
+    // to a database outside of our existing database.
     $info = $this->getPrefixInfo($new_name);
     $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']);
 
@@ -278,10 +278,10 @@
 
   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)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
     }
 
     // SQLite doesn't have a full-featured ALTER TABLE statement. It only
@@ -494,10 +494,10 @@
 
   public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      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)));
+      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)));
     }
 
     $old_schema = $this->introspectSchema($table);
@@ -559,10 +559,10 @@
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $schema['indexes'][$name] = $fields;
@@ -591,10 +591,10 @@
 
   public function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
     }
 
     $schema['unique keys'][$name] = $fields;
@@ -617,14 +617,14 @@
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
     }
 
     $old_schema = $this->introspectSchema($table);
     $new_schema = $old_schema;
 
     if (!empty($new_schema['primary key'])) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
     }
 
     $new_schema['primary key'] = $fields;
@@ -646,7 +646,7 @@
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     $old_schema = $this->introspectSchema($table);
@@ -658,7 +658,7 @@
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
     $old_schema = $this->introspectSchema($table);
diff -Naur drupal-7.9/includes/database/sqlite/select.inc drupal-7.58/includes/database/sqlite/select.inc
--- drupal-7.9/includes/database/sqlite/select.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/database/sqlite/select.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * @ingroup database
+ * @addtogroup database
  * @{
  */
 
@@ -21,7 +21,7 @@
 }
 
 /**
- * @} End of "ingroup database".
+ * @} End of "addtogroup database".
  */
 
 
diff -Naur drupal-7.9/includes/date.inc drupal-7.58/includes/date.inc
--- drupal-7.9/includes/date.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/date.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Initialize the list of date formats and their locales.
+ * Initializes the list of date formats and their locales.
  */
 
 /**
@@ -14,11 +14,6 @@
   // Short date formats.
   $formats[] = array(
     'type' => 'short',
-    'format' => 'Y-m-d H:i',
-    'locales' => array(),
-  );
-  $formats[] = array(
-    'type' => 'short',
     'format' => 'm/d/Y - H:i',
     'locales' => array('en-us'),
   );
@@ -39,6 +34,11 @@
   );
   $formats[] = array(
     'type' => 'short',
+    'format' => 'Y-m-d H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
     'format' => 'm/d/Y - g:ia',
     'locales' => array(),
   );
@@ -86,11 +86,6 @@
   // Medium date formats.
   $formats[] = array(
     'type' => 'medium',
-    'format' => 'D, Y-m-d H:i',
-    'locales' => array(),
-  );
-  $formats[] = array(
-    'type' => 'medium',
     'format' => 'D, m/d/Y - H:i',
     'locales' => array('en-us'),
   );
@@ -106,6 +101,11 @@
   );
   $formats[] = array(
     'type' => 'medium',
+    'format' => 'D, Y-m-d H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
     'format' => 'F j, Y - H:i',
     'locales' => array(),
   );
diff -Naur drupal-7.9/includes/entity.inc drupal-7.58/includes/entity.inc
--- drupal-7.9/includes/entity.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/entity.inc	2018-03-27 21:28:19.000000000 +0200
@@ -14,14 +14,6 @@
 interface DrupalEntityControllerInterface {
 
   /**
-   * Constructor.
-   *
-   * @param $entityType
-   *   The entity type for which the instance is created.
-   */
-  public function __construct($entityType);
-
-  /**
    * Resets the internal, static entity cache.
    *
    * @param $ids
@@ -36,7 +28,9 @@
    * @param $ids
    *   An array of entity IDs, or FALSE to load all entities.
    * @param $conditions
-   *   An array of conditions in the form 'field' => $value.
+   *   An array of conditions. Keys are field names on the entity's base table.
+   *   Values will be compared for equality. All the comparisons will be ANDed
+   *   together. This parameter is deprecated; use an EntityFieldQuery instead.
    *
    * @return
    *   An array of entity objects indexed by their ids. When no results are
@@ -54,7 +48,7 @@
 class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
 
   /**
-   * Static cache of entities.
+   * Static cache of entities, keyed by entity ID.
    *
    * @var array
    */
@@ -119,6 +113,9 @@
 
   /**
    * Constructor: sets basic variables.
+   *
+   * @param $entityType
+   *   The entity type for which the instance is created.
    */
   public function __construct($entityType) {
     $this->entityType = $entityType;
@@ -186,6 +183,11 @@
       }
     }
 
+    // Ensure integer entity IDs are valid.
+    if (!empty($ids)) {
+      $this->cleanIds($ids);
+    }
+
     // Load any remaining entities from the database. This is the case if $ids
     // is set to FALSE (so we load all entities), if there are any ids left to
     // load, if loading a revision, or if $conditions was passed without $ids.
@@ -227,6 +229,35 @@
   }
 
   /**
+   * Ensures integer entity IDs are valid.
+   *
+   * The identifier sanitization provided by this method has been introduced
+   * as Drupal used to rely on the database to facilitate this, which worked
+   * correctly with MySQL but led to errors with other DBMS such as PostgreSQL.
+   *
+   * @param array $ids
+   *   The entity IDs to verify. Non-integer IDs are removed from this array if
+   *   the entity type requires IDs to be integers.
+   */
+  protected function cleanIds(&$ids) {
+    $entity_info = entity_get_info($this->entityType);
+    if (isset($entity_info['base table field types'])) {
+      $id_type = $entity_info['base table field types'][$this->idKey];
+      if ($id_type == 'serial' || $id_type == 'int') {
+        $ids = array_filter($ids, array($this, 'filterId'));
+        $ids = array_map('intval', $ids);
+      }
+    }
+  }
+
+  /**
+   * Callback for array_filter that removes non-integer IDs.
+   */
+  protected function filterId($id) {
+    return is_numeric($id) && $id == (int) $id;
+  }
+
+  /**
    * Builds the query to load the entity.
    *
    * This has full revision support. For entities requiring special queries,
@@ -241,7 +272,9 @@
    * @param $ids
    *   An array of entity IDs, or FALSE to load all entities.
    * @param $conditions
-   *   An array of conditions in the form 'field' => $value.
+   *   An array of conditions. Keys are field names on the entity's base table.
+   *   Values will be compared for equality. All the comparisons will be ANDed
+   *   together. This parameter is deprecated; use an EntityFieldQuery instead.
    * @param $revision_id
    *   The ID of the revision to load, or FALSE if this query is asking for the
    *   most current revision(s).
@@ -296,6 +329,7 @@
 
   /**
    * Attaches data to entities upon loading.
+   *
    * This will attach fields, if the entity is fieldable. It calls
    * hook_entity_load() for modules which need to add data to all entities.
    * It also calls hook_TYPE_load() on the loaded entities. For example
@@ -364,9 +398,23 @@
     // This ensures the same behavior whether loading from memory or database.
     if ($conditions) {
       foreach ($entities as $entity) {
-        $entity_values = (array) $entity;
-        if (array_diff_assoc($conditions, $entity_values)) {
-          unset($entities[$entity->{$this->idKey}]);
+        // Iterate over all conditions and compare them to the entity
+        // properties. We cannot use array_diff_assoc() here since the
+        // conditions can be nested arrays, too.
+        foreach ($conditions as $property_name => $condition) {
+          if (is_array($condition)) {
+            // Multiple condition values for one property are treated as OR
+            // operation: only if the value is not at all in the condition array
+            // we remove the entity.
+            if (!in_array($entity->{$property_name}, $condition)) {
+              unset($entities[$entity->{$this->idKey}]);
+              continue 2;
+            }
+          }
+          elseif ($condition != $entity->{$property_name}) {
+            unset($entities[$entity->{$this->idKey}]);
+            continue 2;
+          }
         }
       }
     }
@@ -398,7 +446,7 @@
  *
  * This class allows finding entities based on entity properties (for example,
  * node->changed), field values, and generic entity meta data (bundle,
- * entity type, entity id, and revision ID). It is not possible to query across
+ * entity type, entity ID, and revision ID). It is not possible to query across
  * multiple entity types. For example, there is no facility to find published
  * nodes written by users created in the last hour, as this would require
  * querying both node->status and user->created.
@@ -415,13 +463,14 @@
  * an EntityFieldQueryException will be raised if an unsupported condition is
  * specified or if the query has field conditions or sorts that are stored in
  * different field storage engines. However, this logic can be overridden in
- * hook_entity_query().
+ * hook_entity_query_alter().
  *
  * Also note that this query does not automatically respect entity access
  * restrictions. Node access control is performed by the SQL storage engine but
  * other storage engines might not do this.
  */
 class EntityFieldQuery {
+
   /**
    * Indicates that both deleted and non-deleted fields should be returned.
    *
@@ -468,7 +517,7 @@
    * @var array
    *
    * @see EntityFieldQuery::fieldLanguageCondition()
-   * @see EntityFieldQuery::fielDeltaCondition()
+   * @see EntityFieldQuery::fieldDeltaCondition()
    */
   public $fieldMetaConditions = array();
 
@@ -594,9 +643,7 @@
    *
    * '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.
+   * Note: The "comment" entity type does not support bundle conditions.
    *
    * @param $name
    *   'entity_type', 'bundle', 'revision_id' or 'entity_id'.
@@ -635,17 +682,42 @@
   /**
    * Adds a condition on field values.
    *
+   * Note that entities with empty field values will be excluded from the
+   * EntityFieldQuery results when using this method.
+   *
    * @param $field
    *   Either a field name or a field array.
    * @param $column
-   *   The column that should hold the value to be matched.
+   *   The column that should hold the value to be matched, defined in the
+   *   hook_field_schema() of this field. If this is omitted then all of the
+   *   other parameters are ignored, except $field, and this call will just be
+   *   adding a condition that says that the field has a value, rather than
+   *   testing the value itself.
    * @param $value
-   *   The value to test the column value against.
+   *   The value to test the column value 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 $operator.
    * @param $operator
-   *   The operator to be used to test the given value.
+   *   The operator to be used to test the given value. The possible values are:
+   *   - '=', '<>', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These
+   *     operators expect $value to be a literal of the same type as the
+   *     column.
+   *   - 'IN', 'NOT IN': These operators expect $value to be an array of
+   *     literals of the same type as the column.
+   *   - 'BETWEEN': This operator expects $value to be an array of two literals
+   *     of the same type as the column.
+   *   The operator can be omitted, and will default to 'IN' if the value is an
+   *   array, or to '=' otherwise.
    * @param $delta_group
    *   An arbitrary identifier: conditions in the same group must have the same
-   *   $delta_group.
+   *   $delta_group. For example, let's presume a multivalue field which has
+   *   two columns, 'color' and 'shape', and for entity ID 1, there are two
+   *   values: red/square and blue/circle. Entity ID 1 does not have values
+   *   corresponding to 'red circle'; however if you pass 'red' and 'circle' as
+   *   conditions, it will appear in the results -- by default queries will run
+   *   against any combination of deltas. By passing the conditions with the
+   *   same $delta_group it will ensure that only values attached to the same
+   *   delta are matched, and entity 1 would then be excluded from the results.
    * @param $language_group
    *   An arbitrary identifier: conditions in the same group must have the same
    *   $language_group.
@@ -720,9 +792,11 @@
    * @param $field
    *   Either a field name or a field array.
    * @param $column
-   *   A column defined in the hook_field_schema() of this field. If this is
-   *   omitted then the query will find only entities that have data in this
-   *   field, using the entity and property conditions if there are any.
+   *   The column that should hold the value to be matched, defined in the
+   *   hook_field_schema() of this field. If this is omitted then all of the
+   *   other parameters are ignored, except $field, and this call will just be
+   *   adding a condition that says that the field has a value, rather than
+   *   testing the value itself.
    * @param $value
    *   The value to test the column value against. In most cases, this is a
    *   scalar. For more complex options, it is an array. The meaning of each
@@ -741,10 +815,10 @@
    * @param $delta_group
    *   An arbitrary identifier: conditions in the same group must have the same
    *   $delta_group. For example, let's presume a multivalue field which has
-   *   two columns, 'color' and 'shape', and for entity id 1, there are two
+   *   two columns, 'color' and 'shape', and for entity ID 1, there are two
    *   values: red/square and blue/circle. Entity ID 1 does not have values
    *   corresponding to 'red circle', however if you pass 'red' and 'circle' as
-   *   conditions, it will appear in the  results - by default queries will run
+   *   conditions, it will appear in the results -- by default queries will run
    *   against any combination of deltas. By passing the conditions with the
    *   same $delta_group it will ensure that only values attached to the same
    *   delta are matched, and entity 1 would then be excluded from the results.
@@ -858,7 +932,9 @@
    * Orders the result set by a given field column.
    *
    * If called multiple times, the query will order by each specified column in
-   * the order this method is called.
+   * the order this method is called. Note that entities with empty field
+   * values will be excluded from the EntityFieldQuery results when using this
+   * method.
    *
    * @param $field
    *   Either a field name or a field array.
@@ -953,7 +1029,7 @@
   }
 
   /**
-   * Enable a pager for the query.
+   * Enables a pager for the query.
    *
    * @param $limit
    *   An integer specifying the number of elements per page.  If passed a false
@@ -981,10 +1057,11 @@
   }
 
   /**
-   * Enable sortable tables for this query.
+   * Enables sortable tables for this query.
    *
    * @param $headers
-   *   An EFQ Header array based on which the order clause is added to the query.
+   *   An EFQ Header array based on which the order clause is added to the
+   *   query.
    *
    * @return EntityFieldQuery
    *   The called object.
@@ -1106,12 +1183,13 @@
    * contains everything necessary for processing.
    *
    * @return
-   *   Either a number if count() was called or an array of associative
-   *   arrays of stub entities. The outer array keys are entity types, and the
-   *   inner array keys are the relevant ID. (In most this cases this will be
-   *   the entity ID. The only exception is when age=FIELD_LOAD_REVISION is used
-   *   and field conditions or sorts are present -- in this case, the key will
-   *   be the revision ID.) The inner array values are always stub entities, as
+   *   Either a number if count() was called or an array of associative arrays
+   *   of stub entities. The outer array keys are entity types, and the inner
+   *   array keys are the relevant ID. (In most cases this will be the entity
+   *   ID. The only exception is when age=FIELD_LOAD_REVISION is used and field
+   *   conditions or sorts are present -- in this case, the key will be the
+   *   revision ID.) The entity type will only exist in the outer array if
+   *   results were found. The inner array values are always stub entities, as
    *   returned by entity_create_stub_entity(). To traverse the returned array:
    *   @code
    *     foreach ($query->execute() as $entity_type => $entities) {
@@ -1121,7 +1199,9 @@
    *   the entities found:
    *   @code
    *     $result = $query->execute();
-   *     $entities = entity_load($my_type, array_keys($result[$my_type]));
+   *     if (!empty($result[$my_type])) {
+   *       $entities = entity_load($my_type, array_keys($result[$my_type]));
+   *     }
    *   @endcode
    */
   public function execute() {
@@ -1196,7 +1276,7 @@
     $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type));
     // Process the property conditions.
     foreach ($this->propertyConditions as $property_condition) {
-      $this->addCondition($select_query, "$base_table." . $property_condition['column'], $property_condition);
+      $this->addCondition($select_query, $base_table . '.' . $property_condition['column'], $property_condition);
     }
     // Process the four possible entity condition.
     // The id field is always present in entity keys.
@@ -1204,7 +1284,7 @@
     $id_map['entity_id'] = $sql_field;
     $select_query->addField($base_table, $sql_field, 'entity_id');
     if (isset($this->entityConditions['entity_id'])) {
-      $this->addCondition($select_query, $sql_field, $this->entityConditions['entity_id']);
+      $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['entity_id']);
     }
 
     // If there is a revision key defined, use it.
@@ -1212,7 +1292,7 @@
       $sql_field = $entity_info['entity keys']['revision'];
       $select_query->addField($base_table, $sql_field, 'revision_id');
       if (isset($this->entityConditions['revision_id'])) {
-        $this->addCondition($select_query, $sql_field, $this->entityConditions['revision_id']);
+        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['revision_id']);
       }
     }
     else {
@@ -1237,7 +1317,13 @@
     }
     $id_map['bundle'] = $sql_field;
     if (isset($this->entityConditions['bundle'])) {
-      $this->addCondition($select_query, $sql_field, $this->entityConditions['bundle'], $having);
+      if (!empty($entity_info['entity keys']['bundle'])) {
+        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['bundle'], $having);
+      }
+      else {
+        // This entity has no bundle, so invalidate the query.
+        $select_query->where('1 = 0');
+      }
     }
 
     // Order the query.
@@ -1250,7 +1336,7 @@
         $select_query->orderBy($id_map[$key], $order['direction']);
       }
       elseif ($order['type'] == 'property') {
-        $select_query->orderBy("$base_table." . $order['specifier'], $order['direction']);
+        $select_query->orderBy($base_table . '.' . $order['specifier'], $order['direction']);
       }
     }
 
@@ -1258,14 +1344,13 @@
   }
 
   /**
-   * Get the total number of results and initialize a pager for the query.
+   * Gets the total number of results and initializes 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.
+   * The pager can be disabled by either setting the pager limit to 0, or by
+   * setting this query to be a count query.
    */
   function initializePager() {
-    if ($this->pager && !$this->count) {
+    if ($this->pager && !empty($this->pager['limit']) && !$this->count) {
       $page = pager_find_page($this->pager['element']);
       $count_query = clone $this;
       $this->pager['total'] = $count_query->count()->execute();
@@ -1346,6 +1431,6 @@
 }
 
 /**
- * Exception thrown when a malformed entity is passed.
+ * Defines an exception thrown when a malformed entity is passed.
  */
 class EntityMalformedException extends Exception { }
diff -Naur drupal-7.9/includes/errors.inc drupal-7.58/includes/errors.inc
--- drupal-7.9/includes/errors.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/errors.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,28 +2,14 @@
 
 /**
  * @file
- * Functions for error handling
+ * Functions for error handling.
  */
 
 /**
- * Error reporting level: display no errors.
- */
-define('ERROR_REPORTING_HIDE', 0);
-
-/**
- * Error reporting level: display errors and warnings.
- */
-define('ERROR_REPORTING_DISPLAY_SOME', 1);
-
-/**
- * Error reporting level: display all messages.
- */
-define('ERROR_REPORTING_DISPLAY_ALL', 2);
-
-/**
- * Map PHP error constants to watchdog severity levels.
+ * Maps PHP error constants to watchdog severity levels.
+ *
  * The error constants are documented at
- * http://php.net/manual/en/errorfunc.constants.php
+ * http://php.net/manual/errorfunc.constants.php
  *
  * @ingroup logging_severity_levels
  */
@@ -52,7 +38,7 @@
 }
 
 /**
- * Custom PHP error handler.
+ * Provides custom PHP error handling.
  *
  * @param $error_level
  *   The level of the error raised.
@@ -63,7 +49,8 @@
  * @param $line
  *   The line number the error was raised at.
  * @param $context
- *   An array that points to the active symbol table at the point the error occurred.
+ *   An array that points to the active symbol table at the point the error
+ *   occurred.
  */
 function _drupal_error_handler_real($error_level, $message, $filename, $line, $context) {
   if ($error_level & error_reporting()) {
@@ -79,7 +66,7 @@
     _drupal_log_error(array(
       '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error',
       // The standard PHP error handler considers that the error messages
-      // are HTML. We mimick this behavior here.
+      // are HTML. We mimic this behavior here.
       '!message' => filter_xss_admin($message),
       '%function' => $caller['function'],
       '%file' => $caller['file'],
@@ -90,10 +77,11 @@
 }
 
 /**
- * Decode an exception, especially to retrive the correct caller.
+ * Decodes an exception and retrieves the correct caller.
  *
  * @param $exception
  *   The exception object that was thrown.
+ *
  * @return
  *   An error in the format expected by _drupal_log_error().
  */
@@ -126,7 +114,7 @@
   return array(
     '%type' => get_class($exception),
     // The standard PHP exception handler considers that the exception message
-    // is plain-text. We mimick this behavior here.
+    // is plain-text. We mimic this behavior here.
     '!message' => check_plain($message),
     '%function' => $caller['function'],
     '%file' => $caller['file'],
@@ -136,7 +124,7 @@
 }
 
 /**
- * Render an error message for an exception without any possibility of a further exception occurring.
+ * Renders an exception error message without further exceptions.
  *
  * @param $exception
  *   The exception object that was thrown.
@@ -171,17 +159,17 @@
 }
 
 /**
- * Log a PHP error or exception, display an error page in fatal cases.
+ * Logs a PHP error or exception and displays an error page in fatal cases.
  *
  * @param $error
  *   An array with the following keys: %type, !message, %function, %file, %line
- *   and severity_level. All the parameters are plain-text, with the exception of
- *   !message, which needs to be a safe HTML string.
+ *   and severity_level. All the parameters are plain-text, with the exception
+ *   of !message, which needs to be a safe HTML string.
  * @param $fatal
  *   TRUE if the error is fatal.
  */
 function _drupal_log_error($error, $fatal = FALSE) {
-  // Initialize a maintenance theme if the boostrap was not complete.
+  // Initialize a maintenance theme if the bootstrap was not complete.
   // Do it early because drupal_set_message() triggers a drupal_theme_initialize().
   if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
     unset($GLOBALS['theme']);
@@ -211,7 +199,16 @@
     $number++;
   }
 
-  watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+  // Log the error immediately, unless this is a non-fatal error which has been
+  // triggered via drupal_trigger_error_with_delayed_logging(); in that case
+  // trigger it in a shutdown function. Fatal errors are always triggered
+  // immediately since for a fatal error the page request will end here anyway.
+  if (!$fatal && drupal_static('_drupal_trigger_error_with_delayed_logging')) {
+    drupal_register_shutdown_function('watchdog', 'php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+  }
+  else {
+    watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+  }
 
   if ($fatal) {
     drupal_add_http_header('Status', '500 Service unavailable (with message)');
@@ -227,14 +224,16 @@
 
   if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
     if ($fatal) {
-      // When called from JavaScript, simply output the error message.
-      print t('%type: !message in %function (line %line of %file).', $error);
+      if (error_displayable($error)) {
+        // When called from JavaScript, simply output the error message.
+        print t('%type: !message in %function (line %line of %file).', $error);
+      }
       exit;
     }
   }
   else {
     // Display the message if the current error reporting level allows this type
-    // of message to be displayed, and unconditionnaly in update.php.
+    // of message to be displayed, and unconditionally in update.php.
     if (error_displayable($error)) {
       $class = 'error';
 
@@ -263,6 +262,7 @@
  *
  * @param $backtrace
  *   A standard PHP backtrace.
+ *
  * @return
  *   An associative array with keys 'file', 'line' and 'function'.
  */
diff -Naur drupal-7.9/includes/file.inc drupal-7.58/includes/file.inc
--- drupal-7.9/includes/file.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/file.inc	2018-03-27 21:28:19.000000000 +0200
@@ -70,11 +70,7 @@
 define('FILE_STATUS_PERMANENT', 1);
 
 /**
- * Methods to manage a registry of stream wrappers.
- */
-
-/**
- * Drupal stream wrapper registry.
+ * Provides Drupal stream wrapper registry.
  *
  * A stream wrapper is an abstraction of a file system that allows Drupal to
  * use the same set of methods to access both local files and remote resources.
@@ -93,7 +89,7 @@
  * wrappers that are appropriate for particular usage. For example, this returns
  * only stream wrappers that use local file storage:
  * @code
- *   $local_stream_wrappers = file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL);
+ *   $local_stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
  * @endcode
  *
  * The $filter parameter can only filter to types containing a particular flag.
@@ -103,7 +99,7 @@
  * array_diff_key() function can be used to help with this. For example, this
  * returns only stream wrappers that do not use local file storage:
  * @code
- *   $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL));
+ *   $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL));
  * @endcode
  *
  * @param $filter
@@ -206,7 +202,7 @@
 }
 
 /**
- * Check that the scheme of a stream URI is valid.
+ * Checks that the scheme of a stream URI is valid.
  *
  * Confirms that there is a registered stream handler for the provided scheme
  * and that it is callable. This is useful if you want to confirm a valid
@@ -232,7 +228,7 @@
 
 
 /**
- * Returns the part of an URI after the schema.
+ * Returns the part of a URI after the schema.
  *
  * @param $uri
  *   A stream, referenced as "scheme://target".
@@ -252,7 +248,7 @@
 }
 
 /**
- * Get the default file stream implementation.
+ * Gets the default file stream implementation.
  *
  * @return
  *   'public', 'private' or any other file scheme defined as the default.
@@ -277,7 +273,9 @@
  *   The normalized URI.
  */
 function file_stream_wrapper_uri_normalize($uri) {
-  $scheme = file_uri_scheme($uri);
+  // Inline file_uri_scheme() function call for performance reasons.
+  $position = strpos($uri, '://');
+  $scheme = $position ? substr($uri, 0, $position) : FALSE;
 
   if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
     $target = file_uri_target($uri);
@@ -286,10 +284,6 @@
       $uri = $scheme . '://' . $target;
     }
   }
-  else {
-    // The default scheme is file://
-    $url = 'file://' . $uri;
-  }
   return $uri;
 }
 
@@ -322,7 +316,7 @@
 }
 
 /**
- * Returns a reference to the stream wrapper class responsible for a given scheme.
+ * Returns a reference to the stream wrapper class responsible for a scheme.
  *
  * This helper method returns a stream instance using a scheme. That is, the
  * passed string does not contain a "://". For example, "public" is a scheme
@@ -357,7 +351,6 @@
  * Creates a web-accessible URL for a stream to an external or local file.
  *
  * Compatibility: normal paths and stream wrappers.
- * @see http://drupal.org/node/515192
  *
  * There are two kinds of local files:
  * - "managed files", i.e. those stored by a Drupal-compatible stream wrapper.
@@ -375,6 +368,8 @@
  *   If the provided string already contains a preceding 'http', 'https', or
  *   '/', nothing is done and the same string is returned. If a stream wrapper
  *   could not be found to generate an external URL, then FALSE is returned.
+ *
+ * @see http://drupal.org/node/515192
  */
 function file_create_url($uri) {
   // Allow the URI to be altered, e.g. to serve a file from a CDN or static
@@ -401,8 +396,8 @@
     }
   }
   elseif ($scheme == 'http' || $scheme == 'https') {
-    // Check for http so that we don't have to implement getExternalUrl() for
-    // the http wrapper.
+    // Check for HTTP so that we don't have to implement getExternalUrl() for
+    // the HTTP wrapper.
     return $uri;
   }
   else {
@@ -417,7 +412,7 @@
 }
 
 /**
- * Check that the directory exists and is writable.
+ * Checks that the directory exists and is writable.
  *
  * Directories need to have execute permissions to be considered a directory by
  * FTP servers, etc.
@@ -459,7 +454,7 @@
 }
 
 /**
- * If missing, create a .htaccess file in each Drupal files directory.
+ * Creates a .htaccess file in each Drupal files directory if it is missing.
  */
 function file_ensure_htaccess() {
   file_create_htaccess('public://', FALSE);
@@ -470,15 +465,18 @@
 }
 
 /**
- * Creates an .htaccess file in the given directory.
+ * Creates a .htaccess file in the given directory.
  *
  * @param $directory
  *   The directory.
  * @param $private
  *   FALSE indicates that $directory should be an open and public directory.
  *   The default is TRUE which indicates a private and protected directory.
+ * @param $force_overwrite
+ *   Set to TRUE to attempt to overwrite the existing .htaccess file if one is
+ *   already present. Defaults to FALSE.
  */
-function file_create_htaccess($directory, $private = TRUE) {
+function file_create_htaccess($directory, $private = TRUE, $force_overwrite = FALSE) {
   if (file_uri_scheme($directory)) {
     $directory = file_stream_wrapper_uri_normalize($directory);
   }
@@ -487,19 +485,12 @@
   }
   $htaccess_path =  $directory . '/.htaccess';
 
-  if (file_exists($htaccess_path)) {
+  if (file_exists($htaccess_path) && !$force_overwrite) {
     // Short circuit if the .htaccess file already exists.
     return;
   }
 
-  if ($private) {
-    // Private .htaccess file.
-    $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks";
-  }
-  else {
-    // Public .htaccess file.
-    $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
-  }
+  $htaccess_lines = file_htaccess_lines($private);
 
   // Write the .htaccess file.
   if (file_put_contents($htaccess_path, $htaccess_lines)) {
@@ -512,6 +503,56 @@
 }
 
 /**
+ * Returns the standard .htaccess lines that Drupal writes to file directories.
+ *
+ * @param $private
+ *   (Optional) Set to FALSE to return the .htaccess lines for an open and
+ *   public directory. The default is TRUE, which returns the .htaccess lines
+ *   for a private and protected directory.
+ *
+ * @return
+ *   A string representing the desired contents of the .htaccess file.
+ *
+ * @see file_create_htaccess()
+ */
+function file_htaccess_lines($private = TRUE) {
+  $lines = <<<EOF
+# Turn off all options we don't need.
+Options None
+Options +FollowSymLinks
+
+# Set the catch-all handler to prevent scripts from being executed.
+SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
+<Files *>
+  # Override the handler again if we're run later in the evaluation list.
+  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
+</Files>
+
+# If we know how to do it safely, disable the PHP engine entirely.
+<IfModule mod_php5.c>
+  php_flag engine off
+</IfModule>
+EOF;
+
+  if ($private) {
+    $lines = <<<EOF
+# Deny all requests from Apache 2.4+.
+<IfModule mod_authz_core.c>
+  Require all denied
+</IfModule>
+
+# Deny all requests from Apache 2.0-2.2.
+<IfModule !mod_authz_core.c>
+  Deny from all
+</IfModule>
+EOF
+    . "\n\n" . $lines;
+  }
+
+  return $lines;
+}
+
+/**
  * Loads file objects from the database.
  *
  * @param $fids
@@ -526,25 +567,25 @@
  * @return
  *   An array of file objects, indexed by fid.
  *
+ * @todo Remove $conditions in Drupal 8.
+ *
  * @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);
 }
 
 /**
- * Load a file object from the database.
+ * Loads a single file object from the database.
  *
  * @param $fid
  *   A file ID.
  *
  * @return
- *   A file object.
+ *   An object representing the file, or FALSE if the file was not found.
  *
  * @see hook_file_load()
  * @see file_load_multiple()
@@ -555,7 +596,7 @@
 }
 
 /**
- * Save a file object to the database.
+ * Saves a file object to the database.
  *
  * If the $file->fid is not set a new record will be added.
  *
@@ -593,7 +634,11 @@
     module_invoke_all('entity_update', $file, 'file');
   }
 
+  // Clear internal properties.
   unset($file->original);
+  // Clear the static loading cache.
+  entity_get_controller('file')->resetCache(array($file->fid));
+
   return $file;
 }
 
@@ -726,10 +771,11 @@
  * stored in the database. This is a powerful function that in many ways
  * performs like an advanced version of copy().
  * - Checks if $source and $destination are valid and readable/writable.
- * - Checks that $source is not equal to $destination; if they are an error
- *   is reported.
  * - If file already exists in $destination either the call will error out,
  *   replace the file or rename the file based on the $replace parameter.
+ * - If the $source and $destination are equal, the behavior depends on the
+ *   $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME
+ *   will rename the file until the $destination is unique.
  * - Adds the new file to the files database. If the source file is a
  *   temporary file, the resulting file will also be a temporary file. See
  *   file_save_upload() for details on temporary files.
@@ -770,7 +816,7 @@
     $file = clone $source;
     $file->fid = NULL;
     $file->uri = $uri;
-    $file->filename = basename($uri);
+    $file->filename = drupal_basename($uri);
     // If we are replacing an existing file re-use its database record.
     if ($replace == FILE_EXISTS_REPLACE) {
       $existing_files = file_load_multiple(array(), array('uri' => $uri));
@@ -783,7 +829,7 @@
     // If we are renaming around an existing file (rather than a directory),
     // use its basename for the filename.
     elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
-      $file->filename = basename($destination);
+      $file->filename = drupal_basename($destination);
     }
 
     $file = file_save($file);
@@ -797,7 +843,7 @@
 }
 
 /**
- * Determine whether the URI has a valid scheme for file API operations.
+ * Determines whether the URI has a valid scheme for file API operations.
  *
  * There must be a scheme and it must be a Drupal-provided scheme like
  * 'public', 'private', 'temporary', or an extension provided with
@@ -824,18 +870,22 @@
  * This is a powerful function that in many ways performs like an advanced
  * version of copy().
  * - Checks if $source and $destination are valid and readable/writable.
- * - Checks that $source is not equal to $destination; if they are an error
- *   is reported.
  * - If file already exists in $destination either the call will error out,
  *   replace the file or rename the file based on the $replace parameter.
+ * - If the $source and $destination are equal, the behavior depends on the
+ *   $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME
+ *   will rename the file until the $destination is unique.
+ * - Provides a fallback using realpaths if the move fails using stream
+ *   wrappers. This can occur because PHP's copy() function does not properly
+ *   support streams if safe_mode or open_basedir are enabled. See
+ *   https://bugs.php.net/bug.php?id=60456
  *
  * @param $source
  *   A string specifying the filepath or URI of the source file.
  * @param $destination
  *   A URI containing the destination that $source should be copied to. The
- *   URI may be a bare filepath (without a scheme) and in that case the default
- *   scheme (file://) will be used. If this value is omitted, Drupal's default
- *   files scheme will be used, usually "public://".
+ *   URI may be a bare filepath (without a scheme). If this value is omitted,
+ *   Drupal's default files scheme will be used, usually "public://".
  * @param $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
@@ -850,7 +900,6 @@
  */
 function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
   $original_source = $source;
-  $original_destination = $destination;
 
   // Assert that the source file actually exists.
   if (!file_exists($source)) {
@@ -867,14 +916,14 @@
 
   // Build a destination URI if necessary.
   if (!isset($destination)) {
-    $destination = file_build_uri(basename($source));
+    $destination = file_build_uri(drupal_basename($source));
   }
 
 
   // Prepare the destination directory.
   if (file_prepare_directory($destination)) {
     // The destination is already a directory, so append the source basename.
-    $destination = file_stream_wrapper_uri_normalize($destination . '/' . basename($source));
+    $destination = file_stream_wrapper_uri_normalize($destination . '/' . drupal_basename($source));
   }
   else {
     // Perhaps $destination is a dir/file?
@@ -891,7 +940,7 @@
   $destination = file_destination($destination, $replace);
   if ($destination === FALSE) {
     drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error');
-    watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => $destination));
+    watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%directory' => $destination));
     return FALSE;
   }
 
@@ -907,8 +956,12 @@
   file_ensure_htaccess();
   // Perform the copy operation.
   if (!@copy($source, $destination)) {
-    watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR);
-    return FALSE;
+    // If the copy failed and realpaths exist, retry the operation using them
+    // instead.
+    if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) {
+      watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR);
+      return FALSE;
+    }
   }
 
   // Set the permissions on the new file.
@@ -918,7 +971,7 @@
 }
 
 /**
- * Given a relative path, construct a URI into Drupal's default files location.
+ * Constructs a URI to Drupal's default files location given a relative path.
  */
 function file_build_uri($path) {
   $uri = file_default_scheme() . '://' . $path;
@@ -926,8 +979,7 @@
 }
 
 /**
- * Determines the destination path for a file depending on how replacement of
- * existing files should be handled.
+ * Determines the destination path for a file.
  *
  * @param $destination
  *   A string specifying the desired final URI or filepath.
@@ -950,7 +1002,7 @@
         break;
 
       case FILE_EXISTS_RENAME:
-        $basename = basename($destination);
+        $basename = drupal_basename($destination);
         $directory = drupal_dirname($destination);
         $destination = file_create_filename($basename, $directory);
         break;
@@ -964,7 +1016,7 @@
 }
 
 /**
- * Move a file to a new location and update the file's database entry.
+ * Moves a file to a new location and update the file's database entry.
  *
  * Moving a file is performed by copying the file to the new location and then
  * deleting the original.
@@ -1025,7 +1077,7 @@
     // If we are renaming around an existing file (rather than a directory),
     // use its basename for the filename.
     elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
-      $file->filename = basename($destination);
+      $file->filename = drupal_basename($destination);
     }
 
     $file = file_save($file);
@@ -1044,8 +1096,7 @@
 }
 
 /**
- * Move a file to a new location without calling any hooks or making any
- * changes to the database.
+ * Moves a file to a new location without database changes or hook invocation.
  *
  * @param $source
  *   A string specifying the filepath or URI of the original file.
@@ -1074,7 +1125,7 @@
 }
 
 /**
- * Modify a filename as needed for security purposes.
+ * Modifies a filename as needed for security purposes.
  *
  * Munging a file name prevents unknown file extensions from masking exploit
  * files. When web servers such as Apache decide how to process a URL request,
@@ -1110,7 +1161,10 @@
 
   // Allow potentially insecure uploads for very savvy users and admin
   if (!variable_get('allow_insecure_uploads', 0)) {
-    $whitelist = array_unique(explode(' ', trim($extensions)));
+    // Remove any null bytes. See http://php.net/manual/security.filesystem.nullbytes.php
+    $filename = str_replace(chr(0), '', $filename);
+
+    $whitelist = array_unique(explode(' ', strtolower(trim($extensions))));
 
     // Split the filename up by periods. The first part becomes the basename
     // the last part the final extension.
@@ -1123,7 +1177,7 @@
     // of allowed extensions.
     foreach ($filename_parts as $filename_part) {
       $new_filename .= '.' . $filename_part;
-      if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
+      if (!in_array(strtolower($filename_part), $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
         $new_filename .= '_';
       }
     }
@@ -1138,7 +1192,7 @@
 }
 
 /**
- * Undo the effect of upload_munge_filename().
+ * Undoes the effect of file_munge_filename().
  *
  * @param $filename
  *   String with the filename to be unmunged.
@@ -1151,7 +1205,7 @@
 }
 
 /**
- * Create a full file path from a directory and filename.
+ * Creates a full file path from a directory and filename.
  *
  * If a file with the specified name already exists, an alternative will be
  * used.
@@ -1206,7 +1260,7 @@
 }
 
 /**
- * Delete a file and its database record.
+ * Deletes a file and its database record.
  *
  * If the $force parameter is not TRUE, file_usage_list() will be called to
  * determine if the file is being used by any modules. If the file is being
@@ -1255,14 +1309,14 @@
   if (file_unmanaged_delete($file->uri)) {
     db_delete('file_managed')->condition('fid', $file->fid)->execute();
     db_delete('file_usage')->condition('fid', $file->fid)->execute();
+    entity_get_controller('file')->resetCache();
     return TRUE;
   }
   return FALSE;
 }
 
 /**
- * Delete a file without calling any hooks or making any changes to the
- * database.
+ * Deletes a file without database changes or hook invocations.
  *
  * This function should be used when the file to be deleted does not have an
  * entry recorded in the files table.
@@ -1298,7 +1352,7 @@
 }
 
 /**
- * Recursively delete all files and directories in the specified filepath.
+ * Deletes all files and directories in the specified filepath recursively.
  *
  * If the specified path is a directory then the function will call itself
  * recursively to process the contents. Once the contents have been removed the
@@ -1336,7 +1390,7 @@
 }
 
 /**
- * Determine total disk space used by a single user or the whole filesystem.
+ * Determines total disk space used by a single user or the whole filesystem.
  *
  * @param $uid
  *   Optional. A user id, specifying NULL returns the total space used by all
@@ -1365,8 +1419,9 @@
  * Temporary files are periodically cleaned. To make the file a permanent file,
  * assign the status and use file_save() to save the changes.
  *
- * @param $source
- *   A string specifying the filepath or URI of the uploaded file to save.
+ * @param $form_field_name
+ *   A string that is the associative array key of the upload form element in
+ *   the form array.
  * @param $validators
  *   An optional, associative array of callback functions used to validate the
  *   file. See file_validate() for a full discussion of the array format.
@@ -1377,9 +1432,9 @@
  *   (Beware: this is not safe and should only be allowed for trusted users, if
  *   at all).
  * @param $destination
- *   A string containing the URI $source should be copied to.
- *   This must be a stream wrapper URI. If this value is omitted, Drupal's
- *   temporary files scheme will be used ("temporary://").
+ *   A string containing the URI that the file should be copied to. This must
+ *   be a stream wrapper URI. If this value is omitted, Drupal's temporary
+ *   files scheme will be used ("temporary://").
  * @param $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE: Replace the existing file.
@@ -1397,45 +1452,45 @@
  *   - source: Path to the file before it is moved.
  *   - destination: Path to the file after it is moved (same as 'uri').
  */
-function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
+function file_save_upload($form_field_name, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
   global $user;
   static $upload_cache;
 
   // Return cached objects without processing since the file will have
   // already been processed and the paths in _FILES will be invalid.
-  if (isset($upload_cache[$source])) {
-    return $upload_cache[$source];
+  if (isset($upload_cache[$form_field_name])) {
+    return $upload_cache[$form_field_name];
   }
 
   // Make sure there's an upload to process.
-  if (empty($_FILES['files']['name'][$source])) {
+  if (empty($_FILES['files']['name'][$form_field_name])) {
     return NULL;
   }
 
   // Check for file upload errors and return FALSE if a lower level system
   // error occurred. For a complete list of errors:
-  // See http://php.net/manual/en/features.file-upload.errors.php.
-  switch ($_FILES['files']['error'][$source]) {
+  // See http://php.net/manual/features.file-upload.errors.php.
+  switch ($_FILES['files']['error'][$form_field_name]) {
     case UPLOAD_ERR_INI_SIZE:
     case UPLOAD_ERR_FORM_SIZE:
-      drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $_FILES['files']['name'][$source], '%maxsize' => format_size(file_upload_max_size()))), 'error');
+      drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $_FILES['files']['name'][$form_field_name], '%maxsize' => format_size(file_upload_max_size()))), 'error');
       return FALSE;
 
     case UPLOAD_ERR_PARTIAL:
     case UPLOAD_ERR_NO_FILE:
-      drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $_FILES['files']['name'][$source])), 'error');
+      drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $_FILES['files']['name'][$form_field_name])), 'error');
       return FALSE;
 
     case UPLOAD_ERR_OK:
       // Final check that this is a valid upload, if it isn't, use the
       // default error handler.
-      if (is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
+      if (is_uploaded_file($_FILES['files']['tmp_name'][$form_field_name])) {
         break;
       }
 
     // Unknown error
     default:
-      drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $_FILES['files']['name'][$source])), 'error');
+      drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $_FILES['files']['name'][$form_field_name])), 'error');
       return FALSE;
   }
 
@@ -1443,10 +1498,10 @@
   $file = new stdClass();
   $file->uid      = $user->uid;
   $file->status   = 0;
-  $file->filename = trim(basename($_FILES['files']['name'][$source]), '.');
-  $file->uri      = $_FILES['files']['tmp_name'][$source];
+  $file->filename = trim(drupal_basename($_FILES['files']['name'][$form_field_name]), '.');
+  $file->uri      = $_FILES['files']['tmp_name'][$form_field_name];
   $file->filemime = file_get_mimetype($file->filename);
-  $file->filesize = $_FILES['files']['size'][$source];
+  $file->filesize = $_FILES['files']['size'][$form_field_name];
 
   $extensions = '';
   if (isset($validators['file_validate_extensions'])) {
@@ -1503,7 +1558,7 @@
     return FALSE;
   }
 
-  $file->source = $source;
+  $file->source = $form_field_name;
   // A URI may already have a trailing slash or look like "public://".
   if (substr($destination, -1) != '/') {
     $destination .= '/';
@@ -1512,11 +1567,11 @@
   // If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
   // there's an existing file so we need to bail.
   if ($file->destination === FALSE) {
-    drupal_set_message(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $source, '%directory' => $destination)), 'error');
+    drupal_set_message(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $form_field_name, '%directory' => $destination)), 'error');
     return FALSE;
   }
 
-  // Add in our check of the the file name length.
+  // Add in our check of the file name length.
   $validators['file_validate_name_length'] = array();
 
   // Call the validation functions specified by this function's caller.
@@ -1531,7 +1586,7 @@
     else {
       $message .= ' ' . array_pop($errors);
     }
-    form_set_error($source, $message);
+    form_set_error($form_field_name, $message);
     return FALSE;
   }
 
@@ -1539,8 +1594,8 @@
   // directory. This overcomes open_basedir restrictions for future file
   // operations.
   $file->uri = $file->destination;
-  if (!drupal_move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
-    form_set_error($source, t('File upload error. Could not move uploaded file.'));
+  if (!drupal_move_uploaded_file($_FILES['files']['tmp_name'][$form_field_name], $file->uri)) {
+    form_set_error($form_field_name, t('File upload error. Could not move uploaded file.'));
     watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));
     return FALSE;
   }
@@ -1559,8 +1614,22 @@
 
   // If we made it this far it's safe to record this file in the database.
   if ($file = file_save($file)) {
+    // Track non-public files in the session if they were uploaded by an
+    // anonymous user. This allows modules such as the File module to only
+    // grant view access to the specific anonymous user who uploaded the file.
+    // See file_file_download().
+    // The 'file_public_schema' variable is used to allow other publicly
+    // accessible file schemes to be treated the same as the public:// scheme
+    // provided by Drupal core and to avoid adding unnecessary data to the
+    // session (and the resulting bypass of the page cache) in those cases. For
+    // security reasons, only schemes that are completely publicly accessible,
+    // with no download restrictions, should be added to this variable. See
+    // file_managed_file_value().
+    if (!$user->uid && !in_array($destination_scheme, variable_get('file_public_schema', array('public')))) {
+      $_SESSION['anonymous_allowed_file_ids'][$file->fid] = $file->fid;
+    }
     // Add file to the cache.
-    $upload_cache[$source] = $file;
+    $upload_cache[$form_field_name] = $file;
     return $file;
   }
   return FALSE;
@@ -1573,7 +1642,6 @@
  * or open_basedir are enabled, so this function fills that gap.
  *
  * Compatibility: normal paths and stream wrappers.
- * @see http://drupal.org/node/515192
  *
  * @param $filename
  *   The filename of the uploaded file.
@@ -1584,6 +1652,7 @@
  *   TRUE on success, or FALSE on failure.
  *
  * @see move_uploaded_file()
+ * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
  */
 function drupal_move_uploaded_file($filename, $uri) {
@@ -1604,7 +1673,7 @@
 }
 
 /**
- * Check that a file meets the criteria specified by the validators.
+ * Checks that a file meets the criteria specified by the validators.
  *
  * After executing the validator callbacks specified hook_file_validate() will
  * also be called to allow other modules to report errors about the file.
@@ -1639,10 +1708,11 @@
 }
 
 /**
- * Check for files with names longer than we can store in the database.
+ * Checks for files with names longer than we can store in the database.
  *
  * @param $file
  *   A Drupal file object.
+ *
  * @return
  *   An array. If the file name is too long, it will contain an error message.
  */
@@ -1659,7 +1729,7 @@
 }
 
 /**
- * Check that the filename ends with an allowed extension.
+ * Checks that the filename ends with an allowed extension.
  *
  * @param $file
  *   A Drupal file object.
@@ -1683,9 +1753,7 @@
 }
 
 /**
- * Check that the file's size is below certain limits.
- *
- * This check is not enforced for the user #1.
+ * Checks that the file's size is below certain limits.
  *
  * @param $file
  *   A Drupal file object.
@@ -1704,25 +1772,22 @@
  */
 function file_validate_size(stdClass $file, $file_limit = 0, $user_limit = 0) {
   global $user;
-
   $errors = array();
 
-  // Bypass validation for uid  = 1.
-  if ($user->uid != 1) {
-    if ($file_limit && $file->filesize > $file_limit) {
-      $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
-    }
+  if ($file_limit && $file->filesize > $file_limit) {
+    $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
+  }
 
-    // Save a query by only calling file_space_used() when a limit is provided.
-    if ($user_limit && (file_space_used($user->uid) + $file->filesize) > $user_limit) {
-      $errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit)));
-    }
+  // Save a query by only calling file_space_used() when a limit is provided.
+  if ($user_limit && (file_space_used($user->uid) + $file->filesize) > $user_limit) {
+    $errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit)));
   }
+
   return $errors;
 }
 
 /**
- * Check that the file is recognized by image_get_info() as an image.
+ * Checks that the file is recognized by image_get_info() as an image.
  *
  * @param $file
  *   A Drupal file object.
@@ -1744,9 +1809,9 @@
 }
 
 /**
- * Verify that image dimensions are within the specified maximum and minimum.
+ * Verifies that image dimensions are within the specified maximum and minimum.
  *
- * Non-image files will be ignored. If a image toolkit is available the image
+ * Non-image files will be ignored. If an image toolkit is available the image
  * will be scaled to fit within the desired maximum dimensions.
  *
  * @param $file
@@ -1802,7 +1867,7 @@
 }
 
 /**
- * Save a string to the specified destination and create a database file entry.
+ * Saves a file to the specified destination and creates a database entry.
  *
  * @param $data
  *   A string containing the contents of the file.
@@ -1841,7 +1906,7 @@
     $file = new stdClass();
     $file->fid = NULL;
     $file->uri = $uri;
-    $file->filename = basename($uri);
+    $file->filename = drupal_basename($uri);
     $file->filemime = file_get_mimetype($file->uri);
     $file->uid      = $user->uid;
     $file->status   = FILE_STATUS_PERMANENT;
@@ -1857,7 +1922,7 @@
     // If we are renaming around an existing file (rather than a directory),
     // use its basename for the filename.
     elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
-      $file->filename = basename($destination);
+      $file->filename = drupal_basename($destination);
     }
 
     return file_save($file);
@@ -1866,7 +1931,7 @@
 }
 
 /**
- * Save a string to the specified destination without invoking file API.
+ * Saves a string to the specified destination without invoking file API.
  *
  * This function is identical to file_save_data() except the file will not be
  * saved to the {file_managed} table and none of the file_* hooks will be
@@ -1877,7 +1942,8 @@
  * @param $destination
  *   A string containing the destination location. This must be a stream wrapper
  *   URI. If no value is provided, a randomized name will be generated and the
- *   file will be saved using Drupal's default files scheme, usually "public://".
+ *   file will be saved using Drupal's default files scheme, usually
+ *   "public://".
  * @param $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
@@ -1903,7 +1969,7 @@
 }
 
 /**
- * Transfer file using HTTP to client.
+ * Transfers a file to the client using HTTP.
  *
  * Pipes a file through Drupal to the client.
  *
@@ -1945,7 +2011,7 @@
  * exists but no modules responded drupal_access_denied() will be returned.
  * If the file does not exist drupal_not_found() will be returned.
  *
- * @see hook_file_download()
+ * @see system_menu()
  */
 function file_download() {
   // Merge remainder of arguments from GET['q'], into relative file path.
@@ -1954,29 +2020,81 @@
   $target = implode('/', $args);
   $uri = $scheme . '://' . $target;
   if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
-    // Let other modules provide headers and controls access to the file.
-    // module_invoke_all() uses array_merge_recursive() which merges header
-    // values into a new array. To avoid that and allow modules to override
-    // headers instead, use array_merge() to merge the returned arrays.
-    $headers = array();
-    foreach (module_implements('file_download') as $module) {
-      $function = $module . '_file_download';
-      $result = $function($uri);
-      if ($result == -1) {
-        return drupal_access_denied();
-      }
-      if (isset($result) && is_array($result)) {
-        $headers = array_merge($headers, $result);
-      }
-    }
+    $headers = file_download_headers($uri);
     if (count($headers)) {
       file_transfer($uri, $headers);
     }
-    return drupal_access_denied();
+    drupal_access_denied();
+  }
+  else {
+    drupal_not_found();
   }
-  return drupal_not_found();
+  drupal_exit();
 }
 
+/**
+ * Retrieves headers for a private file download.
+ *
+ * Calls all module implementations of hook_file_download() to retrieve headers
+ * for files by the module that originally provided the file. The presence of
+ * returned headers indicates the current user has access to the file.
+ *
+ * @param $uri
+ *   The URI for the file whose headers should be retrieved.
+ *
+ * @return
+ *   If access is allowed, headers for the file, suitable for passing to
+ *   file_transfer(). If access is not allowed, an empty array will be returned.
+ *
+ * @see file_transfer()
+ * @see file_download_access()
+ * @see hook_file_download()
+ */
+function file_download_headers($uri) {
+  // Let other modules provide headers and control access to the file.
+  // module_invoke_all() uses array_merge_recursive() which merges header
+  // values into a new array. To avoid that and allow modules to override
+  // headers instead, use array_merge() to merge the returned arrays.
+  $headers = array();
+  foreach (module_implements('file_download') as $module) {
+    $function = $module . '_file_download';
+    $result = $function($uri);
+    if ($result == -1) {
+      // Throw away the headers received so far.
+      $headers = array();
+      break;
+    }
+    if (isset($result) && is_array($result)) {
+      $headers = array_merge($headers, $result);
+    }
+  }
+  return $headers;
+}
+
+/**
+ * Checks that the current user has access to a particular file.
+ *
+ * The return value of this function hinges on the return value from
+ * file_download_headers(), which is the function responsible for collecting
+ * access information through hook_file_download().
+ *
+ * If immediately transferring the file to the browser and the headers will
+ * need to be retrieved, the return value of file_download_headers() should be
+ * used to determine access directly, so that access checks will not be run
+ * twice.
+ *
+ * @param $uri
+ *   The URI for the file whose access should be retrieved.
+ *
+ * @return
+ *   Boolean TRUE if access is allowed. FALSE if access is not allowed.
+ *
+ * @see file_download_headers()
+ * @see hook_file_download()
+ */
+function file_download_access($uri) {
+  return count(file_download_headers($uri)) > 0;
+}
 
 /**
  * Finds all files that match a given mask in a given directory.
@@ -2055,7 +2173,7 @@
 }
 
 /**
- * Determine the maximum file upload size by querying the PHP settings.
+ * Determines the maximum file upload size by querying the PHP settings.
  *
  * @return
  *   A file size limit in bytes based on the PHP upload_max_filesize and
@@ -2079,7 +2197,7 @@
 }
 
 /**
- * Determine an Internet Media Type, or MIME type from a filename.
+ * Determines an Internet Media Type or MIME type from a filename.
  *
  * @param $uri
  *   A string containing the URI, path, or filename.
@@ -2108,7 +2226,7 @@
 }
 
 /**
- * Set the permissions on a file or directory.
+ * Sets the permissions on a file or directory.
  *
  * This function will use the 'file_chmod_directory' and 'file_chmod_file'
  * variables for the default modes for directories and uploaded/generated
@@ -2170,7 +2288,7 @@
  * @param $uri
  *   A URI or pathname.
  * @param $context
- *   Refer to http://php.net/manual/en/ref.stream.php
+ *   Refer to http://php.net/manual/ref.stream.php
  *
  * @return
  *   Boolean TRUE on success, or FALSE on failure.
@@ -2192,32 +2310,25 @@
 }
 
 /**
- * Returns the absolute local filesystem path of a stream URI.
+ * Resolves the absolute filepath of a local URI or filepath.
  *
- * This function was originally written to ease the conversion of 6.x code to
- * use 7.x stream wrappers. However, it assumes that every URI may be resolved
- * to an absolute local filesystem path, and this assumption fails when stream
- * wrappers are used to support remote file storage. Remote stream wrappers
- * may implement the realpath method by always returning FALSE. The use of
- * drupal_realpath() is discouraged, and is slowly being removed from core
- * functions where possible.
+ * The use of drupal_realpath() is discouraged, because it does not work for
+ * remote URIs. Except in rare cases, URIs should not be manually resolved.
  *
  * Only use this function if you know that the stream wrapper in the URI uses
  * the local file system, and you need to pass an absolute path to a function
  * that is incompatible with stream URIs.
  *
- * @param $uri
- *   A stream wrapper URI or a filesystem path, possibly including one or more
- *   symbolic links.
+ * @param string $uri
+ *   A stream wrapper URI or a filepath, possibly including one or more symbolic
+ *   links.
  *
- * @return
- *   The absolute local filesystem path (with no symbolic links), or FALSE on
- *   failure.
+ * @return string|false
+ *   The absolute local filepath (with no symbolic links), or FALSE on failure.
  *
  * @see DrupalStreamWrapperInterface::realpath()
  * @see http://php.net/manual/function.realpath.php
  * @ingroup php_wrappers
- * @todo: This function is deprecated, and should be removed wherever possible.
  */
 function drupal_realpath($uri) {
   // If this URI is a stream, pass it off to the appropriate stream wrapper.
@@ -2226,7 +2337,7 @@
   if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
     return $wrapper->realpath();
   }
-  // Check that the uri has a value. There is a bug in PHP 5.2 on *BSD systems
+  // Check that the URI has a value. There is a bug in PHP 5.2 on *BSD systems
   // that makes realpath not return FALSE as expected when passing an empty
   // variable.
   // @todo Remove when Drupal drops support for PHP 5.2.
@@ -2244,7 +2355,6 @@
  * PHP's dirname() as a fallback.
  *
  * Compatibility: normal paths and stream wrappers.
- * @see http://drupal.org/node/515192
  *
  * @param $uri
  *   A URI or path.
@@ -2253,6 +2363,7 @@
  *   A string containing the directory name.
  *
  * @see dirname()
+ * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
  */
 function drupal_dirname($uri) {
@@ -2267,13 +2378,41 @@
 }
 
 /**
+ * Gets the filename from a given path.
+ *
+ * PHP's basename() does not properly support streams or filenames beginning
+ * with a non-US-ASCII character.
+ *
+ * @see http://bugs.php.net/bug.php?id=37738
+ * @see basename()
+ *
+ * @ingroup php_wrappers
+ */
+function drupal_basename($uri, $suffix = NULL) {
+  $separators = '/';
+  if (DIRECTORY_SEPARATOR != '/') {
+    // For Windows OS add special separator.
+    $separators .= DIRECTORY_SEPARATOR;
+  }
+  // Remove right-most slashes when $uri points to directory.
+  $uri = rtrim($uri, $separators);
+  // Returns the trailing part of the $uri starting after one of the directory
+  // separators.
+  $filename = preg_match('@[^' . preg_quote($separators, '@') . ']+$@', $uri, $matches) ? $matches[0] : '';
+  // Cuts off a suffix from the filename.
+  if ($suffix) {
+    $filename = preg_replace('@' . preg_quote($suffix, '@') . '$@', '', $filename);
+  }
+  return $filename;
+}
+
+/**
  * Creates a directory using Drupal's default mode.
  *
  * PHP's mkdir() does not respect Drupal's default permissions mode. If a mode
  * is not provided, this function will make sure that Drupal's is used.
  *
  * Compatibility: normal paths and stream wrappers.
- * @see http://drupal.org/node/515192
  *
  * @param $uri
  *   A URI or pathname.
@@ -2282,12 +2421,13 @@
  * @param $recursive
  *   Default to FALSE.
  * @param $context
- *   Refer to http://php.net/manual/en/ref.stream.php
+ *   Refer to http://php.net/manual/ref.stream.php
  *
  * @return
  *   Boolean TRUE on success, or FALSE on failure.
  *
  * @see mkdir()
+ * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
  */
 function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) {
@@ -2304,7 +2444,7 @@
 }
 
 /**
- * Remove a directory.
+ * Removes a directory.
  *
  * PHP's rmdir() is broken on Windows, as it can fail to remove a directory
  * when it has a read-only flag set.
@@ -2312,7 +2452,7 @@
  * @param $uri
  *   A URI or pathname.
  * @param $context
- *   Refer to http://php.net/manual/en/ref.stream.php
+ *   Refer to http://php.net/manual/ref.stream.php
  *
  * @return
  *   Boolean TRUE on success, or FALSE on failure.
@@ -2341,7 +2481,6 @@
  * given a filepath.
  *
  * Compatibility: normal paths and stream wrappers.
- * @see http://drupal.org/node/515192
  *
  * @param $directory
  *   The directory where the temporary filename will be created.
@@ -2353,6 +2492,7 @@
  *   The new temporary filename, or FALSE on failure.
  *
  * @see tempnam()
+ * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
  */
 function drupal_tempnam($directory, $prefix) {
@@ -2362,7 +2502,7 @@
     $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
 
     if ($filename = tempnam($wrapper->getDirectoryPath(), $prefix)) {
-      return $scheme . '://' . basename($filename);
+      return $scheme . '://' . drupal_basename($filename);
     }
     else {
       return FALSE;
@@ -2375,7 +2515,7 @@
 }
 
 /**
- * Get the path of system-appropriate temporary directory.
+ * Gets the path of system-appropriate temporary directory.
  */
 function file_directory_temp() {
   $temporary_directory = variable_get('file_temporary_path', NULL);
@@ -2432,26 +2572,16 @@
  *
  * @param $file
  *   A file object.
+ *
  * @return
  *   An associative array of headers, as expected by file_transfer().
  */
 function file_get_content_headers($file) {
-  $name = mime_header_encode($file->filename);
   $type = mime_header_encode($file->filemime);
-  // Serve images, text, and flash content for display rather than download.
-  $inline_types = variable_get('file_inline_types', array('^text/', '^image/', 'flash$'));
-  $disposition = 'attachment';
-  foreach ($inline_types as $inline_type) {
-    // Exclamation marks are used as delimiters to avoid escaping slashes.
-    if (preg_match('!' . $inline_type . '!', $file->filemime)) {
-      $disposition = 'inline';
-    }
-  }
 
   return array(
-    'Content-Type' => $type . '; name="' . $name . '"',
+    'Content-Type' => $type,
     'Content-Length' => $file->filesize,
-    'Content-Disposition' => $disposition . '; filename="' . $name . '"',
     'Cache-Control' => 'private',
   );
 }
diff -Naur drupal-7.9/includes/file.mimetypes.inc drupal-7.58/includes/file.mimetypes.inc
--- drupal-7.9/includes/file.mimetypes.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/file.mimetypes.inc	2018-03-27 21:28:19.000000000 +0200
@@ -43,6 +43,7 @@
       4 => 'application/cap',
       5 => 'application/cu-seeme',
       6 => 'application/dsptype',
+      350 => 'application/epub+zip',
       7 => 'application/hta',
       8 => 'application/java-archive',
       9 => 'application/java-serialized-object',
@@ -64,6 +65,7 @@
       25 => 'application/rss+xml',
       26 => 'application/rtf',
       27 => 'application/smil',
+      349 => 'application/vnd.amazon.ebook',
       28 => 'application/vnd.cinderella',
       29 => 'application/vnd.google-earth.kml+xml',
       30 => 'application/vnd.google-earth.kmz',
@@ -183,6 +185,8 @@
       144 => 'application/x-lzx',
       145 => 'application/x-maker',
       146 => 'application/x-mif',
+      351 => 'application/x-mobipocket-ebook',
+      352 => 'application/x-mobipocket-ebook',
       147 => 'application/x-ms-wmd',
       148 => 'application/x-ms-wmz',
       149 => 'application/x-msdos-program',
@@ -228,8 +232,10 @@
       188 => 'audio/mpeg',
       189 => 'audio/ogg',
       190 => 'audio/prs.sid',
+      356 => 'audio/webm',
       191 => 'audio/x-aiff',
       192 => 'audio/x-gsm',
+      354 => 'audio/x-matroska',
       193 => 'audio/x-mpegurl',
       194 => 'audio/x-ms-wax',
       195 => 'audio/x-ms-wma',
@@ -301,6 +307,7 @@
       261 => 'image/vnd.djvu',
       262 => 'image/vnd.microsoft.icon',
       263 => 'image/vnd.wap.wbmp',
+      355 => 'image/webp',
       264 => 'image/x-cmu-raster',
       265 => 'image/x-coreldraw',
       266 => 'image/x-coreldrawpattern',
@@ -337,6 +344,7 @@
       297 => 'text/vnd.sun.j2me.app-descriptor',
       298 => 'text/vnd.wap.wml',
       299 => 'text/vnd.wap.wmlscript',
+      358 => 'text/vtt',
       300 => 'text/x-bibtex',
       301 => 'text/x-boo',
       302 => 'text/x-c++hdr',
@@ -371,9 +379,11 @@
       331 => 'video/ogg',
       332 => 'video/quicktime',
       333 => 'video/vnd.mpegurl',
+      357 => 'video/webm',
       347 => 'video/x-flv',
       334 => 'video/x-la-asf',
       348 => 'video/x-m4v',
+      353 => 'video/x-matroska',
       335 => 'video/x-mng',
       336 => 'video/x-ms-asf',
       337 => 'video/x-ms-wm',
@@ -854,6 +864,16 @@
       'f4b' => 346,
       'flv' => 347,
       'm4v' => 348,
+      'azw' => 349,
+      'epub' => 350,
+      'mobi' => 351,
+      'prc' => 352,
+      'mkv' => 353,
+      'mka' => 354,
+      'webp' => 355,
+      'weba' => 356,
+      'webm' => 357,
+      'vtt' => 358,
     ),
   );
 }
diff -Naur drupal-7.9/includes/filetransfer/filetransfer.inc drupal-7.58/includes/filetransfer/filetransfer.inc
--- drupal-7.9/includes/filetransfer/filetransfer.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/filetransfer/filetransfer.inc	2018-03-27 21:28:19.000000000 +0200
@@ -211,7 +211,7 @@
    */
   protected function copyDirectoryJailed($source, $destination) {
     if ($this->isDirectory($destination)) {
-      $destination = $destination . '/' . basename($source);
+      $destination = $destination . '/' . drupal_basename($source);
     }
     $this->createDirectory($destination);
     foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
@@ -302,9 +302,9 @@
     $chroot = '';
     while (count($parts)) {
       $check = implode($parts, '/');
-      if ($this->isFile($check . '/' . basename(__FILE__))) {
+      if ($this->isFile($check . '/' . drupal_basename(__FILE__))) {
         // Remove the trailing slash.
-        return substr($chroot,0,-1);
+        return substr($chroot, 0, -1);
       }
       $chroot .= array_shift($parts) . '/';
     }
@@ -381,7 +381,7 @@
    * @param string $path
    *   Path to change permissions of.
    * @param long $mode
-   *   @see http://php.net/chmod
+   *   The new file permission mode to be passed to chmod().
    * @param boolean $recursive
    *   Pass TRUE to recursively chmod the entire directory specified in $path.
    */
@@ -406,10 +406,20 @@
    */
   function __construct($path) {
     parent::__construct($path);
+    $this->skipdots();
+  }
+
+  function rewind() {
+    parent::rewind();
+    $this->skipdots();
   }
 
   function next() {
     parent::next();
+    $this->skipdots();
+  }
+
+  protected function skipdots() {
     while ($this->isDot()) {
       parent::next();
     }
diff -Naur drupal-7.9/includes/filetransfer/ftp.inc drupal-7.58/includes/filetransfer/ftp.inc
--- drupal-7.9/includes/filetransfer/ftp.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/filetransfer/ftp.inc	2018-03-27 21:28:19.000000000 +0200
@@ -82,11 +82,11 @@
     if (!$list) {
       $list = array();
     }
-    foreach ($list as $item){
+    foreach ($list as $item) {
       if ($item == '.' || $item == '..') {
         continue;
       }
-      if (@ftp_chdir($this->connection, $item)){
+      if (@ftp_chdir($this->connection, $item)) {
         ftp_cdup($this->connection);
         $this->removeDirectory(ftp_pwd($this->connection) . '/' . $item);
       }
@@ -122,7 +122,7 @@
 
   function chmodJailed($path, $mode, $recursive) {
     if (!ftp_chmod($this->connection, $mode, $path)) {
-      throw new FileTransferException("Unable to set permissions on %file", NULL, array ('%file' => $path));
+      throw new FileTransferException("Unable to set permissions on %file", NULL, array('%file' => $path));
     }
     if ($this->isDirectory($path) && $recursive) {
       $filelist = @ftp_nlist($this->connection, $path);
diff -Naur drupal-7.9/includes/filetransfer/ssh.inc drupal-7.58/includes/filetransfer/ssh.inc
--- drupal-7.9/includes/filetransfer/ssh.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/filetransfer/ssh.inc	2018-03-27 21:28:19.000000000 +0200
@@ -72,7 +72,8 @@
         return TRUE;
       }
       return FALSE;
-    } else {
+    }
+    else {
       throw new FileTransferException('Cannot check @path.', NULL, array('@path' => $path));
     }
   }
@@ -85,7 +86,8 @@
         return TRUE;
       }
       return FALSE;
-    } else {
+    }
+    else {
       throw new FileTransferException('Cannot check @path.', NULL, array('@path' => $path));
     }
   }
diff -Naur drupal-7.9/includes/form.inc drupal-7.58/includes/form.inc
--- drupal-7.9/includes/form.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/form.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,4 +1,8 @@
 <?php
+ /**
+ * @file
+ * Functions for form and batch generation and processing.
+ */
 
 /**
  * @defgroup forms Form builder functions
@@ -11,12 +15,11 @@
  * reference the form builder function using \@see. For examples, of this see
  * system_modules_uninstall() or user_pass(), the latter of which has the
  * following in its doxygen documentation:
+ * - \@ingroup forms
+ * - \@see user_pass_validate()
+ * - \@see user_pass_submit()
  *
- * \@ingroup forms
- * \@see user_pass_validate().
- * \@see user_pass_submit().
- *
- * @} End of "defgroup forms".
+ * @}
  */
 
 /**
@@ -74,7 +77,7 @@
  * the elements and properties of the form. For information on the array
  * components and format, and more detailed explanations of the Form API
  * workflow, see the
- * @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html Form API reference @endlink
+ * @link forms_api_reference.html Form API reference @endlink
  * and the
  * @link http://drupal.org/node/37775 Form API documentation section. @endlink
  * In addition, there is a set of Form API tutorials in
@@ -90,7 +93,11 @@
  */
 
 /**
- * Wrapper for drupal_build_form() for use when $form_state is not needed.
+ * Returns a renderable form array for a given form ID.
+ *
+ * This function should be used instead of drupal_build_form() when $form_state
+ * is not needed (i.e., when initially rendering the form) and is often
+ * used as a menu callback.
  *
  * @param $form_id
  *   The unique string identifying the desired form. If a function with that
@@ -98,7 +105,8 @@
  *   generate the same form (or very similar forms) using different $form_ids
  *   can implement hook_forms(), which maps different $form_id values to the
  *   proper form constructor function. Examples may be found in node_forms(),
- *   search_forms(), and user_forms().
+ *   and search_forms(). hook_forms() can also be used to define forms in
+ *   classes.
  * @param ...
  *   Any additional arguments are passed on to the functions called by
  *   drupal_get_form(), including the unique form constructor function. For
@@ -124,7 +132,7 @@
 }
 
 /**
- * Build and process a form based on a form id.
+ * Builds and process a form based on a form id.
  *
  * The form may also be retrieved from the cache if the form was built in a
  * previous page-load. The form is then passed on for processing, validation
@@ -136,7 +144,7 @@
  *   generate the same form (or very similar forms) using different $form_ids
  *   can implement hook_forms(), which maps different $form_id values to the
  *   proper form constructor function. Examples may be found in node_forms(),
- *   search_forms(), and user_forms().
+ *   and search_forms().
  * @param $form_state
  *   An array which stores information about the form. This is passed as a
  *   reference so that the caller can use it to examine what in the form changed
@@ -156,6 +164,16 @@
  *       automatically loaded by form_get_cache(). By default the current menu
  *       router item's 'file' definition is added, if any. Use
  *       form_load_include() to add include files from a form constructor.
+ *     - form_id: Identification of the primary form being constructed and
+ *       processed.
+ *     - base_form_id: Identification for a base form, as declared in a
+ *       hook_forms() implementation.
+ *     - immutable: If this flag is set to TRUE, a new form build id is
+ *       generated when the form is loaded from the cache. If it is subsequently
+ *       saved to the cache again, it will have another cache id and therefore
+ *       the original form and form-state will remain unaltered. This is
+ *       important when page caching is enabled in order to prevent form state
+ *       from leaking between anonymous users.
  *   - rebuild_info: Internal. Similar to 'build_info', but pertaining to
  *     drupal_rebuild_form().
  *   - rebuild: Normally, after the entire form processing is completed and
@@ -203,17 +221,15 @@
  *     set.
  *   - 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
- *     @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7#tree #tree @endlink
- *     determines whether the values are a flat array or an array whose structure
- *     parallels the $form array.)
- *   - input: The array of values as they were submitted by the user. These are
- *     raw and unvalidated, so should not be used without a thorough
- *     understanding of security implications. In almost all cases, code should
- *     use the data in the 'values' array exclusively. The most common use of
- *     this key is for multi-step forms that need to clear some of the user
- *     input when setting 'rebuild'. The values correspond to $_POST or $_GET,
- *     depending on the 'method' chosen.
+ *     their decision making. (Note that #tree determines whether the values are
+ *     a flat array or an array whose structure parallels the $form array. See
+ *     @link forms_api_reference.html Form API reference @endlink for more
+ *     information.) These are raw and unvalidated, so should not be used
+ *     without a thorough understanding of security implications. In almost all
+ *     cases, code should use the data in the 'values' array exclusively. The
+ *     most common use of this key is for multi-step forms that need to clear
+ *     some of the user input when setting 'rebuild'. The values correspond to
+ *     $_POST or $_GET, depending on the 'method' chosen.
  *   - always_process: If TRUE and the method is GET, a form_id is not
  *     necessary. This should only be used on RESTful GET forms that do NOT
  *     write data, as this could lead to security issues. It is useful so that
@@ -225,6 +241,12 @@
  *     likely to occur during Ajax operations.
  *   - programmed: If TRUE, the form was submitted programmatically, usually
  *     invoked via drupal_form_submit(). Defaults to FALSE.
+ *   - programmed_bypass_access_check: If TRUE, programmatic form submissions
+ *     are processed without taking #access into account. Set this to FALSE
+ *     when submitting a form programmatically with values that may have been
+ *     input by the user executing the current request; this will cause #access
+ *     to be respected as it would on a normal form submission. Defaults to
+ *     TRUE.
  *   - process_input: Boolean flag. TRUE signifies correct form submission.
  *     This is always TRUE for programmed forms coming from drupal_form_submit()
  *     (see 'programmed' key), or if the form_id coming from the $_POST data is
@@ -375,7 +397,7 @@
 }
 
 /**
- * Retrieve default values for the $form_state array.
+ * Retrieves default values for the $form_state array.
  */
 function form_state_defaults() {
   return array(
@@ -392,6 +414,7 @@
     'submitted' => FALSE,
     'executed' => FALSE,
     'programmed' => FALSE,
+    'programmed_bypass_access_check' => TRUE,
     'cache'=> FALSE,
     'method' => 'post',
     'groups' => array(),
@@ -420,7 +443,7 @@
  *   Modules that need to generate the same form (or very similar forms)
  *   using different $form_ids can implement hook_forms(), which maps
  *   different $form_id values to the proper form constructor function. Examples
- *   may be found in node_forms(), search_forms(), and user_forms().
+ *   may be found in node_forms() and search_forms().
  * @param $form_state
  *   A keyed array containing the current state of the form.
  * @param $old_form
@@ -442,17 +465,25 @@
   $form = drupal_retrieve_form($form_id, $form_state);
 
   // If only parts of the form will be returned to the browser (e.g., Ajax or
-  // RIA clients), re-use the old #build_id to not require client-side code to
-  // manually update the hidden 'build_id' input element.
+  // RIA clients), or if the form already had a new build ID regenerated when it
+  // was retrieved from the form cache, reuse the existing #build_id.
   // Otherwise, a new #build_id is generated, to not clobber the previous
   // build's data in the form cache; also allowing the user to go back to an
   // earlier build, make changes, and re-submit.
   // @see drupal_prepare_form()
-  if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) {
+  $enforce_old_build_id = isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id']);
+  $old_form_is_mutable_copy = isset($old_form['#build_id_old']);
+  if ($enforce_old_build_id || $old_form_is_mutable_copy) {
     $form['#build_id'] = $old_form['#build_id'];
+    if ($old_form_is_mutable_copy) {
+      $form['#build_id_old'] = $old_form['#build_id_old'];
+    }
   }
   else {
-    $form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
+    if (isset($old_form['#build_id'])) {
+      $form['#build_id_old'] = $old_form['#build_id'];
+    }
+    $form['#build_id'] = 'form-' . drupal_random_key();
   }
 
   // #action defaults to request_uri(), but in case of Ajax and other partial
@@ -481,7 +512,7 @@
 }
 
 /**
- * Fetch a form from cache.
+ * Fetches a form from cache.
  */
 function form_get_cache($form_build_id, &$form_state) {
   if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) {
@@ -506,27 +537,49 @@
           }
         }
       }
+      // Generate a new #build_id if the cached form was rendered on a cacheable
+      // page.
+      if (!empty($form_state['build_info']['immutable'])) {
+        $form['#build_id_old'] = $form['#build_id'];
+        $form['#build_id'] = 'form-' . drupal_random_key();
+        $form['form_build_id']['#value'] = $form['#build_id'];
+        $form['form_build_id']['#id'] = $form['#build_id'];
+        unset($form_state['build_info']['immutable']);
+      }
       return $form;
     }
   }
 }
 
 /**
- * Store a form in the cache.
+ * Stores a form in the cache.
  */
 function form_set_cache($form_build_id, $form, $form_state) {
   // 6 hours cache life time for forms should be plenty.
   $expire = 21600;
 
+  // Ensure that the form build_id embedded in the form structure is the same as
+  // the one passed in as a parameter. This is an additional safety measure to
+  // prevent legacy code operating directly with form_get_cache and
+  // form_set_cache from accidentally overwriting immutable form state.
+  if ($form['#build_id'] != $form_build_id) {
+    watchdog('form', 'Form build-id mismatch detected while attempting to store a form in the cache.', array(), WATCHDOG_ERROR);
+    return;
+  }
+
   // Cache form structure.
   if (isset($form)) {
     if ($GLOBALS['user']->uid) {
       $form['#cache_token'] = drupal_get_token();
     }
+    unset($form['#build_id_old']);
     cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire);
   }
 
   // Cache form state.
+  if (variable_get('cache', 0) && drupal_page_is_cacheable()) {
+    $form_state['build_info']['immutable'] = TRUE;
+  }
   if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) {
     cache_set('form_state_' . $form_build_id, $data, 'cache_form', REQUEST_TIME + $expire);
   }
@@ -562,7 +615,7 @@
 }
 
 /**
- * Loads an include file and makes sure it is loaded whenever the form is processed.
+ * Ensures an include file is loaded whenever the form is processed.
  *
  * Example:
  * @code
@@ -626,7 +679,7 @@
  *   Modules that need to generate the same form (or very similar forms)
  *   using different $form_ids can implement hook_forms(), which maps
  *   different $form_id values to the proper form constructor function. Examples
- *   may be found in node_forms(), search_forms(), and user_forms().
+ *   may be found in node_forms() and search_forms().
  * @param $form_state
  *   A keyed array containing the current state of the form. Most important is
  *   the $form_state['values'] collection, a tree of data used to simulate the
@@ -711,11 +764,15 @@
 function drupal_retrieve_form($form_id, &$form_state) {
   $forms = &drupal_static(__FUNCTION__);
 
+  // Record the $form_id.
+  $form_state['build_info']['form_id'] = $form_id;
+
   // Record the filepath of the include file containing the original form, so
   // the form builder callbacks can be loaded when the form is being rebuilt
   // from cache on a different path (such as 'system/ajax'). See
-  // form_get_cache().
-  // $menu_get_item() is not available at installation time.
+  // form_get_cache(). Don't do this in maintenance mode as Drupal may not be
+  // fully bootstrapped (i.e. during installation) in which case
+  // menu_get_item() is not available.
   if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
     $item = menu_get_item();
     if (!empty($item['include_file'])) {
@@ -753,7 +810,7 @@
     }
     if (isset($form_definition['callback'])) {
       $callback = $form_definition['callback'];
-      $form_state['build_info']['base_form_id'] = $callback;
+      $form_state['build_info']['base_form_id'] = isset($form_definition['base_form_id']) ? $form_definition['base_form_id'] : $callback;
     }
     // In case $form_state['wrapper_callback'] is not defined already, we also
     // allow hook_forms() to define one.
@@ -774,7 +831,7 @@
   // the actual form builder function ($callback) expects. This allows for
   // pre-populating a form with common elements for certain forms, such as
   // back/next/save buttons in multi-step form wizards. See drupal_build_form().
-  if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) {
+  if (isset($form_state['wrapper_callback']) && is_callable($form_state['wrapper_callback'])) {
     $form = call_user_func_array($form_state['wrapper_callback'], $args);
     // Put the prepopulated $form into $args.
     $args[0] = $form;
@@ -837,7 +894,10 @@
     // cache when a form is processed, so scenarios that result in
     // the form being built behind the scenes and again for the
     // browser don't increment all the element IDs needlessly.
-    drupal_static_reset('drupal_html_id');
+    if (!form_get_errors()) {
+      // In case of errors, do not break HTML IDs of other forms.
+      drupal_static_reset('drupal_html_id');
+    }
 
     if ($form_state['submitted'] && !form_get_errors() && !$form_state['rebuild']) {
       // Execute form submit handlers.
@@ -879,7 +939,7 @@
         // after the batch is processed.
       }
 
-      // Set a flag to indicate the the form has been processed and executed.
+      // Set a flag to indicate that the form has been processed and executed.
       $form_state['executed'] = TRUE;
 
       // Redirect the form based on values in $form_state.
@@ -928,9 +988,10 @@
 }
 
 /**
- * Prepares a structured form array by adding required elements,
- * executing any hook_form_alter functions, and optionally inserting
- * a validation token to prevent tampering.
+ * Prepares a structured form array.
+ *
+ * Adds required elements, executes any hook_form_alter functions, and
+ * optionally inserts a validation token to prevent tampering.
  *
  * @param $form_id
  *   A unique string identifying the form for validation, submission,
@@ -959,13 +1020,17 @@
   // @see drupal_build_form()
   // @see drupal_rebuild_form()
   if (!isset($form['#build_id'])) {
-    $form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
+    $form['#build_id'] = 'form-' . drupal_random_key();
   }
   $form['form_build_id'] = array(
     '#type' => 'hidden',
     '#value' => $form['#build_id'],
     '#id' => $form['#build_id'],
     '#name' => 'form_build_id',
+    // Form processing and validation requires this value, so ensure the
+    // submitted form value appears literally, regardless of custom #tree
+    // and #parents being set elsewhere.
+    '#parents' => array('form_build_id'),
   );
 
   // Add a token, based on either #token or form_id, to any form displayed to
@@ -989,6 +1054,10 @@
         '#id' => drupal_html_id('edit-' . $form_id . '-form-token'),
         '#type' => 'token',
         '#default_value' => drupal_get_token($form['#token']),
+        // Form processing and validation requires this value, so ensure the
+        // submitted form value appears literally, regardless of custom #tree
+        // and #parents being set elsewhere.
+        '#parents' => array('form_token'),
       );
     }
   }
@@ -998,6 +1067,10 @@
       '#type' => 'hidden',
       '#value' => $form_id,
       '#id' => drupal_html_id("edit-$form_id"),
+      // Form processing and validation requires this value, so ensure the
+      // submitted form value appears literally, regardless of custom #tree
+      // and #parents being set elsewhere.
+      '#parents' => array('form_id'),
     );
   }
   if (!isset($form['#id'])) {
@@ -1056,10 +1129,20 @@
   drupal_alter($hooks, $form, $form_state, $form_id);
 }
 
+/**
+ * Helper function to call form_set_error() if there is a token error.
+ */
+function _drupal_invalid_token_set_form_error() {
+  $path = current_path();
+  $query = drupal_get_query_parameters();
+  $url = url($path, array('query' => $query));
+
+  // Setting this error will cause the form to fail validation.
+  form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
+}
 
 /**
- * Validates user-submitted form data from the $form_state using
- * the validate functions defined in a structured form array.
+ * Validates user-submitted form data in the $form_state array.
  *
  * @param $form_id
  *   A unique string identifying the form for validation, submission,
@@ -1076,7 +1159,7 @@
  *   A keyed array containing the current state of the form. The current
  *   user-submitted data is stored in $form_state['values'], though
  *   form validation functions are passed an explicit copy of the
- *   values for the sake of simplicity. Validation handlers can also
+ *   values for the sake of simplicity. Validation handlers can also use
  *   $form_state to pass information on to submit handlers. For example:
  *     $form_state['data_for_submission'] = $data;
  *   This technique is useful when validation requires file parsing,
@@ -1091,15 +1174,16 @@
   }
 
   // If the session token was set by drupal_prepare_form(), ensure that it
-  // matches the current user's session.
-  if (isset($form['#token'])) {
-    if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) {
-      $path = current_path();
-      $query = drupal_get_query_parameters();
-      $url = url($path, array('query' => $query));
-
-      // Setting this error will cause the form to fail validation.
-      form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
+  // matches the current user's session. This is duplicate to code in
+  // form_builder() but left to protect any custom form handling code.
+  if (!empty($form['#token'])) {
+    if (!drupal_valid_token($form_state['values']['form_token'], $form['#token']) || !empty($form_state['invalid_token'])) {
+      _drupal_invalid_token_set_form_error();
+      // Stop here and don't run any further validation handlers, because they
+      // could invoke non-safe operations which opens the door for CSRF
+      // vulnerabilities.
+      $validated_forms[$form_id] = TRUE;
+      return;
     }
   }
 
@@ -1150,18 +1234,23 @@
 /**
  * Redirects the user to a URL after a form has been processed.
  *
- * After a form was executed, the data in $form_state controls whether the form
- * is redirected. By default, we redirect to a new destination page. The path
- * of the destination page can be set in $form_state['redirect'], as either a
- * string containing the destination or an array of arguments compatible with
- * drupal_goto(). If that is not set, the user is redirected to the current
- * page to display a fresh, unpopulated copy of the form.
+ * After a form is submitted and processed, normally the user should be
+ * redirected to a new destination page. This function figures out what that
+ * destination should be, based on the $form_state array and the 'destination'
+ * query string in the request URL, and redirects the user there.
+ *
+ * Usually (for exceptions, see below) $form_state['redirect'] determines where
+ * to redirect the user. This can be set either to a string (the path to
+ * redirect to), or an array of arguments for drupal_goto(). If
+ * $form_state['redirect'] is missing, the user is usually (again, see below for
+ * exceptions) redirected back to the page they came from, where they should see
+ * a fresh, unpopulated copy of the form.
  *
- * For example, to redirect to 'node':
+ * Here is an example of how to set up a form to redirect to the path 'node':
  * @code
  * $form_state['redirect'] = 'node';
  * @endcode
- * Or to redirect to 'node/123?foo=bar#baz':
+ * And here is an example of how to redirect to 'node/123?foo=bar#baz':
  * @code
  * $form_state['redirect'] = array(
  *   'node/123',
@@ -1174,29 +1263,27 @@
  * );
  * @endcode
  *
- * There are several triggers that may prevent a redirection though:
- * - If $form_state['redirect'] is FALSE, a form builder function or form
- *   validation/submit handler does not want a user to be redirected, which
- *   means that drupal_goto() is not invoked. For most forms, the redirection
- *   logic will be the same regardless of whether $form_state['redirect'] is
- *   undefined or FALSE. However, in case it was not defined and the current
- *   request contains a 'destination' query string, drupal_goto() will redirect
- *   to that given destination instead. Only setting $form_state['redirect'] to
- *   FALSE will prevent any redirection.
- * - If $form_state['no_redirect'] is TRUE, then the callback that originally
- *   built the form explicitly disallows any redirection, regardless of the
- *   redirection value in $form_state['redirect']. For example, ajax_get_form()
- *   defines $form_state['no_redirect'] when building a form in an Ajax
- *   callback to prevent any redirection. $form_state['no_redirect'] should NOT
- *   be altered by form builder functions or form validation/submit handlers.
+ * There are several exceptions to the "usual" behavior described above:
  * - If $form_state['programmed'] is TRUE, the form submission was usually
  *   invoked via drupal_form_submit(), so any redirection would break the script
- *   that invoked drupal_form_submit().
- * - If $form_state['rebuild'] is TRUE, the form needs to be rebuilt without
- *   redirection.
+ *   that invoked drupal_form_submit() and no redirection is done.
+ * - If $form_state['rebuild'] is TRUE, the form is being rebuilt, and no
+ *   redirection is done.
+ * - If $form_state['no_redirect'] is TRUE, redirection is disabled. This is
+ *   set, for instance, by ajax_get_form() to prevent redirection in Ajax
+ *   callbacks. $form_state['no_redirect'] should never be set or altered by
+ *   form builder functions or form validation/submit handlers.
+ * - If $form_state['redirect'] is set to FALSE, redirection is disabled.
+ * - If none of the above conditions has prevented redirection, then the
+ *   redirect is accomplished by calling drupal_goto(), passing in the value of
+ *   $form_state['redirect'] if it is set, or the current path if it is
+ *   not. drupal_goto() preferentially uses the value of $_GET['destination']
+ *   (the 'destination' URL query string) if it is present, so this will
+ *   override any values set by $form_state['redirect']. Note that during
+ *   installation, install_goto() is called in place of drupal_goto().
  *
  * @param $form_state
- *   A keyed array containing the current state of the form.
+ *   An associative array containing the current state of the form.
  *
  * @see drupal_process_form()
  * @see drupal_build_form()
@@ -1228,14 +1315,16 @@
         $function($form_state['redirect']);
       }
     }
-    drupal_goto($_GET['q']);
+    drupal_goto(current_path(), array('query' => drupal_get_query_parameters()));
   }
 }
 
 /**
- * Performs validation on form elements. First ensures required fields are
- * completed, #maxlength is not exceeded, and selected options were in the
- * list of options given to the user. Then calls user-defined validators.
+ * Performs validation on form elements.
+ *
+ * First ensures required fields are completed, #maxlength is not exceeded, and
+ * selected options were in the list of options given to the user. Then calls
+ * user-defined validators.
  *
  * @param $elements
  *   An associative array containing the structure of the form.
@@ -1387,9 +1476,10 @@
 }
 
 /**
- * A helper function used to execute custom validation and submission
- * handlers for a given form. Button-specific handlers are checked
- * first. If none exist, the function falls back to form-level handlers.
+ * Executes custom validation and submission handlers for a given form.
+ *
+ * Button-specific handlers are checked first. If none exist, the function
+ * falls back to form-level handlers.
  *
  * @param $type
  *   The type of handler to execute. 'validate' or 'submit' are the
@@ -1511,8 +1601,6 @@
  * doing anything with that data that requires it to be valid, PHP errors
  * would be triggered if the input processing and validation steps were fully
  * skipped.
- * @see http://drupal.org/node/370537
- * @see http://drupal.org/node/763376
  *
  * @param $name
  *   The name of the form element. If the #parents property of your form
@@ -1528,6 +1616,9 @@
  * @return
  *   Return value is for internal use only. To get a list of errors, use
  *   form_get_errors() or form_get_error().
+ *
+ * @see http://drupal.org/node/370537
+ * @see http://drupal.org/node/763376
  */
 function form_set_error($name = NULL, $message = '', $limit_validation_errors = NULL) {
   $form = &drupal_static(__FUNCTION__, array());
@@ -1573,14 +1664,14 @@
 }
 
 /**
- * Clear all errors against all form elements made by form_set_error().
+ * Clears all errors against all form elements made by form_set_error().
  */
 function form_clear_error() {
   drupal_static_reset('form_set_error');
 }
 
 /**
- * Return an associative array of all errors.
+ * Returns an associative array of all errors.
  */
 function form_get_errors() {
   $form = form_set_error();
@@ -1608,16 +1699,18 @@
 }
 
 /**
- * Flag an element as having an error.
+ * Flags an element as having an error.
  */
 function form_error(&$element, $message = '') {
   form_set_error(implode('][', $element['#parents']), $message);
 }
 
 /**
- * Walk through the structured form array, adding any required properties to
- * each element and mapping the incoming input data to the proper elements.
- * Also, execute any #process handlers attached to a specific element.
+ * Builds and processes all elements in the structured form array.
+ *
+ * Adds any required properties to each element, maps the incoming input data
+ * to the proper elements, and executes any #process handlers attached to a
+ * specific element.
  *
  * This is one of the three primary functions that recursively iterates a form
  * array. This one does it for completing the form building process. The other
@@ -1741,6 +1834,20 @@
     // from the POST data is set and matches the current form_id.
     if ($form_state['programmed'] || (!empty($form_state['input']) && (isset($form_state['input']['form_id']) && ($form_state['input']['form_id'] == $form_id)))) {
       $form_state['process_input'] = TRUE;
+      // If the session token was set by drupal_prepare_form(), ensure that it
+      // matches the current user's session.
+      $form_state['invalid_token'] = FALSE;
+      if (!empty($element['#token'])) {
+        if (empty($form_state['input']['form_token']) || !drupal_valid_token($form_state['input']['form_token'], $element['#token'])) {
+          // Set an early form error to block certain input processing since that
+          // opens the door for CSRF vulnerabilities.
+          _drupal_invalid_token_set_form_error();
+          // This value is checked in _form_builder_handle_input_element().
+          $form_state['invalid_token'] = TRUE;
+          // Make sure file uploads do not get processed.
+          $_FILES = array();
+        }
+      }
     }
     else {
       $form_state['process_input'] = FALSE;
@@ -1844,6 +1951,18 @@
       $element['#attributes']['enctype'] = 'multipart/form-data';
     }
 
+    // Allow Ajax submissions to the form action to bypass verification. This is
+    // especially useful for multipart forms, which cannot be verified via a
+    // response header.
+    $element['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array(
+        'urlIsAjaxTrusted' => array(
+          $element['#action'] => TRUE,
+        ),
+      ),
+    );
+
     // If a form contains a single textfield, and the ENTER key is pressed
     // within it, Internet Explorer submits the form with no POST data
     // identifying any submit button. Other browsers submit POST data as though
@@ -1889,10 +2008,22 @@
 }
 
 /**
- * Populate the #value and #name properties of input elements so they
- * can be processed and rendered.
+ * Adds the #name and #value properties of an input element before rendering.
  */
 function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
+  static $safe_core_value_callbacks = array(
+    'form_type_token_value',
+    'form_type_textarea_value',
+    'form_type_textfield_value',
+    'form_type_checkbox_value',
+    'form_type_checkboxes_value',
+    'form_type_radios_value',
+    'form_type_password_confirm_value',
+    'form_type_select_value',
+    'form_type_tableselect_value',
+    'list_boolean_allowed_values_callback',
+  );
+
   if (!isset($element['#name'])) {
     $name = array_shift($element['#parents']);
     $element['#name'] = $name;
@@ -1942,7 +2073,7 @@
   // #access=FALSE on an element usually allow access for some users, so forms
   // submitted with drupal_form_submit() may bypass access restriction and be
   // treated as high-privilege users instead.
-  $process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
+  $process_input = empty($element['#disabled']) && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
 
   // Set the element's #value property.
   if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
@@ -1971,7 +2102,14 @@
       // property, optionally filtered through $value_callback.
       if ($input_exists) {
         if (function_exists($value_callback)) {
-          $element['#value'] = $value_callback($element, $input, $form_state);
+          // Skip all value callbacks except safe ones like text if the CSRF
+          // token was invalid.
+          if (empty($form_state['invalid_token']) || in_array($value_callback, $safe_core_value_callbacks)) {
+            $element['#value'] = $value_callback($element, $input, $form_state);
+          }
+          else {
+            $input = NULL;
+          }
         }
         if (!isset($element['#value']) && isset($input)) {
           $element['#value'] = $input;
@@ -2029,7 +2167,7 @@
 }
 
 /**
- * Helper function to handle the convoluted logic of button click detection.
+ * Detects if an element triggered the form submission via Ajax.
  *
  * This detects button or non-button controls that trigger a form submission via
  * Ajax or some other scriptable environment. These environments can set the
@@ -2049,7 +2187,7 @@
 }
 
 /**
- * Helper function to handle the convoluted logic of button click detection.
+ * Determines if a given button triggered the form submission.
  *
  * This detects button controls that trigger a form submission by being clicked
  * and having the click processed by the browser rather than being captured by
@@ -2134,17 +2272,17 @@
     // $form_state['values']['foo']['bar'], which is the level where we can
     // unset 'baz' (that is stored in $last_parent).
     $parents = $button['#parents'];
-    $values = &$form_state['values'];
     $last_parent = array_pop($parents);
-    foreach ($parents as $parent) {
-      $values = &$values[$parent];
+    $key_exists = NULL;
+    $values = &drupal_array_get_nested_value($form_state['values'], $parents, $key_exists);
+    if ($key_exists && is_array($values)) {
+      unset($values[$last_parent]);
     }
-    unset($values[$last_parent]);
   }
 }
 
 /**
- * Helper function to determine the value for an image button form element.
+ * Determines the value for an image button form element.
  *
  * @param $form
  *   The form element whose value is being populated.
@@ -2153,6 +2291,7 @@
  *   the element's default value should be returned.
  * @param $form_state
  *   A keyed array containing the current state of the form.
+ *
  * @return
  *   The data that will appear in the $form_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2191,13 +2330,14 @@
 }
 
 /**
- * Helper function to determine the value for a checkbox form element.
+ * Determines the value for a checkbox form element.
  *
  * @param $form
  *   The form element whose value is being populated.
-*  @param $input
+ * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2231,13 +2371,14 @@
 }
 
 /**
- * Helper function to determine the value for a checkboxes form element.
+ * Determines the value for a checkboxes form element.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2271,13 +2412,14 @@
 }
 
 /**
- * Helper function to determine the value for a tableselect form element.
+ * Determines the value for a tableselect form element.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2306,14 +2448,53 @@
 }
 
 /**
- * Helper function to determine the value for a password_confirm form
- * element.
+ * Form value callback: Determines the value for a #type radios form element.
+ *
+ * @param $element
+ *   The form element whose value is being populated.
+ * @param $input
+ *   (optional) The incoming input to populate the form element. If FALSE, the
+ *   element's default value is returned. Defaults to FALSE.
+ *
+ * @return
+ *   The data that will appear in the $element_state['values'] collection for
+ *   this element.
+ */
+function form_type_radios_value(&$element, $input = FALSE) {
+  if ($input !== FALSE) {
+    // When there's user input (including NULL), return it as the value.
+    // However, if NULL is submitted, _form_builder_handle_input_element() will
+    // apply the default value, and we want that validated against #options
+    // unless it's empty. (An empty #default_value, such as NULL or FALSE, can
+    // be used to indicate that no radio button is selected by default.)
+    if (!isset($input) && !empty($element['#default_value'])) {
+      $element['#needs_validation'] = TRUE;
+    }
+    return $input;
+  }
+  else {
+    // For default value handling, simply return #default_value. Additionally,
+    // for a NULL default value, set #has_garbage_value to prevent
+    // _form_builder_handle_input_element() converting the NULL to an empty
+    // string, so that code can distinguish between nothing selected and the
+    // selection of a radio button whose value is an empty string.
+    $value = isset($element['#default_value']) ? $element['#default_value'] : NULL;
+    if (!isset($value)) {
+      $element['#has_garbage_value'] = TRUE;
+    }
+    return $value;
+  }
+}
+
+/**
+ * Determines the value for a password_confirm form element.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2323,16 +2504,28 @@
     $element += array('#default_value' => array());
     return $element['#default_value'] + array('pass1' => '', 'pass2' => '');
   }
+  $value = array('pass1' => '', 'pass2' => '');
+  // Throw out all invalid array keys; we only allow pass1 and pass2.
+  foreach ($value as $allowed_key => $default) {
+    // These should be strings, but allow other scalars since they might be
+    // valid input in programmatic form submissions. Any nested array values
+    // are ignored.
+    if (isset($input[$allowed_key]) && is_scalar($input[$allowed_key])) {
+      $value[$allowed_key] = (string) $input[$allowed_key];
+    }
+  }
+  return $value;
 }
 
 /**
- * Helper function to determine the value for a select form element.
+ * Determines the value for a select form element.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2366,33 +2559,59 @@
 }
 
 /**
- * Helper function to determine the value for a textfield form element.
+ * Determines the value for a textarea form element.
+ *
+ * @param array $element
+ *   The form element whose value is being populated.
+ * @param mixed $input
+ *   The incoming input to populate the form element. If this is FALSE,
+ *   the element's default value should be returned.
+ *
+ * @return string
+ *   The data that will appear in the $element_state['values'] collection
+ *   for this element. Return nothing to use the default.
+ */
+function form_type_textarea_value($element, $input = FALSE) {
+  if ($input !== FALSE && $input !== NULL) {
+    // This should be a string, but allow other scalars since they might be
+    // valid input in programmatic form submissions.
+    return is_scalar($input) ? (string) $input : '';
+  }
+}
+
+/**
+ * Determines the value for a textfield form element.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
  */
 function form_type_textfield_value($element, $input = FALSE) {
   if ($input !== FALSE && $input !== NULL) {
-    // Equate $input to the form value to ensure it's marked for
-    // validation.
-    return str_replace(array("\r", "\n"), '', $input);
+    // This should be a string, but allow other scalars since they might be
+    // valid input in programmatic form submissions.
+    if (!is_scalar($input)) {
+      $input = '';
+    }
+    return str_replace(array("\r", "\n"), '', (string) $input);
   }
 }
 
 /**
- * Helper function to determine the value for form's token value.
+ * Determines the value for form's token value.
  *
  * @param $element
  *   The form element whose value is being populated.
  * @param $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
+ *
  * @return
  *   The data that will appear in the $element_state['values'] collection
  *   for this element. Return nothing to use the default.
@@ -2404,7 +2623,7 @@
 }
 
 /**
- * Changes submitted form values in $form_state.
+ * Changes submitted form values during form validation.
  *
  * Use this function to change the submitted value of a form element in a form
  * validation function, so that the changed value persists in $form_state
@@ -2456,11 +2675,9 @@
 }
 
 /**
- * Helper function for form_options_flatten().
+ * Iterates over an array and returns a flat array with duplicate keys removed.
  *
- * Iterates over arrays which may share common values and produces a flat
- * array that has removed duplicate keys. Also handles cases where objects
- * are passed as array values.
+ * This function also handles cases where objects are passed as array values.
  */
 function _form_options_flatten($array) {
   $return = &drupal_static(__FUNCTION__);
@@ -2498,8 +2715,8 @@
  *   - #required: (optional) Whether the user needs to select an option (TRUE)
  *     or not (FALSE). Defaults to FALSE.
  *   - #empty_option: (optional) The label to show for the first default option.
- *     By default, the label is automatically set to "- Please select -" for a
- *     required field and "- None -" for an optional field.
+ *     By default, the label is automatically set to "- Select -" for a required
+ *     field and "- None -" for an optional field.
  *   - #empty_value: (optional) The value for the first default option, which is
  *     used to determine whether the user submitted a value or not.
  *     - If #required is TRUE, this defaults to '' (an empty string).
@@ -2570,16 +2787,43 @@
 }
 
 /**
- * Converts a select form element's options array into an HTML.
+ * Converts an array of options into HTML, for use in select list form elements.
  *
- * @param $element
- *   An associative array containing the properties of the element.
- * @param $choices
- *   Mixed: Either an associative array of items to list as choices, or an
- *   object with an 'option' member that is an associative array. This
- *   parameter is only used internally and should not be passed.
- * @return
- *   An HTML string of options for the select form element.
+ * This function calls itself recursively to obtain the values for each optgroup
+ * within the list of options and when the function encounters an object with
+ * an 'options' property inside $element['#options'].
+ *
+ * @param array $element
+ *   An associative array containing the following key-value pairs:
+ *   - #multiple: Optional Boolean indicating if the user may select more than
+ *     one item.
+ *   - #options: An associative array of options to render as HTML. Each array
+ *     value can be a string, an array, or an object with an 'option' property:
+ *     - A string or integer key whose value is a translated string is
+ *       interpreted as a single HTML option element. Do not use placeholders
+ *       that sanitize data: doing so will lead to double-escaping. Note that
+ *       the key will be visible in the HTML and could be modified by malicious
+ *       users, so don't put sensitive information in it.
+ *     - A translated string key whose value is an array indicates a group of
+ *       options. The translated string is used as the label attribute for the
+ *       optgroup. Do not use placeholders to sanitize data: doing so will lead
+ *       to double-escaping. The array should contain the options you wish to
+ *       group and should follow the syntax of $element['#options'].
+ *     - If the function encounters a string or integer key whose value is an
+ *       object with an 'option' property, the key is ignored, the contents of
+ *       the option property are interpreted as $element['#options'], and the
+ *       resulting HTML is added to the output.
+ *   - #value: Optional integer, string, or array representing which option(s)
+ *     to pre-select when the list is first displayed. The integer or string
+ *     must match the key of an option in the '#options' list. If '#multiple' is
+ *     TRUE, this can be an array of integers or strings.
+ * @param array|null $choices
+ *   (optional) Either an associative array of options in the same format as
+ *   $element['#options'] above, or NULL. This parameter is only used internally
+ *   and is not intended to be passed in to the initial function call.
+ *
+ * @return string
+ *   An HTML string of options and optgroups for use in a select form element.
  */
 function form_select_options($element, $choices = NULL) {
   if (!isset($choices)) {
@@ -2592,7 +2836,7 @@
   $options = '';
   foreach ($choices as $key => $choice) {
     if (is_array($choice)) {
-      $options .= '<optgroup label="' . $key . '">';
+      $options .= '<optgroup label="' . check_plain($key) . '">';
       $options .= form_select_options($element, $choice);
       $options .= '</optgroup>';
     }
@@ -2614,8 +2858,7 @@
 }
 
 /**
- * Traverses a select element's #option array looking for any values
- * that hold the given key. Returns an array of indexes that match.
+ * Returns the indexes of a select element's options matching a given key.
  *
  * This function is useful if you need to modify the options that are
  * already in a form element; for example, to remove choices which are
@@ -2641,6 +2884,7 @@
  *   The select element to search.
  * @param $key
  *   The key to look for.
+ *
  * @return
  *   An array of indexes that match the given $key. Array will be
  *   empty if no elements were found. FALSE if optgroups were found.
@@ -2745,6 +2989,9 @@
   if (!empty($element['#attributes']['class'])) {
     $attributes['class'] .= ' ' . implode(' ', $element['#attributes']['class']);
   }
+  if (isset($element['#attributes']['title'])) {
+    $attributes['title'] = $element['#attributes']['title'];
+  }
   return '<div' . drupal_attributes($attributes) . '>' . (!empty($element['#children']) ? $element['#children'] : '') . '</div>';
 }
 
@@ -2777,12 +3024,12 @@
 }
 
 /**
- * Validate password_confirm element.
+ * Validates a password_confirm element.
  */
 function password_confirm_validate($element, &$element_state) {
   $pass1 = trim($element['pass1']['#value']);
   $pass2 = trim($element['pass2']['#value']);
-  if (!empty($pass1) || !empty($pass2)) {
+  if (strlen($pass1) > 0 || strlen($pass2) > 0) {
     if (strcmp($pass1, $pass2)) {
       form_error($element, t('The specified passwords do not match.'));
     }
@@ -2828,7 +3075,7 @@
 }
 
 /**
- * Roll out a single date element.
+ * Expands a date element into year, month, and day select elements.
  */
 function form_process_date($element) {
   // Default to current date
@@ -2884,7 +3131,7 @@
 }
 
 /**
- * Validates the date type to stop dates like February 30, 2006.
+ * Validates the date type to prevent invalid dates (e.g., February 30, 2006).
  */
 function date_validate($element) {
   if (!checkdate($element['#value']['month'], $element['#value']['day'], $element['#value']['year'])) {
@@ -2914,7 +3161,7 @@
 }
 
 /**
- * If no default value is set for weight select boxes, use 0.
+ * Sets the value for a weight element, with zero as a default.
  */
 function weight_value(&$form) {
   if (isset($form['#default_value'])) {
@@ -2926,8 +3173,7 @@
 }
 
 /**
- * Roll out a single radios element to a list of radios,
- * using the options array as index.
+ * Expands a radios element into individual radio elements.
  */
 function form_process_radios($element) {
   if (count($element['#options']) > 0) {
@@ -2948,7 +3194,9 @@
         // 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,
+        // Use default or FALSE. A value of FALSE means that the radio button is
+        // not 'checked'.
+        '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE,
         '#attributes' => $element['#attributes'],
         '#parents' => $element['#parents'],
         '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
@@ -2966,14 +3214,12 @@
  * @param $variables
  *   An associative array containing:
  *   - element: An associative array containing the properties of the element.
- *     Properties used: #title, #value, #return_value, #description, #required,
- *     #attributes.
+ *     Properties used: #id, #name, #attributes, #checked, #return_value.
  *
  * @ingroup themeable
  */
 function theme_checkbox($variables) {
   $element = $variables['element'];
-  $t = get_t();
   $element['#attributes']['type'] = 'checkbox';
   element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
 
@@ -3006,15 +3252,19 @@
   if (!empty($element['#attributes']['class'])) {
     $attributes['class'] = array_merge($attributes['class'], $element['#attributes']['class']);
   }
+  if (isset($element['#attributes']['title'])) {
+    $attributes['title'] = $element['#attributes']['title'];
+  }
   return '<div' . drupal_attributes($attributes) . '>' . (!empty($element['#children']) ? $element['#children'] : '') . '</div>';
 }
 
 /**
- * Add form_element theming to an element if title or description is set.
+ * Adds form element theming to an element if its title or description is set.
  *
  * This is used as a pre render function for checkboxes and radios.
  */
 function form_pre_render_conditional_form_element($element) {
+  $t = get_t();
   // Set the element's title attribute to show #title as a tooltip, if needed.
   if (isset($element['#title']) && $element['#title_display'] == 'attribute') {
     $element['#attributes']['title'] = $element['#title'];
@@ -3057,6 +3307,9 @@
   return $element;
 }
 
+/**
+ * Processes a checkboxes form element.
+ */
 function form_process_checkboxes($element) {
   $value = is_array($element['#value']) ? $element['#value'] : array();
   $element['#tree'] = TRUE;
@@ -3118,6 +3371,7 @@
  *   container.
  * @param $form_state
  *   The $form_state array for the form this element belongs to.
+ *
  * @return
  *   The processed element.
  */
@@ -3132,9 +3386,12 @@
 /**
  * Returns HTML to wrap child elements in a container.
  *
- * Used for grouped form items. Can also be used as a #theme_wrapper for any
+ * 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.
+ * classes or an HTML ID.
+ *
+ * See the @link forms_api_reference.html Form API reference @endlink for more
+ * information on the #theme_wrappers render array property.
  *
  * @param $variables
  *   An associative array containing:
@@ -3145,6 +3402,8 @@
  */
 function theme_container($variables) {
   $element = $variables['element'];
+  // Ensure #attributes is set.
+  $element += array('#attributes' => array());
 
   // Special handling for form elements.
   if (isset($element['#array_parents'])) {
@@ -3162,21 +3421,6 @@
 /**
  * Returns HTML for a table with radio buttons or checkboxes.
  *
- * An example of per-row options:
- * @code
- * $options = array();
- * $options[0]['title'] = "A red row"
- * $options[0]['#attributes'] = array ('class' => array('red-row'));
- * $options[1]['title'] = "A blue row"
- * $options[1]['#attributes'] = array ('class' => array('blue-row'));
- *
- * $form['myselector'] = array (
- * '#type' => 'tableselect',
- * '#title' => 'My Selector'
- * '#options' => $options,
- * );
- * @endcode
- *
  * @param $variables
  *   An associative array containing:
  *   - element: An associative array containing the properties and children of
@@ -3184,7 +3428,35 @@
  *     and #js_select. The #options property is an array of selection options;
  *     each array element of #options is an array of properties. These
  *     properties can include #attributes, which is added to the
- *     table row's HTML attributes; see theme_table().
+ *     table row's HTML attributes; see theme_table(). An example of per-row
+ *     options:
+ *     @code
+ *     $options = array(
+ *       array(
+ *         'title' => 'How to Learn Drupal',
+ *         'content_type' => 'Article',
+ *         'status' => 'published',
+ *         '#attributes' => array('class' => array('article-row')),
+ *       ),
+ *       array(
+ *         'title' => 'Privacy Policy',
+ *         'content_type' => 'Page',
+ *         'status' => 'published',
+ *         '#attributes' => array('class' => array('page-row')),
+ *       ),
+ *     );
+ *     $header = array(
+ *       'title' => t('Title'),
+ *       'content_type' => t('Content type'),
+ *       'status' => t('Status'),
+ *     );
+ *     $form['table'] = array(
+ *       '#type' => 'tableselect',
+ *       '#header' => $header,
+ *       '#options' => $options,
+ *       '#empty' => t('No content available.'),
+ *     );
+ *     @endcode
  *
  * @ingroup themeable
  */
@@ -3228,11 +3500,12 @@
 }
 
 /**
- * Create the correct amount of checkbox or radio elements to populate the table.
+ * Creates checkbox or radio elements to populate a tableselect table.
  *
  * @param $element
  *   An associative array containing the properties and children of the
  *   tableselect element.
+ *
  * @return
  *   The processed element.
  */
@@ -3242,7 +3515,7 @@
     $value = is_array($element['#value']) ? $element['#value'] : array();
   }
   else {
-    // Advanced selection behaviour make no sense for radios.
+    // Advanced selection behavior makes no sense for radios.
     $element['#js_select'] = FALSE;
   }
 
@@ -3273,6 +3546,7 @@
             '#return_value' => $key,
             '#default_value' => isset($value[$key]) ? $key : NULL,
             '#attributes' => $element['#attributes'],
+            '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
           );
         }
         else {
@@ -3326,6 +3600,9 @@
  *       different character, 'replace_pattern' needs to be set accordingly.
  *     - error: (optional) A custom form error message string to show, if the
  *       machine name contains disallowed characters.
+ *     - standalone: (optional) Whether the live preview should stay in its own
+ *       form element rather than in the suffix of the source element. Defaults
+ *       to FALSE.
  *   - #maxlength: (optional) Should be set to the maximum allowed length of the
  *     machine name. Defaults to 64.
  *   - #disabled: (optional) Should be set to TRUE in case an existing machine
@@ -3337,6 +3614,9 @@
     '#title' => t('Machine-readable name'),
     '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
     '#machine_name' => array(),
+    '#field_prefix' => '',
+    '#field_suffix' => '',
+    '#suffix' => '',
   );
   // A form element that only wants to set one #machine_name property (usually
   // 'source' only) would leave all other properties undefined, if the defaults
@@ -3347,15 +3627,25 @@
     'label' => t('Machine name'),
     'replace_pattern' => '[^a-z0-9_]+',
     'replace' => '_',
+    'standalone' => FALSE,
+    'field_prefix' => $element['#field_prefix'],
+    'field_suffix' => $element['#field_suffix'],
   );
 
+  // By default, machine names are restricted to Latin alphanumeric characters.
+  // So, default to LTR directionality.
+  if (!isset($element['#attributes'])) {
+    $element['#attributes'] = array();
+  }
+  $element['#attributes'] += array('dir' => 'ltr');
+
   // The source element defaults to array('name'), but may have been overidden.
   if (empty($element['#machine_name']['source'])) {
     return $element;
   }
 
   // Retrieve the form element containing the human-readable name from the
-  // complete form in $form_state. By reference, because we need to append
+  // complete form in $form_state. By reference, because we may need to append
   // a #field_suffix that will hold the live preview.
   $key_exists = NULL;
   $source = drupal_array_get_nested_value($form_state['complete form'], $element['#machine_name']['source'], $key_exists);
@@ -3363,16 +3653,21 @@
     return $element;
   }
 
-  // Append a field suffix to the source form element, which will contain
-  // the live preview of the machine name.
   $suffix_id = $source['#id'] . '-machine-name-suffix';
-  $source += array('#field_suffix' => '');
-  $source['#field_suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+  $element['#machine_name']['suffix'] = '#' . $suffix_id;
 
-  $parents = array_merge($element['#machine_name']['source'], array('#field_suffix'));
-  drupal_array_set_nested_value($form_state['complete form'], $parents, $source['#field_suffix']);
+  if ($element['#machine_name']['standalone']) {
+    $element['#suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+  }
+  else {
+    // Append a field suffix to the source form element, which will contain
+    // the live preview of the machine name.
+    $source += array('#field_suffix' => '');
+    $source['#field_suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
 
-  $element['#machine_name']['suffix'] = '#' . $suffix_id;
+    $parents = array_merge($element['#machine_name']['source'], array('#field_suffix'));
+    drupal_array_set_nested_value($form_state['complete form'], $parents, $source['#field_suffix']);
+  }
 
   $js_settings = array(
     'type' => 'setting',
@@ -3389,7 +3684,7 @@
 }
 
 /**
- * Form element validation handler for #type 'machine_name'.
+ * Form element validation handler for machine_name elements.
  *
  * Note that #maxlength is validated by _form_validate() already.
  */
@@ -3427,8 +3722,7 @@
 }
 
 /**
- * Adds fieldsets to the specified group or adds group members to this
- * fieldset.
+ * Arranges fieldsets into groups.
  *
  * @param $element
  *   An associative array containing the properties and children of the
@@ -3436,6 +3730,7 @@
  *   child elements are taken over into $form_state.
  * @param $form_state
  *   The $form_state array for the form this fieldset belongs to.
+ *
  * @return
  *   The processed element.
  */
@@ -3539,6 +3834,7 @@
  *   fieldset.
  * @param $form_state
  *   The $form_state array for the form this vertical tab widget belongs to.
+ *
  * @return
  *   The processed element.
  */
@@ -3573,8 +3869,8 @@
  *
  * @param $variables
  *   An associative array containing:
- *   - element: An associative array containing the properties and children of the
- *     fieldset. Properties used: #children.
+ *   - element: An associative array containing the properties and children of
+ *     the fieldset. Properties used: #children.
  *
  * @ingroup themeable
  */
@@ -3672,6 +3968,34 @@
 }
 
 /**
+ * Process function to prepare autocomplete data.
+ *
+ * @param $element
+ *   A textfield or other element with a #autocomplete_path.
+ *
+ * @return array
+ *   The processed form element.
+ */
+function form_process_autocomplete($element) {
+  $element['#autocomplete_input'] = array();
+  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
+    $element['#autocomplete_input']['#id'] = $element['#id'] .'-autocomplete';
+    // Force autocomplete to use non-clean URLs since this protects against the
+    // browser interpreting the path plus search string as an actual file.
+    $current_clean_url = isset($GLOBALS['conf']['clean_url']) ? $GLOBALS['conf']['clean_url'] : NULL;
+    $GLOBALS['conf']['clean_url'] = 0;
+    // Force the script path to 'index.php', in case the server is not
+    // configured to find it automatically. Normally it is the responsibility
+    // of the site to do this themselves using hook_url_outbound_alter() (see
+    // url()) but since this code is forcing non-clean URLs on sites that don't
+    // normally use them, it is done here instead.
+    $element['#autocomplete_input']['#url_value'] = url($element['#autocomplete_path'], array('absolute' => TRUE, 'script' => 'index.php'));
+    $GLOBALS['conf']['clean_url'] = $current_clean_url;
+  }
+  return $element;
+}
+
+/**
  * Returns HTML for a textfield form element.
  *
  * @param $variables
@@ -3689,14 +4013,14 @@
   _form_set_class($element, array('form-text'));
 
   $extra = '';
-  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
+  if ($element['#autocomplete_path'] && !empty($element['#autocomplete_input'])) {
     drupal_add_library('system', 'drupal.autocomplete');
     $element['#attributes']['class'][] = 'form-autocomplete';
 
     $attributes = array();
     $attributes['type'] = 'hidden';
-    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
-    $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
+    $attributes['id'] = $element['#autocomplete_input']['#id'];
+    $attributes['value'] = $element['#autocomplete_input']['#url_value'];
     $attributes['disabled'] = 'disabled';
     $attributes['class'][] = 'autocomplete';
     $extra = '<input' . drupal_attributes($attributes) . ' />';
@@ -3783,16 +4107,30 @@
 }
 
 /**
- * Expand weight elements into selects.
+ * Expands a weight element into a select element.
  */
 function form_process_weight($element) {
-  for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) {
-    $weights[$n] = $n;
-  }
-  $element['#options'] = $weights;
-  $element['#type'] = 'select';
   $element['#is_weight'] = TRUE;
-  $element += element_info('select');
+
+  // If the number of options is small enough, use a select field.
+  $max_elements = variable_get('drupal_weight_select_max', DRUPAL_WEIGHT_SELECT_MAX);
+  if ($element['#delta'] <= $max_elements) {
+    $element['#type'] = 'select';
+    for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) {
+      $weights[$n] = $n;
+    }
+    $element['#options'] = $weights;
+    $element += element_info('select');
+  }
+  // Otherwise, use a text field.
+  else {
+    $element['#type'] = 'textfield';
+    // Use a field big enough to fit most weights.
+    $element['#size'] = 10;
+    $element['#element_validate'] = array('element_validate_integer');
+    $element += element_info('textfield');
+  }
+
   return $element;
 }
 
@@ -3867,8 +4205,6 @@
  */
 function theme_form_element($variables) {
   $element = &$variables['element'];
-  // This is also used in the installer, pre-database setup.
-  $t = get_t();
 
   // This function is invoked as theme wrapper, but the rendered form element
   // may not necessarily have been processed by form_builder().
@@ -3953,7 +4289,8 @@
  *
  * Form element labels include the #title and a #required marker. The label is
  * associated with the element itself by the element #id. Labels may appear
- * before or after elements, depending on theme_form_element() and #title_display.
+ * before or after elements, depending on theme_form_element() and
+ * #title_display.
  *
  * This function will not be called for elements with no labels, depending on
  * #title_display. For elements that have an empty #title and are not required,
@@ -3976,7 +4313,7 @@
   $t = get_t();
 
   // If title and required marker are both empty, output no label.
-  if (empty($element['#title']) && empty($element['#required'])) {
+  if ((!isset($element['#title']) || $element['#title'] === '') && empty($element['#required'])) {
     return '';
   }
 
@@ -4026,13 +4363,13 @@
   if (!empty($element['#required'])) {
     $element['#attributes']['class'][] = 'required';
   }
-  if (isset($element['#parents']) && form_get_error($element)) {
+  if (isset($element['#parents']) && form_get_error($element) !== NULL && !empty($element['#validated'])) {
     $element['#attributes']['class'][] = 'error';
   }
 }
 
 /**
- * Helper form element validator: integer.
+ * Form element validation handler for integer elements.
  */
 function element_validate_integer($element, &$form_state) {
   $value = $element['#value'];
@@ -4042,7 +4379,7 @@
 }
 
 /**
- * Helper form element validator: integer > 0.
+ * Form element validation handler for integer elements that must be positive.
  */
 function element_validate_integer_positive($element, &$form_state) {
   $value = $element['#value'];
@@ -4052,7 +4389,7 @@
 }
 
 /**
- * Helper form element validator: number.
+ * Form element validation handler for number elements.
  */
 function element_validate_number($element, &$form_state) {
   $value = $element['#value'];
@@ -4068,7 +4405,7 @@
 /**
  * @defgroup batch Batch operations
  * @{
- * Create and process batch operations.
+ * Creates and processes batch operations.
  *
  * Functions allowing forms processing to be spread out over several page
  * requests, thus ensuring that the processing does not get interrupted
@@ -4103,7 +4440,7 @@
  * returns any user input in the 'results' or 'message' keys of $context,
  * it must also sanitize them first.
  *
- * Sample batch operations:
+ * Sample callback_batch_operation():
  * @code
  * // Simple and artificial: load a node of a given type for a given user
  * function my_function_1($uid, $type, &$context) {
@@ -4155,9 +4492,9 @@
  * }
  * @endcode
  *
- * Sample 'finished' callback:
+ * Sample callback_batch_finished():
  * @code
- * function batch_test_finished($success, $results, $operations) {
+ * function my_finished_callback($success, $results, $operations) {
  *   // The 'success' parameter means no fatal PHP errors were detected. All
  *   // other error management should be handled using 'results'.
  *   if ($success) {
@@ -4177,49 +4514,53 @@
  */
 
 /**
- * Opens a new batch.
+ * Adds a new batch.
  *
- * @param $batch
- *   An array defining the batch. The following keys can be used -- only
- *   'operations' is required, and batch_init() provides default values for
- *   the messages.
- *   - 'operations': Array of function calls to be performed.
+ * Batch operations are added as new batch sets. Batch sets are used to spread
+ * processing (primarily, but not exclusively, forms processing) over several
+ * page requests. This helps to ensure that the processing is not interrupted
+ * due to PHP timeouts, while users are still able to receive feedback on the
+ * progress of the ongoing operations. Combining related operations into
+ * distinct batch sets provides clean code independence for each batch set,
+ * ensuring that two or more batches, submitted independently, can be processed
+ * without mutual interference. Each batch set may specify its own set of
+ * operations and results, produce its own UI messages, and trigger its own
+ * 'finished' callback. Batch sets are processed sequentially, with the progress
+ * bar starting afresh for each new set.
+ *
+ * @param $batch_definition
+ *   An associative array defining the batch, with the following elements (all
+ *   are optional except as noted):
+ *   - operations: (required) Array of operations to be performed, where each
+ *     item is an array consisting of the name of an implementation of
+ *     callback_batch_operation() and an array of parameter.
  *     Example:
  *     @code
  *     array(
- *       array('my_function_1', array($arg1)),
- *       array('my_function_2', array($arg2_1, $arg2_2)),
+ *       array('callback_batch_operation_1', array($arg1)),
+ *       array('callback_batch_operation_2', array($arg2_1, $arg2_2)),
  *     )
  *     @endcode
- *   - 'title': Title for the progress page. Only safe strings should be passed.
- *     Defaults to t('Processing').
- *   - 'init_message': Message displayed while the processing is initialized.
+ *   - title: A safe, translated string to use as the title for the progress
+ *     page. Defaults to t('Processing').
+ *   - init_message: Message displayed while the processing is initialized.
  *     Defaults to t('Initializing.').
- *   - 'progress_message': Message displayed while processing the batch.
- *     Available placeholders are @current, @remaining, @total, @percentage,
- *     @estimate and @elapsed. Defaults to t('Completed @current of @total.').
- *   - 'error_message': Message displayed if an error occurred while processing
+ *   - progress_message: Message displayed while processing the batch. Available
+ *     placeholders are @current, @remaining, @total, @percentage, @estimate and
+ *     @elapsed. Defaults to t('Completed @current of @total.').
+ *   - error_message: Message displayed if an error occurred while processing
  *     the batch. Defaults to t('An error has occurred.').
- *   - 'finished': Name of a function to be executed after the batch has
- *     completed. This should be used to perform any result massaging that
- *     may be needed, and possibly save data in $_SESSION for display after
- *     final page redirection.
- *   - 'file': Path to the file containing the definitions of the
- *     'operations' and 'finished' functions, for instance if they don't
- *     reside in the main .module file. The path should be relative to
- *     base_path(), and thus should be built using drupal_get_path().
- *   - 'css': Array of paths to CSS files to be used on the progress page.
- *   - 'url_options': options passed to url() when constructing redirect
- *     URLs for the batch.
- *
- * Operations are added as new batch sets. Batch sets are used to ensure
- * clean code independence, ensuring that several batches submitted by
- * different parts of the code (core / contrib modules) can be processed
- * correctly while not interfering or having to cope with each other. Each
- * batch set gets to specify his own UI messages, operates on its own set
- * of operations and results, and triggers its own 'finished' callback.
- * Batch sets are processed sequentially, with the progress bar starting
- * fresh for every new set.
+ *   - finished: Name of an implementation of callback_batch_finished(). This is
+ *     executed after the batch has completed. This should be used to perform
+ *     any result massaging that may be needed, and possibly save data in
+ *     $_SESSION for display after final page redirection.
+ *   - file: Path to the file containing the definitions of the 'operations' and
+ *     'finished' functions, for instance if they don't reside in the main
+ *     .module file. The path should be relative to base_path(), and thus should
+ *     be built using drupal_get_path().
+ *   - css: Array of paths to CSS files to be used on the progress page.
+ *   - url_options: options passed to url() when constructing redirect URLs for
+ *     the batch.
  */
 function batch_set($batch_definition) {
   if ($batch_definition) {
@@ -4234,7 +4575,7 @@
     }
 
     // Base and default properties for the batch set.
-    // Use get_t() to allow batches at install time.
+    // Use get_t() to allow batches during installation.
     $t = get_t();
     $init = array(
       'sandbox' => array(),
@@ -4399,6 +4740,7 @@
  *   The batch array.
  * @param $set_id
  *   The id of the set to process.
+ *
  * @return
  *   The name and class of the queue are added by reference to the batch set.
  */
@@ -4428,6 +4770,7 @@
  *
  * @param $batch_set
  *   The batch set.
+ *
  * @return
  *   The queue object.
  */
diff -Naur drupal-7.9/includes/graph.inc drupal-7.58/includes/graph.inc
--- drupal-7.9/includes/graph.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/graph.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,12 +2,12 @@
 
 /**
  * @file
- * Directed acyclic graph functions.
+ * Directed acyclic graph manipulation.
  */
 
 
 /**
- * Perform a depth first sort on a directed acyclic graph.
+ * Performs a depth-first search and sort on a directed acyclic graph.
  *
  * @param $graph
  *   A three dimensional associated array, with the first keys being the names
@@ -52,7 +52,7 @@
     // The components of the graph.
     'components' => array(),
   );
-  // Perform the actual sort.
+  // Perform the actual search.
   foreach ($graph as $start => $data) {
     _drupal_depth_first_search($graph, $state, $start);
   }
@@ -72,7 +72,7 @@
 }
 
 /**
- * Helper function to perform a depth first sort.
+ * Performs a depth-first search on a graph.
  *
  * @param $graph
  *   A three dimensional associated graph array.
@@ -143,4 +143,3 @@
   // topological order if the graph is acyclic.
   $state['last_visit_order'][] = $start;
 }
-
diff -Naur drupal-7.9/includes/image.inc drupal-7.58/includes/image.inc
--- drupal-7.9/includes/image.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/image.inc	2018-03-27 21:28:19.000000000 +0200
@@ -34,7 +34,7 @@
  */
 
 /**
- * Return a list of available toolkits.
+ * Gets a list of available toolkits.
  *
  * @return
  *   An array with the toolkit names as keys and the descriptions as values.
@@ -55,7 +55,7 @@
 }
 
 /**
- * Retrieve the name of the currently used toolkit.
+ * Gets the name of the currently used toolkit.
  *
  * @return
  *   String containing the name of the selected toolkit, or FALSE on error.
@@ -101,7 +101,7 @@
 }
 
 /**
- * Get details about an image.
+ * Gets details about an image.
  *
  * Drupal supports GIF, JPG and PNG file formats when used with the GD
  * toolkit, and may support others, depending on which toolkits are
@@ -186,14 +186,14 @@
  *   Dimensions to be modified - an array with components width and height, in
  *   pixels.
  * @param $width
- *   The target width, in pixels. This value is omitted then the scaling will
+ *   The target width, in pixels. If this value is NULL then the scaling will be
  *   based only on the height value.
  * @param $height
- *   The target height, in pixels. This value is omitted then the scaling will
- *   based only on the width value.
+ *   The target height, in pixels. If this value is NULL then the scaling will
+ *   be based only on the width value.
  * @param $upscale
- *   Boolean indicating that files smaller than the dimensions will be scaled
- *   up. This generally results in a low quality image.
+ *   Boolean indicating that images smaller than the target dimensions will be
+ *   scaled up. This generally results in a low quality image.
  *
  * @return
  *   TRUE if $dimensions was modified, FALSE otherwise.
@@ -203,31 +203,25 @@
 function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NULL, $upscale = FALSE) {
   $aspect = $dimensions['height'] / $dimensions['width'];
 
-  if ($upscale) {
-    // Set width/height according to aspect ratio if either is empty.
-    $width = !empty($width) ? $width : $height / $aspect;
-    $height = !empty($height) ? $height : $width / $aspect;
+  // Calculate one of the dimensions from the other target dimension,
+  // ensuring the same aspect ratio as the source dimensions. If one of the
+  // target dimensions is missing, that is the one that is calculated. If both
+  // are specified then the dimension calculated is the one that would not be
+  // calculated to be bigger than its target.
+  if (($width && !$height) || ($width && $height && $aspect < $height / $width)) {
+    $height = (int) round($width * $aspect);
   }
   else {
-    // Set impossibly large values if the width and height aren't set.
-    $width = !empty($width) ? $width : 9999999;
-    $height = !empty($height) ? $height : 9999999;
-
-    // Don't scale up.
-    if (round($width) >= $dimensions['width'] && round($height) >= $dimensions['height']) {
-      return FALSE;
-    }
+    $width = (int) round($height / $aspect);
   }
 
-  if ($aspect < $height / $width) {
-    $dimensions['width'] = $width;
-    $dimensions['height'] = (int) round($width * $aspect);
-  }
-  else {
-    $dimensions['width'] = (int) round($height / $aspect);
-    $dimensions['height'] = $height;
+  // Don't upscale if the option isn't enabled.
+  if (!$upscale && ($width >= $dimensions['width'] || $height >= $dimensions['height'])) {
+    return FALSE;
   }
 
+  $dimensions['width'] = $width;
+  $dimensions['height'] = $height;
   return TRUE;
 }
 
@@ -239,11 +233,11 @@
  * @param $image
  *   An image object returned by image_load().
  * @param $width
- *   The target width, in pixels. This value is omitted then the scaling will
- *   based only on the height value.
+ *   The target width, in pixels. If this value is NULL then the scaling will
+ *   be based only on the height value.
  * @param $height
- *   The target height, in pixels. This value is omitted then the scaling will
- *   based only on the width value.
+ *   The target height, in pixels. If this value is NULL then the scaling will
+ *   be based only on the width value.
  * @param $upscale
  *   Boolean indicating that files smaller than the dimensions will be scaled
  *   up. This generally results in a low quality image.
@@ -267,7 +261,7 @@
 }
 
 /**
- * Resize an image to the given dimensions (ignoring aspect ratio).
+ * Resizes an image to the given dimensions (ignoring aspect ratio).
  *
  * @param $image
  *   An image object returned by image_load().
@@ -290,7 +284,7 @@
 }
 
 /**
- * Rotate an image by the given number of degrees.
+ * Rotates an image by the given number of degrees.
  *
  * @param $image
  *   An image object returned by image_load().
@@ -314,7 +308,7 @@
 }
 
 /**
- * Crop an image to the rectangle specified by the given rectangle.
+ * Crops an image to a rectangle specified by the given dimensions.
  *
  * @param $image
  *   An image object returned by image_load().
@@ -346,7 +340,7 @@
 }
 
 /**
- * Convert an image to grayscale.
+ * Converts an image to grayscale.
  *
  * @param $image
  *   An image object returned by image_load().
@@ -361,9 +355,8 @@
   return image_toolkit_invoke('desaturate', $image);
 }
 
-
 /**
- * Load an image file and return an image object.
+ * Loads an image file and returns an image object.
  *
  * Any changes to the file are not saved until image_save() is called.
  *
@@ -406,7 +399,7 @@
 }
 
 /**
- * Close the image and save the changes to a file.
+ * Closes the image and saves the changes to a file.
  *
  * @param $image
  *   An image object returned by image_load(). The object's 'info' property
diff -Naur drupal-7.9/includes/install.core.inc drupal-7.58/includes/install.core.inc
--- drupal-7.9/includes/install.core.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/install.core.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,8 +6,7 @@
  */
 
 /**
- * Global flag to indicate that a task should not be run during the current
- * installation request.
+ * Do not run the task during the current installation request.
  *
  * This can be used to skip running an installation task when certain
  * conditions are met, even though the task may still show on the list of
@@ -20,8 +19,7 @@
 define('INSTALL_TASK_SKIP', 1);
 
 /**
- * Global flag to indicate that a task should be run on each installation
- * request that reaches it.
+ * Run the task on each installation request until the database is set up.
  *
  * This is primarily used by the Drupal installer for bootstrap-related tasks.
  */
@@ -200,7 +198,7 @@
 }
 
 /**
- * Begin an installation request, modifying the installation state as needed.
+ * Begins an installation request, modifying the installation state as needed.
  *
  * This function performs commands that must run at the beginning of every page
  * request. It throws an exception if the installation should not proceed.
@@ -295,12 +293,11 @@
   else {
     $task = NULL;
 
-    // Since previous versions of Drupal stored database connection information
-    // in the 'db_url' variable, we should never let an installation proceed if
-    // this variable is defined and the settings file was not verified above
-    // (otherwise we risk installing over an existing site whose settings file
-    // has not yet been updated).
-    if (!empty($GLOBALS['db_url'])) {
+    // Do not install over a configured settings.php. Check the 'db_url'
+    // variable in addition to 'databases', since previous versions of Drupal
+    // used that (and we do not want to allow installations on an existing site
+    // whose settings file has not yet been updated).
+    if (!empty($GLOBALS['databases']) || !empty($GLOBALS['db_url'])) {
       throw new Exception(install_already_done_error());
     }
   }
@@ -365,7 +362,8 @@
  * Runs an individual installation task.
  *
  * @param $task
- *   An array of information about the task to be run.
+ *   An array of information about the task to be run as returned by
+ *   hook_install_tasks().
  * @param $install_state
  *   An array of information about the current installation state. This is
  *   passed in by reference so that it can be modified by the task.
@@ -481,11 +479,15 @@
  * the page request evolves (for example, if an installation profile hasn't
  * been selected yet, we don't yet know which profile tasks need to be run).
  *
+ * You can override this using hook_install_tasks() or
+ * hook_install_tasks_alter().
+ *
  * @param $install_state
  *   An array of information about the current installation state.
  *
  * @return
- *   A list of tasks to be performed, with associated metadata.
+ *   A list of tasks to be performed, with associated metadata as returned by
+ *   hook_install_tasks().
  */
 function install_tasks_to_perform($install_state) {
   // Start with a list of all currently available tasks.
@@ -525,7 +527,7 @@
   $needs_translations = count($install_state['locales']) > 1 && !empty($install_state['parameters']['locale']) && $install_state['parameters']['locale'] != 'en';
 
   // Start with the core installation tasks that run before handing control
-  // to the install profile.
+  // to the installation profile.
   $tasks = array(
     'install_select_profile' => array(
       'display_name' => st('Choose profile'),
@@ -570,6 +572,12 @@
 
   // Now add any tasks defined by the installation profile.
   if (!empty($install_state['parameters']['profile'])) {
+    // Load the profile install file, because it is not always loaded when
+    // hook_install_tasks() is invoked (e.g. batch processing).
+    $profile_install_file = DRUPAL_ROOT . '/profiles/' . $install_state['parameters']['profile'] . '/' . $install_state['parameters']['profile'] . '.install';
+    if (file_exists($profile_install_file)) {
+      include_once $profile_install_file;
+    }
     $function = $install_state['parameters']['profile'] . '_install_tasks';
     if (function_exists($function)) {
       $result = $function($install_state);
@@ -595,7 +603,7 @@
   // Allow the installation profile to modify the full list of tasks.
   if (!empty($install_state['parameters']['profile'])) {
     $profile_file = DRUPAL_ROOT . '/profiles/' . $install_state['parameters']['profile'] . '/' . $install_state['parameters']['profile'] . '.profile';
-    if (is_file($profile_file)) {
+    if (file_exists($profile_file)) {
       include_once $profile_file;
       $function = $install_state['parameters']['profile'] . '_install_tasks_alter';
       if (function_exists($function)) {
@@ -689,6 +697,21 @@
  */
 function install_display_output($output, $install_state) {
   drupal_page_header();
+
+  // Prevent install.php from being indexed when installed in a sub folder.
+  // robots.txt rules are not read if the site is within domain.com/subfolder
+  // resulting in /subfolder/install.php being found through search engines.
+  // When settings.php is writeable this can be used via an external database
+  // leading a malicious user to gain php access to the server.
+  $noindex_meta_tag = array(
+    '#tag' => 'meta',
+    '#attributes' => array(
+      'name' => 'robots',
+      'content' => 'noindex, nofollow',
+    ),
+  );
+  drupal_add_html_head($noindex_meta_tag, 'install_meta_robots');
+
   // Only show the task list if there is an active task; otherwise, the page
   // request has ended before tasks have even been started, so there is nothing
   // meaningful to show.
@@ -703,15 +726,17 @@
 }
 
 /**
- * Installation task; verify the requirements for installing Drupal.
+ * Verifies the requirements for installing Drupal.
  *
  * @param $install_state
  *   An array of information about the current installation state.
  *
  * @return
  *   A themed status report, or an exception if there are requirement errors.
- *   Otherwise, no output is returned, so that the next task can be run
- *   in the same page request.
+ *   If there are only requirement warnings, a themed status report is shown
+ *   initially, but the user is allowed to bypass it by providing 'continue=1'
+ *   in the URL. Otherwise, no output is returned, so that the next task can be
+ *   run in the same page request.
  */
 function install_verify_requirements(&$install_state) {
   // Check the installation requirements for Drupal and this profile.
@@ -723,22 +748,30 @@
   // Check the severity of the requirements reported.
   $severity = drupal_requirements_severity($requirements);
 
-  if ($severity == REQUIREMENT_ERROR) {
+  // If there are errors, always display them. If there are only warnings, skip
+  // them if the user has provided a URL parameter acknowledging the warnings
+  // and indicating a desire to continue anyway. See drupal_requirements_url().
+  if ($severity == REQUIREMENT_ERROR || ($severity == REQUIREMENT_WARNING && empty($install_state['parameters']['continue']))) {
     if ($install_state['interactive']) {
       drupal_set_title(st('Requirements problem'));
       $status_report = theme('status_report', array('requirements' => $requirements));
-      $status_report .= st('Check the error messages and <a href="!url">proceed with the installation</a>.', array('!url' => check_url(request_uri())));
+      $status_report .= st('Check the error messages and <a href="!url">proceed with the installation</a>.', array('!url' => check_url(drupal_requirements_url($severity))));
       return $status_report;
     }
     else {
-      // Throw an exception showing all unmet requirements.
+      // Throw an exception showing any unmet requirements.
       $failures = array();
       foreach ($requirements as $requirement) {
+        // Skip warnings altogether for non-interactive installations; these
+        // proceed in a single request so there is no good opportunity (and no
+        // good method) to warn the user anyway.
         if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
           $failures[] = $requirement['title'] . ': ' . $requirement['value'] . "\n\n" . $requirement['description'];
         }
       }
-      throw new Exception(implode("\n\n", $failures));
+      if (!empty($failures)) {
+        throw new Exception(implode("\n\n", $failures));
+      }
     }
   }
 }
@@ -753,6 +786,15 @@
   // Install system.module.
   drupal_install_system();
 
+  // Call file_ensure_htaccess() to ensure that all of Drupal's standard
+  // directories (e.g., the public and private files directories) have
+  // appropriate .htaccess files. These directories will have already been
+  // created by this point in the installer, since Drupal creates them during
+  // the install_verify_requirements() task. Note that we cannot call
+  // file_ensure_htaccess() any earlier than this, since it relies on
+  // system.module in order to work.
+  file_ensure_htaccess();
+
   // Enable the user module so that sessions can be recorded during the
   // upcoming bootstrap step.
   module_enable(array('user'), FALSE);
@@ -761,16 +803,23 @@
   // variable_set() can be used now that system.module is installed.
   $modules = $install_state['profile_info']['dependencies'];
 
-  // The install profile is also a module, which needs to be installed
+  // The installation profile is also a module, which needs to be installed
   // after all the dependencies have been installed.
   $modules[] = drupal_get_profile();
 
   variable_set('install_profile_modules', array_diff($modules, array('system')));
   $install_state['database_tables_exist'] = TRUE;
+
+  // Prevent the hook_requirements() check from telling us to convert the
+  // database to utf8mb4.
+  $connection = Database::getConnection();
+  if ($connection->utf8mb4IsConfigurable() && $connection->utf8mb4IsActive()) {
+    variable_set('drupal_all_databases_are_utf8mb4', TRUE);
+  }
 }
 
 /**
- * Verify and return the last installation task that was completed.
+ * Verifies and returns the last installation task that was completed.
  *
  * @return
  *   The last completed task, if there is one. An exception is thrown if Drupal
@@ -814,7 +863,7 @@
 }
 
 /**
- * Verify PDO library.
+ * Verifies the PDO library.
  */
 function install_verify_pdo() {
   // PDO was moved to PHP core in 5.2.0, but the old extension (targeting 5.0
@@ -826,15 +875,14 @@
 }
 
 /**
- * Installation task; define a form to configure and rewrite settings.php.
+ * Form constructor for a form to configure and rewrite settings.php.
  *
- * @param $form_state
- *   An associative array containing the current state of the form.
  * @param $install_state
  *   An array of information about the current installation state.
  *
- * @return
- *   The form API definition for the database configuration form.
+ * @see install_settings_form_validate()
+ * @see install_settings_form_submit()
+ * @ingroup forms
  */
 function install_settings_form($form, &$form_state, &$install_state) {
   global $databases;
@@ -897,7 +945,9 @@
 }
 
 /**
- * Form API validate for install_settings form.
+ * Form validation handler for install_settings_form().
+ *
+ * @see install_settings_form_submit()
  */
 function install_settings_form_validate($form, &$form_state) {
   $driver = $form_state['values']['driver'];
@@ -954,7 +1004,9 @@
 }
 
 /**
- * Form API submit for install_settings form.
+ * Form submission handler for install_settings_form().
+ *
+ * @see install_settings_form_validate()
  */
 function install_settings_form_submit($form, &$form_state) {
   global $install_state;
@@ -965,7 +1017,7 @@
     'required' => TRUE,
   );
   $settings['drupal_hash_salt'] = array(
-    'value'    => drupal_hash_base64(drupal_random_bytes(55)),
+    'value'    => drupal_random_key(),
     'required' => TRUE,
   );
   drupal_rewrite_settings($settings);
@@ -985,7 +1037,7 @@
 }
 
 /**
- * Installation task; select which profile to install.
+ * Selects which profile to install.
  *
  * @param $install_state
  *   An array of information about the current installation state. The chosen
@@ -1025,8 +1077,21 @@
 }
 
 /**
- * Helper function for automatically selecting an installation profile from a
- * list or from a selection passed in via $_POST.
+ * Selects an installation profile.
+ *
+ * A profile will be selected if:
+ * - Only one profile is available,
+ * - A profile was submitted through $_POST,
+ * - Exactly one of the profiles is marked as "exclusive".
+ * If multiple profiles are marked as "exclusive" then no profile will be
+ * selected.
+ *
+ * @param array $profiles
+ *   An associative array of profiles with the machine-readable names as keys.
+ *
+ * @return
+ *   The machine-readable name of the selected profile or NULL if no profile was
+ *   selected.
  */
 function _install_select_profile($profiles) {
   if (sizeof($profiles) == 0) {
@@ -1046,15 +1111,34 @@
       }
     }
   }
+  // Check for a profile marked as "exclusive" and ensure that only one
+  // profile is marked as such.
+  $exclusive_profile = NULL;
+  foreach ($profiles as $profile) {
+    $profile_info = install_profile_info($profile->name);
+    if (!empty($profile_info['exclusive'])) {
+      if (empty($exclusive_profile)) {
+        $exclusive_profile = $profile->name;
+      }
+      else {
+        // We found a second "exclusive" profile. There's no way to choose
+        // between them, so we ignore the property.
+        return;
+      }
+    }
+  }
+  return $exclusive_profile;
 }
 
 /**
- * Form API array definition for the profile selection form.
+ * Form constructor for the profile selection form.
  *
  * @param $form_state
  *   Array of metadata about state of form processing.
  * @param $profile_files
  *   Array of .profile files, as returned from file_scan_directory().
+ *
+ * @ingroup forms
  */
 function install_select_profile_form($form, &$form_state, $profile_files) {
   $profiles = array();
@@ -1231,7 +1315,9 @@
 }
 
 /**
- * Form API array definition for language selection.
+ * Form constructor for the language selection form.
+ *
+ * @ingroup forms
  */
 function install_select_locale_form($form, &$form_state, $locales, $profilename) {
   include_once DRUPAL_ROOT . '/includes/iso.inc';
@@ -1281,7 +1367,7 @@
 }
 
 /**
- * Installation task; load information about the chosen profile.
+ * Loads information about the chosen profile during installation.
  *
  * @param $install_state
  *   An array of information about the current installation state. The loaded
@@ -1290,7 +1376,7 @@
  */
 function install_load_profile(&$install_state) {
   $profile_file = DRUPAL_ROOT . '/profiles/' . $install_state['parameters']['profile'] . '/' . $install_state['parameters']['profile'] . '.profile';
-  if (is_file($profile_file)) {
+  if (file_exists($profile_file)) {
     include_once $profile_file;
     $install_state['profile_info'] = install_profile_info($install_state['parameters']['profile'], $install_state['parameters']['locale']);
   }
@@ -1300,7 +1386,7 @@
 }
 
 /**
- * Installation task; perform a full bootstrap of Drupal.
+ * Performs a full bootstrap of Drupal during installation.
  *
  * @param $install_state
  *   An array of information about the current installation state.
@@ -1310,7 +1396,7 @@
 }
 
 /**
- * Installation task; install required modules via a batch process.
+ * Installs required modules via a batch process.
  *
  * @param $install_state
  *   An array of information about the current installation state.
@@ -1363,7 +1449,7 @@
 }
 
 /**
- * Installation task; import languages via a batch process.
+ * Imports languages via a batch process during installation.
  *
  * @param $install_state
  *   An array of information about the current installation state.
@@ -1397,24 +1483,16 @@
 }
 
 /**
- * Installation task; configure settings for the new site.
+ * Form constructor for a form to configure the new site.
  *
- * @param $form_state
- *   An associative array containing the current state of the form.
  * @param $install_state
  *   An array of information about the current installation state.
  *
- * @return
- *   The form API definition for the site configuration form.
+ * @see install_configure_form_validate()
+ * @see install_configure_form_submit()
+ * @ingroup forms
  */
 function install_configure_form($form, &$form_state, &$install_state) {
-  if (variable_get('site_name', FALSE) || variable_get('site_mail', FALSE)) {
-    // Site already configured: This should never happen, means re-running the
-    // installer, possibly by an attacker after the 'install_task' variable got
-    // accidentally blown somewhere. Stop it now.
-    throw new Exception(install_already_done_error());
-  }
-
   drupal_set_title(st('Configure site'));
 
   // Warn about settings.php permissions risk
@@ -1435,7 +1513,7 @@
   // Add JavaScript time zone detection.
   drupal_add_js('misc/timezone.js');
   // We add these strings as settings because JavaScript translation does not
-  // work on install time.
+  // work during installation.
   drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))), 'setting');
   drupal_add_js('jQuery(function () { Drupal.cleanURLsInstallCheck(); });', 'inline');
   // Add JS to show / hide the 'Email administrator about site updates' elements
@@ -1478,7 +1556,7 @@
 }
 
 /**
- * Installation task; perform final steps and display a 'finished' page.
+ * Finishes importing files at end of installation.
  *
  * @param $install_state
  *   An array of information about the current installation state.
@@ -1494,13 +1572,13 @@
 
   // Flush all caches to ensure that any full bootstraps during the installer
   // do not leave stale cached data, and that any content types or other items
-  // registered by the install profile are registered correctly.
+  // registered by the installation profile are registered correctly.
   drupal_flush_all_caches();
 
   // Remember the profile which was used.
   variable_set('install_profile', drupal_get_profile());
 
-  // Install profiles are always loaded last
+  // Installation profiles are always loaded last
   db_update('system')
     ->fields(array('weight' => 1000))
     ->condition('type', 'module')
@@ -1519,7 +1597,9 @@
 }
 
 /**
- * Batch callback for batch installation of modules.
+ * Implements callback_batch_operation().
+ *
+ * Performs batch installation of modules.
  */
 function _install_module_batch($module, $module_name, &$context) {
   // Install and enable the module right away, so that the module will be
@@ -1532,6 +1612,8 @@
 }
 
 /**
+ * Implements callback_batch_finished().
+ *
  * 'Finished' callback for module installation batch.
  */
 function _install_profile_modules_finished($success, $results, $operations) {
@@ -1665,7 +1747,15 @@
 }
 
 /**
- * Forms API array definition for site configuration.
+ * Form constructor for a site configuration form.
+ *
+ * @param $install_state
+ *   An array of information about the current installation state.
+ *
+ * @see install_configure_form()
+ * @see install_configure_form_validate()
+ * @see install_configure_form_submit()
+ * @ingroup forms
  */
 function _install_configure_form($form, &$form_state, &$install_state) {
   include_once DRUPAL_ROOT . '/includes/locale.inc';
@@ -1778,7 +1868,9 @@
 }
 
 /**
- * Forms API validate for the site configuration form.
+ * Form validation handler for install_configure_form().
+ *
+ * @see install_configure_form_submit()
  */
 function install_configure_form_validate($form, &$form_state) {
   if ($error = user_validate_name($form_state['values']['account']['name'])) {
@@ -1793,7 +1885,9 @@
 }
 
 /**
- * Forms API submit for the site configuration form.
+ * Form submission handler for install_configure_form().
+ *
+ * @see install_configure_form_validate()
  */
 function install_configure_form_submit($form, &$form_state) {
   global $user;
@@ -1816,7 +1910,7 @@
 
   // We precreated user 1 with placeholder values. Let's save the real values.
   $account = user_load(1);
-  $merge_data = array('init' => $form_state['values']['account']['mail'], 'roles' => !empty($account->roles) ? $account->roles : array(), 'status' => 1);
+  $merge_data = array('init' => $form_state['values']['account']['mail'], 'roles' => !empty($account->roles) ? $account->roles : array(), 'status' => 1, 'timezone' => $form_state['values']['date_default_timezone']);
   user_save($account, array_merge($form_state['values']['account'], $merge_data));
   // Load global $user and perform final login tasks.
   $user = user_load(1);
diff -Naur drupal-7.9/includes/install.inc drupal-7.58/includes/install.inc
--- drupal-7.9/includes/install.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/install.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,6 +1,11 @@
 <?php
 
 /**
+* @file
+* API functions for installing modules and themes.
+*/
+
+/**
  * Indicates that a module has not been installed yet.
  */
 define('SCHEMA_UNINSTALLED', -1);
@@ -71,7 +76,7 @@
 define('FILE_NOT_EXECUTABLE', 128);
 
 /**
- * Initialize the update system by loading all installed module's .install files.
+ * Loads .install files for installed modules to initialize the update system.
  */
 function drupal_load_updates() {
   foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) {
@@ -180,11 +185,11 @@
 }
 
 /**
- * Loads the install profile, extracting its defined distribution name.
+ * Loads the installation profile, extracting its defined distribution name.
  *
  * @return
  *   The distribution name defined in the profile's .info file. Defaults to
- *   "Drupal" if none is explicitly provided by the install profile.
+ *   "Drupal" if none is explicitly provided by the installation profile.
  *
  * @see install_profile_info()
  */
@@ -204,11 +209,12 @@
 }
 
 /**
- * Auto detect the base_url with PHP predefined variables.
+ * Detects the base URL using the PHP $_SERVER variables.
  *
  * @param $file
  *   The name of the file calling this function so we can strip it out of
  *   the URI when generating the base_url.
+ *
  * @return
  *   The auto-detected $base_url that should be configured in settings.php
  */
@@ -223,7 +229,7 @@
 }
 
 /**
- * Detect all supported databases that are compiled into PHP.
+ * Detects all supported databases that are compiled into PHP.
  *
  * @return
  *  An array of database types compiled into PHP.
@@ -239,7 +245,7 @@
 }
 
 /**
- * Return all supported database installer objects that are compiled into PHP.
+ * Returns all supported database installer objects that are compiled into PHP.
  *
  * @return
  *  An array of database installer objects compiled into PHP.
@@ -414,7 +420,7 @@
       }
     }
     if (!empty($message)) {
-      $message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
+      $message = 'Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider.' . $message;
       throw new DatabaseTaskException($message);
     }
   }
@@ -576,7 +582,7 @@
 }
 
 /**
- * Replace values in settings.php with values in the submitted array.
+ * Replaces values in settings.php with values in the submitted array.
  *
  * @param $settings
  *   An array of settings that need to be updated.
@@ -647,6 +653,13 @@
     if ($fp && fwrite($fp, $buffer) === FALSE) {
       throw new Exception(st('Failed to modify %settings. Verify the file permissions.', array('%settings' => $settings_file)));
     }
+    else {
+      // The existing settings.php file might have been included already. In
+      // case an opcode cache is enabled, the rewritten contents of the file
+      // will not be reflected in this process. Ensure to invalidate the file
+      // in case an opcode cache is enabled.
+      drupal_clear_opcode_cache(DRUPAL_ROOT . '/' . $settings_file);
+    }
   }
   else {
     throw new Exception(st('Failed to open %settings. Verify the file permissions.', array('%settings' => $default_settings)));
@@ -654,10 +667,11 @@
 }
 
 /**
- * Verify an install profile for installation.
+ * Verifies an installation profile for installation.
  *
  * @param $install_state
  *   An array of information about the current installation state.
+ *
  * @return
  *   The list of modules to install.
  */
@@ -681,8 +695,8 @@
     $present_modules[] = $present_module->name;
   }
 
-  // The install profile is also a module, which needs to be installed after all the other dependencies
-  // have been installed.
+  // The installation profile is also a module, which needs to be installed
+  // after all the other dependencies have been installed.
   $present_modules[] = drupal_get_profile();
 
   // Verify that all of the profile's required modules are present.
@@ -706,7 +720,7 @@
 }
 
 /**
- * Callback to install the system module.
+ * Installs the system module.
  *
  * Separated from the installation of other modules so core system
  * functions can be made available while other modules are installed.
@@ -734,20 +748,28 @@
 }
 
 /**
- * Uninstalls a given list of modules.
+ * Uninstalls a given list of disabled 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.
+ * @param string[] $module_list
+ *   The modules to uninstall. It is the caller's responsibility to ensure that
+ *   all modules in this list have already been disabled before this function
+ *   is called.
+ * @param bool $uninstall_dependents
+ *   (optional) 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.
+ *   Defaults to TRUE.
+ *
+ * @return bool
+ *   Returns TRUE if the operation succeeds or FALSE if it aborts due to an
+ *   unsafe condition, namely, $uninstall_dependents is TRUE and a module in
+ *   $module_list has dependents which are not already uninstalled and not also
+ *   included in $module_list).
  *
- * @return
- *   FALSE if one or more dependent modules are missing from the list, TRUE
- *   otherwise.
+ * @see module_disable()
+ * @see module_enable()
  */
 function drupal_uninstall_modules($module_list = array(), $uninstall_dependents = TRUE) {
   if ($uninstall_dependents) {
@@ -759,7 +781,7 @@
     $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.
+        // This module doesn't exist or is already uninstalled. Skip it.
         unset($module_list[$module]);
         continue;
       }
@@ -792,7 +814,7 @@
   }
 
   if (!empty($module_list)) {
-    // Call hook_module_uninstall to let other modules act
+    // Let other modules react.
     module_invoke_all('modules_uninstalled', $module_list);
   }
 
@@ -800,7 +822,7 @@
 }
 
 /**
- * Verify the state of the specified file.
+ * Verifies the state of the specified file.
  *
  * @param $file
  *   The file to check for.
@@ -808,6 +830,7 @@
  *   An optional bitmask created from various FILE_* constants.
  * @param $type
  *   The type of file. Can be file (default), dir, or link.
+ *
  * @return
  *   TRUE on success or FALSE on failure. A message is set for the latter.
  */
@@ -879,7 +902,7 @@
 }
 
 /**
- * Create a directory with specified permissions.
+ * Creates a directory with the specified permissions.
  *
  * @param $file
  *  The name of the directory to create;
@@ -887,6 +910,7 @@
  *  The permissions of the directory to create.
  * @param $message
  *  (optional) Whether to output messages. Defaults to TRUE.
+ *
  * @return
  *  TRUE/FALSE whether or not the directory was successfully created.
  */
@@ -918,7 +942,7 @@
 }
 
 /**
- * Attempt to fix file permissions.
+ * Attempts to fix file permissions.
  *
  * The general approach here is that, because we do not know the security
  * setup of the webserver, we apply our permission changes to all three
@@ -935,6 +959,7 @@
  *  The desired permissions for the file.
  * @param $message
  *  (optional) Whether to output messages. Defaults to TRUE.
+ *
  * @return
  *  TRUE/FALSE whether or not we were able to fix the file's permissions.
  */
@@ -999,9 +1024,8 @@
   }
 }
 
-
 /**
- * Send the user to a different installer page.
+ * Sends the user to a different installer page.
  *
  * This issues an on-site HTTP redirect. Messages (and errors) are erased.
  *
@@ -1017,7 +1041,69 @@
 }
 
 /**
- * Functional equivalent of t(), used when some systems are not available.
+ * Returns the URL of the current script, with modified query parameters.
+ *
+ * This function can be called by low-level scripts (such as install.php and
+ * update.php) and returns the URL of the current script. Existing query
+ * parameters are preserved by default, but new ones can optionally be merged
+ * in.
+ *
+ * This function is used when the script must maintain certain query parameters
+ * over multiple page requests in order to work correctly. In such cases (for
+ * example, update.php, which requires the 'continue=1' parameter to remain in
+ * the URL throughout the update process if there are any requirement warnings
+ * that need to be bypassed), using this function to generate the URL for links
+ * to the next steps of the script ensures that the links will work correctly.
+ *
+ * @param $query
+ *   (optional) An array of query parameters to merge in to the existing ones.
+ *
+ * @return
+ *   The URL of the current script, with query parameters modified by the
+ *   passed-in $query. The URL is not sanitized, so it still needs to be run
+ *   through check_url() if it will be used as an HTML attribute value.
+ *
+ * @see drupal_requirements_url()
+ */
+function drupal_current_script_url($query = array()) {
+  $uri = $_SERVER['SCRIPT_NAME'];
+  $query = array_merge(drupal_get_query_parameters(), $query);
+  if (!empty($query)) {
+    $uri .= '?' . drupal_http_build_query($query);
+  }
+  return $uri;
+}
+
+/**
+ * Returns a URL for proceeding to the next page after a requirements problem.
+ *
+ * This function can be called by low-level scripts (such as install.php and
+ * update.php) and returns a URL that can be used to attempt to proceed to the
+ * next step of the script.
+ *
+ * @param $severity
+ *   The severity of the requirements problem, as returned by
+ *   drupal_requirements_severity().
+ *
+ * @return
+ *   A URL for attempting to proceed to the next step of the script. The URL is
+ *   not sanitized, so it still needs to be run through check_url() if it will
+ *   be used as an HTML attribute value.
+ *
+ * @see drupal_current_script_url()
+ */
+function drupal_requirements_url($severity) {
+  $query = array();
+  // If there are no errors, only warnings, append 'continue=1' to the URL so
+  // the user can bypass this screen on the next page load.
+  if ($severity == REQUIREMENT_WARNING) {
+    $query['continue'] = 1;
+  }
+  return drupal_current_script_url($query);
+}
+
+/**
+ * Translates a string when some systems are not available.
  *
  * Used during the install process, when database, theme, and localization
  * system is possibly not yet available.
@@ -1056,7 +1142,6 @@
     }
   }
 
-  require_once DRUPAL_ROOT . '/includes/theme.inc';
   // Transform arguments before inserting them
   foreach ($args as $key => $value) {
     switch ($key[0]) {
@@ -1077,12 +1162,12 @@
 }
 
 /**
- * Check an install profile's requirements.
+ * Checks an installation profile's requirements.
  *
  * @param $profile
- *   Name of install profile to check.
+ *   Name of installation profile to check.
  * @return
- *   Array of the install profile's requirements.
+ *   Array of the installation profile's requirements.
  */
 function drupal_check_profile($profile) {
   include_once DRUPAL_ROOT . '/includes/file.inc';
@@ -1108,11 +1193,12 @@
 }
 
 /**
- * Extract highest severity from requirements array.
+ * Extracts the highest severity from the requirements array.
  *
  * @param $requirements
  *   An array of requirements, in the same format as is returned by
  *   hook_requirements().
+ *
  * @return
  *   The highest severity in the array.
  */
@@ -1127,12 +1213,13 @@
 }
 
 /**
- * Check a module's requirements.
+ * Checks a module's requirements.
  *
  * @param $module
  *   Machine name of module to check.
+ *
  * @return
- *   TRUE/FALSE depending on the requirements are in place.
+ *   TRUE or FALSE, depending on whether the requirements are met.
  */
 function drupal_check_module($module) {
   module_load_install($module);
@@ -1157,19 +1244,26 @@
 }
 
 /**
- * Retrieve info about an install profile from its .info file.
+ * Retrieves information about an installation profile from its .info file.
  *
  * The information stored in a profile .info file is similar to that stored in
  * a normal Drupal module .info file. For example:
- * - name: The real name of the install profile for display purposes.
+ * - name: The real name of the installation profile for display purposes.
  * - description: A brief description of the profile.
- * - dependencies: An array of shortnames of other modules this install profile requires.
+ * - dependencies: An array of shortnames of other modules that this install
+ *   profile requires.
  *
  * Additional, less commonly-used information that can appear in a profile.info
  * file but not in a normal Drupal module .info file includes:
  * - distribution_name: The name of the Drupal distribution that is being
  *   installed, to be shown throughout the installation process. Defaults to
  *   'Drupal'.
+ * - exclusive: If the install profile is intended to be the only eligible
+ *   choice in a distribution, setting exclusive = TRUE will auto-select it
+ *   during installation, and the install profile selection screen will be
+ *   skipped. If more than one profile is found where exclusive = TRUE then
+ *   this property will have no effect and the profile selection screen will
+ *   be shown as normal with all available profiles shown.
  *
  * Note that this function does an expensive file system scan to get info file
  * information for dependencies. If you only need information from the info
diff -Naur drupal-7.9/includes/iso.inc drupal-7.58/includes/iso.inc
--- drupal-7.9/includes/iso.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/iso.inc	2018-03-27 21:28:19.000000000 +0200
@@ -53,6 +53,7 @@
     'BM' => $t('Bermuda'),
     'BN' => $t('Brunei'),
     'BO' => $t('Bolivia'),
+    'BQ' => $t('Caribbean Netherlands'),
     'BR' => $t('Brazil'),
     'BS' => $t('Bahamas'),
     'BT' => $t('Bhutan'),
@@ -75,6 +76,7 @@
     'CR' => $t('Costa Rica'),
     'CU' => $t('Cuba'),
     'CV' => $t('Cape Verde'),
+    'CW' => $t('Curaçao'),
     'CX' => $t('Christmas Island'),
     'CY' => $t('Cyprus'),
     'CZ' => $t('Czech Republic'),
@@ -229,8 +231,10 @@
     'SN' => $t('Senegal'),
     'SO' => $t('Somalia'),
     'SR' => $t('Suriname'),
+    'SS' => $t('South Sudan'),
     'ST' => $t('Sao Tome and Principe'),
     'SV' => $t('El Salvador'),
+    'SX' => $t('Sint Maarten'),
     'SY' => $t('Syria'),
     'SZ' => $t('Swaziland'),
     'TC' => $t('Turks and Caicos Islands'),
@@ -460,7 +464,7 @@
     'tt' => array('Tatar', 'Tatarça'),
     'tw' => array('Twi'),
     'ty' => array('Tahitian'),
-    'ug' => array('Uighur'),
+    'ug' => array('Uyghur'),
     'uk' => array('Ukrainian', 'Українська'),
     'ur' => array('Urdu', /* Left-to-right marker "‭" */ 'اردو', LANGUAGE_RTL),
     'uz' => array('Uzbek', "o'zbek"),
diff -Naur drupal-7.9/includes/json-encode.inc drupal-7.58/includes/json-encode.inc
--- drupal-7.9/includes/json-encode.inc	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/includes/json-encode.inc	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Provides a helper to properly encode HTML-safe JSON prior to PHP 5.3.0.
+ */
+
+/**
+ * Encodes a PHP variable to HTML-safe JSON for PHP versions below 5.3.0.
+ *
+ * @see drupal_json_encode()
+ */
+function drupal_json_encode_helper($var) {
+  switch (gettype($var)) {
+    case 'boolean':
+      return $var ? 'true' : 'false'; // Lowercase necessary!
+
+    case 'integer':
+    case 'double':
+      return $var;
+
+    case 'resource':
+    case 'string':
+      // Always use Unicode escape sequences (\u0022) over JSON escape
+      // sequences (\") to prevent browsers interpreting these as
+      // special characters.
+      $replace_pairs = array(
+        // ", \ and U+0000 - U+001F must be escaped according to RFC 4627.
+        '\\' => '\u005C',
+        '"' => '\u0022',
+        "\x00" => '\u0000',
+        "\x01" => '\u0001',
+        "\x02" => '\u0002',
+        "\x03" => '\u0003',
+        "\x04" => '\u0004',
+        "\x05" => '\u0005',
+        "\x06" => '\u0006',
+        "\x07" => '\u0007',
+        "\x08" => '\u0008',
+        "\x09" => '\u0009',
+        "\x0a" => '\u000A',
+        "\x0b" => '\u000B',
+        "\x0c" => '\u000C',
+        "\x0d" => '\u000D',
+        "\x0e" => '\u000E',
+        "\x0f" => '\u000F',
+        "\x10" => '\u0010',
+        "\x11" => '\u0011',
+        "\x12" => '\u0012',
+        "\x13" => '\u0013',
+        "\x14" => '\u0014',
+        "\x15" => '\u0015',
+        "\x16" => '\u0016',
+        "\x17" => '\u0017',
+        "\x18" => '\u0018',
+        "\x19" => '\u0019',
+        "\x1a" => '\u001A',
+        "\x1b" => '\u001B',
+        "\x1c" => '\u001C',
+        "\x1d" => '\u001D',
+        "\x1e" => '\u001E',
+        "\x1f" => '\u001F',
+        // Prevent browsers from interpreting these as as special.
+        "'" => '\u0027',
+        '<' => '\u003C',
+        '>' => '\u003E',
+        '&' => '\u0026',
+        // Prevent browsers from interpreting the solidus as special and
+        // non-compliant JSON parsers from interpreting // as a comment.
+        '/' => '\u002F',
+        // While these are allowed unescaped according to ECMA-262, section
+        // 15.12.2, they cause problems in some JSON parsers.
+        "\xe2\x80\xa8" => '\u2028', // U+2028, Line Separator.
+        "\xe2\x80\xa9" => '\u2029', // U+2029, Paragraph Separator.
+      );
+
+      return '"' . strtr($var, $replace_pairs) . '"';
+
+    case 'array':
+      // Arrays in JSON can't be associative. If the array is empty or if it
+      // has sequential whole number keys starting with 0, it's not associative
+      // so we can go ahead and convert it as an array.
+      if (empty($var) || array_keys($var) === range(0, sizeof($var) - 1)) {
+        $output = array();
+        foreach ($var as $v) {
+          $output[] = drupal_json_encode_helper($v);
+        }
+        return '[ ' . implode(', ', $output) . ' ]';
+      }
+      // Otherwise, fall through to convert the array as an object.
+
+    case 'object':
+      $output = array();
+      foreach ($var as $k => $v) {
+        $output[] = drupal_json_encode_helper(strval($k)) . ':' . drupal_json_encode_helper($v);
+      }
+      return '{' . implode(', ', $output) . '}';
+
+    default:
+      return 'null';
+  }
+}
diff -Naur drupal-7.9/includes/language.inc drupal-7.58/includes/language.inc
--- drupal-7.9/includes/language.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/language.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,7 +2,9 @@
 
 /**
  * @file
- * Multiple language handling functionality.
+ * Language Negotiation API.
+ *
+ * @see http://drupal.org/node/1497272
  */
 
 /**
@@ -11,7 +13,95 @@
 define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default');
 
 /**
- * Return all the defined language types.
+ * @defgroup language_negotiation Language Negotiation API functionality
+ * @{
+ * Functions to customize the language types and the negotiation process.
+ *
+ * The language negotiation API is based on two major concepts:
+ * - Language types: types of translatable data (the types of data that a user
+ *   can view or request).
+ * - Language negotiation providers: functions for determining which language to
+ *   use to present a particular piece of data to the user.
+ * Both language types and language negotiation providers are customizable.
+ *
+ * Drupal defines three built-in language types:
+ * - Interface language: The page's main language, used to present translated
+ *   user interface elements such as titles, labels, help text, and messages.
+ * - Content language: The language used to present content that is available
+ *   in more than one language (see
+ *   @link field_language Field Language API @endlink for details).
+ * - URL language: The language associated with URLs. When generating a URL,
+ *   this value will be used by url() as a default if no explicit preference is
+ *   provided.
+ * Modules can define additional language types through
+ * hook_language_types_info(), and alter existing language type definitions
+ * through hook_language_types_info_alter().
+ *
+ * Language types may be configurable or fixed. The language negotiation
+ * providers associated with a configurable language type can be explicitly
+ * set through the user interface. A fixed language type has predetermined
+ * (module-defined) language negotiation settings and, thus, does not appear in
+ * the configuration page. Here is a code snippet that makes the content
+ * language (which by default inherits the interface language's values)
+ * configurable:
+ * @code
+ * function mymodule_language_types_info_alter(&$language_types) {
+ *   unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+ * }
+ * @endcode
+ *
+ * Every language type can have a different set of language negotiation
+ * providers assigned to it. Different language types often share the same
+ * language negotiation settings, but they can have independent settings if
+ * needed. If two language types are configured the same way, their language
+ * switcher configuration will be functionally identical and the same settings
+ * will act on both language types.
+ *
+ * Drupal defines the following built-in language negotiation providers:
+ * - URL: Determine the language from the URL (path prefix or domain).
+ * - Session: Determine the language from a request/session parameter.
+ * - User: Follow the user's language preference.
+ * - Browser: Determine the language from the browser's language settings.
+ * - Default language: Use the default site language.
+ * Language negotiation providers are simple callback functions that implement a
+ * particular logic to return a language code. For instance, the URL provider
+ * searches for a valid path prefix or domain name in the current request URL.
+ * If a language negotiation provider does not return a valid language code, the
+ * next provider associated to the language type (based on provider weight) is
+ * invoked.
+ *
+ * Modules can define additional language negotiation providers through
+ * hook_language_negotiation_info(), and alter existing providers through
+ * hook_language_negotiation_info_alter(). Here is an example snippet that lets
+ * path prefixes be ignored for administrative paths:
+ * @code
+ * function mymodule_language_negotiation_info_alter(&$negotiation_info) {
+ *   // Replace the core function with our own function.
+ *   module_load_include('language', 'inc', 'language.negotiation');
+ *   $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['language'] = 'mymodule_from_url';
+ *   $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module';
+ * }
+ *
+ * function mymodule_from_url($languages) {
+ *   // Use the core URL language negotiation provider to get a valid language
+ *   // code.
+ *   module_load_include('language', 'inc', 'language.negotiation');
+ *   $langcode = language_from_url($languages);
+ *
+ *   // If we are on an administrative path, override with the default language.
+ *   if (isset($_GET['q']) && strtok($_GET['q'], '/') == 'admin') {
+ *     return language_default()->langcode;
+ *   }
+ *   return $langcode;
+ * }
+ * @endcode
+ *
+ * For more information, see
+ * @link http://drupal.org/node/1497272 Language Negotiation API @endlink
+ */
+
+/**
+ * Returns all the defined language types.
  *
  * @return
  *   An array of language type names. The name will be used as the global
@@ -30,11 +120,11 @@
 }
 
 /**
- * Return only the configurable language types.
+ * Returns only the configurable language types.
  *
  * A language type maybe configurable or fixed. A fixed language type is a type
- * whose negotiation values are unchangeable and defined while defining the
- * language type itself.
+ * whose language negotiation providers are module-defined and not altered
+ * through the user interface.
  *
  * @param $stored
  *   Optional. By default retrieves values from the 'language_types' variable to
@@ -68,7 +158,7 @@
 }
 
 /**
- * Disable the given language types.
+ * Disables the given language types.
  *
  * @param $types
  *   An array of language types.
@@ -122,16 +212,17 @@
 }
 
 /**
- * Check if a language provider is enabled.
+ * Checks whether a language negotiation provider is enabled for a language type.
  *
  * This has two possible behaviors:
  *  - If $provider_id is given return its ID if enabled, FALSE otherwise.
- *  - If no ID is passed the first enabled language provider is returned.
+ *  - If no ID is passed the first enabled language negotiation provider is
+ *    returned.
  *
  * @param $type
- *   The language negotiation type.
+ *   The language negotiation provider type.
  * @param $provider_id
- *   The language provider ID.
+ *   The language negotiation provider ID.
  *
  * @return
  *   The provider ID if it is enabled, FALSE otherwise.
@@ -155,14 +246,13 @@
 }
 
 /**
- * Check if the given language provider is enabled for any configurable language
- * type.
+ * Checks if the language negotiation provider is enabled for any language type.
  *
  * @param $provider_id
- *   The language provider ID.
+ *   The language negotiation provider ID.
  *
  * @return
- *   TRUE if there is at least one language type for which the give language
+ *   TRUE if there is at least one language type for which the given language
  *   provider is enabled, FALSE otherwise.
  */
 function language_negotiation_get_any($provider_id) {
@@ -176,7 +266,7 @@
 }
 
 /**
- * Return the language switch links for the given language.
+ * Returns the language switch links for the given language.
  *
  * @param $type
  *   The language negotiation type.
@@ -190,6 +280,11 @@
   $links = FALSE;
   $negotiation = variable_get("language_negotiation_$type", array());
 
+  // Only get the languages if we have more than one.
+  if (count(language_list()) >= 2) {
+    $language = language_initialize($type);
+  }
+
   foreach ($negotiation as $id => $provider) {
     if (isset($provider['callbacks']['switcher'])) {
       if (isset($provider['file'])) {
@@ -199,6 +294,12 @@
       $callback = $provider['callbacks']['switcher'];
       $result = $callback($type, $path);
 
+      // Add support for WCAG 2.0's Language of Parts to add language identifiers.
+      // http://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html
+      foreach ($result as $langcode => $link) {
+        $result[$langcode]['attributes']['xml:lang'] = $langcode;
+      }
+
       if (!empty($result)) {
         // Allow modules to provide translations for specific links.
         drupal_alter('language_switch_links', $result, $type, $path);
@@ -212,7 +313,7 @@
 }
 
 /**
- * Updates language configuration to remove any language provider that is no longer defined.
+ * Removes any unused language negotiation providers from the configuration.
  */
 function language_negotiation_purge() {
   // Ensure that we are getting the defined language negotiation information. An
@@ -235,12 +336,12 @@
 }
 
 /**
- * Save a list of language providers.
+ * Saves a list of language negotiation providers.
  *
  * @param $type
  *   The language negotiation type.
  * @param $language_providers
- *   An array of language provider weights keyed by id.
+ *   An array of language negotiation provider weights keyed by provider ID.
  *   @see language_provider_weight()
  */
 function language_negotiation_set($type, $language_providers) {
@@ -266,7 +367,7 @@
       // If the provider does not express any preference about types, make it
       // available for any configurable type.
       $types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
-      // Check if the provider is defined and has the right type.
+      // Check whether the provider is defined and has the right type.
       if (isset($types[$type])) {
         $provider_data = array();
         foreach ($provider_fields as $field) {
@@ -283,10 +384,10 @@
 }
 
 /**
- * Return all the defined language providers.
+ * Returns all the defined language negotiation providers.
  *
  * @return
- *   An array of language providers.
+ *   An array of language negotiation providers.
  */
 function language_negotiation_info() {
   $language_providers = &drupal_static(__FUNCTION__);
@@ -295,7 +396,7 @@
     // Collect all the module-defined language negotiation providers.
     $language_providers = module_invoke_all('language_negotiation_info');
 
-    // Add the default language provider.
+    // Add the default language negotiation provider.
     $language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
       'callbacks' => array('language' => 'language_from_default'),
       'weight' => 10,
@@ -303,7 +404,7 @@
       'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
     );
 
-    // Let other modules alter the list of language providers.
+    // Let other modules alter the list of language negotiation providers.
     drupal_alter('language_negotiation_info', $language_providers);
   }
 
@@ -311,16 +412,17 @@
 }
 
 /**
- * Helper function used to cache the language providers results.
+ * Helper function used to cache the language negotiation providers results.
  *
  * @param $provider_id
- *   The language provider ID.
+ *   The language negotiation provider's identifier.
  * @param $provider
- *   The language provider to be invoked. If not passed it will be explicitly
- *   loaded through language_negotiation_info().
+ *   (optional) An associative array of information about the provider to be
+ *   invoked (see hook_language_negotiation_info() for details). If not passed
+ *   in, it will be loaded through language_negotiation_info().
  *
  * @return
- *   The language provider's return value.
+ *   A language object representing the language chosen by the provider.
  */
 function language_provider_invoke($provider_id, $provider = NULL) {
   $results = &drupal_static(__FUNCTION__);
@@ -341,22 +443,26 @@
       require_once DRUPAL_ROOT . '/' . $provider['file'];
     }
 
-    // If the language provider has no cache preference or this is satisfied
-    // we can execute the callback.
+    // If the language negotiation provider has no cache preference or this is
+    // satisfied we can execute the callback.
     $cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
     $callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
     $langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
     $results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
   }
 
-  return $results[$provider_id];
+  // Since objects are resources, we need to return a clone to prevent the
+  // language negotiation provider cache from being unintentionally altered. The
+  // same providers might be used with different language types based on
+  // configuration.
+  return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id];
 }
 
 /**
- * Return the passed language provider weight or a default value.
+ * Returns the passed language negotiation provider weight or a default value.
  *
  * @param $provider
- *   A language provider data structure.
+ *   A language negotiation provider data structure.
  *
  * @return
  *   A numeric weight.
@@ -367,32 +473,35 @@
 }
 
 /**
- * Choose a language for the given type based on language negotiation settings.
+ * Chooses a language based on language negotiation provider settings.
  *
  * @param $type
- *   The language type.
+ *   The language type key to find the language for.
  *
  * @return
  *   The negotiated language object.
  */
 function language_initialize($type) {
-  // Execute the language providers in the order they were set up and return the
+  // Execute the language negotiation providers in the order they were set up and return the
   // first valid language found.
   $negotiation = variable_get("language_negotiation_$type", array());
 
-  foreach ($negotiation as $id => $provider) {
-    $language = language_provider_invoke($id, $provider);
+  foreach ($negotiation as $provider_id => $provider) {
+    $language = language_provider_invoke($provider_id, $provider);
     if ($language) {
+      $language->provider = $provider_id;
       return $language;
     }
   }
 
   // If no other language was found use the default one.
-  return language_default();
+  $language = language_default();
+  $language->provider = LANGUAGE_NEGOTIATION_DEFAULT;
+  return $language;
 }
 
 /**
- * Default language provider.
+ * Returns the default language negotiation provider.
  *
  * @return
  *   The default language code.
@@ -402,10 +511,10 @@
 }
 
 /**
- * Split the given path into prefix and actual path.
+ * Splits the given path into prefix and actual path.
  *
- * Parse the given path and return the language object identified by the
- * prefix and the actual path.
+ * Parse the given path and return the language object identified by the prefix
+ * and the actual path.
  *
  * @param $path
  *   The path to split.
@@ -434,10 +543,10 @@
 }
 
 /**
- * Return the possible fallback languages ordered by language weight.
+ * Returns the possible fallback languages ordered by language weight.
  *
  * @param
- *   The language type.
+ *   (optional) The language type. Defaults to LANGUAGE_TYPE_CONTENT.
  *
  * @return
  *   An array of language codes.
@@ -465,3 +574,7 @@
 
   return $fallback_candidates;
 }
+
+/**
+ * @} End of "language_negotiation"
+ */
diff -Naur drupal-7.9/includes/locale.inc drupal-7.58/includes/locale.inc
--- drupal-7.9/includes/locale.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/locale.inc	2018-03-27 21:28:19.000000000 +0200
@@ -43,6 +43,36 @@
 define('LOCALE_JS_STRING', '(?:(?:\'(?:\\\\\'|[^\'])*\'|"(?:\\\\"|[^"])*")(?:\s*\+\s*)?)+');
 
 /**
+ * Regular expression pattern used to match simple JS object literal.
+ *
+ * This pattern matches a basic JS object, but will fail on an object with
+ * nested objects. Used in JS file parsing for string arg processing.
+ */
+define('LOCALE_JS_OBJECT', '\{.*?\}');
+
+/**
+ * Regular expression to match an object containing a key 'context'.
+ *
+ * Pattern to match a JS object containing a 'context key' with a string value,
+ * which is captured. Will fail if there are nested objects.
+ */
+define('LOCALE_JS_OBJECT_CONTEXT', '
+  \{              # match object literal start
+  .*?             # match anything, non-greedy
+  (?:             # match a form of "context"
+    \'context\'
+    |
+    "context"
+    |
+    context
+  )
+  \s*:\s*         # match key-value separator ":"
+  (' . LOCALE_JS_STRING . ')  # match context string
+  .*?             # match anything, non-greedy
+  \}              # match end of object literal
+');
+
+/**
  * Translation import mode overwriting all existing translations
  * if new translated version available.
  */
@@ -111,7 +141,7 @@
   //   language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
   // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5"
   $browser_langcodes = array();
-  if (preg_match_all('@([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']), $matches, PREG_SET_ORDER)) {
+  if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']), $matches, PREG_SET_ORDER)) {
     foreach ($matches as $match) {
       // We can safely use strtolower() here, tags are ASCII.
       // RFC2616 mandates that the decimal part is no more than three digits,
@@ -249,6 +279,12 @@
       break;
 
     case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN:
+      // Get only the host, not the port.
+      $http_host= $_SERVER['HTTP_HOST'];
+      if (strpos($http_host, ':') !== FALSE) {
+        $http_host_tmp = explode(':', $http_host);
+        $http_host = current($http_host_tmp);
+      }
       foreach ($languages as $language) {
         // Skip check if the language doesn't have a domain.
         if ($language->domain) {
@@ -256,7 +292,7 @@
           // Remove protocol and add http:// so parse_url works
           $host = 'http://' . str_replace(array('http://', 'https://'), '', $language->domain);
           $host = parse_url($host, PHP_URL_HOST);
-          if ($_SERVER['HTTP_HOST'] == $host) {
+          if ($http_host == $host) {
             $language_url = $language->language;
             break;
           }
@@ -362,7 +398,7 @@
       $links[$langcode]['query'][$param] = $langcode;
     }
     else {
-      $links[$langcode]['attributes']['class'][] = ' session-active';
+      $links[$langcode]['attributes']['class'][] = 'session-active';
     }
   }
 
@@ -399,9 +435,48 @@
     switch (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX)) {
       case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN:
         if ($options['language']->domain) {
+          // Save the original base URL. If it contains a port, we need to
+          // retain it below.
+          if (!empty($options['base_url'])) {
+            // The colon in the URL scheme messes up the port checking below.
+            $normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']);
+          }
+
           // Ask for an absolute URL with our modified base_url.
+          global $is_https;
+          $url_scheme = ($is_https) ? 'https://' : 'http://';
           $options['absolute'] = TRUE;
-          $options['base_url'] = $options['language']->domain;
+
+          // Take the domain without ports or protocols so we can apply the
+          // protocol needed. The setting might include a protocol.
+          // This is changed in Drupal 8 but we need to keep backwards
+          // compatibility for Drupal 7.
+          $host = 'http://' . str_replace(array('http://', 'https://'), '', $options['language']->domain);
+          $host = parse_url($host, PHP_URL_HOST);
+
+          // Apply the appropriate protocol to the URL.
+          $options['base_url'] = $url_scheme . $host;
+
+          // In case either the original base URL or the HTTP host contains a
+          // port, retain it.
+          $http_host = $_SERVER['HTTP_HOST'];
+          if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) {
+            list($host, $port) = explode(':', $normalized_base_url);
+            $options['base_url'] .= ':' . $port;
+          }
+          elseif (strpos($http_host, ':') !== FALSE) {
+            list($host, $port) = explode(':', $http_host);
+            $options['base_url'] .= ':' . $port;
+          }
+
+          if (isset($options['https']) && variable_get('https', FALSE)) {
+            if ($options['https'] === TRUE) {
+              $options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
+            }
+            elseif ($options['https'] === FALSE) {
+              $options['base_url'] = str_replace('https://', 'http://', $options['base_url']);
+            }
+          }
         }
         break;
 
@@ -468,6 +543,22 @@
  * possible attack vector (img).
  */
 function locale_string_is_safe($string) {
+  // Some strings have tokens in them. For tokens in the first part of href or
+  // src HTML attributes, filter_xss() removes part of the token, the part
+  // before the first colon.  filter_xss() assumes it could be an attempt to
+  // inject javascript. When filter_xss() removes part of tokens, it causes the
+  // string to not be translatable when it should be translatable. See
+  // LocaleStringIsSafeTest::testLocaleStringIsSafe().
+  //
+  // We can recognize tokens since they are wrapped with brackets and are only
+  // composed of alphanumeric characters, colon, underscore, and dashes. We can
+  // be sure these strings are safe to strip out before the string is checked in
+  // filter_xss() because no dangerous javascript will match that pattern.
+  //
+  // @todo Do not strip out the token. Fix filter_xss() to not incorrectly
+  //   alter the string. https://www.drupal.org/node/2372127
+  $string = preg_replace('/\[[a-z0-9_-]+(:[a-z0-9_-]+)+\]/i', '', $string);
+
   return decode_entities($string) == decode_entities(filter_xss($string, array('a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'ins', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'ul', 'var')));
 }
 
@@ -576,9 +667,6 @@
  *   translations).
  */
 function _locale_import_po($file, $langcode, $mode, $group = NULL) {
-  // Try to allocate enough time to parse and import the data.
-  drupal_set_time_limit(240);
-
   // Check if we have the language already in the database.
   if (!db_query("SELECT COUNT(language) FROM {languages} WHERE language = :language", array(':language' => $langcode))->fetchField()) {
     drupal_set_message(t('The language selected for import is not supported.'), 'error');
@@ -662,6 +750,12 @@
   $lineno = 0;
 
   while (!feof($fd)) {
+    // Refresh the time limit every 10 parsed rows to ensure there is always
+    // enough time to import the data for large PO files.
+    if (!($lineno % 10)) {
+      drupal_set_time_limit(30);
+    }
+
     // A line should not be longer than 10 * 1024.
     $line = fgets($fd, 10 * 1024);
 
@@ -948,7 +1042,7 @@
           // data untouched or if we don't have an existing plural formula.
           $header = _locale_import_parse_header($value['msgstr']);
 
-          // Get the plural formula and update in database.
+          // Get and store the plural formula if available.
           if (isset($header["Plural-Forms"]) && $p = _locale_import_parse_plural_forms($header["Plural-Forms"], $file->uri)) {
             list($nplurals, $plural) = $p;
             db_update('languages')
@@ -959,15 +1053,6 @@
               ->condition('language', $lang)
               ->execute();
           }
-          else {
-            db_update('languages')
-              ->fields(array(
-                'plurals' => 0,
-                'formula' => '',
-              ))
-              ->condition('language', $lang)
-              ->execute();
-          }
         }
         $header_done = TRUE;
       }
@@ -1447,6 +1532,9 @@
     [^\w]Drupal\s*\.\s*t\s*                       # match "Drupal.t" with whitespace
     \(\s*                                         # match "(" argument list start
     (' . LOCALE_JS_STRING . ')\s*                 # capture string argument
+    (?:,\s*' . LOCALE_JS_OBJECT . '\s*            # optionally capture str args
+      (?:,\s*' . LOCALE_JS_OBJECT_CONTEXT . '\s*) # optionally capture context
+    ?)?                                           # close optional args
     [,\)]                                         # match ")" or "," to finish
     ~sx', $file, $t_matches);
 
@@ -1474,55 +1562,73 @@
         (?:\s*\+\s*)?             # match "+" with possible whitespace, for str concat
       )+                          # match multiple because we supports concatenating strs
     )\s*                          # end capturing of plural string argument
+    (?:,\s*' . LOCALE_JS_OBJECT . '\s*          # optionally capture string args
+      (?:,\s*' . LOCALE_JS_OBJECT_CONTEXT . '\s*)?  # optionally capture context
+    )?
     [,\)]
     ~sx', $file, $plural_matches);
 
+  $matches = array();
+
+  // Add strings from Drupal.t().
+  foreach ($t_matches[1] as $key => $string) {
+    $matches[] = array(
+      'string'  => $string,
+      'context' => $t_matches[2][$key],
+    );
+  }
 
-  // Loop through all matches and process them.
-  $all_matches = array_merge($plural_matches[1], $t_matches[1]);
-  foreach ($all_matches as $key => $string) {
-    $strings = array($string);
+  // Add string from Drupal.formatPlural().
+  foreach ($plural_matches[1] as $key => $string) {
+    $matches[] = array(
+      'string'  => $string,
+      'context' => $plural_matches[3][$key],
+    );
 
     // If there is also a plural version of this string, add it to the strings array.
     if (isset($plural_matches[2][$key])) {
-      $strings[] = $plural_matches[2][$key];
+      $matches[] = array(
+        'string'  => $plural_matches[2][$key],
+        'context' => $plural_matches[3][$key],
+      );
     }
+  }
 
-    foreach ($strings as $key => $string) {
-      // Remove the quotes and string concatenations from the string.
-      $string = implode('', preg_split('~(?<!\\\\)[\'"]\s*\+\s*[\'"]~s', substr($string, 1, -1)));
-
-      $source = db_query("SELECT lid, location FROM {locales_source} WHERE source = :source AND textgroup = 'default'", array(':source' => $string))->fetchObject();
-      if ($source) {
-        // We already have this source string and now have to add the location
-        // to the location column, if this file is not yet present in there.
-        $locations = preg_split('~\s*;\s*~', $source->location);
-
-        if (!in_array($filepath, $locations)) {
-          $locations[] = $filepath;
-          $locations = implode('; ', $locations);
-
-          // Save the new locations string to the database.
-          db_update('locales_source')
-            ->fields(array(
-              'location' => $locations,
-            ))
-            ->condition('lid', $source->lid)
-            ->execute();
-        }
-      }
-      else {
-        // We don't have the source string yet, thus we insert it into the database.
-        db_insert('locales_source')
+  foreach ($matches as $key => $match) {
+    // Remove the quotes and string concatenations from the string.
+    $string = implode('', preg_split('~(?<!\\\\)[\'"]\s*\+\s*[\'"]~s', substr($match['string'], 1, -1)));
+    $context = implode('', preg_split('~(?<!\\\\)[\'"]\s*\+\s*[\'"]~s', substr($match['context'], 1, -1)));
+
+    $source = db_query("SELECT lid, location FROM {locales_source} WHERE source = :source AND context = :context AND textgroup = 'default'", array(':source' => $string, ':context' => $context))->fetchObject();
+    if ($source) {
+      // We already have this source string and now have to add the location
+      // to the location column, if this file is not yet present in there.
+      $locations = preg_split('~\s*;\s*~', $source->location);
+
+      if (!in_array($filepath, $locations)) {
+        $locations[] = $filepath;
+        $locations = implode('; ', $locations);
+
+        // Save the new locations string to the database.
+        db_update('locales_source')
           ->fields(array(
-            'location' => $filepath,
-            'source' => $string,
-            'context' => '',
-            'textgroup' => 'default',
+            'location' => $locations,
           ))
+          ->condition('lid', $source->lid)
           ->execute();
       }
     }
+    else {
+      // We don't have the source string yet, thus we insert it into the database.
+      db_insert('locales_source')
+        ->fields(array(
+          'location' => $filepath,
+          'source' => $string,
+          'context' => $context,
+          'textgroup' => 'default',
+        ))
+        ->execute();
+    }
   }
 }
 
@@ -1793,7 +1899,16 @@
   }
 
   $sql_query = db_select('locales_source', 's');
-  $sql_query->leftJoin('locales_target', 't', 't.lid = s.lid');
+
+  $limit_language = NULL;
+  if ($query['language'] != 'en' && $query['language'] != 'all') {
+    $sql_query->leftJoin('locales_target', 't', "t.lid = s.lid AND t.language = :langcode", array(':langcode' => $query['language']));
+    $limit_language = $query['language'];
+  }
+  else {
+    $sql_query->leftJoin('locales_target', 't', 't.lid = s.lid');
+  }
+
   $sql_query->fields('s', array('source', 'location', 'context', 'lid', 'textgroup'));
   $sql_query->fields('t', array('translation', 'language'));
 
@@ -1822,12 +1937,6 @@
       break;
   }
 
-  $limit_language = NULL;
-  if ($query['language'] != 'en' && $query['language'] != 'all') {
-    $sql_query->condition('language', $query['language']);
-    $limit_language = $query['language'];
-  }
-
   // Add a condition on the text group.
   if (!empty($query['group']) && $query['group'] != 'all') {
     $sql_query->condition('s.textgroup', $query['group']);
@@ -1861,7 +1970,7 @@
       $groups[$string['group']],
       array('data' => check_plain(truncate_utf8($string['source'], 150, FALSE, TRUE)) . '<br /><small>' . $string['location'] . '</small>'),
       $string['context'],
-      array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
+      array('data' => _locale_translate_language_list($string, $limit_language), 'align' => 'center'),
       array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
       array('data' => l(t('delete'), "admin/config/regional/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
     );
@@ -1942,11 +2051,11 @@
 
   // Construct the array for JavaScript translations.
   // Only add strings with a translation to the translations array.
-  $result = db_query("SELECT s.lid, s.source, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language WHERE s.location LIKE '%.js%' AND s.textgroup = :textgroup", array(':language' => $language->language, ':textgroup' => 'default'));
+  $result = db_query("SELECT s.lid, s.source, s.context, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language WHERE s.location LIKE '%.js%' AND s.textgroup = :textgroup", array(':language' => $language->language, ':textgroup' => 'default'));
 
   $translations = array();
   foreach ($result as $data) {
-    $translations[$data->source] = $data->translation;
+    $translations[$data->context][$data->source] = $data->translation;
   }
 
   // Construct the JavaScript file, if there are translations.
@@ -2056,16 +2165,21 @@
 /**
  * List languages in search result table
  */
-function _locale_translate_language_list($translation, $limit_language) {
+function _locale_translate_language_list($string, $limit_language) {
   // Add CSS.
   drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
 
+  // Include both translated and not yet translated target languages in the
+  // list. The source language is English for built-in strings and the default
+  // language for other strings.
   $languages = language_list();
-  unset($languages['en']);
+  $default = language_default();
+  $omit = $string['group'] == 'default' ? 'en' : $default->language;
+  unset($languages[$omit]);
   $output = '';
   foreach ($languages as $langcode => $language) {
     if (!$limit_language || $limit_language == $langcode) {
-      $output .= (!empty($translation[$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
+      $output .= (!empty($string['languages'][$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
     }
   }
 
@@ -2231,6 +2345,8 @@
 }
 
 /**
+ * Implements callback_batch_operation().
+ *
  * Perform interface translation import as a batch step.
  *
  * @param $filepath
@@ -2242,13 +2358,15 @@
   // The filename is either {langcode}.po or {prefix}.{langcode}.po, so
   // we can extract the language code to use for the import from the end.
   if (preg_match('!(/|\.)([^\./]+)\.po$!', $filepath, $langcode)) {
-    $file = (object) array('filename' => basename($filepath), 'uri' => $filepath);
+    $file = (object) array('filename' => drupal_basename($filepath), 'uri' => $filepath);
     _locale_import_read_po('db-store', $file, LOCALE_IMPORT_KEEP, $langcode[2]);
     $context['results'][] = $filepath;
   }
 }
 
 /**
+ * Implements callback_batch_finished().
+ *
  * Finished callback of system page locale import batch.
  * Inform the user of translation files imported.
  */
@@ -2259,6 +2377,8 @@
 }
 
 /**
+ * Implements callback_batch_finished().
+ *
  * Finished callback of language addition locale import batch.
  * Inform the user of translation files imported.
  */
diff -Naur drupal-7.9/includes/lock.inc drupal-7.58/includes/lock.inc
--- drupal-7.9/includes/lock.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/lock.inc	2018-03-27 21:28:19.000000000 +0200
@@ -92,7 +92,7 @@
  * Acquire (or renew) a lock, but do not block if it fails.
  *
  * @param $name
- *   The name of the lock.
+ *   The name of the lock. Limit of name's length is 255 characters.
  * @param $timeout
  *   A number of seconds (float) before the lock expires (minimum of 0.001).
  *
diff -Naur drupal-7.9/includes/mail.inc drupal-7.58/includes/mail.inc
--- drupal-7.9/includes/mail.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/mail.inc	2018-03-27 21:28:19.000000000 +0200
@@ -10,10 +10,10 @@
  *
  * $conf['mail_line_endings'] will override this setting.
  */
-define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE ? "\r\n" : "\n");
+define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE) ? "\r\n" : "\n");
 
 /**
- * Compose and optionally send an e-mail message.
+ * Composes and optionally sends an e-mail message.
  *
  * Sending an e-mail works with defining an e-mail template (subject, text
  * and possibly e-mail headers) and the replacement values to use in the
@@ -57,6 +57,12 @@
  *     user_mail_tokens($variables, $data, $options);
  *     switch($key) {
  *       case 'notice':
+ *         // If the recipient can receive such notices by instant-message, do
+ *         // not send by email.
+ *         if (example_im_send($key, $message, $params)) {
+ *           $message['send'] = FALSE;
+ *           break;
+ *         }
  *         $langcode = $message['language']->language;
  *         $message['subject'] = t('Notification from !site', $variables, array('langcode' => $langcode));
  *         $message['body'][] = t("Dear !username\n\nThere is new content available on the site.", $variables, array('langcode' => $langcode));
@@ -65,6 +71,19 @@
  *   }
  * @endcode
  *
+ * Another example, which uses drupal_mail() to format a message for sending
+ * later:
+ *
+ * @code
+ *   $params = array('current_conditions' => $data);
+ *   $to = 'user@example.com';
+ *   $message = drupal_mail('example', 'notice', $to, $language, $params, FALSE);
+ *   // Only add to the spool if sending was not canceled.
+ *   if ($message['send']) {
+ *     example_spool_message($message);
+ *   }
+ * @endcode
+ *
  * @param $module
  *   A module name to invoke hook_mail() on. The {$module}_mail() hook will be
  *   called to complete the $message structure which will already contain common
@@ -74,7 +93,9 @@
  *   will be {$module}_{$key}.
  * @param $to
  *   The e-mail address or addresses where the message will be sent to. The
- *   formatting of this string must comply with RFC 2822. Some examples are:
+ *   formatting of this string will be validated with the
+ *   @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
+ *   Some examples are:
  *   - user@example.com
  *   - user@example.com, anotheruser@example.com
  *   - User <user@example.com>
@@ -86,8 +107,10 @@
  * @param $from
  *   Sets From to this value, if given.
  * @param $send
- *   Send the message directly, without calling drupal_mail_system()->mail()
- *   manually.
+ *   If TRUE, drupal_mail() will call drupal_mail_system()->mail() to deliver
+ *   the message, and store the result in $message['result']. Modules
+ *   implementing hook_mail_alter() may cancel sending by setting
+ *   $message['send'] to FALSE.
  *
  * @return
  *   The $message array structure containing all details of the
@@ -108,6 +131,7 @@
     'from'     => isset($from) ? $from : $default_from,
     'language' => $language,
     'params'   => $params,
+    'send'     => TRUE,
     'subject'  => '',
     'body'     => array()
   );
@@ -148,12 +172,20 @@
 
   // Optionally send e-mail.
   if ($send) {
-    $message['result'] = $system->mail($message);
-
-    // Log errors
-    if (!$message['result']) {
-      watchdog('mail', 'Error sending e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
-      drupal_set_message(t('Unable to send e-mail. Contact the site administrator if the problem persists.'), 'error');
+    // The original caller requested sending. Sending was canceled by one or
+    // more hook_mail_alter() implementations. We set 'result' to NULL, because
+    // FALSE indicates an error in sending.
+    if (empty($message['send'])) {
+      $message['result'] = NULL;
+    }
+    // Sending was originally requested and was not canceled.
+    else {
+      $message['result'] = $system->mail($message);
+      // Log errors.
+      if (!$message['result']) {
+        watchdog('mail', 'Error sending e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
+        drupal_set_message(t('Unable to send e-mail. Contact the site administrator if the problem persists.'), 'error');
+      }
     }
   }
 
@@ -161,7 +193,7 @@
 }
 
 /**
- * Returns an object that implements the MailSystemInterface.
+ * Returns an object that implements the MailSystemInterface interface.
  *
  * Allows for one or more custom mail backends to format and send mail messages
  * composed using drupal_mail().
@@ -182,9 +214,9 @@
  * 'mail_system', which is a keyed array.  The default implementation
  * is the class whose name is the value of 'default-system' key. A more specific
  * match first to key and then to module will be used in preference to the
- * default. To specificy a different class for all mail sent by one module, set
+ * default. To specify a different class for all mail sent by one module, set
  * the class name as the value for the key corresponding to the module name. To
- * specificy a class for a particular message sent by one module, set the class
+ * specify a class for a particular message sent by one module, set the class
  * name as the value for the array key that is the message id, which is
  * "${module}_${key}".
  *
@@ -277,19 +309,21 @@
    *   - id: A unique identifier of the e-mail type. Examples: 'contact_user_copy',
    *     'user_password_reset'.
    *   - to: The mail address or addresses where the message will be sent to.
-   *     The formatting of this string must comply with RFC 2822. Some examples:
+   *     The formatting of this string will be validated with the
+   *     @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
+   *     Some examples are:
    *     - user@example.com
    *     - user@example.com, anotheruser@example.com
    *     - User <user@example.com>
    *     - User <user@example.com>, Another User <anotheruser@example.com>
-   *    - subject: Subject of the e-mail to be sent. This must not contain any
-   *      newline characters, or the mail may not be sent properly.
-   *    - body: Message to be sent. Accepts both CRLF and LF line-endings.
-   *      E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
-   *      smart plain text wrapping.
-   *    - headers: Associative array containing all additional mail headers not
-   *      defined by one of the other parameters.  PHP's mail() looks for Cc
-   *      and Bcc headers and sends the mail to addresses in these headers too.
+   *   - subject: Subject of the e-mail to be sent. This must not contain any
+   *     newline characters, or the mail may not be sent properly.
+   *   - body: Message to be sent. Accepts both CRLF and LF line-endings.
+   *     E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
+   *     smart plain text wrapping.
+   *   - headers: Associative array containing all additional mail headers not
+   *     defined by one of the other parameters.  PHP's mail() looks for Cc and
+   *     Bcc headers and sends the mail to addresses in these headers too.
    *
    * @return
    *   TRUE if the mail was successfully accepted for delivery, otherwise FALSE.
@@ -298,18 +332,21 @@
 }
 
 /**
- * Perform format=flowed soft wrapping for mail (RFC 3676).
+ * Performs format=flowed soft wrapping for mail (RFC 3676).
  *
  * We use delsp=yes wrapping, but only break non-spaced languages when
  * absolutely necessary to avoid compatibility issues.
  *
  * We deliberately use LF rather than CRLF, see drupal_mail().
  *
- * @param $text
+ * @param string $text
  *   The plain text to process.
- * @param $indent (optional)
+ * @param string $indent (optional)
  *   A string to indent the text with. Only '>' characters are repeated on
  *   subsequent wrapped lines. Others are replaced by spaces.
+ *
+ * @return string
+ *   The content of the email as a string with formatting applied.
  */
 function drupal_wrap_mail($text, $indent = '') {
   // Convert CRLF into LF.
@@ -319,8 +356,9 @@
   $soft = strpos($clean_indent, ' ') === FALSE;
   // Check if the string has line breaks.
   if (strpos($text, "\n") !== FALSE) {
-    // Remove trailing spaces to make existing breaks hard.
-    $text = preg_replace('/ +\n/m', "\n", $text);
+    // Remove trailing spaces to make existing breaks hard, but leave signature
+    // marker untouched (RFC 3676, Section 4.3).
+    $text = preg_replace('/(?(?<!^--) +\n|  +\n)/m', "\n", $text);
     // Wrap each line at the needed width.
     $lines = explode("\n", $text);
     array_walk($lines, '_drupal_wrap_mail_line', array('soft' => $soft, 'length' => strlen($indent)));
@@ -341,8 +379,7 @@
 }
 
 /**
- * Transform an HTML string into plain text, preserving the structure of the
- * markup. Useful for preparing the body of a node to be sent by e-mail.
+ * Transforms an HTML string into plain text, preserving its structure.
  *
  * The output will be suitable for use as 'format=flowed; delsp=yes' text
  * (RFC 3676) and can be passed directly to drupal_mail() for sending.
@@ -521,21 +558,21 @@
 }
 
 /**
- * Helper function for array_walk in drupal_wrap_mail().
- *
  * Wraps words on a single line.
+ *
+ * Callback for array_walk() winthin drupal_wrap_mail().
  */
 function _drupal_wrap_mail_line(&$line, $key, $values) {
   // Use soft-breaks only for purely quoted or unindented text.
-  $line = wordwrap($line, 77 - $values['length'], $values['soft'] ? "  \n" : "\n");
+  $line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
   // Break really long words at the maximum width allowed.
-  $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
+  $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n", TRUE);
 }
 
 /**
- * Helper function for drupal_html_to_text().
- *
  * Keeps track of URLs and replaces them with placeholder tokens.
+ *
+ * Callback for preg_replace_callback() within drupal_html_to_text().
  */
 function _drupal_html_to_mail_urls($match = NULL, $reset = FALSE) {
   global $base_url, $base_path;
@@ -560,18 +597,18 @@
 }
 
 /**
- * Helper function for drupal_wrap_mail() and drupal_html_to_text().
+ * Replaces non-quotation markers from a given piece of indentation with spaces.
  *
- * Replace all non-quotation markers from a given piece of indentation with spaces.
+ * Callback for array_map() within drupal_html_to_text().
  */
 function _drupal_html_to_text_clean($indent) {
   return preg_replace('/[^>]/', ' ', $indent);
 }
 
 /**
- * Helper function for drupal_html_to_text().
+ * Pads the last line with the given character.
  *
- * Pad the last line with the given character.
+ * @see drupal_html_to_text()
  */
 function _drupal_html_to_text_pad($text, $pad, $prefix = '') {
   // Remove last line break.
diff -Naur drupal-7.9/includes/menu.inc drupal-7.58/includes/menu.inc
--- drupal-7.9/includes/menu.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/menu.inc	2018-03-27 21:28:19.000000000 +0200
@@ -229,12 +229,20 @@
 define('MENU_FOUND', 1);
 
 /**
- * Internal menu status code -- Menu item was not found.
+ * Menu status code -- Not found.
+ *
+ * This can be used as the return value from a page callback, although it is
+ * preferable to use a load function to accomplish this; see the hook_menu()
+ * documentation for details.
  */
 define('MENU_NOT_FOUND', 2);
 
 /**
- * Internal menu status code -- Menu item access is denied.
+ * Menu status code -- Access denied.
+ *
+ * This can be used as the return value from a page callback, although it is
+ * preferable to use an access callback to accomplish this; see the hook_menu()
+ * documentation for details.
  */
 define('MENU_ACCESS_DENIED', 3);
 
@@ -275,6 +283,20 @@
  */
 
 /**
+ * Reserved key to identify the most specific menu link for a given path.
+ *
+ * The value of this constant is a hash of the constant name. We use the hash
+ * so that the reserved key is over 32 characters in length and will not
+ * collide with allowed menu names:
+ * @code
+ * sha1('MENU_PREFERRED_LINK') = 1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91
+ * @endcode
+ *
+ * @see menu_link_get_preferred()
+ */
+define('MENU_PREFERRED_LINK', '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91');
+
+/**
  * Returns the ancestors (and relevant placeholders) for any given path.
  *
  * For example, the ancestors of node/12345/edit are:
@@ -295,7 +317,7 @@
  * actually exists. This list of 'masks' is built in menu_rebuild().
  *
  * @param $parts
- *   An array of path parts, for the above example
+ *   An array of path parts; for the above example, 
  *   array('node', '12345', 'edit').
  *
  * @return
@@ -307,7 +329,14 @@
   $ancestors = array();
   $length =  $number_parts - 1;
   $end = (1 << $number_parts) - 1;
-  $masks = variable_get('menu_masks', array());
+  $masks = variable_get('menu_masks');
+  // If the optimized menu_masks array is not available use brute force to get
+  // the correct $ancestors and $placeholders returned. Do not use this as the
+  // default value of the menu_masks variable to avoid building such a big
+  // array.
+  if (!$masks) {
+    $masks = range(511, 1);
+  }
   // Only examine patterns that actually exist as router items (the masks).
   foreach ($masks as $i) {
     if ($i > $end) {
@@ -396,9 +425,9 @@
  * @param $path
  *   The path.
  * @param $router_item
- *   The router item. Usually you take a router entry from menu_get_item and
- *   set it back either modified or to a different path. This lets you modify the
- *   navigation block, the page title, the breadcrumb and the page help in one
+ *   The router item. Usually a router entry from menu_get_item() is either
+ *   modified or set to a different path. This allows the navigation block,
+ *   the page title, the breadcrumb, and the page help to be modified in one
  *   call.
  */
 function menu_set_item($path, $router_item) {
@@ -406,21 +435,22 @@
 }
 
 /**
- * Get a router item.
+ * Gets a router item.
  *
  * @param $path
- *   The path, for example node/5. The function will find the corresponding
- *   node/% item and return that.
+ *   The path; for example, 'node/5'. The function will find the corresponding
+ *   node/% item and return that. Defaults to the current path.
  * @param $router_item
  *   Internal use only.
  *
  * @return
- *   The router item, an associate array corresponding to one row in the
- *   menu_router table. The value of key map holds the loaded objects. The
- *   value of key access is TRUE if the current user can access this page.
- *   The values for key title, page_arguments, access_arguments, and
- *   theme_arguments will be filled in based on the database values and the
- *   objects loaded.
+ *   The router item or, if an error occurs in _menu_translate(), FALSE. A
+ *   router item is an associative array corresponding to one row in the
+ *   menu_router table. The value corresponding to the key 'map' holds the
+ *   loaded objects. The value corresponding to the key 'access' is TRUE if the
+ *   current user can access this page. The values corresponding to the keys
+ *   'title', 'page_arguments', 'access_arguments', and 'theme_arguments' will
+ *   be filled in based on the database values and the objects loaded.
  */
 function menu_get_item($path = NULL, $router_item = NULL) {
   $router_items = &drupal_static(__FUNCTION__);
@@ -434,22 +464,16 @@
     // Rebuild if we know it's needed, or if the menu masks are missing which
     // occurs rarely, likely due to a race condition of multiple rebuilds.
     if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) {
-      menu_rebuild();
+      if (_menu_check_rebuild()) {
+        menu_rebuild();
+      }
     }
     $original_map = arg(NULL, $path);
 
-    // Since there is no limit to the length of $path, use a hash to keep it
-    // short yet unique.
-    $cid = 'menu_item:' . hash('sha256', $path);
-    if ($cached = cache_get($cid, 'cache_menu')) {
-      $router_item = $cached->data;
-    }
-    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');
-    }
+    $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();
+
     if ($router_item) {
       // Allow modules to alter the router item before it is translated and
       // checked for access.
@@ -528,7 +552,7 @@
  * @param $item
  *   A menu router or menu link item
  * @param $map
- *   An array of path arguments (ex: array('node', '5'))
+ *   An array of path arguments; for example, array('node', '5').
  *
  * @return
  *   Returns TRUE for success, FALSE if an object cannot be loaded.
@@ -593,17 +617,18 @@
 }
 
 /**
- * Check access to a menu item using the access callback
+ * Checks access to a menu item using the access callback.
  *
  * @param $item
  *   A menu router or menu link item
  * @param $map
- *   An array of path arguments (ex: array('node', '5'))
+ *   An array of path arguments; for example, array('node', '5').
  *
  * @return
  *   $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
  */
 function _menu_check_access(&$item, $map) {
+  $item['access'] = FALSE;
   // Determine access callback, which will decide whether or not the current
   // user has access to this path.
   $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
@@ -625,7 +650,7 @@
 }
 
 /**
- * Localize the router item title using t() or another callback.
+ * Localizes the router item title using t() or another callback.
  *
  * Translate the title and description to allow storage of English title
  * strings in the database, yet display of them in the language required
@@ -723,7 +748,7 @@
  * @param $router_item
  *   A menu router item
  * @param $map
- *   An array of path arguments (ex: array('node', '5'))
+ *   An array of path arguments; for example, array('node', '5').
  * @param $to_arg
  *   Execute $item['to_arg_functions'] or not. Use only if you want to render a
  *   path from the menu table, for example tabs.
@@ -733,7 +758,7 @@
  *   $item['load_functions']. $item['access'] becomes TRUE if the item is
  *   accessible, FALSE otherwise. $item['href'] is set according to the map.
  *   If an error occurs during calling the load_functions (like trying to load
- *   a non existing node) then this function return FALSE.
+ *   a non-existent node) then this function returns FALSE.
  */
 function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
   if ($to_arg && !empty($router_item['to_arg_functions'])) {
@@ -783,14 +808,14 @@
 }
 
 /**
- * This function translates the path elements in the map using any to_arg
- * helper function. These functions take an argument and return an object.
- * See http://drupal.org/node/109153 for more information.
+ * Translates the path elements in the map using any to_arg helper function.
  *
  * @param $map
- *   An array of path arguments (ex: array('node', '5'))
+ *   An array of path arguments; for example, array('node', '5').
  * @param $to_arg_functions
- *   An array of helper function (ex: array(2 => 'menu_tail_to_arg'))
+ *   An array of helper functions; for example, array(2 => 'menu_tail_to_arg').
+ *
+ * @see hook_menu()
  */
 function _menu_link_map_translate(&$map, $to_arg_functions) {
   $to_arg_functions = unserialize($to_arg_functions);
@@ -807,14 +832,14 @@
 }
 
 /**
- * Returns path as one string from the argument we are currently at.
+ * Returns a string containing the path relative to the current index.
  */
 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.
+ * Loads the path as one string relative to the current index.
  *
  * To use this load function, you must specify the load arguments
  * in the router item as:
@@ -831,8 +856,10 @@
 }
 
 /**
- * This function is similar to _menu_translate() but does link-specific
- * preparation such as always calling to_arg functions
+ * Provides menu link access control, translation, and argument handling.
+ *
+ * This function is similar to _menu_translate(), but it also does
+ * link-specific preparation (such as always calling to_arg() functions).
  *
  * @param $item
  *   A menu link.
@@ -926,7 +953,7 @@
 }
 
 /**
- * Get a loaded object from a router item.
+ * Gets a loaded object from a router item.
  *
  * menu_get_object() provides access to objects loaded by the current router
  * item. For example, on the page node/%node, the router loads the %node object,
@@ -983,7 +1010,7 @@
 }
 
 /**
- * Returns a rendered menu tree.
+ * Returns an output structure for rendering a menu tree.
  *
  * The menu item's LI element is given one of the following classes:
  * - expanded: The menu item is showing its submenu.
@@ -1066,7 +1093,7 @@
 }
 
 /**
- * Get the data structure representing a named menu tree.
+ * Gets the data structure representing a named menu tree.
  *
  * Since this can be the full tree including hidden items, the data returned
  * may be used for generating an an admin interface or a select.
@@ -1134,7 +1161,7 @@
 }
 
 /**
- * Set the path for determining the active trail of the specified menu tree.
+ * Sets the path for determining the active trail of the specified menu tree.
  *
  * This path will also affect the breadcrumbs under some circumstances.
  * Breadcrumbs are built using the preferred link returned by
@@ -1159,7 +1186,7 @@
 }
 
 /**
- * Get the path for determining the active trail of the specified menu tree.
+ * Gets the path for determining the active trail of the specified menu tree.
  *
  * @param $menu_name
  *   The menu name of the requested tree.
@@ -1173,7 +1200,7 @@
 }
 
 /**
- * Get the data structure representing a named menu tree, based on the current page.
+ * Gets the data structure for a named menu tree, based on the current page.
  *
  * The tree order is maintained by storing each parent in an individual
  * field, see http://drupal.org/node/141866 for more.
@@ -1241,7 +1268,7 @@
         if ($item['access']) {
           // Find a menu link corresponding to the current path. If $active_path
           // is NULL, let menu_link_get_preferred() determine the path.
-          if ($active_link = menu_link_get_preferred($active_path)) {
+          if ($active_link = menu_link_get_preferred($active_path, $menu_name)) {
             // The active link may only be taken into account to build the
             // active trail, if it resides in the requested menu. Otherwise,
             // we'd needlessly re-run _menu_build_tree() queries for every menu
@@ -1307,7 +1334,7 @@
 }
 
 /**
- * Build a menu tree, translate links, and check access.
+ * Builds a menu tree, translates links, and checks access.
  *
  * @param $menu_name
  *   The name of the menu.
@@ -1322,9 +1349,11 @@
  *     trail. This option is ignored, if 'expanded' is non-empty. Internally
  *     used for breadcrumbs.
  *   - min_depth: The minimum depth of menu links in the resulting tree.
- *     Defaults to 1, which is the default to build a whole tree for a menu, i.e.
- *     excluding menu container itself.
+ *     Defaults to 1, which is the default to build a whole tree for a menu
+ *     (excluding menu container itself).
  *   - max_depth: The maximum depth of menu links in the resulting tree.
+ *   - conditions: An associative array of custom database select query
+ *     condition key/value pairs; see _menu_build_tree() for the actual query.
  *
  * @return
  *   A fully built menu tree.
@@ -1338,7 +1367,7 @@
 }
 
 /**
- * Build a menu tree.
+ * Builds a menu tree.
  *
  * This function may be used build the data for a menu tree only, for example
  * to further massage the data manually before further processing happens.
@@ -1408,6 +1437,12 @@
     if (isset($parameters['max_depth'])) {
       $query->condition('ml.depth', $parameters['max_depth'], '<=');
     }
+    // Add custom query conditions, if any were passed.
+    if (isset($parameters['conditions'])) {
+      foreach ($parameters['conditions'] as $column => $value) {
+        $query->condition($column, $value);
+      }
+    }
 
     // Build an ordered array of links using the query result object.
     $links = array();
@@ -1428,7 +1463,7 @@
 }
 
 /**
- * Recursive helper function - collect node links.
+ * Collects node links from a given menu tree recursively.
  *
  * @param $tree
  *   The menu tree you wish to collect node links from.
@@ -1451,7 +1486,7 @@
 }
 
 /**
- * Check access and perform other dynamic operations for each link in the tree.
+ * Checks access and performs dynamic operations for each link in the tree.
  *
  * @param $tree
  *   The menu tree you wish to operate on.
@@ -1460,7 +1495,7 @@
  *   menu_tree_collect_node_links().
  */
 function menu_tree_check_access(&$tree, $node_links = array()) {
-  if ($node_links) {
+  if ($node_links && (user_access('access content') || user_access('bypass node access'))) {
     $nids = array_keys($node_links);
     $select = db_select('node', 'n');
     $select->addField('n', 'nid');
@@ -1478,7 +1513,7 @@
 }
 
 /**
- * Recursive helper function for menu_tree_check_access()
+ * Sorts the menu tree and recursively checks access for each item.
  */
 function _menu_tree_check_access(&$tree) {
   $new_tree = array();
@@ -1501,7 +1536,7 @@
 }
 
 /**
- * Builds the data representing a menu tree.
+ * Sorts and returns the built data representing a menu tree.
  *
  * @param $links
  *   A flat array of menu links that are part of the menu. Each array element
@@ -1533,7 +1568,7 @@
 }
 
 /**
- * Recursive helper function to build the data representing a menu tree.
+ * Builds the data representing a menu tree.
  *
  * The function is a bit complex because the rendering of a link depends on
  * the next menu link.
@@ -1568,9 +1603,10 @@
 }
 
 /**
- * Preprocesses the rendered tree for theme_menu_tree().
+ * Implements template_preprocess_HOOK() for theme_menu_tree().
  */
 function template_preprocess_menu_tree(&$variables) {
+  $variables['#tree'] = $variables['tree'];
   $variables['tree'] = $variables['tree']['#children'];
 }
 
@@ -1762,7 +1798,7 @@
 }
 
 /**
- * Return an array containing the names of system-defined (default) menus.
+ * Returns an array containing the names of system-defined (default) menus.
  */
 function menu_list_system_menus() {
   return array(
@@ -1774,14 +1810,14 @@
 }
 
 /**
- * Return an array of links to be rendered as the Main menu.
+ * Returns an array of links to be rendered as the Main menu.
  */
 function menu_main_menu() {
   return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'));
 }
 
 /**
- * Return an array of links to be rendered as the Secondary links.
+ * Returns an array of links to be rendered as the Secondary links.
  */
 function menu_secondary_menu() {
 
@@ -1796,7 +1832,7 @@
 }
 
 /**
- * Return an array of links for a navigation menu.
+ * Returns an array of links for a navigation menu.
  *
  * @param $menu_name
  *   The name of the menu.
@@ -1901,13 +1937,21 @@
     }
 
     // Get all tabs (also known as local tasks) and the root page.
-    $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
-      ->fields('menu_router')
-      ->condition('tab_root', $router_item['tab_root'])
-      ->condition('context', MENU_CONTEXT_INLINE, '<>')
-      ->orderBy('weight')
-      ->orderBy('title')
-      ->execute();
+    $cid = 'local_tasks:' . $router_item['tab_root'];
+    if ($cache = cache_get($cid, 'cache_menu')) {
+      $result = $cache->data;
+    }
+    else {
+      $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
+        ->fields('menu_router')
+        ->condition('tab_root', $router_item['tab_root'])
+        ->condition('context', MENU_CONTEXT_INLINE, '<>')
+        ->orderBy('weight')
+        ->orderBy('title')
+        ->execute()
+        ->fetchAll();
+      cache_set($cid, $result, 'cache_menu');
+    }
     $map = $router_item['original_map'];
     $children = array();
     $tasks = array();
@@ -2088,14 +2132,12 @@
 }
 
 /**
- * Retrieve contextual links for a system object based on registered local tasks.
+ * Retrieves contextual links for a path based on registered local tasks.
  *
  * This leverages the menu system to retrieve the first layer of registered
  * local tasks for a given system path. All local tasks of the tab type
  * MENU_CONTEXT_INLINE are taken into account.
  *
- * @see hook_menu()
- *
  * For example, when considering the following registered local tasks:
  * - node/%node/view (default local task) with no 'context' defined
  * - node/%node/edit with context: MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE
@@ -2116,13 +2158,14 @@
  *   example 'node' or 'admin/structure/block/manage'.
  * @param $args
  *   A list of dynamic path arguments to append to $parent_path to form the
- *   fully-qualified menu router path, for example array(123) for a certain
+ *   fully-qualified menu router path; for example, array(123) for a certain
  *   node or array('system', 'navigation') for a certain block.
  *
  * @return
  *   A list of menu router items that are local tasks for the passed-in path.
  *
  * @see contextual_links_preprocess()
+ * @see hook_menu()
  */
 function menu_contextual_links($module, $parent_path, $args) {
   static $path_empty = array();
@@ -2130,7 +2173,7 @@
   $links = array();
   // Performance: In case a previous invocation for the same parent path did not
   // return any links, we immediately return here.
-  if (isset($path_empty[$parent_path])) {
+  if (isset($path_empty[$parent_path]) && strpos($parent_path, '%') !== FALSE) {
     return $links;
   }
   // Construct the item-specific parent path.
@@ -2216,7 +2259,7 @@
 }
 
 /**
- * Returns the router path, or the path of the parent tab of a default local task.
+ * Returns the router path, or the path for a default local task's parent.
  */
 function menu_tab_root_path() {
   $links = menu_local_tasks();
@@ -2237,7 +2280,13 @@
 /**
  * Returns HTML for primary and secondary local tasks.
  *
+ * @param $variables
+ *   An associative array containing:
+ *     - primary: (optional) An array of local tasks (tabs).
+ *     - secondary: (optional) An array of local tasks (tabs).
+ *
  * @ingroup themeable
+ * @see menu_local_tasks()
  */
 function theme_menu_local_tasks(&$variables) {
   $output = '';
@@ -2259,7 +2308,16 @@
 }
 
 /**
- * Set (or get) the active menu for the current page - determines the active trail.
+ * Sets (or gets) the active menu for the current page.
+ *
+ * The active menu for the page determines the active trail.
+ *
+ * @return
+ *   An array of menu machine names, in order of preference. The
+ *   'menu_default_active_menus' variable may be used to assert a menu order
+ *   different from the order of creation, or to prevent a particular menu from
+ *   being used at all in the active trail.
+ *   E.g., $conf['menu_default_active_menus'] = array('navigation', 'main-menu')
  */
 function menu_set_active_menu_names($menu_names = NULL) {
   $active = &drupal_static(__FUNCTION__);
@@ -2274,17 +2332,17 @@
 }
 
 /**
- * Get the active menu for the current page - determines the active trail.
+ * Gets the active menu for the current page.
  */
 function menu_get_active_menu_names() {
   return menu_set_active_menu_names();
 }
 
 /**
- * Set the active path, which determines which page is loaded.
+ * Sets the active path, which determines which page is loaded.
  *
  * Note that this may not have the desired effect unless invoked very early
- * in the page load, such as during hook_boot, or unless you call
+ * in the page load, such as during hook_boot(), or unless you call
  * menu_execute_active_handler() to generate your page output.
  *
  * @param $path
@@ -2292,10 +2350,13 @@
  */
 function menu_set_active_item($path) {
   $_GET['q'] = $path;
+  // Since the active item has changed, the active menu trail may also be out
+  // of date.
+  drupal_static_reset('menu_set_active_trail');
 }
 
 /**
- * Sets the active trail (path to menu tree root) of the current page.
+ * Sets the active trail (path to the menu tree root) of the current page.
  *
  * Any trail set by this function will only be used for functionality that calls
  * menu_get_active_trail(). Drupal core only uses trails set here for
@@ -2359,7 +2420,7 @@
           // argument placeholders (%). Such links are not contained in regular
           // menu trees, and have only been loaded for the additional
           // translation that happens here, so as to be able to display them in
-          // the breadcumb for the current page.
+          // the breadcrumb for the current page.
           // @see _menu_tree_check_access()
           // @see _menu_link_translate()
           if (strpos($link['href'], '%') !== FALSE) {
@@ -2377,7 +2438,7 @@
     // appending either the preferred link or the menu router item for the
     // current page. Exclude it if we are on the front page.
     $last = end($trail);
-    if ($last['href'] != $preferred_link['href'] && !drupal_is_front_page()) {
+    if ($preferred_link && $last['href'] != $preferred_link['href'] && !drupal_is_front_page()) {
       $trail[] = $preferred_link;
     }
   }
@@ -2385,28 +2446,35 @@
 }
 
 /**
- * Lookup the preferred menu link for a given system path.
+ * Looks up the preferred menu link for a given system path.
  *
  * @param $path
- *   The path, for example 'node/5'. The function will find the corresponding
+ *   The path; for example, 'node/5'. The function will find the corresponding
  *   menu link ('node/5' if it exists, or fallback to 'node/%').
+ * @param $selected_menu
+ *   The name of a menu used to restrict the search for a preferred menu link.
+ *   If not specified, all the menus returned by menu_get_active_menu_names()
+ *   will be used.
  *
  * @return
- *   A fully translated menu link, or NULL if no matching menu link was
+ *   A fully translated menu link, or FALSE if no matching menu link was
  *   found. The most specific menu link ('node/5' preferred over 'node/%') in
  *   the most preferred menu (as defined by menu_get_active_menu_names()) is
  *   returned.
  */
-function menu_link_get_preferred($path = NULL) {
+function menu_link_get_preferred($path = NULL, $selected_menu = NULL) {
   $preferred_links = &drupal_static(__FUNCTION__);
 
   if (!isset($path)) {
     $path = $_GET['q'];
   }
 
-  if (!isset($preferred_links[$path])) {
-    $preferred_links[$path] = FALSE;
+  if (empty($selected_menu)) {
+    // Use an illegal menu name as the key for the preferred menu link.
+    $selected_menu = MENU_PREFERRED_LINK;
+  }
 
+  if (!isset($preferred_links[$path])) {
     // Look for the correct menu link by building a list of candidate paths,
     // which are ordered by priority (translated hrefs are preferred over
     // untranslated paths). Afterwards, the most relevant path is picked from
@@ -2428,6 +2496,8 @@
 
     // Retrieve a list of menu names, ordered by preference.
     $menu_names = menu_get_active_menu_names();
+    // Put the selected menu at the front of the list.
+    array_unshift($menu_names, $selected_menu);
 
     $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
     $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
@@ -2435,37 +2505,43 @@
     // Weight must be taken from {menu_links}, not {menu_router}.
     $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');
+    $query->addTag('preferred_menu_links');
 
     // 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;
+      // Add any menus not already in the menu name search list.
+      if (!in_array($candidate['menu_name'], $menu_names)) {
+        $menu_names[] = $candidate['menu_name'];
+      }
     }
 
-    // Pick the most specific link, in the most preferred menu.
+    // Store the most specific link for each menu. Also save the most specific
+    // link of the most preferred menu in $preferred_link.
     foreach ($path_candidates as $link_path) {
-      if (!isset($candidates[$link_path])) {
-        continue;
-      }
-      foreach ($menu_names as $menu_name) {
-        if (!isset($candidates[$link_path][$menu_name])) {
-          continue;
-        }
-        $candidate_item = $candidates[$link_path][$menu_name];
-        $map = explode('/', $path);
-        _menu_translate($candidate_item, $map);
-        if ($candidate_item['access']) {
-          $preferred_links[$path] = $candidate_item;
+      if (isset($candidates[$link_path])) {
+        foreach ($menu_names as $menu_name) {
+          if (empty($preferred_links[$path][$menu_name]) && isset($candidates[$link_path][$menu_name])) {
+            $candidate_item = $candidates[$link_path][$menu_name];
+            $map = explode('/', $path);
+            _menu_translate($candidate_item, $map);
+            if ($candidate_item['access']) {
+              $preferred_links[$path][$menu_name] = $candidate_item;
+              if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
+                // Store the most specific link.
+                $preferred_links[$path][MENU_PREFERRED_LINK] = $candidate_item;
+              }
+            }
+          }
         }
-        break 2;
       }
     }
   }
 
-  return $preferred_links[$path];
+  return isset($preferred_links[$path][$selected_menu]) ? $preferred_links[$path][$selected_menu] : FALSE;
 }
 
 /**
@@ -2491,7 +2567,7 @@
 }
 
 /**
- * Get the breadcrumb for the current page, as determined by the active trail.
+ * Gets the breadcrumb for the current page, as determined by the active trail.
  *
  * @see menu_set_active_trail()
  */
@@ -2542,20 +2618,40 @@
 }
 
 /**
- * Get the title of the current page, as determined by the active trail.
+ * Gets the title of the current page, as determined by the active trail.
  */
 function menu_get_active_title() {
   $active_trail = menu_get_active_trail();
+  $local_task_title = NULL;
 
   foreach (array_reverse($active_trail) as $item) {
-    if (!(bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
-      return $item['title'];
+    // Local task titles are displayed as tabs and therefore should not be
+    // repeated as the page title. However, if the local task appears in a
+    // top-level menu, it is no longer a "local task" anymore (the front page
+    // of the site does not have tabs) so it is better to use the local task
+    // title in that case than to fall back on the front page link in the
+    // active trail (which is usually "Home" and would not make sense in this
+    // context).
+    if ((bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
+      // A local task title is being skipped; track it in case it needs to be
+      // used later.
+      $local_task_title = $item['title'];
+    }
+    else {
+      // This is not a local task, so use it for the page title (unless the
+      // conditions described above are met).
+      if (isset($local_task_title) && isset($item['href']) && $item['href'] == '<front>') {
+        return $local_task_title;
+      }
+      else {
+        return $item['title'];
+      }
     }
   }
 }
 
 /**
- * Get a menu link by its mlid, access checked and link translated for rendering.
+ * Gets a translated, access-checked menu link that is ready for rendering.
  *
  * This function should never be called from within node_load() or any other
  * function used as a menu object load function since an infinite recursion may
@@ -2587,7 +2683,7 @@
 }
 
 /**
- * Clears the cached cached data for a single named menu.
+ * Clears the cached data for a single named menu.
  */
 function menu_cache_clear($menu_name = 'navigation') {
   $cache_cleared = &drupal_static(__FUNCTION__, array());
@@ -2606,7 +2702,9 @@
 }
 
 /**
- * Clears all cached menu data. This should be called any time broad changes
+ * Clears all cached menu data.
+ *
+ * This should be called any time broad changes
  * might have been made to the router items or menu links.
  */
 function menu_cache_clear_all() {
@@ -2627,10 +2725,25 @@
 }
 
 /**
- * (Re)populate the database tables used by various menu functions.
+ * Checks whether a menu_rebuild() is necessary.
+ */
+function _menu_check_rebuild() {
+  // To absolutely ensure that the menu rebuild is required, re-load the
+  // variables in case they were set by another process.
+  $variables = variable_initialize();
+  if (empty($variables['menu_rebuild_needed']) && !empty($variables['menu_masks'])) {
+    unset($GLOBALS['conf']['menu_rebuild_needed']);
+    $GLOBALS['conf']['menu_masks'] = $variables['menu_masks'];
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Populates the database tables used by various menu functions.
  *
  * This function will clear and populate the {menu_router} table, add entries
- * to {menu_links} for new router items, then remove stale items from
+ * to {menu_links} for new router items, and then remove stale items from
  * {menu_links}. If called from update.php or install.php, it will also
  * schedule a call to itself on the first real page load from
  * menu_execute_active_handler(), because the maintenance page environment
@@ -2646,6 +2759,14 @@
     // We choose to block here since otherwise the router item may not
     // be available in menu_execute_active_handler() resulting in a 404.
     lock_wait('menu_rebuild');
+
+    if (_menu_check_rebuild()) {
+      // If we get here and menu_masks was not set, then it is possible a menu
+      // is being reloaded, or that the process rebuilding the menu was unable
+      // to complete successfully. A missing menu_masks variable could result
+      // in a 404, so re-run the function.
+      return menu_rebuild();
+    }
     return FALSE;
   }
 
@@ -2670,13 +2791,19 @@
     $transaction->rollback();
     watchdog_exception('menu', $e);
   }
+  // Explicitly commit the transaction now; this ensures that the database
+  // operations during the menu rebuild are committed before the lock is made
+  // available again, since locks may not always reside in the same database
+  // connection. The lock is acquired outside of the transaction so should also
+  // be released outside of it.
+  unset($transaction);
 
   lock_release('menu_rebuild');
   return TRUE;
 }
 
 /**
- * Collect and alter the menu definitions.
+ * Collects and alters the menu definitions.
  */
 function menu_router_build() {
   // We need to manually call each module so that we can know which module
@@ -2700,7 +2827,7 @@
 }
 
 /**
- * Helper function to store the menu router if we have it in memory.
+ * Stores the menu router if we have it in memory.
  */
 function _menu_router_cache($new_menu = NULL) {
   $menu = &drupal_static(__FUNCTION__);
@@ -2712,7 +2839,7 @@
 }
 
 /**
- * Get the menu router.
+ * Gets the menu router.
  */
 function menu_get_router() {
   // Check first if we have it in memory already.
@@ -2749,7 +2876,7 @@
 }
 
 /**
- * Helper function to build menu links for the items in the menu router.
+ * Builds menu links for the items in the menu router.
  */
 function _menu_navigation_links_rebuild($menu) {
   // Add normal and suggested items as links.
@@ -2849,7 +2976,7 @@
 }
 
 /**
- * Clone an array of menu links.
+ * Clones an array of menu links.
  *
  * @param $links
  *   An array of menu links to clone.
@@ -2940,12 +3067,14 @@
 }
 
 /**
- * Helper function for menu_link_delete; deletes a single menu link.
+ * Deletes a single menu link.
  *
  * @param $item
  *   Item to be deleted.
  * @param $force
  *   Forces deletion. Internal use only, setting to TRUE is discouraged.
+ *
+ * @see menu_link_delete()
  */
 function _menu_delete_item($item, $force = FALSE) {
   $item = is_object($item) ? get_object_vars($item) : $item;
@@ -3106,10 +3235,10 @@
   }
   // If every value in $existing_item is the same in the $item, there is no
   // reason to run the update queries or clear the caches. We use
-  // array_intersect_assoc() with the $item as the first parameter because
+  // array_intersect_key() with the $item as the first parameter because
   // $item may have additional keys left over from building a router entry.
   // The intersect removes the extra keys, allowing a meaningful comparison.
-  if (!$existing_item || (array_intersect_assoc($item, $existing_item)) != $existing_item) {
+  if (!$existing_item || (array_intersect_key($item, $existing_item) != $existing_item)) {
     db_update('menu_links')
       ->fields(array(
         'menu_name' => $item['menu_name'],
@@ -3157,7 +3286,7 @@
 }
 
 /**
- * Find a possible parent for a given menu link.
+ * Finds 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:
@@ -3171,6 +3300,7 @@
  *   A menu link.
  * @param $parent_candidates
  *   An array of menu links keyed by mlid.
+ *
  * @return
  *   A menu link structure of the possible parent or FALSE if no valid parent
  *   has been found.
@@ -3236,7 +3366,7 @@
 }
 
 /**
- * Helper function to clear the page and block caches at most twice per page load.
+ * Clears the page and block caches at most twice per page load.
  */
 function _menu_clear_page_cache() {
   $cache_cleared = &drupal_static(__FUNCTION__, 0);
@@ -3258,7 +3388,7 @@
 }
 
 /**
- * Helper function to update a list of menus with expanded items
+ * Updates a list of menus with expanded items.
  */
 function _menu_set_expanded_menus() {
   $names = db_query("SELECT menu_name FROM {menu_links} WHERE expanded <> 0 GROUP BY menu_name")->fetchCol();
@@ -3266,7 +3396,7 @@
 }
 
 /**
- * Find the router path which will serve this path.
+ * Finds the router path which will serve this path.
  *
  * @param $link_path
  *  The path for we are looking up its router path.
@@ -3308,7 +3438,7 @@
 }
 
 /**
- * Insert, update or delete an uncustomized menu link related to a module.
+ * Inserts, updates, or deletes an uncustomized menu link related to a module.
  *
  * @param $module
  *   The name of the module.
@@ -3348,7 +3478,7 @@
 }
 
 /**
- * Find the depth of an item's children relative to its depth.
+ * Finds the depth of an item's children relative to its depth.
  *
  * For example, if the item has a depth of 2, and the maximum of any child in
  * the menu link tree is 5, the relative depth is 3.
@@ -3380,7 +3510,7 @@
 }
 
 /**
- * Update the children of a menu link that's being moved.
+ * Updates the children of a menu link that is being moved.
  *
  * The menu name, parents (p1 - p6), and depth are updated for all children of
  * the link, and the has_children status of the previous parent is updated.
@@ -3429,7 +3559,7 @@
 }
 
 /**
- * Check and update the has_children status for the parent of a link.
+ * Checks and updates the 'has_children' status for the parent of a link.
  */
 function _menu_update_parental_status($item, $exclude = FALSE) {
   // If plid == 0, there is nothing to update.
@@ -3453,7 +3583,7 @@
 }
 
 /**
- * Helper function that sets the p1..p9 values for a menu link being saved.
+ * Sets the p1 through p9 values for a menu link being saved.
  */
 function _menu_link_parents_set(&$item, $parent) {
   $i = 1;
@@ -3471,7 +3601,7 @@
 }
 
 /**
- * Helper function to build the router table based on the data from hook_menu.
+ * Builds the router table based on the data from hook_menu().
  */
 function _menu_router_build($callbacks) {
   // First pass: separate callbacks from paths, making paths ready for
@@ -3698,7 +3828,7 @@
 }
 
 /**
- * Helper function to save data from menu_router_build() to the router table.
+ * Saves data from menu_router_build() to the router table.
  */
 function _menu_router_save($menu, $masks) {
   // Delete the existing router since we have some data to replace it.
diff -Naur drupal-7.9/includes/module.inc drupal-7.58/includes/module.inc
--- drupal-7.9/includes/module.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/module.inc	2018-03-27 21:28:19.000000000 +0200
@@ -6,7 +6,7 @@
  */
 
 /**
- * Load all the modules that have been enabled in the system table.
+ * Loads all the modules that have been enabled in the system table.
  *
  * @param $bootstrap
  *   Whether to load only the reduced set of modules loaded in "bootstrap mode"
@@ -102,7 +102,7 @@
 }
 
 /**
- * Build a list of bootstrap modules and enabled modules and themes.
+ * Builds a list of bootstrap modules and enabled modules and themes.
  *
  * @param $type
  *   The type of list to return:
@@ -178,6 +178,34 @@
           $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename);
         }
       }
+      foreach ($lists['theme'] as $key => $theme) {
+        if (!empty($theme->info['base theme'])) {
+          // Make a list of the theme's base themes.
+          require_once DRUPAL_ROOT . '/includes/theme.inc';
+          $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
+          // Don't proceed if there was a problem with the root base theme.
+          if (!current($lists['theme'][$key]->base_themes)) {
+            continue;
+          }
+          // Determine the root base theme.
+          $base_key = key($lists['theme'][$key]->base_themes);
+          // Add to the list of sub-themes for each of the theme's base themes.
+          foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
+            $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
+          }
+          // Add the base theme's theme engine info.
+          $lists['theme'][$key]->info['engine'] = isset($lists['theme'][$base_key]->info['engine']) ? $lists['theme'][$base_key]->info['engine'] : 'theme';
+        }
+        else {
+          // A plain theme is its own engine.
+          $base_key = $key;
+          if (!isset($lists['theme'][$key]->info['engine'])) {
+            $lists['theme'][$key]->info['engine'] = 'theme';
+          }
+        }
+        // Set the theme engine prefix.
+        $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
+      }
       cache_set('system_list', $lists, 'cache_bootstrap');
     }
     // To avoid a separate database lookup for the filepath, prime the
@@ -191,7 +219,7 @@
 }
 
 /**
- * Reset all system_list() caches.
+ * Resets all system_list() caches.
  */
 function system_list_reset() {
   drupal_static_reset('system_list');
@@ -199,10 +227,14 @@
   drupal_static_reset('list_themes');
   cache_clear_all('bootstrap_modules', 'cache_bootstrap');
   cache_clear_all('system_list', 'cache_bootstrap');
+
+  // Clean up the bootstrap file scan cache.
+  drupal_static_reset('_drupal_file_scan_cache');
+  cache_clear_all('_drupal_file_scan_cache', 'cache_bootstrap');
 }
 
 /**
- * Find dependencies any level deep and fill in required by information too.
+ * Determines which modules require and are required by each module.
  *
  * @param $files
  *   The array of filesystem objects used to rebuild the cache.
@@ -235,13 +267,13 @@
 }
 
 /**
- * Determine whether a given module exists.
+ * Determines whether a given module exists.
  *
- * @param $module
+ * @param string $module
  *   The name of the module (without the .module extension).
  *
- * @return
- *   TRUE if the module is both installed and enabled.
+ * @return bool
+ *   TRUE if the module is both installed and enabled, FALSE otherwise.
  */
 function module_exists($module) {
   $list = module_list();
@@ -249,7 +281,7 @@
 }
 
 /**
- * Load a module's installation hooks.
+ * Loads a module's installation hooks.
  *
  * @param $module
  *   The name of the module (without the .module extension).
@@ -265,7 +297,7 @@
 }
 
 /**
- * Load a module include file.
+ * Loads a module include file.
  *
  * Examples:
  * @code
@@ -292,23 +324,33 @@
  *   The name of the included file, if successful; FALSE otherwise.
  */
 function module_load_include($type, $module, $name = NULL) {
+  static $files = array();
+
   if (!isset($name)) {
     $name = $module;
   }
 
+  $key = $type . ':' . $module . ':' . $name;
+  if (isset($files[$key])) {
+    return $files[$key];
+  }
+
   if (function_exists('drupal_get_path')) {
     $file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
     if (is_file($file)) {
       require_once $file;
+      $files[$key] = $file;
       return $file;
     }
+    else {
+      $files[$key] = FALSE;
+    }
   }
   return FALSE;
 }
 
 /**
- * Load an include file for each of the modules that have been enabled in
- * the system table.
+ * Loads an include file for each module enabled in the {system} table.
  */
 function module_load_all_includes($type, $name = NULL) {
   $modules = module_list();
@@ -338,20 +380,22 @@
  * - Invoke hook_modules_installed().
  * - Invoke hook_modules_enabled().
  *
- * @param $module_list
+ * @param string[] $module_list
  *   An array of module names.
- * @param $enable_dependencies
+ * @param bool $enable_dependencies
  *   If TRUE, dependencies will automatically be added and enabled 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
+ * @return bool
  *   FALSE if one or more dependencies are missing, TRUE otherwise.
  *
  * @see hook_install()
  * @see hook_enable()
  * @see hook_modules_installed()
  * @see hook_modules_enabled()
+ * @see module_disable()
+ * @see drupal_uninstall_modules()
  */
 function module_enable($module_list, $enable_dependencies = TRUE) {
   if ($enable_dependencies) {
@@ -425,6 +469,8 @@
       registry_update();
       // Refresh the schema to include it.
       drupal_get_schema(NULL, TRUE);
+      // Update the theme registry to include it.
+      drupal_theme_rebuild();
       // Clear entity cache.
       entity_info_cache_clear();
 
@@ -474,14 +520,17 @@
 }
 
 /**
- * Disable a given set of modules.
+ * Disables a given set of modules.
  *
- * @param $module_list
+ * @param string[] $module_list
  *   An array of module names.
- * @param $disable_dependents
+ * @param bool $disable_dependents
  *   If TRUE, dependent modules will automatically be added and disabled 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.
+ *
+ * @see drupal_uninstall_modules()
+ * @see module_enable()
  */
 function module_disable($module_list, $disable_dependents = TRUE) {
   if ($disable_dependents) {
@@ -539,12 +588,15 @@
     system_list_reset();
     module_list(TRUE);
     module_implements('', FALSE, TRUE);
+    entity_info_cache_clear();
     // Invoke hook_modules_disabled before disabling modules,
     // so we can still call module hooks to get information.
     module_invoke_all('modules_disabled', $invoke_modules);
     // Update the registry to remove the newly-disabled module.
     registry_update();
     _system_update_bootstrap_status();
+    // Update the theme registry to remove the newly-disabled module.
+    drupal_theme_rebuild();
   }
 
   // If there remains no more node_access module, rebuilding will be
@@ -578,11 +630,42 @@
  * just models that you can modify. Only the hooks implemented within modules
  * are executed when running Drupal.
  *
- * See also @link themeable the themeable group page. @endlink
+ * @see themeable
+ * @see callbacks
  */
 
+ /**
+  * @defgroup callbacks Callbacks
+  * @{
+  * Callback function signatures.
+  *
+  * Drupal's API sometimes uses callback functions to allow you to define how
+  * some type of processing happens. A callback is a function with a defined
+  * signature, which you define in a module. Then you pass the function name as
+  * a parameter to a Drupal API function or return it as part of a hook
+  * implementation return value, and your function is called at an appropriate
+  * time. For instance, when setting up batch processing you might need to
+  * provide a callback function for each processing step and/or a callback for
+  * when processing is finished; you would do that by defining these functions
+  * and passing their names into the batch setup function.
+  *
+  * Callback function signatures, like hook definitions, are described by
+  * creating and documenting dummy functions in a *.api.php file; normally, the
+  * dummy callback function's name should start with "callback_", and you should
+  * document the parameters and return value and provide a sample function body.
+  * Then your API documentation can refer to this callback function in its
+  * documentation. A user of your API can usually name their callback function
+  * anything they want, although a standard name would be to replace "callback_"
+  * with the module name.
+  *
+  * @see hooks
+  * @see themeable
+  *
+  * @}
+  */
+
 /**
- * Determine whether a module implements a hook.
+ * Determines whether a module implements a hook.
  *
  * @param $module
  *   The name of the module (without the .module extension).
@@ -611,14 +694,18 @@
 }
 
 /**
- * Determine which modules are implementing a hook.
+ * Determines which modules are implementing a hook.
  *
- * @param $hook
+ * Lazy-loaded include files specified with "group" via hook_hook_info() or
+ * hook_module_implements_alter() will be automatically included by this
+ * function when necessary.
+ *
+ * @param string $hook
  *   The name of the hook (e.g. "help" or "menu").
- * @param $sort
+ * @param bool $sort
  *   By default, modules are ordered by weight and filename, settings this option
  *   to TRUE, module list will be ordered by module name.
- * @param $reset
+ * @param bool $reset
  *   For internal use only: Whether to force the stored list of hook
  *   implementations to be regenerated (such as after enabling a new module,
  *   before processing hook_enable).
@@ -633,8 +720,10 @@
   static $drupal_static_fast;
   if (!isset($drupal_static_fast)) {
     $drupal_static_fast['implementations'] = &drupal_static(__FUNCTION__);
+    $drupal_static_fast['verified'] = &drupal_static(__FUNCTION__ . ':verified');
   }
   $implementations = &$drupal_static_fast['implementations'];
+  $verified = &$drupal_static_fast['verified'];
 
   // We maintain a persistent cache of hook implementations in addition to the
   // static cache to avoid looping through every module and every hook on each
@@ -648,14 +737,19 @@
   // per request.
   if ($reset) {
     $implementations = array();
+    $verified = array();
     cache_set('module_implements', array(), 'cache_bootstrap');
     drupal_static_reset('module_hook_info');
     drupal_static_reset('drupal_alter');
     cache_clear_all('hook_info', 'cache_bootstrap');
+    cache_clear_all('system_cache_tables', 'cache');
     return;
   }
 
   // Fetch implementations from cache.
+  // This happens on the first call to module_implements(*, *, FALSE) during a
+  // request, but also when $implementations have been reset, e.g. after
+  // module_enable().
   if (empty($implementations)) {
     $implementations = cache_get('module_implements', 'cache_bootstrap');
     if ($implementations === FALSE) {
@@ -664,12 +758,17 @@
     else {
       $implementations = $implementations->data;
     }
+    // Forget all previously "verified" hooks, in case that $implementations
+    // were cleared via drupal_static_reset('module_implements') instead of
+    // module_implements(*, *, TRUE).
+    $verified = array();
   }
 
   if (!isset($implementations[$hook])) {
     // The hook is not cached, so ensure that whether or not it has
     // implementations, that the cache is updated at the end of the request.
     $implementations['#write_cache'] = TRUE;
+    // Discover implementations for this hook.
     $hook_info = module_hook_info();
     $implementations[$hook] = array();
     $list = module_list(FALSE, FALSE, $sort);
@@ -681,13 +780,31 @@
         $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
       }
     }
-    // Allow modules to change the weight of specific implementations but avoid
+    // Allow modules to change the weight of specific implementations, but avoid
     // an infinite loop.
     if ($hook != 'module_implements_alter') {
+      // Remember the implementations before hook_module_implements_alter().
+      $implementations_before = $implementations[$hook];
       drupal_alter('module_implements', $implementations[$hook], $hook);
+      // Verify implementations that were added or modified.
+      foreach (array_diff_assoc($implementations[$hook], $implementations_before) as $module => $group) {
+        // If drupal_alter('module_implements') changed or added a $group, the
+        // respective file needs to be included.
+        if ($group) {
+          module_load_include('inc', $module, "$module.$group");
+        }
+        // If a new implementation was added, verify that the function exists.
+        if (!function_exists($module . '_' . $hook)) {
+          unset($implementations[$hook][$module]);
+        }
+      }
     }
+    // Implementations for this hook are now "verified".
+    $verified[$hook] = TRUE;
   }
-  else {
+  elseif (!isset($verified[$hook])) {
+    // Implementations for this hook were in the cache, but they are not
+    // "verified" yet.
     foreach ($implementations[$hook] as $module => $group) {
       // If this hook implementation is stored in a lazy-loaded file, so include
       // that file first.
@@ -706,13 +823,21 @@
         $implementations['#write_cache'] = TRUE;
       }
     }
+    $verified[$hook] = TRUE;
   }
 
   return array_keys($implementations[$hook]);
 }
 
 /**
- * Retrieve a list of what hooks are explicitly declared.
+ * Retrieves a list of hooks that are declared through hook_hook_info().
+ *
+ * @return
+ *   An associative array whose keys are hook names and whose values are an
+ *   associative array containing a group name. The structure of the array
+ *   is the same as the return value of hook_hook_info().
+ *
+ * @see hook_hook_info()
  */
 function module_hook_info() {
   // This function is indirectly invoked from bootstrap_invoke_all(), in which
@@ -763,18 +888,23 @@
  * @see module_implements()
  */
 function module_implements_write_cache() {
+  // The list of implementations includes vital modules only before full
+  // bootstrap, so do not write cache if we are not fully bootstrapped yet.
+  if (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL) {
+    return;
+  }
   $implementations = &drupal_static('module_implements');
-  // Check whether we need to write the cache. We do not want to cache hooks
-  // which are only invoked on HTTP POST requests since these do not need to be
-  // optimized as tightly, and not doing so keeps the cache entry smaller.
-  if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
+  if (isset($implementations['#write_cache'])) {
     unset($implementations['#write_cache']);
     cache_set('module_implements', $implementations, 'cache_bootstrap');
   }
 }
 
 /**
- * Invoke a hook in a particular module.
+ * Invokes a hook in a particular module.
+ *
+ * All arguments are passed by value. Use drupal_alter() if you need to pass
+ * arguments by reference.
  *
  * @param $module
  *   The name of the module (without the .module extension).
@@ -785,6 +915,8 @@
  *
  * @return
  *   The return value of the hook implementation.
+ *
+ * @see drupal_alter()
  */
 function module_invoke($module, $hook) {
   $args = func_get_args();
@@ -796,7 +928,10 @@
 }
 
 /**
- * Invoke a hook in all enabled modules that implement it.
+ * Invokes a hook in all enabled modules that implement it.
+ *
+ * All arguments are passed by value. Use drupal_alter() if you need to pass
+ * arguments by reference.
  *
  * @param $hook
  *   The name of the hook to invoke.
@@ -805,7 +940,11 @@
  *
  * @return
  *   An array of return values of the hook implementations. If modules return
- *   arrays from their implementations, those are merged into one array.
+ *   arrays from their implementations, those are merged into one array
+ *   recursively. Note: integer keys in arrays will be lost, as the merge is
+ *   done using array_merge_recursive().
+ *
+ * @see drupal_alter()
  */
 function module_invoke_all($hook) {
   $args = func_get_args();
@@ -833,13 +972,13 @@
  */
 
 /**
- * Array of modules required by core.
+ * Returns an array of modules required by core.
  */
 function drupal_required_modules() {
   $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.
+  // An installation profile is required and one must always be loaded.
   $required[] = drupal_get_profile();
 
   foreach ($files as $name => $file) {
@@ -853,15 +992,16 @@
 }
 
 /**
- * Hands off alterable variables to type-specific *_alter implementations.
+ * Passes alterable variables to specific hook_TYPE_alter() implementations.
  *
  * This dispatch function hands off the passed-in variables to type-specific
  * hook_TYPE_alter() implementations in modules. It ensures a consistent
  * interface for all altering operations.
  *
- * A maximum of 2 alterable arguments is supported. In case more arguments need
- * to be passed and alterable, modules provide additional variables assigned by
- * reference in the last $context argument:
+ * A maximum of 2 alterable arguments is supported (a third is supported for
+ * legacy reasons, but should not be used in new code). In case more arguments
+ * need to be passed and alterable, modules provide additional variables
+ * assigned by reference in the last $context argument:
  * @code
  *   $context = array(
  *     'alterable' => &$alterable,
@@ -900,8 +1040,14 @@
  *   (optional) An additional variable that is passed by reference. If more
  *   context needs to be provided to implementations, then this should be an
  *   associative array as described above.
+ * @param $context3
+ *   (optional) An additional variable that is passed by reference. This
+ *   parameter is deprecated and will not exist in Drupal 8; consequently, it
+ *   should not be used for new Drupal 7 code either. It is here only for
+ *   backwards compatibility with older code that passed additional arguments
+ *   to drupal_alter().
  */
-function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
+function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
   // Use the advanced drupal_static() pattern, since this is called very often.
   static $drupal_static_fast;
   if (!isset($drupal_static_fast)) {
@@ -952,10 +1098,24 @@
       }
       // If any modules implement one of the extra hooks that do not implement
       // the primary hook, we need to add them to the $modules array in their
-      // appropriate order.
+      // appropriate order. module_implements() can only return ordered
+      // implementations of a single hook. To get the ordered implementations
+      // of multiple hooks, we mimic the module_implements() logic of first
+      // ordering by module_list(), and then calling
+      // drupal_alter('module_implements').
       if (array_diff($extra_modules, $modules)) {
-        // Order the modules by the order returned by module_list().
+        // Merge the arrays and order by module_list().
         $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
+        // Since module_implements() already took care of loading the necessary
+        // include files, we can safely pass FALSE for the array values.
+        $implementations = array_fill_keys($modules, FALSE);
+        // Let modules adjust the order solely based on the primary hook. This
+        // ensures the same module order regardless of whether this if block
+        // runs. Calling drupal_alter() recursively in this way does not result
+        // in an infinite loop, because this call is for a single $type, so we
+        // won't end up in this code block again.
+        drupal_alter('module_implements', $implementations, $hook);
+        $modules = array_keys($implementations);
       }
       foreach ($modules as $module) {
         // Since $modules is a merged array, for any given module, we do not
@@ -1000,7 +1160,6 @@
   }
 
   foreach ($functions[$cid] as $function) {
-    $function($data, $context1, $context2);
+    $function($data, $context1, $context2, $context3);
   }
 }
-
diff -Naur drupal-7.9/includes/pager.inc drupal-7.58/includes/pager.inc
--- drupal-7.9/includes/pager.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/pager.inc	2018-03-27 21:28:19.000000000 +0200
@@ -630,7 +630,13 @@
     }
   }
 
-  return l($text, $_GET['q'], array('attributes' => $attributes, 'query' => $query));
+  // @todo l() cannot be used here, since it adds an 'active' class based on the
+  //   path only (which is always the current path for pager links). Apparently,
+  //   none of the pager links is active at any time - but it should still be
+  //   possible to use l() here.
+  // @see http://drupal.org/node/1410574
+  $attributes['href'] = url($_GET['q'], array('query' => $query));
+  return '<a' . drupal_attributes($attributes) . '>' . check_plain($text) . '</a>';
 }
 
 /**
diff -Naur drupal-7.9/includes/password.inc drupal-7.58/includes/password.inc
--- drupal-7.9/includes/password.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/password.inc	2018-03-27 21:28:19.000000000 +0200
@@ -43,7 +43,7 @@
 }
 
 /**
- * Encode bytes into printable base 64 using the *nix standard from crypt().
+ * Encodes bytes into printable base 64 using the *nix standard from crypt().
  *
  * @param $input
  *   The string containing bytes to encode.
@@ -140,7 +140,7 @@
  * @param $algo
  *   The string name of a hashing algorithm usable by hash(), like 'sha256'.
  * @param $password
- *   The plain-text password to hash.
+ *   Plain-text password up to 512 bytes (128 to 512 UTF-8 characters) to hash.
  * @param $setting
  *   An existing hash or the output of _password_generate_salt().  Must be
  *   at least 12 characters (the settings and salt).
@@ -150,6 +150,10 @@
  *   The return string will be truncated at DRUPAL_HASH_LENGTH characters max.
  */
 function _password_crypt($algo, $password, $setting) {
+  // Prevent DoS attacks by refusing to hash large passwords.
+  if (strlen($password) > 512) {
+    return FALSE;
+  }
   // The first 12 characters of an existing hash are its setting string.
   $setting = substr($setting, 0, 12);
 
@@ -285,4 +289,3 @@
   // Check whether the iteration count used differs from the standard number.
   return (_password_get_count_log2($account->pass) !== $count_log2);
 }
-
diff -Naur drupal-7.9/includes/path.inc drupal-7.58/includes/path.inc
--- drupal-7.9/includes/path.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/path.inc	2018-03-27 21:28:19.000000000 +0200
@@ -13,12 +13,12 @@
  * Initialize the $_GET['q'] variable to the proper normal path.
  */
 function drupal_path_initialize() {
-  if (!empty($_GET['q'])) {
-    $_GET['q'] = drupal_get_normal_path($_GET['q']);
-  }
-  else {
-    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
+  // Ensure $_GET['q'] is set before calling drupal_normal_path(), to support
+  // path caching with hook_url_inbound_alter().
+  if (empty($_GET['q'])) {
+    $_GET['q'] = variable_get('site_frontpage', 'node');
   }
+  $_GET['q'] = drupal_get_normal_path($_GET['q']);
 }
 
 /**
@@ -347,7 +347,8 @@
  * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
  *
  * @return
- *   The current Drupal URL path.
+ *   The current Drupal URL path. The path is untrusted user input and must be
+ *   treated as such.
  *
  * @see request_path()
  */
@@ -386,7 +387,7 @@
 }
 
 /**
- * Fetch a specific URL alias from the database.
+ * Fetches a specific URL alias from the database.
  *
  * @param $conditions
  *   A string representing the source, a number representing the pid, or an
@@ -431,21 +432,27 @@
  *   - language: (optional) The language of the alias.
  */
 function path_save(&$path) {
-  $path += array('pid' => NULL, 'language' => LANGUAGE_NONE);
+  $path += array('language' => LANGUAGE_NONE);
 
-  // Insert or update the alias.
-  $status = drupal_write_record('url_alias', $path, (!empty($path['pid']) ? 'pid' : array()));
+  // Load the stored alias, if any.
+  if (!empty($path['pid']) && !isset($path['original'])) {
+    $path['original'] = path_load($path['pid']);
+  }
 
-  // Verify that a record was written.
-  if ($status) {
-    if ($status === SAVED_NEW) {
-      module_invoke_all('path_insert', $path);
-    }
-    else {
-      module_invoke_all('path_update', $path);
-    }
-    drupal_clear_path_cache($path['source']);
+  if (empty($path['pid'])) {
+    drupal_write_record('url_alias', $path);
+    module_invoke_all('path_insert', $path);
   }
+  else {
+    drupal_write_record('url_alias', $path, array('pid'));
+    module_invoke_all('path_update', $path);
+  }
+
+  // Clear internal properties.
+  unset($path['original']);
+
+  // Clear the static alias cache.
+  drupal_clear_path_cache($path['source']);
 }
 
 /**
@@ -469,11 +476,11 @@
 }
 
 /**
- * Determine whether a path is in the administrative section of the site.
+ * Determines whether a path is in the administrative section of the site.
  *
- * By default, paths are considered to be non-administrative. If a path does not
- * match any of the patterns in path_get_admin_paths(), or if it matches both
- * administrative and non-administrative patterns, it is considered
+ * By default, paths are considered to be non-administrative. If a path does
+ * not match any of the patterns in path_get_admin_paths(), or if it matches
+ * both administrative and non-administrative patterns, it is considered
  * non-administrative.
  *
  * @param $path
@@ -497,7 +504,7 @@
 }
 
 /**
- * Get a list of administrative and non-administrative paths.
+ * Gets a list of administrative and non-administrative paths.
  *
  * @return array
  *   An associative array containing the following keys:
@@ -554,8 +561,8 @@
   elseif ($dynamic_allowed && preg_match('/\/\%/', $path)) {
     // Path is dynamic (ie 'user/%'), so check directly against menu_router table.
     if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) {
-      $item['link_path']  = $form_item['link_path'];
-      $item['link_title'] = $form_item['link_title'];
+      $item['link_path']  = $item['path'];
+      $item['link_title'] = $item['title'];
       $item['external']   = FALSE;
       $item['options'] = '';
       _menu_link_translate($item);
diff -Naur drupal-7.9/includes/registry.inc drupal-7.58/includes/registry.inc
--- drupal-7.9/includes/registry.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/registry.inc	2018-03-27 21:28:19.000000000 +0200
@@ -10,7 +10,7 @@
  * @{
  * The code registry engine.
  *
- * Drupal maintains an internal registry of all functions or classes in the
+ * Drupal maintains an internal registry of all interfaces or classes in the
  * system, allowing it to lazy-load code files as needed (reducing the amount
  * of code that must be parsed on each request).
  */
@@ -120,7 +120,10 @@
 }
 
 /**
- * Parse all files that have changed since the registry was last built, and save their function and class listings.
+ * Parse all changed files and save their interface and class listings.
+ *
+ * Parse all files that have changed since the registry was last built, and save
+ * their interface and class listings.
  *
  * @param $files
  *  The list of files to check and parse.
@@ -131,10 +134,6 @@
     if (file_exists($filename)) {
       $hash = hash_file('sha256', $filename);
       if (empty($file['hash']) || $file['hash'] != $hash) {
-        // Delete registry entries for this file, so we can insert the new resources.
-        db_delete('registry')
-          ->condition('filename', $filename)
-          ->execute();
         $file['hash'] = $hash;
         $parsed_files[$filename] = $file;
       }
@@ -153,34 +152,41 @@
 }
 
 /**
- * Parse a file and save its function and class listings.
+ * Parse a file and save its interface and class listings.
  *
  * @param $filename
- *  Name of the file we are going to parse.
+ *   Name of the file we are going to parse.
  * @param $contents
- *  Contents of the file we are going to parse as a string.
+ *   Contents of the file we are going to parse as a string.
  * @param $module
  *   (optional) Name of the module this file belongs to.
  * @param $weight
  *   (optional) Weight of the module.
  */
 function _registry_parse_file($filename, $contents, $module = '', $weight = 0) {
-  if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
-    $query = db_insert('registry')->fields(array('name', 'type', 'filename', 'module', 'weight'));
+  if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface|trait)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
     foreach ($matches[2] as $key => $name) {
-      $query->values(array(
-        'name' => $name,
-        'type' => $matches[1][$key],
-        'filename' => $filename,
-        'module' => $module,
-        'weight' => $weight,
-      ));
-    }
-    $query->execute();
+      db_merge('registry')
+        ->key(array(
+          'name' => $name,
+          'type' => $matches[1][$key],
+        ))
+        ->fields(array(
+          'filename' => $filename,
+          'module' => $module,
+          'weight' => $weight,
+        ))
+        ->execute();
+    }
+    // Delete any resources for this file where the name is not in the list
+    // we just merged in.
+    db_delete('registry')
+      ->condition('filename', $filename)
+      ->condition('name', $matches[2], 'NOT IN')
+      ->execute();
   }
 }
 
 /**
  * @} End of "defgroup registry".
  */
-
diff -Naur drupal-7.9/includes/request-sanitizer.inc drupal-7.58/includes/request-sanitizer.inc
--- drupal-7.9/includes/request-sanitizer.inc	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/includes/request-sanitizer.inc	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains code for sanitizing user input from the request.
+ */
+
+/**
+ * Sanitizes user input from the request.
+ */
+class DrupalRequestSanitizer {
+
+  /**
+   * Tracks whether the request was already sanitized.
+   */
+  protected static $sanitized = FALSE;
+
+  /**
+   * Modifies the request to strip dangerous keys from user input.
+   */
+  public static function sanitize() {
+    if (!self::$sanitized) {
+      $whitelist = variable_get('sanitize_input_whitelist', array());
+      $log_sanitized_keys = variable_get('sanitize_input_logging', FALSE);
+
+      // Process query string parameters.
+      $get_sanitized_keys = array();
+      $_GET = self::stripDangerousValues($_GET, $whitelist, $get_sanitized_keys);
+      if ($log_sanitized_keys && $get_sanitized_keys) {
+        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from query string parameters (GET): @keys', array('@keys' => implode(', ', $get_sanitized_keys))), E_USER_NOTICE);
+      }
+
+      // Process request body parameters.
+      $post_sanitized_keys = array();
+      $_POST = self::stripDangerousValues($_POST, $whitelist, $post_sanitized_keys);
+      if ($log_sanitized_keys && $post_sanitized_keys) {
+        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from request body parameters (POST): @keys', array('@keys' => implode(', ', $post_sanitized_keys))), E_USER_NOTICE);
+      }
+
+      // Process cookie parameters.
+      $cookie_sanitized_keys = array();
+      $_COOKIE = self::stripDangerousValues($_COOKIE, $whitelist, $cookie_sanitized_keys);
+      if ($log_sanitized_keys && $cookie_sanitized_keys) {
+        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from cookie parameters (COOKIE): @keys', array('@keys' => implode(', ', $cookie_sanitized_keys))), E_USER_NOTICE);
+      }
+
+      $request_sanitized_keys = array();
+      $_REQUEST = self::stripDangerousValues($_REQUEST, $whitelist, $request_sanitized_keys);
+
+      self::$sanitized = TRUE;
+    }
+  }
+
+  /**
+   * Strips dangerous keys from the provided input.
+   *
+   * @param mixed $input
+   *   The input to sanitize.
+   * @param string[] $whitelist
+   *   An array of keys to whitelist as safe.
+   * @param string[] $sanitized_keys
+   *   An array of keys that have been removed.
+   *
+   * @return mixed
+   *   The sanitized input.
+   */
+  protected static function stripDangerousValues($input, array $whitelist, array &$sanitized_keys) {
+    if (is_array($input)) {
+      foreach ($input as $key => $value) {
+        if ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE)) {
+          unset($input[$key]);
+          $sanitized_keys[] = $key;
+        }
+        else {
+          $input[$key] = self::stripDangerousValues($input[$key], $whitelist, $sanitized_keys);
+        }
+      }
+    }
+    return $input;
+  }
+
+}
diff -Naur drupal-7.9/includes/session.inc drupal-7.58/includes/session.inc
--- drupal-7.9/includes/session.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/session.inc	2018-03-27 21:28:19.000000000 +0200
@@ -79,7 +79,7 @@
   // Handle the case of first time visitors and clients that don't store
   // cookies (eg. web crawlers).
   $insecure_session_name = substr(session_name(), 1);
-  if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) {
+  if (empty($sid) || (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name]))) {
     $user = drupal_anonymous_user();
     return '';
   }
@@ -163,7 +163,7 @@
   try {
     if (!drupal_save_session()) {
       // We don't have anything to do if we are not allowed to save the session.
-      return;
+      return TRUE;
     }
 
     // Check whether $_SESSION has been changed in this request.
@@ -172,7 +172,7 @@
 
     // For performance reasons, do not update the sessions table, unless
     // $_SESSION has changed or more than 180 has passed since the last update.
-    if ($is_changed || REQUEST_TIME - $user->timestamp > variable_get('session_write_interval', 180)) {
+    if ($is_changed || !isset($user->timestamp) || REQUEST_TIME - $user->timestamp > variable_get('session_write_interval', 180)) {
       // Either ssid or sid or both will be added from $key below.
       $fields = array(
         'uid' => $user->uid,
@@ -199,6 +199,9 @@
           }
         }
       }
+      elseif (variable_get('https', FALSE)) {
+        unset($key['ssid']);
+      }
 
       db_merge('sessions')
         ->key($key)
@@ -255,17 +258,23 @@
     // we lazily start sessions at the end of this request, and some
     // processes (like drupal_get_token()) needs to know the future
     // session ID in advance.
+    $GLOBALS['lazy_session'] = TRUE;
     $user = drupal_anonymous_user();
     // Less random sessions (which are much faster to generate) are used for
     // anonymous users than are generated in drupal_session_regenerate() when
     // a user becomes authenticated.
-    session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE)));
+    session_id(drupal_random_key());
+    if ($is_https && variable_get('https', FALSE)) {
+      $insecure_session_name = substr(session_name(), 1);
+      $session_id = drupal_random_key();
+      $_COOKIE[$insecure_session_name] = $session_id;
+    }
   }
   date_default_timezone_set(drupal_get_user_timezone());
 }
 
 /**
- * Forcefully starts a session, preserving already set session data.
+ * Starts a session forcefully, preserving already set session data.
  *
  * @ingroup php_wrappers
  */
@@ -291,7 +300,7 @@
  * If an anonymous user already have an empty session, destroy it.
  */
 function drupal_session_commit() {
-  global $user;
+  global $user, $is_https;
 
   if (!drupal_save_session()) {
     // We don't have anything to do if we are not allowed to save the session.
@@ -310,6 +319,12 @@
     // started.
     if (!drupal_session_started()) {
       drupal_session_start();
+      if ($is_https && variable_get('https', FALSE)) {
+        $insecure_session_name = substr(session_name(), 1);
+        $params = session_get_cookie_params();
+        $expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
+        setcookie($insecure_session_name, $_COOKIE[$insecure_session_name], $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
+      }
     }
     // Write the session data.
     session_write_close();
@@ -334,13 +349,18 @@
  */
 function drupal_session_regenerate() {
   global $user, $is_https;
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return;
+  }
+
   if ($is_https && variable_get('https', FALSE)) {
     $insecure_session_name = substr(session_name(), 1);
-    if (isset($_COOKIE[$insecure_session_name])) {
+    if (!isset($GLOBALS['lazy_session']) && isset($_COOKIE[$insecure_session_name])) {
       $old_insecure_session_id = $_COOKIE[$insecure_session_name];
     }
     $params = session_get_cookie_params();
-    $session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
+    $session_id = drupal_random_key();
     // If a session cookie lifetime is set, the session will expire
     // $params['lifetime'] seconds from the current request. If it is not set,
     // it will expire when the browser is closed.
@@ -352,7 +372,7 @@
   if (drupal_session_started()) {
     $old_session_id = session_id();
   }
-  session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)));
+  session_id(drupal_random_key());
 
   if (isset($old_session_id)) {
     $params = session_get_cookie_params();
@@ -403,6 +423,11 @@
 function _drupal_session_destroy($sid) {
   global $user, $is_https;
 
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return TRUE;
+  }
+
   // Delete session data.
   db_delete('sessions')
     ->condition($is_https ? 'ssid' : 'sid', $sid)
@@ -416,8 +441,13 @@
   // Unset the session cookies.
   _drupal_session_delete_cookie(session_name());
   if ($is_https) {
-    _drupal_session_delete_cookie(substr(session_name(), 1), TRUE);
+    _drupal_session_delete_cookie(substr(session_name(), 1), FALSE);
+  }
+  elseif (variable_get('https', FALSE)) {
+    _drupal_session_delete_cookie('S' . session_name(), TRUE);
   }
+
+  return TRUE;
 }
 
 /**
@@ -425,13 +455,17 @@
  *
  * @param $name
  *   Name of session cookie to delete.
- * @param $force_insecure
- *   Force cookie to be insecure.
+ * @param boolean $secure
+ *   Force the secure value of the cookie.
  */
-function _drupal_session_delete_cookie($name, $force_insecure = FALSE) {
-  if (isset($_COOKIE[$name])) {
+function _drupal_session_delete_cookie($name, $secure = NULL) {
+  global $is_https;
+  if (isset($_COOKIE[$name]) || (!$is_https && $secure === TRUE)) {
     $params = session_get_cookie_params();
-    setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], !$force_insecure && $params['secure'], $params['httponly']);
+    if ($secure !== NULL) {
+      $params['secure'] = $secure;
+    }
+    setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
     unset($_COOKIE[$name]);
   }
 }
@@ -443,6 +477,11 @@
  *   User ID.
  */
 function drupal_session_destroy_uid($uid) {
+  // Nothing to do if we are not allowed to change the session.
+  if (!drupal_save_session()) {
+    return;
+  }
+
   db_delete('sessions')
     ->condition('uid', $uid)
     ->execute();
@@ -485,7 +524,10 @@
  *   FALSE if writing session data has been disabled. Otherwise, TRUE.
  */
 function drupal_save_session($status = NULL) {
-  $save_session = &drupal_static(__FUNCTION__, TRUE);
+  // PHP session ID, session, and cookie handling happens in the global scope.
+  // This value has to persist across calls to drupal_static_reset(), since a
+  // potentially wrong or disallowed session would be written otherwise.
+  static $save_session = TRUE;
   if (isset($status)) {
     $save_session = $status;
   }
diff -Naur drupal-7.9/includes/stream_wrappers.inc drupal-7.58/includes/stream_wrappers.inc
--- drupal-7.9/includes/stream_wrappers.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/stream_wrappers.inc	2018-03-27 21:28:19.000000000 +0200
@@ -93,7 +93,7 @@
 /**
  * Generic PHP stream wrapper interface.
  *
- * @see http://www.php.net/manual/en/class.streamwrapper.php
+ * @see http://www.php.net/manual/class.streamwrapper.php
  */
 interface StreamWrapperInterface {
   public function stream_open($uri, $mode, $options, &$opened_url);
@@ -133,7 +133,7 @@
    * @param $uri
    *   A string containing the URI that should be used for this instance.
    */
-  function setUri($uri);
+  public function setUri($uri);
 
   /**
    * Returns the stream resource URI.
@@ -219,7 +219,6 @@
   public function dirname($uri = NULL);
 }
 
-
 /**
  * Drupal stream wrapper base class for local files.
  *
@@ -317,7 +316,7 @@
     }
 
     $extension = '';
-    $file_parts = explode('.', basename($uri));
+    $file_parts = explode('.', drupal_basename($uri));
 
     // Remove the first part: a full filename should not match an extension.
     array_shift($file_parts);
@@ -377,7 +376,7 @@
     $realpath = realpath($path);
     if (!$realpath) {
       // This file does not yet exist.
-      $realpath = realpath(dirname($path)) . '/' . basename($path);
+      $realpath = realpath(dirname($path)) . '/' . drupal_basename($path);
     }
     $directory = realpath($this->getDirectoryPath());
     if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
@@ -401,7 +400,7 @@
    * @return
    *   Returns TRUE if file was opened successfully.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-open.php
+   * @see http://php.net/manual/streamwrapper.stream-open.php
    */
   public function stream_open($uri, $mode, $options, &$opened_path) {
     $this->uri = $uri;
@@ -429,7 +428,7 @@
    * @return
    *   Always returns TRUE at the present time.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-lock.php
+   * @see http://php.net/manual/streamwrapper.stream-lock.php
    */
   public function stream_lock($operation) {
     if (in_array($operation, array(LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB))) {
@@ -448,7 +447,7 @@
    * @return
    *   The string that was read, or FALSE in case of an error.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-read.php
+   * @see http://php.net/manual/streamwrapper.stream-read.php
    */
   public function stream_read($count) {
     return fread($this->handle, $count);
@@ -463,7 +462,7 @@
    * @return
    *   The number of bytes written (integer).
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-write.php
+   * @see http://php.net/manual/streamwrapper.stream-write.php
    */
   public function stream_write($data) {
     return fwrite($this->handle, $data);
@@ -475,7 +474,7 @@
    * @return
    *   TRUE if end-of-file has been reached.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-eof.php
+   * @see http://php.net/manual/streamwrapper.stream-eof.php
    */
   public function stream_eof() {
     return feof($this->handle);
@@ -492,7 +491,7 @@
    * @return
    *   TRUE on success.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-seek.php
+   * @see http://php.net/manual/streamwrapper.stream-seek.php
    */
   public function stream_seek($offset, $whence) {
     // fseek returns 0 on success and -1 on a failure.
@@ -506,7 +505,7 @@
    * @return
    *   TRUE if data was successfully stored (or there was no data to store).
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-flush.php
+   * @see http://php.net/manual/streamwrapper.stream-flush.php
    */
   public function stream_flush() {
     return fflush($this->handle);
@@ -518,7 +517,7 @@
    * @return
    *   The current offset in bytes from the beginning of file.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-tell.php
+   * @see http://php.net/manual/streamwrapper.stream-tell.php
    */
   public function stream_tell() {
     return ftell($this->handle);
@@ -531,7 +530,7 @@
    *   An array with file status, or FALSE in case of an error - see fstat()
    *   for a description of this array.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-stat.php
+   * @see http://php.net/manual/streamwrapper.stream-stat.php
    */
   public function stream_stat() {
     return fstat($this->handle);
@@ -543,22 +542,171 @@
    * @return
    *   TRUE if stream was successfully closed.
    *
-   * @see http://php.net/manual/en/streamwrapper.stream-close.php
+   * @see http://php.net/manual/streamwrapper.stream-close.php
    */
   public function stream_close() {
     return fclose($this->handle);
   }
 
   /**
+   * Sets metadata on the stream.
+   *
+   * WARNING: Do not call this method directly! It will be called internally by
+   * PHP itself when one of the following functions is called on a stream URL:
+   *
+   * @param string $uri
+   *   A string containing the URI to the file to set metadata on.
+   * @param int $option
+   *   One of:
+   *   - STREAM_META_TOUCH: The method was called in response to touch().
+   *   - STREAM_META_OWNER_NAME: The method was called in response to chown()
+   *     with string parameter.
+   *   - STREAM_META_OWNER: The method was called in response to chown().
+   *   - STREAM_META_GROUP_NAME: The method was called in response to chgrp().
+   *   - STREAM_META_GROUP: The method was called in response to chgrp().
+   *   - STREAM_META_ACCESS: The method was called in response to chmod().
+   * @param mixed $value
+   *   If option is:
+   *   - STREAM_META_TOUCH: Array consisting of two arguments of the touch()
+   *     function.
+   *   - STREAM_META_OWNER_NAME or STREAM_META_GROUP_NAME: The name of the owner
+   *     user/group as string.
+   *   - STREAM_META_OWNER or STREAM_META_GROUP: The value of the owner
+   *     user/group as integer.
+   *   - STREAM_META_ACCESS: The argument of the chmod() as integer.
+   *
+   * @return bool
+   *   Returns TRUE on success or FALSE on failure. If $option is not
+   *   implemented, FALSE should be returned.
+   *
+   * @see touch()
+   * @see chmod()
+   * @see chown()
+   * @see chgrp()
+   * @link http://php.net/manual/streamwrapper.stream-metadata.php
+   */
+  public function stream_metadata($uri, $option, $value) {
+    $target = $this->getLocalPath($uri);
+    $return = FALSE;
+    switch ($option) {
+      case STREAM_META_TOUCH:
+        if (!empty($value)) {
+          $return = touch($target, $value[0], $value[1]);
+        }
+        else {
+          $return = touch($target);
+        }
+        break;
+
+      case STREAM_META_OWNER_NAME:
+      case STREAM_META_OWNER:
+        $return = chown($target, $value);
+        break;
+
+      case STREAM_META_GROUP_NAME:
+      case STREAM_META_GROUP:
+        $return = chgrp($target, $value);
+        break;
+
+      case STREAM_META_ACCESS:
+        $return = chmod($target, $value);
+        break;
+    }
+    if ($return) {
+      // For convenience clear the file status cache of the underlying file,
+      // since metadata operations are often followed by file status checks.
+      clearstatcache(TRUE, $target);
+    }
+    return $return;
+  }
+
+  /**
+   * Truncate stream.
+   *
+   * Will respond to truncation; e.g., through ftruncate().
+   *
+   * @param int $new_size
+   *   The new size.
+   *
+   * @return bool
+   *   TRUE on success, FALSE otherwise.
+   */
+  public function stream_truncate($new_size) {
+    return ftruncate($this->handle, $new_size);
+  }
+
+  /**
+   * Retrieve the underlying stream resource.
+   *
+   * This method is called in response to stream_select().
+   *
+   * @param int $cast_as
+   *   Can be STREAM_CAST_FOR_SELECT when stream_select() is calling
+   *   stream_cast() or STREAM_CAST_AS_STREAM when stream_cast() is called for
+   *   other uses.
+   *
+   * @return resource|false
+   *   The underlying stream resource or FALSE if stream_select() is not
+   *   supported.
+   *
+   * @see stream_select()
+   * @link http://php.net/manual/streamwrapper.stream-cast.php
+   */
+  public function stream_cast($cast_as) {
+    return $this->handle ? $this->handle : FALSE;
+  }
+
+  /**
+   * Change stream options.
+   *
+   * This method is called to set options on the stream.
+   *
+   * Since Windows systems do not allow it and it is not needed for most use
+   * cases anyway, this method is not supported on local files and will trigger
+   * an error and return false. If needed, custom subclasses can provide
+   * OS-specific implementations for advanced use cases.
+   *
+   * @param int $option
+   *   One of:
+   *   - STREAM_OPTION_BLOCKING: The method was called in response to
+   *     stream_set_blocking().
+   *   - STREAM_OPTION_READ_TIMEOUT: The method was called in response to
+   *     stream_set_timeout().
+   *   - STREAM_OPTION_WRITE_BUFFER: The method was called in response to
+   *     stream_set_write_buffer().
+   * @param int $arg1
+   *   If option is:
+   *   - STREAM_OPTION_BLOCKING: The requested blocking mode:
+   *     - 1 means blocking.
+   *     - 0 means not blocking.
+   *   - STREAM_OPTION_READ_TIMEOUT: The timeout in seconds.
+   *   - STREAM_OPTION_WRITE_BUFFER: The buffer mode, STREAM_BUFFER_NONE or
+   *     STREAM_BUFFER_FULL.
+   * @param int $arg2
+   *   If option is:
+   *   - STREAM_OPTION_BLOCKING: This option is not set.
+   *   - STREAM_OPTION_READ_TIMEOUT: The timeout in microseconds.
+   *   - STREAM_OPTION_WRITE_BUFFER: The requested buffer size.
+   *
+   * @return bool
+   *   TRUE on success, FALSE otherwise. If $option is not implemented, FALSE
+   *   should be returned.
+   */
+  public function stream_set_option($option, $arg1, $arg2) {
+    trigger_error('stream_set_option() not supported for local file based stream wrappers', E_USER_WARNING);
+    return FALSE;
+  }
+
+  /**
    * Support for unlink().
    *
    * @param $uri
-   *   A string containing the uri to the resource to delete.
+   *   A string containing the URI to the resource to delete.
    *
    * @return
    *   TRUE if resource was successfully deleted.
    *
-   * @see http://php.net/manual/en/streamwrapper.unlink.php
+   * @see http://php.net/manual/streamwrapper.unlink.php
    */
   public function unlink($uri) {
     $this->uri = $uri;
@@ -569,14 +717,14 @@
    * Support for rename().
    *
    * @param $from_uri,
-   *   The uri to the file to rename.
+   *   The URI to the file to rename.
    * @param $to_uri
-   *   The new uri for file.
+   *   The new URI for file.
    *
    * @return
    *   TRUE if file was successfully renamed.
    *
-   * @see http://php.net/manual/en/streamwrapper.rename.php
+   * @see http://php.net/manual/streamwrapper.rename.php
    */
   public function rename($from_uri, $to_uri) {
     return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
@@ -622,7 +770,7 @@
    * @return
    *   TRUE if directory was successfully created.
    *
-   * @see http://php.net/manual/en/streamwrapper.mkdir.php
+   * @see http://php.net/manual/streamwrapper.mkdir.php
    */
   public function mkdir($uri, $mode, $options) {
     $this->uri = $uri;
@@ -654,7 +802,7 @@
    * @return
    *   TRUE if directory was successfully removed.
    *
-   * @see http://php.net/manual/en/streamwrapper.rmdir.php
+   * @see http://php.net/manual/streamwrapper.rmdir.php
    */
   public function rmdir($uri, $options) {
     $this->uri = $uri;
@@ -678,7 +826,7 @@
    *   An array with file status, or FALSE in case of an error - see fstat()
    *   for a description of this array.
    *
-   * @see http://php.net/manual/en/streamwrapper.url-stat.php
+   * @see http://php.net/manual/streamwrapper.url-stat.php
    */
   public function url_stat($uri, $flags) {
     $this->uri = $uri;
@@ -704,7 +852,7 @@
    * @return
    *   TRUE on success.
    *
-   * @see http://php.net/manual/en/streamwrapper.dir-opendir.php
+   * @see http://php.net/manual/streamwrapper.dir-opendir.php
    */
   public function dir_opendir($uri, $options) {
     $this->uri = $uri;
@@ -719,7 +867,7 @@
    * @return
    *   The next filename, or FALSE if there are no more files in the directory.
    *
-   * @see http://php.net/manual/en/streamwrapper.dir-readdir.php
+   * @see http://php.net/manual/streamwrapper.dir-readdir.php
    */
   public function dir_readdir() {
     return readdir($this->handle);
@@ -731,7 +879,7 @@
    * @return
    *   TRUE on success.
    *
-   * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
+   * @see http://php.net/manual/streamwrapper.dir-rewinddir.php
    */
   public function dir_rewinddir() {
     rewinddir($this->handle);
@@ -747,7 +895,7 @@
    * @return
    *   TRUE on success.
    *
-   * @see http://php.net/manual/en/streamwrapper.dir-closedir.php
+   * @see http://php.net/manual/streamwrapper.dir-closedir.php
    */
   public function dir_closedir() {
     closedir($this->handle);
@@ -788,8 +936,6 @@
  *
  * Provides support for storing privately accessible files with the Drupal file
  * interface.
- *
- * Extends DrupalPublicStreamWrapper.
  */
 class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
   /**
diff -Naur drupal-7.9/includes/tablesort.inc drupal-7.58/includes/tablesort.inc
--- drupal-7.9/includes/tablesort.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/tablesort.inc	2018-03-27 21:28:19.000000000 +0200
@@ -46,16 +46,15 @@
       // Based on code from db_escape_table(), but this can also contain a dot.
       $field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']);
 
-      // Sort order can only be ASC or DESC.
-      $sort = drupal_strtoupper($ts['sort']);
-      $sort = in_array($sort, array('ASC', 'DESC')) ? $sort : '';
-      $this->orderBy($field, $sort);
+      // orderBy() will ensure that only ASC/DESC values are accepted, so we
+      // don't need to sanitize that here.
+      $this->orderBy($field, $ts['sort']);
     }
     return $this;
   }
 
   /**
-   * Initialize the table sort context.
+   * Initializes the table sort context.
    */
   protected function init() {
     $ts = $this->order();
@@ -115,7 +114,7 @@
 }
 
 /**
- * Format a column header.
+ * Formats a column header.
  *
  * If the cell in question is the column header for the current sort criterion,
  * it gets special formatting. All possible sort criteria become links.
@@ -126,6 +125,7 @@
  *   An array of column headers in the format described in theme_table().
  * @param $ts
  *   The current table sort context as returned from tablesort_init().
+ *
  * @return
  *   A properly formatted cell, ready for _theme_table_cell().
  */
@@ -151,7 +151,7 @@
 }
 
 /**
- * Format a table cell.
+ * Formats a table cell.
  *
  * Adds a class attribute to all cells in the currently active column.
  *
@@ -163,6 +163,7 @@
  *   The current table sort context as returned from tablesort_init().
  * @param $i
  *   The index of the cell's table column.
+ *
  * @return
  *   A properly formatted cell, ready for _theme_table_cell().
  */
@@ -179,7 +180,7 @@
 }
 
 /**
- * Compose a URL query parameter array for table sorting links.
+ * Composes a URL query parameter array for table sorting links.
  *
  * @return
  *   A URL query parameter array that consists of all components of the current
@@ -190,10 +191,11 @@
 }
 
 /**
- * Determine the current sort criterion.
+ * Determines the current sort criterion.
  *
  * @param $headers
  *   An array of column headers in the format described in theme_table().
+ *
  * @return
  *   An associative array describing the criterion, containing the keys:
  *   - "name": The localized title of the table column.
@@ -226,10 +228,11 @@
 }
 
 /**
- * Determine the current sort direction.
+ * Determines the current sort direction.
  *
  * @param $headers
  *   An array of column headers in the format described in theme_table().
+ *
  * @return
  *   The current sort direction ("asc" or "desc").
  */
diff -Naur drupal-7.9/includes/theme.inc drupal-7.58/includes/theme.inc
--- drupal-7.9/includes/theme.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/theme.inc	2018-03-27 21:28:19.000000000 +0200
@@ -65,7 +65,7 @@
 }
 
 /**
- * Initialize the theme system by loading the theme.
+ * Initializes the theme system by loading the theme.
  */
 function drupal_theme_initialize() {
   global $theme, $user, $theme_key;
@@ -113,8 +113,9 @@
 }
 
 /**
- * Initialize the theme system given already loaded information. This
- * function is useful to initialize a theme when no database is present.
+ * Initializes the theme system given already loaded information.
+ *
+ * This function is useful to initialize a theme when no database is present.
  *
  * @param $theme
  *   An object with the following information:
@@ -235,24 +236,52 @@
 }
 
 /**
- * Get the theme registry.
+ * Gets the theme registry.
+ *
+ * @param $complete
+ *   Optional boolean to indicate whether to return the complete theme registry
+ *   array or an instance of the ThemeRegistry class. If TRUE, the complete
+ *   theme registry array will be returned. This is useful if you want to
+ *   foreach over the whole registry, use array_* functions or inspect it in a
+ *   debugger. If FALSE, an instance of the ThemeRegistry class will be
+ *   returned, this provides an ArrayObject which allows it to be accessed
+ *   with array syntax and  isset(), and should be more lightweight
+ *   than the full registry. Defaults to TRUE.
  *
  * @return
- *   The theme registry array if it has been stored in memory, NULL otherwise.
+ *   The complete theme registry array, or an instance of the ThemeRegistry
+ *   class.
  */
-function theme_get_registry() {
-  static $theme_registry = NULL;
+function theme_get_registry($complete = TRUE) {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['registry'] = &drupal_static('theme_get_registry');
+  }
+  $theme_registry = &$drupal_static_fast['registry'];
 
-  if (!isset($theme_registry)) {
+  // Initialize the theme, if this is called early in the bootstrap, or after
+  // static variables have been reset.
+  if (!is_array($theme_registry)) {
+    drupal_theme_initialize();
+    $theme_registry = array();
+  }
+
+  $key = (int) $complete;
+
+  if (!isset($theme_registry[$key])) {
     list($callback, $arguments) = _theme_registry_callback();
-    $theme_registry = call_user_func_array($callback, $arguments);
+    if (!$complete) {
+      $arguments[] = FALSE;
+    }
+    $theme_registry[$key] = call_user_func_array($callback, $arguments);
   }
 
-  return $theme_registry;
+  return $theme_registry[$key];
 }
 
 /**
- * Set the callback that will be used by theme_get_registry() to fetch the registry.
+ * Sets the callback that will be used by theme_get_registry().
  *
  * @param $callback
  *   The name of the callback function.
@@ -268,7 +297,7 @@
 }
 
 /**
- * Get the theme_registry cache from the database; if it doesn't exist, build it.
+ * Gets the theme_registry cache; if it doesn't exist, builds it.
  *
  * @param $theme
  *   The loaded $theme object as returned by list_themes().
@@ -277,42 +306,165 @@
  *   oldest first order.
  * @param $theme_engine
  *   The name of the theme engine.
+ * @param $complete
+ *   Whether to load the complete theme registry or an instance of the
+ *   ThemeRegistry class.
+ *
+ * @return
+ *   The theme registry array, or an instance of the ThemeRegistry class.
  */
-function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
-  // Check the theme registry cache; if it exists, use it.
-  $cache = cache_get("theme_registry:$theme->name", 'cache');
-  if (isset($cache->data)) {
-    $registry = $cache->data;
+function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL, $complete = TRUE) {
+  if ($complete) {
+    // Check the theme registry cache; if it exists, use it.
+    $cached = cache_get("theme_registry:$theme->name");
+    if (isset($cached->data)) {
+      $registry = $cached->data;
+    }
+    else {
+      // If not, build one and cache it.
+      $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
+      // Only persist this registry if all modules are loaded. This assures a
+      // complete set of theme hooks.
+      if (module_load_all(NULL)) {
+        _theme_save_registry($theme, $registry);
+      }
+    }
+    return $registry;
   }
   else {
-    // If not, build one and cache it.
-    $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
-   // Only persist this registry if all modules are loaded. This assures a
-   // complete set of theme hooks.
-    if (module_load_all(NULL)) {
-      _theme_save_registry($theme, $registry);
-    }
+    return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache');
   }
-  return $registry;
 }
 
 /**
- * Write the theme_registry cache into the database.
+ * Writes the theme_registry cache into the database.
  */
 function _theme_save_registry($theme, $registry) {
   cache_set("theme_registry:$theme->name", $registry);
 }
 
 /**
- * Force the system to rebuild the theme registry; this should be called
- * when modules are added to the system, or when a dynamic system needs
- * to add more theme hooks.
+ * Forces the system to rebuild the theme registry.
+ *
+ * This function should be called when modules are added to the system, or when
+ * a dynamic system needs to add more theme hooks.
  */
 function drupal_theme_rebuild() {
+  drupal_static_reset('theme_get_registry');
   cache_clear_all('theme_registry', 'cache', TRUE);
 }
 
 /**
+ * Builds the run-time theme registry.
+ *
+ * Extends DrupalCacheArray to allow the theme registry to be accessed as a
+ * complete registry, while internally caching only the parts of the registry
+ * that are actually in use on the site. On cache misses the complete
+ * theme registry is loaded and used to update the run-time cache.
+ */
+class ThemeRegistry Extends DrupalCacheArray {
+
+  /**
+   * Whether the partial registry can be persisted to the cache.
+   *
+   * This is only allowed if all modules and the request method is GET. theme()
+   * should be very rarely called on POST requests and this avoids polluting
+   * the runtime cache.
+   */
+  protected $persistable;
+
+  /**
+   * The complete theme registry array.
+   */
+  protected $completeRegistry;
+
+  function __construct($cid, $bin) {
+    $this->cid = $cid;
+    $this->bin = $bin;
+    $this->persistable = module_load_all(NULL) && $_SERVER['REQUEST_METHOD'] == 'GET';
+
+    $data = array();
+    if ($this->persistable && $cached = cache_get($this->cid, $this->bin)) {
+      $data = $cached->data;
+    }
+    else {
+      // If there is no runtime cache stored, fetch the full theme registry,
+      // but then initialize each value to NULL. This allows offsetExists()
+      // to function correctly on non-registered theme hooks without triggering
+      // a call to resolveCacheMiss().
+      $data = $this->initializeRegistry();
+      if ($this->persistable) {
+        $this->set($data);
+      }
+    }
+    $this->storage = $data;
+  }
+
+  /**
+   * Initializes the full theme registry.
+   *
+   * @return
+   *   An array with the keys of the full theme registry, but the values
+   *   initialized to NULL.
+   */
+  function initializeRegistry() {
+    $this->completeRegistry = theme_get_registry();
+
+    return array_fill_keys(array_keys($this->completeRegistry), NULL);
+  }
+
+  public function offsetExists($offset) {
+    // Since the theme registry allows for theme hooks to be requested that
+    // are not registered, just check the existence of the key in the registry.
+    // Use array_key_exists() here since a NULL value indicates that the theme
+    // hook exists but has not yet been requested.
+    return array_key_exists($offset, $this->storage);
+  }
+
+  public function offsetGet($offset) {
+    // If the offset is set but empty, it is a registered theme hook that has
+    // not yet been requested. Offsets that do not exist at all were not
+    // registered in hook_theme().
+    if (isset($this->storage[$offset])) {
+      return $this->storage[$offset];
+    }
+    elseif (array_key_exists($offset, $this->storage)) {
+      return $this->resolveCacheMiss($offset);
+    }
+  }
+
+  public function resolveCacheMiss($offset) {
+    if (!isset($this->completeRegistry)) {
+      $this->completeRegistry = theme_get_registry();
+    }
+    $this->storage[$offset] = $this->completeRegistry[$offset];
+    if ($this->persistable) {
+      $this->persist($offset);
+    }
+    return $this->storage[$offset];
+  }
+
+  public function set($data, $lock = TRUE) {
+    $lock_name = $this->cid . ':' . $this->bin;
+    if (!$lock || lock_acquire($lock_name)) {
+      if ($cached = cache_get($this->cid, $this->bin)) {
+        // Use array merge instead of union so that filled in values in $data
+        // overwrite empty values in the current cache.
+        $data = array_merge($cached->data, $data);
+      }
+      else {
+        $registry = $this->initializeRegistry();
+        $data = array_merge($registry, $data);
+      }
+      cache_set($this->cid, $data, $this->bin);
+      if ($lock) {
+        lock_release($lock_name);
+      }
+    }
+  }
+}
+
+/**
  * Process a single implementation of hook_theme().
  *
  * @param $cache
@@ -356,7 +508,7 @@
  *   themes/bartik.
  *
  * @see theme()
- * @see _theme_process_registry()
+ * @see _theme_build_registry()
  * @see hook_theme()
  * @see list_themes()
  */
@@ -485,7 +637,8 @@
     $cache = $result + $cache;
   }
 
-  // Let themes have variable processors even if they didn't register a template.
+  // Let themes have variable processors even if they didn't register a
+  // template.
   if ($type == 'theme' || $type == 'base_theme') {
     foreach ($cache as $hook => $info) {
       // Check only if not registered by the theme or engine.
@@ -512,7 +665,7 @@
 }
 
 /**
- * Build the theme registry cache.
+ * Builds the theme registry cache.
  *
  * @param $theme
  *   The loaded $theme object as returned by list_themes().
@@ -574,7 +727,7 @@
 }
 
 /**
- * Return a list of all currently available themes.
+ * Returns a list of all currently available themes.
  *
  * Retrieved from the database, if available and the site is not in maintenance
  * mode; otherwise compiled freshly from the filesystem.
@@ -584,21 +737,40 @@
  *
  * @return
  *   An associative array of the currently available themes. The keys are the
- *   names of the themes and the values are objects having the following
+ *   themes' machine names and the values are objects having the following
  *   properties:
- *   - 'filename': The name of the .info file.
- *   - 'name': The name of the theme.
- *   - 'status': 1 for enabled, 0 for disabled themes.
- *   - 'info': The contents of the .info file.
- *   - 'stylesheets': A two dimensional array, using the first key for the
- *     'media' attribute (e.g. 'all'), the second for the name of the file
- *     (e.g. style.css). The value is a complete filepath
- *     (e.g. themes/bartik/style.css).
- *   - 'scripts': An associative array of JavaScripts, using the filename as key
- *     and the complete filepath as value.
- *   - 'engine': The name of the theme engine.
- *   - 'base theme': The name of the base theme.
- */
+ *   - filename: The filepath and name of the .info file.
+ *   - name: The machine name of the theme.
+ *   - status: 1 for enabled, 0 for disabled themes.
+ *   - info: The contents of the .info file.
+ *   - stylesheets: A two dimensional array, using the first key for the
+ *     media attribute (e.g. 'all'), the second for the name of the file
+ *     (e.g. style.css). The value is a complete filepath (e.g.
+ *     themes/bartik/style.css). Not set if no stylesheets are defined in the
+ *     .info file.
+ *   - scripts: An associative array of JavaScripts, using the filename as key
+ *     and the complete filepath as value. Not set if no scripts are defined in
+ *     the .info file.
+ *   - prefix: The base theme engine prefix.
+ *   - engine: The machine name of the theme engine.
+ *   - base_theme: If this is a sub-theme, the machine name of the base theme
+ *     defined in the .info file. Otherwise, the element is not set.
+ *   - base_themes: If this is a sub-theme, an associative array of the
+ *     base-theme ancestors of this theme, starting with this theme's base
+ *     theme, then the base theme's own base theme, etc. Each entry has an
+ *     array key equal to the theme's machine name, and a value equal to the
+ *     human-readable theme name; if a theme with matching machine name does
+ *     not exist in the system, the value will instead be NULL (and since the
+ *     system would not know whether that theme itself has a base theme, that
+ *     will end the array of base themes). This is not set if the theme is not
+ *     a sub-theme.
+ *   - sub_themes: An associative array of themes on the system that are
+ *     either direct sub-themes (that is, they declare this theme to be
+ *     their base theme), direct sub-themes of sub-themes, etc. The keys are
+ *     the themes' machine names, and the values are the themes' human-readable
+ *     names. This element is not set if there are no themes on the system that
+ *     declare this theme as their base theme.
+*/
 function list_themes($refresh = FALSE) {
   $list = &drupal_static(__FUNCTION__, array());
 
@@ -654,70 +826,142 @@
 }
 
 /**
+ * Find all the base themes for the specified theme.
+ *
+ * Themes can inherit templates and function implementations from earlier themes.
+ *
+ * @param $themes
+ *   An array of available themes.
+ * @param $key
+ *   The name of the theme whose base we are looking for.
+ * @param $used_keys
+ *   A recursion parameter preventing endless loops.
+ * @return
+ *   Returns an array of all of the theme's ancestors; the first element's value
+ *   will be NULL if an error occurred.
+ */
+function drupal_find_base_themes($themes, $key, $used_keys = array()) {
+  $base_key = $themes[$key]->info['base theme'];
+  // Does the base theme exist?
+  if (!isset($themes[$base_key])) {
+    return array($base_key => NULL);
+  }
+
+  $current_base_theme = array($base_key => $themes[$base_key]->info['name']);
+
+  // Is the base theme itself a child of another theme?
+  if (isset($themes[$base_key]->info['base theme'])) {
+    // Do we already know the base themes of this theme?
+    if (isset($themes[$base_key]->base_themes)) {
+      return $themes[$base_key]->base_themes + $current_base_theme;
+    }
+    // Prevent loops.
+    if (!empty($used_keys[$base_key])) {
+      return array($base_key => NULL);
+    }
+    $used_keys[$base_key] = TRUE;
+    return drupal_find_base_themes($themes, $base_key, $used_keys) + $current_base_theme;
+  }
+  // If we get here, then this is our parent theme.
+  return $current_base_theme;
+}
+
+/**
  * Generates themed output.
  *
- * All requests for themed output must go through this function. It examines
- * the request and routes it to the appropriate theme function or template, by
- * checking the theme registry.
- *
- * The first argument to this function is the name of the theme hook. For
- * instance, to theme a table, the theme hook name is 'table'. By default, this
- * theme hook could be implemented by a function called 'theme_table' or a
- * template file called 'table.tpl.php', but hook_theme() can override the
- * default function or template name.
+ * All requests for themed output must go through this function (however,
+ * calling the theme() function directly is strongly discouraged - see next
+ * paragraph). It examines the request and routes it to the appropriate
+ * @link themeable theme function or template @endlink, by checking the theme
+ * registry.
+ *
+ * Avoid calling this function directly. It is preferable to replace direct
+ * calls to the theme() function with calls to drupal_render() by passing a
+ * render array with a #theme key to drupal_render(), which in turn calls
+ * theme().
+ *
+ * @section sec_theme_hooks Theme Hooks
+ * Most commonly, the first argument to this function is the name of the theme
+ * hook. For instance, to theme a taxonomy term, the theme hook name is
+ * 'taxonomy_term'. Modules register theme hooks within a hook_theme()
+ * implementation and provide a default implementation via a function named
+ * theme_HOOK() (e.g., theme_taxonomy_term()) or via a template file named
+ * according to the value of the 'template' key registered with the theme hook
+ * (see hook_theme() for details). Default templates are implemented with the
+ * PHPTemplate rendering engine and are named the same as the theme hook, with
+ * underscores changed to hyphens, so for the 'taxonomy_term' theme hook, the
+ * default template is 'taxonomy-term.tpl.php'.
+ *
+ * @subsection sub_overriding_theme_hooks Overriding Theme Hooks
+ * Themes may also register new theme hooks within a hook_theme()
+ * implementation, but it is more common for themes to override default
+ * implementations provided by modules than to register entirely new theme
+ * hooks. Themes can override a default implementation by implementing a
+ * function named THEME_HOOK() (for example, the 'bartik' theme overrides the
+ * default implementation of the 'menu_tree' theme hook by implementing a
+ * bartik_menu_tree() function), or by adding a template file within its folder
+ * structure that follows the template naming structure used by the theme's
+ * rendering engine (for example, since the Bartik theme uses the PHPTemplate
+ * rendering engine, it overrides the default implementation of the 'page' theme
+ * hook by containing a 'page.tpl.php' file within its folder structure).
  *
+ * @subsection sub_preprocess_templates Preprocessing for Template Files
  * If the implementation is a template file, several functions are called
  * before the template file is invoked, to modify the $variables array. These
  * fall into the "preprocessing" phase and the "processing" phase, and are
  * executed (if they exist), in the following order (note that in the following
  * list, HOOK indicates the theme hook name, MODULE indicates a module name,
  * THEME indicates a theme name, and ENGINE indicates a theme engine name):
- * - template_preprocess(&$variables, $hook): Creates a default set of variables
- *   for all theme hooks.
- * - template_preprocess_HOOK(&$variables): Should be implemented by
- *   the module that registers the theme hook, to set up default variables.
+ * - template_preprocess(&$variables, $hook): Creates a default set of
+ *   variables for all theme hooks with template implementations.
+ * - template_preprocess_HOOK(&$variables): Should be implemented by the module
+ *   that registers the theme hook, to set up default variables.
  * - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
  *   implementing modules.
  * - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
- *   all implementing modules, so that modules that didn't define the theme hook
- *   can alter the variables.
+ *   all implementing modules, so that modules that didn't define the theme
+ *   hook can alter the variables.
  * - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
- *   set necessary variables for all theme hooks.
+ *   set necessary variables for all theme hooks with template implementations.
  * - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
  *   necessary variables for the particular theme hook.
  * - THEME_preprocess(&$variables, $hook): Allows the theme to set necessary
- *   variables for all theme hooks.
+ *   variables for all theme hooks with template implementations.
  * - THEME_preprocess_HOOK(&$variables): Allows the theme to set necessary
  *   variables specific to the particular theme hook.
- * - template_process(&$variables, $hook): Creates a default set of variables
- *   for all theme hooks.
- * - template_process_HOOK(&$variables): This is the first processor specific
- *   to the theme hook; it should be implemented by the module that registers
- *   it.
+ * - template_process(&$variables, $hook): Creates an additional set of default
+ *   variables for all theme hooks with template implementations. The variables
+ *   created in this function are derived from ones created by
+ *   template_preprocess(), but potentially altered by the other preprocess
+ *   functions listed above. For example, any preprocess function can add to or
+ *   modify the $variables['attributes_array'] variable, and after all of them
+ *   have finished executing, template_process() flattens it into a
+ *   $variables['attributes'] string for convenient use by templates.
+ * - template_process_HOOK(&$variables): Should be implemented by the module
+ *   that registers the theme hook, if it needs to perform additional variable
+ *   processing after all preprocess functions have finished.
  * - MODULE_process(&$variables, $hook): hook_process() is invoked on all
  *   implementing modules.
  * - MODULE_process_HOOK(&$variables): hook_process_HOOK() is invoked on
  *   on all implementing modules, so that modules that didn't define the theme
  *   hook can alter the variables.
- * - ENGINE_engine_process(&$variables, $hook): Allows the theme engine to set
- *   necessary variables for all theme hooks.
- * - ENGINE_engine_process_HOOK(&$variables): Allows the theme engine to set
- *   necessary variables for the particular theme hook.
- * - ENGINE_process(&$variables, $hook): Allows the theme engine to process the
- *   variables.
- * - ENGINE_process_HOOK(&$variables): Allows the theme engine to process the
- *   variables specific to the theme hook.
+ * - ENGINE_engine_process(&$variables, $hook): Allows the theme engine to
+ *   process variables for all theme hooks with template implementations.
+ * - ENGINE_engine_process_HOOK(&$variables): Allows the theme engine to process
+ *   the variables specific to the theme hook.
  * - THEME_process(&$variables, $hook):  Allows the theme to process the
- *   variables.
+ *   variables for all theme hooks with template implementations.
  * - THEME_process_HOOK(&$variables):  Allows the theme to process the
  *   variables specific to the theme hook.
  *
+ * @subsection sub_preprocess_theme_funcs Preprocessing for Theme Functions
  * If the implementation is a function, only the theme-hook-specific preprocess
  * and process functions (the ones ending in _HOOK) are called from the
  * list above. This is because theme hooks with function implementations
  * need to be fast, and calling the non-theme-hook-specific preprocess and
  * process functions for them would incur a noticeable performance penalty.
  *
+ * @subsection sub_alternate_suggestions Suggesting Alternate Hooks
  * There are two special variables that these preprocess and process functions
  * can set: 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be
  * merged together to form a list of 'suggested' alternate theme hooks to use,
@@ -733,10 +977,10 @@
  * @param $hook
  *   The name of the theme hook to call. If the name contains a
  *   double-underscore ('__') and there isn't an implementation for the full
- *   name, the part before the '__' is checked. This allows a fallback to a more
- *   generic implementation. For example, if theme('links__node', ...) is
- *   called, but there is no implementation of that theme hook, then the 'links'
- *   implementation is used. This process is iterative, so if
+ *   name, the part before the '__' is checked. This allows a fallback to a
+ *   more generic implementation. For example, if theme('links__node', ...) is
+ *   called, but there is no implementation of that theme hook, then the
+ *   'links' implementation is used. This process is iterative, so if
  *   theme('links__contextual__node', ...) is called, theme() checks for the
  *   following implementations, and uses the first one that exists:
  *   - links__contextual__node
@@ -758,10 +1002,14 @@
  *
  * @return
  *   An HTML string representing the themed output.
+ *
+ * @see drupal_render()
+ * @see themeable
+ * @see hook_theme()
+ * @see template_preprocess()
+ * @see template_process()
  */
 function theme($hook, $variables = array()) {
-  static $hooks = NULL;
-
   // If called before all modules are loaded, we do not necessarily have a full
   // theme registry to work with, and therefore cannot process the theme
   // request properly. See also _theme_load_registry().
@@ -769,10 +1017,7 @@
     throw new Exception(t('theme() may not be called until all modules are loaded.'));
   }
 
-  if (!isset($hooks)) {
-    drupal_theme_initialize();
-    $hooks = theme_get_registry();
-  }
+  $hooks = theme_get_registry(FALSE);
 
   // If an array of hook candidates were passed, use the first one that has an
   // implementation.
@@ -784,6 +1029,7 @@
     }
     $hook = $candidate;
   }
+  $theme_hook_original = $hook;
 
   // If there's no implementation, check for more generic fallbacks. If there's
   // still no implementation, log an error and return an empty string.
@@ -800,7 +1046,7 @@
       // Only log a message when not trying theme suggestions ($hook being an
       // array).
       if (!isset($candidate)) {
-        watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
+        watchdog('theme', 'Theme hook %hook not found.', array('%hook' => $hook), WATCHDOG_WARNING);
       }
       return '';
     }
@@ -812,7 +1058,8 @@
   // point path_to_theme() to the currently used theme path:
   $theme_path = $info['theme path'];
 
-  // Include a file if the theme function or variable processor is held elsewhere.
+  // Include a file if the theme function or variable processor is held
+  // elsewhere.
   if (!empty($info['includes'])) {
     foreach ($info['includes'] as $include_file) {
       include_once DRUPAL_ROOT . '/' . $include_file;
@@ -844,6 +1091,8 @@
     $variables += array($info['render element'] => array());
   }
 
+  $variables['theme_hook_original'] = $theme_hook_original;
+
   // Invoke the variable processors, if any. The processors may specify
   // alternate suggestions for which hook's template/function to use. If the
   // hook is a suggestion of a base hook, invoke the variable processors of
@@ -852,6 +1101,13 @@
   if (isset($info['base hook'])) {
     $base_hook = $info['base hook'];
     $base_hook_info = $hooks[$base_hook];
+    // Include files required by the base hook, since its variable processors
+    // might reside there.
+    if (!empty($base_hook_info['includes'])) {
+      foreach ($base_hook_info['includes'] as $include_file) {
+        include_once DRUPAL_ROOT . '/' . $include_file;
+      }
+    }
     if (isset($base_hook_info['preprocess functions']) || isset($base_hook_info['process functions'])) {
       $variables['theme_hook_suggestion'] = $hook;
       $hook = $base_hook;
@@ -945,7 +1201,12 @@
     if (isset($info['path'])) {
       $template_file = $info['path'] . '/' . $template_file;
     }
-    $output = $render_function($template_file, $variables);
+    if (variable_get('theme_debug', FALSE)) {
+      $output = _theme_render_template_debug($render_function, $template_file, $variables, $extension);
+    }
+    else {
+      $output = $render_function($template_file, $variables);
+    }
   }
 
   // restore path_to_theme()
@@ -954,14 +1215,14 @@
 }
 
 /**
- * Return the path to the current themed element.
+ * Returns the path to the current themed element.
  *
- * It can point to the active theme or the module handling a themed implementation.
- * For example, when invoked within the scope of a theming call it will depend
- * on where the theming function is handled. If implemented from a module, it
- * will point to the module. If implemented from the active theme, it will point
- * to the active theme. When called outside the scope of a theming call, it will
- * always point to the active theme.
+ * It can point to the active theme or the module handling a themed
+ * implementation. For example, when invoked within the scope of a theming call
+ * it will depend on where the theming function is handled. If implemented from
+ * a module, it will point to the module. If implemented from the active theme,
+ * it will point to the active theme. When called outside the scope of a
+ * theming call, it will always point to the active theme.
  */
 function path_to_theme() {
   global $theme_path;
@@ -974,7 +1235,7 @@
 }
 
 /**
- * Allow themes and/or theme engines to easily discover overridden theme functions.
+ * Allows themes and/or theme engines to discover overridden theme functions.
  *
  * @param $cache
  *   The existing cache of theme hooks to test against.
@@ -987,6 +1248,7 @@
 function drupal_find_theme_functions($cache, $prefixes) {
   $implementations = array();
   $functions = get_defined_functions();
+  $theme_functions = preg_grep('/^(' . implode(')|(', $prefixes) . ')_/', $functions['user']);
 
   foreach ($cache as $hook => $info) {
     foreach ($prefixes as $prefix) {
@@ -1003,7 +1265,7 @@
       // intermediary suggestion.
       $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
       if (!isset($info['base hook']) && !empty($pattern)) {
-        $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
+        $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $theme_functions);
         if ($matches) {
           foreach ($matches as $match) {
             $new_hook = substr($match, strlen($prefix) + 1);
@@ -1031,7 +1293,7 @@
 }
 
 /**
- * Allow themes and/or theme engines to easily discover overridden templates.
+ * Allows themes and/or theme engines to easily discover overridden templates.
  *
  * @param $cache
  *   The existing cache of theme hooks to test against.
@@ -1108,7 +1370,8 @@
       if ($matches) {
         foreach ($matches as $match) {
           $file = substr($match, 0, strpos($match, '.'));
-          // Put the underscores back in for the hook name and register this pattern.
+          // Put the underscores back in for the hook name and register this
+          // pattern.
           $arg_name = isset($info['variables']) ? 'variables' : 'render element';
           $implementations[strtr($file, '-', '_')] = array(
             'template' => $file,
@@ -1124,7 +1387,7 @@
 }
 
 /**
- * Retrieve a setting for the current theme or for a given theme.
+ * Retrieves a setting for the current theme or for a given theme.
  *
  * The final setting is obtained from the last value found in the following
  * sources:
@@ -1242,7 +1505,7 @@
 }
 
 /**
- * Render a system default template, which is essentially a PHP template.
+ * Renders a system default template, which is essentially a PHP template.
  *
  * @param $template_file
  *   The filename of the template to render.
@@ -1253,14 +1516,87 @@
  *   The output generated by the template.
  */
 function theme_render_template($template_file, $variables) {
-  extract($variables, EXTR_SKIP);               // Extract the variables to a local namespace
-  ob_start();                                   // Start output buffering
-  include DRUPAL_ROOT . '/' . $template_file;   // Include the template file
-  return ob_get_clean();                        // End buffering and return its contents
+  // Extract the variables to a local namespace
+  extract($variables, EXTR_SKIP);
+
+  // Start output buffering
+  ob_start();
+
+  // Include the template file
+  include DRUPAL_ROOT . '/' . $template_file;
+
+  // End buffering and return its contents
+  return ob_get_clean();
 }
 
 /**
- * Enable a given list of themes.
+ * Renders a template for any engine.
+ *
+ * Includes the possibility to get debug output by setting the
+ * theme_debug variable to TRUE.
+ *
+ * @param string $template_function
+ *   The function to call for rendering the template.
+ * @param string $template_file
+ *   The filename of the template to render.
+ * @param array $variables
+ *   A keyed array of variables that will appear in the output.
+ * @param string $extension
+ *   The extension used by the theme engine for template files.
+ *
+ * @return string
+ *   The output generated by the template including debug information.
+ */
+function _theme_render_template_debug($template_function, $template_file, $variables, $extension) {
+  $output = array(
+    'debug_prefix' => '',
+    'debug_info' => '',
+    'rendered_markup' => call_user_func($template_function, $template_file, $variables),
+    'debug_suffix' => '',
+  );
+  $output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
+  $output['debug_prefix'] .= "\n<!-- CALL: theme('" . check_plain($variables['theme_hook_original']) . "') -->";
+  // If there are theme suggestions, reverse the array so more specific
+  // suggestions are shown first.
+  if (!empty($variables['theme_hook_suggestions'])) {
+    $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
+  }
+  // Add debug output for directly called suggestions like
+  // '#theme' => 'comment__node__article'.
+  if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
+    $derived_suggestions[] = $hook = $variables['theme_hook_original'];
+    while ($pos = strrpos($hook, '__')) {
+      $hook = substr($hook, 0, $pos);
+      $derived_suggestions[] = $hook;
+    }
+    // Get the value of the base hook (last derived suggestion) and append it
+    // to the end of all theme suggestions.
+    $base_hook = array_pop($derived_suggestions);
+    $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
+    $variables['theme_hook_suggestions'][] = $base_hook;
+  }
+  if (!empty($variables['theme_hook_suggestions'])) {
+    $current_template = basename($template_file);
+    $suggestions = $variables['theme_hook_suggestions'];
+    // Only add the original theme hook if it wasn't a directly called
+    // suggestion.
+    if (strpos($variables['theme_hook_original'], '__') === FALSE) {
+      $suggestions[] = $variables['theme_hook_original'];
+    }
+    foreach ($suggestions as &$suggestion) {
+      $template = strtr($suggestion, '_', '-') . $extension;
+      $prefix = ($template == $current_template) ? 'x' : '*';
+      $suggestion = $prefix . ' ' . $template;
+    }
+    $output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n   " . check_plain(implode("\n   ", $suggestions)) . "\n-->";
+  }
+  $output['debug_info'] .= "\n<!-- BEGIN OUTPUT from '" . check_plain($template_file) . "' -->\n";
+  $output['debug_suffix'] .= "\n<!-- END OUTPUT from '" . check_plain($template_file) . "' -->\n\n";
+  return implode('', $output);
+}
+
+/**
+ * Enables a given list of themes.
  *
  * @param $theme_list
  *   An array of theme names.
@@ -1285,7 +1621,7 @@
 }
 
 /**
- * Disable a given list of themes.
+ * Disables a given list of themes.
  *
  * @param $theme_list
  *   An array of theme names.
@@ -1318,7 +1654,7 @@
 }
 
 /**
- * @ingroup themeable
+ * @addtogroup themeable
  * @{
  */
 
@@ -1356,7 +1692,7 @@
       $output .= " </ul>\n";
     }
     else {
-      $output .= $messages[0];
+      $output .= reset($messages);
     }
     $output .= "</div>\n";
   }
@@ -1371,15 +1707,33 @@
  * theme('link') for rendering the anchor tag.
  *
  * To optimize performance for sites that don't need custom theming of links,
- * the l() function includes an inline copy of this function, and uses that copy
- * if none of the enabled modules or the active theme implement any preprocess
- * or process functions or override this theme implementation.
- *
- * @param $variables
- *   An associative array containing the keys 'text', 'path', and 'options'. See
- *   the l() function for information about these variables.
+ * the l() function includes an inline copy of this function, and uses that
+ * copy if none of the enabled modules or the active theme implement any
+ * preprocess or process functions or override this theme implementation.
+ *
+ * @param array $variables
+ *   An associative array containing the keys:
+ *   - text: The text of the link.
+ *   - path: The internal path or external URL being linked to. It is used as
+ *     the $path parameter of the url() function.
+ *   - options: (optional) An array that defaults to empty, but can contain:
+ *     - attributes: Can contain optional attributes:
+ *       - class: must be declared in an array. Example: 'class' =>
+ *         array('class_name1','class_name2').
+ *       - title: must be a string. Example: 'title' => 'Example title'
+ *       - Others are more flexible as long as they work with
+ *         drupal_attributes($variables['options']['attributes]).
+ *     - html: Boolean flag that tells whether text contains HTML or plain
+ *       text. If set to TRUE, the text value will not be sanitized so the
+         calling function must ensure that it already contains safe HTML.
+ *   The elements $variables['options']['attributes'] and
+ *   $variables['options']['html'] are used in this function similarly to the
+ *   way that $options['attributes'] and $options['html'] are used in l().
+ *   The link itself is built by the url() function, which takes
+ *   $variables['path'] and $variables['options'] as arguments.
  *
  * @see l()
+ * @see url()
  */
 function theme_link($variables) {
   return '<a href="' . check_plain(url($variables['path'], $variables['options'])) . '"' . drupal_attributes($variables['options']['attributes']) . '>' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . '</a>';
@@ -1391,22 +1745,23 @@
  * @param $variables
  *   An associative array containing:
  *   - 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
+ *     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) 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 element 'class' is
+ *     - attributes: (optional) Attributes for the anchor, or for the <span>
+ *       tag used in its place if no 'href' is supplied. If element 'class' is
  *       included, it must be an array of one or more class names.
- *     If the 'href' element is supplied, the entire link array is passed to l()
- *     as its $options parameter.
+ *     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:
+ *   - 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.
@@ -1428,8 +1783,6 @@
   $output = '';
 
   if (count($links) > 0) {
-    $output = '';
-
     // Treat the heading first if it is present to prepend it to the
     // list of links.
     if (!empty($heading)) {
@@ -1457,7 +1810,8 @@
     foreach ($links as $key => $link) {
       $class = array($key);
 
-      // Add first, last and active classes to the list of links to help out themers.
+      // Add first, last and active classes to the list of links to help out
+      // themers.
       if ($i == 1) {
         $class[] = 'first';
       }
@@ -1475,7 +1829,8 @@
         $output .= l($link['title'], $link['href'], $link);
       }
       elseif (!empty($link['title'])) {
-        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes.
+        // Some links are actually not links, but we wrap these in <span> for
+        // adding title and class attributes.
         if (empty($link['html'])) {
           $link['title'] = check_plain($link['title']);
         }
@@ -1510,8 +1865,8 @@
  *     attribute to be omitted in some cases. Therefore, this variable defaults
  *     to an empty string, but can be set to NULL for the attribute to be
  *     omitted. Usually, neither omission nor an empty string satisfies
- *     accessibility requirements, so it is strongly encouraged for code calling
- *     theme('image') to pass a meaningful value for this variable.
+ *     accessibility requirements, so it is strongly encouraged for code
+ *     calling theme('image') to pass a meaningful value for this variable.
  *     - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
  *     - http://www.w3.org/TR/xhtml1/dtds.html
  *     - http://dev.w3.org/html5/spec/Overview.html#alt
@@ -1564,7 +1919,9 @@
  *     - "data": The localized title of the table column.
  *     - "field": The database field represented in the table column (required
  *       if user is to be able to sort on this column).
- *     - "sort": A default sort order for this column ("asc" or "desc").
+ *     - "sort": A default sort order for this column ("asc" or "desc"). Only
+ *       one column should be given a default sort order because table sorting
+ *       only applies to one column at a time.
  *     - Any HTML attributes, such as "colspan", to apply to the column header
  *       cell.
  *   - rows: An array of table rows. Every row is an array of cells, or an
@@ -1723,25 +2080,24 @@
     $flip = array('even' => 'odd', 'odd' => 'even');
     $class = 'even';
     foreach ($rows as $number => $row) {
-      $attributes = array();
-
       // Check if we're dealing with a simple or complex row
       if (isset($row['data'])) {
-        foreach ($row as $key => $value) {
-          if ($key == 'data') {
-            $cells = $value;
-          }
-          else {
-            $attributes[$key] = $value;
-          }
-        }
+        $cells = $row['data'];
+        $no_striping = isset($row['no_striping']) ? $row['no_striping'] : FALSE;
+
+        // Set the attributes array and exclude 'data' and 'no_striping'.
+        $attributes = $row;
+        unset($attributes['data']);
+        unset($attributes['no_striping']);
       }
       else {
         $cells = $row;
+        $attributes = array();
+        $no_striping = FALSE;
       }
       if (count($cells)) {
         // Add odd/even class
-        if (empty($row['no_striping'])) {
+        if (!$no_striping) {
           $class = $flip[$class];
           $attributes['class'][] = $class;
         }
@@ -1768,7 +2124,8 @@
  *
  * @param $variables
  *   An associative array containing:
- *   - style: Set to either 'asc' or 'desc', this determines which icon to show.
+ *   - style: Set to either 'asc' or 'desc', this determines which icon to
+ *     show.
  */
 function theme_tablesort_indicator($variables) {
   if ($variables['style'] == "asc") {
@@ -1821,18 +2178,23 @@
   $type = $variables['type'];
   $attributes = $variables['attributes'];
 
+  // Only output the list container and title, if there are any list items.
+  // Check to see whether the block title exists before adding a header.
+  // Empty headers are not semantic and present accessibility challenges.
   $output = '<div class="item-list">';
-  if (isset($title)) {
+  if (isset($title) && $title !== '') {
     $output .= '<h3>' . $title . '</h3>';
   }
 
   if (!empty($items)) {
     $output .= "<$type" . drupal_attributes($attributes) . '>';
     $num_items = count($items);
-    foreach ($items as $i => $item) {
+    $i = 0;
+    foreach ($items as $item) {
       $attributes = array();
       $children = array();
       $data = '';
+      $i++;
       if (is_array($item)) {
         foreach ($item as $key => $value) {
           if ($key == 'data') {
@@ -1853,10 +2215,10 @@
         // Render nested list.
         $data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
       }
-      if ($i == 0) {
+      if ($i == 1) {
         $attributes['class'][] = 'first';
       }
-      if ($i == $num_items - 1) {
+      if ($i == $num_items) {
         $attributes['class'][] = 'last';
       }
       $output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
@@ -1872,7 +2234,7 @@
  *
  * @param $variables
  *   An associative array containing:
- *   - url: The url for the link.
+ *   - url: The URL for the link.
  */
 function theme_more_help_link($variables) {
   return '<div class="more-help-link">' . l(t('More help'), $variables['url']) . '</div>';
@@ -1888,7 +2250,7 @@
  *   - title: A descriptive title of the feed.
  */
 function theme_feed_icon($variables) {
-  $text = t('Subscribe to @feed-title', array('@feed-title' => $variables['title']));
+  $text = t('Subscribe to !feed-title', array('!feed-title' => $variables['title']));
   if ($image = theme('image', array('path' => 'misc/feed.png', 'width' => 16, 'height' => 16, 'alt' => $text))) {
     return l($image, $variables['url'], array('html' => TRUE, 'attributes' => array('class' => array('feed-icon'), 'title' => $text)));
   }
@@ -1906,7 +2268,8 @@
  *       - script: To load JavaScript.
  *     - #attributes: (optional) An array of HTML attributes to apply to the
  *       tag.
- *     - #value: (optional) A string containing tag content, such as inline CSS.
+ *     - #value: (optional) A string containing tag content, such as inline
+ *       CSS.
  *     - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
  *       wrapper prefix.
  *     - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
@@ -1937,7 +2300,7 @@
  *
  * @param $variables
  *   An associative array containing:
- *   - url: The url of the main page.
+ *   - url: The URL of the main page.
  *   - title: A descriptive verb for the link, like 'Read more'.
  */
 function theme_more_link($variables) {
@@ -1981,6 +2344,8 @@
 /**
  * Returns HTML for a progress bar.
  *
+ * Note that the core Batch API uses this only for non-JavaScript batch jobs.
+ *
  * @param $variables
  *   An associative array containing:
  *   - percent: The percentage of the progress.
@@ -2012,7 +2377,7 @@
 }
 
 /**
- * @} End of "ingroup themeable".
+ * @} End of "addtogroup themeable".
  */
 
 /**
@@ -2058,18 +2423,23 @@
 
 /**
  * Adds a default set of helper variables for variable processors and templates.
- * This comes in before any other preprocess function which makes it possible to
- * be used in default theme implementations (non-overridden theme functions).
  *
- * For more detailed information, see theme().
+ * This function is called for theme hooks implemented as templates only, not
+ * for theme hooks implemented as functions. This preprocess function is the
+ * first in the sequence of preprocessing and processing functions that is
+ * called when preparing variables for a template. See theme() for more details
+ * about the full sequence.
  *
+ * @see theme()
+ * @see template_process()
  */
 function template_preprocess(&$variables, $hook) {
   global $user;
   static $count = array();
 
-  // Track run count for each hook to provide zebra striping.
-  // See "template_preprocess_block()" which provides the same feature specific to blocks.
+  // Track run count for each hook to provide zebra striping. See
+  // "template_preprocess_block()" which provides the same feature specific to
+  // blocks.
   $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1;
   $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
   $variables['id'] = $count[$hook]++;
@@ -2139,10 +2509,19 @@
 }
 
 /**
- * A default process function used to alter variables as late as possible.
+ * Adds helper variables derived from variables defined during preprocessing.
  *
- * For more detailed information, see theme().
+ * When preparing variables for a theme hook implementation, all 'preprocess'
+ * functions run first, then all 'process' functions (see theme() for details
+ * about the full sequence).
+ *
+ * This function serializes array variables manipulated during the preprocessing
+ * phase into strings for convenient use by templates. As with
+ * template_preprocess(), this function does not get called for theme hooks
+ * implemented as functions.
  *
+ * @see theme()
+ * @see template_preprocess()
  */
 function template_process(&$variables, $hook) {
   // Flatten out classes.
@@ -2260,10 +2639,13 @@
   // Move some variables to the top level for themer convenience and template cleanliness.
   $variables['show_messages'] = $variables['page']['#show_messages'];
 
-  foreach (system_region_list($GLOBALS['theme']) as $region_key => $region_name) {
+  foreach (system_region_list($GLOBALS['theme'], REGIONS_ALL, FALSE) as $region_key) {
     if (!isset($variables['page'][$region_key])) {
       $variables['page'][$region_key] = array();
     }
+    if ($region_content = drupal_get_region_content($region_key)) {
+      $variables['page'][$region_key][]['#markup'] = $region_content;
+    }
   }
 
   // Set up layout variable.
@@ -2420,13 +2802,13 @@
 }
 
 /**
- * The variables array generated here is a mirror of template_preprocess_page().
- * This preprocessor will run its course when theme_maintenance_page() is
- * invoked.
- *
- * An alternate template file of "maintenance-page--offline.tpl.php" can be
- * used when the database is offline to hide errors and completely replace the
- * content.
+ * Process variables for maintenance-page.tpl.php.
+ *
+ * The variables array generated here is a mirror of
+ * template_preprocess_page(). This preprocessor will run its course when
+ * theme_maintenance_page() is invoked. An alternate template file of
+ * maintenance-page--offline.tpl.php can be used when the database is offline to
+ * hide errors and completely replace the content.
  *
  * The $variables array contains the following arguments:
  * - $content
@@ -2520,10 +2902,13 @@
 }
 
 /**
+ * Theme process function for theme_maintenance_field().
+ *
  * The variables array generated here is a mirror of template_process_html().
  * This processor will run its course when theme_maintenance_page() is invoked.
  *
  * @see maintenance-page.tpl.php
+ * @see template_process_html()
  */
 function template_process_maintenance_page(&$variables) {
   $variables['head']    = drupal_get_html_head();
@@ -2535,7 +2920,7 @@
 /**
  * Preprocess variables for region.tpl.php
  *
- * Prepare the values passed to the theme_region function to be passed into a
+ * Prepares the values passed to the theme_region function to be passed into a
  * pluggable template engine. Uses the region name to generate a template file
  * suggestions. If none are found, the default region.tpl.php is used.
  *
diff -Naur drupal-7.9/includes/theme.maintenance.inc drupal-7.58/includes/theme.maintenance.inc
--- drupal-7.9/includes/theme.maintenance.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/theme.maintenance.inc	2018-03-27 21:28:19.000000000 +0200
@@ -10,9 +10,9 @@
  *
  * Used for site installs, updates and when the site is in maintenance mode.
  * It also applies when the database is unavailable or bootstrap was not
- * complete. Seven is always used for the initial install and update operations.
- * In other cases, Bartik is used, but this can be overridden by setting a
- * "maintenance_theme" key in the $conf variable in settings.php.
+ * complete. Seven is always used for the initial install and update
+ * operations. In other cases, Bartik is used, but this can be overridden by
+ * setting a "maintenance_theme" key in the $conf variable in settings.php.
  */
 function _drupal_maintenance_theme() {
   global $theme, $theme_key, $conf;
@@ -85,7 +85,7 @@
 }
 
 /**
- * This builds the registry when the site needs to bypass any database calls.
+ * Builds the registry when the site needs to bypass any database calls.
  */
 function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
   return _theme_build_registry($theme, $base_theme, $theme_engine);
@@ -160,7 +160,7 @@
 }
 
 /**
- * Returns HTML for a report of the results from an operation run via authorize.php.
+ * Returns HTML for a results report of an operation run by authorize.php.
  *
  * @param $variables
  *   An associative array containing:
diff -Naur drupal-7.9/includes/token.inc drupal-7.58/includes/token.inc
--- drupal-7.9/includes/token.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/token.inc	2018-03-27 21:28:19.000000000 +0200
@@ -77,8 +77,13 @@
  *   Text with tokens replaced.
  */
 function token_replace($text, array $data = array(), array $options = array()) {
+  $text_tokens = token_scan($text);
+  if (empty($text_tokens)) {
+    return $text;
+  }
+
   $replacements = array();
-  foreach (token_scan($text) as $type => $tokens) {
+  foreach ($text_tokens as $type => $tokens) {
     $replacements += token_generate($type, $tokens, $data, $options);
     if (!empty($options['clear'])) {
       $replacements += array_fill_keys($tokens, '');
@@ -108,13 +113,13 @@
  */
 function token_scan($text) {
   // Matches tokens with the following pattern: [$type:$name]
-  // $type and $name may not contain  [ ] or whitespace characters.
-  // $type may not contain : characters, but $name may.
+  // $type and $name may not contain  [ ] characters.
+  // $type may not contain : or whitespace characters, but $name may.
   preg_match_all('/
     \[             # [ - pattern start
     ([^\s\[\]:]*)  # match $type not containing whitespace : [ or ]
     :              # : - separator
-    ([^\s\[\]]*)   # match $name not containing whitespace [ or ]
+    ([^\[\]]*)     # match $name not containing [ or ]
     \]             # ] - pattern end
     /x', $text, $matches);
 
@@ -185,10 +190,10 @@
 }
 
 /**
- * Given a list of tokens, returns those that begin with a specific prefix.
+ * Returns a list of tokens that begin with a specific prefix.
  *
- * Used to extract a group of 'chained' tokens (such as [node:author:name]) from
- * the full list of tokens found in text. For example:
+ * Used to extract a group of 'chained' tokens (such as [node:author:name])
+ * from the full list of tokens found in text. For example:
  * @code
  *   $data = array(
  *     'author:name' => '[node:author:name]',
@@ -225,8 +230,10 @@
 /**
  * Returns metadata describing supported tokens.
  *
- * The metadata array contains token type, name, and description data as well as
- * an optional pointer indicating that the token chains to another set of tokens.
+ * The metadata array contains token type, name, and description data as well
+ * as an optional pointer indicating that the token chains to another set of
+ * tokens.
+ *
  * For example:
  * @code
  *   $data['types']['node'] = array(
diff -Naur drupal-7.9/includes/unicode.inc drupal-7.58/includes/unicode.inc
--- drupal-7.9/includes/unicode.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/unicode.inc	2018-03-27 21:28:19.000000000 +0200
@@ -1,6 +1,11 @@
 <?php
 
 /**
+* @file
+* Provides Unicode-related conversions and operations.
+*/
+
+/**
  * Indicates an error during check for PHP unicode support.
  */
 define('UNICODE_ERROR', -1);
@@ -19,8 +24,6 @@
 /**
  * Matches Unicode characters that are word boundaries.
  *
- * @see http://unicode.org/glossary
- *
  * Characters with the following General_category (gc) property values are used
  * as word boundaries. While this does not fully conform to the Word Boundaries
  * algorithm described in http://unicode.org/reports/tr29, as PCRE does not
@@ -39,6 +42,8 @@
  * Note that the PCRE property matcher is not used because we wanted to be
  * compatible with Unicode 5.2.0 regardless of the PCRE version used (and any
  * bugs in PCRE property tables).
+ *
+ * @see http://unicode.org/glossary
  */
 define('PREG_CLASS_UNICODE_WORD_BOUNDARY',
   '\x{0}-\x{2F}\x{3A}-\x{40}\x{5B}-\x{60}\x{7B}-\x{A9}\x{AB}-\x{B1}\x{B4}' .
@@ -73,7 +78,7 @@
   '\x{A836}-\x{A839}\x{A874}-\x{A877}\x{A8CE}-\x{A8CF}\x{A8F8}-\x{A8FA}' .
   '\x{A92E}-\x{A92F}\x{A95F}\x{A9C1}-\x{A9CD}\x{A9DE}-\x{A9DF}' .
   '\x{AA5C}-\x{AA5F}\x{AA77}-\x{AA79}\x{AADE}-\x{AADF}\x{ABEB}' .
-  '\x{D800}-\x{F8FF}\x{FB29}\x{FD3E}-\x{FD3F}\x{FDFC}-\x{FDFD}' .
+  '\x{E000}-\x{F8FF}\x{FB29}\x{FD3E}-\x{FD3F}\x{FDFC}-\x{FDFD}' .
   '\x{FE10}-\x{FE19}\x{FE30}-\x{FE6B}\x{FEFF}-\x{FF0F}\x{FF1A}-\x{FF20}' .
   '\x{FF3B}-\x{FF40}\x{FF5B}-\x{FF65}\x{FFE0}-\x{FFFD}');
 
@@ -96,7 +101,7 @@
  *   Whether to report any fatal errors with form_set_error().
  */
 function _unicode_check() {
-  // Ensure translations don't break at install time
+  // Ensure translations don't break during installation.
   $t = get_t();
 
   // Check for mbstring extension
@@ -111,11 +116,15 @@
   if (ini_get('mbstring.encoding_translation') != 0) {
     return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.encoding_translation</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
   }
-  if (ini_get('mbstring.http_input') != 'pass') {
-    return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_input</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
-  }
-  if (ini_get('mbstring.http_output') != 'pass') {
-    return array(UNICODE_ERROR, $t('Multibyte string output conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_output</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
+  // mbstring.http_input and mbstring.http_output are deprecated and empty by
+  // default in PHP 5.6.
+  if (version_compare(PHP_VERSION, '5.6.0') == -1) {
+    if (ini_get('mbstring.http_input') != 'pass') {
+      return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_input</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
+    }
+    if (ini_get('mbstring.http_output') != 'pass') {
+      return array(UNICODE_ERROR, $t('Multibyte string output conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_output</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
+    }
   }
 
   // Set appropriate configuration
@@ -125,10 +134,10 @@
 }
 
 /**
- * Return Unicode library status and errors.
+ * Returns Unicode library status and errors.
  */
 function unicode_requirements() {
-  // Ensure translations don't break at install time
+  // Ensure translations don't break during installation.
   $t = get_t();
 
   $libraries = array(
@@ -157,14 +166,14 @@
 }
 
 /**
- * Prepare a new XML parser.
+ * Prepares a new XML parser.
  *
- * This is a wrapper around xml_parser_create() which extracts the encoding from
- * the XML data first and sets the output encoding to UTF-8. This function should
- * be used instead of xml_parser_create(), because PHP 4's XML parser doesn't
- * check the input encoding itself. "Starting from PHP 5, the input encoding is
- * automatically detected, so that the encoding parameter specifies only the
- * output encoding."
+ * This is a wrapper around xml_parser_create() which extracts the encoding
+ * from the XML data first and sets the output encoding to UTF-8. This function
+ * should be used instead of xml_parser_create(), because PHP 4's XML parser
+ * doesn't check the input encoding itself. "Starting from PHP 5, the input
+ * encoding is automatically detected, so that the encoding parameter specifies
+ * only the output encoding."
  *
  * This is also where unsupported encodings will be converted. Callers should
  * take this into account: $data might have been changed after the call.
@@ -213,7 +222,7 @@
 }
 
 /**
- * Convert data to UTF-8
+ * Converts data to UTF-8.
  *
  * Requires the iconv, GNU recode or mbstring PHP extension.
  *
@@ -244,15 +253,15 @@
 }
 
 /**
- * Truncate a UTF-8-encoded string safely to a number of bytes.
+ * Truncates a UTF-8-encoded string safely to a number of bytes.
  *
  * If the end position is in the middle of a UTF-8 sequence, it scans backwards
  * until the beginning of the byte sequence.
  *
  * Use this function whenever you want to chop off a string at an unsure
  * location. On the other hand, if you're sure that you're splitting on a
- * character boundary (e.g. after using strpos() or similar), you can safely use
- * substr() instead.
+ * character boundary (e.g. after using strpos() or similar), you can safely
+ * use substr() instead.
  *
  * @param $string
  *   The string to truncate.
@@ -306,7 +315,7 @@
  *   boundaries, giving you "See myverylongurl..." (assuming you had set
  *   $add_ellipses to TRUE).
  *
- * @return
+ * @return string
  *   The truncated string.
  */
 function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1) {
@@ -356,8 +365,7 @@
 }
 
 /**
- * Encodes MIME/HTTP header values that contain non-ASCII, UTF-8 encoded
- * characters.
+ * Encodes MIME/HTTP header values that contain incorrectly encoded characters.
  *
  * For example, mime_header_encode('tést.txt') returns "=?UTF-8?B?dMOpc3QudHh0?=".
  *
@@ -369,6 +377,14 @@
  *   each chunk starts and ends on a character boundary.
  * - Using \n as the chunk separator may cause problems on some systems and may
  *   have to be changed to \r\n or \r.
+ *
+ * @param $string
+ *   The header to encode.
+ *
+ * @return string
+ *   The mime-encoded header.
+ *
+ * @see mime_header_decode()
  */
 function mime_header_encode($string) {
   if (preg_match('/[^\x20-\x7E]/', $string)) {
@@ -388,7 +404,15 @@
 }
 
 /**
- * Complement to mime_header_encode
+ * Decodes MIME/HTTP encoded header values.
+ *
+ * @param $header
+ *   The header to decode.
+ *
+ * @return string
+ *   The mime-decoded header.
+ *
+ * @see mime_header_encode()
  */
 function mime_header_decode($header) {
   // First step: encoded chunks followed by other encoded chunks (need to collapse whitespace)
@@ -398,7 +422,17 @@
 }
 
 /**
- * Helper function to mime_header_decode
+ * Decodes encoded header data passed from mime_header_decode().
+ *
+ * Callback for preg_replace_callback() within mime_header_decode().
+ *
+ * @param $matches
+ *   The array of matches from preg_replace_callback().
+ *
+ * @return string
+ *   The mime-decoded string.
+ *
+ * @see mime_header_decode()
  */
 function _mime_header_decode($matches) {
   // Regexp groups:
@@ -415,9 +449,9 @@
 /**
  * Decodes all HTML entities (including numerical ones) to regular UTF-8 bytes.
  *
- * Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;",
- * not "<"). Be careful when using this function, as decode_entities can revert
- * previous sanitization efforts (&lt;script&gt; will become <script>).
+ * Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;"
+ * , not "<"). Be careful when using this function, as decode_entities can
+ * revert previous sanitization efforts (&lt;script&gt; will become <script>).
  *
  * @param $text
  *   The text to decode entities in.
@@ -430,8 +464,15 @@
 }
 
 /**
- * Count the amount of characters in a UTF-8 string. This is less than or
- * equal to the byte count.
+ * Counts the number of characters in a UTF-8 string.
+ *
+ * This is less than or equal to the byte count.
+ *
+ * @param $text
+ *   The string to run the operation on.
+ *
+ * @return integer
+ *   The length of the string.
  *
  * @ingroup php_wrappers
  */
@@ -449,6 +490,12 @@
 /**
  * Uppercase a UTF-8 string.
  *
+ * @param $text
+ *   The string to run the operation on.
+ *
+ * @return string
+ *   The string in uppercase.
+ *
  * @ingroup php_wrappers
  */
 function drupal_strtoupper($text) {
@@ -468,6 +515,12 @@
 /**
  * Lowercase a UTF-8 string.
  *
+ * @param $text
+ *   The string to run the operation on.
+ *
+ * @return string
+ *   The string in lowercase.
+ *
  * @ingroup php_wrappers
  */
 function drupal_strtolower($text) {
@@ -485,15 +538,28 @@
 }
 
 /**
- * Helper function for case conversion of Latin-1.
- * Used for flipping U+C0-U+DE to U+E0-U+FD and back.
+ * Flips U+C0-U+DE to U+E0-U+FD and back.
+ *
+ * @param $matches
+ *   An array of matches.
+ *
+ * @return array
+ *   The Latin-1 version of the array of matches.
+ *
+ * @see drupal_strtolower()
  */
 function _unicode_caseflip($matches) {
   return $matches[0][0] . chr(ord($matches[0][1]) ^ 32);
 }
 
 /**
- * Capitalize the first letter of a UTF-8 string.
+ * Capitalizes the first letter of a UTF-8 string.
+ *
+ * @param $text
+ *   The string to convert.
+ *
+ * @return
+ *   The string with the first letter as uppercase.
  *
  * @ingroup php_wrappers
  */
@@ -503,12 +569,21 @@
 }
 
 /**
- * Cut off a piece of a string based on character indices and counts. Follows
- * the same behavior as PHP's own substr() function.
+ * Cuts off a piece of a string based on character indices and counts.
+ *
+ * Follows the same behavior as PHP's own substr() function. Note that for
+ * cutting off a string at a known character/substring location, the usage of
+ * PHP's normal strpos/substr is safe and much faster.
  *
- * Note that for cutting off a string at a known character/substring
- * location, the usage of PHP's normal strpos/substr is safe and
- * much faster.
+ * @param $text
+ *   The input string.
+ * @param $start
+ *   The position at which to start reading.
+ * @param $length
+ *   The number of characters to read.
+ *
+ * @return
+ *   The shortened string.
  *
  * @ingroup php_wrappers
  */
diff -Naur drupal-7.9/includes/update.inc drupal-7.58/includes/update.inc
--- drupal-7.9/includes/update.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/update.inc	2018-03-27 21:28:19.000000000 +0200
@@ -38,7 +38,7 @@
 }
 
 /**
- * Helper function to test compatibility of a module or theme.
+ * Tests the compatibility of a module or theme.
  */
 function update_check_incompatibility($name, $type = 'module') {
   static $themes, $modules;
@@ -410,15 +410,18 @@
     // Initialize batch update information.
     $sandbox['progress'] = 0;
     $sandbox['last_user_processed'] = -1;
-    $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE data IS NOT NULL")->fetchField();
+    $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE data LIKE :block", array(
+        ':block' => '%' . db_like(serialize('block')) . '%',
+      ))
+      ->fetchField();
   }
   // Now do the batch update of the user-specific block visibility settings.
   $limit = 100;
   $result = db_select('users', 'u')
     ->fields('u', array('uid', 'data'))
     ->condition('uid', $sandbox['last_user_processed'], '>')
+    ->condition('data', '%' . db_like(serialize('block')) . '%', 'LIKE')
     ->orderBy('uid', 'ASC')
-    ->where('data IS NOT NULL')
     ->range(0, $limit)
     ->execute();
   foreach ($result as $row) {
@@ -746,7 +749,7 @@
     // 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().
+    // system_update_7072().
     if ($message = variable_get('site_offline_message', NULL)) {
       variable_set('maintenance_mode_message', $message);
     }
@@ -782,16 +785,24 @@
 /**
  * Register the currently installed profile in the system table.
  *
- * Install profiles are now treated as modules by Drupal, and have an upgrade
- * path based on their schema version in the system table.
+ * Installation profiles are now treated as modules by Drupal, and have an
+ * upgrade path based on their schema version in the system table.
  *
- * The install profile will be set to schema_version 0, as it has already been
- * installed. Any other hook_update_N functions provided by the install profile
- * will be run by update.php.
+ * The installation profile will be set to schema_version 0, as it has already
+ * been installed. Any other hook_update_N functions provided by the
+ * installation profile will be run by update.php.
  */
 function update_fix_d7_install_profile() {
   $profile = drupal_get_profile();
 
+  // 'Default' profile has been renamed to 'Standard' in D7.
+  // We change the profile here to prevent a broken record in the system table.
+  // See system_update_7049().
+  if ($profile == 'default') {
+    $profile = 'standard';
+    variable_set('install_profile', $profile);
+  }
+
   $results = db_select('system', 's')
     ->fields('s', array('name', 'schema_version'))
     ->condition('name', $profile)
@@ -815,9 +826,6 @@
       'files' => array(),
     );
 
-    // The install profile is always required.
-    $file->info['required'] = TRUE;
-
     $values = array(
       'filename' => $filename,
       'name' => $profile,
@@ -828,10 +836,10 @@
       'owner' => '',
     );
 
-    // Install profile hooks are always executed last by the module system
+    // Installation profile hooks are always executed last by the module system
     $values['weight'] = 1000;
 
-    // Initializing the system table entry for the install profile
+    // Initializing the system table entry for the installation profile
     db_insert('system')
       ->fields(array_keys($values))
       ->values($values)
@@ -840,7 +848,8 @@
     // Reset the cached schema version.
     drupal_get_installed_schema_version($profile, TRUE);
 
-    // Load the updates again to make sure the install profile updates are loaded
+    // Load the updates again to make sure the installation profile updates
+    // are loaded.
     drupal_load_updates();
   }
 }
@@ -895,7 +904,7 @@
   }
   else {
     // Otherwise use $base_url as session name, without the protocol
-    // to use the same session identifiers across http and https.
+    // to use the same session identifiers across HTTP and HTTPS.
     list( , $session_name) = explode('://', $base_url, 2);
   }
 
@@ -907,7 +916,9 @@
 }
 
 /**
- * Perform one update and store the results for display on finished page.
+ * Implements callback_batch_operation().
+ *
+ * Performs one update and stores the results for display on the results page.
  *
  * If an update function completes successfully, it should return a message
  * as a string indicating success, for example:
@@ -1007,7 +1018,7 @@
 class DrupalUpdateException extends Exception { }
 
 /**
- * Start the database update batch process.
+ * Starts the database update batch process.
  *
  * @param $start
  *   An array whose keys contain the names of modules to be updated during the
@@ -1077,7 +1088,9 @@
 }
 
 /**
- * Finish the update process and store results for eventual display.
+ * Implements callback_batch_finished().
+ *
+ * Finishes the update process and stores the results for eventual display.
  *
  * After the updates run, all caches are flushed. The update results are
  * stored into the session (for example, to be displayed on the update results
@@ -1114,7 +1127,7 @@
 }
 
 /**
- * Return a list of all the pending database updates.
+ * Returns a list of all the pending database updates.
  *
  * @return
  *   An associative array keyed by module name which contains all information
@@ -1408,7 +1421,7 @@
 }
 
 /**
- * Invoke hook_update_dependencies() in all installed modules.
+ * Invokes hook_update_dependencies() in all installed modules.
  *
  * This function is similar to module_invoke_all(), with the main difference
  * that it does not require that a module be enabled to invoke its hook, only
@@ -1474,17 +1487,3 @@
 
   return $return;
 }
-
-/**
- * @defgroup update-api-6.x-to-7.x Update versions of API functions
- * @{
- * Functions similar to normal API function but not firing hooks.
- *
- * During update, it is impossible to judge the consequences of firing a hook
- * as it might hit a module not yet updated. So simplified versions of some
- * core APIs are provided.
- */
-
-/**
- * @} End of "defgroup update-api-6.x-to-7.x"
- */
diff -Naur drupal-7.9/includes/updater.inc drupal-7.58/includes/updater.inc
--- drupal-7.9/includes/updater.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/updater.inc	2018-03-27 21:28:19.000000000 +0200
@@ -141,7 +141,7 @@
       return FALSE;
     }
     foreach ($info_files as $info_file) {
-      if (drupal_substr($info_file->filename, 0, -5) == basename($directory)) {
+      if (drupal_substr($info_file->filename, 0, -5) == drupal_basename($directory)) {
         // Info file Has the same name as the directory, return it.
         return $info_file->uri;
       }
@@ -163,7 +163,7 @@
    *   The name of the project.
    */
   public static function getProjectName($directory) {
-    return basename($directory);
+    return drupal_basename($directory);
   }
 
   /**
@@ -330,7 +330,7 @@
           }
           catch (FileTransferException $e) {
             $message = t($e->getMessage(), $e->arguments);
-            $throw_message = t('Unable to create %directory due to the following: %reason', array('%directory' => $install_location, '%reason' => $message));
+            $throw_message = t('Unable to create %directory due to the following: %reason', array('%directory' => $directory, '%reason' => $message));
             throw new UpdaterException($throw_message);
           }
         }
diff -Naur drupal-7.9/includes/utility.inc drupal-7.58/includes/utility.inc
--- drupal-7.9/includes/utility.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/utility.inc	2018-03-27 21:28:19.000000000 +0200
@@ -12,6 +12,7 @@
  *   The variable to export.
  * @param $prefix
  *   A prefix that will be added at the beginning of every lines of the output.
+ *
  * @return
  *   The variable exported in a way compatible to Drupal's coding standards.
  */
@@ -46,6 +47,13 @@
       $output = "'" . $var . "'";
     }
   }
+  elseif (is_object($var) && get_class($var) === 'stdClass') {
+    // var_export() will export stdClass objects using an undefined
+    // magic method __set_state() leaving the export broken. This
+    // workaround avoids this by casting the object as an array for
+    // export and casting it back to an object when evaluated.
+    $output = '(object) ' . drupal_var_export((array) $var, $prefix);
+  }
   else {
     $output = var_export($var, TRUE);
   }
diff -Naur drupal-7.9/includes/xmlrpc.inc drupal-7.58/includes/xmlrpc.inc
--- drupal-7.9/includes/xmlrpc.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/xmlrpc.inc	2018-03-27 21:28:19.000000000 +0200
@@ -178,7 +178,41 @@
   xml_set_element_handler($xmlrpc_message->_parser, 'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
   xml_set_character_data_handler($xmlrpc_message->_parser, 'xmlrpc_message_cdata');
   xmlrpc_message_set($xmlrpc_message);
-  if (!xml_parse($xmlrpc_message->_parser, $xmlrpc_message->message)) {
+
+  // Strip XML declaration.
+  $header = preg_replace('/<\?xml.*?\?'.'>/s', '', substr($xmlrpc_message->message, 0, 100), 1);
+  $xml = trim(substr_replace($xmlrpc_message->message, $header, 0, 100));
+  if ($xml == '') {
+    return FALSE;
+  }
+  // Strip DTD.
+  $header = preg_replace('/^<!DOCTYPE[^>]*+>/i', '', substr($xml, 0, 200), 1);
+  $xml = trim(substr_replace($xml, $header, 0, 200));
+  if ($xml == '') {
+    return FALSE;
+  }
+  // Confirm the XML now starts with a valid root tag. A root tag can end in [> \t\r\n]
+  $root_tag = substr($xml, 0, strcspn(substr($xml, 0, 20), "> \t\r\n"));
+  // Reject a second DTD.
+  if (strtoupper($root_tag) == '<!DOCTYPE') {
+    return FALSE;
+  }
+  if (!in_array($root_tag, array('<methodCall', '<methodResponse', '<fault'))) {
+    return FALSE;
+  }
+  // Skip parsing if there is an unreasonably large number of tags.
+  try {
+    $dom = new DOMDocument();
+    @$dom->loadXML($xml);
+    if ($dom->getElementsByTagName('*')->length > variable_get('xmlrpc_message_maximum_tag_count', 30000)) {
+      return FALSE;
+    }
+  }
+  catch (Exception $e) {
+    return FALSE;
+  }
+
+  if (!xml_parse($xmlrpc_message->_parser, $xml)) {
     return FALSE;
   }
   xml_parser_free($xmlrpc_message->_parser);
@@ -622,4 +656,3 @@
 function xmlrpc_clear_error() {
   xmlrpc_error(NULL, NULL, TRUE);
 }
-
diff -Naur drupal-7.9/includes/xmlrpcs.inc drupal-7.58/includes/xmlrpcs.inc
--- drupal-7.9/includes/xmlrpcs.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/includes/xmlrpcs.inc	2018-03-27 21:28:19.000000000 +0200
@@ -9,7 +9,9 @@
  * Invokes XML-RPC methods on this server.
  *
  * @param array $callbacks
- *   Array of external XML-RPC method names with the callbacks they map to.
+ *   Either an associative array of external XML-RPC method names as keys with
+ *   the callbacks they map to as values, or a more complex structure
+ *   describing XML-RPC callbacks as returned from hook_xmlrpc().
  */
 function xmlrpc_server($callbacks) {
   $xmlrpc_server = new stdClass();
@@ -262,6 +264,10 @@
  */
 function xmlrpc_server_multicall($methodcalls) {
   // See http://www.xmlrpc.com/discuss/msgReader$1208
+  // To avoid multicall expansion attacks, limit the number of duplicate method
+  // calls allowed with a default of 1. Set to -1 for unlimited.
+  $duplicate_method_limit = variable_get('xmlrpc_multicall_duplicate_method_limit', 1);
+  $method_count = array();
   $return = array();
   $xmlrpc_server = xmlrpc_server_get();
   foreach ($methodcalls as $call) {
@@ -271,10 +277,14 @@
       $ok = FALSE;
     }
     $method = $call['methodName'];
+    $method_count[$method] = isset($method_count[$method]) ? $method_count[$method] + 1 : 1;
     $params = $call['params'];
     if ($method == 'system.multicall') {
       $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.'));
     }
+    elseif ($duplicate_method_limit > 0 && $method_count[$method] > $duplicate_method_limit) {
+      $result = xmlrpc_error(-156579, t('Too many duplicate method calls in system.multicall.'));
+    }
     elseif ($ok) {
       $result = xmlrpc_server_call($xmlrpc_server, $method, $params);
     }
@@ -382,4 +392,3 @@
   $xmlrpc_server = xmlrpc_server_get();
   return $xmlrpc_server->help[$method];
 }
-
diff -Naur drupal-7.9/install.php drupal-7.58/install.php
--- drupal-7.9/install.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/install.php	2018-03-27 21:28:19.000000000 +0200
@@ -6,12 +6,12 @@
  */
 
 /**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
  */
 define('DRUPAL_ROOT', getcwd());
 
 /**
- * Global flag to indicate that site is in installation mode.
+ * Global flag to indicate the site is in installation mode.
  */
 define('MAINTENANCE_MODE', 'install');
 
diff -Naur drupal-7.9/misc/ajax.js drupal-7.58/misc/ajax.js
--- drupal-7.9/misc/ajax.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/ajax.js	2018-03-27 21:28:19.000000000 +0200
@@ -14,6 +14,8 @@
 
 Drupal.ajax = Drupal.ajax || {};
 
+Drupal.settings.urlIsAjaxTrusted = Drupal.settings.urlIsAjaxTrusted || {};
+
 /**
  * Attaches the Ajax behavior to each Ajax form element.
  */
@@ -130,6 +132,11 @@
   // 5. /nojs# - Followed by a fragment.
   //      E.g.: path/nojs#myfragment
   this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1');
+  // If the 'nojs' version of the URL is trusted, also trust the 'ajax' version.
+  if (Drupal.settings.urlIsAjaxTrusted[element_settings.url]) {
+    Drupal.settings.urlIsAjaxTrusted[this.url] = true;
+  }
+
   this.wrapper = '#' + element_settings.wrapper;
 
   // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
@@ -155,18 +162,36 @@
       ajax.ajaxing = true;
       return ajax.beforeSend(xmlhttprequest, options);
     },
-    success: function (response, status) {
+    success: function (response, status, xmlhttprequest) {
       // Sanity check for browser support (object expected).
       // When using iFrame uploads, responses must be returned as a string.
       if (typeof response == 'string') {
         response = $.parseJSON(response);
       }
+
+      // Prior to invoking the response's commands, verify that they can be
+      // trusted by checking for a response header. See
+      // ajax_set_verification_header() for details.
+      // - Empty responses are harmless so can bypass verification. This avoids
+      //   an alert message for server-generated no-op responses that skip Ajax
+      //   rendering.
+      // - Ajax objects with trusted URLs (e.g., ones defined server-side via
+      //   #ajax) can bypass header verification. This is especially useful for
+      //   Ajax with multipart forms. Because IFRAME transport is used, the
+      //   response headers cannot be accessed for verification.
+      if (response !== null && !Drupal.settings.urlIsAjaxTrusted[ajax.url]) {
+        if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') {
+          var customMessage = Drupal.t("The response failed verification so will not be processed.");
+          return ajax.error(xmlhttprequest, ajax.url, customMessage);
+        }
+      }
+
       return ajax.success(response, status);
     },
-    complete: function (response, status) {
+    complete: function (xmlhttprequest, status) {
       ajax.ajaxing = false;
       if (status == 'error' || status == 'parsererror') {
-        return ajax.error(response, ajax.url);
+        return ajax.error(xmlhttprequest, ajax.url);
       }
     },
     dataType: 'json',
@@ -175,6 +200,9 @@
 
   // Bind the ajaxSubmit function to the element event.
   $(ajax.element).bind(element_settings.event, function (event) {
+    if (!Drupal.settings.urlIsAjaxTrusted[ajax.url] && !Drupal.urlIsLocal(ajax.url)) {
+      throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {'!url': ajax.url}));
+    }
     return ajax.eventResponse(this, event);
   });
 
@@ -318,7 +346,7 @@
 Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
   // 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.
@@ -348,7 +376,7 @@
     // this is only needed for IFRAME submissions.
     var v = $.fieldValue(this.element);
     if (v !== null) {
-      options.extraData[this.element.name] = v;
+      options.extraData[this.element.name] = Drupal.checkPlain(v);
     }
   }
 
@@ -396,7 +424,7 @@
   Drupal.freezeHeight();
 
   for (var i in response) {
-    if (response[i]['command'] && this.commands[response[i]['command']]) {
+    if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) {
       this.commands[response[i]['command']](this, response[i], status);
     }
   }
@@ -447,8 +475,8 @@
 /**
  * Handler for the form redirection error.
  */
-Drupal.ajax.prototype.error = function (response, uri) {
-  alert(Drupal.ajaxError(response, uri));
+Drupal.ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
+  Drupal.displayAjaxError(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
   // Remove the progress element.
   if (this.progress.element) {
     $(this.progress.element).remove();
@@ -462,7 +490,7 @@
   $(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;
+    var settings = this.settings || Drupal.settings;
     Drupal.attachBehaviors(this.form, settings);
   }
 };
@@ -616,6 +644,33 @@
       .removeClass('odd even')
       .filter(':even').addClass('odd').end()
       .filter(':odd').addClass('even');
+  },
+
+  /**
+   * Command to add css.
+   *
+   * Uses the proprietary addImport method if available as browsers which
+   * support that method ignore @import statements in dynamically added
+   * stylesheets.
+   */
+  add_css: function (ajax, response, status) {
+    // Add the styles in the normal way.
+    $('head').prepend(response.data);
+    // Add imports in the styles using the addImport method if available.
+    var match, importMatch = /^@import url\("(.*)"\);$/igm;
+    if (document.styleSheets[0].addImport && importMatch.test(response.data)) {
+      importMatch.lastIndex = 0;
+      while (match = importMatch.exec(response.data)) {
+        document.styleSheets[0].addImport(match[1]);
+      }
+    }
+  },
+
+  /**
+   * Command to update a form's build ID.
+   */
+  updateBuildId: function(ajax, response, status) {
+    $('input[name="form_build_id"][value="' + response['old'] + '"]').val(response['new']);
   }
 };
 
diff -Naur drupal-7.9/misc/authorize.js drupal-7.58/misc/authorize.js
--- drupal-7.9/misc/authorize.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/authorize.js	2018-03-27 21:28:19.000000000 +0200
@@ -16,7 +16,6 @@
 
     // Removes the float on the select box (used for non-JS interface).
     if ($('.connection-settings-update-filetransfer-default-wrapper').length > 0) {
-      console.log($('.connection-settings-update-filetransfer-default-wrapper'));
       $('.connection-settings-update-filetransfer-default-wrapper').css('float', 'none');
     }
     // Hides the submit button for non-js users.
diff -Naur drupal-7.9/misc/autocomplete.js drupal-7.58/misc/autocomplete.js
--- drupal-7.9/misc/autocomplete.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/autocomplete.js	2018-03-27 21:28:19.000000000 +0200
@@ -32,7 +32,7 @@
 Drupal.autocompleteSubmit = function () {
   return $('#autocomplete').each(function () {
     this.owner.hidePopup();
-  }).size() == 0;
+  }).length == 0;
 };
 
 /**
@@ -41,7 +41,7 @@
 Drupal.jsAC = function ($input, db) {
   var ac = this;
   this.input = $input[0];
-  this.ariaLive = $('#' + $input.attr('id') + '-autocomplete-aria-live');
+  this.ariaLive = $('#' + this.input.id + '-autocomplete-aria-live');
   this.db = db;
 
   $input
@@ -99,10 +99,12 @@
       return true;
 
     default: // All other keys.
-      if (input.value.length > 0)
+      if (input.value.length > 0 && !input.readOnly) {
         this.populatePopup();
-      else
+      }
+      else {
         this.hidePopup(e.keyCode);
+      }
       return true;
   }
 };
@@ -112,6 +114,7 @@
  */
 Drupal.jsAC.prototype.select = function (node) {
   this.input.value = $(node).data('autocompleteValue');
+  $(this.input).trigger('autocompleteSelect', [node]);
 };
 
 /**
@@ -123,7 +126,7 @@
   }
   else if (this.popup) {
     var lis = $('li', this.popup);
-    if (lis.size() > 0) {
+    if (lis.length > 0) {
       this.highlight(lis.get(0));
     }
   }
@@ -165,7 +168,7 @@
 Drupal.jsAC.prototype.hidePopup = function (keycode) {
   // Select item if the right key or mousebutton was pressed.
   if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
-    this.input.value = $(this.selected).data('autocompleteValue');
+    this.select(this.selected);
   }
   // Hide popup.
   var popup = this.popup;
@@ -218,7 +221,7 @@
   for (key in matches) {
     $('<li></li>')
       .html($('<div></div>').html(matches[key]))
-      .mousedown(function () { ac.select(this); })
+      .mousedown(function () { ac.hidePopup(this); })
       .mouseover(function () { ac.highlight(this); })
       .mouseout(function () { ac.unhighlight(this); })
       .data('autocompleteValue', key)
@@ -227,7 +230,7 @@
 
   // Show popup with matches, if any.
   if (this.popup) {
-    if (ul.children().size()) {
+    if (ul.children().length) {
       $(this.popup).empty().append(ul).show();
       $(this.ariaLive).html(Drupal.t('Autocomplete popup'));
     }
@@ -268,8 +271,11 @@
   var db = this;
   this.searchString = searchString;
 
-  // See if this string needs to be searched for anyway.
-  searchString = searchString.replace(/^\s+|\s+$/, '');
+  // See if this string needs to be searched for anyway. The pattern ../ is
+  // stripped since it may be misinterpreted by the browser.
+  searchString = searchString.replace(/^\s+|\.{2,}\/|\s+$/g, '');
+  // Skip empty search strings, or search strings ending with a comma, since
+  // that is the separator between search terms.
   if (searchString.length <= 0 ||
     searchString.charAt(searchString.length - 1) == ',') {
     return;
@@ -287,10 +293,11 @@
   this.timer = setTimeout(function () {
     db.owner.setStatus('begin');
 
-    // Ajax GET request for autocompletion.
+    // Ajax GET request for autocompletion. We use Drupal.encodePath instead of
+    // encodeURIComponent to allow autocomplete search terms to contain slashes.
     $.ajax({
       type: 'GET',
-      url: db.uri + '/' + encodeURIComponent(searchString),
+      url: db.uri + '/' + Drupal.encodePath(searchString),
       dataType: 'json',
       success: function (matches) {
         if (typeof matches.status == 'undefined' || matches.status != 0) {
@@ -303,7 +310,7 @@
         }
       },
       error: function (xmlhttp) {
-        alert(Drupal.ajaxError(xmlhttp, db.uri));
+        Drupal.displayAjaxError(Drupal.ajaxError(xmlhttp, db.uri));
       }
     });
   }, this.delay);
diff -Naur drupal-7.9/misc/collapse.js drupal-7.58/misc/collapse.js
--- drupal-7.9/misc/collapse.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/collapse.js	2018-03-27 21:28:19.000000000 +0200
@@ -58,9 +58,9 @@
     $('fieldset.collapsible', context).once('collapse', function () {
       var $fieldset = $(this);
       // Expand fieldset if there are errors inside, or if it contains an
-      // element that is targeted by the uri fragment identifier. 
+      // element that is targeted by the URI fragment identifier.
       var anchor = location.hash && location.hash != '#' ? ', ' + location.hash : '';
-      if ($('.error' + anchor, $fieldset).length) {
+      if ($fieldset.find('.error' + anchor).length) {
         $fieldset.removeClass('collapsed');
       }
 
diff -Naur drupal-7.9/misc/drupal.js drupal-7.58/misc/drupal.js
--- drupal-7.9/misc/drupal.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/drupal.js	2018-03-27 21:28:19.000000000 +0200
@@ -7,6 +7,63 @@
 (function ($) {
 
 /**
+ * Override jQuery.fn.init to guard against XSS attacks.
+ *
+ * See http://bugs.jquery.com/ticket/9521
+ */
+var jquery_init = $.fn.init;
+$.fn.init = function (selector, context, rootjQuery) {
+  // If the string contains a "#" before a "<", treat it as invalid HTML.
+  if (selector && typeof selector === 'string') {
+    var hash_position = selector.indexOf('#');
+    if (hash_position >= 0) {
+      var bracket_position = selector.indexOf('<');
+      if (bracket_position > hash_position) {
+        throw 'Syntax error, unrecognized expression: ' + selector;
+      }
+    }
+  }
+  return jquery_init.call(this, selector, context, rootjQuery);
+};
+$.fn.init.prototype = jquery_init.prototype;
+
+/**
+ * Pre-filter Ajax requests to guard against XSS attacks.
+ *
+ * See https://github.com/jquery/jquery/issues/2432
+ */
+if ($.ajaxPrefilter) {
+  // For newer versions of jQuery, use an Ajax prefilter to prevent
+  // auto-executing script tags from untrusted domains. This is similar to the
+  // fix that is built in to jQuery 3.0 and higher.
+  $.ajaxPrefilter(function (s) {
+    if (s.crossDomain) {
+      s.contents.script = false;
+    }
+  });
+}
+else if ($.httpData) {
+  // For the version of jQuery that ships with Drupal core, override
+  // jQuery.httpData to prevent auto-detecting "script" data types from
+  // untrusted domains.
+  var jquery_httpData = $.httpData;
+  $.httpData = function (xhr, type, s) {
+    // @todo Consider backporting code from newer jQuery versions to check for
+    //   a cross-domain request here, rather than using Drupal.urlIsLocal() to
+    //   block scripts from all URLs that are not on the same site.
+    if (!type && !Drupal.urlIsLocal(s.url)) {
+      var content_type = xhr.getResponseHeader('content-type') || '';
+      if (content_type.indexOf('javascript') >= 0) {
+        // Default to a safe data type.
+        type = 'text';
+      }
+    }
+    return jquery_httpData.call(this, xhr, type, s);
+  };
+  $.httpData.prototype = jquery_httpData.prototype;
+}
+
+/**
  * Attach all registered behaviors to a page element.
  *
  * Behaviors are event-triggered actions that attach to page elements, enhancing
@@ -116,7 +173,7 @@
  */
 Drupal.checkPlain = function (str) {
   var character, regex,
-      replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
+      replace = { '&': '&amp;', "'": '&#39;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
   str = String(str);
   for (character in replace) {
     if (replace.hasOwnProperty(character)) {
@@ -147,24 +204,77 @@
 Drupal.formatString = function(str, args) {
   // Transform arguments before inserting them.
   for (var key in args) {
-    switch (key.charAt(0)) {
-      // Escaped only.
-      case '@':
-        args[key] = Drupal.checkPlain(args[key]);
-      break;
-      // Pass-through.
-      case '!':
-        break;
-      // Escaped and placeholder.
-      case '%':
-      default:
-        args[key] = Drupal.theme('placeholder', args[key]);
-        break;
+    if (args.hasOwnProperty(key)) {
+      switch (key.charAt(0)) {
+        // Escaped only.
+        case '@':
+          args[key] = Drupal.checkPlain(args[key]);
+          break;
+        // Pass-through.
+        case '!':
+          break;
+        // Escaped and placeholder.
+        default:
+          args[key] = Drupal.theme('placeholder', args[key]);
+          break;
+      }
     }
-    str = str.replace(key, args[key]);
   }
-  return str;
-}
+
+  return Drupal.stringReplace(str, args, null);
+};
+
+/**
+ * Replace substring.
+ *
+ * The longest keys will be tried first. Once a substring has been replaced,
+ * its new value will not be searched again.
+ *
+ * @param {String} str
+ *   A string with placeholders.
+ * @param {Object} args
+ *   Key-value pairs.
+ * @param {Array|null} keys
+ *   Array of keys from the "args".  Internal use only.
+ *
+ * @return {String}
+ *   Returns the replaced string.
+ */
+Drupal.stringReplace = function (str, args, keys) {
+  if (str.length === 0) {
+    return str;
+  }
+
+  // If the array of keys is not passed then collect the keys from the args.
+  if (!$.isArray(keys)) {
+    keys = [];
+    for (var k in args) {
+      if (args.hasOwnProperty(k)) {
+        keys.push(k);
+      }
+    }
+
+    // Order the keys by the character length. The shortest one is the first.
+    keys.sort(function (a, b) { return a.length - b.length; });
+  }
+
+  if (keys.length === 0) {
+    return str;
+  }
+
+  // Take next longest one from the end.
+  var key = keys.pop();
+  var fragments = str.split(key);
+
+  if (keys.length) {
+    for (var i = 0; i < fragments.length; i++) {
+      // Process each fragment with a copy of remaining keys.
+      fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
+    }
+  }
+
+  return fragments.join(args[key]);
+};
 
 /**
  * Translate strings to the page language or a given language.
@@ -177,13 +287,21 @@
  *   An object of replacements pairs to make after translation. Incidences
  *   of any key in this array are replaced with the corresponding value.
  *   See Drupal.formatString().
+ *
+ * @param options
+ *   - 'context' (defaults to the empty context): The context the source string
+ *     belongs to.
+ *
  * @return
  *   The translated string.
  */
-Drupal.t = function (str, args) {
+Drupal.t = function (str, args, options) {
+  options = options || {};
+  options.context = options.context || '';
+
   // Fetch the localized version of the string.
-  if (Drupal.locale.strings && Drupal.locale.strings[str]) {
-    str = Drupal.locale.strings[str];
+  if (Drupal.locale.strings && Drupal.locale.strings[options.context] && Drupal.locale.strings[options.context][str]) {
+    str = Drupal.locale.strings[options.context][str];
   }
 
   if (args) {
@@ -216,29 +334,97 @@
  *   See Drupal.formatString().
  *   Note that you do not need to include @count in this array.
  *   This replacement is done automatically for the plural case.
+ * @param options
+ *   The options to pass to the Drupal.t() function.
  * @return
  *   A translated string.
  */
-Drupal.formatPlural = function (count, singular, plural, args) {
-  var args = args || {};
+Drupal.formatPlural = function (count, singular, plural, args, options) {
+  args = args || {};
   args['@count'] = count;
   // Determine the index of the plural form.
   var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
 
   if (index == 0) {
-    return Drupal.t(singular, args);
+    return Drupal.t(singular, args, options);
   }
   else if (index == 1) {
-    return Drupal.t(plural, args);
+    return Drupal.t(plural, args, options);
   }
   else {
     args['@count[' + index + ']'] = args['@count'];
     delete args['@count'];
-    return Drupal.t(plural.replace('@count', '@count[' + index + ']'), args);
+    return Drupal.t(plural.replace('@count', '@count[' + index + ']'), args, options);
   }
 };
 
 /**
+ * Returns the passed in URL as an absolute URL.
+ *
+ * @param url
+ *   The URL string to be normalized to an absolute URL.
+ *
+ * @return
+ *   The normalized, absolute URL.
+ *
+ * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
+ * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
+ * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
+ */
+Drupal.absoluteUrl = function (url) {
+  var urlParsingNode = document.createElement('a');
+
+  // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
+  // strings may throw an exception.
+  try {
+    url = decodeURIComponent(url);
+  } catch (e) {}
+
+  urlParsingNode.setAttribute('href', url);
+
+  // IE <= 7 normalizes the URL when assigned to the anchor node similar to
+  // the other browsers.
+  return urlParsingNode.cloneNode(false).href;
+};
+
+/**
+ * Returns true if the URL is within Drupal's base path.
+ *
+ * @param url
+ *   The URL string to be tested.
+ *
+ * @return
+ *   Boolean true if local.
+ *
+ * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
+ */
+Drupal.urlIsLocal = function (url) {
+  // Always use browser-derived absolute URLs in the comparison, to avoid
+  // attempts to break out of the base path using directory traversal.
+  var absoluteUrl = Drupal.absoluteUrl(url);
+  var protocol = location.protocol;
+
+  // Consider URLs that match this site's base URL but use HTTPS instead of HTTP
+  // as local as well.
+  if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
+    protocol = 'https:';
+  }
+  var baseUrl = protocol + '//' + location.host + Drupal.settings.basePath.slice(0, -1);
+
+  // Decoding non-UTF-8 strings may throw an exception.
+  try {
+    absoluteUrl = decodeURIComponent(absoluteUrl);
+  } catch (e) {}
+  try {
+    baseUrl = decodeURIComponent(baseUrl);
+  } catch (e) {}
+
+  // The given URL matches the site's base URL, or has a path under the site's
+  // base URL.
+  return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0;
+};
+
+/**
  * Generate the themed representation of a Drupal object.
  *
  * All requests for themed output must go through this function. It examines
@@ -317,9 +503,32 @@
 };
 
 /**
+ * Add a global variable which determines if the window is being unloaded.
+ *
+ * This is primarily used by Drupal.displayAjaxError().
+ */
+Drupal.beforeUnloadCalled = false;
+$(window).bind('beforeunload pagehide', function () {
+    Drupal.beforeUnloadCalled = true;
+});
+
+/**
+ * Displays a JavaScript error from an Ajax response when appropriate to do so.
+ */
+Drupal.displayAjaxError = function (message) {
+  // Skip displaying the message if the user deliberately aborted (for example,
+  // by reloading the page or navigating to a different page) while the Ajax
+  // request was still ongoing. See, for example, the discussion at
+  // http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-clicks-refresh.
+  if (!Drupal.beforeUnloadCalled) {
+    alert(message);
+  }
+};
+
+/**
  * Build an error message from an Ajax response.
  */
-Drupal.ajaxError = function (xmlhttp, uri) {
+Drupal.ajaxError = function (xmlhttp, uri, customMessage) {
   var statusCode, statusText, pathText, responseText, readyStateText, message;
   if (xmlhttp.status) {
     statusCode = "\n" + Drupal.t("An AJAX HTTP error occurred.") +  "\n" + Drupal.t("HTTP Result Code: !status", {'!status': xmlhttp.status});
@@ -352,7 +561,10 @@
   // We don't need readyState except for status == 0.
   readyStateText = xmlhttp.status == 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : "";
 
-  message = statusCode + pathText + statusText + responseText + readyStateText;
+  // Additional message beyond what the xmlhttp object provides.
+  customMessage = customMessage ? ("\n" + Drupal.t("CustomMessage: !customMessage", {'!customMessage': customMessage})) : "";
+
+  message = statusCode + pathText + statusText + customMessage + responseText + readyStateText;
   return message;
 };
 
diff -Naur drupal-7.9/misc/favicon.ico drupal-7.58/misc/favicon.ico
--- drupal-7.9/misc/favicon.ico	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/favicon.ico	2018-03-27 21:28:19.000000000 +0200
@@ -1,2 +1,7 @@
-         h     (                                                }N W zX W l!y6Ώ^R "                            W GV Y Y [ĩ{Pu|6U z                    V CX Zv-|7Y cAs(jaez            ^ +e q ۹nJdu,u19        d s s Ӿl        j s s ܹʤ{2̴ƭ        l s s x
-֬h۾ܹ s q _ itb        k s s s s s s s s s r ] Y W         h s s s s s s s s s s n Y W         c s s s s s s s s s s s ` T         \ ض~Ñs s s s s s s s _ P             NңWss s s s s n ^ p                    Ic߻s s s s l _ m                            \ ̫uĈ's o e ϗ] /                                        z,ڵyi ^ =                                                    w#] 5                                                        ?    
\ No newline at end of file
+         h  &              (                                         troT@h~Zhڝs-ܔr9fN(l-+''''      @@@ D7#BZY Y bçwenx6* H     D7"BV Y u+{4[llffgwaH   spllr ݻ`\ms)urn  hL ps s Ĩzzn\r  n s s ߿ݿu(̵r  ~ ܺs s vܸӮȐ6s p ^ }7ɰr*  ~"غs s s s s s s s s q ] Y l$  n&s s s s s s s s s s n Y a)  ]H&Z~us s s s s s s s s ^ SC)R  ''&t׶͙Ets s s s s s s {M *))  UUU QMF&zs s s s s p
+ꒊ}&      ͤx	s s s [ H?/*       \\\=7,TŶ̗As [ ?' f ///        \\\     	ĥrk)          mmm   YG*d\[Z       ?                          ?      (       @                                       <<< <<< A?<`S<Lf<s<z<{<F}NyiNTURNNNN NNN NNN NNN NNN                 ,Q2 Q X Y Y Y _	s(t*n\c=  4                      www FFF FFF KIF}a2U Y Y Y Y iȫǧ~-_;                DDD     	 "oE ԍX Y Y Y Y Y >ɰdY Y Y Y x/e
+V  ,          DDD 
+ $xK Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y [ ] 쏇y,         JHDqG ؏Y \ [ Y ;ræwYdY Y ¦v¥uYY URY Y Hv3:71        d.k r s uϩкh[ʱcY ѻr     @@@  6m s s s իf¦v]\fYYϸ#B@@@     @@@ kB s s s s ϩJY bĥvX@@@     IF@i s s s s ͤԽKG@    q^@\r s s s s Ӧ\LSαr_@`    v@s s s s s uرqsc Y Znлr@    @s s s s s s ع׶Æ"s s s i Y Y p#ӻu+|@    @s s s s s s s s ̘C޼Ȝ޽Ȑ6s s s s s s l Z Y Y n `Y @    @s s s s s s s s s s s s s s s s s s s s m Z Y Y Y Y |@    Js s s s s s s s s s s s s s s s s s s s s j Y Y Y Y P    xLzs s s s s s s s s s s s s s s s s s s s s s c Y Y Y vRr    h^L<p s s s s s s s s s s s s s s s s s s s s s p Y Y W h`R2    MLL[ s s s s s s s s s s s s s s s s s s s s s s a Y rG RRR    LLL G, |ʓ9}s s s s s s s s s s s s s s s s s s s g X 6" pRRR     LLL  Fϥɛ֫es s s s s s s s s s s s s s s s s j wJ  
+RRR     LLL     3$ZͣӤXx	s s s s s s s s s s s s s s s g & P    RRR     LLL         dT:྇Ć#s s s s s s s s s s s s s r [;  WWW      ooo ooo qpouͣʒ9s s s s s s s s s s s r k*           lllSE.~԰ʓ;s s s s s s s s s p _: ba_              ~<Ѫć$s s s s s s s e 9# h   ___                  :-`ڱps s s s r c W6          ___                         
+^O7vs s a =% n                 ___                                1%T͚Gr c73,,,, ,,, ,,, ,,, ,,, ,,, {{{                                    sVѢVvI 
+                                           =-fl)                         666 666 666 666 666 JB6,HB6&666                      ?                                      ?  ?
\ No newline at end of file
diff -Naur drupal-7.9/misc/machine-name.js drupal-7.58/misc/machine-name.js
--- drupal-7.9/misc/machine-name.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/machine-name.js	2018-03-27 21:28:19.000000000 +0200
@@ -19,6 +19,10 @@
    *     disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
    *   - replace: A character to replace disallowed characters with; e.g., '_'
    *     or '-'.
+   *   - standalone: Whether the preview should stay in its own element rather
+   *     than the suffix of the source element.
+   *   - field_prefix: The #field_prefix of the form element.
+   *   - field_suffix: The #field_suffix of the form element.
    */
   attach: function (context, settings) {
     var self = this;
@@ -26,7 +30,7 @@
       var $source = $(source_id, context).addClass('machine-name-source');
       var $target = $(options.target, context).addClass('machine-name-target');
       var $suffix = $(options.suffix, context);
-      var $wrapper = $target.parents('.form-item:first');
+      var $wrapper = $target.closest('.form-item');
       // All elements have to exist.
       if (!$source.length || !$target.length || !$suffix.length || !$wrapper.length) {
         return;
@@ -49,10 +53,12 @@
         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);
+      var $preview = $('<span class="machine-name-value">' + options.field_prefix + Drupal.checkPlain(machine) + options.field_suffix + '</span>');
+      $suffix.empty();
+      if (options.label) {
+        $suffix.append(' ').append('<span class="machine-name-label">' + options.label + ':</span>');
+      }
+      $suffix.append(' ').append($preview);
 
       // If the machine name cannot be edited, stop further processing.
       if ($target.is(':disabled')) {
@@ -74,12 +80,14 @@
       // 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 () {
+        $source.bind('keyup.machineName change.machineName input.machineName', function () {
           machine = self.transliterate($(this).val(), options);
           // Set the machine name to the transliterated value.
-          if (machine != options.replace && machine != '') {
-            $target.val(machine);
-            $preview.text(machine);
+          if (machine != '') {
+            if (machine != options.replace) {
+              $target.val(machine);
+              $preview.html(options.field_prefix + Drupal.checkPlain(machine) + options.field_suffix);
+            }
             $suffix.show();
           }
           else {
diff -Naur drupal-7.9/misc/states.js drupal-7.58/misc/states.js
--- drupal-7.9/misc/states.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/states.js	2018-03-27 21:28:19.000000000 +0200
@@ -16,12 +16,13 @@
  */
 Drupal.behaviors.states = {
   attach: function (context, settings) {
+    var $context = $(context);
     for (var selector in settings.states) {
       for (var state in settings.states[selector]) {
         new states.Dependent({
-          element: $(selector),
+          element: $context.find(selector),
           state: states.State.sanitize(state),
-          dependees: settings.states[selector][state]
+          constraints: settings.states[selector][state]
         });
       }
     }
@@ -40,12 +41,14 @@
  *   Object with the following keys (all of which are required):
  *   - element: A jQuery object of the dependent element
  *   - state: A State object describing the state that is dependent
- *   - dependees: An object with dependency specifications. Lists all elements
- *     that this element depends on.
+ *   - constraints: An object with dependency specifications. Lists all elements
+ *     that this element depends on. It can be nested and can contain arbitrary
+ *     AND and OR clauses.
  */
 states.Dependent = function (args) {
-  $.extend(this, { values: {}, oldValue: undefined }, args);
+  $.extend(this, { values: {}, oldValue: null }, args);
 
+  this.dependees = this.getDependees();
   for (var selector in this.dependees) {
     this.initializeDependee(selector, this.dependees[selector]);
   }
@@ -69,7 +72,7 @@
     // as a string before applying the strict comparison in compare(). Otherwise
     // numeric keys in the form's #states array fail to match string values
     // returned from jQuery's val().
-    return (value.constructor.name === 'String') ? compare(String(reference), value) : compare(reference, value);
+    return (typeof value === 'string') ? compare(reference.toString(), value) : compare(reference, value);
   }
 };
 
@@ -84,26 +87,33 @@
    *   dependee's compliance status.
    */
   initializeDependee: function (selector, dependeeStates) {
-    var self = this;
+    var state;
 
     // Cache for the states of this dependee.
-    self.values[selector] = {};
+    this.values[selector] = {};
 
-    $.each(dependeeStates, function (state, value) {
-      state = states.State.sanitize(state);
+    for (var i in dependeeStates) {
+      if (dependeeStates.hasOwnProperty(i)) {
+        state = dependeeStates[i];
+        // Make sure we're not initializing this selector/state combination twice.
+        if ($.inArray(state, dependeeStates) === -1) {
+          continue;
+        }
+
+        state = states.State.sanitize(state);
 
-      // Initialize the value of this state.
-      self.values[selector][state.pristine] = undefined;
+        // Initialize the value of this state.
+        this.values[selector][state.name] = null;
 
-      // Monitor state changes of the specified state for this dependee.
-      $(selector).bind('state:' + state, function (e) {
-        var complies = self.compare(value, e.value);
-        self.update(selector, state, complies);
-      });
-
-      // Make sure the event we just bound ourselves to is actually fired.
-      new states.Trigger({ selector: selector, state: state });
-    });
+        // Monitor state changes of the specified state for this dependee.
+        $(selector).bind('state:' + state, $.proxy(function (e) {
+          this.update(selector, state, e.value);
+        }, this));
+
+        // Make sure the event we just bound ourselves to is actually fired.
+        new states.Trigger({ selector: selector, state: state });
+      }
+    }
   },
 
   /**
@@ -111,12 +121,16 @@
    *
    * @param reference
    *   The value used for reference.
-   * @param value
-   *   The value to compare with the reference value.
+   * @param selector
+   *   CSS selector describing the dependee.
+   * @param state
+   *   A State object describing the dependee's updated state.
+   *
    * @return
-   *   true, undefined or false.
+   *   true or false.
    */
-  compare: function (reference, value) {
+  compare: function (reference, selector, state) {
+    var value = this.values[selector][state.name];
     if (reference.constructor.name in states.Dependent.comparisons) {
       // Use a custom compare function for certain reference value types.
       return states.Dependent.comparisons[reference.constructor.name](reference, value);
@@ -139,8 +153,8 @@
    */
   update: function (selector, state, value) {
     // Only act when the 'new' value is actually new.
-    if (value !== this.values[selector][state.pristine]) {
-      this.values[selector][state.pristine] = value;
+    if (value !== this.values[selector][state.name]) {
+      this.values[selector][state.name] = value;
       this.reevaluate();
     }
   },
@@ -149,16 +163,8 @@
    * Triggers change events in case a state changed.
    */
   reevaluate: function () {
-    var value = undefined;
-
-    // Merge all individual values to find out whether this dependee complies.
-    for (var selector in this.values) {
-      for (var state in this.values[selector]) {
-        state = states.State.sanitize(state);
-        var complies = this.values[selector][state.pristine];
-        value = ternary(value, invert(complies, state.invert));
-      }
-    }
+    // Check whether any constraint for this dependent state is satisifed.
+    var value = this.verifyConstraints(this.constraints);
 
     // Only invoke a state change event when the value actually changed.
     if (value !== this.oldValue) {
@@ -173,6 +179,124 @@
       // infinite loops.
       this.element.trigger({ type: 'state:' + this.state, value: value, trigger: true });
     }
+  },
+
+  /**
+   * Evaluates child constraints to determine if a constraint is satisfied.
+   *
+   * @param constraints
+   *   A constraint object or an array of constraints.
+   * @param selector
+   *   The selector for these constraints. If undefined, there isn't yet a
+   *   selector that these constraints apply to. In that case, the keys of the
+   *   object are interpreted as the selector if encountered.
+   *
+   * @return
+   *   true or false, depending on whether these constraints are satisfied.
+   */
+  verifyConstraints: function(constraints, selector) {
+    var result;
+    if ($.isArray(constraints)) {
+      // This constraint is an array (OR or XOR).
+      var hasXor = $.inArray('xor', constraints) === -1;
+      for (var i = 0, len = constraints.length; i < len; i++) {
+        if (constraints[i] != 'xor') {
+          var constraint = this.checkConstraints(constraints[i], selector, i);
+          // Return if this is OR and we have a satisfied constraint or if this
+          // is XOR and we have a second satisfied constraint.
+          if (constraint && (hasXor || result)) {
+            return hasXor;
+          }
+          result = result || constraint;
+        }
+      }
+    }
+    // Make sure we don't try to iterate over things other than objects. This
+    // shouldn't normally occur, but in case the condition definition is bogus,
+    // we don't want to end up with an infinite loop.
+    else if ($.isPlainObject(constraints)) {
+      // This constraint is an object (AND).
+      for (var n in constraints) {
+        if (constraints.hasOwnProperty(n)) {
+          result = ternary(result, this.checkConstraints(constraints[n], selector, n));
+          // False and anything else will evaluate to false, so return when any
+          // false condition is found.
+          if (result === false) { return false; }
+        }
+      }
+    }
+    return result;
+  },
+
+  /**
+   * Checks whether the value matches the requirements for this constraint.
+   *
+   * @param value
+   *   Either the value of a state or an array/object of constraints. In the
+   *   latter case, resolving the constraint continues.
+   * @param selector
+   *   The selector for this constraint. If undefined, there isn't yet a
+   *   selector that this constraint applies to. In that case, the state key is
+   *   propagates to a selector and resolving continues.
+   * @param state
+   *   The state to check for this constraint. If undefined, resolving
+   *   continues.
+   *   If both selector and state aren't undefined and valid non-numeric
+   *   strings, a lookup for the actual value of that selector's state is
+   *   performed. This parameter is not a State object but a pristine state
+   *   string.
+   *
+   * @return
+   *   true or false, depending on whether this constraint is satisfied.
+   */
+  checkConstraints: function(value, selector, state) {
+    // Normalize the last parameter. If it's non-numeric, we treat it either as
+    // a selector (in case there isn't one yet) or as a trigger/state.
+    if (typeof state !== 'string' || (/[0-9]/).test(state[0])) {
+      state = null;
+    }
+    else if (typeof selector === 'undefined') {
+      // Propagate the state to the selector when there isn't one yet.
+      selector = state;
+      state = null;
+    }
+
+    if (state !== null) {
+      // constraints is the actual constraints of an element to check for.
+      state = states.State.sanitize(state);
+      return invert(this.compare(value, selector, state), state.invert);
+    }
+    else {
+      // Resolve this constraint as an AND/OR operator.
+      return this.verifyConstraints(value, selector);
+    }
+  },
+
+  /**
+   * Gathers information about all required triggers.
+   */
+  getDependees: function() {
+    var cache = {};
+    // Swivel the lookup function so that we can record all available selector-
+    // state combinations for initialization.
+    var _compare = this.compare;
+    this.compare = function(reference, selector, state) {
+      (cache[selector] || (cache[selector] = [])).push(state.name);
+      // Return nothing (=== undefined) so that the constraint loops are not
+      // broken.
+    };
+
+    // This call doesn't actually verify anything but uses the resolving
+    // mechanism to go through the constraints array, trying to look up each
+    // value. Since we swivelled the compare function, this comparison returns
+    // undefined and lookup continues until the very end. Instead of lookup up
+    // the value, we record that combination of selector and state so that we
+    // can initialize all triggers.
+    this.verifyConstraints(this.constraints);
+    // Restore the original function.
+    this.compare = _compare;
+
+    return cache;
   }
 };
 
@@ -192,7 +316,6 @@
 
 states.Trigger.prototype = {
   initialize: function () {
-    var self = this;
     var trigger = states.Trigger.states[this.state];
 
     if (typeof trigger == 'function') {
@@ -200,9 +323,11 @@
       trigger.call(window, this.element);
     }
     else {
-      $.each(trigger, function (event, valueFn) {
-        self.defaultTrigger(event, valueFn);
-      });
+      for (var event in trigger) {
+        if (trigger.hasOwnProperty(event)) {
+          this.defaultTrigger(event, trigger[event]);
+        }
+      }
     }
 
     // Mark this trigger as initialized for this element.
@@ -210,23 +335,22 @@
   },
 
   defaultTrigger: function (event, valueFn) {
-    var self = this;
     var oldValue = valueFn.call(this.element);
 
     // Attach the event callback.
-    this.element.bind(event, function (e) {
-      var value = valueFn.call(self.element, e);
+    this.element.bind(event, $.proxy(function (e) {
+      var value = valueFn.call(this.element, e);
       // Only trigger the event if the value has actually changed.
       if (oldValue !== value) {
-        self.element.trigger({ type: 'state:' + self.state, value: value, oldValue: oldValue });
+        this.element.trigger({ type: 'state:' + this.state, value: value, oldValue: oldValue });
         oldValue = value;
       }
-    });
+    }, this));
 
-    states.postponed.push(function () {
+    states.postponed.push($.proxy(function () {
       // Trigger the event once for initialization purposes.
-      self.element.trigger({ type: 'state:' + self.state, value: oldValue, oldValue: undefined });
-    });
+      this.element.trigger({ type: 'state:' + this.state, value: oldValue, oldValue: null });
+    }, this));
   }
 };
 
@@ -249,7 +373,7 @@
 
   checked: {
     'change': function () {
-      return this.attr('checked');
+      return this.is(':checked');
     }
   },
 
@@ -275,7 +399,7 @@
 
   collapsed: {
     'collapsed': function(e) {
-      return (e !== undefined && 'value' in e) ? e.value : this.is('.collapsed');
+      return (typeof e !== 'undefined' && 'value' in e) ? e.value : this.is('.collapsed');
     }
   }
 };
@@ -307,7 +431,7 @@
 };
 
 /**
- * Create a new State object by sanitizing the passed value.
+ * Creates a new State object by sanitizing the passed value.
  */
 states.State.sanitize = function (state) {
   if (state instanceof states.State) {
@@ -352,72 +476,73 @@
  * bubble up to these handlers. We use this system so that themes and modules
  * can override these state change handlers for particular parts of a page.
  */
-{
-  $(document).bind('state:disabled', function(e) {
-    // Only act when this change was triggered by a dependency and not by the
-    // element monitoring itself.
-    if (e.trigger) {
-      $(e.target)
-        .attr('disabled', e.value)
-        .filter('.form-element')
-          .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
-    }
-  });
-
-  $(document).bind('state:required', function(e) {
-    if (e.trigger) {
-      if (e.value) {
-        $(e.target).closest('.form-item, .form-wrapper').find('label').append('<span class="form-required">*</span>');
-      }
-      else {
-        $(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
+$(document).bind('state:disabled', function(e) {
+  // Only act when this change was triggered by a dependency and not by the
+  // element monitoring itself.
+  if (e.trigger) {
+    $(e.target)
+      .attr('disabled', e.value)
+        .closest('.form-item, .form-submit, .form-wrapper').toggleClass('form-disabled', e.value)
+        .find('select, input, textarea').attr('disabled', e.value);
+
+    // Note: WebKit nightlies don't reflect that change correctly.
+    // See https://bugs.webkit.org/show_bug.cgi?id=23789
+  }
+});
+
+$(document).bind('state:required', function(e) {
+  if (e.trigger) {
+    if (e.value) {
+      var $label = $(e.target).closest('.form-item, .form-wrapper').find('label');
+      // Avoids duplicate required markers on initialization.
+      if (!$label.find('.form-required').length) {
+        $label.append('<span class="form-required">*</span>');
       }
     }
-  });
-
-  $(document).bind('state:visible', function(e) {
-    if (e.trigger) {
-      $(e.target).closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'show' : 'hide']();
+    else {
+      $(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
     }
-  });
+  }
+});
 
-  $(document).bind('state:checked', function(e) {
-    if (e.trigger) {
-      $(e.target).attr('checked', e.value);
-    }
-  });
+$(document).bind('state:visible', function(e) {
+  if (e.trigger) {
+      $(e.target).closest('.form-item, .form-submit, .form-wrapper').toggle(e.value);
+  }
+});
 
-  $(document).bind('state:collapsed', function(e) {
-    if (e.trigger) {
-      if ($(e.target).is('.collapsed') !== e.value) {
-        $('> legend a', e.target).click();
-      }
+$(document).bind('state:checked', function(e) {
+  if (e.trigger) {
+    $(e.target).attr('checked', e.value);
+  }
+});
+
+$(document).bind('state:collapsed', function(e) {
+  if (e.trigger) {
+    if ($(e.target).is('.collapsed') !== e.value) {
+      $('> legend a', e.target).click();
     }
-  });
-}
+  }
+});
 
 /**
  * These are helper functions implementing addition "operators" and don't
  * implement any logic that is particular to states.
  */
-{
-  // Bitwise AND with a third undefined state.
-  function ternary (a, b) {
-    return a === undefined ? b : (b === undefined ? a : a && b);
-  };
-
-  // Inverts a (if it's not undefined) when invert is true.
-  function invert (a, invert) {
-    return (invert && a !== undefined) ? !a : a;
-  };
-
-  // Compares two values while ignoring undefined values.
-  function compare (a, b) {
-    return (a === b) ? (a === undefined ? a : true) : (a === undefined || b === undefined);
-  }
+
+// Bitwise AND with a third undefined state.
+function ternary (a, b) {
+  return typeof a === 'undefined' ? b : (typeof b === 'undefined' ? a : a && b);
+}
+
+// Inverts a (if it's not undefined) when invert is true.
+function invert (a, invert) {
+  return (invert && typeof a !== 'undefined') ? !a : a;
+}
+
+// Compares two values while ignoring undefined values.
+function compare (a, b) {
+  return (a === b) ? (typeof a === 'undefined' ? a : true) : (typeof a === 'undefined' || typeof b === 'undefined');
 }
 
 })(jQuery);
diff -Naur drupal-7.9/misc/tabledrag.js drupal-7.58/misc/tabledrag.js
--- drupal-7.9/misc/tabledrag.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/tabledrag.js	2018-03-27 21:28:19.000000000 +0200
@@ -106,8 +106,10 @@
 
   // Add mouse bindings to the document. The self variable is passed along
   // as event handlers do not have direct access to the tableDrag object.
-  $(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
-  $(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
+  $(document).bind('mousemove pointermove', function (event) { return self.dragRow(event, self); });
+  $(document).bind('mouseup pointerup', function (event) { return self.dropRow(event, self); });
+  $(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
+  $(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
 };
 
 /**
@@ -123,9 +125,9 @@
     // Find the first field in this group.
     for (var d in this.tableSettings[group]) {
       var field = $('.' + this.tableSettings[group][d].target + ':first', this.table);
-      if (field.size() && this.tableSettings[group][d].hidden) {
+      if (field.length && this.tableSettings[group][d].hidden) {
         var hidden = this.tableSettings[group][d].hidden;
-        var cell = field.parents('td:first');
+        var cell = field.closest('td');
         break;
       }
     }
@@ -201,6 +203,8 @@
     // The cookie expires in one year.
     expires: 365
   });
+  // Trigger an event to allow other scripts to react to this display change.
+  $('table.tabledrag-processed').trigger('columnschange', 'hide');
 };
 
 /**
@@ -224,6 +228,8 @@
     // The cookie expires in one year.
     expires: 365
   });
+  // Trigger an event to allow other scripts to react to this display change.
+  $('table.tabledrag-processed').trigger('columnschange', 'show');
 };
 
 /**
@@ -256,7 +262,7 @@
   if ($('td:first .indentation:last', item).length) {
     $('td:first .indentation:last', item).after(handle);
     // Update the total width of indentation in this entire table.
-    self.indentCount = Math.max($('.indentation', item).size(), self.indentCount);
+    self.indentCount = Math.max($('.indentation', item).length, self.indentCount);
   }
   else {
     $('td:first', item).prepend(handle);
@@ -270,7 +276,10 @@
   });
 
   // Add the mousedown action for the handle.
-  handle.mousedown(function (event) {
+  handle.bind('mousedown touchstart pointerdown', function (event) {
+    if (event.originalEvent.type == "touchstart") {
+      event = event.originalEvent.touches[0];
+    }
     // Create a new dragObject recording the event information.
     self.dragObject = {};
     self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
@@ -362,7 +371,7 @@
           if ($(item).is('.tabledrag-root')) {
             // Swap with the previous top-level row.
             var groupHeight = 0;
-            while (previousRow && $('.indentation', previousRow).size()) {
+            while (previousRow && $('.indentation', previousRow).length) {
               previousRow = $(previousRow).prev('tr').get(0);
               groupHeight += $(previousRow).is(':hidden') ? 0 : previousRow.offsetHeight;
             }
@@ -402,12 +411,12 @@
           if ($(item).is('.tabledrag-root')) {
             // Swap with the next group (necessarily a top-level one).
             var groupHeight = 0;
-            nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
+            var nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
             if (nextGroup) {
               $(nextGroup.group).each(function () {
                 groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
               });
-              nextGroupRow = $(nextGroup.group).filter(':last').get(0);
+              var nextGroupRow = $(nextGroup.group).filter(':last').get(0);
               self.rowObject.swap('after', nextGroupRow);
               // No need to check for indentation, 0 is the only valid one.
               window.scrollBy(0, parseInt(groupHeight, 10));
@@ -496,7 +505,7 @@
     if (self.indentEnabled) {
       var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x;
       // Set the number of indentations the mouse has been moved left or right.
-      var indentDiff = Math.round(xDiff / self.indentAmount * self.rtl);
+      var indentDiff = Math.round(xDiff / self.indentAmount);
       // Indent the row with our estimated diff, which may be further
       // restricted according to the rows around this row.
       var indentChange = self.rowObject.indent(indentDiff);
@@ -571,12 +580,20 @@
  * Get the mouse coordinates from the event (allowing for browser differences).
  */
 Drupal.tableDrag.prototype.mouseCoords = function (event) {
+  // Complete support for pointer events was only introduced to jQuery in
+  // version 1.11.1; between versions 1.7 and 1.11.0 pointer events have the
+  // clientX and clientY properties undefined. In those cases, the properties
+  // must be retrieved from the event.originalEvent object instead.
+  var clientX = event.clientX || event.originalEvent.clientX;
+  var clientY = event.clientY || event.originalEvent.clientY;
+
   if (event.pageX || event.pageY) {
     return { x: event.pageX, y: event.pageY };
   }
+
   return {
-    x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
-    y: event.clientY + document.body.scrollTop  - document.body.clientTop
+    x: clientX + document.body.scrollLeft - document.body.clientLeft,
+    y: clientY + document.body.scrollTop  - document.body.clientTop
   };
 };
 
@@ -688,7 +705,7 @@
     var sourceRow = changedRow;
     if ($(previousRow).is('.draggable') && $('.' + group, previousRow).length) {
       if (this.indentEnabled) {
-        if ($('.indentations', previousRow).size() == $('.indentations', changedRow)) {
+        if ($('.indentations', previousRow).length == $('.indentations', changedRow)) {
           sourceRow = previousRow;
         }
       }
@@ -698,7 +715,7 @@
     }
     else if ($(nextRow).is('.draggable') && $('.' + group, nextRow).length) {
       if (this.indentEnabled) {
-        if ($('.indentations', nextRow).size() == $('.indentations', changedRow)) {
+        if ($('.indentations', nextRow).length == $('.indentations', changedRow)) {
           sourceRow = nextRow;
         }
       }
@@ -754,7 +771,7 @@
     switch (rowSettings.action) {
       case 'depth':
         // Get the depth of the target row.
-        targetElement.value = $('.indentation', $(sourceElement).parents('tr:first')).size();
+        targetElement.value = $('.indentation', $(sourceElement).closest('tr')).length;
         break;
       case 'match':
         // Update the value.
@@ -884,20 +901,20 @@
   this.element = tableRow;
   this.method = method;
   this.group = [tableRow];
-  this.groupDepth = $('.indentation', tableRow).size();
+  this.groupDepth = $('.indentation', tableRow).length;
   this.changed = false;
-  this.table = $(tableRow).parents('table:first').get(0);
+  this.table = $(tableRow).closest('table').get(0);
   this.indentEnabled = indentEnabled;
   this.maxDepth = maxDepth;
   this.direction = ''; // Direction the row is being moved.
 
   if (this.indentEnabled) {
-    this.indents = $('.indentation', tableRow).size();
+    this.indents = $('.indentation', tableRow).length;
     this.children = this.findChildren(addClasses);
     this.group = $.merge(this.group, this.children);
     // Find the depth of this entire group.
     for (var n = 0; n < this.group.length; n++) {
-      this.groupDepth = Math.max($('.indentation', this.group[n]).size(), this.groupDepth);
+      this.groupDepth = Math.max($('.indentation', this.group[n]).length, this.groupDepth);
     }
   }
 };
@@ -1009,7 +1026,7 @@
 
   // Minimum indentation:
   // Do not orphan the next row.
-  minIndent = nextRow ? $('.indentation', nextRow).size() : 0;
+  minIndent = nextRow ? $('.indentation', nextRow).length : 0;
 
   // Maximum indentation:
   if (!prevRow || $(prevRow).is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) {
@@ -1021,7 +1038,7 @@
   }
   else {
     // Do not go deeper than as a child of the previous row.
-    maxIndent = $('.indentation', prevRow).size() + ($(prevRow).is('.tabledrag-leaf') ? 0 : 1);
+    maxIndent = $('.indentation', prevRow).length + ($(prevRow).is('.tabledrag-leaf') ? 0 : 1);
     // Limit by the maximum allowed depth for the table.
     if (this.maxDepth) {
       maxIndent = Math.min(maxIndent, this.maxDepth - (this.groupDepth - this.indents));
@@ -1042,8 +1059,8 @@
 Drupal.tableDrag.prototype.row.prototype.indent = function (indentDiff) {
   // Determine the valid indentations interval if not available yet.
   if (!this.interval) {
-    prevRow = $(this.element).prev('tr').get(0);
-    nextRow = $(this.group).filter(':last').next('tr').get(0);
+    var prevRow = $(this.element).prev('tr').get(0);
+    var nextRow = $(this.group).filter(':last').next('tr').get(0);
     this.interval = this.validIndentInterval(prevRow, nextRow);
   }
 
diff -Naur drupal-7.9/misc/tableheader.js drupal-7.58/misc/tableheader.js
--- drupal-7.9/misc/tableheader.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/tableheader.js	2018-03-27 21:28:19.000000000 +0200
@@ -27,6 +27,14 @@
   this.originalTable = $(table);
   this.originalHeader = $(table).children('thead');
   this.originalHeaderCells = this.originalHeader.find('> tr > th');
+  this.displayWeight = null;
+
+  // React to columns change to avoid making checks in the scroll callback.
+  this.originalTable.bind('columnschange', function (e, display) {
+    // This will force header size to be calculated on scroll.
+    self.widthCalculated = (self.displayWeight !== null && self.displayWeight === display);
+    self.displayWeight = display;
+  });
 
   // Clone the table header so it inherits original jQuery properties. Hide
   // the table to avoid a flash of the header clone upon page load.
@@ -95,16 +103,30 @@
   // visible or when forced.
   if (this.stickyVisible && (calculateWidth || !this.widthCalculated)) {
     this.widthCalculated = true;
+    var $that = null;
+    var $stickyCell = null;
+    var display = null;
+    var cellWidth = null;
     // Resize header and its cell widths.
-    this.stickyHeaderCells.each(function (index) {
-      var cellWidth = self.originalHeaderCells.eq(index).css('width');
-      // Exception for IE7.
-      if (cellWidth == 'auto') {
-        cellWidth = self.originalHeaderCells.get(index).clientWidth + 'px';
+    // Only apply width to visible table cells. This prevents the header from
+    // displaying incorrectly when the sticky header is no longer visible.
+    for (var i = 0, il = this.originalHeaderCells.length; i < il; i += 1) {
+      $that = $(this.originalHeaderCells[i]);
+      $stickyCell = this.stickyHeaderCells.eq($that.index());
+      display = $that.css('display');
+      if (display !== 'none') {
+        cellWidth = $that.css('width');
+        // Exception for IE7.
+        if (cellWidth === 'auto') {
+          cellWidth = $that[0].clientWidth + 'px';
+        }
+        $stickyCell.css({'width': cellWidth, 'display': display});
+      }
+      else {
+        $stickyCell.css('display', 'none');
       }
-      $(this).css('width', cellWidth);
-    });
-    this.stickyTable.css('width', this.originalTable.css('width'));
+    }
+    this.stickyTable.css('width', this.originalTable.outerWidth());
   }
 };
 
diff -Naur drupal-7.9/misc/tableselect.js drupal-7.58/misc/tableselect.js
--- drupal-7.9/misc/tableselect.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/tableselect.js	2018-03-27 21:28:19.000000000 +0200
@@ -2,13 +2,14 @@
 
 Drupal.behaviors.tableSelect = {
   attach: function (context, settings) {
-    $('table:has(th.select-all)', context).once('table-select', Drupal.tableSelect);
+    // Select the inner-most table in case of nested tables.
+    $('th.select-all', context).closest('table').once('table-select', Drupal.tableSelect);
   }
 };
 
 Drupal.tableSelect = function () {
   // Do not add a "Select all" checkbox if there are no rows with checkboxes in the table
-  if ($('td input:checkbox', this).size() == 0) {
+  if ($('td input:checkbox', this).length == 0) {
     return;
   }
 
@@ -16,7 +17,8 @@
   var table = this, checkboxes, lastChecked;
   var strings = { 'selectAll': Drupal.t('Select all rows in this table'), 'selectNone': Drupal.t('Deselect all rows in this table') };
   var updateSelectAll = function (state) {
-    $('th.select-all input:checkbox', table).each(function () {
+    // Update table's select-all checkbox (and sticky header's if available).
+    $(table).prev('table.sticky-header').andSelf().find('th.select-all input:checkbox').each(function() {
       $(this).attr('title', state ? strings.selectNone : strings.selectAll);
       this.checked = state;
     });
@@ -29,7 +31,7 @@
       checkboxes.each(function () {
         this.checked = event.target.checked;
         // Either add or remove the selected class based on the state of the check all checkbox.
-        $(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
+        $(this).closest('tr').toggleClass('selected', this.checked);
       });
       // Update the title and the state of the check all box.
       updateSelectAll(event.target.checked);
@@ -39,14 +41,14 @@
   // For each of the checkboxes within the table that are not disabled.
   checkboxes = $('td input:checkbox:enabled', table).click(function (e) {
     // Either add or remove the selected class based on the state of the check all checkbox.
-    $(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
+    $(this).closest('tr').toggleClass('selected', this.checked);
 
     // If this is a shift click, we need to highlight everything in the range.
     // Also make sure that we are actually checking checkboxes over a range and
     // that a checkbox has been checked or unchecked before.
     if (e.shiftKey && lastChecked && lastChecked != e.target) {
       // We use the checkbox's parent TR to do our range searching.
-      Drupal.tableSelectRange($(e.target).parents('tr')[0], $(lastChecked).parents('tr')[0], e.target.checked);
+      Drupal.tableSelectRange($(e.target).closest('tr')[0], $(lastChecked).closest('tr')[0], e.target.checked);
     }
 
     // If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
@@ -55,10 +57,14 @@
     // Keep track of the last checked checkbox.
     lastChecked = e.target;
   });
+
+  // If all checkboxes are checked on page load, make sure the select-all one
+  // is checked too, otherwise keep unchecked.
+  updateSelectAll((checkboxes.length == $(checkboxes).filter(':checked').length));
 };
 
 Drupal.tableSelectRange = function (from, to, state) {
-  // We determine the looping mode based on the the order of from and to.
+  // We determine the looping mode based on the order of from and to.
   var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
 
   // Traverse through the sibling nodes.
@@ -69,7 +75,7 @@
     }
 
     // Either add or remove the selected class based on the state of the target checkbox.
-    $(i)[ state ? 'addClass' : 'removeClass' ]('selected');
+    $(i).toggleClass('selected', state);
     $('input:checkbox', i).each(function () {
       this.checked = state;
     });
diff -Naur drupal-7.9/misc/throbber-active.gif drupal-7.58/misc/throbber-active.gif
--- drupal-7.9/misc/throbber-active.gif	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/misc/throbber-active.gif	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,6 @@
+GIF89a   {{ƵZ5ʋkFs                                    !NETSCAPE2.0   !  ,       _$N4ɨN		G.	F9FC"dH٤qHë rdN!Z%Aᒔ84"BUU{A.<+0u+')+! !  ,       G$NHL0>-".*GT*	#Li"JhL5 d,@2uYmG+i !  ,       ?$NϘct:$!L(	@"R`(Ղ5ɭb'FӘ(`ZV^( !  ,       H$N蔤b@HĨ$!krHpbhdDXrwNM@``9I,
+ !  ,       I$NHL0>-ʸl !,z'`HjƤ6E" !S		@2yzyS`prZ  !  ,       @$NϘctдú#2EH"6D!JJ0bD ]kx*`:Q:y !  ,       E$N蔤b@Xw"C2"LN	P1"PD2.CNQ !  ,       F$NL0>-ʸl rRk4 '"E!L"bYE1)A+ !  ,       A$NϘctдú#2EH"TP;Iu@`ul01(<
+ !  ,       I$N蔤b@HAATPSd)
+NNch!bK&Sm0zD  !  ,       H$NHL0>-ʸc̊Aט@NiՊDn,]9aUo
+ !  ,       A$NϘct8Q,#.Q# H!L #J"QP$ +cV܉RDVw
+ ;
\ No newline at end of file
diff -Naur drupal-7.9/misc/throbber-inactive.png drupal-7.58/misc/throbber-inactive.png
--- drupal-7.9/misc/throbber-inactive.png	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/misc/throbber-inactive.png	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,4 @@
+PNG
+
+   IHDR         v4A   tEXtSoftware Adobe ImageReadyqe<   IDATxڜR0t*D"#' H$M<&wQ{,u,(
+ʲLCiJ"u҄ v]j.. m!?l栀Z>G8Ut>Yc{GvrdW	:B&w<wA8cLFrI6Pa.ɞ}O7g` 	LrE    IENDB`
\ No newline at end of file
diff -Naur drupal-7.9/misc/vertical-tabs.css drupal-7.58/misc/vertical-tabs.css
--- drupal-7.9/misc/vertical-tabs.css	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/vertical-tabs.css	2018-03-27 21:28:19.000000000 +0200
@@ -19,9 +19,12 @@
   padding: 0 1em;
   border: 0;
 }
-.vertical-tabs legend {
+fieldset.vertical-tabs-pane legend {
   display: none;
 }
+fieldset.vertical-tabs-pane fieldset legend {
+  display: block;
+}
 
 /* Layout of each tab */
 .vertical-tabs ul.vertical-tabs-list li {
diff -Naur drupal-7.9/misc/vertical-tabs.js drupal-7.58/misc/vertical-tabs.js
--- drupal-7.9/misc/vertical-tabs.js	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/misc/vertical-tabs.js	2018-03-27 21:28:19.000000000 +0200
@@ -50,8 +50,8 @@
       if (!tab_focus) {
         // If the current URL has a fragment and one of the tabs contains an
         // element that matches the URL fragment, activate that tab.
-        if (window.location.hash && $(window.location.hash, this).length) {
-          tab_focus = $(window.location.hash, this).closest('.vertical-tabs-pane');
+        if (window.location.hash && $(this).find(window.location.hash).length) {
+          tab_focus = $(this).find(window.location.hash).closest('.vertical-tabs-pane');
         }
         else {
           tab_focus = $('> .vertical-tabs-pane:first', this);
@@ -92,16 +92,6 @@
     }
   });
 
-  // Pressing the Enter key lets you leave the tab again.
-  this.fieldset.keydown(function(event) {
-    // Enter key should not trigger inside <textarea> to allow for multi-line entries.
-    if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
-      // Set focus on the selected tab button again.
-      $(".vertical-tab-button.selected a").focus();
-      return false;
-    }
-  });
-
   this.fieldset
     .bind('summaryUpdated', function () {
       self.updateSummary();
@@ -144,6 +134,8 @@
   tabShow: function () {
     // Display the tab.
     this.item.show();
+    // Show the vertical tabs.
+    this.item.closest('.vertical-tabs').show();
     // Update .first marker for items. We need recurse from parent to retain the
     // actual DOM element order as jQuery implements sortOrder, but not as public
     // method.
@@ -174,6 +166,10 @@
     if ($firstTab.length) {
       $firstTab.data('verticalTab').focus();
     }
+    // Hide the vertical tabs (if no tabs remain).
+    else {
+      this.item.closest('.vertical-tabs').hide();
+    }
     return this;
   }
 };
diff -Naur drupal-7.9/modules/aggregator/aggregator-feed-source.tpl.php drupal-7.58/modules/aggregator/aggregator-feed-source.tpl.php
--- drupal-7.9/modules/aggregator/aggregator-feed-source.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-feed-source.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -17,6 +17,8 @@
  *
  * @see template_preprocess()
  * @see template_preprocess_aggregator_feed_source()
+ *
+ * @ingroup themeable
  */
 ?>
 <div class="feed-source">
diff -Naur drupal-7.9/modules/aggregator/aggregator-item.tpl.php drupal-7.58/modules/aggregator/aggregator-item.tpl.php
--- drupal-7.9/modules/aggregator/aggregator-item.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-item.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -16,6 +16,8 @@
  *
  * @see template_preprocess()
  * @see template_preprocess_aggregator_item()
+ *
+ * @ingroup themeable
  */
 ?>
 <div class="feed-item">
diff -Naur drupal-7.9/modules/aggregator/aggregator-rtl.css drupal-7.58/modules/aggregator/aggregator-rtl.css
--- drupal-7.9/modules/aggregator/aggregator-rtl.css	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-rtl.css	2018-03-27 21:28:19.000000000 +0200
@@ -1,3 +1,6 @@
+/**
+ * Right-to-Left styles for theme in the Aggregator module.
+ */
 
 #aggregator .feed-source .feed-icon {
   float: left;
diff -Naur drupal-7.9/modules/aggregator/aggregator-summary-item.tpl.php drupal-7.58/modules/aggregator/aggregator-summary-item.tpl.php
--- drupal-7.9/modules/aggregator/aggregator-summary-item.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-summary-item.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -13,6 +13,8 @@
  *
  * @see template_preprocess()
  * @see template_preprocess_aggregator_summary_item()
+ *
+ * @ingroup themeable
  */
 ?>
 <a href="<?php print $feed_url; ?>"><?php print $feed_title; ?></a>
diff -Naur drupal-7.9/modules/aggregator/aggregator-summary-items.tpl.php drupal-7.58/modules/aggregator/aggregator-summary-items.tpl.php
--- drupal-7.9/modules/aggregator/aggregator-summary-items.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-summary-items.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -14,6 +14,8 @@
  *
  * @see template_preprocess()
  * @see template_preprocess_aggregator_summary_items()
+ *
+ * @ingroup themeable
  */
 ?>
 <h3><?php print $title; ?></h3>
diff -Naur drupal-7.9/modules/aggregator/aggregator-wrapper.tpl.php drupal-7.58/modules/aggregator/aggregator-wrapper.tpl.php
--- drupal-7.9/modules/aggregator/aggregator-wrapper.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator-wrapper.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -10,6 +10,8 @@
  *
  * @see template_preprocess()
  * @see template_preprocess_aggregator_wrapper()
+ *
+ * @ingroup themeable
  */
 ?>
 <div id="aggregator">
diff -Naur drupal-7.9/modules/aggregator/aggregator.admin.inc drupal-7.58/modules/aggregator/aggregator.admin.inc
--- drupal-7.9/modules/aggregator/aggregator.admin.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.admin.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,11 +2,11 @@
 
 /**
  * @file
- * Admin page callbacks for the aggregator module.
+ * Administration page callbacks for the Aggregator module.
  */
 
 /**
- * Menu callback; displays the aggregator administration page.
+ * Page callback: Displays the Aggregator module administration page.
  */
 function aggregator_admin_overview() {
   return aggregator_view();
@@ -16,7 +16,7 @@
  * Displays the aggregator administration page.
  *
  * @return
- *   The page HTML.
+ *   A HTML-formatted string with administration page content.
  */
 function aggregator_view() {
   $result = db_query('SELECT f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block ORDER BY f.title');
@@ -33,7 +33,7 @@
       ($feed->checked && $feed->refresh ? t('%time left', array('%time' => format_interval($feed->checked + $feed->refresh - REQUEST_TIME))) : t('never')),
       l(t('edit'), "admin/config/services/aggregator/edit/feed/$feed->fid"),
       l(t('remove items'), "admin/config/services/aggregator/remove/$feed->fid"),
-      l(t('update items'), "admin/config/services/aggregator/update/$feed->fid"),
+      l(t('update items'), "admin/config/services/aggregator/update/$feed->fid", array('query' => array('token' => drupal_get_token("aggregator/update/$feed->fid")))),
     );
   }
   $output .= theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No feeds available. <a href="@link">Add feed</a>.', array('@link' => url('admin/config/services/aggregator/add/feed')))));
@@ -53,7 +53,11 @@
 }
 
 /**
- * Form builder; Generate a form to add/edit feed sources.
+ * Form constructor for adding and editing feed sources.
+ *
+ * @param $feed
+ *   (optional) If editing a feed, the feed to edit as a PHP stdClass value; if
+ *   adding a new feed, NULL. Defaults to NULL.
  *
  * @ingroup forms
  * @see aggregator_form_feed_validate()
@@ -73,7 +77,7 @@
   $form['url'] = array('#type' => 'textfield',
     '#title' => t('URL'),
     '#default_value' => isset($feed->url) ? $feed->url : '',
-    '#maxlength' => 255,
+    '#maxlength' => NULL,
     '#description' => t('The fully-qualified URL of the feed.'),
     '#required' => TRUE,
   );
@@ -129,7 +133,9 @@
 }
 
 /**
- * Validate aggregator_form_feed() form submissions.
+ * Form validation handler for aggregator_form_feed().
+ *
+ * @see aggregator_form_feed_submit()
  */
 function aggregator_form_feed_validate($form, &$form_state) {
   if ($form_state['values']['op'] == t('Save')) {
@@ -156,7 +162,9 @@
 }
 
 /**
- * Process aggregator_form_feed() form submissions.
+ * Form submission handler for aggregator_form_feed().
+ *
+ * @see aggregator_form_feed_validate()
  *
  * @todo Add delete confirmation dialog.
  */
@@ -198,6 +206,14 @@
   }
 }
 
+/**
+ * Deletes a feed.
+ *
+ * @param $feed
+ *   An associative array describing the feed to be cleared.
+ *
+ * @see aggregator_admin_remove_feed_submit()
+ */
 function aggregator_admin_remove_feed($form, $form_state, $feed) {
   return confirm_form(
     array(
@@ -215,10 +231,9 @@
 }
 
 /**
- * Remove all items from a feed and redirect to the overview page.
+ * Form submission handler for aggregator_admin_remove_feed().
  *
- * @param $feed
- *   An associative array describing the feed to be cleared.
+ * Removes all items from a feed and redirects to the overview page.
  */
 function aggregator_admin_remove_feed_submit($form, &$form_state) {
   aggregator_remove($form_state['values']['feed']);
@@ -226,7 +241,7 @@
 }
 
 /**
- * Form builder; Generate a form to import feeds from OPML.
+ * Form constructor for importing feeds from OPML.
  *
  * @ingroup forms
  * @see aggregator_form_opml_validate()
@@ -280,7 +295,9 @@
 }
 
 /**
- * Validate aggregator_form_opml form submissions.
+ * Form validation handler for aggregator_form_opml().
+ *
+ * @see aggregator_form_opml_submit()
  */
 function aggregator_form_opml_validate($form, &$form_state) {
   // If both fields are empty or filled, cancel.
@@ -295,7 +312,9 @@
 }
 
 /**
- * Process aggregator_form_opml form submissions.
+ * Form submission handler for aggregator_form_opml().
+ *
+ * @see aggregator_form_opml_validate()
  */
 function aggregator_form_opml_submit($form, &$form_state) {
   $data = '';
@@ -347,7 +366,7 @@
 }
 
 /**
- * Parse an OPML file.
+ * Parses an OPML file.
  *
  * Feeds are recognized as <outline> elements with the attributes "text" and
  * "xmlurl" set.
@@ -357,9 +376,9 @@
  *
  * @return
  *   An array of feeds, each an associative array with a "title" and a "url"
- *   element, or NULL if the OPML document failed to be parsed. An empty
- *   array will be returned if the document is valid but contains no feeds, as
- *   some OPML documents do.
+ *   element, or NULL if the OPML document failed to be parsed. An empty array
+ *   will be returned if the document is valid but contains no feeds, as some
+ *   OPML documents do.
  */
 function _aggregator_parse_opml($opml) {
   $feeds = array();
@@ -380,19 +399,23 @@
 }
 
 /**
- * Menu callback; refreshes a feed, then redirects to the overview page.
+ * Page callback: Refreshes a feed, then redirects to the overview page.
  *
  * @param $feed
  *   An object describing the feed to be refreshed.
  */
 function aggregator_admin_refresh_feed($feed) {
+  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'aggregator/update/' . $feed->fid)) {
+    return MENU_ACCESS_DENIED;
+  }
   aggregator_refresh($feed);
   drupal_goto('admin/config/services/aggregator');
 }
 
 /**
- * Form builder; Configure the aggregator system.
+ * Form constructor for the aggregator system settings.
  *
+ * @see aggregator_admin_form_submit()
  * @ingroup forms
  */
 function aggregator_admin_form($form, $form_state) {
@@ -500,6 +523,9 @@
   return $form;
 }
 
+/**
+ * Form submission handler for aggregator_admin_form().
+ */
 function aggregator_admin_form_submit($form, &$form_state) {
   if (isset($form_state['values']['aggregator_processors'])) {
     $form_state['values']['aggregator_processors'] = array_filter($form_state['values']['aggregator_processors']);
@@ -508,7 +534,13 @@
 }
 
 /**
- * Form builder; Generate a form to add/edit/delete aggregator categories.
+ * Form constructor to add/edit/delete aggregator categories.
+ *
+ * @param $edit
+ *   An associative array containing:
+ *   - title: A string to use for the category title.
+ *   - description: A string to use for the category description.
+ *   - cid: The category ID.
  *
  * @ingroup forms
  * @see aggregator_form_category_validate()
@@ -536,7 +568,9 @@
 }
 
 /**
- * Validate aggregator_form_feed form submissions.
+ * Form validation handler for aggregator_form_category().
+ *
+ * @see aggregator_form_category_submit()
  */
 function aggregator_form_category_validate($form, &$form_state) {
   if ($form_state['values']['op'] == t('Save')) {
@@ -554,7 +588,9 @@
 }
 
 /**
- * Process aggregator_form_category form submissions.
+ * Form submission handler for aggregator_form_category().
+ *
+ * @see aggregator_form_category_validate()
  *
  * @todo Add delete confirmation dialog.
  */
diff -Naur drupal-7.9/modules/aggregator/aggregator.api.php drupal-7.58/modules/aggregator/aggregator.api.php
--- drupal-7.9/modules/aggregator/aggregator.api.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.api.php	2018-03-27 21:28:19.000000000 +0200
@@ -11,21 +11,21 @@
  */
 
 /**
- * Implement this hook to create an alternative fetcher for aggregator module.
+ * Create an alternative fetcher for aggregator.module.
  *
- * A fetcher downloads feed data to a Drupal site. The fetcher is called
- * at the first of the three aggregation stages: data is downloaded by the
- * active fetcher, it is converted to a common format by the active parser and
- * finally, it is passed to all active processors which manipulate or store the
- * data.
+ * A fetcher downloads feed data to a Drupal site. The fetcher is called at the
+ * first of the three aggregation stages: first, data is downloaded by the
+ * active fetcher; second, it is converted to a common format by the active
+ * parser; and finally, it is passed to all active processors, which manipulate
+ * or store the data.
  *
- * Modules that define this hook can be set as active fetcher on
- * admin/config/services/aggregator. Only one fetcher can be active at a time.
+ * Modules that define this hook can be set as the active fetcher within the
+ * configuration page. Only one fetcher can be active at a time.
  *
  * @param $feed
- *   The $feed object that describes the resource to be downloaded.
- *   $feed->url contains the link to the feed. Download the data at the URL
- *   and expose it to other modules by attaching it to $feed->source_string.
+ *   A feed object representing the resource to be downloaded. $feed->url
+ *   contains the link to the feed. Download the data at the URL and expose it
+ *   to other modules by attaching it to $feed->source_string.
  *
  * @return
  *   TRUE if fetching was successful, FALSE otherwise.
@@ -41,13 +41,11 @@
 }
 
 /**
- * Implement this hook to expose the title and a short description of your
- * fetcher.
+ * Specify the title and short description of your fetcher.
  *
- * The title and the description provided are shown on
- * admin/config/services/aggregator among other places. Use as title the human
- * readable name of the fetcher and as description a brief (40 to 80 characters)
- * explanation of the fetcher's functionality.
+ * The title and the description provided are shown within the configuration
+ * page. Use as title the human readable name of the fetcher and as description
+ * a brief (40 to 80 characters) explanation of the fetcher's functionality.
  *
  * This hook is only called if your module implements hook_aggregator_fetch().
  * If this hook is not implemented aggregator will use your module's file name
@@ -68,41 +66,37 @@
 }
 
 /**
- * Implement this hook to create an alternative parser for aggregator module.
+ * Create an alternative parser for aggregator module.
  *
  * A parser converts feed item data to a common format. The parser is called
- * at the second of the three aggregation stages: data is downloaded by the
- * active fetcher, it is converted to a common format by the active parser and
- * finally, it is passed to all active processors which manipulate or store the
- * data.
+ * at the second of the three aggregation stages: first, data is downloaded
+ * by the active fetcher; second, it is converted to a common format by the
+ * active parser; and finally, it is passed to all active processors which
+ * manipulate or store the data.
  *
- * Modules that define this hook can be set as active parser on
- * admin/config/services/aggregator. Only one parser can be active at a time.
+ * Modules that define this hook can be set as the active parser within the
+ * configuration page. Only one parser can be active at a time.
  *
  * @param $feed
- *   The $feed object that describes the resource to be parsed.
- *   $feed->source_string contains the raw feed data as a string. Parse data
- *   from $feed->source_string and expose it to other modules as an array of
- *   data items on $feed->items.
- *
- *   Feed format:
- *   - $feed->description (string) - description of the feed
- *   - $feed->image (string) - image for the feed
- *   - $feed->etag (string) - value of feed's entity tag header field
- *   - $feed->modified (UNIX timestamp) - value of feed's last modified header
- *     field
- *   - $feed->items (Array) - array of feed items.
- *
- *   By convention, the common format for a single feed item is:
- *   $item[key-name] = value;
- *
- *   Recognized keys:
- *   TITLE (string) - the title of a feed item
- *   DESCRIPTION (string) - the description (body text) of a feed item
- *   TIMESTAMP (UNIX timestamp) - the feed item's published time as UNIX timestamp
- *   AUTHOR (string) - the feed item's author
- *   GUID (string) - RSS/Atom global unique identifier
- *   LINK (string) - the feed item's URL
+ *   An object describing the resource to be parsed. $feed->source_string
+ *   contains the raw feed data. The hook implementation should parse this data
+ *   and add the following properties to the $feed object:
+ *   - description: The human-readable description of the feed.
+ *   - link: A full URL that directly relates to the feed.
+ *   - image: An image URL used to display an image of the feed.
+ *   - etag: An entity tag from the HTTP header used for cache validation to
+ *     determine if the content has been changed.
+ *   - modified: The UNIX timestamp when the feed was last modified.
+ *   - items: An array of feed items. The common format for a single feed item
+ *     is an associative array containing:
+ *     - title: The human-readable title of the feed item.
+ *     - description: The full body text of the item or a summary.
+ *     - timestamp: The UNIX timestamp when the feed item was last published.
+ *     - author: The author of the feed item.
+ *     - guid: The global unique identifier (GUID) string that uniquely
+ *       identifies the item. If not available, the link is used to identify
+ *       the item.
+ *     - link: A full URL to the individual feed item.
  *
  * @return
  *   TRUE if parsing was successful, FALSE otherwise.
@@ -122,13 +116,11 @@
 }
 
 /**
- * Implement this hook to expose the title and a short description of your
- * parser.
+ * Specify the title and short description of your parser.
  *
- * The title and the description provided are shown on
- * admin/config/services/aggregator among other places. Use as title the human
- * readable name of the parser and as description a brief (40 to 80 characters)
- * explanation of the parser's functionality.
+ * The title and the description provided are shown within the configuration
+ * page. Use as title the human readable name of the parser and as description
+ * a brief (40 to 80 characters) explanation of the parser's functionality.
  *
  * This hook is only called if your module implements hook_aggregator_parse().
  * If this hook is not implemented aggregator will use your module's file name
@@ -149,23 +141,23 @@
 }
 
 /**
- * Implement this hook to create a processor for aggregator module.
+ * Create a processor for aggregator.module.
  *
  * A processor acts on parsed feed data. Active processors are called at the
- * third and last of the aggregation stages: data is downloaded by the active
- * fetcher, it is converted to a common format by the active parser and
- * finally, it is passed to all active processors which manipulate or store the
- * data.
+ * third and last of the aggregation stages: first, data is downloaded by the
+ * active fetcher; second, it is converted to a common format by the active
+ * parser; and finally, it is passed to all active processors that manipulate or
+ * store the data.
  *
- * Modules that define this hook can be activated as processor on
- * admin/config/services/aggregator.
+ * Modules that define this hook can be activated as a processor within the
+ * configuration page.
  *
  * @param $feed
- *   The $feed object that describes the resource to be processed. $feed->items
- *   contains an array of feed items downloaded and parsed at the parsing
- *   stage. See hook_aggregator_parse() for the basic format of a single item
- *   in the $feed->items array. For the exact format refer to the particular
- *   parser in use.
+ *   A feed object representing the resource to be processed. $feed->items
+ *   contains an array of feed items downloaded and parsed at the parsing stage.
+ *   See hook_aggregator_parse() for the basic format of a single item in the
+ *   $feed->items array. For the exact format refer to the particular parser in
+ *   use.
  *
  * @see hook_aggregator_process_info()
  * @see hook_aggregator_fetch()
@@ -180,17 +172,15 @@
 }
 
 /**
- * Implement this hook to expose the title and a short description of your
- * processor.
+ * Specify the title and short description of your processor.
  *
- * The title and the description provided are shown most importantly on
- * admin/config/services/aggregator. Use as title the natural name of the
- * processor and as description a brief (40 to 80 characters) explanation of
- * the functionality.
- *
- * This hook is only called if your module implements
- * hook_aggregator_process(). If this hook is not implemented aggregator
- * will use your module's file name as title and there will be no description.
+ * The title and the description provided are shown within the configuration
+ * page. Use as title the natural name of the processor and as description a
+ * brief (40 to 80 characters) explanation of the functionality.
+ *
+ * This hook is only called if your module implements hook_aggregator_process().
+ * If this hook is not implemented aggregator will use your module's file name
+ * as title and there will be no description.
  *
  * @return
  *   An associative array defining a title and a description string.
@@ -199,7 +189,7 @@
  *
  * @ingroup aggregator
  */
-function hook_aggregator_process_info($feed) {
+function hook_aggregator_process_info() {
   return array(
     'title' => t('Default processor'),
     'description' => t('Creates lightweight records of feed items.'),
@@ -207,8 +197,7 @@
 }
 
 /**
- * Implement this hook to remove stored data if a feed is being deleted or a
- * feed's items are being removed.
+ * Remove stored feed data.
  *
  * Aggregator calls this hook if either a feed is deleted or a user clicks on
  * "remove items".
diff -Naur drupal-7.9/modules/aggregator/aggregator.css drupal-7.58/modules/aggregator/aggregator.css
--- drupal-7.9/modules/aggregator/aggregator.css	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.css	2018-03-27 21:28:19.000000000 +0200
@@ -1,3 +1,6 @@
+/**
+ * Styles for theme in the Aggregator module.
+ */
 
 #aggregator .feed-source .feed-title {
   margin-top: 0;
diff -Naur drupal-7.9/modules/aggregator/aggregator.fetcher.inc drupal-7.58/modules/aggregator/aggregator.fetcher.inc
--- drupal-7.9/modules/aggregator/aggregator.fetcher.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.fetcher.inc	2018-03-27 21:28:19.000000000 +0200
@@ -27,7 +27,7 @@
     $headers['If-None-Match'] = $feed->etag;
   }
   if ($feed->modified) {
-    $headers['If-Modified-Since'] = gmdate(DATE_RFC1123, $feed->modified);
+    $headers['If-Modified-Since'] = gmdate(DATE_RFC7231, $feed->modified);
   }
 
   // Request feed.
diff -Naur drupal-7.9/modules/aggregator/aggregator.info drupal-7.58/modules/aggregator/aggregator.info
--- drupal-7.9/modules/aggregator/aggregator.info	2011-10-26 22:25:30.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.info	2018-03-28 21:06:59.000000000 +0200
@@ -7,8 +7,8 @@
 configure = admin/config/services/aggregator/settings
 stylesheets[all][] = aggregator.css
 
-; Information added by drupal.org packaging script on 2011-10-26
-version = "7.9"
+; Information added by Drupal.org packaging script on 2018-03-28
+version = "7.58"
 project = "drupal"
-datestamp = "1319660730"
+datestamp = "1522264019"
 
diff -Naur drupal-7.9/modules/aggregator/aggregator.install drupal-7.58/modules/aggregator/aggregator.install
--- drupal-7.9/modules/aggregator/aggregator.install	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.install	2018-03-27 21:28:19.000000000 +0200
@@ -130,10 +130,8 @@
         'description' => 'Title of the feed.',
       ),
       'url' => array(
-        'type' => 'varchar',
-        'length' => 255,
+        'type' => 'text',
         'not null' => TRUE,
-        'default' => '',
         'description' => 'URL to the feed.',
       ),
       'refresh' => array(
@@ -155,10 +153,8 @@
         'description' => 'Time when this feed was queued for refresh, 0 if not queued.',
       ),
       'link' => array(
-        'type' => 'varchar',
-        'length' => 255,
+        'type' => 'text',
         'not null' => TRUE,
-        'default' => '',
         'description' => 'The parent website of the feed; comes from the <link> element in the feed.',
       ),
       'description' => array(
@@ -202,13 +198,13 @@
       )
     ),
     'primary key' => array('fid'),
-    'unique keys' => array(
-      'url'  => array('url'),
-      'title' => array('title'),
-    ),
     'indexes' => array(
+      'url'  => array(array('url', 255)),
       'queued' => array('queued'),
     ),
+    'unique keys' => array(
+      'title' => array('title'),
+    ),
   );
 
   $schema['aggregator_item'] = array(
@@ -233,10 +229,8 @@
         'description' => 'Title of the feed item.',
       ),
       'link' => array(
-        'type' => 'varchar',
-        'length' => 255,
+        'type' => 'text',
         'not null' => TRUE,
-        'default' => '',
         'description' => 'Link to the feed item.',
       ),
       'author' => array(
@@ -258,15 +252,15 @@
         'description' => 'Posted date of the feed item, as a Unix timestamp.',
       ),
       'guid' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => FALSE,
+        'type' => 'text',
+        'not null' => TRUE,
         'description' => 'Unique identifier for the feed item.',
       )
     ),
     'primary key' => array('iid'),
     'indexes' => array(
       'fid' => array('fid'),
+      'timestamp' => array('timestamp'),
     ),
     'foreign keys' => array(
       'aggregator_feed' => array(
@@ -280,6 +274,11 @@
 }
 
 /**
+ * @addtogroup updates-6.x-to-7.x
+ * @{
+ */
+
+/**
  * Add hash column to aggregator_feed table.
  */
 function aggregator_update_7000() {
@@ -306,3 +305,36 @@
   db_add_index('aggregator_feed', 'queued', array('queued'));
 }
 
+/**
+ * @} End of "addtogroup updates-6.x-to-7.x"
+ */
+
+/**
+ * @addtogroup updates-7.x-extra
+ * @{
+ */
+
+/**
+ * Increase the length of {aggregator_feed}.url.
+ */
+function aggregator_update_7003() {
+  db_drop_unique_key('aggregator_feed', 'url');
+  db_change_field('aggregator_feed', 'url', 'url', array('type' => 'text', 'not null' => TRUE, 'description' => 'URL to the feed.'));
+  db_change_field('aggregator_feed', 'link', 'link', array('type' => 'text', 'not null' => TRUE, 'description' => 'The parent website of the feed; comes from the <link> element in the feed.'));
+  db_change_field('aggregator_item', 'link', 'link', array('type' => 'text', 'not null' => TRUE, 'description' => 'Link to the feed item.'));
+  db_change_field('aggregator_item', 'guid', 'guid', array('type' => 'text', 'not null' => TRUE, 'description' => 'Unique identifier for the feed item.'));
+  db_add_index('aggregator_feed', 'url', array(array('url', 255)));
+}
+
+/**
+ * Add index on timestamp.
+ */
+function aggregator_update_7004() {
+  if (!db_index_exists('aggregator_item', 'timestamp')) {
+    db_add_index('aggregator_item', 'timestamp', array('timestamp'));
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-7.x-extra"
+ */
diff -Naur drupal-7.9/modules/aggregator/aggregator.module drupal-7.58/modules/aggregator/aggregator.module
--- drupal-7.9/modules/aggregator/aggregator.module	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.module	2018-03-27 21:28:19.000000000 +0200
@@ -18,7 +18,7 @@
     case 'admin/help#aggregator':
       $output = '';
       $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Aggregator module is an on-site syndicator and news reader that gathers and displays fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines in feeds, using a number of standardized XML-based formats. For more information, see the online handbook entry for <a href="@aggregator-module">Aggregator module</a>.', array('@aggregator-module' => 'http://drupal.org/handbook/modules/aggregator', '@aggregator' => url('aggregator'))) . '</p>';
+      $output .= '<p>' . t('The Aggregator module is an on-site syndicator and news reader that gathers and displays fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines in feeds, using a number of standardized XML-based formats. For more information, see the online handbook entry for <a href="@aggregator-module">Aggregator module</a>.', array('@aggregator-module' => 'http://drupal.org/documentation/modules/aggregator', '@aggregator' => url('aggregator'))) . '</p>';
       $output .= '<h3>' . t('Uses') . '</h3>';
       $output .= '<dl>';
       $output .= '<dt>' . t('Viewing feeds') . '</dt>';
@@ -266,21 +266,24 @@
 }
 
 /**
- * Title callback for aggregatory category pages.
+ * Title callback: Returns a title for aggregator category pages.
+ *
+ * @param $category
+ *   An aggregator category.
  *
  * @return
- *   An aggregator category title.
+ *   A string with the aggregator category title.
  */
 function _aggregator_category_title($category) {
   return $category['title'];
 }
 
 /**
- * Find out whether there are any aggregator categories.
+ * Determines whether there are any aggregator categories.
  *
  * @return
- *   TRUE if there is at least one category and the user has access to them, FALSE
- *   otherwise.
+ *   TRUE if there is at least one category and the user has access to them;
+ *   FALSE otherwise.
  */
 function _aggregator_has_categories() {
   return user_access('access news feeds') && (bool) db_query_range('SELECT 1 FROM {aggregator_category}', 0, 1)->fetchField();
@@ -394,6 +397,7 @@
   if (user_access('access news feeds')) {
     $block = array();
     list($type, $id) = explode('-', $delta);
+    $result = FALSE;
     switch ($type) {
       case 'feed':
         if ($feed = db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE block <> 0 AND fid = :fid', array(':fid' => $id))->fetchObject()) {
@@ -411,9 +415,12 @@
         }
         break;
     }
+
     $items = array();
-    foreach ($result as $item) {
-      $items[] = theme('aggregator_block_item', array('item' => $item));
+    if (!empty($result)) {
+      foreach ($result as $item) {
+        $items[] = theme('aggregator_block_item', array('item' => $item));
+      }
     }
 
     // Only display the block if there are items to show.
@@ -425,7 +432,7 @@
 }
 
 /**
- * Add/edit/delete aggregator categories.
+ * Adds/edits/deletes aggregator categories.
  *
  * @param $edit
  *   An associative array describing the category to be added/edited/deleted.
@@ -448,11 +455,21 @@
       db_delete('aggregator_category')
         ->condition('cid', $edit['cid'])
         ->execute();
-      // Make sure there is no active block for this category.
-      db_delete('block')
-        ->condition('module', 'aggregator')
-        ->condition('delta', 'category-' . $edit['cid'])
+      // Remove category from feeds.
+      db_delete('aggregator_category_feed')
+        ->condition('cid', $edit['cid'])
         ->execute();
+      // Remove category from feed items.
+      db_delete('aggregator_category_item')
+        ->condition('cid', $edit['cid'])
+        ->execute();
+      // Make sure there is no active block for this category.
+      if (module_exists('block')) {
+        db_delete('block')
+          ->condition('module', 'aggregator')
+          ->condition('delta', 'category-' . $edit['cid'])
+          ->execute();
+      }
       $edit['title'] = '';
       $op = 'delete';
     }
@@ -511,10 +528,12 @@
       ->condition('fid', $edit['fid'])
       ->execute();
     // Make sure there is no active block for this feed.
-    db_delete('block')
-      ->condition('module', 'aggregator')
-      ->condition('delta', 'feed-' . $edit['fid'])
-      ->execute();
+    if (module_exists('block')) {
+      db_delete('block')
+        ->condition('module', 'aggregator')
+        ->condition('delta', 'feed-' . $edit['fid'])
+        ->execute();
+    }
   }
   elseif (!empty($edit['title'])) {
     $edit['fid'] = db_insert('aggregator_feed')
@@ -523,6 +542,7 @@
         'url' => $edit['url'],
         'refresh' => $edit['refresh'],
         'block' => $edit['block'],
+        'link' => '',
         'description' => '',
         'image' => '',
       ))
@@ -557,19 +577,23 @@
   // Call hook_aggregator_remove() on all modules.
   module_invoke_all('aggregator_remove', $feed);
   // Reset feed.
-  db_merge('aggregator_feed')
-    ->key(array('fid' => $feed->fid))
+  db_update('aggregator_feed')
+    ->condition('fid', $feed->fid)
     ->fields(array(
       'checked' => 0,
       'hash' => '',
       'etag' => '',
       'modified' => 0,
-      'description' => $feed->description,
-      'image' => $feed->image,
     ))
     ->execute();
 }
 
+/**
+ * Gets the fetcher, parser, and processors.
+ *
+ * @return
+ *   An array containing the fetcher, parser, and processors.
+ */
 function _aggregator_get_variables() {
   // Fetch the feed.
   $fetcher = variable_get('aggregator_fetcher', 'aggregator');
@@ -656,10 +680,11 @@
 }
 
 /**
- * Load an aggregator feed.
+ * Loads an aggregator feed.
  *
  * @param $fid
  *   The feed id.
+ *
  * @return
  *   An object describing the feed.
  */
@@ -673,10 +698,11 @@
 }
 
 /**
- * Load an aggregator category.
+ * Loads an aggregator category.
  *
  * @param $cid
  *   The category id.
+ *
  * @return
  *   An associative array describing the category.
  */
@@ -705,10 +731,11 @@
 }
 
 /**
- * Safely render HTML content, as allowed.
+ * Renders the HTML content safely, as allowed.
  *
  * @param $value
  *   The content to be filtered.
+ *
  * @return
  *   The filtered content.
  */
@@ -717,14 +744,13 @@
 }
 
 /**
- * Check and sanitize aggregator configuration.
+ * Checks and sanitizes the aggregator configuration.
  *
- * Goes through all fetchers, parsers and processors and checks whether they are
- * available.
- * If one is missing resets to standard configuration.
+ * Goes through all fetchers, parsers and processors and checks whether they
+ * are available. If one is missing, resets to standard configuration.
  *
  * @return
- *   TRUE if this function reset the configuration FALSE if not.
+ *   TRUE if this function resets the configuration; FALSE if not.
  */
 function aggregator_sanitize_configuration() {
   $reset = FALSE;
@@ -755,8 +781,9 @@
  *
  * @param $count
  *   Items count.
+ *
  * @return
- *   Plural-formatted "@count items"
+ *   A string that is plural-formatted as "@count items".
  */
 function _aggregator_items($count) {
   return format_plural($count, '1 item', '@count items');
diff -Naur drupal-7.9/modules/aggregator/aggregator.pages.inc drupal-7.58/modules/aggregator/aggregator.pages.inc
--- drupal-7.9/modules/aggregator/aggregator.pages.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.pages.inc	2018-03-27 21:28:19.000000000 +0200
@@ -2,14 +2,14 @@
 
 /**
  * @file
- * User page callbacks for the aggregator module.
+ * User page callbacks for the Aggregator module.
  */
 
 /**
- * Menu callback; displays the most recent items gathered from any feed.
+ * Page callback: Displays the most recent items gathered from any feed.
  *
  * @return
- *   The items HTML.
+ *   The rendered list of items for the feed.
  */
 function aggregator_page_last() {
   drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
@@ -20,13 +20,15 @@
 }
 
 /**
- * Menu callback; displays all the items captured from a particular feed.
+ * Page callback: Displays all the items captured from the particular feed.
  *
  * @param $feed
  *   The feed for which to display all items.
  *
  * @return
  *   The rendered list of items for a feed.
+ *
+ * @see aggregator_menu()
  */
 function aggregator_page_source($feed) {
   drupal_set_title($feed->title);
@@ -40,13 +42,13 @@
 }
 
 /**
- * Menu callback; displays a form with all items captured from a feed.
+ * Page callback: Displays a form with all items captured from a feed.
  *
  * @param $feed
- *   The feed for which to list all the aggregated items.
+ *   The feed for which to list all of the aggregated items.
  *
  * @return
- *   The rendered list of items for a feed.
+ *   The rendered list of items for the feed.
  *
  * @see aggregator_page_source()
  */
@@ -55,13 +57,13 @@
 }
 
 /**
- * Menu callback; displays all the items aggregated in a particular category.
+ * Page callback: Displays all the items aggregated in a particular category.
  *
  * @param $category
- *   The category for which to list all the aggregated items.
+ *   The category for which to list all of the aggregated items.
  *
  * @return
-*   The rendered list of items for a category.
+ *   The rendered list of items for the feed.
  */
 function aggregator_page_category($category) {
   drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
@@ -74,13 +76,13 @@
 }
 
 /**
- * Menu callback; displays a form containing items aggregated in a category.
+ * Page callback: Displays a form containing items aggregated in a category.
  *
  * @param $category
- *   The category for which to list all the aggregated items.
+ *   The category for which to list all of the aggregated items.
  *
  * @return
-*   The rendered list of items for a category.
+ *   The rendered list of items for the feed.
  *
  * @see aggregator_page_category()
  */
@@ -160,11 +162,13 @@
  * @param $items
  *   The items to be listed.
  * @param $op
- *   Which form should be added to the items. Only 'categorize' is now recognized.
+ *   Which form should be added to the items. Only 'categorize' is now
+ *   recognized.
  * @param $feed_source
  *   The feed source URL.
+ *
  * @return
- *   The items HTML.
+ *   The rendered list of items for the feed.
  */
 function _aggregator_page_list($items, $op, $feed_source = '') {
   if (user_access('administer news feeds') && ($op == 'categorize')) {
@@ -184,16 +188,19 @@
 }
 
 /**
- * Form builder; build the page list form.
+ * Form constructor to build the page list form.
  *
  * @param $items
  *   An array of the feed items.
  * @param $feed_source
- *   The feed source URL.
- * @return
- *   The form structure.
- * @ingroup forms
+ *   (optional) The feed source URL. Defaults to an empty string.
+ *
+ * @return array
+ *   An array of FAPI elements.
+ *
  * @see aggregator_categorize_items_submit()
+ * @see theme_aggregator_categorize_items()
+ * @ingroup forms
  */
 function aggregator_categorize_items($items, $feed_source = '') {
   $form['#submit'][] = 'aggregator_categorize_items_submit';
@@ -236,7 +243,7 @@
 }
 
 /**
- * Process aggregator_categorize_items() form submissions.
+ * Form submission handler for aggregator_categorize_items().
  */
 function aggregator_categorize_items_submit($form, &$form_state) {
   if (!empty($form_state['values']['categories'])) {
@@ -293,7 +300,7 @@
 }
 
 /**
- * Process variables for aggregator-wrapper.tpl.php.
+ * Processes variables for aggregator-wrapper.tpl.php.
  *
  * @see aggregator-wrapper.tpl.php
  */
@@ -302,7 +309,7 @@
 }
 
 /**
- * Process variables for aggregator-item.tpl.php.
+ * Processes variables for aggregator-item.tpl.php.
  *
  * @see aggregator-item.tpl.php
  */
@@ -333,7 +340,12 @@
 }
 
 /**
- * Menu callback; displays all the feeds used by the aggregator.
+ * Page callback: Displays all the feeds used by the aggregator.
+ *
+ * @return
+ *   An HTML-formatted string.
+ *
+ * @see aggregator_menu()
  */
 function aggregator_page_sources() {
   $result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');
@@ -357,7 +369,12 @@
 }
 
 /**
- * Menu callback; displays all the categories used by the aggregator.
+ * Page callback: Displays all the categories used by the Aggregator module.
+ *
+ * @return string
+ *   An HTML formatted string.
+ *
+ * @see aggregator_menu()
  */
 function aggregator_page_categories() {
   $result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');
@@ -379,7 +396,10 @@
 }
 
 /**
- * Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
+ * Page callback: Generates an RSS 0.92 feed of aggregator items or categories.
+ *
+ * @return string
+ *   An HTML formatted string.
  */
 function aggregator_page_rss() {
   $result = NULL;
@@ -447,12 +467,14 @@
 }
 
 /**
- * Menu callback; generates an OPML representation of all feeds.
+ * Page callback: Generates an OPML representation of all feeds.
  *
  * @param $cid
- *   If set, feeds are exported only from a category with this ID. Otherwise, all feeds are exported.
+ *   (optional) If set, feeds are exported only from a category with this ID.
+ *   Otherwise, all feeds are exported. Defaults to NULL.
+ *
  * @return
- *   The output XML.
+ *   An OPML formatted string.
  */
 function aggregator_page_opml($cid = NULL) {
   if ($cid) {
@@ -467,14 +489,12 @@
 }
 
 /**
- * Prints the OPML page for a feed.
+ * Prints the OPML page for the feed.
  *
  * @param $variables
  *   An associative array containing:
  *   - feeds: An array of the feeds to theme.
  *
- * @return void
- *
  * @ingroup themeable
  */
 function theme_aggregator_page_opml($variables) {
@@ -499,7 +519,7 @@
 }
 
 /**
- * Process variables for aggregator-summary-items.tpl.php.
+ * Processes variables for aggregator-summary-items.tpl.php.
  *
  * @see aggregator-summary-items.tpl.php
  */
@@ -510,7 +530,7 @@
 }
 
 /**
- * Process variables for aggregator-summary-item.tpl.php.
+ * Processes variables for aggregator-summary-item.tpl.php.
  *
  * @see aggregator-summary-item.tpl.php
  */
@@ -530,7 +550,7 @@
 }
 
 /**
- * Process variables for aggregator-feed-source.tpl.php.
+ * Processes variables for aggregator-feed-source.tpl.php.
  *
  * @see aggregator-feed-source.tpl.php
  */
diff -Naur drupal-7.9/modules/aggregator/aggregator.parser.inc drupal-7.58/modules/aggregator/aggregator.parser.inc
--- drupal-7.9/modules/aggregator/aggregator.parser.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.parser.inc	2018-03-27 21:28:19.000000000 +0200
@@ -54,12 +54,13 @@
 }
 
 /**
- * Parse a feed and store its items.
+ * Parses a feed and stores its items.
  *
  * @param $data
  *   The feed data.
  * @param $feed
  *   An object describing the feed to be parsed.
+ *
  * @return
  *   FALSE on error, TRUE otherwise.
  */
@@ -164,7 +165,9 @@
 }
 
 /**
- * Callback function used by the XML parser.
+ * Performs an action when an opening tag is encountered.
+ *
+ * Callback function used by xml_parse() within aggregator_parse_feed().
  */
 function aggregator_element_start($parser, $name, $attributes) {
   global $item, $element, $tag, $items, $channel;
@@ -212,7 +215,9 @@
 }
 
 /**
- * Call-back function used by the XML parser.
+ * Performs an action when a closing tag is encountered.
+ *
+ * Callback function used by xml_parse() within aggregator_parse_feed().
  */
 function aggregator_element_end($parser, $name) {
   global $element;
@@ -234,7 +239,9 @@
 }
 
 /**
- * Callback function used by the XML parser.
+ * Performs an action when data is encountered.
+ *
+ * Callback function used by xml_parse() within aggregator_parse_feed().
  */
 function aggregator_element_data($parser, $data) {
   global $channel, $element, $items, $item, $image, $tag;
@@ -281,14 +288,15 @@
 }
 
 /**
- * Parse the W3C date/time format, a subset of ISO 8601.
+ * Parses the W3C date/time format, a subset of ISO 8601.
  *
- * PHP date parsing functions do not handle this format.
- * See http://www.w3.org/TR/NOTE-datetime for more information.
- * Originally from MagpieRSS (http://magpierss.sourceforge.net/).
+ * PHP date parsing functions do not handle this format. See
+ * http://www.w3.org/TR/NOTE-datetime for more information. Originally from
+ * MagpieRSS (http://magpierss.sourceforge.net/).
  *
  * @param $date_str
  *   A string with a potentially W3C DTF date.
+ *
  * @return
  *   A timestamp if parsed successfully or FALSE if not.
  */
diff -Naur drupal-7.9/modules/aggregator/aggregator.processor.inc drupal-7.58/modules/aggregator/aggregator.processor.inc
--- drupal-7.9/modules/aggregator/aggregator.processor.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.processor.inc	2018-03-27 21:28:19.000000000 +0200
@@ -38,8 +38,9 @@
           $item['timestamp'] = isset($entry->timestamp) ? $entry->timestamp : REQUEST_TIME;
         }
 
-        // Make sure the item title fits in 255 varchar column.
+        // Make sure the item title and author fit in the 255 varchar column.
         $item['title'] = truncate_utf8($item['title'], 255, TRUE, TRUE);
+        $item['author'] = truncate_utf8($item['author'], 255, TRUE, TRUE);
         aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid : ''), 'fid' => $feed->fid, 'timestamp' => $item['timestamp'], 'title' => $item['title'], 'link' => $item['link'], 'author' => $item['author'], 'description' => $item['description'], 'guid' => $item['guid']));
       }
     }
@@ -71,7 +72,7 @@
  */
 function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
   if (in_array('aggregator', variable_get('aggregator_processors', array('aggregator')))) {
-    $info = module_invoke('aggregator', 'aggregator_process', 'info');
+    $info = module_invoke('aggregator', 'aggregator_process_info');
     $items = drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
     $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
     $period[AGGREGATOR_CLEAR_NEVER] = t('Never');
@@ -117,7 +118,7 @@
     $form['modules']['aggregator']['aggregator_teaser_length'] = array(
       '#type' => 'select',
       '#title' => t('Length of trimmed description'),
-      '#default_value' => 600,
+      '#default_value' => variable_get('aggregator_teaser_length', 600),
       '#options' => drupal_map_assoc(array(0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000), '_aggregator_characters'),
       '#description' => t("The maximum number of characters used in the trimmed version of content.")
     );
@@ -126,14 +127,23 @@
 }
 
 /**
- * Helper function for teaser length choices.
+ * Creates display text for teaser length option values.
+ *
+ * Callback for drupal_map_assoc() within
+ * aggregator_form_aggregator_admin_form_alter().
+ *
+ * @param $length
+ *   The desired length of teaser text, in bytes.
+ *
+ * @return
+ *   A translated string explaining the teaser string length.
  */
 function _aggregator_characters($length) {
   return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
 }
 
 /**
- * Add/edit/delete an aggregator item.
+ * Adds/edits/deletes an aggregator item.
  *
  * @param $edit
  *   An associative array describing the item to be added/edited/deleted.
@@ -175,7 +185,7 @@
 }
 
 /**
- * Expire feed items on $feed that are older than aggregator_clear.
+ * Expires items from a feed depending on expiration settings.
  *
  * @param $feed
  *   Object describing feed.
diff -Naur drupal-7.9/modules/aggregator/aggregator.test drupal-7.58/modules/aggregator/aggregator.test
--- drupal-7.9/modules/aggregator/aggregator.test	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/aggregator.test	2018-03-27 21:28:19.000000000 +0200
@@ -5,6 +5,9 @@
  * Tests for aggregator.module.
  */
 
+/**
+ * Defines a base class for testing the Aggregator module.
+ */
 class AggregatorTestCase extends DrupalWebTestCase {
   function setUp() {
     parent::setUp('aggregator', 'aggregator_test');
@@ -13,10 +16,15 @@
   }
 
   /**
-   * Create an aggregator feed (simulate form submission on admin/config/services/aggregator/add/feed).
+   * Creates an aggregator feed.
+   *
+   * This method simulates the form submission on path
+   * admin/config/services/aggregator/add/feed.
    *
    * @param $feed_url
-   *   If given, feed will be created with this URL, otherwise /rss.xml will be used.
+   *   (optional) If given, feed will be created with this URL, otherwise
+   *   /rss.xml will be used. Defaults to NULL.
+   *
    * @return $feed
    *   Full feed object if possible.
    *
@@ -25,29 +33,30 @@
   function createFeed($feed_url = NULL) {
     $edit = $this->getFeedEditArray($feed_url);
     $this->drupalPost('admin/config/services/aggregator/add/feed', $edit, t('Save'));
-    $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
+    $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), format_string('The feed !name has been added.', array('!name' => $edit['title'])));
 
     $feed = db_query("SELECT *  FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $edit['title'], ':url' => $edit['url']))->fetch();
-    $this->assertTrue(!empty($feed), t('The feed found in database.'));
+    $this->assertTrue(!empty($feed), 'The feed found in database.');
     return $feed;
   }
 
   /**
-   * Delete an aggregator feed.
+   * Deletes an aggregator feed.
    *
    * @param $feed
    *   Feed object representing the feed.
    */
   function deleteFeed($feed) {
     $this->drupalPost('admin/config/services/aggregator/edit/feed/' . $feed->fid, array(), t('Delete'));
-    $this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->title)), t('Feed deleted successfully.'));
+    $this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->title)), 'Feed deleted successfully.');
   }
 
   /**
-   * Return a randomly generated feed edit array.
+   * Returns a randomly generated feed edit array.
    *
    * @param $feed_url
-   *   If given, feed will be created with this URL, otherwise /rss.xml will be used.
+   *   (optional) If given, feed will be created with this URL, otherwise
+   *   /rss.xml will be used. Defaults to NULL.
    * @return
    *   A feed array.
    */
@@ -68,7 +77,7 @@
   }
 
   /**
-   * Return the count of the randomly created feed array.
+   * Returns the count of the randomly created feed array.
    *
    * @return
    *   Number of feed items on default feed created by createFeed().
@@ -80,20 +89,28 @@
   }
 
   /**
-   * Update feed items (simulate click to admin/config/services/aggregator/update/$fid).
+   * Updates the feed items.
+   *
+   * This method simulates a click to
+   * admin/config/services/aggregator/update/$fid.
    *
    * @param $feed
-   *   Feed object representing the feed.
+   *   Feed object representing the feed, passed by reference.
    * @param $expected_count
    *   Expected number of feed items.
    */
   function updateFeedItems(&$feed, $expected_count) {
     // First, let's ensure we can get to the rss xml.
     $this->drupalGet($feed->url);
-    $this->assertResponse(200, t('!url is reachable.', array('!url' => $feed->url)));
+    $this->assertResponse(200, format_string('!url is reachable.', array('!url' => $feed->url)));
 
-    // Refresh the feed (simulated link click).
+    // Attempt to access the update link directly without an access token.
     $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
+    $this->assertResponse(403);
+
+    // Refresh the feed (simulated link click).
+    $this->drupalGet('admin/config/services/aggregator');
+    $this->clickLink('update items');
 
     // Ensure we have the right number of items.
     $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid));
@@ -103,22 +120,22 @@
       $feed->items[] = $item->iid;
     }
     $feed->item_count = count($feed->items);
-    $this->assertEqual($expected_count, $feed->item_count, t('Total items in feed equal to the total items in database (!val1 != !val2)', array('!val1' => $expected_count, '!val2' => $feed->item_count)));
+    $this->assertEqual($expected_count, $feed->item_count, format_string('Total items in feed equal to the total items in database (!val1 != !val2)', array('!val1' => $expected_count, '!val2' => $feed->item_count)));
   }
 
   /**
-   * Confirm item removal from a feed.
+   * Confirms an item removal from a feed.
    *
    * @param $feed
    *   Feed object representing the feed.
    */
   function removeFeedItems($feed) {
     $this->drupalPost('admin/config/services/aggregator/remove/' . $feed->fid, array(), t('Remove items'));
-    $this->assertRaw(t('The news items from %title have been removed.', array('%title' => $feed->title)), t('Feed items removed.'));
+    $this->assertRaw(t('The news items from %title have been removed.', array('%title' => $feed->title)), 'Feed items removed.');
   }
 
   /**
-   * Add and remove feed items and ensure that the count is zero.
+   * Adds and removes feed items and ensure that the count is zero.
    *
    * @param $feed
    *   Feed object representing the feed.
@@ -135,7 +152,7 @@
   }
 
   /**
-   * Pull feed categories from aggregator_category_feed table.
+   * Pulls feed categories from {aggregator_category_feed} table.
    *
    * @param $feed
    *   Feed object representing the feed.
@@ -149,7 +166,11 @@
   }
 
   /**
-   * Pull categories from aggregator_category table.
+   * Pulls categories from {aggregator_category} table.
+   *
+   * @return
+   *   An associative array keyed by category ID and values are set to the
+   *   category names.
    */
   function getCategories() {
     $categories = array();
@@ -160,14 +181,14 @@
     return $categories;
   }
 
-
   /**
-   * Check if the feed name and url is unique.
+   * Checks whether the feed name and URL are unique.
    *
    * @param $feed_name
    *   String containing the feed name to check.
    * @param $feed_url
-   *   String containing the feed url to check.
+   *   String containing the feed URL to check.
+   *
    * @return
    *   TRUE if feed is unique.
    */
@@ -177,10 +198,11 @@
   }
 
   /**
-   * Create a valid OPML file from an array of feeds.
+   * Creates a valid OPML file from an array of feeds.
    *
    * @param $feeds
    *   An array of feeds.
+   *
    * @return
    *   Path to valid OPML file.
    */
@@ -218,7 +240,7 @@
   }
 
   /**
-   * Create an invalid OPML file.
+   * Creates an invalid OPML file.
    *
    * @return
    *   Path to invalid OPML file.
@@ -235,7 +257,7 @@
   }
 
   /**
-   * Create a valid but empty OPML file.
+   * Creates a valid but empty OPML file.
    *
    * @return
    *   Path to empty OPML file.
@@ -266,11 +288,15 @@
     return $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'aggregator') . '/tests/aggregator_test_atom.xml';
   }
 
+  function getHtmlEntitiesSample() {
+    return $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'aggregator') . '/tests/aggregator_test_title_entities.xml';
+  }
+
   /**
    * Creates sample article nodes.
    *
    * @param $count
-   *   (optional) The number of nodes to generate.
+   *   (optional) The number of nodes to generate. Defaults to five.
    */
   function createSampleNodes($count = 5) {
     $langcode = LANGUAGE_NONE;
@@ -284,6 +310,41 @@
   }
 }
 
+/**
+ * Tests functionality of the configuration settings in the Aggregator module.
+ */
+class AggregatorConfigurationTestCase extends AggregatorTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Aggregator configuration',
+      'description' => 'Test aggregator settings page.',
+      'group' => 'Aggregator',
+    );
+  }
+
+  /**
+   * Tests the settings form to ensure the correct default values are used.
+   */
+  function testSettingsPage() {
+    $edit = array(
+      'aggregator_allowed_html_tags' => '<a>',
+      'aggregator_summary_items' => 10,
+      'aggregator_clear' => 3600,
+      'aggregator_category_selector' => 'select',
+      'aggregator_teaser_length' => 200,
+    );
+    $this->drupalPost('admin/config/services/aggregator/settings', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'));
+
+    foreach ($edit as $name => $value) {
+      $this->assertFieldByName($name, $value, format_string('"@name" has correct default value.', array('@name' => $name)));
+    }
+  }
+}
+
+/**
+ * Tests adding aggregator feeds.
+ */
 class AddFeedTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -294,27 +355,59 @@
   }
 
   /**
-   * Create a feed, ensure that it is unique, check the source, and delete the feed.
+   * Creates and ensures that a feed is unique, checks source, and deletes feed.
    */
   function testAddFeed() {
     $feed = $this->createFeed();
 
     // Check feed data.
-    $this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/add/feed', array('absolute' => TRUE)), t('Directed to correct url.'));
-    $this->assertTrue($this->uniqueFeed($feed->title, $feed->url), t('The feed is unique.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/add/feed', array('absolute' => TRUE)), 'Directed to correct url.');
+    $this->assertTrue($this->uniqueFeed($feed->title, $feed->url), 'The feed is unique.');
 
     // Check feed source.
     $this->drupalGet('aggregator/sources/' . $feed->fid);
-    $this->assertResponse(200, t('Feed source exists.'));
-    $this->assertText($feed->title, t('Page title'));
+    $this->assertResponse(200, 'Feed source exists.');
+    $this->assertText($feed->title, 'Page title');
     $this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize');
-    $this->assertResponse(200, t('Feed categorization page exists.'));
+    $this->assertResponse(200, 'Feed categorization page exists.');
 
     // Delete feed.
     $this->deleteFeed($feed);
   }
+
+  /**
+   * Tests feeds with very long URLs.
+   */
+  function testAddLongFeed() {
+    // Create a feed with a URL of > 255 characters.
+    $long_url = "https://www.google.com/search?ix=heb&sourceid=chrome&ie=UTF-8&q=angie+byron#sclient=psy-ab&hl=en&safe=off&source=hp&q=angie+byron&pbx=1&oq=angie+byron&aq=f&aqi=&aql=&gs_sm=3&gs_upl=0l0l0l10534l0l0l0l0l0l0l0l0ll0l0&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=a70b6b1f0abe28d8&biw=1629&bih=889&ix=heb";
+    $feed = $this->createFeed($long_url);
+
+    // Create a second feed of > 255 characters, where the only difference is
+    // after the 255th character.
+    $long_url_2 = "https://www.google.com/search?ix=heb&sourceid=chrome&ie=UTF-8&q=angie+byron#sclient=psy-ab&hl=en&safe=off&source=hp&q=angie+byron&pbx=1&oq=angie+byron&aq=f&aqi=&aql=&gs_sm=3&gs_upl=0l0l0l10534l0l0l0l0l0l0l0l0ll0l0&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=a70b6b1f0abe28d8&biw=1629&bih=889";
+    $feed_2 = $this->createFeed($long_url_2);
+
+    // Check feed data.
+    $this->assertTrue($this->uniqueFeed($feed->title, $feed->url), 'The first long URL feed is unique.');
+    $this->assertTrue($this->uniqueFeed($feed_2->title, $feed_2->url), 'The second long URL feed is unique.');
+
+    // Check feed source.
+    $this->drupalGet('aggregator/sources/' . $feed->fid);
+    $this->assertResponse(200, 'Long URL feed source exists.');
+    $this->assertText($feed->title, 'Page title');
+    $this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize');
+    $this->assertResponse(200, 'Long URL feed categorization page exists.');
+
+    // Delete feeds.
+    $this->deleteFeed($feed);
+    $this->deleteFeed($feed_2);
+  }
 }
 
+/**
+ * Tests the categorize feed functionality in the Aggregator module.
+ */
 class CategorizeFeedTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -325,18 +418,18 @@
   }
 
   /**
-   * Create a feed and make sure you can add more than one category to it.
+   * Creates a feed and makes sure you can add/delete categories to it.
    */
   function testCategorizeFeed() {
 
     // Create 2 categories.
     $category_1 = array('title' => $this->randomName(10), 'description' => '');
     $this->drupalPost('admin/config/services/aggregator/add/category', $category_1, t('Save'));
-    $this->assertRaw(t('The category %title has been added.', array('%title' => $category_1['title'])), t('The category %title has been added.', array('%title' => $category_1['title'])));
+    $this->assertRaw(t('The category %title has been added.', array('%title' => $category_1['title'])), format_string('The category %title has been added.', array('%title' => $category_1['title'])));
 
     $category_2 = array('title' => $this->randomName(10), 'description' => '');
     $this->drupalPost('admin/config/services/aggregator/add/category', $category_2, t('Save'));
-    $this->assertRaw(t('The category %title has been added.', array('%title' => $category_2['title'])), t('The category %title has been added.', array('%title' => $category_2['title'])));
+    $this->assertRaw(t('The category %title has been added.', array('%title' => $category_2['title'])), format_string('The category %title has been added.', array('%title' => $category_2['title'])));
 
     // Get categories from database.
     $categories = $this->getCategories();
@@ -354,10 +447,37 @@
 
     // Assert the feed has two categories.
     $this->getFeedCategories($db_feed);
-    $this->assertEqual(count($db_feed->categories), 2, t('Feed has 2 categories'));
+    $this->assertEqual(count($db_feed->categories), 2, 'Feed has 2 categories');
+
+    // Use aggregator_save_feed() to delete a category.
+    $category = reset($categories);
+    aggregator_save_category(array('cid' => $category->cid));
+
+    // Assert that category is deleted.
+    $db_category = db_query("SELECT COUNT(*) FROM {aggregator_category} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField();
+    $this->assertFalse($db_category, format_string('The category %title has been deleted.', array('%title' => $category->title)));
+
+    // Assert that category has been removed from feed.
+    $categorized_feeds = db_query("SELECT COUNT(*) FROM {aggregator_category_feed} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField();
+    $this->assertFalse($categorized_feeds, format_string('The category %title has been removed from feed %feed_title.', array('%title' => $category->title, '%feed_title' => $feed['title'])));
+
+    // Assert that no broken links (associated with the deleted category)
+    // appear on one of the other category pages.
+    $this->createSampleNodes();
+    $this->drupalGet('admin/config/services/aggregator');
+    $this->clickLink('update items');
+    $categories = $this->getCategories();
+    $category = reset($categories);
+    $this->drupalGet('aggregator/categories/' . $category->cid);
+    global $base_path;
+    $this->assertNoRaw('<a href="' . $base_path . 'aggregator/categories/"></a>,');
   }
+
 }
 
+/**
+ * Tests functionality of updating the feed in the Aggregator module.
+ */
 class UpdateFeedTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -368,7 +488,7 @@
   }
 
   /**
-   * Create a feed and attempt to update it.
+   * Creates a feed and attempts to update it.
    */
   function testUpdateFeed() {
     $remamining_fields = array('title', 'url', '');
@@ -382,16 +502,16 @@
         $edit[$same_field] = $feed->{$same_field};
       }
       $this->drupalPost('admin/config/services/aggregator/edit/feed/' . $feed->fid, $edit, t('Save'));
-      $this->assertRaw(t('The feed %name has been updated.', array('%name' => $edit['title'])), t('The feed %name has been updated.', array('%name' => $edit['title'])));
+      $this->assertRaw(t('The feed %name has been updated.', array('%name' => $edit['title'])), format_string('The feed %name has been updated.', array('%name' => $edit['title'])));
 
       // Check feed data.
       $this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/', array('absolute' => TRUE)));
-      $this->assertTrue($this->uniqueFeed($edit['title'], $edit['url']), t('The feed is unique.'));
+      $this->assertTrue($this->uniqueFeed($edit['title'], $edit['url']), 'The feed is unique.');
 
       // Check feed source.
       $this->drupalGet('aggregator/sources/' . $feed->fid);
-      $this->assertResponse(200, t('Feed source exists.'));
-      $this->assertText($edit['title'], t('Page title'));
+      $this->assertResponse(200, 'Feed source exists.');
+      $this->assertText($edit['title'], 'Page title');
 
       // Delete feed.
       $feed->title = $edit['title']; // Set correct title so deleteFeed() will work.
@@ -400,6 +520,9 @@
   }
 }
 
+/**
+ * Tests functionality for removing feeds in the Aggregator module.
+ */
 class RemoveFeedTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -410,7 +533,7 @@
   }
 
   /**
-   * Remove a feed and ensure that all it services are removed.
+   * Removes a feed and ensures that all of its services are removed.
    */
   function testRemoveFeed() {
     $feed = $this->createFeed();
@@ -420,14 +543,17 @@
 
     // Check feed source.
     $this->drupalGet('aggregator/sources/' . $feed->fid);
-    $this->assertResponse(404, t('Deleted feed source does not exists.'));
+    $this->assertResponse(404, 'Deleted feed source does not exists.');
 
     // Check database for feed.
     $result = db_query("SELECT COUNT(*) FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $feed->title, ':url' => $feed->url))->fetchField();
-    $this->assertFalse($result, t('Feed not found in database'));
+    $this->assertFalse($result, 'Feed not found in database');
   }
 }
 
+/**
+ * Tests functionality of updating a feed item in the Aggregator module.
+ */
 class UpdateFeedItemTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -438,7 +564,7 @@
   }
 
   /**
-   * Test running "update items" from the 'admin/config/services/aggregator' page.
+   * Tests running "update items" from 'admin/config/services/aggregator' page.
    */
   function testUpdateFeedItem() {
     $this->createSampleNodes();
@@ -460,14 +586,14 @@
     );
 
     $this->drupalGet($edit['url']);
-    $this->assertResponse(array(200), t('URL !url is accessible', array('!url' => $edit['url'])));
+    $this->assertResponse(array(200), format_string('URL !url is accessible', array('!url' => $edit['url'])));
 
     $this->drupalPost('admin/config/services/aggregator/add/feed', $edit, t('Save'));
-    $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
+    $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), format_string('The feed !name has been added.', array('!name' => $edit['title'])));
 
     $feed = db_query("SELECT * FROM {aggregator_feed} WHERE url = :url", array(':url' => $edit['url']))->fetchObject();
-    $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
 
+    aggregator_refresh($feed);
     $before = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField();
 
     // Sleep for 3 second.
@@ -481,11 +607,10 @@
         'modified' => 0,
       ))
       ->execute();
-    $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
+    aggregator_refresh($feed);
 
     $after = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField();
-
-    $this->assertTrue($before === $after, t('Publish timestamp of feed item was not updated (!before === !after)', array('!before' => $before, '!after' => $after)));
+    $this->assertTrue($before === $after, format_string('Publish timestamp of feed item was not updated (!before === !after)', array('!before' => $before, '!after' => $after)));
   }
 }
 
@@ -499,7 +624,7 @@
   }
 
   /**
-   * Test running "remove items" from the 'admin/config/services/aggregator' page.
+   * Tests running "remove items" from 'admin/config/services/aggregator' page.
    */
   function testRemoveFeedItem() {
     // Create a bunch of test feeds.
@@ -518,15 +643,18 @@
       // Update and remove items two times in a row to make sure that removal
       // resets all 'modified' information (modified, etag, hash) and allows for
       // immediate update.
-      $this->updateAndRemove($feed, 2);
-      $this->updateAndRemove($feed, 2);
-      $this->updateAndRemove($feed, 2);
+      $this->updateAndRemove($feed, 4);
+      $this->updateAndRemove($feed, 4);
+      $this->updateAndRemove($feed, 4);
       // Delete feed.
       $this->deleteFeed($feed);
     }
   }
 }
 
+/**
+ * Tests categorization functionality in the Aggregator module.
+ */
 class CategorizeFeedItemTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -537,6 +665,8 @@
   }
 
   /**
+   * Checks that children of a feed inherit a defined category.
+   *
    * If a feed has a category, make sure that the children inherit that
    * categorization.
    */
@@ -546,14 +676,14 @@
     // Simulate form submission on "admin/config/services/aggregator/add/category".
     $edit = array('title' => $this->randomName(10), 'description' => '');
     $this->drupalPost('admin/config/services/aggregator/add/category', $edit, t('Save'));
-    $this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), t('The category %title has been added.', array('%title' => $edit['title'])));
+    $this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), format_string('The category %title has been added.', array('%title' => $edit['title'])));
 
     $category = db_query("SELECT * FROM {aggregator_category} WHERE title = :title", array(':title' => $edit['title']))->fetch();
-    $this->assertTrue(!empty($category), t('The category found in database.'));
+    $this->assertTrue(!empty($category), 'The category found in database.');
 
     $link_path = 'aggregator/categories/' . $category->cid;
     $menu_link = db_query("SELECT * FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $link_path))->fetch();
-    $this->assertTrue(!empty($menu_link), t('The menu link associated with the category found in database.'));
+    $this->assertTrue(!empty($menu_link), 'The menu link associated with the category found in database.');
 
     $feed = $this->createFeed();
     db_insert('aggregator_category_feed')
@@ -564,7 +694,7 @@
       ->execute();
     $this->updateFeedItems($feed, $this->getDefaultFeedItemCount());
     $this->getFeedCategories($feed);
-    $this->assertTrue(!empty($feed->categories), t('The category found in the feed.'));
+    $this->assertTrue(!empty($feed->categories), 'The category found in the feed.');
 
     // For each category of a feed, ensure feed items have that category, too.
     if (!empty($feed->categories) && !empty($feed->items)) {
@@ -575,15 +705,30 @@
           ->execute()
           ->fetchField();
 
-        $this->assertEqual($feed->item_count, $categorized_count, t('Total items in feed equal to the total categorized feed items in database'));
+        $this->assertEqual($feed->item_count, $categorized_count, 'Total items in feed equal to the total categorized feed items in database');
       }
     }
 
+    // Delete category from feed items when category is deleted.
+    $cid = reset($feed->categories);
+    $categories = $this->getCategories();
+    $category_title = $categories[$cid]->title;
+
+    // Delete category.
+    aggregator_save_category(array('cid' => $cid));
+
+    // Assert category has been removed from feed items.
+    $categorized_count = db_query("SELECT COUNT(*) FROM {aggregator_category_item} WHERE cid = :cid", array(':cid' => $cid))->fetchField();
+    $this->assertFalse($categorized_count, format_string('The category %title has been removed from feed items.', array('%title' => $category_title)));
     // Delete feed.
     $this->deleteFeed($feed);
   }
+
 }
 
+/**
+ * Tests importing feeds from OPML functionality for the Aggregator module.
+ */
 class ImportOPMLTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -594,7 +739,7 @@
   }
 
   /**
-   * Open OPML import form.
+   * Opens OPML import form.
    */
   function openImportForm() {
     db_delete('aggregator_category')->execute();
@@ -608,22 +753,22 @@
       ->execute();
 
     $this->drupalGet('admin/config/services/aggregator/add/opml');
-    $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.'));
+    $this->assertText('A single OPML document may contain a collection of many feeds.', 'Found OPML help text.');
+    $this->assertField('files[upload]', 'Found file upload field.');
+    $this->assertField('remote', 'Found Remote URL field.');
+    $this->assertField('refresh', 'Found Refresh field.');
+    $this->assertFieldByName("category[$cid]", $cid, 'Found category field.');
   }
 
   /**
-   * Submit form filled with invalid fields.
+   * Submits form filled with invalid fields.
    */
   function validateImportFormFields() {
     $before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
 
     $edit = array();
     $this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
-    $this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), t('Error if no fields are filled.'));
+    $this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), 'Error if no fields are filled.');
 
     $path = $this->getEmptyOpml();
     $edit = array(
@@ -631,32 +776,32 @@
       'remote' => file_create_url($path),
     );
     $this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
-    $this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), t('Error if both fields are filled.'));
+    $this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), 'Error if both fields are filled.');
 
     $edit = array('remote' => 'invalidUrl://empty');
     $this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
-    $this->assertText(t('This URL is not valid.'), t('Error if the URL is invalid.'));
+    $this->assertText(t('This URL is not valid.'), 'Error if the URL is invalid.');
 
     $after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
-    $this->assertEqual($before, $after, t('No feeds were added during the three last form submissions.'));
+    $this->assertEqual($before, $after, 'No feeds were added during the three last form submissions.');
   }
 
   /**
-   * Submit form with invalid, empty and valid OPML files.
+   * Submits form with invalid, empty, and valid OPML files.
    */
   function submitImportForm() {
     $before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
 
     $form['files[upload]'] = $this->getInvalidOpml();
     $this->drupalPost('admin/config/services/aggregator/add/opml', $form, t('Import'));
-    $this->assertText(t('No new feed has been added.'), t('Attempting to upload invalid XML.'));
+    $this->assertText(t('No new feed has been added.'), 'Attempting to upload invalid XML.');
 
     $edit = array('remote' => file_create_url($this->getEmptyOpml()));
     $this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
-    $this->assertText(t('No new feed has been added.'), t('Attempting to load empty OPML from remote URL.'));
+    $this->assertText(t('No new feed has been added.'), 'Attempting to load empty OPML from remote URL.');
 
     $after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
-    $this->assertEqual($before, $after, t('No feeds were added during the two last form submissions.'));
+    $this->assertEqual($before, $after, 'No feeds were added during the two last form submissions.');
 
     db_delete('aggregator_feed')->execute();
     db_delete('aggregator_category')->execute();
@@ -680,11 +825,11 @@
       'category[1]'   => $category,
     );
     $this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
-    $this->assertRaw(t('A feed with the URL %url already exists.', array('%url' => $feeds[0]['url'])), t('Verifying that a duplicate URL was identified'));
-    $this->assertRaw(t('A feed named %title already exists.', array('%title' => $feeds[1]['title'])), t('Verifying that a duplicate title was identified'));
+    $this->assertRaw(t('A feed with the URL %url already exists.', array('%url' => $feeds[0]['url'])), 'Verifying that a duplicate URL was identified');
+    $this->assertRaw(t('A feed named %title already exists.', array('%title' => $feeds[1]['title'])), 'Verifying that a duplicate title was identified');
 
     $after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
-    $this->assertEqual($after, 2, t('Verifying that two distinct feeds were added.'));
+    $this->assertEqual($after, 2, 'Verifying that two distinct feeds were added.');
 
     $feeds_from_db = db_query("SELECT f.title, f.url, f.refresh, cf.cid FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} cf ON f.fid = cf.fid");
     $refresh = $category = TRUE;
@@ -695,12 +840,15 @@
       $refresh = $refresh && $feed->refresh == 900;
     }
 
-    $this->assertEqual($title[$feeds[0]['url']], $feeds[0]['title'], t('First feed was added correctly.'));
-    $this->assertEqual($url[$feeds[1]['title']], $feeds[1]['url'], t('Second feed was added correctly.'));
-    $this->assertTrue($refresh, t('Refresh times are correct.'));
-    $this->assertTrue($category, t('Categories are correct.'));
+    $this->assertEqual($title[$feeds[0]['url']], $feeds[0]['title'], 'First feed was added correctly.');
+    $this->assertEqual($url[$feeds[1]['title']], $feeds[1]['url'], 'Second feed was added correctly.');
+    $this->assertTrue($refresh, 'Refresh times are correct.');
+    $this->assertTrue($category, 'Categories are correct.');
   }
 
+  /**
+   * Tests the import of an OPML file.
+   */
   function testOPMLImport() {
     $this->openImportForm();
     $this->validateImportFormFields();
@@ -708,6 +856,9 @@
   }
 }
 
+/**
+ * Tests functionality of the cron process in the Aggregator module.
+ */
 class AggregatorCronTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -718,7 +869,7 @@
   }
 
   /**
-   * Add feeds update them on cron.
+   * Adds feeds and updates them via cron process.
    */
   public function testCron() {
     // Create feed and test basic updating on cron.
@@ -754,6 +905,9 @@
   }
 }
 
+/**
+ * Tests rendering functionality in the Aggregator module.
+ */
 class AggregatorRenderingTestCase extends AggregatorTestCase {
   public static function getInfo() {
     return array(
@@ -764,9 +918,9 @@
   }
 
   /**
-   * Add a feed block to the page and checks its links.
+   * Adds a feed block to the page and checks its links.
    *
-   * TODO: Test the category block as well.
+   * @todo Test the category block as well.
    */
   public function testBlockLinks() {
     // Create feed.
@@ -798,24 +952,34 @@
     $this->assertFieldByName('blocks[' . $block['module'] . '_' . $block['delta'] . '][region]', '', 'Aggregator feed block is available for positioning.');
     // Position it.
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-    $this->assertText(t('The block settings have been updated.'), t('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
+    $this->assertText(t('The block settings have been updated.'), format_string('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
     // Confirm that the block is now being displayed on pages.
     $this->drupalGet('node');
-    $this->assertText(t($block['title']), t('Feed block is displayed on the page.'));
+    $this->assertText(t($block['title']), 'Feed block is displayed on the page.');
 
     // Find the expected read_more link.
     $href = 'aggregator/sources/' . $feed->fid;
     $links = $this->xpath('//a[@href = :href]', array(':href' => url($href)));
-    $this->assert(isset($links[0]), t('Link to href %href found.', array('%href' => $href)));
+    $this->assert(isset($links[0]), format_string('Link to href %href found.', array('%href' => $href)));
 
     // Visit that page.
     $this->drupalGet($href);
     $correct_titles = $this->xpath('//h1[normalize-space(text())=:title]', array(':title' => $feed->title));
-    $this->assertFalse(empty($correct_titles), t('Aggregator feed page is available and has the correct title.'));
+    $this->assertFalse(empty($correct_titles), 'Aggregator feed page is available and has the correct title.');
+
+    // Set the number of news items to 0 to test that the block does not show
+    // up.
+    $feed->block = 0;
+    aggregator_save_feed((array) $feed);
+    // It is necessary to flush the cache after saving the number of items.
+    drupal_flush_all_caches();
+    // Check that the block is no longer displayed.
+    $this->drupalGet('node');
+    $this->assertNoText(t($block['title']), 'Feed block is not displayed on the page when number of items is set to 0.');
   }
 
   /**
-   * Create a feed and check that feed's page.
+   * Creates a feed and checks that feed's page.
    */
   public function testFeedPage() {
     // Increase the number of items published in the rss.xml feed so we have
@@ -830,7 +994,7 @@
     // Check for the presence of a pager.
     $this->drupalGet('aggregator/sources/' . $feed->fid);
     $elements = $this->xpath("//ul[@class=:class]", array(':class' => 'pager'));
-    $this->assertTrue(!empty($elements), t('Individual source page contains a pager.'));
+    $this->assertTrue(!empty($elements), 'Individual source page contains a pager.');
 
     // Reset the number of items in rss.xml to the default value.
     variable_set('feed_default_items', 10);
@@ -838,7 +1002,7 @@
 }
 
 /**
- * Tests for feed parsing.
+ * Tests feed parsing in the Aggregator module.
  */
 class FeedParserTestCase extends AggregatorTestCase {
   public static function getInfo() {
@@ -858,30 +1022,49 @@
   }
 
   /**
-   * Test a feed that uses the RSS 0.91 format.
+   * Tests a feed that uses the RSS 0.91 format.
    */
   function testRSS091Sample() {
     $feed = $this->createFeed($this->getRSS091Sample());
     aggregator_refresh($feed);
     $this->drupalGet('aggregator/sources/' . $feed->fid);
-    $this->assertResponse(200, t('Feed %name exists.', array('%name' => $feed->title)));
+    $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
     $this->assertText('First example feed item title');
     $this->assertLinkByHref('http://example.com/example-turns-one');
     $this->assertText('First example feed item description.');
+
+    // Several additional items that include elements over 255 characters.
+    $this->assertRaw("Second example feed item title.");
+    $this->assertText('Long link feed item title');
+    $this->assertText('Long link feed item description');
+    $this->assertLinkByHref('http://example.com/tomorrow/and/tomorrow/and/tomorrow/creeps/in/this/petty/pace/from/day/to/day/to/the/last/syllable/of/recorded/time/and/all/our/yesterdays/have/lighted/fools/the/way/to/dusty/death/out/out/brief/candle/life/is/but/a/walking/shadow/a/poor/player/that/struts/and/frets/his/hour/upon/the/stage/and/is/heard/no/more/it/is/a/tale/told/by/an/idiot/full/of/sound/and/fury/signifying/nothing');
+    $this->assertText('Long author feed item title');
+    $this->assertText('Long author feed item description');
+    $this->assertLinkByHref('http://example.com/long/author');
   }
 
   /**
-   * Test a feed that uses the Atom format.
+   * Tests a feed that uses the Atom format.
    */
   function testAtomSample() {
     $feed = $this->createFeed($this->getAtomSample());
     aggregator_refresh($feed);
     $this->drupalGet('aggregator/sources/' . $feed->fid);
-    $this->assertResponse(200, t('Feed %name exists.', array('%name' => $feed->title)));
+    $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
     $this->assertText('Atom-Powered Robots Run Amok');
     $this->assertLinkByHref('http://example.org/2003/12/13/atom03');
     $this->assertText('Some text.');
     $this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(':link' => 'http://example.org/2003/12/13/atom03'))->fetchField(), 'Atom entry id element is parsed correctly.');
   }
-}
 
+  /**
+   * Tests a feed that uses HTML entities in item titles.
+   */
+  function testHtmlEntitiesSample() {
+    $feed = $this->createFeed($this->getHtmlEntitiesSample());
+    aggregator_refresh($feed);
+    $this->drupalGet('aggregator/sources/' . $feed->fid);
+    $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
+    $this->assertRaw("Quote&quot; Amp&amp;");
+  }
+}
diff -Naur drupal-7.9/modules/aggregator/tests/aggregator_test.info drupal-7.58/modules/aggregator/tests/aggregator_test.info
--- drupal-7.9/modules/aggregator/tests/aggregator_test.info	2011-10-26 22:25:30.000000000 +0200
+++ drupal-7.58/modules/aggregator/tests/aggregator_test.info	2018-03-28 21:06:59.000000000 +0200
@@ -5,8 +5,8 @@
 core = 7.x
 hidden = TRUE
 
-; Information added by drupal.org packaging script on 2011-10-26
-version = "7.9"
+; Information added by Drupal.org packaging script on 2018-03-28
+version = "7.58"
 project = "drupal"
-datestamp = "1319660730"
+datestamp = "1522264019"
 
diff -Naur drupal-7.9/modules/aggregator/tests/aggregator_test.module drupal-7.58/modules/aggregator/tests/aggregator_test.module
--- drupal-7.9/modules/aggregator/tests/aggregator_test.module	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/tests/aggregator_test.module	2018-03-27 21:28:19.000000000 +0200
@@ -32,7 +32,7 @@
   // Send appropriate response. We respond with a 304 not modified on either
   // etag or on last modified.
   if ($use_last_modified) {
-    drupal_add_http_header('Last-Modified', gmdate(DATE_RFC1123, $last_modified));
+    drupal_add_http_header('Last-Modified', gmdate(DATE_RFC7231, $last_modified));
   }
   if ($use_etag) {
     drupal_add_http_header('ETag', $etag);
diff -Naur drupal-7.9/modules/aggregator/tests/aggregator_test_rss091.xml drupal-7.58/modules/aggregator/tests/aggregator_test_rss091.xml
--- drupal-7.9/modules/aggregator/tests/aggregator_test_rss091.xml	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/aggregator/tests/aggregator_test_rss091.xml	2018-03-27 21:28:19.000000000 +0200
@@ -26,5 +26,16 @@
       <link>http://example.com/example-turns-two</link>
       <description>Second example feed item description.</description>
     </item>
+    <item>
+      <title>Long link feed item title.</title>
+      <link>http://example.com/tomorrow/and/tomorrow/and/tomorrow/creeps/in/this/petty/pace/from/day/to/day/to/the/last/syllable/of/recorded/time/and/all/our/yesterdays/have/lighted/fools/the/way/to/dusty/death/out/out/brief/candle/life/is/but/a/walking/shadow/a/poor/player/that/struts/and/frets/his/hour/upon/the/stage/and/is/heard/no/more/it/is/a/tale/told/by/an/idiot/full/of/sound/and/fury/signifying/nothing</link>
+      <description>Long link feed item description.</description>
+    </item>
+    <item>
+      <title>Long author feed item title.</title>
+      <link>http://example.com/long/author</link>
+      <author>I wanted to get out and walk eastward toward the park through the soft twilight, but each time I tried to go I became entangled in some wild, strident argument which pulled me back, as if with ropes, into my chair. Yet high over the city our line of yellow windows must have contributed their share of human secrecy to the casual watcher in the darkening streets, and I was him too, looking up and wondering. I was within and without, simultaneously enchanted and repelled by the inexhaustible variety of life.</author>
+      <description>Long author feed item description.</description>
+    </item>
   </channel>
 </rss>
diff -Naur drupal-7.9/modules/aggregator/tests/aggregator_test_title_entities.xml drupal-7.58/modules/aggregator/tests/aggregator_test_title_entities.xml
--- drupal-7.9/modules/aggregator/tests/aggregator_test_title_entities.xml	1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.58/modules/aggregator/tests/aggregator_test_title_entities.xml	2018-03-27 21:28:19.000000000 +0200
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="0.91">
+  <channel>
+    <title>Example with Entities</title>
+    <link>http://example.com</link>
+    <description>Example RSS Feed With HTML Entities in Title</description>
+    <language>en-us</language>
+    <item>
+      <title>Quote&quot; Amp&amp;</title>
+      <link>http://example.com/example-turns-one</link>
+      <description>Some text.</description>
+    </item>
+  </channel>
+</rss>
diff -Naur drupal-7.9/modules/block/block-admin-display-form.tpl.php drupal-7.58/modules/block/block-admin-display-form.tpl.php
--- drupal-7.9/modules/block/block-admin-display-form.tpl.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/block/block-admin-display-form.tpl.php	2018-03-27 21:28:19.000000000 +0200
@@ -21,6 +21,8 @@
  *
  * @see template_preprocess_block_admin_display_form()
  * @see theme_block_admin_display()
+ *
+ * @ingroup themeable
  */
 ?>
 <?php
diff -Naur drupal-7.9/modules/block/block.admin.inc drupal-7.58/modules/block/block.admin.inc
--- drupal-7.9/modules/block/block.admin.inc	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/block/block.admin.inc	2018-03-27 21:28:19.000000000 +0200
@@ -57,7 +57,7 @@
 }
 
 /**
- * Form builder for the main blocks administration form.
+ * Form constructor for the main block administration form.
  *
  * @param $blocks
  *   An array of blocks, as returned by block_admin_display_prepare_blocks().
@@ -165,7 +165,7 @@
 }
 
 /**
- * Form submission handler for the main blocks administration form.
+ * Form submission handler for block_admin_display_form().
  *
  * @see block_admin_display_form()
  */
@@ -197,10 +197,9 @@
 }
 
 /**
- * Helper function for sorting blocks on admin/structure/block.
+ * Sorts active blocks by region, then by weight; sorts inactive blocks by name.
  *
- * Active blocks are sorted by region, then by weight.
- * Disabled blocks are sorted by name.
+ * Callback for usort() in block_admin_display_prepare_blocks().
  */
 function _block_compare($a, $b) {
   global $theme_key;
@@ -240,7 +239,7 @@
 }
 
 /**
- * Form builder for the block configuration form.
+ * Form constructor for the block configuration form.
  *
  * Also used by block_add_block_form() for adding a new custom block.
  *
@@ -273,7 +272,7 @@
   $form['settings']['title'] = array(
     '#type' => 'textfield',
     '#title' => t('Block title'),
-    '#maxlength' => 64,
+    '#maxlength' => 255,
     '#description' => $block->module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>!placeholder</em> to display no title, or leave blank to use the default block title.', array('!placeholder' => '&lt;none&gt;')),
     '#default_value' => isset($block->title) ? $block->title : '',
     '#weight' => -19,
@@ -441,7 +440,7 @@
 }
 
 /**
- * Form validation handler for the block configuration form.
+ * Form validation handler for block_admin_configure().
  *
  * @see block_admin_configure()
  * @see block_admin_configure_submit()
@@ -459,7 +458,7 @@
 }
 
 /**
- * Form submission handler for the block configuration form.
+ * Form submission handler for block_admin_configure().
  *
  * @see block_admin_configure()
  * @see block_admin_configure_validate()
@@ -519,7 +518,7 @@
 }
 
 /**
- * Form builder for the add block form.
+ * Form constructor for the add block form.
  *
  * @see block_add_block_form_validate()
  * @see block_add_block_form_submit()
@@ -530,7 +529,7 @@
 }
 
 /**
- * Form validation handler for the add block form.
+ * Form validation handler for block_add_block_form().
  *
  * @see block_add_block_form()
  * @see block_add_block_form_submit()
@@ -544,7 +543,7 @@
 }
 
 /**
- * Form submission handler for the add block form.
+ * Form submission handler for block_add_block_form().
  *
  * Saves the new custom block.
  *
@@ -609,7 +608,7 @@
 }
 
 /**
- * Form builder for the custom block deletion form.
+ * Form constructor for the custom block deletion form.
  *
  * @param $module
  *   The name of the module that implements the block to be deleted. This should
@@ -629,7 +628,7 @@
 }
 
 /**
- * Form submission handler for the custom block deletion form.
+ * Form submission handler for block_custom_block_delete().
  *
  * @see block_custom_block_delete()
  */
diff -Naur drupal-7.9/modules/block/block.api.php drupal-7.58/modules/block/block.api.php
--- drupal-7.9/modules/block/block.api.php	2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.58/modules/block/block.api.php	2018-03-27 21:28:19.000000000 +0200
@@ -20,11 +20,11 @@
  * identifier referred to as "delta" (the array key in the return value). Delta
  * values only need to be unique within your module, and they are used in the
  * following ways:
- * - Passed into the other block hooks in your module as an argument to
- *   identify the block being configured or viewed.
+ * - Passed into the other block hooks in your module as an argument to identify
+ *   the block being configured or viewed.
  * - Used to construct the default HTML ID of "block-MODULE-DELTA" applied to
- *   each block when it is rendered (which can then be used for CSS styling or
- *   JavaScript programming).
+ *   each block when it is rendered. This ID may then be used for CSS styling or
+ *   JavaScript programming.
  * - Used to define a theming template suggestion of block__MODULE__DELTA, for
  *   advanced theming possibilities.
  * - Used by other modules to identify your block in hook_block_info_alter() and
@@ -39,43 +39,44 @@
  *   An associative array whose keys define the delta for each block and whose
  *   values contain the block descriptions. Each block description is itself an
  *   associative array, with the following key-value pairs:
- *   - 'info': (required) The human-readable administrative name of the block.
- *     This is used to identify the block on administration screens, and
- *     is not displayed to non-administrative users.
- *   - 'cache': (optional) A bitmask describing what kind of caching is
+ *   - info: (required) The human-readable administrative name of the block.
+ *     This is used to identify the block on administration screens, and is not
+ *     displayed to non-administrative users.
+ *   - cache: (optional) A bitmask describing what kind of caching is
  *     appropriate for the block. Drupal provides the following bitmask
  *     constants for defining cache granularity:
  *     - DRUPAL_CACHE_PER_ROLE (default): The block can change depending on the
  *       roles the user viewing the page belongs to.
  *     - DRUPAL_CACHE_PER_USER: The block can change depending on the user
- *       viewing the page. This setting can be resource-consuming for sites
- *       with large number of users, and should only be used when
+ *       viewing the page. This setting can be resource-consuming for sites with
+ *       large number of users, and should only be used when
  *       DRUPAL_CACHE_PER_ROLE is not sufficient.
- *     - DRUPAL_CACHE_PER_PAGE: The block can change depending on the page
- *       being viewed.
- *     - DRUPAL_CACHE_GLOBAL: The block is the same for every user on every
- *       page where it is visible.
+ *     - DRUPAL_CACHE_PER_PAGE: The block can change depending on the page being
+ *       viewed.
+ *     - DRUPAL_CACHE_GLOBAL: The block is the same for every user on every page
+ *       where it is visible.
+ *     - DRUPAL_CACHE_CUSTOM: The module implements its own caching system.
  *     - 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.
+ *   - properties: (optional) Array of additional metadata to add to the block.
+ *     Common properties include:
+ *     - administrative: Boolean that categorizes this block as usable in an
+ *       administrative context. This might include blocks that 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.
- *   - 'status': (optional) Initial value for block enabled status. (1 =
- *     enabled, 0 = disabled). Most modules do not provide an initial value,
- *     and any value provided can be modified by a user on the block
- *     configuration screen.
- *   - 'region': (optional) Initial value for theme region within which this
- *     block is set. Most modules do not provide an initial value, and
- *     any value provided can be modified by a user on the block configuration
- *     screen. Note: If you set a region that isn't available in the currently
- *     enabled theme, the block will be disabled.
- *   - 'visibility': (optional) Initial value for the visibility flag, which
- *     tells how to interpret the 'pages' value. Possible values are:
+ *   - status: (optional) Initial value for block enabled status. (1 = enabled,
+ *     0 = disabled). Most modules do not provide an initial value, and any
+ *     value provided can be modified by a user on the block configuration
+ *     screen.
+ *   - region: (optional) Initial value for theme region within which this
+ *     block is set. Most modules do not provide an initial value, and any value
+ *     provided can be modified by a user on the block configuration screen.
+ *     Note: If you set a region that isn't available in the currently enabled
+ *     theme, the block will be disabled.
+ *   - visibility: (optional) Initial value for the visibility flag, which tells
+ *     how to interpret the 'pages' value. Possible values are:
  *     - BLOCK_VISIBILITY_NOTLISTED: Show on all pages except listed pages.
  *       'pages' lists the paths where the block should not be shown.
  *     - BLOCK_VISIBILITY_LISTED: Show only on listed pages. 'pages' lists the
@@ -85,7 +86,14 @@
  *     Most modules do not provide an initial value for 'visibility' or 'pages',
  *     and any value provided can be modified by a user on the block
  *     configuration screen.
- *   - 'pages': (optional) See 'visibility' above.
+ *   - pages: (optional) See 'visibility' above. A string that contains one or
+ *     more page paths separated by "\n", "\r", or "\r\n" when 'visibility' is
+ *     set to BLOCK_VISIBILITY_NOTLISTED or BLOCK_VISIBILITY_LISTED (example:
+ *     "<front>\nnode/1"), or custom PHP code when 'visibility' is set to
+ *     BLOCK_VISIBILITY_PHP. Paths may use '*' as a wildcard (matching any
+ *     number of characters); '<front>' designates the site's front page. For
+ *     BLOCK_VISIBILITY_PHP, the PHP code's ret