diff --git a/core/authorize.php b/core/authorize.php
index 114dcd3..8afa471 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -32,9 +32,9 @@
  * 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).
+ * such as 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).
  */
 const MAINTENANCE_MODE = 'update';
 
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 97b73f4..fda84b8 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2428,8 +2428,7 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
  * $options['preprocess'] should be only set to TRUE when a file is required for
  * all typical visitors and most pages of a site. It is critical that all
  * preprocessed files are added unconditionally on every page, even if the
- * files do not happen to be needed on a page. This is normally done by calling
- * drupal_add_css() in a hook_init() implementation.
+ * files do not happen to be needed on a page.
  *
  * Non-preprocessed files should only be added to the page when they are
  * actually needed.
@@ -2483,23 +2482,22 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
  *     enabled, this should be set to TRUE if the stylesheet is present on every
  *     page of the website for users for whom it is present at all. This
  *     defaults to FALSE. It is set to TRUE for stylesheets added via module and
- *     theme .info files. Modules that add stylesheets within hook_init()
- *     implementations, or from other code that ensures that the stylesheet is
- *     added to all website pages, should also set this flag to TRUE. All
- *     stylesheets within the same group that have the 'every_page' flag set to
- *     TRUE and do not have 'preprocess' set to FALSE are aggregated together
- *     into a single aggregate file, and that aggregate file can be reused
- *     across a user's entire site visit, leading to faster navigation between
- *     pages. However, stylesheets that are only needed on pages less frequently
- *     visited, can be added by code that only runs for those particular pages,
- *     and that code should not set the 'every_page' flag. This minimizes the
- *     size of the aggregate file that the user needs to download when first
- *     visiting the website. Stylesheets without the 'every_page' flag are
- *     aggregated into a separate aggregate file. This other aggregate file is
- *     likely to change from page to page, and each new aggregate file needs to
- *     be downloaded when first encountered, so it should be kept relatively
- *     small by ensuring that most commonly needed stylesheets are added to
- *     every page.
+ *     theme .info files. Modules that add stylesheets from code that ensures
+ *     that the stylesheet is added to all website pages, should also set this
+ *     flag to TRUE. All stylesheets within the same group that have the
+ *     'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
+ *     are aggregated together into a single aggregate file, and that aggregate
+ *     file can be reused across a user's entire site visit, leading to faster
+ *     navigation between pages. However, stylesheets that are only needed on
+ *     pages less frequently visited, can be added by code that only runs for
+ *     those particular pages, and that code should not set the 'every_page'
+ *     flag. This minimizes the size of the aggregate file that the user needs
+ *     to download when first visiting the website. Stylesheets without the
+ *     'every_page' flag are aggregated into a separate aggregate file. This
+ *     other aggregate file is likely to change from page to page, and each new
+ *     aggregate file needs to be downloaded when first encountered, so it
+ *     should be kept relatively small by ensuring that most commonly needed
+ *     stylesheets are added to every page.
  *   - 'weight': The weight of the stylesheet specifies the order in which the
  *     CSS will appear relative to other stylesheets with the same group and
  *     'every_page' flag. The exact ordering of stylesheets is as follows:
