diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index f754ecb..3ca6f5b 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -5,6 +5,141 @@
  * API for the Drupal menu system.
  */
 
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Template\Attribute;
+use Drupal\menu_link\MenuLinkInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+/**
+ * @defgroup menu Menu and routing system
+ * @{
+ * Define the navigation menus, and route page requests to code based on URLs.
+ *
+ * The Drupal routing system defines how Drupal responds to URLs passed to the
+ * browser. The menu system, which depends on the routing system, is used for
+ * navigation. The Menu module allows menus to be created in the user interface
+ * as hierarchical lists of links.
+ *
+ * @section registering_paths Registering router paths
+ * To register a path, you need to add lines similar to this in a
+ * module.routing.yml file:
+ * @code
+ * block.admin_display:
+ *   path: '/admin/structure/block'
+ *   defaults:
+ *     _content: '\Drupal\block\Controller\BlockListController::listing'
+ *   requirements:
+ *     _permission: 'administer blocks'
+ * @endcode
+ * @todo Add more information here, especially about controllers and what all
+ *   the stuff in the routing.yml file means.
+ *
+ * @section Defining menu links
+ * Once you have a route defined, you can use hook_menu_link_defaults() to
+ * define links for your module's paths in the main Navigation menu or other
+ * menus. See the hook_menu_link_defaults() documentation for more details.
+ *
+ * @todo The rest of this topic has not been reviewed or updated for Drupal 8.x
+ *   and is not correct!
+ * @todo It is quite likely that hook_menu() will be replaced with a different
+ *   hook, configuration system, or plugin system before the 8.0 release.
+ *
+ * Drupal's menu system follows a simple hierarchy defined by paths.
+ * Implementations of hook_menu() define menu items and assign them to
+ * paths (which should be unique). The menu system aggregates these items
+ * and determines the menu hierarchy from the paths. For example, if the
+ * paths defined were a, a/b, e, a/b/c/d, f/g, and a/b/h, the menu system
+ * would form the structure:
+ * - a
+ *   - a/b
+ *     - a/b/c/d
+ *     - a/b/h
+ * - e
+ * - f/g
+ * Note that the number of elements in the path does not necessarily
+ * determine the depth of the menu item in the tree.
+ *
+ * When responding to a page request, the menu system looks to see if the
+ * path requested by the browser is registered as a menu item with a
+ * callback. If not, the system searches up the menu tree for the most
+ * complete match with a callback it can find. If the path a/b/i is
+ * requested in the tree above, the callback for a/b would be used.
+ *
+ * The found callback function is called with any arguments specified
+ * in the "page arguments" attribute of its menu item. The
+ * attribute must be an array. After these arguments, any remaining
+ * components of the path are appended as further arguments. In this
+ * way, the callback for a/b above could respond to a request for
+ * a/b/i differently than a request for a/b/j.
+ *
+ * For an illustration of this process, see page_example.module.
+ *
+ * Access to the callback functions is also protected by the menu system.
+ * The "access callback" with an optional "access arguments" of each menu
+ * item is called before the page callback proceeds. If this returns TRUE,
+ * then access is granted; if FALSE, then access is denied. Default local task
+ * menu items (see next paragraph) may omit this attribute to use the value
+ * provided by the parent item.
+ *
+ * In the default Drupal interface, you will notice many links rendered as
+ * tabs. These are known in the menu system as "local tasks", and they are
+ * rendered as tabs by default, though other presentations are possible.
+ * Local tasks function just as other menu items in most respects. It is
+ * convention that the names of these tasks should be short verbs if
+ * possible. In addition, a "default" local task should be provided for
+ * each set. When visiting a local task's parent menu item, the default
+ * local task will be rendered as if it is selected; this provides for a
+ * normal tab user experience. This default task is special in that it
+ * links not to its provided path, but to its parent item's path instead.
+ * The default task's path is only used to place it appropriately in the
+ * menu hierarchy.
+ *
+ * Everything described so far is stored in the menu_router table. The
+ * menu_links table holds the visible menu links. By default these are
+ * derived from the same hook_menu definitions, however you are free to
+ * add more with menu_link_save().
+ */
+
+/**
+ * @defgroup menu_flags Menu flags
+ * @{
+ * Flags for use in the "type" attribute of menu items.
+ */
+
+/**
+ * Internal menu flag -- menu item is the root of the menu tree.
+ */
+const MENU_IS_ROOT = 0x0001;
+
+/**
+ * Internal menu flag -- menu item is visible in the menu tree.
+ */
+const MENU_VISIBLE_IN_TREE = 0x0002;
+
+/**
+ * Internal menu flag -- menu item links back to its parent.
+ */
+const MENU_LINKS_TO_PARENT = 0x0008;
+
+/**
+ * Internal menu flag -- menu item can be modified by administrator.
+ */
+const MENU_MODIFIED_BY_ADMIN = 0x0020;
+
+/**
+ * Internal menu flag -- menu item was created by administrator.
+ */
+const MENU_CREATED_BY_ADMIN = 0x0040;
+
+/**
+ * Internal menu flag -- menu item is a local task.
+ */
+const MENU_IS_LOCAL_TASK = 0x0080;
+
 /**
  * @addtogroup menu
  * @{
@@ -214,6 +349,336 @@ function menu_local_tabs() {
  */
 function menu_cache_clear_all() {
   \Drupal::cache('menu')->invalidateAll();
+  \Drupal::cache('data')->deleteAll();
+  menu_reset_static_cache();
+}
+
+/**
+ * Resets the menu system static cache.
+ */
+function menu_reset_static_cache() {
+  \Drupal::entityManager()
+    ->getStorage('menu_link')->resetCache();
+  drupal_static_reset('_menu_build_tree');
+  drupal_static_reset('menu_tree');
+  drupal_static_reset('menu_tree_all_data');
+  drupal_static_reset('menu_tree_page_data');
+  drupal_static_reset('menu_link_get_preferred');
+}
+
+/**
+ * Saves menu links recursively for menu_links_rebuild_defaults().
+ */
+function _menu_link_save_recursive($controller, $machine_name, &$children, &$links) {
+  $menu_link = $links[$machine_name];
+  if ($menu_link->isNew() || !$menu_link->customized) {
+    if (!isset($menu_link->plid) && !empty($menu_link->parent) && !empty($links[$menu_link->parent])) {
+      $parent = $links[$menu_link->parent];
+
+      if (empty($menu_link->menu_name) || $parent->menu_name == $menu_link->menu_name) {
+        $menu_link->plid = $parent->id();
+        $menu_link->menu_name = $parent->menu_name;
+      }
+    }
+    $controller->save($menu_link);
+  }
+  if (!empty($children[$machine_name])) {
+    foreach ($children[$machine_name] as $next_name) {
+      _menu_link_save_recursive($controller, $next_name, $children, $links);
+    }
+  }
+  // Remove processed link names so we can find stragglers.
+  unset($children[$machine_name]);
+}
+
+/**
+ * Gets all default menu link definitions.
+ *
+ * @return array
+ *   An array of default menu links.
+ */
+function menu_link_get_defaults() {
+  $module_handler = \Drupal::moduleHandler();
+  $all_links = $module_handler->invokeAll('menu_link_defaults');
+  /** @var \Drupal\Core\Routing\RouteProviderInterface $route_provider */
+  $route_provider = \Drupal::service('router.route_provider');
+
+  // Fill in the machine name from the array key.
+  foreach ($all_links as $machine_name => $link) {
+    $all_links[$machine_name]['machine_name'] = $machine_name;
+  }
+  $module_handler->alter('menu_link_defaults', $all_links);
+
+  // Validate the menu link definitions.
+  foreach ($all_links as $machine_name => $link) {
+
+    // Check for required array keys.
+    if (!isset($link['link_title'])) {
+      throw new \Exception(sprintf('Menu link %s does not have a "link_title" key in its definition.', $machine_name));
+    }
+
+    // Check that the link path is external.
+    if (isset($link['link_path']) && UrlHelper::isValid($link['link_path'], TRUE)) {
+      throw new \Exception(sprintf('link_path %s for menu link %s must be absolute.', $link['link_path'], $machine_name));
+    }
+
+    // Check if the specified parent menu link exists.
+    if (isset($link['parent']) && !isset($all_links[$link['parent']])) {
+      throw new \Exception(sprintf('Menu link %s specifies it has parent %s, but no menu link with that machine name exists.', $machine_name, $link['parent']));
+    }
+
+    // Check for either a route name or a link path.
+    if (!isset($link['route_name']) && !isset($link['link_path'])) {
+      throw new \Exception(sprintf('Menu link %s must provide either a "route_name" or a "link_path" key in its definition.', $machine_name));
+    }
+
+    // Check if the specified route exists.
+    if (isset($link['route_name'])) {
+      try {
+        $route_provider->getRouteByName($link['route_name']);
+      }
+      catch (RouteNotFoundException $e) {
+        throw new \Exception(sprintf('Menu link %s specifies route name %s, but no route with that machine name exists.', $machine_name, $link['route_name']), 0, $e);
+      }
+    }
+  }
+
+  return $all_links;
+}
+
+/**
+ * Builds menu links for the items returned from hook_menu_link_defaults().
+ */
+function menu_link_rebuild_defaults() {
+  // Ensure that all configuration used to build the menu items are loaded
+  // without overrides.
+  $old_state = \Drupal::configFactory()->getOverrideState();
+  \Drupal::configFactory()->setOverrideState(FALSE);
+  $module_handler = \Drupal::moduleHandler();
+  if (!$module_handler->moduleExists('menu_link')) {
+    // The Menu link module may not be available during install, so rebuild
+    // when possible.
+    return;
+  }
+  /** @var \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage */
+  $menu_link_storage = \Drupal::entityManager()
+    ->getStorage('menu_link');
+  $links = array();
+  $children = array();
+  $top_links = array();
+  $all_links = menu_link_get_defaults();
+  if ($all_links) {
+    foreach ($all_links as $machine_name => $link) {
+      // For performance reasons, do a straight query now and convert to a menu
+      // link entity later.
+      // @todo revisit before release.
+      $existing_item = db_select('menu_links')
+        ->fields('menu_links')
+        ->condition('machine_name', $machine_name)
+        ->condition('module', 'system')
+        ->execute()->fetchObject();
+      if ($existing_item) {
+        $existing_item->options = unserialize($existing_item->options);
+        $existing_item->route_parameters = unserialize($existing_item->route_parameters);
+        $link['mlid'] = $existing_item->mlid;
+        $link['plid'] = $existing_item->plid;
+        $link['uuid'] = $existing_item->uuid;
+        $link['customized'] = $existing_item->customized;
+        $link['updated'] = $existing_item->updated;
+        $menu_link = $menu_link_storage->createFromDefaultLink($link);
+
+        // Convert the existing item to a typed object.
+        /** @var \Drupal\menu_link\MenuLinkInterface $existing_item */
+        $existing_item = $menu_link_storage->create(get_object_vars($existing_item));
+
+        if (!$existing_item->customized) {
+          // A change in hook_menu_link_defaults() may move the link to a
+          // different menu or parent.
+          if (!empty($link['menu_name']) && ($link['menu_name'] != $existing_item->menu_name)) {
+            $menu_link->plid = NULL;
+            $menu_link->menu_name = $link['menu_name'];
+          }
+          elseif (!empty($link['parent'])) {
+            $menu_link->plid = NULL;
+          }
+
+          $menu_link->original = $existing_item;
+        }
+      }
+      else {
+        if (empty($link['route_name']) && empty($link['link_path'])) {
+          watchdog('error', 'Menu_link %machine_name does neither provide a route_name nor a link_path, so it got skipped.', array('%machine_name' => $machine_name));
+          continue;
+        }
+        $menu_link = $menu_link_storage->createFromDefaultLink($link);
+      }
+      if (!empty($link['parent'])) {
+        $children[$link['parent']][$machine_name] = $machine_name;
+        $menu_link->parent = $link['parent'];
+        if (empty($link['menu_name'])) {
+          // Reset the default menu name so it is populated from the parent.
+          $menu_link->menu_name = NULL;
+        }
+      }
+      else {
+        // A top level link - we need them to root our tree.
+        $top_links[$machine_name] = $machine_name;
+        $menu_link->plid = 0;
+      }
+      $links[$machine_name] = $menu_link;
+    }
+  }
+  foreach ($top_links as $machine_name) {
+    _menu_link_save_recursive($menu_link_storage, $machine_name, $children, $links);
+  }
+  // Handle any children we didn't find starting from top-level links.
+  foreach ($children as $orphan_links) {
+    foreach ($orphan_links as $machine_name) {
+      // Force it to the top level.
+      $links[$machine_name]->plid = 0;
+      _menu_link_save_recursive($menu_link_storage, $machine_name, $children, $links);
+    }
+  }
+
+  // Find any item whose entry in hook_menu_link_defaults() no longer exists.
+  if ($all_links) {
+    $query = \Drupal::entityQuery('menu_link')
+      ->condition('machine_name', array_keys($all_links), 'NOT IN')
+      ->exists('machine_name')
+      ->condition('external', 0)
+      ->condition('updated', 0)
+      ->condition('customized', 0)
+      ->sort('depth', 'DESC');
+    $result = $query->execute();
+  }
+  else {
+    $result = array();
+  }
+
+  // Remove all such items. Starting from those with the greatest depth will
+  // minimize the amount of re-parenting done by the menu link controller.
+  if ($result) {
+    menu_link_delete_multiple($result, TRUE);
+  }
+  \Drupal::configFactory()->setOverrideState($old_state);
+}
+
+/**
+ * Returns an array containing all links for a menu.
+ *
+ * @param $menu_name
+ *   The name of the menu whose links should be returned.
+ *
+ * @return
+ *   An array of menu links.
+ */
+function menu_load_links($menu_name) {
+  $links = array();
+
+  $query = \Drupal::entityQuery('menu_link')
+    ->condition('menu_name', $menu_name)
+    // Order by weight so as to be helpful for menus that are only one level
+    // deep.
+    ->sort('weight');
+  $result = $query->execute();
+
+  if (!empty($result)) {
+    $links = menu_link_load_multiple($result);
+  }
+
+  return $links;
+}
+
+/**
+ * Deletes all links for a menu.
+ *
+ * @param $menu_name
+ *   The name of the menu whose links will be deleted.
+ */
+function menu_delete_links($menu_name) {
+  $links = menu_load_links($menu_name);
+  menu_link_delete_multiple(array_keys($links), FALSE, TRUE);
+}
+
+/**
+ * Clears the page and block caches at most twice per page load.
+ */
+function _menu_clear_page_cache() {
+  $cache_cleared = &drupal_static(__FUNCTION__, 0);
+
+  // Clear the page and block caches, but at most twice, including at
+  //  the end of the page load when there are multiple links saved or deleted.
+  if ($cache_cleared == 0) {
+    Cache::invalidateTags(array('content' => TRUE));
+    // Keep track of which menus have expanded items.
+    _menu_set_expanded_menus();
+    $cache_cleared = 1;
+  }
+  elseif ($cache_cleared == 1) {
+    drupal_register_shutdown_function('Drupal\Core\Cache\Cache::invalidateTags', array('content' => TRUE));
+    // Keep track of which menus have expanded items.
+    drupal_register_shutdown_function('_menu_set_expanded_menus');
+    $cache_cleared = 2;
+  }
+}
+
+/**
+ * Updates a list of menus with expanded items.
+ */
+function _menu_set_expanded_menus() {
+  $names = array();
+  $result = Drupal::entityQueryAggregate('menu_link')
+    ->condition('expanded', 0, '<>')
+    ->groupBy('menu_name')
+    ->execute();
+
+  // Flatten the resulting array.
+  foreach($result as $k => $v) {
+    $names[$k] = $v['menu_name'];
+  }
+
+  \Drupal::state()->set('menu_expanded', $names);
+}
+
+
+/**
+ * Checks whether the site is in maintenance mode.
+ *
+ * This function will log the current user out and redirect to front page
+ * if the current user has no 'access site in maintenance mode' permission.
+ *
+ * @param $check_only
+ *   If this is set to TRUE, the function will perform the access checks and
+ *   return the site offline status, but not log the user out or display any
+ *   messages.
+ *
+ * @return
+ *   FALSE if the site is not in maintenance mode, the user login page is
+ *   displayed, or the user has the 'access site in maintenance mode'
+ *   permission. TRUE for anonymous users not being on the login page when the
+ *   site is in maintenance mode.
+ */
+function _menu_site_is_offline($check_only = FALSE) {
+  // Check if site is in maintenance mode.
+  if (\Drupal::state()->get('system.maintenance_mode')) {
+    if (user_access('access site in maintenance mode')) {
+      // Ensure that the maintenance mode message is displayed only once
+      // (allowing for page redirects) and specifically suppress its display on
+      // the maintenance mode settings page.
+      if (!$check_only && current_path() != 'admin/config/development/maintenance') {
+        if (user_access('administer site configuration')) {
+          drupal_set_message(t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance'))), 'status', FALSE);
+        }
+        else {
+          drupal_set_message(t('Operating in maintenance mode.'), 'status', FALSE);
+        }
+      }
+    }
+    else {
+      return TRUE;
+    }
+  }
+  return FALSE;
 }
 
 /**
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 94fbb64..42bf82c 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -16,6 +16,1379 @@
  */
 
 /**
+ * Defines one or more hooks that are exposed by a module.
+ *
+ * Normally hooks do not need to be explicitly defined. However, by declaring a
+ * hook explicitly, a module may define a "group" for it. Modules that implement
+ * a hook may then place their implementation in either $module.module or in
+ * $module.$group.inc. If the hook is located in $module.$group.inc, then that
+ * file will be automatically loaded when needed.
+ * In general, hooks that are rarely invoked and/or are very large should be
+ * placed in a separate include file, while hooks that are very short or very
+ * frequently called should be left in the main module file so that they are
+ * always available.
+ *
+ * @return
+ *   An associative array whose keys are hook names and whose values are an
+ *   associative array containing:
+ *   - group: A string defining the group to which the hook belongs. The module
+ *     system will determine whether a file with the name $module.$group.inc
+ *     exists, and automatically load it when required.
+ *
+ * See system_hook_info() for all hook groups defined by Drupal core.
+ *
+ * @see hook_hook_info_alter().
+ */
+function hook_hook_info() {
+  $hooks['token_info'] = array(
+    'group' => 'tokens',
+  );
+  $hooks['tokens'] = array(
+    'group' => 'tokens',
+  );
+  return $hooks;
+}
+
+/**
+ * Perform periodic actions.
+ *
+ * Modules that require some commands to be executed periodically can
+ * implement hook_cron(). The engine will then call the hook whenever a cron
+ * run happens, as defined by the administrator. Typical tasks managed by
+ * hook_cron() are database maintenance, backups, recalculation of settings
+ * or parameters, automated mailing, and retrieving remote data.
+ *
+ * Short-running or non-resource-intensive tasks can be executed directly in
+ * the hook_cron() implementation.
+ *
+ * Long-running tasks and tasks that could time out, such as retrieving remote
+ * data, sending email, and intensive file tasks, should use the queue API
+ * instead of executing the tasks directly. To do this, first define one or
+ * more queues via hook_queue_info(). Then, add items that need to be
+ * processed to the defined queues.
+ */
+function hook_cron() {
+  // Short-running operation example, not using a queue:
+  // Delete all expired records since the last cron run.
+  $expires = \Drupal::state()->get('mymodule.cron_last_run', REQUEST_TIME);
+  db_delete('mymodule_table')
+    ->condition('expires', $expires, '>=')
+    ->execute();
+  \Drupal::state()->set('mymodule.cron_last_run', REQUEST_TIME);
+
+  // Long-running operation example, leveraging a queue:
+  // Fetch feeds from other sites.
+  $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh <> :never', array(
+    ':time' => REQUEST_TIME,
+    ':never' => AGGREGATOR_CLEAR_NEVER,
+  ));
+  $queue = \Drupal::queue('aggregator_feeds');
+  foreach ($result as $feed) {
+    $queue->createItem($feed);
+  }
+}
+
+/**
+ * Alter available data types for typed data wrappers.
+ *
+ * @param array $data_types
+ *   An array of data type information.
+ *
+ * @see hook_data_type_info()
+ */
+function hook_data_type_info_alter(&$data_types) {
+  $data_types['email']['class'] = '\Drupal\mymodule\Type\Email';
+}
+
+/**
+ * Declare queues holding items that need to be run periodically.
+ *
+ * While there can be only one hook_cron() process running at the same time,
+ * there can be any number of processes defined here running. Because of
+ * this, long running tasks are much better suited for this API. Items queued
+ * in hook_cron() might be processed in the same cron run if there are not many
+ * items in the queue, otherwise it might take several requests, which can be
+ * run in parallel.
+ *
+ * You can create queues, add items to them, claim them, etc without declaring
+ * the queue in this hook if you want, however, you need to take care of
+ * processing the items in the queue in that case.
+ *
+ * @return
+ *   An associative array where the key is the queue name and the value is
+ *   again an associative array. Possible keys are:
+ *   - 'worker callback': A PHP callable to call that is an implementation of
+ *     callback_queue_worker().
+ *   - 'cron': (optional) An associative array containing the optional key:
+ *     - 'time': (optional) How much time Drupal cron should spend on calling
+ *       this worker in seconds. Defaults to 15.
+ *     If the cron key is not defined, the queue will not be processed by cron,
+ *     and must be processed by other means.
+ *
+ * @see hook_cron()
+ * @see hook_queue_info_alter()
+ */
+function hook_queue_info() {
+  $queues['aggregator_feeds'] = array(
+    'title' => t('Aggregator refresh'),
+    'worker callback' => array('Drupal\my_module\MyClass', 'aggregatorRefresh'),
+    // Only needed if this queue should be processed by cron.
+    'cron' => array(
+      'time' => 60,
+    ),
+  );
+  return $queues;
+}
+
+/**
+ * Alter cron queue information before cron runs.
+ *
+ * Called by \Drupal\Core\Cron to allow modules to alter cron queue settings
+ * before any jobs are processesed.
+ *
+ * @param array $queues
+ *   An array of cron queue information.
+ *
+ * @see hook_queue_info()
+ * @see \Drupal\Core\Cron
+ */
+function hook_queue_info_alter(&$queues) {
+  // This site has many feeds so let's spend 90 seconds on each cron run
+  // updating feeds instead of the default 60.
+  $queues['aggregator_feeds']['cron']['time'] = 90;
+}
+
+/**
+ * Work on a single queue item.
+ *
+ * Callback for hook_queue_info().
+ *
+ * @param $queue_item_data
+ *   The data that was passed to \Drupal\Core\Queue\QueueInterface::createItem()
+ *   when the item was queued.
+ *
+ * @throws \Exception
+ *   The worker callback may throw an exception to indicate there was a problem.
+ *   The cron process will log the exception, and leave the item in the queue to
+ *   be processed again later.
+ *
+ * @see \Drupal\Core\Cron::run()
+ */
+function callback_queue_worker($queue_item_data) {
+  $node = node_load($queue_item_data);
+  $node->title = 'Updated title';
+  $node->save();
+}
+
+/**
+ * Allows modules to declare their own Form API element types and specify their
+ * default values.
+ *
+ * This hook allows modules to declare their own form element types and to
+ * specify their default values. The values returned by this hook will be
+ * merged with the elements returned by form constructor implementations and so
+ * can return defaults for any Form APIs keys in addition to those explicitly
+ * mentioned below.
+ *
+ * Each of the form element types defined by this hook is assumed to have
+ * a matching theme function, e.g. theme_elementtype(), which should be
+ * registered with hook_theme() as normal.
+ *
+ * For more information about custom element types see the explanation at
+ * http://drupal.org/node/169815.
+ *
+ * @return
+ *  An associative array describing the element types being defined. The array
+ *  contains a sub-array for each element type, with the machine-readable type
+ *  name as the key. Each sub-array has a number of possible attributes:
+ *  - "#input": boolean indicating whether or not this element carries a value
+ *    (even if it's hidden).
+ *  - "#process": array of callback functions taking $element, $form_state,
+ *    and $complete_form.
+ *  - "#after_build": array of callables taking $element and $form_state.
+ *  - "#validate": array of callback functions taking $form and $form_state.
+ *  - "#element_validate": array of callback functions taking $element and
+ *    $form_state.
+ *  - "#pre_render": array of callables taking $element.
+ *  - "#post_render": array of callables taking $children and $element.
+ *  - "#submit": array of callback functions taking $form and $form_state.
+ *  - "#title_display": optional string indicating if and how #title should be
+ *    displayed, see the form-element template and theme_form_element_label().
+ *
+ * @see hook_element_info_alter()
+ * @see system_element_info()
+ */
+function hook_element_info() {
+  $types['filter_format'] = array(
+    '#input' => TRUE,
+  );
+  return $types;
+}
+
+/**
+ * Alter the element type information returned from modules.
+ *
+ * A module may implement this hook in order to alter the element type defaults
+ * defined by a module.
+ *
+ * @param $type
+ *   All element type defaults as collected by hook_element_info().
+ *
+ * @see hook_element_info()
+ */
+function hook_element_info_alter(&$type) {
+  // Decrease the default size of textfields.
+  if (isset($type['textfield']['#size'])) {
+    $type['textfield']['#size'] = 40;
+  }
+}
+
+/**
+ * Perform necessary alterations to the JavaScript before it is presented on
+ * the page.
+ *
+ * @param $javascript
+ *   An array of all JavaScript being presented on the page.
+ *
+ * @see _drupal_add_js()
+ * @see drupal_get_js()
+ * @see drupal_js_defaults()
+ */
+function hook_js_alter(&$javascript) {
+  // Swap out jQuery to use an updated version of the library.
+  $javascript['core/assets/vendor/jquery/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
+}
+
+/**
+ * Alters the JavaScript/CSS library registry.
+ *
+ * Allows certain, contributed modules to update libraries to newer versions
+ * while ensuring backwards compatibility. In general, such manipulations should
+ * only be done by designated modules, since most modules that integrate with a
+ * certain library also depend on the API of a certain library version.
+ *
+ * @param $libraries
+ *   The JavaScript/CSS libraries provided by $module. Keyed by internal library
+ *   name and passed by reference.
+ * @param $module
+ *   The name of the module that registered the libraries.
+ */
+function hook_library_info_alter(&$libraries, $module) {
+  // Update Farbtastic to version 2.0.
+  if ($module == 'core' && isset($libraries['jquery.farbtastic'])) {
+    // Verify existing version is older than the one we are updating to.
+    if (version_compare($libraries['jquery.farbtastic']['version'], '2.0', '<')) {
+      // Update the existing Farbtastic to version 2.0.
+      $libraries['jquery.farbtastic']['version'] = '2.0';
+      // To accurately replace library files, the order of files and the options
+      // of each file have to be retained; e.g., like this:
+      $old_path = 'assets/vendor/farbtastic';
+      // Since the replaced library files are no longer located in a directory
+      // relative to the original extension, specify an absolute path (relative
+      // to DRUPAL_ROOT / base_path()) to the new location.
+      $new_path = '/' . drupal_get_path('module', 'farbtastic_update') . '/js';
+      $new_js = array();
+      $replacements = array(
+        $old_path . '/farbtastic.js' => $new_path . '/farbtastic-2.0.js',
+      );
+      foreach ($libraries['jquery.farbtastic']['js'] as $source => $options) {
+        if (isset($replacements[$source])) {
+          $new_js[$replacements[$source]] = $options;
+        }
+        else {
+          $new_js[$source] = $options;
+        }
+      }
+      $libraries['jquery.farbtastic']['js'] = $new_js;
+    }
+  }
+}
+
+/**
+ * Alters a JavaScript/CSS library before it is attached.
+ *
+ * Allows modules and themes to dynamically attach further assets to a library
+ * when it is added to the page; e.g., to add JavaScript settings.
+ *
+ * This hook is only invoked once per library and page.
+ *
+ * @param array $library
+ *   The JavaScript/CSS library that is being added.
+ * @param string $extension
+ *   The name of the extension that registered the library.
+ * @param string $name
+ *   The name of the library.
+ *
+ * @see _drupal_add_library()
+ */
+function hook_library_alter(array &$library, $name) {
+  if ($name == 'core/jquery.ui.datepicker') {
+    // Note: If the added assets do not depend on additional request-specific
+    // data supplied here, consider to statically register it directly via
+    // hook_library_info_alter() already.
+    $library['dependencies'][] = 'locale/drupal.locale.datepicker';
+
+    $language_interface = \Drupal::languageManager()->getCurrentLanguage();
+    $settings['jquery']['ui']['datepicker'] = array(
+      'isRTL' => $language_interface->direction == Language::DIRECTION_RTL,
+      'firstDay' => \Drupal::config('system.date')->get('first_day'),
+    );
+    $library['js'][] = array(
+      'type' => 'setting',
+      'data' => $settings,
+    );
+  }
+}
+
+/**
+ * Alter CSS files before they are output on the page.
+ *
+ * @param $css
+ *   An array of all CSS items (files and inline CSS) being requested on the page.
+ *
+ * @see _drupal_add_css()
+ * @see drupal_get_css()
+ */
+function hook_css_alter(&$css) {
+  // Remove defaults.css file.
+  unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
+}
+
+/**
+ * Alter the Ajax command data that is sent to the client.
+ *
+ * @param \Drupal\Core\Ajax\CommandInterface[] $data
+ *   An array of all the rendered commands that will be sent to the client.
+ *
+ * @see \Drupal\Core\Ajax\AjaxResponse::ajaxRender()
+ */
+function hook_ajax_render_alter(array &$data) {
+  // Inject any new status messages into the content area.
+  $status_messages = array('#theme' => 'status_messages');
+  $command = new \Drupal\Core\Ajax\PrependCommand('#block-system-main .content', drupal_render($status_messages));
+  $data[] = $command->render();
+}
+
+/**
+ * Add elements to a page before it is rendered.
+ *
+ * Use this hook when you want to add elements at the page level. For your
+ * additions to be printed, they have to be placed below a top level array key
+ * of the $page array that has the name of a region of the active theme.
+ *
+ * By default, valid region keys are 'page_top', 'header', 'sidebar_first',
+ * 'content', 'sidebar_second' and 'page_bottom'. To get a list of all regions
+ * of the active theme, use system_region_list($theme). Note that $theme is a
+ * global variable.
+ *
+ * If you want to alter the elements added by other modules or if your module
+ * depends on the elements of other modules, use hook_page_alter() instead which
+ * runs after this hook.
+ *
+ * @param $page
+ *   Nested array of renderable elements that make up the page.
+ *
+ * @see hook_page_alter()
+ * @see drupal_render_page()
+ */
+function hook_page_build(&$page) {
+  $path = drupal_get_path('module', 'foo');
+  // Add JavaScript/CSS assets to all pages.
+  // @see drupal_process_attached()
+  $page['#attached']['js'][$path . '/foo.js'] = array('every_page' => TRUE);
+  $page['#attached']['css'][$path . '/foo.base.css'] = array('every_page' => TRUE);
+  $page['#attached']['css'][$path . '/foo.theme.css'] = array('every_page' => TRUE);
+
+  // Add a special CSS file to a certain page only.
+  if (drupal_is_front_page()) {
+    $page['#attached']['css'][] = $path . '/foo.front.css';
+  }
+
+  // Append a standard disclaimer to the content region on a node detail page.
+  if (\Drupal::request()->attributes->get('node')) {
+    $page['content']['disclaimer'] = array(
+      '#markup' => t('Acme, Inc. is not responsible for the contents of this sample code.'),
+      '#weight' => 25,
+    );
+  }
+}
+
+/**
+ * Define links for menus.
+ *
+ * @return array
+ *   An array of default menu links. Each link has a key that is the machine
+ *   name, which must be unique. By default, use the route name as the
+ *   machine name. In cases where multiple links use the same route name, such
+ *   as two links to the same page in different menus, or two links using the
+ *   same route name but different route parameters, the suggested machine name
+ *   patten is the route name followed by a dot and a unique suffix. For
+ *   example, an additional logout link might have a machine name of
+ *   user.logout.navigation, and default links provided to edit the article and
+ *   page content types could use machine names node.type_edit.article and
+ *   node.type_edit.page. Since the machine name may be arbitrary, you should
+ *   never write code that assumes it is identical to the route name.
+ *
+ *   The value corresponding to each machine name key is an associative array
+ *   that may contain the following key-value pairs:
+ *   - link_title: (required) The untranslated title of the menu item.
+ *   - description: (optional) The untranslated description of the link.
+ *   - route_name: (optional) The route name to be used to build the path.
+ *     Either a route_name or a link_path must be provided.
+ *   - route_parameters: (optional) The route parameters to build the path.
+ *   - link_path: (optional) If you have an external link use link_path instead
+ *     of providing a route_name.
+ *   - parent: (optional) The machine name of the link that is this link's menu
+ *     parent.
+ *   - weight: (optional) An integer that determines the relative position of
+ *     items in the menu; higher-weighted items sink. Defaults to 0. Menu items
+ *     with the same weight are ordered alphabetically.
+ *   - menu_name: (optional) The machine name of a menu to put the link in, if
+ *     not the default Tools menu.
+ *   - expanded: (optional) If set to TRUE, and if a menu link is provided for
+ *     this menu item (as a result of other properties), then the menu link is
+ *     always expanded, equivalent to its 'always expanded' checkbox being set
+ *     in the UI.
+ *   - type: (optional) A bitmask of flags describing properties of the menu
+ *     item. The following two bitmasks are provided as constants in menu.inc:
+ *     - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
+ *       moved/hidden by the administrator.
+ *     - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
+ *       administrator may enable.
+ *     If the "type" element is omitted, MENU_NORMAL_ITEM is assumed.
+ *   - options: (optional) An array of options to be passed to l() when
+ *     generating a link from this menu item.
+ *
+ * @see hook_menu_link_defaults_alter()
+ */
+function hook_menu_link_defaults() {
+  $links['user.page'] = array(
+    'link_title' => 'My account',
+    'weight' => -10,
+    'route_name' => 'user.page',
+    'menu_name' => 'account',
+  );
+
+  $links['user.logout'] = array(
+    'link_title' => 'Log out',
+    'route_name' => 'user.logout',
+    'weight' => 10,
+    'menu_name' => 'account',
+  );
+
+  return $links;
+}
+
+/**
+ * Alter links for menus.
+ *
+ * @see hook_menu_link_defaults()
+ */
+function hook_menu_link_defaults_alter(&$links) {
+  // Change the weight and title of the user.logout link.
+  $links['user.logout']['weight'] = -10;
+  $links['user.logout']['link_title'] = t('Logout');
+}
+
+/**
+ * Alter tabs and actions displayed on the page before they are rendered.
+ *
+ * This hook is invoked by menu_local_tasks(). The system-determined tabs and
+ * actions are passed in by reference. Additional tabs or actions may be added.
+ *
+ * Each tab or action is an associative array containing:
+ * - #theme: The theme function to use to render.
+ * - #link: An associative array containing:
+ *   - title: The localized title of the link.
+ *   - href: The system path to link to.
+ *   - localized_options: An array of options to pass to l().
+ * - #weight: The link's weight compared to other links.
+ * - #active: Whether the link should be marked as 'active'.
+ *
+ * @param array $data
+ *   An associative array containing:
+ *   - actions: A list of of actions keyed by their href, each one being an
+ *     associative array as described above.
+ *   - tabs: A list of (up to 2) tab levels that contain a list of of tabs keyed
+ *     by their href, each one being an associative array as described above.
+ * @param string $route_name
+ *   The route name of the page.
+ */
+function hook_menu_local_tasks(&$data, $route_name) {
+  // Add an action linking to node/add to all pages.
+  $data['actions']['node/add'] = array(
+    '#theme' => 'menu_local_action',
+    '#link' => array(
+      'title' => t('Add content'),
+      'href' => 'node/add',
+      'localized_options' => array(
+        'attributes' => array(
+          'title' => t('Add content'),
+        ),
+      ),
+    ),
+  );
+
+  // Add a tab linking to node/add to all pages.
+  $data['tabs'][0]['node/add'] = array(
+    '#theme' => 'menu_local_task',
+    '#link' => array(
+      'title' => t('Example tab'),
+      'href' => 'node/add',
+      'localized_options' => array(
+        'attributes' => array(
+          'title' => t('Add content'),
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * Alter tabs and actions displayed on the page before they are rendered.
+ *
+ * This hook is invoked by menu_local_tasks(). The system-determined tabs and
+ * actions are passed in by reference. Existing tabs or actions may be altered.
+ *
+ * @param array $data
+ *   An associative array containing tabs and actions. See
+ *   hook_menu_local_tasks() for details.
+ * @param string $route_name
+ *   The route name of the page.
+ *
+ * @see hook_menu_local_tasks()
+ */
+function hook_menu_local_tasks_alter(&$data, $route_name) {
+}
+
+/**
+ * Alter local actions plugins.
+ *
+ * @param array $local_actions
+ *   The array of local action plugin definitions, keyed by plugin ID.
+ *
+ * @see \Drupal\Core\Menu\LocalActionInterface
+ * @see \Drupal\Core\Menu\LocalActionManager
+ */
+function hook_menu_local_actions_alter(&$local_actions) {
+}
+
+/**
+ * Alter local tasks plugins.
+ *
+ * @param array $local_tasks
+ *   The array of local tasks plugin definitions, keyed by plugin ID.
+ *
+ * @see \Drupal\Core\Menu\LocalTaskInterface
+ * @see \Drupal\Core\Menu\LocalTaskManager
+ */
+function hook_local_tasks_alter(&$local_tasks) {
+  // Remove a specified local task plugin.
+  unset($local_tasks['example_plugin_id']);
+}
+
+/**
+ * Alter contextual links before they are rendered.
+ *
+ * This hook is invoked by
+ * \Drupal\Core\Menu\ContextualLinkManager::getContextualLinkPluginsByGroup().
+ * The system-determined contextual links are passed in by reference. Additional
+ * links may be added and existing links can be altered.
+ *
+ * Each contextual link contains the following entries:
+ * - title: The localized title of the link.
+ * - route_name: The route name of the link.
+ * - route_parameters: The route parameters of the link.
+ * - localized_options: An array of options to pass to url().
+ * - (optional) weight: The weight of the link, which is used to sort the links.
+ *
+ *
+ * @param array $links
+ *   An associative array containing contextual links for the given $group,
+ *   as described above. The array keys are used to build CSS class names for
+ *   contextual links and must therefore be unique for each set of contextual
+ *   links.
+ * @param string $group
+ *   The group of contextual links being rendered.
+ * @param array $route_parameters.
+ *   The route parameters passed to each route_name of the contextual links.
+ *   For example:
+ *   @code
+ *   array('node' => $node->id())
+ *   @endcode
+ *
+ * @see \Drupal\Core\Menu\ContextualLinkManager
+ */
+function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
+  if ($group == 'menu') {
+    // Dynamically use the menu name for the title of the menu_edit contextual
+    // link.
+    $menu = \Drupal::entityManager()->getStorage('menu')->load($route_parameters['menu']);
+    $links['menu_edit']['title'] = t('Edit menu: !label', array('!label' => $menu->label()));
+  }
+}
+
+/**
+ * Alter the plugin definition of contextual links.
+ *
+ * @param array $contextual_links
+ *   An array of contextual_links plugin definitions, keyed by contextual link
+ *   ID. Each entry contains the following keys:
+ *     - title: The displayed title of the link
+ *     - route_name: The route_name of the contextual link to be displayed
+ *     - group: The group under which the contextual links should be added to.
+ *       Possible values are e.g. 'node' or 'menu'.
+ *
+ * @see \Drupal\Core\Menu\ContextualLinkManager
+ */
+function hook_contextual_links_plugins_alter(array &$contextual_links) {
+  $contextual_links['menu_edit']['title'] = 'Edit the menu';
+}
+
+/**
+ * Perform alterations before a page is rendered.
+ *
+ * Use this hook when you want to remove or alter elements at the page
+ * level, or add elements at the page level that depend on an other module's
+ * elements (this hook runs after hook_page_build().
+ *
+ * If you are making changes to entities such as forms, menus, or user
+ * profiles, use those objects' native alter hooks instead (hook_form_alter(),
+ * for example).
+ *
+ * The $page array contains top level elements for each block region:
+ * @code
+ *   $page['page_top']
+ *   $page['header']
+ *   $page['sidebar_first']
+ *   $page['content']
+ *   $page['sidebar_second']
+ *   $page['page_bottom']
+ * @endcode
+ *
+ * The 'content' element contains the main content of the current page, and its
+ * structure will vary depending on what module is responsible for building the
+ * page. Some legacy modules may not return structured content at all: their
+ * pre-rendered markup will be located in $page['content']['main']['#markup'].
+ *
+ * Pages built by Drupal's core Node module use a standard structure:
+ *
+ * @code
+ *   // Node body.
+ *   $page['content']['system_main']['nodes'][$nid]['body']
+ *   // Array of links attached to the node (add comments, read more).
+ *   $page['content']['system_main']['nodes'][$nid]['links']
+ *   // The node entity itself.
+ *   $page['content']['system_main']['nodes'][$nid]['#node']
+ *   // The results pager.
+ *   $page['content']['system_main']['pager']
+ * @endcode
+ *
+ * Blocks may be referenced by their module/delta pair within a region:
+ * @code
+ *   // The login block in the first sidebar region.
+ *   $page['sidebar_first']['user_login']['#block'];
+ * @endcode
+ *
+ * @param $page
+ *   Nested array of renderable elements that make up the page.
+ *
+ * @see hook_page_build()
+ * @see drupal_render_page()
+ */
+function hook_page_alter(&$page) {
+  // Add help text to the user login block.
+  $page['sidebar_first']['user_login']['help'] = array(
+    '#weight' => -10,
+    '#markup' => t('To post comments or add content, you first have to log in.'),
+  );
+}
+
+/**
+ * Perform alterations before a form is rendered.
+ *
+ * One popular use of this hook is to add form elements to the node form. When
+ * altering a node form, the node entity can be retrieved by invoking
+ * $form_state['controller']->getEntity().
+ *
+ * In addition to hook_form_alter(), which is called for all forms, there are
+ * two more specific form hooks available. The first,
+ * hook_form_BASE_FORM_ID_alter(), allows targeting of a form/forms via a base
+ * form (if one exists). The second, hook_form_FORM_ID_alter(), can be used to
+ * target a specific form directly.
+ *
+ * The call order is as follows: all existing form alter functions are called
+ * for module A, then all for module B, etc., followed by all for any base
+ * theme(s), and finally for the theme itself. The module order is determined
+ * by system weight, then by module name.
+ *
+ * Within each module, form alter hooks are called in the following order:
+ * first, hook_form_alter(); second, hook_form_BASE_FORM_ID_alter(); third,
+ * hook_form_FORM_ID_alter(). So, for each module, the more general hooks are
+ * called first followed by the more specific.
+ *
+ * @param $form
+ *   Nested array of form elements that comprise the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form. The arguments
+ *   that drupal_get_form() was originally called with are available in the
+ *   array $form_state['build_info']['args'].
+ * @param $form_id
+ *   String representing the name of the form itself. Typically this is the
+ *   name of the function that generated the form.
+ *
+ * @see hook_form_BASE_FORM_ID_alter()
+ * @see hook_form_FORM_ID_alter()
+ * @see forms_api_reference.html
+ */
+function hook_form_alter(&$form, &$form_state, $form_id) {
+  if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
+    $upload_enabled_types = \Drupal::config('mymodule.settings')->get('upload_enabled_types');
+    $form['workflow']['upload_' . $form['type']['#value']] = array(
+      '#type' => 'radios',
+      '#title' => t('Attachments'),
+      '#default_value' => in_array($form['type']['#value'], $upload_enabled_types) ? 1 : 0,
+      '#options' => array(t('Disabled'), t('Enabled')),
+    );
+    // Add a custom submit handler to save the array of types back to the config file.
+    $form['actions']['submit']['#submit'][] = 'mymodule_upload_enabled_types_submit';
+  }
+}
+
+/**
+ * Provide a form-specific alteration instead of the global hook_form_alter().
+ *
+ * Modules can implement hook_form_FORM_ID_alter() to modify a specific form,
+ * rather than implementing hook_form_alter() and checking the form ID, or
+ * using long switch statements to alter multiple forms.
+ *
+ * Form alter hooks are called in the following order: hook_form_alter(),
+ * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
+ * hook_form_alter() for more details.
+ *
+ * @param $form
+ *   Nested array of form elements that comprise the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form. The arguments
+ *   that drupal_get_form() was originally called with are available in the
+ *   array $form_state['build_info']['args'].
+ * @param $form_id
+ *   String representing the name of the form itself. Typically this is the
+ *   name of the function that generated the form.
+ *
+ * @see hook_form_alter()
+ * @see hook_form_BASE_FORM_ID_alter()
+ * @see drupal_prepare_form()
+ * @see forms_api_reference.html
+ */
+function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
+  // Modification for the form with the given form ID goes here. For example, if
+  // FORM_ID is "user_register_form" this code would run only on the user
+  // registration form.
+
+  // Add a checkbox to registration form about agreeing to terms of use.
+  $form['terms_of_use'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("I agree with the website's terms and conditions."),
+    '#required' => TRUE,
+  );
+}
+
+/**
+ * Provide a form-specific alteration for shared ('base') forms.
+ *
+ * By default, when drupal_get_form() is called, Drupal looks for a function
+ * with the same name as the form ID, and uses that function to build the form.
+ * In contrast, base forms allow multiple form IDs to be mapped to a single base
+ * (also called 'factory') form function.
+ *
+ * Modules can implement hook_form_BASE_FORM_ID_alter() to modify a specific
+ * base form, rather than implementing hook_form_alter() and checking for
+ * conditions that would identify the shared form constructor.
+ *
+ * To identify the base form ID for a particular form (or to determine whether
+ * one exists) check the $form_state. The base form ID is stored under
+ * $form_state['build_info']['base_form_id'].
+ *
+ * Form alter hooks are called in the following order: hook_form_alter(),
+ * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
+ * hook_form_alter() for more details.
+ *
+ * @param $form
+ *   Nested array of form elements that comprise the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form.
+ * @param $form_id
+ *   String representing the name of the form itself. Typically this is the
+ *   name of the function that generated the form.
+ *
+ * @see hook_form_alter()
+ * @see hook_form_FORM_ID_alter()
+ * @see drupal_prepare_form()
+ */
+function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
+  // Modification for the form with the given BASE_FORM_ID goes here. For
+  // example, if BASE_FORM_ID is "node_form", this code would run on every
+  // node form, regardless of node type.
+
+  // Add a checkbox to the node form about agreeing to terms of use.
+  $form['terms_of_use'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("I agree with the website's terms and conditions."),
+    '#required' => TRUE,
+  );
+}
+
+/**
+ * Alter an email message created with the drupal_mail() function.
+ *
+ * hook_mail_alter() allows modification of email messages created and sent
+ * with drupal_mail(). Usage examples include adding and/or changing message
+ * text, message fields, and message headers.
+ *
+ * Email messages sent using functions other than drupal_mail() will not
+ * invoke hook_mail_alter(). For example, a contributed module directly
+ * calling the drupal_mail_system()->mail() or PHP mail() function
+ * will not invoke this hook. All core modules use drupal_mail() for
+ * messaging, it is best practice but not mandatory in contributed modules.
+ *
+ * @param $message
+ *   An array containing the message data. Keys in this array include:
+ *  - 'id':
+ *     The drupal_mail() id of the message. Look at module source code or
+ *     drupal_mail() for possible id values.
+ *  - 'to':
+ *     The address or addresses the message will be sent to. The
+ *     formatting of this string must comply with RFC 2822.
+ *  - 'from':
+ *     The address the message will be marked as being from, which is
+ *     either a custom address or the site-wide default email address.
+ *  - 'subject':
+ *     Subject of the email to be sent. This must not contain any newline
+ *     characters, or the email may not be sent properly.
+ *  - 'body':
+ *     An array of strings containing the message text. The message body is
+ *     created by concatenating the individual array strings into a single text
+ *     string using "\n\n" as a separator.
+ *  - 'headers':
+ *     Associative array containing mail headers, such as From, Sender,
+ *     MIME-Version, Content-Type, etc.
+ *  - 'params':
+ *     An array of optional parameters supplied by the caller of drupal_mail()
+ *     that is used to build the message before hook_mail_alter() is invoked.
+ *  - 'language':
+ *     The language object used to build the message before hook_mail_alter()
+ *     is invoked.
+ *  - 'send':
+ *     Set to FALSE to abort sending this email message.
+ *
+ * @see drupal_mail()
+ */
+function hook_mail_alter(&$message) {
+  if ($message['id'] == 'modulename_messagekey') {
+    if (!example_notifications_optin($message['to'], $message['id'])) {
+      // If the recipient has opted to not receive such messages, cancel
+      // sending.
+      $message['send'] = FALSE;
+      return;
+    }
+    $message['body'][] = "--\nMail sent out from " . \Drupal::config('system.site')->get('name');
+  }
+}
+
+/**
+ * Alter the registry of modules implementing a hook.
+ *
+ * This hook is invoked during \Drupal::moduleHandler()->getImplementations().
+ * A module may implement this hook in order to reorder the implementing
+ * modules, which are otherwise ordered by the module's system weight.
+ *
+ * Note that hooks invoked using \Drupal::moduleHandler->alter() can have
+ * multiple variations(such as hook_form_alter() and hook_form_FORM_ID_alter()).
+ * \Drupal::moduleHandler->alter() will call all such variants defined by a
+ * single module in turn. For the purposes of hook_module_implements_alter(),
+ * these variants are treated as a single hook. Thus, to ensure that your
+ * implementation of hook_form_FORM_ID_alter() is called at the right time,
+ * you will have to change the order of hook_form_alter() implementation in
+ * hook_module_implements_alter().
+ *
+ * @param $implementations
+ *   An array keyed by the module's name. The value of each item corresponds
+ *   to a $group, which is usually FALSE, unless the implementation is in a
+ *   file named $module.$group.inc.
+ * @param $hook
+ *   The name of the module hook being implemented.
+ */
+function hook_module_implements_alter(&$implementations, $hook) {
+  if ($hook == 'rdf_mapping') {
+    // Move my_module_rdf_mapping() to the end of the list.
+    // \Drupal::moduleHandler()->getImplementations()
+    // iterates through $implementations with a foreach loop which PHP iterates
+    // in the order that the items were added, so to move an item to the end of
+    // the array, we remove it and then add it.
+    $group = $implementations['my_module'];
+    unset($implementations['my_module']);
+    $implementations['my_module'] = $group;
+  }
+}
+
+/**
+ * Perform alterations to the breadcrumb built by the BreadcrumbManager.
+ *
+ * @param array $breadcrumb
+ *   An array of breadcrumb link a tags, returned by the breadcrumb manager
+ *   build method, for example
+ *   @code
+ *     array('<a href="/">Home</a>');
+ *   @endcode
+ * @param array $attributes
+ *   Attributes representing the current page, coming from
+ *   \Drupal::request()->attributes.
+ * @param array $context
+ *   May include the following key:
+ *   - builder: the instance of
+ *     \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface that constructed this
+ *     breadcrumb, or NULL if no builder acted based on the current attributes.
+ */
+function hook_system_breadcrumb_alter(array &$breadcrumb, array $attributes, array $context) {
+  // Add an item to the end of the breadcrumb.
+  $breadcrumb[] = Drupal::l(t('Text'), 'example_route_name');
+}
+
+/**
+ * Alter the information parsed from module and theme .info.yml files
+ *
+ * This hook is invoked in _system_rebuild_module_data() and in
+ * _system_rebuild_theme_data(). A module may implement this hook in order to
+ * add to or alter the data generated by reading the .info.yml file with
+ * \Drupal\Core\Extension\InfoParser.
+ *
+ * @param array $info
+ *   The .info.yml file contents, passed by reference so that it can be altered.
+ * @param \Drupal\Core\Extension\Extension $file
+ *   Full information about the module or theme.
+ * @param string $type
+ *   Either 'module' or 'theme', depending on the type of .info.yml file that
+ *   was passed.
+ */
+function hook_system_info_alter(array &$info, \Drupal\Core\Extension\Extension $file, $type) {
+  // Only fill this in if the .info.yml file does not define a 'datestamp'.
+  if (empty($info['datestamp'])) {
+    $info['datestamp'] = $file->getMTime();
+  }
+}
+
+/**
+ * Define user permissions.
+ *
+ * This hook can supply permissions that the module defines, so that they
+ * can be selected on the user permissions page and used to grant or restrict
+ * access to actions the module performs.
+ *
+ * Permissions are checked using user_access().
+ *
+ * For a detailed usage example, see page_example.module.
+ *
+ * @return
+ *   An array whose keys are permission names and whose corresponding values
+ *   are arrays containing the following key-value pairs:
+ *   - title: The human-readable name of the permission, to be shown on the
+ *     permission administration page. This should be wrapped in the t()
+ *     function so it can be translated.
+ *   - description: (optional) A description of what the permission does. This
+ *     should be wrapped in the t() function so it can be translated.
+ *   - restrict access: (optional) A boolean which can be set to TRUE to
+ *     indicate that site administrators should restrict access to this
+ *     permission to trusted users. This should be used for permissions that
+ *     have inherent security risks across a variety of potential use cases
+ *     (for example, the "administer filters" and "bypass node access"
+ *     permissions provided by Drupal core). When set to TRUE, a standard
+ *     warning message defined in user_admin_permissions() and output via
+ *     theme_user_permission_description() will be associated with the
+ *     permission and displayed with it on the permission administration page.
+ *     Defaults to FALSE.
+ *   - warning: (optional) A translated warning message to display for this
+ *     permission on the permission administration page. This warning overrides
+ *     the automatic warning generated by 'restrict access' being set to TRUE.
+ *     This should rarely be used, since it is important for all permissions to
+ *     have a clear, consistent security warning that is the same across the
+ *     site. Use the 'description' key instead to provide any information that
+ *     is specific to the permission you are defining.
+ *
+ * @see theme_user_permission_description()
+ */
+function hook_permission() {
+  return array(
+    'administer my module' =>  array(
+      'title' => t('Administer my module'),
+      'description' => t('Perform administration tasks for my module.'),
+    ),
+  );
+}
+
+/**
+ * Register a module or theme's theme implementations.
+ *
+ * The implementations declared by this hook have several purposes:
+ * - They can specify how a particular render array is to be rendered as HTML.
+ *   This is usually the case if the theme function is assigned to the render
+ *   array's #theme property.
+ * - They can return HTML for default calls to _theme().
+ * - They can return HTML for calls to _theme() for a theme suggestion.
+ *
+ * @param array $existing
+ *   An array of existing implementations that may be used for override
+ *   purposes. This is primarily useful for themes that may wish to examine
+ *   existing implementations to extract data (such as arguments) so that
+ *   it may properly register its own, higher priority implementations.
+ * @param $type
+ *   Whether a theme, module, etc. is being processed. This is primarily useful
+ *   so that themes tell if they are the actual theme being called or a parent
+ *   theme. May be one of:
+ *   - 'module': A module is being checked for theme implementations.
+ *   - 'base_theme_engine': A theme engine is being checked for a theme that is
+ *     a parent of the actual theme being used.
+ *   - 'theme_engine': A theme engine is being checked for the actual theme
+ *     being used.
+ *   - 'base_theme': A base theme is being checked for theme implementations.
+ *   - 'theme': The actual theme in use is being checked.
+ * @param $theme
+ *   The actual name of theme, module, etc. that is being being processed.
+ * @param $path
+ *   The directory path of the theme or module, so that it doesn't need to be
+ *   looked up.
+ *
+ * @return array
+ *   An associative array of information about theme implementations. The keys
+ *   on the outer array are known as "theme hooks". For simple theme
+ *   implementations for regular calls to _theme(), the theme hook is the first
+ *   argument. For theme suggestions, instead of the array key being the base
+ *   theme hook, the key is a theme suggestion name with the format
+ *   'base_hook_name__sub_hook_name'. For render elements, the key is the
+ *   machine name of the render element. The array values are themselves arrays
+ *   containing information about the theme hook and its implementation. Each
+ *   information array must contain either a 'variables' element (for _theme()
+ *   calls) or a 'render element' element (for render elements), but not both.
+ *   The following elements may be part of each information array:
+ *   - variables: Used for _theme() call items only: an array of variables,
+ *     where the array keys are the names of the variables, and the array
+ *     values are the default values if they are not passed into _theme().
+ *     Template implementations receive each array key as a variable in the
+ *     template file (so they must be legal PHP/Twig variable names). Function
+ *     implementations are passed the variables in a single $variables function
+ *     argument.
+ *   - render element: Used for render element items only: the name of the
+ *     renderable element or element tree to pass to the theme function. This
+ *     name is used as the name of the variable that holds the renderable
+ *     element or tree in preprocess and process functions.
+ *   - file: The file the implementation resides in. This file will be included
+ *     prior to the theme being rendered, to make sure that the function or
+ *     preprocess function (as needed) is actually loaded; this makes it
+ *     possible to split theme functions out into separate files quite easily.
+ *   - path: Override the path of the file to be used. Ordinarily the module or
+ *     theme path will be used, but if the file will not be in the default
+ *     path, include it here. This path should be relative to the Drupal root
+ *     directory.
+ *   - template: If specified, this theme implementation is a template, and
+ *     this is the template file without an extension. Do not put .html.twig on
+ *     this file; that extension will be added automatically by the default
+ *     rendering engine (which is Twig). If 'path' above is specified, the
+ *     template should also be in this path.
+ *   - function: If specified, this will be the function name to invoke for
+ *     this implementation. If neither 'template' nor 'function' is specified,
+ *     a default function name will be assumed. For example, if a module
+ *     registers the 'node' theme hook, 'theme_node' will be assigned to its
+ *     function. If the chameleon theme registers the node hook, it will be
+ *     assigned 'chameleon_node' as its function.
+ *   - base hook: Used for _theme() suggestions only: the base theme hook name.
+ *     Instead of this suggestion's implementation being used directly, the base
+ *     hook will be invoked with this implementation as its first suggestion.
+ *     The base hook's files will be included and the base hook's preprocess
+ *     functions will be called in place of any suggestion's preprocess
+ *     functions. If an implementation of hook_theme_suggestions_HOOK() (where
+ *     HOOK is the base hook) changes the suggestion order, a different
+ *     suggestion may be used in place of this suggestion. If after
+ *     hook_theme_suggestions_HOOK() this suggestion remains the first
+ *     suggestion, then this suggestion's function or template will be used to
+ *     generate the output for _theme().
+ *   - pattern: A regular expression pattern to be used to allow this theme
+ *     implementation to have a dynamic name. The convention is to use __ to
+ *     differentiate the dynamic portion of the theme. For example, to allow
+ *     forums to be themed individually, the pattern might be: 'forum__'. Then,
+ *     when the forum is themed, call:
+ *     @code
+ *     _theme(array('forum__' . $tid, 'forum'), $forum)
+ *     @endcode
+ *   - preprocess functions: A list of functions used to preprocess this data.
+ *     Ordinarily this won't be used; it's automatically filled in. By default,
+ *     for a module this will be filled in as template_preprocess_HOOK. For
+ *     a theme this will be filled in as twig_preprocess and
+ *     twig_preprocess_HOOK as well as themename_preprocess and
+ *     themename_preprocess_HOOK.
+ *   - override preprocess functions: Set to TRUE when a theme does NOT want
+ *     the standard preprocess functions to run. This can be used to give a
+ *     theme FULL control over how variables are set. For example, if a theme
+ *     wants total control over how certain variables in the page.html.twig are
+ *     set, this can be set to true. Please keep in mind that when this is used
+ *     by a theme, that theme becomes responsible for making sure necessary
+ *     variables are set.
+ *   - type: (automatically derived) Where the theme hook is defined:
+ *     'module', 'theme_engine', or 'theme'.
+ *   - theme path: (automatically derived) The directory path of the theme or
+ *     module, so that it doesn't need to be looked up.
+ *
+ * @see hook_theme_registry_alter()
+ */
+function hook_theme($existing, $type, $theme, $path) {
+  return array(
+    'forum_display' => array(
+      'variables' => array('forums' => NULL, 'topics' => NULL, 'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL),
+    ),
+    'forum_list' => array(
+      'variables' => array('forums' => NULL, 'parents' => NULL, 'tid' => NULL),
+    ),
+    'forum_icon' => array(
+      'variables' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0),
+    ),
+    'status_report' => array(
+      'render element' => 'requirements',
+      'file' => 'system.admin.inc',
+    ),
+  );
+}
+
+/**
+ * Alter the theme registry information returned from hook_theme().
+ *
+ * The theme registry stores information about all available theme hooks,
+ * including which callback functions those hooks will call when triggered,
+ * what template files are exposed by these hooks, and so on.
+ *
+ * Note that this hook is only executed as the theme cache is re-built.
+ * Changes here will not be visible until the next cache clear.
+ *
+ * The $theme_registry array is keyed by theme hook name, and contains the
+ * information returned from hook_theme(), as well as additional properties
+ * added by \Drupal\Core\Theme\Registry::processExtension().
+ *
+ * For example:
+ * @code
+ * $theme_registry['user'] = array(
+ *   'variables' => array(
+ *     'account' => NULL,
+ *   ),
+ *   'template' => 'core/modules/user/user',
+ *   'file' => 'core/modules/user/user.pages.inc',
+ *   'type' => 'module',
+ *   'theme path' => 'core/modules/user',
+ *   'preprocess functions' => array(
+ *     0 => 'template_preprocess',
+ *     1 => 'template_preprocess_user_profile',
+ *   ),
+ * );
+ * @endcode
+ *
+ * @param $theme_registry
+ *   The entire cache of theme registry information, post-processing.
+ *
+ * @see hook_theme()
+ * @see \Drupal\Core\Theme\Registry::processExtension()
+ */
+function hook_theme_registry_alter(&$theme_registry) {
+  // Kill the next/previous forum topic navigation links.
+  foreach ($theme_registry['forum_topic_navigation']['preprocess functions'] as $key => $value) {
+    if ($value == 'template_preprocess_forum_topic_navigation') {
+      unset($theme_registry['forum_topic_navigation']['preprocess functions'][$key]);
+    }
+  }
+}
+
+/**
+ * Alter the default, hook-independent variables for all templates.
+ *
+ * Allows modules to provide additional default template variables or manipulate
+ * existing. This hook is invoked from template_preprocess() after basic default
+ * template variables have been set up and before the next template preprocess
+ * function is invoked.
+ *
+ * Note that the default template variables are statically cached within a
+ * request. When adding a template variable that depends on other context, it is
+ * your responsibility to appropriately reset the static cache in
+ * template_preprocess() when needed:
+ * @code
+ * drupal_static_reset('template_preprocess');
+ * @endcode
+ *
+ * See user_template_preprocess_default_variables_alter() for an example.
+ *
+ * @param array $variables
+ *   An associative array of default template variables, as set up by
+ *   _template_preprocess_default_variables(). Passed by reference.
+ *
+ * @see template_preprocess()
+ * @see _template_preprocess_default_variables()
+ */
+function hook_template_preprocess_default_variables_alter(&$variables) {
+  $variables['is_admin'] = user_access('access administration pages');
+}
+
+/**
+ * Log an event message.
+ *
+ * This hook allows modules to route log events to custom destinations, such as
+ * SMS, Email, pager, syslog, ...etc.
+ *
+ * @param array $log_entry
+ *   An associative array containing the following keys:
+ *   - type: The type of message for this entry.
+ *   - user: The user object for the user who was logged in when the event
+ *     happened.
+ *   - uid: The user ID for the user who was logged in when the event happened.
+ *   - request_uri: The request URI for the page the event happened in.
+ *   - referer: The page that referred the user to the page where the event
+ *     occurred.
+ *   - ip: The IP address where the request for the page came from.
+ *   - timestamp: The UNIX timestamp of the date/time the event occurred.
+ *   - severity: 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: Normal but significant conditions.
+ *     - WATCHDOG_INFO: Informational messages.
+ *     - WATCHDOG_DEBUG: Debug-level messages.
+ *   - link: An optional link provided by the module that called the watchdog()
+ *     function.
+ *   - message: The text of the message to be logged. Variables in the message
+ *     are indicated by using placeholder strings alongside the variables
+ *     argument to declare the value of the placeholders. See t() for
+ *     documentation on how the message and variable parameters interact.
+ *   - variables: An array of variables to be inserted into the message on
+ *     display. Will be NULL or missing if a message is already translated or if
+ *     the message is not possible to translate.
+ */
+function hook_watchdog(array $log_entry) {
+  global $base_url;
+  $language_interface = \Drupal::languageManager()->getCurrentLanguage();
+
+  $severity_list = array(
+    WATCHDOG_EMERGENCY     => t('Emergency'),
+    WATCHDOG_ALERT     => t('Alert'),
+    WATCHDOG_CRITICAL     => t('Critical'),
+    WATCHDOG_ERROR       => t('Error'),
+    WATCHDOG_WARNING   => t('Warning'),
+    WATCHDOG_NOTICE    => t('Notice'),
+    WATCHDOG_INFO      => t('Info'),
+    WATCHDOG_DEBUG     => t('Debug'),
+  );
+
+  $to = 'someone@example.com';
+  $params = array();
+  $params['subject'] = t('[@site_name] @severity_desc: Alert from your web site', array(
+    '@site_name' => \Drupal::config('system.site')->get('name'),
+    '@severity_desc' => $severity_list[$log_entry['severity']],
+  ));
+
+  $params['message']  = "\nSite:         @base_url";
+  $params['message'] .= "\nSeverity:     (@severity) @severity_desc";
+  $params['message'] .= "\nTimestamp:    @timestamp";
+  $params['message'] .= "\nType:         @type";
+  $params['message'] .= "\nIP Address:   @ip";
+  $params['message'] .= "\nRequest URI:  @request_uri";
+  $params['message'] .= "\nReferrer URI: @referer_uri";
+  $params['message'] .= "\nUser:         (@uid) @name";
+  $params['message'] .= "\nLink:         @link";
+  $params['message'] .= "\nMessage:      \n\n@message";
+
+  $params['message'] = t($params['message'], array(
+    '@base_url'      => $base_url,
+    '@severity'      => $log_entry['severity'],
+    '@severity_desc' => $severity_list[$log_entry['severity']],
+    '@timestamp'     => format_date($log_entry['timestamp']),
+    '@type'          => $log_entry['type'],
+    '@ip'            => $log_entry['ip'],
+    '@request_uri'   => $log_entry['request_uri'],
+    '@referer_uri'   => $log_entry['referer'],
+    '@uid'           => $log_entry['uid'],
+    '@name'          => $log_entry['user']->name,
+    '@link'          => strip_tags($log_entry['link']),
+    '@message'       => strip_tags($log_entry['message']),
+  ));
+
+  drupal_mail('emaillog', 'entry', $to, $language_interface->id, $params);
+}
+
+/**
+ * Prepare a message based on parameters; called from drupal_mail().
+ *
+ * Note that hook_mail(), unlike hook_mail_alter(), is only called on the
+ * $module argument to drupal_mail(), not all modules.
+ *
+ * @param $key
+ *   An identifier of the mail.
+ * @param $message
+ *   An array to be filled in. Elements in this array include:
+ *   - id: An ID to identify the mail sent. Look at module source code
+ *     or drupal_mail() for possible id values.
+ *   - to: The address or addresses the message will be sent to. The
+ *     formatting of this string must comply with RFC 2822.
+ *   - subject: Subject of the e-mail to be sent. This must not contain any
+ *     newline characters, or the mail may not be sent properly. drupal_mail()
+ *     sets this to an empty string when the hook is invoked.
+ *   - body: An array of lines containing the message to be sent. Drupal will
+ *     format the correct line endings for you. drupal_mail() sets this to an
+ *     empty array when the hook is invoked.
+ *   - from: The address the message will be marked as being from, which is
+ *     set by drupal_mail() to either a custom address or the site-wide
+ *     default email address when the hook is invoked.
+ *   - headers: Associative array containing mail headers, such as From,
+ *     Sender, MIME-Version, Content-Type, etc. drupal_mail() pre-fills
+ *     several headers in this array.
+ * @param $params
+ *   An array of parameters supplied by the caller of drupal_mail().
+ */
+function hook_mail($key, &$message, $params) {
+  $account = $params['account'];
+  $context = $params['context'];
+  $variables = array(
+    '%site_name' => \Drupal::config('system.site')->get('name'),
+    '%username' => user_format_name($account),
+  );
+  if ($context['hook'] == 'taxonomy') {
+    $entity = $params['entity'];
+    $vocabulary = entity_load('taxonomy_vocabulary', $entity->id());
+    $variables += array(
+      '%term_name' => $entity->name,
+      '%term_description' => $entity->description,
+      '%term_id' => $entity->id(),
+      '%vocabulary_name' => $vocabulary->name,
+      '%vocabulary_description' => $vocabulary->description,
+      '%vocabulary_id' => $vocabulary->id(),
+    );
+  }
+
+  // Node-based variable translation is only available if we have a node.
+  if (isset($params['node'])) {
+    /** @var \Drupal\node\NodeInterface $node */
+    $node = $params['node'];
+    $variables += array(
+      '%uid' => $node->getOwnerId(),
+      '%node_url' => url('node/' . $node->id(), array('absolute' => TRUE)),
+      '%node_type' => node_get_type_label($node),
+      '%title' => $node->getTitle(),
+      '%teaser' => $node->teaser,
+      '%body' => $node->body,
+    );
+  }
+  $subject = strtr($context['subject'], $variables);
+  $body = strtr($context['message'], $variables);
+  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
+  $message['body'][] = drupal_html_to_text($body);
+}
+
+/**
  * Flush all persistent and static caches.
  *
  * This hook asks your module to clear all of its static caches,