@@ -3564,8 +3562,7 @@ function drupal_region_class($region) {
  * $options['preprocess'] should be only set to TRUE when a file is required for
  * all typical visitors and most pages of a site. It is critical that all
  * preprocessed files are added unconditionally on every page, even if the
- * files are not needed on a page. This is normally done by calling
- * drupal_add_js() in a hook_init() implementation.
+ * files are not needed on a page.
  *
  * Non-preprocessed files should only be added to the page when they are
  * actually needed.
@@ -3607,23 +3604,22 @@ function drupal_region_class($region) {
  *     enabled, this should be set to TRUE if the JavaScript is present on every
  *     page of the website for users for whom it is present at all. This
  *     defaults to FALSE. It is set to TRUE for JavaScript files that are added
- *     via module and theme .info files. Modules that add JavaScript within
- *     hook_init() implementations, or from other code that ensures that the
- *     JavaScript is added to all website pages, should also set this flag to
- *     TRUE. All JavaScript files within the same group and that have the
- *     'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
- *     are aggregated together into a single aggregate file, and that aggregate
- *     file can be reused across a user's entire site visit, leading to faster
- *     navigation between pages. However, JavaScript that is only needed on
- *     pages less frequently visited, can be added by code that only runs for
- *     those particular pages, and that code should not set the 'every_page'
- *     flag. This minimizes the size of the aggregate file that the user needs
- *     to download when first visiting the website. JavaScript without the
- *     'every_page' flag is aggregated into a separate aggregate file. This
- *     other aggregate file is likely to change from page to page, and each new
- *     aggregate file needs to be downloaded when first encountered, so it
- *     should be kept relatively small by ensuring that most commonly needed
- *     JavaScript is added to every page.
+ *     via module and theme .info files. Modules that add JavaScript from code
+ *     that ensures that the JavaScript is added to all website pages, should
+ *     also set this flag to TRUE. All JavaScript files within the same group
+ *     and that have the 'every_page' flag set to TRUE and do not have
+ *     'preprocess' set to FALSE are aggregated together into a single
+ *     aggregate file, and that aggregate file can be reused across a user's
+ *     entire site visit, leading to faster navigation between pages. However,
+ *     JavaScript that is only needed on pages less frequently visited, can be
+ *     added by code that only runs for those particular pages, and that code
+ *     should not set the 'every_page' flag. This minimizes the size of the
+ *     aggregate file that the user needs to download when first visiting the
+ *     website. JavaScript without the 'every_page' flag is aggregated into a
+ *     separate aggregate file. This other aggregate file is likely to change
+ *     from page to page, and each new aggregate file needs to be downloaded
+ *     when first encountered, so it should be kept relatively small by
+ *     ensuring that most commonly needed JavaScript is added to every page.
  *   - weight: A number defining the order in which the JavaScript is added to
  *     the page relative to other JavaScript with the same 'scope', 'group',
  *     and 'every_page' value. In some cases, the order in which the JavaScript
@@ -4876,16 +4872,8 @@ function _drupal_bootstrap_full($skip = FALSE) {
   // Let all modules take action before the menu system handles the request.
   // We do not want this while running update.php.
   if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
-    // Prior to invoking hook_init(), initialize the theme (potentially a custom
-    // one for this page), so that:
-    // - Modules with hook_init() implementations that call theme() or
-    //   theme_get_registry() don't initialize the incorrect theme.
-    // - The theme can have hook_*_alter() implementations affect page building
-    //   (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()),
-    //   ahead of when rendering starts.
     menu_set_custom_theme();
     drupal_theme_initialize();
-    module_invoke_all('init');
   }
 }
 
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 508e01b..c1bbdc0 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -99,8 +99,8 @@ function update_prepare_d8_bootstrap() {
   // by default to avoid exceptions.
   $GLOBALS['conf']['cache_classes'] = array('cache' => 'Drupal\Core\Cache\NullBackend');
 
-  // Enable UpdateBundle service overrides.
-  $GLOBALS['conf']['container_bundles'][] = 'Drupal\Core\DependencyInjection\UpdateBundle';
+  // Enable UpdateAPIBundle service overrides.
+  $GLOBALS['conf']['container_bundles'][] = 'Drupal\Core\DependencyInjection\UpdateAPIBundle';
 
   // Bootstrap the kernel.
   // Do not attempt to dump and write it.
diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateAPIBundle.php b/core/lib/Drupal/Core/DependencyInjection/UpdateAPIBundle.php
new file mode 100644
index 0000000..6851b6b
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/UpdateAPIBundle.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\UpdateAPIBundle.
+ */
+
+namespace Drupal\Core\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Update API dependency injection container.
+ *
+ * This bundle is manually added by update.php via $conf['container_bundles']
+ * and required to prevent various services from trying to retrieve data from
+ * storages that do not exist yet.
+ */
+class UpdateAPIBundle extends Bundle {
+
+  /**
+   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
+   */
+  public function build(SymfonyContainerBuilder $container) {
+    // Disable the Lock service.
+    $container
+      ->register('lock', 'Drupal\Core\Lock\NullLockBackend');
+
+    // Prevent config from accessing {cache_config}.
+    // @see $conf['cache_classes'], update_prepare_d8_bootstrap()
+    $container
+      ->register('config.storage', 'Drupal\Core\Config\FileStorage')
+      ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY));
+  }
+}
diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php b/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php
deleted file mode 100644
index 06a9522..0000000
--- a/core/lib/Drupal/Core/DependencyInjection/UpdateBundle.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\DependencyInjection\UpdateBundle.
- */
-
-namespace Drupal\Core\DependencyInjection;
-
-use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
-use Symfony\Component\HttpKernel\Bundle\Bundle;
-
-/**
- * Bundle class for update.php service overrides.
- *
- * This bundle is manually added by update.php via $conf['container_bundles']
- * and required to prevent various services from trying to retrieve data from
- * storages that do not exist yet.
- */
-class UpdateBundle extends Bundle {
-
-  /**
-   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
-   */
-  public function build(SymfonyContainerBuilder $container) {
-    // Disable the Lock service.
-    $container
-      ->register('lock', 'Drupal\Core\Lock\NullLockBackend');
-
-    // Prevent config from accessing {cache_config}.
-    // @see $conf['cache_classes'], update_prepare_d8_bootstrap()
-    $container
-      ->register('config.storage', 'Drupal\Core\Config\FileStorage')
-      ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY));
-  }
-
-}
diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
index 242f935..39828ef 100644
--- a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
@@ -27,16 +27,8 @@ class LegacyRequestSubscriber implements EventSubscriberInterface {
    */
   public function onKernelRequestLegacy(GetResponseEvent $event) {
     if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      // Prior to invoking hook_init(), initialize the theme (potentially a
-      // custom one for this page), so that:
-      // - Modules with hook_init() implementations that call theme() or
-      //   theme_get_registry() don't initialize the incorrect theme.
-      // - The theme can have hook_*_alter() implementations affect page
-      //   building (e.g., hook_form_alter(), hook_node_view_alter(),
-      //   hook_page_alter()), ahead of when rendering starts.
       menu_set_custom_theme();
       drupal_theme_initialize();
-      module_invoke_all('init');
 
       // Tell Drupal it is now fully bootstrapped (for the benefit of code that
       // calls drupal_get_bootstrap_phase()), but without having
diff --git a/core/modules/action/tests/action_loop_test/action_loop_test.module b/core/modules/action/tests/action_loop_test/action_loop_test.module
index 8c3b98d..88f1ce6 100644
--- a/core/modules/action/tests/action_loop_test/action_loop_test.module
+++ b/core/modules/action/tests/action_loop_test/action_loop_test.module
@@ -20,15 +20,6 @@ function action_loop_test_watchdog(array $log_entry) {
 }
 
 /**
- * Implements hook_init().
- */
-function action_loop_test_init() {
-  if (!empty($_GET['trigger_action_on_watchdog'])) {
-    watchdog_skip_semaphore('action_loop_test', 'Triggering action loop');
-  }
-}
-
-/**
  * Implements hook_action_info().
  */
 function action_loop_test_action_info() {
diff --git a/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/ActionLoopTestBundle.php b/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/ActionLoopTestBundle.php
new file mode 100644
index 0000000..0e7a647
--- /dev/null
+++ b/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/ActionLoopTestBundle.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\ActionLoopTestBundle.
+ */
+
+namespace Drupal\Core\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Action loop test dependency injection container.
+ */
+class ActionLoopTestBundle extends Bundle {
+
+  /**
+   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
+   */
+  public function build(SymfonyContainerBuilder $container) {
+    $container->register('action_loop_test.subscriber', 'Drupal\action_loop_test\EventSubscriber\ActionLoopTestSubscriber')
+      ->addTag('event_subscriber');
+    }
+}
diff --git a/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/EventSubscriber/ActionLoopTestSubscriber.php b/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/EventSubscriber/ActionLoopTestSubscriber.php
new file mode 100644
index 0000000..7cb6d59
--- /dev/null
+++ b/core/modules/action/tests/action_loop_test/lib/Drupal/action_loop_test/EventSubscriber/ActionLoopTestSubscriber.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\action_loop_test\EventSubscriber\ActionLoopTestSubscriber.
+ */
+
+namespace Drupal\action_loop_test\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Action loop test subscriber for controller requests.
+ */
+class ActionLoopTestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The request service.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request = NULL;
+
+  /**
+   * Implements __construct().
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request service.
+   */
+  function __construct(Request $request) {
+    $this->request = $request;
+  }
+
+  /**
+   * Implements event handler for kernel.request.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    if ($this->request->query->get('trigger_action_on_watchdog')) {
+      watchdog_skip_semaphore('action_loop_test', 'Triggering action loop');
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index cb97937..4adb87b 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -9,16 +9,6 @@
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 /**
- * Implements hook_init().
- */
-function language_test_init() {
-  language_test_store_language_negotiation();
-  if (isset(language(LANGUAGE_TYPE_INTERFACE)->langcode) && isset(language(LANGUAGE_TYPE_INTERFACE)->method_id)) {
-    drupal_set_message(t('Language negotiation method: @name', array('@name' => language(LANGUAGE_TYPE_INTERFACE)->method_id)));
-  }
-}
-
-/**
  * Implements hook_language_types_info().
  */
 function language_test_language_types_info() {
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/EventSubscriber/LanguageTestSubscriber.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/EventSubscriber/LanguageTestSubscriber.php
new file mode 100644
index 0000000..c5f2e9f
--- /dev/null
+++ b/core/modules/language/tests/language_test/lib/Drupal/language_test/EventSubscriber/LanguageTestSubscriber.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language_test\EventSubscriber\LanguageTestSubscriber.
+ */
+
+namespace Drupal\language_test\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Language test subscriber for controller requests.
+ */
+class LanguageTestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements event handler for kernel.request.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    language_test_store_language_negotiation();
+    if (isset(language(LANGUAGE_TYPE_INTERFACE)->langcode) && isset(language(LANGUAGE_TYPE_INTERFACE)->method_id)) {
+      drupal_set_message(t('Language negotiation method: @name', array('@name' => language(LANGUAGE_TYPE_INTERFACE)->method_id)));
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestBundle.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestBundle.php
index b711507..2cb7046 100644
--- a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestBundle.php
+++ b/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestBundle.php
@@ -19,6 +19,9 @@ class LanguageTestBundle extends Bundle {
    * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
    */
   public function build(ContainerBuilder $container) {
+    $container->register('language_test.subscriber', 'Drupal\language_test\EventSubscriber\LanguageTestSubscriber')
+      ->addTag('event_subscriber');
+
     // Overrides language_manager class to test domain language negotiation.
     $definition = $container->getDefinition('language_manager');
     $definition->setClass('Drupal\language_test\LanguageTestManager');
diff --git a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
new file mode 100644
index 0000000..2c2b345
--- /dev/null
+++ b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\overlay\EventSubscriber\OverlaySubscriber.
+ */
+
+namespace Drupal\overlay\EventSubscriber;
+
+use Drupal\user\UserDataInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Overlay subscriber for controller requests.
+ */
+class OverlaySubscriber implements EventSubscriberInterface {
+
+  /**
+   * The user.data service.
+   *
+   * @var \Drupal\user\UserDataInterface
+   */
+  protected $userData = NULL;
+
+  /**
+   * Implements __construct().
+   *
+   * @param \Drupal\user\UserDataInterface $user_data
+   *   The user.data service.
+   */
+  function __construct(UserDataInterface $user_data) {
+    $this->userData = $user_data;
+  }
+
+  /**
+   * Implements event handler for kernel.request.
+   *
+   * Determine whether the current page request is destined to appear in the
+   * parent window or in the overlay window, and format the page accordingly.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    global $user;
+
+    $mode = overlay_get_mode();
+
+    // Only act if the user has access to the overlay and a mode was not already
+    // set. Other modules can also enable the overlay directly for other uses.
+    $user_data = drupal_container()->get('user.data')->get('overlay', $user->uid, 'enabled');
+    $use_overlay = !isset($user_data) || $user_data;
+    if (empty($mode) && user_access('access overlay') && $use_overlay) {
+      $current_path = current_path();
+      // After overlay is enabled on the modules page, redirect to
+      // <front>#overlay=admin/modules to actually enable the overlay.
+      // @see overlay_enable().
+      if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
+        unset($_SESSION['overlay_enable_redirect']);
+        drupal_goto('<front>', array('fragment' => 'overlay=' . $current_path));
+      }
+
+      if (isset($_GET['render']) && $_GET['render'] == 'overlay') {
+        // If a previous page requested that we close the overlay, close it and
+        // redirect to the final destination.
+        if (isset($_SESSION['overlay_close_dialog'])) {
+          call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
+          unset($_SESSION['overlay_close_dialog']);
+        }
+        // If this page shouldn't be rendered inside the overlay, redirect to the
+        // parent.
+        elseif (!path_is_admin($current_path)) {
+          overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
+        }
+
+        // Indicate that we are viewing an overlay child page.
+        overlay_set_mode('child');
+
+        // Unset the render parameter to avoid it being included in URLs on the page.
+        unset($_GET['render']);
+      }
+      // Do not enable the overlay if we already are on an admin page.
+      elseif (!path_is_admin($current_path)) {
+        // Otherwise add overlay parent code and our behavior.
+        overlay_set_mode('parent');
+      }
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/overlay/lib/Drupal/overlay/OverlayBundle.php b/core/modules/overlay/lib/Drupal/overlay/OverlayBundle.php
new file mode 100644
index 0000000..18502ef
--- /dev/null
+++ b/core/modules/overlay/lib/Drupal/overlay/OverlayBundle.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\overlay\OverlayBundle.
+ */
+
+namespace Drupal\overlay;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Overlay dependency injection container.
+ */
+class OverlayBundle extends Bundle {
+
+  /**
+   * Overrides Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    $container->register('overlay.subscriber', 'Drupal\overlay\EventSubscriber\OverlaySubscriber')
+      ->addArgument(new Reference('user.data'))
+      ->addTag('event_subscriber');
+  }
+}
diff --git a/core/modules/overlay/overlay.install b/core/modules/overlay/overlay.install
index 588f871..1d67314 100644
--- a/core/modules/overlay/overlay.install
+++ b/core/modules/overlay/overlay.install
@@ -13,7 +13,8 @@
  */
 function overlay_enable() {
   if (strpos(current_path(), 'admin/modules') === 0) {
-    // Flag for a redirect to <front>#overlay=admin/modules on hook_init().
+    // Flag for a redirect to <front>#overlay=admin/modules.
+    // @see \Drupal\overlay\EventSubscriber\OverlaySubscriber::onRequest().
     $_SESSION['overlay_enable_redirect'] = 1;
   }
 }
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 1893a15..d2bb428 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -112,59 +112,6 @@ function overlay_user_update($account) {
 }
 
 /**
- * Implements hook_init().
- *
- * Determine whether the current page request is destined to appear in the
- * parent window or in the overlay window, and format the page accordingly.
- *
- * @see overlay_set_mode()
- */
-function overlay_init() {
-  global $user;
-
-  $mode = overlay_get_mode();
-
-  // Only act if the user has access to the overlay and a mode was not already
-  // set. Other modules can also enable the overlay directly for other uses.
-  $user_data = drupal_container()->get('user.data')->get('overlay', $user->uid, 'enabled');
-  $use_overlay = !isset($user_data) || $user_data;
-  if (empty($mode) && user_access('access overlay') && $use_overlay) {
-    $current_path = current_path();
-    // After overlay is enabled on the modules page, redirect to
-    // <front>#overlay=admin/modules to actually enable the overlay.
-    if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
-      unset($_SESSION['overlay_enable_redirect']);
-      drupal_goto('<front>', array('fragment' => 'overlay=' . $current_path));
-    }
-
-    if (isset($_GET['render']) && $_GET['render'] == 'overlay') {
-      // If a previous page requested that we close the overlay, close it and
-      // redirect to the final destination.
-      if (isset($_SESSION['overlay_close_dialog'])) {
-        call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
-        unset($_SESSION['overlay_close_dialog']);
-      }
-      // If this page shouldn't be rendered inside the overlay, redirect to the
-      // parent.
-      elseif (!path_is_admin($current_path)) {
-        overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
-      }
-
-      // Indicate that we are viewing an overlay child page.
-      overlay_set_mode('child');
-
-      // Unset the render parameter to avoid it being included in URLs on the page.
-      unset($_GET['render']);
-    }
-    // Do not enable the overlay if we already are on an admin page.
-    elseif (!path_is_admin($current_path)) {
-      // Otherwise add overlay parent code and our behavior.
-      overlay_set_mode('parent');
-    }
-  }
-}
-
-/**
  * Implements hook_exit().
  *
  * When viewing an overlay child page, check if we need to trigger a refresh of
@@ -641,8 +588,7 @@ function overlay_get_mode() {
  *     being used. For example, since the overlay module itself sets the mode
  *     to 'parent' or 'child' in overlay_init() when certain conditions are
  *     met, other modules which want to override that behavior can do so by
- *     setting the mode to 'none' earlier in the page request - e.g., in their
- *     own hook_init() implementations, if they have a lower weight.
+ *     setting the mode to 'none' earlier in the page request.
  *   This parameter is optional, and if omitted, the current mode will be
  *   returned with no action taken.
  *
diff --git a/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php b/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php
new file mode 100644
index 0000000..991b89f
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\EventSubscriber\SystemSubscriber.
+ */
+
+namespace Drupal\system\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * System subscriber for controller requests.
+ */
+class SystemSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements event handler for kernel.request.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    // Ignore slave database servers for this request.
+    //
+    // In Drupal's distributed database structure, new data is written to the master
+    // and then propagated to the slave servers.  This means there is a lag
+    // between when data is written to the master and when it is available on the slave.
+    // At these times, we will want to avoid using a slave server temporarily.
+    // For example, if a user posts a new node then we want to disable the slave
+    // server for that user temporarily to allow the slave server to catch up.
+    // That way, that user will see their changes immediately while for other
+    // users we still get the benefits of having a slave server, just with slightly
+    // stale data.  Code that wants to disable the slave server should use the
+    // db_set_ignore_slave() function to set $_SESSION['ignore_slave_server'] to
+    // the timestamp after which the slave can be re-enabled.
+    if (isset($_SESSION['ignore_slave_server'])) {
+      if ($_SESSION['ignore_slave_server'] >= REQUEST_TIME) {
+        Database::ignoreTarget('default', 'slave');
+      }
+      else {
+        unset($_SESSION['ignore_slave_server']);
+      }
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/SystemBundle.php b/core/modules/system/lib/Drupal/system/SystemBundle.php
index 8662169..b639316 100644
--- a/core/modules/system/lib/Drupal/system/SystemBundle.php
+++ b/core/modules/system/lib/Drupal/system/SystemBundle.php
@@ -21,6 +21,8 @@ class SystemBundle extends Bundle {
   public function build(ContainerBuilder $container) {
     $container->register('access_check.cron', 'Drupal\system\Access\CronAccessCheck')
       ->addTag('access_check');
+    $container->register('system.subscriber', 'Drupal\system\EventSubscriber\SystemSubscriber')
+      ->addTag('event_subscriber');
 
     // Register the various system plugin manager classes with the dependency
     // injection container.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/HookInitTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/HookInitTest.php
deleted file mode 100644
index 3863d22..0000000
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/HookInitTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Theme\HookInitTest.
- */
-
-namespace Drupal\system\Tests\Theme;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Functional test for initialization of the theme system in hook_init().
- */
-class HookInitTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('theme_test');
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Theme initialization in hook_init()',
-      'description' => 'Tests that the theme system can be correctly initialized in hook_init().',
-      'group' => 'Theme',
-    );
-  }
-
-  /**
-   * Test that the theme system can generate output when called by hook_init().
-   */
-  function testThemeInitializationHookInit() {
-    $this->drupalGet('theme-test/hook-init');
-    // Verify that themed output generated in hook_init() appears.
-    $this->assertRaw('Themed output generated in hook_init()');
-    // Verify that the default theme's CSS still appears when the theme system
-    // is initialized in hook_init().
-    $this->assertRaw('stark/css/layout.css');
-  }
-}
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 528eb02..4a36dd9 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -1451,25 +1451,6 @@ function hook_forms($form_id, $args) {
 }
 
 /**
- * Perform setup tasks for non-cached page requests.
- *
- * This hook is run at the beginning of the page request. It is typically
- * used to set up global parameters that are needed later in the request.
- * When this hook is called, the theme and all modules are already loaded in
- * memory.
- *
- * This hook is not run on cached pages.
- *
- * @see hook_exit()
- *
- * Do not use this hook to add CSS/JS to pages, use hook_page_build() instead.
- *
- * @see hook_page_build()
- */
-function hook_init() {
-}
-
-/**
  * Define image toolkits provided by this module.
  *
  * The file which includes each toolkit's functions must be declared as part of
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 8ba745c..135fe4c 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2488,33 +2488,6 @@ function system_filetransfer_info() {
 }
 
 /**
- * Implements hook_init().
- */
-function system_init() {
-  // Ignore slave database servers for this request.
-  //
-  // In Drupal's distributed database structure, new data is written to the master
-  // and then propagated to the slave servers.  This means there is a lag
-  // between when data is written to the master and when it is available on the slave.
-  // At these times, we will want to avoid using a slave server temporarily.
-  // For example, if a user posts a new node then we want to disable the slave
-  // server for that user temporarily to allow the slave server to catch up.
-  // That way, that user will see their changes immediately while for other
-  // users we still get the benefits of having a slave server, just with slightly
-  // stale data.  Code that wants to disable the slave server should use the
-  // db_set_ignore_slave() function to set $_SESSION['ignore_slave_server'] to
-  // the timestamp after which the slave can be re-enabled.
-  if (isset($_SESSION['ignore_slave_server'])) {
-    if ($_SESSION['ignore_slave_server'] >= REQUEST_TIME) {
-      Database::ignoreTarget('default', 'slave');
-    }
-    else {
-      unset($_SESSION['ignore_slave_server']);
-    }
-  }
-}
-
-/**
  * Implements hook_page_build().
  */
 function system_page_build(&$page) {
diff --git a/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/EventSubscriber/MenuTestSubscriber.php b/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/EventSubscriber/MenuTestSubscriber.php
new file mode 100644
index 0000000..0e291b7
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/EventSubscriber/MenuTestSubscriber.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_test\EventSubscriber\MenuTestSubscriber.
+ */
+
+namespace Drupal\menu_test\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Menu test subscriber for controller requests.
+ */
+class MenuTestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements event handler for kernel.request.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    // When requested by one of the MenuTrailTestCase tests, record the initial
+    // active trail during Drupal's bootstrap (before the user is redirected to a
+    // custom 403 or 404 page). See menu_test_custom_403_404_callback().
+    $state = drupal_container()->get('state');
+    if ($state->get('menu_test.record_active_trail') ?: FALSE) {
+      $state->set('menu_test.active_trail_initial', menu_get_active_trail());
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/MenuTestBundle.php b/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/MenuTestBundle.php
new file mode 100644
index 0000000..40ce739
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/lib/Drupal/menu_test/MenuTestBundle.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\MenuTestBundle.
+ */
+
+namespace Drupal\menu_test;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Menu test dependency injection container.
+ */
+class MenuTestBundle extends Bundle {
+
+  /**
+   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
+   */
+  public function build(SymfonyContainerBuilder $container) {
+    $container->register('menu_test.subscriber', 'Drupal\menu_test\EventSubscriber\MenuTestSubscriber')
+      ->addTag('event_subscriber');
+  }
+}
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module
index 36cef57..955a221 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.module
+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -402,18 +402,6 @@ function menu_test_menu_trail_callback() {
 }
 
 /**
- * Implements hook_init().
- */
-function menu_test_init() {
-  // When requested by one of the MenuTrailTestCase tests, record the initial
-  // active trail during Drupal's bootstrap (before the user is redirected to a
-  // custom 403 or 404 page). See menu_test_custom_403_404_callback().
-  if (state()->get('menu_test.record_active_trail') ?: FALSE) {
-    state()->set('menu_test.active_trail_initial', menu_get_active_trail());
-  }
-}
-
-/**
  * Callback for our custom 403 and 404 pages.
  */
 function menu_test_custom_403_404_callback() {
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index 73ff44b..b84a405 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -49,11 +49,6 @@ function theme_test_menu() {
     'theme callback' => '_theme_custom_theme',
     'type' => MENU_CALLBACK,
   );
-  $items['theme-test/hook-init'] = array(
-    'page callback' => 'theme_test_hook_init_page_callback',
-    'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
-  );
   $items['theme-test/template-test'] = array(
     'page callback' => 'theme_test_template_test_page_callback',
     'access callback' => TRUE,
@@ -68,28 +63,6 @@ function theme_test_menu() {
 }
 
 /**
- * Implements hook_init().
- */
-function theme_test_init() {
-  if (arg(0) == 'theme-test' && arg(1) == 'hook-init') {
-    // First, force the theme registry to be rebuilt on this page request. This
-    // allows us to test a full initialization of the theme system in the code
-    // below.
-    drupal_theme_rebuild();
-    // Next, initialize the theme system by storing themed text in a global
-    // variable. We will use this later in theme_test_hook_init_page_callback()
-    // to test that even when the theme system is initialized this early, it is
-    // still capable of returning output and theming the page as a whole.
-    $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()'));
-  }
-  if (arg(0) == 'user' && arg(1) == 'autocomplete') {
-    // Register a fake registry loading callback. If it gets called by
-    // theme_get_registry(), the registry has not been initialized yet.
-    _theme_registry_callback('_theme_test_load_registry', array());
-  }
-}
-
-/**
  * Fake registry loading callback.
  */
 function _theme_test_load_registry() {
@@ -98,13 +71,6 @@ function _theme_test_load_registry() {
 }
 
 /**
- * Menu callback for testing themed output generated in hook_init().
- */
-function theme_test_hook_init_page_callback() {
-  return $GLOBALS['theme_test_output'];
-}
-
-/**
  * Menu callback for testing template overridding based on filename.
  */
 function theme_test_template_test_page_callback() {
diff --git a/core/modules/update/lib/Drupal/update/EventSubscriber/UpdateSubscriber.php b/core/modules/update/lib/Drupal/update/EventSubscriber/UpdateSubscriber.php
new file mode 100644
index 0000000..b9c30d7
--- /dev/null
+++ b/core/modules/update/lib/Drupal/update/EventSubscriber/UpdateSubscriber.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\update\EventSubscriber\UpdateSubscriber.
+ */
+
+namespace Drupal\update\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Update subscriber for controller requests.
+ */
+class UpdateSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Implements event handler for kernel.request.
+   */
+  public function onRequest(GetResponseEvent $event) {
+    if (arg(0) == 'admin' && user_access('administer site configuration')) {
+      switch (current_path()) {
+        // These pages don't need additional nagging.
+        case 'admin/appearance/update':
+        case 'admin/appearance/install':
+        case 'admin/modules/update':
+        case 'admin/modules/install':
+        case 'admin/reports/updates':
+        case 'admin/reports/updates/update':
+        case 'admin/reports/updates/install':
+        case 'admin/reports/updates/settings':
+        case 'admin/reports/status':
+        case 'admin/update/ready':
+          return;
+
+        // If we are on the appearance or modules list, display a detailed report
+        // of the update status.
+        case 'admin/appearance':
+        case 'admin/modules':
+          $verbose = TRUE;
+          break;
+
+      }
+      module_load_install('update');
+      $status = update_requirements('runtime');
+      foreach (array('core', 'contrib') as $report_type) {
+        $type = 'update_' . $report_type;
+        if (!empty($verbose)) {
+          if (isset($status[$type]['severity'])) {
+            if ($status[$type]['severity'] == REQUIREMENT_ERROR) {
+              drupal_set_message($status[$type]['description'], 'error');
+            }
+            elseif ($status[$type]['severity'] == REQUIREMENT_WARNING) {
+              drupal_set_message($status[$type]['description'], 'warning');
+            }
+          }
+        }
+        // Otherwise, if we're on *any* admin page and there's a security
+        // update missing, print an error message about it.
+        else {
+          if (isset($status[$type])
+              && isset($status[$type]['reason'])
+              && $status[$type]['reason'] === UPDATE_NOT_SECURE) {
+            drupal_set_message($status[$type]['description'], 'error');
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onRequest');
+    return $events;
+  }
+
+}
diff --git a/core/modules/update/lib/Drupal/update/UpdateBundle.php b/core/modules/update/lib/Drupal/update/UpdateBundle.php
new file mode 100644
index 0000000..2d0f2ba
--- /dev/null
+++ b/core/modules/update/lib/Drupal/update/UpdateBundle.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\update\UpdateBundle.
+ */
+
+namespace Drupal\update;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Update dependency injection container.
+ */
+class UpdateBundle extends Bundle {
+
+  /**
+   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
+   */
+  public function build(SymfonyContainerBuilder $container) {
+    $container->register('update.subscriber', 'Drupal\update\EventSubscriber\UpdateSubscriber')
+      ->addTag('event_subscriber');
+  }
+}
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 00ef879..5d3796f 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -96,60 +96,6 @@ function update_help($path, $arg) {
 }
 
 /**
- * Implements hook_init().
- */
-function update_init() {
-  if (arg(0) == 'admin' && user_access('administer site configuration')) {
-    switch (current_path()) {
-      // These pages don't need additional nagging.
-      case 'admin/appearance/update':
-      case 'admin/appearance/install':
-      case 'admin/modules/update':
-      case 'admin/modules/install':
-      case 'admin/reports/updates':
-      case 'admin/reports/updates/update':
-      case 'admin/reports/updates/install':
-      case 'admin/reports/updates/settings':
-      case 'admin/reports/status':
-      case 'admin/update/ready':
-        return;
-
-      // If we are on the appearance or modules list, display a detailed report
-      // of the update status.
-      case 'admin/appearance':
-      case 'admin/modules':
-        $verbose = TRUE;
-        break;
-
-    }
-    module_load_install('update');
-    $status = update_requirements('runtime');
-    foreach (array('core', 'contrib') as $report_type) {
-      $type = 'update_' . $report_type;
-      if (!empty($verbose)) {
-        if (isset($status[$type]['severity'])) {
-          if ($status[$type]['severity'] == REQUIREMENT_ERROR) {
-            drupal_set_message($status[$type]['description'], 'error');
-          }
-          elseif ($status[$type]['severity'] == REQUIREMENT_WARNING) {
-            drupal_set_message($status[$type]['description'], 'warning');
-          }
-        }
-      }
-      // Otherwise, if we're on *any* admin page and there's a security
-      // update missing, print an error message about it.
-      else {
-        if (isset($status[$type])
-            && isset($status[$type]['reason'])
-            && $status[$type]['reason'] === UPDATE_NOT_SECURE) {
-          drupal_set_message($status[$type]['description'], 'error');
-        }
-      }
-    }
-  }
-}
-
-/**
  * Implements hook_menu().
  */
 function update_menu() {
diff --git a/core/update.php b/core/update.php
index 46d933b..0a1516a 100644
--- a/core/update.php
+++ b/core/update.php
@@ -38,8 +38,8 @@
 /**
  * Global flag indicating that update.php is being run.
  *
- * When this flag is set, various operations do not take place, such as invoking
- * hook_init() and hook_exit(), css/js preprocessing, and translation.
+ * When this flag is set, various operations do not take place, such as css/js
+ * preprocessing, and translation.
  *
  * This constant is defined using define() instead of const so that PHP
  * versions older than 5.3 can display the proper PHP requirements instead of
