diff --git a/core/core.services.yml b/core/core.services.yml
index e49da7f..d03cffe 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -436,6 +436,43 @@ services:
     class: Drupal\system\Plugin\ImageToolkitInterface
     factory_method: getDefaultToolkit
     factory_service: image.toolkit.manager
+  fragment_handler:
+    class: Symfony\Component\HttpKernel\Fragment\FragmentHandler
+    tags:
+      - { name: event_subscriber }
+      - { name: fragment_handler }
+  block.address_generator:
+    class: Drupal\block\BlockAddressGenerator
+    arguments: ['@url_generator']
+  block_controller:
+    class: Drupal\block\DefaultBlockController
+    arguments: ['@module_handler']
+  block_renderer_inline:
+    class: Drupal\Core\FragmentRenderer\InlineBlockFragmentRenderer
+    arguments: ['@http_kernel', '@block.address_generator', '@block_controller']
+    tags:
+      - { name: render_strategy }
+  display_route_enhancer:
+    class: Drupal\Core\Booze\DisplayRouteEnhancer
+    tags:
+      - { name: route_enhancer }
+  content_route_enhancer:
+    class: Drupal\Core\Booze\ContentRouteEnhancer
+    arguments: ['@controller_resolver']
+    tags:
+      - { name: route_enhancer }
+  display_controller_subscriber:
+    class: Drupal\Core\EventSubscriber\DisplayControllerSubscriber
+    arguments: ['@module_handler']
+    tags:
+      - { name: event_subscriber }
+  asset_library_manager:
+    class: Drupal\Core\Asset\AssetLibraryManager
+  html_view_subscriber:
+    class: Drupal\Core\EventSubscriber\HtmlViewSubscriber
+    tags:
+      - { name: event_subscriber }
+    arguments: ['@module_handler']
   token:
     class: Drupal\Core\Utility\Token
     arguments: ['@module_handler']
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5387f71..26222b8 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1779,6 +1779,7 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
  * @return
  *   An array of queued cascading stylesheets.
  *
+ * @deprecated
  * @see drupal_get_css()
  */
 function drupal_add_css($data = NULL, $options = NULL) {
@@ -2973,6 +2974,7 @@ function drupal_add_js($data = NULL, $options = NULL) {
  *
  * @see drupal_get_js()
  * @see drupal_add_js()
+ * @deprecated
  */
 function drupal_js_defaults($data = NULL) {
   return array(
diff --git a/core/includes/config.inc b/core/includes/config.inc
index 32ba50d..b2493b0 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -169,6 +169,37 @@ function config_get_entity_type_by_name($name) {
 }
 
 /**
+ * Loads the correct type of ConfigEntity from a full configuration object name.
+ *
+ * ConfigEntity expects that the id passed to entity_load() will not include the
+ * config prefix used by the entity type being loaded. This is unhelpful for
+ * calling code that has the fully prefixed configuration object name and can
+ * not reliably know the specific type of ConfigEntity to load.
+ *
+ * This function figures out which type of entity the configuration object
+ * corresponds to, then performs the entity_load().
+ *
+ * Note: this should only be used if the calling code CANNOT safely know what
+ * type of ConfigEntity it should be loading ahead of time. Otherwise, use
+ * entity_load() directly.
+ *
+ * @param $name
+ *   The full configuration object name, including prefix.
+ *
+ * @return \Drupal\Core\Config\Entity\ConfigEntityInterface
+ */
+function config_load_entity_by_name($name) {
+  $entity = array_filter(entity_get_info(), function($entity_info) use ($name) {
+    return (isset($entity_info['config_prefix']) && strpos($name, $entity_info['config_prefix'] . '.') === 0);
+  });
+
+  list($type, $info) = each($entity);
+  $id = substr($name, strlen($info['config_prefix'] . '.'));
+
+  return entity_load($type, $id);
+}
+
+/**
  * Returns the typed config manager service.
  *
  * Use the typed data manager service for creating typed configuration objects.
diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
index 2d1aa8a..87eaaad 100644
--- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
+++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
@@ -113,4 +113,11 @@ public function setContextValue($name, $value);
    */
   public function validateContexts();
 
+ /**
+   * Indicates whether or not all contextual requirements have been satisfied.
+   *
+   * @return bool
+   */
+  public function contextIsSatisfied();
+
 }
diff --git a/core/lib/Drupal/Core/Asset/AssetBag.php b/core/lib/Drupal/Core/Asset/AssetBag.php
new file mode 100644
index 0000000..4732f1b
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetBag.php
@@ -0,0 +1,257 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetBag.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\AssetInterface;
+use Drupal\Core\Asset\AssetBagInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * The default AssetBag, used to declare assets needed for a response.
+ */
+class AssetBag implements AssetBagInterface {
+
+  /**
+   * The container to be used by this AssetBag when accessing services.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected $container;
+
+  protected $assets = array();
+
+  protected $hasJs = FALSE;
+
+  protected $hasCss = FALSE;
+
+  protected $terminated = FALSE;
+
+  protected $sorted = array();
+
+  protected $needsSorting = FALSE;
+
+  /**
+   * An indexed array holding nested AssetBagInterface objects.
+   *
+   * @todo there's a better solution here using SplObjectStorage
+   *
+   * @var array
+   */
+  protected $bags;
+
+  /**
+   * Constructs an AssetBag object, initializing certain values.
+   *
+   * @return \Drupal\Core\Asset\AssetBag
+   */
+  public function __construct() {
+//    $this->javascript['settings'] = array(
+//      'type' => 'setting',
+//      'scope' => 'header',
+//      'group' => JS_SETTING,
+//      'every_page' => TRUE,
+//      'weight' => 0,
+//      'browsers' => array(),
+//    );
+    // @todo this stuff made sense in drupal_add_js(), but seems redundant to have in each AssetBag.
+    // url() generates the script and prefix using hook_url_outbound_alter().
+    // Instead of running the hook_url_outbound_alter() again here, extract
+    // them from url().
+    // @todo Make this less hacky: http://drupal.org/node/1547376.
+//    $scriptPath = $GLOBALS['script_path'];
+//    $pathPrefix = '';
+//    url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
+//    $this->javascript['settings']['data'][] = array(
+//      'basePath' => base_path(),
+//      'scriptPath' => $scriptPath,
+//      'pathPrefix' => $pathPrefix,
+//      'currentPath' => current_path(),
+//    );
+  }
+
+  public function add(AssetInterface $asset) {
+    if ($this->terminated) {
+      throw new \LogicException('Assets cannot be added to a terminated AssetBag.', E_ERROR);
+    }
+
+    $this->needsSorting = TRUE;
+
+    $this->assets[] = $asset;
+    if ($asset instanceof JavascriptAssetInterface) {
+      $this->hasJs = TRUE;
+    }
+    if ($asset instanceof StylesheetAssetInterface) {
+      $this->hasCss = TRUE;
+    }
+  }
+
+  /**
+   * Adds another AssetBag to this one.
+   *
+   * @param \Drupal\Core\Asset\AssetBagInterface $bag
+   * @param bool              $terminate
+   *   Whether or not the provided bag should be flagged as terminated.
+   *
+   * @return mixed|void
+   * @throws \LogicException
+   */
+  public function addAssetBag(AssetBagInterface $bag, $terminate = TRUE) {
+    if ($this->terminated) {
+      throw new \LogicException('Assets cannot be added to a terminated AssetBag.', E_ERROR);
+    }
+
+    foreach ($bag->all() as $asset) {
+      $this->add($asset);
+    }
+
+    if ($terminate) {
+      $bag->terminate();
+    }
+  }
+
+  /**
+   * Indicates whether this object contains any CSS assets.
+   *
+   * @return bool
+   */
+  public function hasCss() {
+    return $this->hasCss;
+  }
+
+  /**
+   * Returns the CSS assets in this bag, fully resolved into page order.
+   *
+   * @todo see if we can make this return an AssetCollection
+   *
+   * @return array
+   */
+  public function getCss() {
+    $this->sort();
+    return $this->sorted['css'];
+  }
+
+
+  /**
+   * Returns all CSS assets contained directly in the bag.
+   *
+   * Note that this will NOT include assets that have been brought in as part of
+   * dependency declarations.
+   *
+   * @return array
+   *   An array of CSS assets, ordered by the sequence in which they entered the
+   *   bag.
+   */
+  public function getUnsortedCss() {
+    $css = array();
+    foreach ($this->assets as $asset) {
+      if ($asset instanceof StylesheetAssetInterface) {
+        $css[] = $asset;
+      }
+    }
+
+    return $css;
+  }
+
+
+  /**
+   * Sorts all assets in this bag into their final rendering order.
+   */
+  protected function sort() {
+    if (!$this->needsSorting) {
+      return;
+    }
+
+    $this->sorted['js'] = $this->sorted['css'] = array();
+
+    $all = array();
+
+
+    $this->needsSorting = FALSE;
+  }
+
+
+  /**
+   * Returns all assets contained in this object.
+   *
+   * The assets are returned in the order in which they were added, which is
+   * unlikely to be the final correct rendering order.
+   *
+   * @return array
+   */
+  public function all() {
+    return $this->assets;
+  }
+
+
+  /**
+   * Adds configuration settings for eventual inclusion in drupalSettings.
+   *
+   * @todo decide how to handle these in a fully-classed asset system
+   *
+   * @param $data
+   *   An associative array containing configuration settings, to be eventually
+   *   merged into drupalSettings. Settings should be be wrapped in another
+   *   variable, typically by module name, in order to avoid conflicts in the
+   *   drupalSettings namespace. Items added with a string key will replace
+   *   existing settings with that key; items with numeric array keys will be
+   *   added to the existing settings array.
+   *
+   * @return AssetBagInterface $this
+   *   Returns the current AssetBagInterface object for method chaining.
+   */
+  public function addJsSetting($data) {
+    $this->javascript['settings']['data'][] = $data;
+  }
+
+  /**
+   * Indicates whether this AssetBagInterface contains any JavaScript assets.
+   *
+   * @return bool
+   */
+  public function hasJs() {
+    return $this->hasJs;
+  }
+
+  /**
+   * Returns the JavaScript assets in this bag, fully resolved into page order.
+   *
+   * @todo see if we can make this return an AssetCollection
+   *
+   * @return array
+   */
+  public function getJs() {
+    $this->sort();
+    return $this->sorted['js'];
+  }
+
+
+  /**
+   * Returns all JavaScript assets contained directly in the bag.
+   *
+   * Note that this will NOT include assets that have been brought in as part of
+   * dependency declarations.
+   *
+   * @return array
+   *   An array of JavaScript assets, ordered by the sequence in which they
+   *   entered the bag.
+   */
+  public function getUnsortedJs() {
+    $js = array();
+    foreach ($this->assets as $asset) {
+      if ($asset instanceof JavascriptAssetInterface) {
+        $js[] = $asset;
+      }
+    }
+
+    return $js;
+  }
+
+  public function terminate() {
+    $this->terminated = TRUE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/AssetBagInterface.php b/core/lib/Drupal/Core/Asset/AssetBagInterface.php
new file mode 100644
index 0000000..8f0356d
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetBagInterface.php
@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetBagInterface.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\AssetInterface;
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+
+/**
+ * Defines a common interface for asset bags.
+ *
+ * Asset bags are a mechanism for internal Drupal code to list a set of assets
+ * and provide some metadata about their manner of use. During a normal page
+ * build, a number of these bags are likely to be built and ultimately merged
+ * onto the Response object.
+ *
+ * An AssetBagInterface object's contents are not expected to be in the final,
+ * ordered form in which will ultimately be delivered as part of the page
+ * response. Rather, a stack of such bags will be combined towards the end of
+ * the page request into the final asset list.
+ */
+interface AssetBagInterface {
+
+  public function add(AssetInterface $asset);
+
+  /**
+   * Adds another AssetBag to this one.
+   *
+   * @param AssetBagInterface $bag
+   *
+   * @return mixed
+   */
+  public function addAssetBag(AssetBagInterface $bag);
+
+  /**
+   * Adds configuration settings for eventual inclusion in Drupal.settings.
+   *
+   * @todo fix this up to use proper classes asset objects somehow
+   *
+   * @param $data
+   *   An associative array containing configuration settings, to be eventually
+   *   merged into drupalSettings. Settings should be be wrapped in another
+   *   variable, typically by module name, in order to avoid conflicts in the
+   *   Drupal.settings namespace. Items added with a string key will replace
+   *   existing settings with that key; items with numeric array keys will be
+   *   added to the existing settings array.
+   *
+   * @return AssetBagInterface $this
+   *   Returns the current AssetBagInterface object for method chaining.
+   */
+  public function addJsSetting($data);
+
+  /**
+   * Indicates whether this object contains any CSS assets.
+   *
+   * @return bool
+   */
+  public function hasCss();
+
+  /**
+   * Returns the CSS assets in this bag, fully resolved into page order.
+   *
+   * @todo see if we can make this return an AssetCollection
+   *
+   * @return array
+   */
+  public function getCss();
+
+  /**
+   * Returns all CSS assets contained directly in the bag.
+   *
+   * Note that this will NOT include assets that have been brought in as part of
+   * dependency declarations.
+   *
+   * @return array
+   *   An array of CSS assets, ordered by the sequence in which they entered the
+   *   bag.
+   */
+  public function getUnsortedCss();
+
+  /**
+   * Indicates whether this AssetBagInterface contains any JavaScript assets.
+   *
+   * @return bool
+   */
+  public function hasJs();
+
+  /**
+   * Returns the JavaScript assets in this bag, fully resolved into page order.
+   *
+   * @todo see if we can make this return an AssetCollection
+   *
+   * @return array
+   */
+  public function getJs();
+
+  /**
+   * Returns all JavaScript assets contained directly in the bag.
+   *
+   * Note that this will NOT include assets that have been brought in as part of
+   * dependency declarations.
+   *
+   * @return array
+   *   An array of JavaScript assets, ordered by the sequence in which they
+   *   entered the bag.
+   */
+  public function getUnsortedJs();
+
+  /**
+   * Returns all assets contained in this object.
+   *
+   * The assets are returned in the order in which they were added, which is
+   * unlikely to be the final correct rendering order.
+   *
+   * @return array
+   */
+  public function all();
+
+  /**
+   * Marks this bag as incapable of receiving new assets.
+   *
+   * @return void
+   */
+  public function terminate();
+}
diff --git a/core/lib/Drupal/Core/Asset/AssetGrouper.php b/core/lib/Drupal/Core/Asset/AssetGrouper.php
new file mode 100644
index 0000000..3087a98
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetGrouper.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Asset\AssetGrouper.
+ */
+
+namespace Drupal\Core\Asset;
+
+/**
+ * Default asset grouper for Drupal.
+ */
+class AssetGrouper implements AssetGroupingInterface {
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Asset/AssetGroupingInterface.php b/core/lib/Drupal/Core/Asset/AssetGroupingInterface.php
new file mode 100644
index 0000000..aadc38e
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetGroupingInterface.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Asset\AssetGroupingInterface.
+ */
+
+namespace Drupal\Core\Asset;
+
+/**
+ * Interface defining a service that organizes sets of assets into groups.
+ */
+interface AssetGroupingInterface {
+
+  /**
+   * Organizes the passed collection of assets into groups.
+   *
+   * Each group is itself an array, containing all asset data for each of the
+   * assets contained within the group.
+   *
+   * @param array $collection
+   *   A single-level array containing assets as contained in drupal_add_css()
+   *   or drupal_add_js().
+   *
+   * @return array
+   *   A two-level array containing asset groups, which themselves contain all
+   *   the assets from the original parameter.
+   *
+   */
+  public function groupAssets($collection);
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Asset/AssetInterface.php b/core/lib/Drupal/Core/Asset/AssetInterface.php
new file mode 100644
index 0000000..ebf7381
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetInterface.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetInterface.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Asset\AssetInterface as AsseticAssetInterface;
+
+/**
+ * Represents an asset.
+ *
+ * This interface extends the AssetInterface provided by Assetic to allow
+ * more sophisticated logic and behaviors to be attached to individual assets.
+ */
+interface AssetInterface extends AsseticAssetInterface {
+
+  /**
+   * Sets the flag indicating preprocessability.
+   *
+   * @param bool $preprocess
+   *
+   * @return AssetInterface
+   *
+   * @see AssetInterface::isPreprocessable()
+   */
+  public function setPreprocessable($preprocess = TRUE);
+
+  /**
+   * Indicates whether or not this asset is eligible for preprocessing.
+   *
+   * Assets that are marked as not preprocessable will always be passed directly
+   * through to the browser without aggregation. Assets that are marked as
+   * eligible for preprocessing will be included in any broader aggregation
+   * logic that has been configured.
+   *
+   * @return bool
+   */
+  public function isPreprocessable();
+
+  /**
+   * Set an explicit weight for this asset.
+   *
+   * Weight is used to determine asset ordering. Explicitly setting a weight
+   * is generally not a good idea, as weights are dynamically calculated. It is
+   * generally better to let the system determine the appropriate weight by
+   * looking at the entry point at which your asset was added to the stack.
+   *
+   * @param int $weight
+   *
+   * @return void
+   */
+  public function setWeight($weight);
+
+  public function getWeight();
+
+  /**
+   * @todo can we do this with a filter?
+   */
+  public function setBrowsers();
+
+  public function getBrowsers();
+}
diff --git a/core/lib/Drupal/Core/Asset/AssetLibrary.php b/core/lib/Drupal/Core/Asset/AssetLibrary.php
new file mode 100644
index 0000000..4b65ecf
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetLibrary.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetLibrary.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Asset\AssetCollection;
+use Assetic\Asset\AssetInterface as AsseticAssetInterface;
+use Drupal\Core\Asset\AssetInterface as DrupalAssetInterface;
+
+/**
+ * @todo not sure if AssetCollection will be a good baseline for this
+ */
+class AssetLibrary extends AssetCollection {
+
+  protected $title = '';
+
+  protected $version;
+
+  protected $website = '';
+
+  /**
+   * @todo really, what's the use case here?
+   *
+   * @param $title
+   */
+  public function setTitle($title) {
+    $this->title = $title;
+    return $this;
+  }
+
+  public function getTitle() {
+    return $this->title;
+  }
+
+  /**
+   * @todo omgwtfbbqsigh - do we really need this?
+   *
+   * @param $website
+   */
+  public function setWebsite($website) {
+    $this->website = $website;
+    return $this;
+  }
+
+  public function getWebsite() {
+    return $this->website;
+  }
+
+  public function setVersion($version) {
+    $this->version = $version;
+    return $this;
+  }
+
+  public function getVersion() {
+    return $this->version;
+  }
+
+  public function add(AsseticAssetInterface $asset) {
+    // @todo ugh.
+    if (!$asset instanceof DrupalAssetInterface) {
+      throw new \InvalidArgumentException('Drupal library assets must conform to Drupal\'s AssetInterface.');
+    }
+
+    return parent::add($asset);
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/AssetLibraryManager.php b/core/lib/Drupal/Core/Asset/AssetLibraryManager.php
new file mode 100644
index 0000000..b3ff5bb
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetLibraryManager.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetLibraryManager.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\AssetManager;
+
+class AssetLibraryManager extends AssetManager {
+  protected $libraries;
+}
diff --git a/core/lib/Drupal/Core/Asset/AssetLibraryReference.php b/core/lib/Drupal/Core/Asset/AssetLibraryReference.php
new file mode 100644
index 0000000..df48267
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AssetLibraryReference.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\AssetLibraryReference.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Asset\AssetReference;
+use Drupal\Core\Asset\AssetLibraryManager;
+
+class AssetLibraryReference {
+
+  /**
+   * @var \Drupal\Core\Asset\AssetLibraryManager;
+   */
+  protected $manager;
+
+  public function __construct($name, AssetLibraryManager $manager = NULL) {
+    if (!$manager instanceof AssetLibraryManager) {
+      // If no manager was injected, fetch it via global container access
+      $this->manager = drupal_container()->get('asset_library_manager');
+    }
+  }
+
+  public function getAssets() {
+
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/BaseAsset.php b/core/lib/Drupal/Core/Asset/BaseAsset.php
new file mode 100644
index 0000000..c7fa521
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/BaseAsset.php
@@ -0,0 +1,230 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\BaseAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Filter\FilterCollection;
+use Assetic\Filter\FilterInterface;
+use Drupal\Core\Asset\AssetInterface;
+
+/**
+ * A base abstract asset.
+ *
+ * This is an amalgam of Assetic\Asset\BaseAsset (copied directly) with
+ * implementations of the additional methods specified by Drupal's own
+ * Drupal\Core\Asset\AssetInterface.
+ *
+ * The methods load() and getLastModified() are left undefined, although a
+ * reusable doLoad() method is available to child classes.
+ */
+abstract class BaseAsset implements AssetInterface {
+
+  protected $filters;
+
+  protected $sourceRoot;
+
+  protected $sourcePath;
+
+  protected $targetPath;
+
+  protected $content;
+
+  protected $loaded;
+
+  protected $vars;
+
+  protected $values;
+
+  protected $preprocess = TRUE;
+
+  protected $weightOffset = NULL;
+
+  protected $explicitWeight = 0;
+
+  /**
+   * Constructor.
+   *
+   * @param array $filters Filters for the asset
+   */
+  public function __construct($filters = array(), $sourceRoot = NULL, $sourcePath = NULL, array $vars = array()) {
+    $this->filters = new FilterCollection($filters);
+    $this->sourceRoot = $sourceRoot;
+    $this->sourcePath = $sourcePath;
+    $this->vars = $vars;
+    $this->values = array();
+    $this->loaded = FALSE;
+  }
+
+  public function __clone() {
+    $this->filters = clone $this->filters;
+  }
+
+  public function ensureFilter(FilterInterface $filter) {
+    $this->filters->ensure($filter);
+  }
+
+  public function getFilters() {
+    return $this->filters->all();
+  }
+
+  public function clearFilters() {
+    $this->filters->clear();
+  }
+
+  /**
+   * Encapsulates asset loading logic.
+   *
+   * @param string          $content          The asset content
+   * @param FilterInterface $additionalFilter An additional filter
+   */
+  protected function doLoad($content, FilterInterface $additionalFilter = NULL) {
+    $filter = clone $this->filters;
+    if ($additionalFilter) {
+      $filter->ensure($additionalFilter);
+    }
+
+    $asset = clone $this;
+    $asset->setContent($content);
+
+    $filter->filterLoad($asset);
+    $this->content = $asset->getContent();
+
+    $this->loaded = TRUE;
+  }
+
+  public function dump(FilterInterface $additionalFilter = NULL) {
+    if (!$this->loaded) {
+      $this->load();
+    }
+
+    $filter = clone $this->filters;
+    if ($additionalFilter) {
+      $filter->ensure($additionalFilter);
+    }
+
+    $asset = clone $this;
+    $filter->filterDump($asset);
+
+    return $asset->getContent();
+  }
+
+  public function getContent() {
+    return $this->content;
+  }
+
+  public function setContent($content) {
+    $this->content = $content;
+  }
+
+  public function getSourceRoot() {
+    return $this->sourceRoot;
+  }
+
+  public function getSourcePath() {
+    return $this->sourcePath;
+  }
+
+  public function getTargetPath() {
+    return $this->targetPath;
+  }
+
+  public function setTargetPath($targetPath) {
+    if ($this->vars) {
+      foreach ($this->vars as $var) {
+        if (FALSE === strpos($targetPath, $var)) {
+          throw new \RuntimeException(sprintf('The asset target path "%s" must contain the variable "{%s}".', $targetPath, $var));
+        }
+      }
+    }
+
+    $this->targetPath = $targetPath;
+  }
+
+  public function getVars() {
+    return $this->vars;
+  }
+
+  public function setValues(array $values) {
+    foreach ($values as $var => $v) {
+      if (!in_array($var, $this->vars, TRUE)) {
+        throw new \InvalidArgumentException(sprintf('The asset with source path "%s" has no variable named "%s".', $this->sourcePath, $var));
+      }
+    }
+
+    $this->values = $values;
+    $this->loaded = FALSE;
+  }
+
+  public function getValues() {
+    return $this->values;
+  }
+
+  /**
+   * Sets the flag indicating preprocessability.
+   *
+   * @param bool $preprocess
+   *
+   * @return AssetInterface
+   *
+   * @see AssetInterface::isPreprocessable()
+   */
+  public function setPreprocessable($preprocess = TRUE) {
+    $this->preprocess = $preprocess;
+  }
+
+  /**
+   * Indicates whether or not this asset is eligible for preprocessing.
+   *
+   * Assets that are marked as not preprocessable will always be passed directly
+   * through to the browser without aggregation. Assets that are marked as
+   * eligible for preprocessing will be included in any broader aggregation
+   * logic that has been configured.
+   *
+   * @return bool
+   */
+  public function isPreprocessable() {
+    return (bool) $this->preprocess;
+  }
+
+  /**
+   * Set an explicit weight for this asset.
+   *
+   * Weight is used to determine asset ordering. Explicitly setting a weight
+   * is generally not a good idea, as weights are dynamically calculated. It is
+   * generally better to let the system determine the appropriate weight by
+   * looking at the entry point at which your asset was added to the stack.
+   *
+   * @param int $weight
+   *
+   * @return void
+   */
+  public function setWeight($weight) {
+    $this->explicitWeight = (int) $weight;
+  }
+
+  public function getWeight($raw = FALSE) {
+    // @todo All of this is crap.
+    $weight = empty($this->explicitWeight) ? $this->weight : $this->explicitWeight;
+    if ($raw) {
+      return $weight;
+    }
+    else {
+      return $weight + $this->weightOffset;
+    }
+  }
+
+  /**
+   * @todo can we do this with a filter?
+   */
+  public function setBrowsers() {
+    // TODO: Implement setBrowsers() method.
+  }
+
+  public function getBrowsers() {
+    // TODO: Implement getBrowsers() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/BaseExternalAsset.php b/core/lib/Drupal/Core/Asset/BaseExternalAsset.php
new file mode 100644
index 0000000..c61dbcc
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/BaseExternalAsset.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\BaseFileAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Util\PathUtils;
+use Assetic\Filter\FilterInterface;
+use Drupal\Core\Asset\BaseAsset;
+
+abstract class BaseExternalAsset extends BaseAsset {
+
+  protected $preprocess = FALSE;
+
+  /**
+   * @todo Wholly grabbed from Assetic; probably needs Druplification
+   *
+   * @param array $sourceUrl
+   * @param array $filters
+   * @param bool  $ignoreErrors
+   * @param array $vars
+   */
+  public function __construct($sourceUrl, $filters = array(), $ignoreErrors = FALSE, array $vars = array()) {
+    if (0 === strpos($sourceUrl, '//')) {
+      $sourceUrl = 'http:'.$sourceUrl;
+    } elseif (FALSE === strpos($sourceUrl, '://')) {
+      throw new \InvalidArgumentException(sprintf('"%s" is not a valid URL.', $sourceUrl));
+    }
+
+    $this->sourceUrl = $sourceUrl;
+    $this->ignoreErrors = $ignoreErrors;
+
+    list($scheme, $url) = explode('://', $sourceUrl, 2);
+    list($host, $path) = explode('/', $url, 2);
+
+    parent::__construct($filters, $scheme.'://'.$host, $path, $vars);
+  }
+  /**
+   * Returns the time the current asset was last modified.
+   *
+   * @todo copied right from Assetic. needs to be made more Drupalish.
+   *
+   * @return integer|null A UNIX timestamp
+   */
+  public function getLastModified() {
+    if (false !== @file_get_contents($this->sourceUrl, false, stream_context_create(array('http' => array('method' => 'HEAD'))))) {
+      foreach ($http_response_header as $header) {
+        if (0 === stripos($header, 'Last-Modified: ')) {
+          list(, $mtime) = explode(':', $header, 2);
+
+          return strtotime(trim($mtime));
+        }
+      }
+    }
+  }
+
+  /**
+   * Loads the asset into memory and applies load filters.
+   *
+   * You may provide an additional filter to apply during load.
+   *
+   * @todo copied right from Assetic. needs to be made more Drupalish.
+   *
+   * @param FilterInterface $additionalFilter An additional filter
+   */
+  public function load(FilterInterface $additionalFilter = NULL) {
+    if (false === $content = @file_get_contents(PathUtils::resolvePath(
+      $this->sourceUrl, $this->getVars(), $this->getValues()))) {
+      if ($this->ignoreErrors) {
+        return;
+      } else {
+        throw new \RuntimeException(sprintf('Unable to load asset from URL "%s"', $this->sourceUrl));
+      }
+    }
+
+    $this->doLoad($content, $additionalFilter);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Asset/BaseFileAsset.php b/core/lib/Drupal/Core/Asset/BaseFileAsset.php
new file mode 100644
index 0000000..ee3c52a
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/BaseFileAsset.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\BaseFileAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Util\PathUtils;
+use Assetic\Filter\FilterInterface;
+use Drupal\Core\Asset\BaseAsset;
+
+abstract class BaseFileAsset extends BaseAsset {
+
+  protected $source;
+
+  public function __construct($source, $filters = array(), $sourceRoot = null, $sourcePath = null, array $vars = array()) {
+    if (null === $sourceRoot) {
+      $sourceRoot = dirname($source);
+      if (null === $sourcePath) {
+        $sourcePath = basename($source);
+      }
+    } elseif (null === $sourcePath) {
+      if (0 !== strpos($source, $sourceRoot)) {
+        throw new \InvalidArgumentException(sprintf('The source "%s" is not in the root directory "%s"', $source, $sourceRoot));
+      }
+
+      $sourcePath = substr($source, strlen($sourceRoot) + 1);
+    }
+
+    $this->source = $source;
+
+    parent::__construct($filters, $sourceRoot, $sourcePath, $vars);
+  }
+
+  /**
+   * Returns the time the current asset was last modified.
+   *
+   * @todo copied right from Assetic. needs to be made more Drupalish.
+   *
+   * @return integer|null A UNIX timestamp
+   */
+  public function getLastModified() {
+    $source = PathUtils::resolvePath($this->source, $this->getVars(),
+      $this->getValues());
+
+    if (!is_file($source)) {
+      throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source));
+    }
+
+    return filemtime($source);
+  }
+
+  /**
+   * Loads the asset into memory and applies load filters.
+   *
+   * You may provide an additional filter to apply during load.
+   *
+   * @todo copied right from Assetic. needs to be made more Drupalish.
+   *
+   * @param FilterInterface $additionalFilter An additional filter
+   */
+  public function load(FilterInterface $additionalFilter = NULL) {
+    $source = PathUtils::resolvePath($this->source, $this->getVars(),
+      $this->getValues());
+
+    if (!is_file($source)) {
+      throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source));
+    }
+
+    $this->doLoad(file_get_contents($source), $additionalFilter);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Asset/BaseStringAsset.php b/core/lib/Drupal/Core/Asset/BaseStringAsset.php
new file mode 100644
index 0000000..4f7b4b3
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/BaseStringAsset.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\BaseInlineAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Assetic\Filter\FilterInterface;
+use Drupal\Core\Asset\BaseAsset;
+
+abstract class BaseStringAsset extends BaseAsset {
+
+  protected $lastModified;
+
+  protected $preprocess = FALSE;
+
+  public function __construct($content, $filters = array(), $sourceRoot = null, $sourcePath = null) {
+    $this->content = $content;
+
+    parent::__construct($filters, $sourceRoot, $sourcePath);
+  }
+
+  public function setLastModified($last_modified) {
+    $this->lastModified = $last_modified;
+  }
+
+  public function getLastModified() {
+    return $this->lastModified;
+  }
+
+  public function load(FilterInterface $additionalFilter = NULL) {
+    $this->doLoad($this->content, $additionalFilter);
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/JavascriptAssetInterface.php b/core/lib/Drupal/Core/Asset/JavascriptAssetInterface.php
new file mode 100644
index 0000000..01f4930
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JavascriptAssetInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\JavascriptAssetInterface.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\AssetInterface;
+
+/**
+ * Represents a JavaScript asset.
+ */
+interface JavascriptAssetInterface extends AssetInterface {
+
+  public function setScope($scope);
+
+  public function getScope();
+
+  public function getScopeDefault();
+
+//  public function addDependency($name);
+//
+//  public function hasDependencies();
+//
+//  public function getDependencies();
+}
diff --git a/core/lib/Drupal/Core/Asset/JavascriptExternalAsset.php b/core/lib/Drupal/Core/Asset/JavascriptExternalAsset.php
new file mode 100644
index 0000000..0984dd7
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JavascriptExternalAsset.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\JavascriptExternalAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\JavascriptAssetInterface;
+use Drupal\Core\Asset\BaseExternalAsset;
+
+class JavascriptExternalAsset extends BaseExternalAsset implements JavascriptAssetInterface {
+
+  protected $scope;
+
+  /**
+   * Scope defaults to footer as almost all JavaScript assets can be placed in
+   * the footer.
+   *
+   * @tricky this is a change from the previous behavior!
+   *
+   * @var string
+   */
+  protected $scopeDefault = 'footer';
+
+  public function setScope($scope) {
+    $this->scope = $scope;
+  }
+
+  public function getScope() {
+    return empty($this->scope) ? $this->scopeDefault : $this->scope;
+  }
+
+  public function getScopeDefault() {
+    return $this->scopeDefault;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/JavascriptFileAsset.php b/core/lib/Drupal/Core/Asset/JavascriptFileAsset.php
new file mode 100644
index 0000000..3235e14
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JavascriptFileAsset.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\JavascriptFileAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\JavascriptAssetInterface;
+use Drupal\Core\Asset\AssetLibraryReference;
+use Drupal\Core\Asset\BaseFileAsset;
+
+class JavascriptFileAsset extends BaseFileAsset implements JavascriptAssetInterface {
+
+  protected $scope;
+
+  /**
+   * Scope defaults to footer as almost all JavaScript assets can be placed in
+   * the footer.
+   *
+   * @tricky this is a change from the previous behavior!
+   *
+   * @var string
+   */
+  protected $scopeDefault = 'footer';
+
+  public function setScope($scope) {
+    $this->scope = $scope;
+  }
+
+  public function getScope() {
+    return empty($this->scope) ? $this->scopeDefault : $this->scope;
+  }
+
+  public function getScopeDefault() {
+    return $this->scopeDefault;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/JavascriptStringAsset.php b/core/lib/Drupal/Core/Asset/JavascriptStringAsset.php
new file mode 100644
index 0000000..c8f3767
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JavascriptStringAsset.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\JavascriptStringAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\JavascriptAssetInterface;
+use Drupal\Core\Asset\BaseStringAsset;
+
+class JavascriptStringAsset extends BaseStringAsset implements JavascriptAssetInterface {
+
+  protected $scope;
+
+  /**
+   * Scope defaults to footer as almost all JavaScript assets can be placed in
+   * the footer.
+   *
+   * @tricky this is a change from the previous behavior!
+   *
+   * @var string
+   */
+  protected $scopeDefault = 'footer';
+
+  public function setScope($scope) {
+    $this->scope = $scope;
+  }
+
+  public function getScope() {
+    return empty($this->scope) ? $this->scopeDefault : $this->scope;
+  }
+
+  public function getScopeDefault() {
+    return $this->scopeDefault;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/StylesheetAssetInterface.php b/core/lib/Drupal/Core/Asset/StylesheetAssetInterface.php
new file mode 100644
index 0000000..9a81daf
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/StylesheetAssetInterface.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\StylesheetAssetInterface.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\AssetInterface;
+
+/**
+ * Represents a cascading stylesheet (CSS) asset.
+ */
+interface StylesheetAssetInterface extends AssetInterface {
+
+  /**
+   * Sets the media property to be applied on this stylesheet asset.
+   *
+   * @param string $type
+   *   Either a media type, or a media query.
+   *
+   * @return NULL
+   */
+  public function setMedia($type);
+
+  /**
+   * Returns the current value of the media property on this stylesheet asset.
+   *
+   * @return string
+   */
+  public function getMedia();
+
+  /**
+   * Returns the default value of the media property on this stylesheet asset.
+   *
+   * @return mixed
+   */
+  public function getMediaDefault();
+}
diff --git a/core/lib/Drupal/Core/Asset/StylesheetExternalAsset.php b/core/lib/Drupal/Core/Asset/StylesheetExternalAsset.php
new file mode 100644
index 0000000..b7dc800
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/StylesheetExternalAsset.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\StylesheetExternalAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\StylesheetAssetInterface;
+use Drupal\Core\Asset\BaseExternalAsset;
+
+class StylesheetExternalAsset extends BaseExternalAsset implements StylesheetAssetInterface {
+
+  /**
+   * The media query or type to use for this asset. Defaults to 'all'.
+   *
+   * @todo inject the defaults instead of hardcoding them.
+   *
+   * @var string
+   */
+  protected $mediaDefault = 'all';
+
+  protected $media;
+
+  protected $preprocess = FALSE;
+
+  /**
+   * Returns the current value of the media property on this stylesheet asset.
+   *
+   * @return string
+   */
+  public function getMedia() {
+    return $this->media;
+  }
+
+  /**
+   * Returns the default value of the media property on this stylesheet asset.
+   *
+   * @return mixed
+   */
+  public function getMediaDefault() {
+    return $this->mediaDefault;
+  }
+
+  /**
+   * Sets the media property to be applied on this stylesheet asset.
+   *
+   * @param string $type
+   *   Either a media type, or a media query.
+   *
+   * @return NULL
+   */
+  public function setMedia($type) {
+    $this->media = $type;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/StylesheetFileAsset.php b/core/lib/Drupal/Core/Asset/StylesheetFileAsset.php
new file mode 100644
index 0000000..38b3a6b
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/StylesheetFileAsset.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\StylesheetFileAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\StylesheetAssetInterface;
+use Drupal\Core\Asset\BaseFileAsset;
+
+class StylesheetFileAsset extends BaseFileAsset implements StylesheetAssetInterface {
+
+  /**
+   * The media query or type to use for this asset. Defaults to 'all'.
+   *
+   * @todo inject the defaults instead of hardcoding them.
+   *
+   * @var string
+   */
+  protected $mediaDefault = 'all';
+
+  protected $media;
+
+  /**
+   * Returns the current value of the media property on this stylesheet asset.
+   *
+   * @return string
+   */
+  public function getMedia() {
+    return $this->media;
+  }
+
+  /**
+   * Returns the default value of the media property on this stylesheet asset.
+   *
+   * @return mixed
+   */
+  public function getMediaDefault() {
+    return $this->mediaDefault;
+  }
+
+  /**
+   * Sets the media property to be applied on this stylesheet asset.
+   *
+   * @param string $type
+   *   Either a media type, or a media query.
+   *
+   * @return NULL
+   */
+  public function setMedia($type) {
+    $this->media = $type;
+  }
+}
diff --git a/core/lib/Drupal/Core/Asset/StylesheetStringAsset.php b/core/lib/Drupal/Core/Asset/StylesheetStringAsset.php
new file mode 100644
index 0000000..639f6c1
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/StylesheetStringAsset.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Asset\StylesheetStringAsset.
+ */
+
+namespace Drupal\Core\Asset;
+
+use Drupal\Core\Asset\StylesheetAssetInterface;
+use Drupal\Core\Asset\BaseStringAsset;
+
+class StylesheetStringAsset extends BaseStringAsset implements StylesheetAssetInterface {
+
+  /**
+   * The media query or type to use for this asset. Defaults to 'all'.
+   *
+   * @todo inject the defaults instead of hardcoding them.
+   *
+   * @var string
+   */
+  protected $mediaDefault = 'all';
+
+  protected $media;
+
+  protected $preprocess = FALSE;
+
+  /**
+   * Returns the current value of the media property on this stylesheet asset.
+   *
+   * @return string
+   */
+  public function getMedia() {
+    return $this->media;
+  }
+
+  /**
+   * Returns the default value of the media property on this stylesheet asset.
+   *
+   * @return mixed
+   */
+  public function getMediaDefault() {
+    return $this->mediaDefault;
+  }
+
+  /**
+   * Sets the media property to be applied on this stylesheet asset.
+   *
+   * @param string $type
+   *   Either a media type, or a media query.
+   *
+   * @return NULL
+   */
+  public function setMedia($type) {
+    $this->media = $type;
+  }
+}
diff --git a/core/lib/Drupal/Core/Booze/ContentRouteEnhancer.php b/core/lib/Drupal/Core/Booze/ContentRouteEnhancer.php
new file mode 100644
index 0000000..97d0e67
--- /dev/null
+++ b/core/lib/Drupal/Core/Booze/ContentRouteEnhancer.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Booze\ContentPassthroughSubscriber.
+ */
+
+namespace Drupal\Core\Booze;
+
+use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Controller\ControllerResolver;
+
+/**
+ * Class for upcasting _content into a workable callback.
+ *
+ * We use the _content property on routes to simulate the 'page callback'
+ * experience in previous versions of Drupal: it is the callback responsible
+ * for populating the main content area of an HTML page. Because all such
+ * top-level content must be encapsulated by blocks, this route enhancer
+ * creates a closure with logic for calling it to be used later on.
+ */
+class ContentRouteEnhancer implements RouteEnhancerInterface {
+
+  protected $resolver;
+
+  public function __construct(ControllerResolver $resolver) {
+    $this->resolver = $resolver;
+  }
+
+  public function enhance(array $defaults, Request $request) {
+    // @todo this check is ridiculous, but temporarily necessary to narrow the scope to SCOTCH-y routes
+    if (isset($defaults['_content']) && !isset($defaults['_content_closure']) && isset($defaults['_display'])) {
+      // Clone the request and pretend like _content is the _controller
+      $request = clone $request;
+      $request->attributes->set('_controller', $defaults['_content']);
+
+      $controller = $this->resolver->getController($request);
+      $arguments = $this->resolver->getArguments($request, $controller);
+
+      $defaults['_content_closure'] = function() use ($controller, $arguments) {
+        return call_user_func_array($controller, $arguments);
+      };
+    }
+
+    return $defaults;
+  }
+}
diff --git a/core/lib/Drupal/Core/Booze/DisplayRouteEnhancer.php b/core/lib/Drupal/Core/Booze/DisplayRouteEnhancer.php
new file mode 100644
index 0000000..0d4c5f5
--- /dev/null
+++ b/core/lib/Drupal/Core/Booze/DisplayRouteEnhancer.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Booze\DisplayRouteEnhancer.
+ */
+
+namespace Drupal\Core\Booze;
+
+use Drupal\layout\Config\BoundDisplayInterface;
+use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\Request;
+
+class DisplayRouteEnhancer implements RouteEnhancerInterface {
+  /**
+   * Implements \Symfony\Cmf\Component\Routing\Enhancer\ŖouteEnhancerInterface.
+   *
+   * Upcasts _display identifiers on routes into their full Display objects.
+   *
+   * @param array $defaults
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *
+   * @return array
+   *   The modified defaults. This enhancer will only operate on keys called
+   *   "_display", and only if their value is a string.
+   */
+  public function enhance(array $defaults, Request $request) {
+    if (isset($defaults['_display']) && is_string($defaults['_display'])) {
+
+      $entity = entity_load('display', str_replace('display.bound.', '', $defaults['_display']));
+      if (!$entity instanceof BoundDisplayInterface) {
+        $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
+        throw new NotFoundHttpException(sprintf("Display %s could not be found for route on path %s.", $defaults['_display'], $route->getPath()));
+      }
+      $defaults['_display'] = $entity;
+    }
+
+    return $defaults;
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/Entity/EmbeddedPluginConfigInterface.php b/core/lib/Drupal/Core/Config/Entity/EmbeddedPluginConfigInterface.php
new file mode 100644
index 0000000..98352fb
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Entity/EmbeddedPluginConfigInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Config\Entity\EmbeddedPluginConfigInterface.
+ */
+
+namespace Drupal\Core\Config\Entity;
+
+/**
+ * Interface for ConfigEntities that are used as embedded config by plugins.
+ */
+interface EmbeddedPluginConfigInterface extends ConfigEntityInterface {
+  /**
+   * Returns the id of the plugin in which this configuration is embedded.
+   *
+   * @return string
+   */
+  public function getPluginId();
+
+  /**
+   * Sets the id of the plugin in which this configuration is embedded.
+   *
+   * @param string $plugin_id
+   *   The id of the plugin.
+   *
+   * @return void
+   */
+  public function setPluginId($plugin_id);
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 472105a..3e780a6 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -17,6 +17,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterBlockFragmentRenderersPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -63,6 +64,8 @@ public function build(ContainerBuilder $container) {
     $container->addCompilerPass(new ListCacheBinsPass());
     // Add the compiler pass for appending string translators.
     $container->addCompilerPass(new RegisterStringTranslatorsPass());
+    // Add a compiler pass for registering services needing destruction.
+    $container->addCompilerPass(new RegisterBlockFragmentRenderersPass());
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterBlockFragmentRenderersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterBlockFragmentRenderersPass.php
new file mode 100644
index 0000000..7f0e874
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterBlockFragmentRenderersPass.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterBlockFragmentRenderersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Adds services tagged 'render_strategy' to the 'fragment_handler' service.
+ *
+ * Drupal's block fragment rendering strategies utilize a slightly modified
+ * interface vs. core symfony's, but our service can support either interface.
+ */
+class RegisterBlockFragmentRenderersPass implements CompilerPassInterface {
+  /**
+   * Adds services tagged 'render_strategy' to 'fragment_handler' services.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *  The container to process.
+   */
+  public function process(ContainerBuilder $container) {
+    $services = array();
+    foreach ($container->findTaggedServiceIds('fragment_handler') as $id => $attributes) {
+      $services[] = $container->getDefinition($id);
+    }
+
+    foreach ($container->findTaggedServiceIds('render_strategy') as $id => $attributes) {
+      foreach ($services as $service) {
+        $service->addMethodCall('addRenderer', array(new Reference($id)));
+      }
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/DisplayController.php b/core/lib/Drupal/Core/DisplayController.php
new file mode 100644
index 0000000..2e4974f
--- /dev/null
+++ b/core/lib/Drupal/Core/DisplayController.php
@@ -0,0 +1,218 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Booze\DrunkController.
+ */
+
+namespace Drupal\Core;
+
+use Drupal\Core\FragmentRenderer\BlockFragmentRendererInterface;
+use Drupal\block\Plugin\Type\BlockManager;
+use Drupal\layout\Config\UnboundDisplayInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\layout\Config\BoundDisplayInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\system\Plugin\Block\SystemMainBlock;
+use Drupal\Core\Page\HtmlFragment;
+use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
+
+/**
+ * Default controller for handling text/html responses.
+ *
+ * This is the base controller for the "blocks and layouts" rendering system,
+ * specifically the respond() method. That takes a
+ * Drupal\layout\Config\BoundDisplayInterface object, which contains a set of
+ * blocks and a layout plugin, and renders them into a PageFragment object,
+ * itself a renderable object that is used by later parts of the system.
+ */
+class DisplayController {
+
+  /**
+   * An array containing rendered block output, keyed by the block instance that
+   * produced it.
+   *
+   * @var array
+   */
+  public $blockFragments = array();
+
+  /**
+   * An associative array of rendered regions.
+   * @var array
+   */
+  public $renderedRegions;
+
+  /**
+   * The Response object that is built up over the course of the request and
+   * eventually returned from this controller.
+   *
+   * @var \Symfony\Component\HttpFoundation\Response
+   */
+  protected $response;
+
+  /**
+   * The display configuration object containing layout and block information,
+   * used by this controller to assemble all page elements.
+   *
+   * @var \Drupal\layout\Config\BoundDisplayInterface
+   */
+  protected $display;
+
+  /**
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * @var \Drupal\block\Plugin\Type\BlockManager
+   */
+  protected $blockManager;
+
+  /**
+   * An array of FragmentRendererInterface objects.
+   *
+   * @var array
+   */
+  protected $renderingStrategies = array();
+
+  /**
+   * Constructs the DisplayController service.
+   *
+   * @param ModuleHandlerInterface $moduleHandler
+   *   The module handler service, used for hook invocations.
+   * @param BlockManager           $blockManager
+   *   The BlockManager, used to instantiate blocks.
+   */
+  public function __construct(ModuleHandlerInterface $moduleHandler, BlockManager $blockManager) {
+    $this->moduleHandler = $moduleHandler;
+    $this->blockManager = $blockManager;
+  }
+
+  /**
+   * Adds a block rendering strategy.
+   *
+   * @todo probably best to shift this into a plugin, then inject the manager.
+   *
+   * @param BlockFragmentRendererInterface $strategy
+   *   A FragmentRendererInterface instance
+   */
+  public function addRenderer(BlockFragmentRendererInterface $strategy) {
+    $this->renderingStrategies[$strategy->getName()] = $strategy;
+  }
+
+  /**
+   * Controller method for normal rendering of blocks and layouts-driven HTML
+   * page.
+   *
+   * @todo the output may need more or less assembling, depending on how
+   * 'compiled' of a template we have in the display. We either can handle it
+   * below here via a delegator pattern, or with sibling classes.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request         $request
+   *   The request object.
+   * @param \Drupal\layout\Config\BoundDisplayInterface       $_display
+   *   A configuration object containing the layout instance and set of
+   *   block instances that have been configured to be used for the current
+   *   route.
+   *
+   * @return \Drupal\Core\Page\HtmlFragment
+   */
+  public function respond(Request $request, BoundDisplayInterface $_display) {
+    $this->display = $_display;
+
+    // Create a HtmlFragment object right away that we can easily decorate as we go.
+    $this->response = new HtmlFragment();
+
+    $this->blockFragments = $this->renderBlocks($request, $this->display);
+    $this->renderRegions($request);
+
+    $content = $this->display->getLayoutInstance()->renderLayout(FALSE, $this->renderedRegions);
+
+    $this->response->setContent($content);
+
+    return $this->response;
+  }
+
+  /**
+   * Renders all blocks contained in the provided display.
+   *
+   * @param Request               $request
+   *   The current Request object.
+   * @param BoundDisplayInterface $display
+   *   The Display to render.
+   *
+   * @return array
+   *   An array of HtmlFragment objects, returned from block rendering.
+   */
+  protected function renderBlocks(Request $request, BoundDisplayInterface $display) {
+    $blockFragments = array();
+    foreach ($display->getAllOuterBlockConfig() as $id => $config) {
+      $block = $display->getBlock($id);
+
+
+      if ($block instanceof SystemMainBlock) {
+        $block->setControllerClosure($request->attributes->get('_content_closure'));
+      }
+
+      $munged_request = clone $request;
+      // @todo muck with the Request here to get it to where we need
+      $blockFragments[$id] = $this->renderingStrategies[$config['strategy']]->render($block, $munged_request);
+    }
+
+    return $blockFragments;
+  }
+
+  /**
+   * Renders all rendered blocks into their respective layout regions, using
+   * the layout attached to the current display object.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   */
+  protected function renderRegions(Request $request) {
+    $layout = $this->display->getLayoutInstance();
+    $outer_configs = $this->display->getAllOuterBlockConfig();
+    $group_configs = $this->display->getAllGroupConfig();
+
+    // @todo this entire method is a mess. trim it all down by hiding the munging logic in iterators and bags
+
+    foreach ($layout->getRegions() as $region => $info) {
+      $groups = $rendered = array();
+
+      foreach ($this->display->getSortedBlocksByRegion($region) as $id) {
+        $block_weight = $outer_configs[$id]['weight'];
+
+        if (!empty($outer_configs[$id]['group'])) {
+          $group_name = $outer_configs[$id]['group'];
+          if (!isset($group_configs[$group_name])) {
+            throw new \Exception(sprintf('Block "%s" indicates it is part of group "%s", but that group does not exist.', $id, $group_name), E_RECOVERABLE_ERROR);
+          }
+
+          while (!empty($groups[$group_name][$block_weight])) {
+            $block_weight += 0.001;
+          }
+          $groups[$group_name][$block_weight] = $this->blockFragments[$id]->getContent();
+        }
+        else {
+           while (!empty($rendered[$block_weight])) {
+             $block_weight += 0.001;
+           }
+           $rendered[$block_weight] = $this->blockFragments[$id]->getContent();
+        }
+      }
+
+      foreach ($groups as $group_name => $blocks) {
+        $group = array(
+          '#theme' => 'group',
+          '#blocks' => implode("", $blocks),
+          '#config' => $group_configs[$group_name],
+        );
+        $rendered[$group_configs[$group_name]['weight']] = drupal_render($group);
+      }
+
+      ksort($rendered);
+      $this->renderedRegions[$region] = implode("", array_filter($rendered));
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/DisplayControllerSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DisplayControllerSubscriber.php
new file mode 100644
index 0000000..f2694cf
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/DisplayControllerSubscriber.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\EventSubscriber\DrunkControllerSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+use Drupal\layout\Config\BoundDisplayInterface;
+
+/**
+ * Controller injector for text/html responses.
+ */
+class DisplayControllerSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Attaches a display for blocks-driven HTML rendering, if appropriate.
+   *
+   * This determines if the Request and Route are appropriate candidates for
+   * passing through block-driven rendering, and if so, attaches a controller
+   * to do so.
+   *
+   * This is more or less the default case; we only don't take over if Drupal
+   * is doing things like form processing, returning JSON or other things that
+   * (generally) do not involve composing HTML.
+   *
+   */
+  public function onDisplayControllerSetDisplay(FilterControllerEvent $event) {
+    $request = $event->getRequest();
+
+    // @todo implement a separate flag and remove this hardmapping
+    if ('display_controller:respond' !== $request->attributes->get('_controller')
+        || $request->attributes->get('_display') instanceof BoundDisplayInterface) {
+      return;
+    }
+
+    $route = $request->attributes->get('_route');
+
+    if (!empty($route)) {
+      $display = entity_load('display', $route);
+    }
+
+    if (empty($display)) {
+       throw new NotFoundHttpException(sprintf('No display could be located for the route %s.', $route));
+       return;
+    }
+
+    $display->setMainContent($request->attributes->get('_content'));
+
+    $request->attributes->set('_display', $display);
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  public static function getSubscribedEvents() {
+    $events[KernelEvents::CONTROLLER][] = array('onDisplayControllerSetDisplay', 100);
+
+    return $events;
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/EventSubscriber/HtmlViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/HtmlViewSubscriber.php
new file mode 100644
index 0000000..64351e3
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/HtmlViewSubscriber.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\HtmlViewSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Page\HtmlFragment;
+use Drupal\Core\Asset\AssetBag;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Subscriber for KernelEvents::VIEW events that finalizes an HTML response.
+ *
+ * This subscriber takes a HtmlFragment, the sort generated by a block or
+ * layout-driven route, and marshals it into a full Response object by dealing
+ * with assets and wrapping the in the skeletal HTML, primarily the <head> tag
+ * and its contents.
+ */
+class HtmlViewSubscriber implements EventSubscriberInterface {
+
+  /**
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  public function __construct(ModuleHandlerInterface $moduleHandler) {
+    $this->moduleHandler = $moduleHandler;
+  }
+
+  /**
+   * Processes a specialized Drupal Response into fully-formed HTML.
+   *
+   * This subscriber only acts if presented with a specialized Response object
+   * that contains a partial HTML page, plus the metadata necessary to construct
+   * the remainder of the page.
+   *
+   * @todo we're ignoring content negotiation and assuming HTML. could be JSON, at least...
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event
+   *   The Event to process.
+   *
+   * @return \Symfony\Component\HttpFoundation\Response
+   */
+  public function onHtmlFragmentResponse(GetResponseForControllerResultEvent $event) {
+    // Only act if we have a specialized Drupal response to work with.
+    if (!($response = $event->getControllerResult()) instanceof HtmlFragment) {
+      return;
+    }
+
+   $vars = array(
+      'page' => array(
+        '#children' => $response->getContent(),
+        'page_top' => array(),
+        'page_bottom' => array(),
+      ),
+      'response' => $response,
+    );
+
+    $event->setResponse(new Response(theme('html', $vars)));
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::VIEW][] = array('onHtmlFragmentResponse', 40);
+
+    return $events;
+  }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
index fa4be98..b5a908d 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
@@ -47,6 +47,12 @@ public function onView(GetResponseForControllerResultEvent $event) {
 
     $request = $event->getRequest();
 
+    // This expects either strings or arrays; it does not handle objects. Bail
+    // out if the controller result is any kind of object.
+    if (is_object($event->getControllerResult())) {
+      return;
+    }
+
     // For a master request, we process the result and wrap it as needed.
     // For a subrequest, all we want is the string value.  We assume that
     // is just an HTML string from a controller, so wrap that into a response
@@ -152,7 +158,7 @@ public function onHtml(GetResponseForControllerResultEvent $event) {
    *   An array of event listener definitions.
    */
   static function getSubscribedEvents() {
-    $events[KernelEvents::VIEW][] = array('onView');
+    $events[KernelEvents::VIEW][] = array('onView', 30);
 
     return $events;
   }
diff --git a/core/lib/Drupal/Core/FragmentRenderer/AsyncBlockFragmentRenderer.php b/core/lib/Drupal/Core/FragmentRenderer/AsyncBlockFragmentRenderer.php
new file mode 100644
index 0000000..bbefa09
--- /dev/null
+++ b/core/lib/Drupal/Core/FragmentRenderer/AsyncBlockFragmentRenderer.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\FragmentRenderer\AsyncBlockFragmentRenderer.
+ */
+namespace Drupal\Core\FragmentRenderer;
+
+use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
+
+abstract class AsyncBlockFragmentRenderer implements FragmentRendererInterface {
+  protected function getPathFromBlock($block) {
+    // 1. determine differentiating vectors - config (instance), injected context
+    // 2. determine injected services (yowza)
+    // 3. extract URL
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/FragmentRenderer/BlockFragmentRendererInterface.php b/core/lib/Drupal/Core/FragmentRenderer/BlockFragmentRendererInterface.php
new file mode 100644
index 0000000..2f6a51a
--- /dev/null
+++ b/core/lib/Drupal/Core/FragmentRenderer/BlockFragmentRendererInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\FragmentRenderer\BlockFragmentRendererInterface.
+ */
+
+namespace Drupal\Core\FragmentRenderer;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
+
+/**
+ * Interface for all block rendering strategies.
+ *
+ * @todo eeeew. playing interface games like this is terrible.
+ */
+interface BlockFragmentRendererInterface extends FragmentRendererInterface {
+  /**
+   * Renders a block, returning an HtmlFragment.
+   *
+   * This supercedes the render method of the parent interface by specifying
+   * that an HtmlFragment be returned.
+   *
+   * @todo is it best to pass the block plugin in here, or something else?
+   * @param \Drupal\block\BlockInterface $block
+   *   A block plugin, fully injected with its configuration and data.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   A Request instance.
+   * @param array $options
+   *   An array of options to be used in rendering the fragment.
+   *
+   * @return \Drupal\Core\Page\HtmlFragment
+   */
+  public function render($block, Request $request, array $options = array());
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/FragmentRenderer/FragmentHandler.php b/core/lib/Drupal/Core/FragmentRenderer/FragmentHandler.php
new file mode 100644
index 0000000..256e41a
--- /dev/null
+++ b/core/lib/Drupal/Core/FragmentRenderer/FragmentHandler.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\FragmentRenderer\FragmentHandler.
+ */
+namespace Drupal\Core\FragmentRenderer;
+
+use Drupal\Core\Page\HtmlFragment;
+use Symfony\Component\HttpKernel\Fragment\FragmentHandler as BaseFragmentHandler;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
+
+/**
+ * Renders a block into an HtmlFragment using a particular rendering strategy.
+ *
+ * This class proxies requests to render a block as an HtmlFragment off to the
+ * appropriate named FragmentRendererInterface service, where the real work is
+ * done.
+ *
+ * @see BlockFragmentRendererInterface
+ */
+class FragmentHandler extends BaseFragmentHandler {
+  private $debug;
+  private $renderers;
+  private $requests;
+
+  /**
+   * Sets up a BlockFragmentRenderer service.
+   *
+   * @param array $renderers
+   *   An array of FragmentRendererInterface instances
+   * @param Boolean $debug
+   *   Whether the debug mode is enabled or not
+   */
+  public function __construct(array $renderers = array(), $debug = FALSE) {
+    $this->renderers = array();
+    foreach ($renderers as $renderer) {
+      $this->addRenderer($renderer);
+    }
+    $this->debug = $debug;
+    $this->requests = array();
+  }
+
+  /**
+   * Renders and returns an HtmlFragment from a block.
+   *
+   * @param \Drupal\block\BlockInterface $block
+   *   The block to be rendered.
+   * @param string $renderer
+   *   The name of the BlockFragmentRendererInterface to use.
+   * @param array $options
+   *   An array of options to pass to the renderer.
+   *
+   * @return HtmlFragment|Response
+   *   An HtmlFragment object representing the block's output and accompanying
+   *   out-of-band information (primarily title and assets).
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown if the renderer does not exist.
+   */
+  public function render($block, $renderer = 'block_inline', array $options = array()) {
+    if (!isset($options['ignore_errors'])) {
+      $options['ignore_errors'] = !$this->debug;
+    }
+
+    if (!isset($this->renderers[$renderer])) {
+      throw new \InvalidArgumentException(sprintf('The "%s" fragment renderer does not exist.', $renderer));
+    }
+
+    // Support both native Symfony and Drupal fragment rendering patterns.
+    // @todo this is kinda horrible.
+    if ($this->renderers[$renderer] instanceof BlockFragmentRendererInterface) {
+      return $this->renderers[$renderer]->render($block, $this->requests[0], $options);
+    }
+    else if ($this->renderers[$renderer] instanceof FragmentRendererInterface) {
+      return $this->deliver($this->renderers[$renderer]->render($block, $this->requests[0], $options));
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/FragmentRenderer/InlineBlockFragmentRenderer.php b/core/lib/Drupal/Core/FragmentRenderer/InlineBlockFragmentRenderer.php
new file mode 100644
index 0000000..1b5abde
--- /dev/null
+++ b/core/lib/Drupal/Core/FragmentRenderer/InlineBlockFragmentRenderer.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\FragmentRenderer\InlineBlockFragmentRenderer.
+ */
+
+namespace Drupal\Core\FragmentRenderer;
+
+use Drupal\Core\Page\HtmlFragment;
+use Drupal\block\BlockAddressGenerator;
+use Drupal\block\BlockControllerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Drupal\block\BlockPluginInterface;
+use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Block fragment renderer for inline placement of final block output.
+ *
+ * This strategy is sensitive to whether or not a block has indicated that it is
+ * subrequest safe. If it is, then a subrequest is used; otherwise, the block is
+ * directly rendered here via the block rendering service here.
+ */
+class InlineBlockFragmentRenderer extends InlineFragmentRenderer implements BlockFragmentRendererInterface {
+  /**
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $kernel;
+
+  /**
+   * The BlockAddressGenerator service to use.
+   *
+   * @var \Drupal\block\BlockAddressGenerator
+   */
+  protected $blockAddressor;
+
+  /**
+   * @var \Drupal\block\BlockControllerInterface
+   */
+  protected $blockController;
+
+  public function __construct(HttpKernelInterface $kernel, BlockAddressGenerator $blockAddressor, BlockControllerInterface $blockController) {
+    $this->kernel = $kernel;
+    $this->blockAddressor = $blockAddressor;
+    $this->blockController = $blockController;
+  }
+
+  /**
+   * Gets the name of the strategy.
+   *
+   * @return string
+   *   The system name of the strategy.
+   */
+  public function getName() {
+    return 'inline_block';
+  }
+
+  /**
+   * Renders a block, returning an HtmlFragment.
+   *
+   * @todo is it best to pass the block plugin in here, or something else?
+   *
+   * @param \Drupal\block\BlockPluginInterface $block
+   *   A block plugin, fully injected with its configuration and data.
+   * @param Request                    $request A Request instance
+   * @param array                      $options An array of options
+   *
+   * @return HtmlFragment
+   */
+  public function render($block, Request $request, array $options = array()) {
+    if (!$block instanceof BlockPluginInterface) {
+      throw new \InvalidArgumentException('A block instance must be provided to the fragment renderer.');
+    }
+
+    // @todo this needs to be rolled into the more general pattern of context prep
+    if (!$block->isSubrequestSafe()) {
+      // Have to check access first, since normally the subrequest would do it
+      // for us.
+      if ($block->access()) {
+        $fragment = $this->blockController->respond($request, $block);
+      }
+      else {
+        $fragment = new HtmlFragment();
+        // @todo this needs to be brought into line with how the subrequest would handle it. ...which is a Response set with a 403. yikes.
+      }
+      return $fragment;
+    }
+    else {
+      $display = empty($options['display']) ? '' : $options['display'];
+      $subrequest = $this->createSubRequest($this->blockAddressor->generateAddress($block, $request, $display), $request);
+
+      $level = ob_get_level();
+      try {
+        return $this->kernel->handle($subrequest, HttpKernelInterface::SUB_REQUEST, FALSE);
+      } catch (\Exception $e) {
+        // let's clean up the output buffers that were created by the sub-request
+        while (ob_get_level() > $level) {
+            ob_get_clean();
+        }
+
+        if (isset($options['alt'])) {
+            $alt = $options['alt'];
+            unset($options['alt']);
+
+            return $this->render($alt, $request, $options);
+        }
+
+        if (!isset($options['ignore_errors']) || !$options['ignore_errors']) {
+            throw $e;
+        }
+
+        // @todo decide what to return with if an exception is thrown in the subrequest
+      }
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Page/HtmlFragment.php b/core/lib/Drupal/Core/Page/HtmlFragment.php
new file mode 100644
index 0000000..3e831cf
--- /dev/null
+++ b/core/lib/Drupal/Core/Page/HtmlFragment.php
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\HtmlFragment.
+ */
+
+namespace Drupal\Core\Page;
+
+use Drupal\Core\Asset\AssetBag;
+use Drupal\Core\Asset\AssetBagInterface;
+
+/**
+ * Response object that contains variables for injection into the html template.
+ *
+ * @todo should we have this conform to an interface? https://drupal.org/node/1871596#comment-7134686
+ * @todo add method replacements for *all* data sourced by html.tpl.php
+ */
+class HtmlFragment {
+
+  /**
+   * HTML content string.
+   *
+   * @var string
+   */
+  protected $content;
+
+  /**
+   * The title of this HtmlFragment.
+   *
+   * @var string
+   */
+  protected $title = '';
+
+  public function __construct($content = '') {
+    $this->content = $content;
+    $this->bag = new AssetBag();
+  }
+
+  /**
+   * Adds another asset bag to those already contained in this fragment.
+   *
+   * @param AssetBagInterface $bag
+   */
+  public function addAssetBag(AssetBagInterface $bag) {
+    $this->bag->addAssetBag($bag);
+  }
+
+  /**
+   * Returns the AssetBag representing the collected assets in this fragment.
+   *
+   * @return AssetBag
+   */
+  public function getAssets() {
+    return $this->bag;
+  }
+
+  /**
+   * Sets the response content.
+   *
+   * This should be the bulk of the page content, and will ultimately be placed
+   * within the <body> tag in final HTML output.
+   *
+   * Valid types are strings, numbers, and objects that implement a __toString()
+   * method.
+   *
+   * @param mixed $content
+   *
+   * @return \Drupal\Core\Page\HtmlFragment
+   */
+  public function setContent($content) {
+    $this->content = $content;
+    return $this;
+  }
+
+  /**
+   * Gets the main content of this HtmlFragment.
+   *
+   * @return string
+   */
+  public function getContent() {
+    return $this->content;
+  }
+
+  /**
+   * Sets the title of this HtmlFragment.
+   *
+   * Handling of this title varies depending on what is consuming this
+   * HtmlFragment object. If it's a block, it may only be used as the block's
+   * title; if it's at the page level, it will be used in a number of places,
+   * including the html <head> title.
+   */
+  public function setTitle($title, $output = CHECK_PLAIN) {
+    $this->title = ($output == PASS_THROUGH) ? $title : check_plain($title);
+  }
+
+  /**
+   * Indicates whether or not this HtmlFragment has a title.
+   *
+   * @return bool
+   */
+  public function hasTitle() {
+    return !empty($this->title);
+  }
+
+  /**
+   * Gets the title for this HtmlFragment, if any.
+   *
+   * @return string
+   */
+  public function getTitle() {
+    return $this->title;
+  }
+
+  /**
+   * Clones the current HtmlFragment instance.
+   */
+  public function __clone() {
+    $this->bag = clone $this->bag;
+  }
+}
diff --git a/core/lib/Drupal/Core/Plugin/ConfigEntityAwarePluginInterface.php b/core/lib/Drupal/Core/Plugin/ConfigEntityAwarePluginInterface.php
new file mode 100644
index 0000000..f99cf71
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/ConfigEntityAwarePluginInterface.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Plugin\ConfigEntityAwarePluginInterface.
+ */
+
+namespace Drupal\Core\Plugin;
+
+use Drupal\Core\Config\Entity\EmbeddedPluginConfigInterface;
+
+/**
+ * Interface for plugins that use ConfigEntity for their configuration storage.
+ */
+interface ConfigEntityAwarePluginInterface {
+  /**
+   * Sets the ConfigEntity for this plugin.
+   *
+   * @param EmbeddedPluginConfigInterface $config
+   *   The ConfigEntity object.
+   *
+   * @return void
+   */
+  public function setConfig(EmbeddedPluginConfigInterface $config);
+
+  /**
+   * Returns the ConfigEntity for this plugin.
+   *
+   * @return EmbeddedPluginConfigInterface
+   */
+  public function getConfig();
+
+  /**
+   * Returns the string identifier of the instance id.
+   *
+   * This is typically, though not necessarily, the full name of the
+   * configuration object that backs the plugin's ConfigEntity.
+   *
+   * @return string
+   */
+  public function getInstanceId();
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Plugin/Mapper/ConfigDrivenMapperInterface.php b/core/lib/Drupal/Core/Plugin/Mapper/ConfigDrivenMapperInterface.php
new file mode 100644
index 0000000..c385cfd
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Mapper/ConfigDrivenMapperInterface.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\Core\Plugin\Mapper\ConfigDrivenMapperInterface.
+ */
+
+namespace Drupal\Core\Plugin\Mapper;
+
+use Drupal\Component\Plugin\Exception\PluginException;
+
+/**
+ * Defines an interface for retrieving plugins via a config id.
+ *
+ * For plugins that use the config system for their configuration CRUD, most
+ * calling code will have only a config id, not a plugin id. The plugin id is
+ * only stored in the configuration referenced by the config id.
+ *
+ * The most useful interface pattern for these cases is to simply allow calling
+ * code to load the plugin by providing the config id.
+ */
+interface ConfigDrivenMapperInterface {
+  /**
+   * Gets a configured plugin instance from a configuration id.
+   *
+   * The calling code may optionally also specify a plugin id
+   *
+   * @param string $config_id
+   *   The id of the configuration to load.
+   *
+   * @param string $plugin_id
+   *   Optional. If provided, this plugin id will be used instead of whatever is
+   *   specified by the loaded configuration.
+   *
+   * @return object
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function getInstanceViaConfig($config_id, $plugin_id = '');
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
index c355cc7..a81e41e 100644
--- a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
+++ b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php
@@ -32,6 +32,7 @@ class ContentControllerEnhancer implements RouteEnhancerInterface {
     'drupal_dialog' => 'controller.dialog:dialog',
     'drupal_modal' => 'controller.dialog:modal',
     'html' => 'controller.page:content',
+    'booze' => 'display_controller:respond',
   );
 
   /**
@@ -53,6 +54,9 @@ public function enhance(array $defaults, Request $request) {
       if (isset($this->types[$type])) {
         $defaults['_controller'] = $this->types[$type];
       }
+      if (isset($defaults['_display'])) {
+        $defaults['_controller'] = $this->types['booze'];
+      }
     }
     return $defaults;
   }
diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml
index af247b0..7c277e3 100644
--- a/core/modules/block/block.routing.yml
+++ b/core/modules/block/block.routing.yml
@@ -1,3 +1,17 @@
+block_address_standalone:
+  pattern: '/block-address/standalone/{block}/{route}'
+  defaults:
+    _controller: 'block_controller:respond'
+  requirements:
+    _access_addressed_block: 'TRUE'
+
+block_address_embedded:
+  pattern: '/block-address/embedded/{display}/{block}'
+  defaults:
+    _controller: 'block_controller:respond'
+  requirements:
+    _access_addressed_block: 'TRUE'
+
 block_admin_block_delete:
   pattern: '/admin/structure/block/manage/{block}/delete'
   defaults:
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index 745bf66..1bc972a 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -9,3 +9,12 @@ services:
     factory_method: get
     factory_service: cache_factory
     arguments: [block]
+  display_controller:
+    class: Drupal\Core\DisplayController
+    arguments: ['@module_handler', '@plugin.manager.block']
+    tags:
+      - { name: fragment_handler }
+  access_check.block:
+    class: Drupal\block\AddressedBlockAccessCheck
+    tags:
+      - { name: access_check }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
index 01b11ba..a455788 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
@@ -18,7 +18,13 @@
  *  id = "custom_block",
  *  admin_label = @Translation("Custom block"),
  *  module = "custom_block",
- *  derivative = "Drupal\custom_block\Plugin\Derivative\CustomBlock"
+ *  derivative = "Drupal\custom_block\Plugin\Derivative\CustomBlock",
+ *  has_native_access_logic = FALSE,
+ *  settings = {
+ *    "status" = TRUE,
+ *    "info" = "",
+ *    "view_mode" = "full"
+ *   }
  * )
  */
 class CustomBlockBlock extends BlockBase {
diff --git a/core/modules/block/lib/Drupal/block/AddressedBlockAccessCheck.php b/core/modules/block/lib/Drupal/block/AddressedBlockAccessCheck.php
new file mode 100644
index 0000000..e986b2b
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/AddressedBlockAccessCheck.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\AddressedBlockAccessCheck.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Access check for addressable block routes.
+ */
+class AddressedBlockAccessCheck implements AccessCheckInterface {
+  public function applies(Route $route) {
+    return array_key_exists('_access_addressed_block', $route->getRequirements());
+  }
+
+  /**
+   * Checks for access to route.
+   *
+   * @param \Symfony\Component\Routing\Route          $route
+   *   The route to check against.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   *
+   * @return mixed
+   *   TRUE if access is allowed.
+   *   FALSE if not.
+   *   NULL if no opinion.
+   */
+  public function access(Route $route, Request $request) {
+    $block = $request->attributes->get('_block');
+    return $block->access();
+  }
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/BlockAddressGenerator.php b/core/modules/block/lib/Drupal/block/BlockAddressGenerator.php
new file mode 100644
index 0000000..658f8dd
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockAddressGenerator.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\BlockAddressGenerator.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Block\BlockInterface;
+use Drupal\layout\Config\BoundDisplayInterface;
+use Drupal\block\Exception\MissingRequiredDataException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+/**
+ * Generates addressable URLs for blocks.
+ */
+class BlockAddressGenerator {
+
+  /**
+   * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface
+   */
+  protected $generator;
+
+  /**
+   * A static map containing the known addressable block routes.
+   *
+   * @var array
+   */
+  protected $routes = array(
+    'embedded' => 'block_address_embedded',
+    'standalone' => 'block_address_standalone',
+    'main' => 'block_address_main',
+  );
+
+  public function __construct(UrlGeneratorInterface $generator) {
+    $this->generator = $generator;
+  }
+
+  /**
+   * Generates a URL for the injected block.
+   *
+   * The block must have its configuration injected, and all of its context
+   * requirements satisfied before being passed to this method.
+   *
+   * @param \Drupal\Block\BlockInterface $block
+   *   The block for which a url should be generated.
+   *
+   * @param \Drupal\layout\Config\BoundDisplayInterface $display
+   *   Optional. Providing the display indicates that we are generating a route
+   *   to a block embedded within that display.
+   *
+   * @return string
+   *   The generated URL
+   *
+   * @throws \Drupal\block\Exception\MissingRequiredDataException
+   */
+  public function generateAddress(BlockInterface $block, Request $request, BoundDisplayInterface $display = NULL) {
+    if (!$block->contextIsSatisfied()) {
+      throw new MissingRequiredDataException(sprintf("Cannot generate an addressable URL for block '%s' as not all of its context has been injected.", $block->getPluginId()));
+    }
+
+    $params = array();
+    foreach ($block->getContexts() as $name => $context) {
+      // @todo this is pseudocode, the underlying systems here are not yet ready...i think
+      $params[$name] = $context->getType() . ':' . $context->getId();
+    }
+    // @todo missing the route, how should we get that in here...pass in the request object? kinda eew.
+    // @todo handle the main content block. UGH.
+
+    // Add different parameters if the block is standalone or embedded; if a
+    // display was passed in, that means it's embedded.
+    if (!empty($display)) {
+      $params['display'] = $display->id(); // @todo this is sans-prefix, we need with-prefix
+      $route = $this->routes['embedded'];
+    }
+    else {
+      $params['route'] = $request->attributes->get('_route');
+      $route = $this->routes['standalone'];
+    }
+
+    $params['block_id'] = $block->getInstanceId();
+    return $this->generator->generate($route, $params);
+  }
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php
index 57ff44d..2808840 100644
--- a/core/modules/block/lib/Drupal/block/BlockBase.php
+++ b/core/modules/block/lib/Drupal/block/BlockBase.php
@@ -7,7 +7,11 @@
 
 namespace Drupal\block;
 
+use Drupal\Component\Plugin\ContextAwarePluginBase;
 use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Asset\AssetBag;
+use Drupal\block\Plugin\Core\Entity\Block;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 
 /**
  * Defines a base block implementation that most blocks plugins will extend.
@@ -16,7 +20,7 @@
  * block settings, and handling for general user-defined block visibility
  * settings.
  */
-abstract class BlockBase extends PluginBase implements BlockPluginInterface {
+abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface {
 
   /**
    * {@inheritdoc}
@@ -33,6 +37,24 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi
   }
 
   /**
+   * Indicates whether or not all contextual requirements have been satisfied.
+   *
+   * @return bool
+   */
+  public function contextIsSatisfied() {
+    return TRUE;
+    // @todo once we implement contexts as part of the annotation, provide default read/validate behavior here
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isSubrequestSafe() {
+    $definition = $this->getDefinition();
+    return $definition['subrequest_safe'];
+  }
+
+  /**
    * Returns plugin-specific settings for the block.
    *
    * Block plugins only need to override this method if they override the
@@ -225,7 +247,7 @@ public function submit($form, &$form_state) {
    */
   public function blockSubmit($form, &$form_state) {}
 
-  /**
+/**
    * Implements \Drupal\block\BlockInterface::build().
    */
   public function build() {
@@ -253,4 +275,51 @@ public function build() {
    */
   abstract protected function blockBuild();
 
+  /**
+   * Returns an AssetBag containing the assets required by this block.
+   *
+   * @return \Drupal\Core\Asset\AssetBagInterface
+   */
+  public function getAssets() {
+    return new AssetBag();
+    // @todo Implement asset declarations as part of the annotations, then read them here, THEN use this to attach them.
+  }
+
+  final public function getSemantics() {
+    if (isset($this->configuration['semantics'])) {
+      return $this->configuration['semantics'];
+    }
+    else {
+      $definition = $this->getDefinition();
+      return $definition['semantics'];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  final public function getTitle() {
+    // Override titles should supersede native title logic.
+    if (isset($this->configuration['label'])) {
+      return $this->configuration['label'];
+    }
+    else {
+      return $this->doGetTitle();
+    }
+  }
+
+  /**
+   * Returns a title for the block based on some native block logic.
+   *
+   * This method is intended for overriding by subclasses in order to provide
+   * their own logic for generating the block title.
+   *
+   * @see BlockBase::getTitle()
+   *
+   * @return string
+   */
+  protected function doGetTitle() {
+    // @todo make this abstract instead
+    return '';
+  }
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockController.php b/core/modules/block/lib/Drupal/block/BlockController.php
new file mode 100644
index 0000000..89f58ae
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockController.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\BlockController.
+ */
+
+namespace Drupal\block;
+
+/**
+ * TODO Add class description.
+ */
+class BlockController {
+
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/BlockControllerInterface.php b/core/modules/block/lib/Drupal/block/BlockControllerInterface.php
new file mode 100644
index 0000000..ef8b5e8
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockControllerInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\BlockControllerInterface.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Page\HtmlFragment;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface describing block controllers.
+ *
+ * Block controllers are responsible for injecting incoming context data onto a
+ * block controller and making an HtmlFragment response out of its built render
+ * array.
+ */
+interface BlockControllerInterface {
+  /**
+   * Renders a provided block into an HtmlFragment.
+   *
+   * @param Request        $request
+   * @param BlockPluginInterface $block
+   *
+   * @return \Drupal\Core\Page\HtmlFragment
+   */
+  public function respond(Request $request, BlockPluginInterface $block);
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/BlockRenderController.php b/core/modules/block/lib/Drupal/block/BlockRenderController.php
index 12fff82..86f4d23 100644
--- a/core/modules/block/lib/Drupal/block/BlockRenderController.php
+++ b/core/modules/block/lib/Drupal/block/BlockRenderController.php
@@ -44,4 +44,15 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
     return $build;
   }
 
+  /**
+   * Use render instead of view
+   * @param EntityInterface $entity
+   * @param type $view_mode
+   * @param type $langcode
+   * @return type
+   */
+  public function render(EntityInterface $entity, $langcode = NULL) {
+    $render = $this->view($entity, 'block', $langcode);
+    return drupal_render($render);
+  }
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockStorageController.php b/core/modules/block/lib/Drupal/block/BlockStorageController.php
index d6c547d..02ce952 100644
--- a/core/modules/block/lib/Drupal/block/BlockStorageController.php
+++ b/core/modules/block/lib/Drupal/block/BlockStorageController.php
@@ -21,6 +21,7 @@ class BlockStorageController extends ConfigStorageController {
   public function load(array $ids = NULL) {
     $entities = parent::load($ids);
     // Only blocks with a valid plugin should be loaded.
+    // @todo this validation doesn't make sense in a SCOTCH world; fix/remove it
     return array_filter($entities, function ($entity) {
       return $entity->getPlugin();
     });
diff --git a/core/modules/block/lib/Drupal/block/DefaultBlockController.php b/core/modules/block/lib/Drupal/block/DefaultBlockController.php
new file mode 100644
index 0000000..4c0ff7a
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/DefaultBlockController.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\DefaultBlockController.
+ */
+
+namespace Drupal\block;
+
+use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Page\HtmlFragment;
+use Drupal\block\BlockPluginInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Default controller for rendering a block.
+ */
+class DefaultBlockController implements BlockControllerInterface {
+
+  /**
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  public function __construct(ModuleHandlerInterface $moduleHandler) {
+    $this->moduleHandler = $moduleHandler;
+  }
+  /**
+   * Renders a provided block into an HtmlFragment.
+   *
+   * @param Request        $request
+   * @param BlockPluginInterface $block
+   *
+   * @return \Drupal\Core\Page\HtmlFragment
+   */
+  public function respond(Request $request, BlockPluginInterface $block) {
+    $fragment = new HtmlFragment();
+    $fragment->addAssetBag($block->getAssets());
+    $fragment->setTitle($block->getTitle());
+
+    if ($build = $block->build()) {
+      $render = array(
+        '#theme' => 'block_ng',
+        '#block' => $block,
+        'content' => $build['content'],
+        '#configuration' => $block->getConfig(),
+        '#label' => check_plain($block->getTitle()),
+      );
+
+      $this->moduleHandler->alter('block_ng_view', $render);
+
+      $fragment->setContent(drupal_render($render));
+    }
+
+    return $fragment;
+  }
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/Exception/ExceptionInterface.php b/core/modules/block/lib/Drupal/block/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..2a8a41d
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Exception/ExceptionInterface.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\ExceptionInterface.
+ */
+
+namespace Drupal\block\Exception;
+
+/**
+ * A general exception interface for all block-related exceptions.
+ */
+interface ExceptionInterface {
+
+}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/Exception/MissingRequiredDataException.php b/core/modules/block/lib/Drupal/block/Exception/MissingRequiredDataException.php
new file mode 100644
index 0000000..c7e9da8
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Exception/MissingRequiredDataException.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\block\MissingRequiredDataException.
+ */
+
+namespace Drupal\block\Exception;
+
+use InvalidArgumentException;
+use Drupal\block\Exception\ExceptionInterface;
+
+/**
+ * Exception indicating that a block is missing certain injected data.
+ *
+ * Throw this exception if an operation is attempted on or by a block that
+ * requires that block to have all of its contextual data and configuration
+ * requirements met.
+ */
+class MissingRequiredDataException extends InvalidArgumentException implements ExceptionInterface {}
\ No newline at end of file
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php b/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
index 3c8b14c..7022183 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php
@@ -8,6 +8,7 @@
 namespace Drupal\block\Plugin\Core\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Config\Entity\EmbeddedPluginConfigInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\block\BlockPluginBag;
@@ -39,7 +40,7 @@
  *   }
  * )
  */
-class Block extends ConfigEntityBase implements BlockInterface {
+class Block extends ConfigEntityBase implements BlockInterface, EmbeddedPluginConfigInterface {
 
   /**
    * The ID of the block.
@@ -114,6 +115,21 @@ public function getPlugin() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function getPluginId() {
+    return $this->plugin;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setPluginId($plugin_id) {
+    $this->plugin = $plugin_id;
+  }
+
+
+  /**
    * Overrides \Drupal\Core\Entity\Entity::uri();
    */
   public function uri() {
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 012bf10..76ffc27 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -6,14 +6,19 @@
 
 namespace Drupal\block\Plugin\Type;
 
+use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
+use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Plugin\Mapper\ConfigDrivenMapperInterface;
+use Drupal\block\BlockInterface;
+use Drupal\block\Plugin\Core\Entity\Block;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -22,7 +27,14 @@
  *
  * @see \Drupal\block\BlockPluginInterface
  */
-class BlockManager extends PluginManagerBase {
+class BlockManager extends PluginManagerBase implements ConfigDrivenMapperInterface {
+
+  protected $defaults = array(
+    'semantics' => 'div',
+    'has_native_access_logic' => TRUE,
+    // Indicates whether or not a block can be safely deferred to a subrequest.
+    'subrequest_safe' => FALSE, // @todo it'd be great to default to TRUE here.
+  );
 
   /**
    * Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
@@ -34,10 +46,28 @@ class BlockManager extends PluginManagerBase {
   public function __construct(\Traversable $namespaces) {
     $this->discovery = new AnnotatedClassDiscovery('Block', $namespaces);
     $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
+    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
     $this->discovery = new AlterDecorator($this->discovery, 'block');
     $this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(Language::TYPE_INTERFACE)->langcode, 'block', CacheBackendInterface::CACHE_PERMANENT, array('block'));
-
     $this->factory = new DefaultFactory($this->discovery);
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * @return \Drupal\block\BlockInterface
+   *   A configured BlockInterface instance.
+   */
+  public function getInstanceViaConfig($config_id, $plugin_id = '') {
+    // Allow for different prefixes - e.g., custom vs. generic reusable blocks.
+    $entity = config_load_entity_by_name($config_id);
+
+    if (!$entity instanceof BlockInterface) {
+      throw new PluginException(sprintf('No block configuration found for config id "%s".', $config_id));
+    }
+
+    $plugin_id = $plugin_id ?: $entity->getPluginId();
+    return $this->createInstance($plugin_id, $entity->get('settings'));
+  }
+
 }
diff --git a/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
index 1bde917..b34af61 100644
--- a/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
+++ b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
@@ -17,6 +17,7 @@
  * @Plugin(
  *   id = "test_cache",
  *   admin_label = @Translation("Test block caching"),
+ *   has_native_access_logic = FALSE,
  *   module = "block_test"
  * )
  */
diff --git a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
index 7461aa7..4de59a7 100644
--- a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
+++ b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
@@ -17,6 +17,7 @@
  * @Plugin(
  *   id = "book_navigation",
  *   admin_label = @Translation("Book navigation"),
+ *   has_native_access_logic = FALSE,
  *   module = "book"
  * )
  */
diff --git a/core/modules/booze_test/booze_test.info.yml b/core/modules/booze_test/booze_test.info.yml
new file mode 100644
index 0000000..9988a36
--- /dev/null
+++ b/core/modules/booze_test/booze_test.info.yml
@@ -0,0 +1,6 @@
+name: "Booze test"
+type: module
+description: "it gets ya drunk."
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/booze_test/booze_test.module b/core/modules/booze_test/booze_test.module
new file mode 100644
index 0000000..d65d323
--- /dev/null
+++ b/core/modules/booze_test/booze_test.module
@@ -0,0 +1,10 @@
+<?php
+
+function booze_poc() {
+  drupal_set_title("IT'S TIME FOR SCOTCH");
+  return array(
+    '#markup' => '...bitches.',
+    '#prefix' => '<div id="first-time-EVAH">',
+    '#suffix' => '</div>',
+  );
+}
diff --git a/core/modules/booze_test/booze_test.routing.yml b/core/modules/booze_test/booze_test.routing.yml
new file mode 100644
index 0000000..e2918f1
--- /dev/null
+++ b/core/modules/booze_test/booze_test.routing.yml
@@ -0,0 +1,7 @@
+booze_test_1:
+  pattern: '/booze'
+  defaults:
+    _content: 'booze_poc'
+    _display: 'display.bound.frontend'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/booze_test/config/display.bound.frontendtmp.yml b/core/modules/booze_test/config/display.bound.frontendtmp.yml
new file mode 100644
index 0000000..acad122
--- /dev/null
+++ b/core/modules/booze_test/config/display.bound.frontendtmp.yml
@@ -0,0 +1,35 @@
+id: frontendtmp
+label: Frontend master display
+layout: static_layout:bartik__frontend
+layoutSettings: { }
+blockInfo:
+# these have bartik in their namespace, but that's irrelevant to our use here -
+# we're just reusing them while we get everything together.
+  bartik.help:
+    region: help
+    region-type: content
+    weight: 0 # should float in unbound/master
+  bartik.content:
+    region: content
+    region-type: content
+    weight: 0 # should float in unbound/master
+  bartik.footer:
+    region: footer
+    region-type: footer
+    weight: 0 # stick-top in unbound/master
+  bartik.powered:
+    region: footer
+    region-type: footer
+    weight: 10 # float in unbound/master
+  bartik.search:
+    region: sidebar_first
+    region-type: aside
+    weight: 0 # stick-top in unbound/master
+  bartik.login:
+    region: sidebar_first
+    region-type: aside
+    weight: 10 # stick-top in unbound/master
+  bartik.tools:
+    region: sidebar_first
+    region-type: aside
+    weight: 20 # stick-top in unbound/master
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
index 4ab3bfd..15ea916 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
@@ -17,6 +17,7 @@
  * @Plugin(
  *   id = "language_block",
  *   admin_label = @Translation("Language switcher"),
+ *   has_native_access_logic = FALSE,
  *   module = "language",
  *   derivative = "Drupal\language\Plugin\Derivative\LanguageBlock"
  * )
diff --git a/core/modules/layout/layout.info.yml b/core/modules/layout/layout.info.yml
index 6980504..7d72cd6 100644
--- a/core/modules/layout/layout.info.yml
+++ b/core/modules/layout/layout.info.yml
@@ -4,3 +4,4 @@ description: 'Makes it possible to swap different page layouts.'
 package: Core
 version: VERSION
 core: 8.x
+required: TRUE
diff --git a/core/modules/layout/layout.module b/core/modules/layout/layout.module
index 17acc6d..7c6fd0f 100644
--- a/core/modules/layout/layout.module
+++ b/core/modules/layout/layout.module
@@ -5,6 +5,8 @@
  * Manages page layouts for content presentation.
  */
 
+use Drupal\Core\Template\Attribute;
+
 /**
  * Implements hook_menu().
  */
@@ -18,7 +20,7 @@ function layout_menu() {
     'title' => 'View template',
     'page callback' => 'layout_page_view',
     'page arguments' => array(4),
-    'access callback' => 'layout_user_access',
+    'access callback' => 'layout_administer_access',
     'access arguments' => array(4),
     'file' => 'layout.admin.inc',
   );
@@ -35,7 +37,7 @@ function layout_menu() {
  *   TRUE if the current user can access page layout menu items; FALSE
  *   otherwise.
  */
-function layout_user_access($key) {
+function layout_administer_access($key) {
   return (user_access('administer layouts') && layout_manager()->getDefinition($key));
 }
 
@@ -73,7 +75,64 @@ function layout_theme($existing, $type, $theme, $path) {
       'variables' => array('content' => NULL),
       'path' => $layout['path'],
       'template' => $layout['template'],
+      'base hook' => 'page',
     );
   }
+
+  $items['block_ng'] = array(
+    'render element' => 'elements',
+    'template' => 'block-ng',
+  );
+
+  $items['group'] = array(
+    'render element' => 'elements',
+    'template' => 'group',
+  );
   return $items;
 }
+
+function template_preprocess_block_ng(&$variables) {
+  $block = $variables['elements']['#block'];
+
+  // Add appropriate theme hook suggestions, based on the plugin name.
+  $parts = explode(':', $block->getPluginId());
+  $suggestion = 'block_ng';
+  while ($part = array_shift($parts)) {
+    $variables['theme_hook_suggestions'][] = $suggestion .= '__' . strtr($part, '-', '_');
+  }
+
+  $variables['semantics'] = $block->getSemantics();
+  // @todo reaching in like this is messy.
+  $config = $block->getConfig();
+  if ($config['label_display'] == BLOCK_LABEL_VISIBLE) {
+    $variables['title'] = check_plain($block->getTitle());
+  }
+  $variables['attributes'] = new Attribute();
+
+  $classes = array('block-ng', strtr($block->getPluginId(), '_', '-'));
+  if (!empty($config['classes'])) {
+    $classes += array_merge($classes, $config['classes']);
+  }
+  $variables['attributes']['class'] = $classes;
+
+  // Only add an id to the block if one was explicitly set in config.
+  if (!empty($config['id'])) {
+    $variables['attributes']['id'] = $config['id'];
+  }
+  $variables['content'] = $variables['elements']['content'];
+}
+
+function template_preprocess_group(&$variables) {
+  $variables['content'] = $variables['elements']['#blocks'];
+
+  $config = $variables['elements']['#config'];
+  $variables['semantics'] = $config['semantics'];
+
+  $variables['attributes'] = new Attribute();
+  if (!empty($config['classes'])) {
+    $variables['attributes']['class'] = $config['classes'];
+  }
+  if (!empty($config['id'])) {
+    $variables['attributes']['class'] = $config['id'];
+  }
+}
diff --git a/core/modules/layout/layouts/static/core/core.html.twig b/core/modules/layout/layouts/static/core/core.html.twig
new file mode 100644
index 0000000..f89832a
--- /dev/null
+++ b/core/modules/layout/layouts/static/core/core.html.twig
@@ -0,0 +1,49 @@
+{#
+
+@file
+Core's primary frontend layout implementation.
+
+
+The doctype, html, head, and body tags are not in this template; they are handled by the "html" template.
+
+Available variables:
+
+General utility variables:
+- base_path: The base URL path of the Drupal installation. At the very least, this will always default to /.
+- directory: The directory the template is located in, e.g. modules/system or themes/bartik.
+- is_front: TRUE if the current page is the front page.
+- logged_in: TRUE if the user is registered and signed in.
+- is_admin: TRUE if the user has permission to access administration pages.
+
+Regions:
+- content.header: Items for the header region.
+- content.content: Items for the main region.
+- content.footer: Items for the footer region.
+
+@see template_preprocess()
+@see template_preprocess_content()
+@see template_process()
+@see bartik_process_page()
+@see html.tpl.php
+
+@ingroup themeable
+
+#}
+
+{% if content.header %}
+  <header role="banner">
+    {{ content.header }}
+  </header>
+{% endif %}
+
+{% if content.main %}
+  <main role="main">
+    {{ content.main }}
+  </main>
+{% endif %}
+
+{% if content.footer %}
+  <footer role="contentinfo">
+    {{ content.footer }}
+  </footer>
+{% endif %}
\ No newline at end of file
diff --git a/core/modules/layout/layouts/static/core/core.yml b/core/modules/layout/layouts/static/core/core.yml
new file mode 100644
index 0000000..0b5f470
--- /dev/null
+++ b/core/modules/layout/layouts/static/core/core.yml
@@ -0,0 +1,13 @@
+title: Core Layout
+category: Core
+template: core
+regions:
+  header:
+    label: Header
+    type: header
+  main:
+    label: Main
+    type: main
+  footer:
+    label: Footer
+    type: footer
\ No newline at end of file
diff --git a/core/modules/layout/layouts/static/one-col/one-col.yml b/core/modules/layout/layouts/static/one-col/one-col.yml
deleted file mode 100644
index ea550ca..0000000
--- a/core/modules/layout/layouts/static/one-col/one-col.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-title: One column
-category: Columns: 1
-template: one-col
-regions:
-  content:
-    label: Middle column
-    type: content
\ No newline at end of file
diff --git a/core/modules/layout/layouts/static/twocol/two-col-rtl.css b/core/modules/layout/layouts/static/twocol/two-col-rtl.css
deleted file mode 100644
index 0fe6a0a..0000000
--- a/core/modules/layout/layouts/static/twocol/two-col-rtl.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* Large resolutions (desktop, tablets in landscape, ...) */
-@media only screen and (min-width: 59em) {
-  .layout-two-col .layout-region {
-    float: right;
-  }
-}
diff --git a/core/modules/layout/layouts/static/twocol/two-col.css b/core/modules/layout/layouts/static/twocol/two-col.css
deleted file mode 100644
index bb7ae25..0000000
--- a/core/modules/layout/layouts/static/twocol/two-col.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/* Large resolutions (desktop, tablets in landscape, ...) */
-@media only screen and (min-width: 59em) {
-  .layout-two-col .layout-region {
-    float: left; /* LTR */
-    width: 50%;
-  }
-}
diff --git a/core/modules/layout/layouts/static/twocol/two-col.yml b/core/modules/layout/layouts/static/twocol/two-col.yml
deleted file mode 100644
index e6c435e..0000000
--- a/core/modules/layout/layouts/static/twocol/two-col.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-title: Two column
-category: Columns: 2
-template: two-col
-stylesheets:
-  - two-col.css
-regions:
-  first:
-    label: Left side
-    type: content
-  second:
-    label: Right side
-    type: aside
diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php
index afe3229..8afab18 100644
--- a/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php
+++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php
@@ -8,6 +8,9 @@
 namespace Drupal\layout\Config;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\block\Plugin\Type\BlockManager;
+use Drupal\layout\Config\InheritableDisplayInterface;
+use Drupal\layout\Config\HeirDisplayInterface;
 use Drupal\layout\Plugin\LayoutInterface;
 
 /**
@@ -32,7 +35,9 @@
   public $uuid;
 
   /**
-   * Contains all block configuration.
+   * Contains all local block configuration.
+   *
+   * @todo update these docs to reflect the distinction between standalone and embedded blocks
    *
    * There are two levels to the configuration contained herein: display-level
    * block configuration, and then block instance configuration.
@@ -79,17 +84,97 @@
   protected $blockInfo = array();
 
   /**
-   * Implements DisplayInterface::getAllBlockInfo().
+   * Contains block configuration for all embedded blocks.
+   *
+   * This is an associative array, keyed on internal block id, with each value
+   * being an array of the internal configuration for a block that is embedded
+   * directly on this display. This is the counterpart to standalone storage via
+   * an independent configuration object - exactly the same data is stored, but
+   * it is located directly on the display rather than in a separate object.
+   *
+   * @see \Drupal\block\Plugin\Core\Entity\Block
+   *
+   * @var array
+   */
+  protected $embeddedBlockConfigs = array();
+
+  /**
+   * An associative array with information about the groups contained in this
+   * display.
+   *
+   * @var array
+   */
+  protected $groups;
+
+  /**
+   * @var \Drupal\block\Plugin\Type\BlockManager
+   */
+  protected $blockManager;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo this makes unserialization of displays hard - though that may not be an issue.
+   */
+  public function setBlockManager(BlockManager $blockManager) {
+    $this->blockManager = $blockManager;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlockManager() {
+    if (!isset($this->blockManager)) {
+      // @todo reaching out like this sucks, but injecting into entities via their storage controllers would require mucking with the EntityManager...not worth it yet.
+      $this->blockManager = \Drupal::service('plugin.manager.block');
+    }
+    return $this->blockManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @throws \InvalidArgumentException
+   */
+  public function getBlock($id) {
+    $infos = $this->getAllOuterBlockConfig();
+    $configs = $this->getAllEmbeddedBlockConfigs();
+
+    if (!isset($infos[$id])) {
+      throw new \InvalidArgumentException(sprintf("Display '%s' does not contain a block with id '%s'.", $this->id(), $id));
+    }
+
+    // Figure out if we're dealing with an embedded or standalone block.
+    if (empty($infos[$id]['embedded'])) {
+      // The block is standalone; have the BlockManager load it by config_id.
+      return $this->getBlockManager()->getInstanceViaConfig($id);
+    }
+    else {
+      $config = $configs[$id];
+      $plugin_id = $config['plugin'];
+      return $this->getBlockManager()->createInstance($plugin_id, $config['settings']);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
    */
-  public function getAllBlockInfo() {
-    return $this->blockInfo;
+  public function getAllEmbeddedBlockConfigs() {
+    return $this->embeddedBlockConfigs;
   }
 
   /**
-   * Implements DisplayInterface::mapBlocksToLayout().
+   * {@inheritdoc}
+   */
+  public function getAllGroupConfig() {
+    return $this->groups;
+  }
+
+  /**
+   * {@inheritdoc}
    *
-   * @todo Decouple this implementation from this class, so that it could be
-   *   more easily customized.
+   * @todo Decouple this implementation from this class and place it onto the layout plugin.
    */
   public function mapBlocksToLayout(LayoutInterface $layout) {
     $types = array();
@@ -126,7 +211,7 @@ public function mapBlocksToLayout(LayoutInterface $layout) {
   }
 
   /**
-   * Implements DisplayInterface::getAllRegionTypes().
+   * {@inheritdoc}
    */
   public function getAllRegionTypes() {
     $types = array();
@@ -135,4 +220,15 @@ public function getAllRegionTypes() {
     }
     return array_unique($types);
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getExportProperties() {
+    $properties = parent::getExportProperties();
+    $properties['blockInfo'] = $this->blockInfo;
+    $properties['embeddedBlockConfigs'] = $this->embeddedBlockConfigs;
+    $properties['groups'] = $this->groups;
+    return $properties;
+  }
 }
diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php
index 916d897..0f88797 100644
--- a/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php
+++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php
@@ -6,6 +6,9 @@
 
 namespace Drupal\layout\Config;
 
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\block\BlockInterface;
+use Drupal\block\Plugin\Type\BlockManager;
 use Drupal\layout\Plugin\LayoutInterface;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 
@@ -34,6 +37,8 @@
   /**
    * Returns the display-specific configuration of all blocks in this display.
    *
+   * @todo update docs to reflect separation between 'embedded' and 'standalone' blocks
+   *
    * For each block that exists in Drupal (e.g., the "Who's Online" block),
    * multiple "configured instances" can be created (e.g., a "Who's been online
    * in the last 5 minutes" instance and a "Who's been online in the last 60
@@ -62,7 +67,59 @@
    *     different regions.
    *   - weight: Within a region, blocks are rendered from low to high weight.
    */
-  public function getAllBlockInfo();
+  public function getAllOuterBlockConfig();
+
+  /**
+   * Returns all embedded block configurations.
+   *
+   * @return array
+   */
+  public function getAllEmbeddedBlockConfigs();
+
+  /**
+   * Return the configuration for all region groups in this display.
+   *
+   * @return array
+   */
+  public function getAllGroupConfig();
+
+  /**
+   * Gets a configured BlockInterface instance.
+   *
+   * This method abstracts the difference between a reusable/externally
+   * configured block and a block that is embedded within the display.
+   *
+   * @todo this separation of responsibilities is still a little awkward.
+   *
+   * @param $id
+   *   The display's internal id for the block.
+   *
+   * @return \Drupal\block\BlockInterface
+   */
+  public function getBlock($id);
+
+  /**
+   * Injects a BlockManager.
+   *
+   * Displays use the BlockManager to create BlockInterface objects with their
+   * configuration already correctly injected.
+   *
+   * @todo this will eventually be tricky because of the difficulties the BlockManager may have with loading different block entity types (custom block vs. generic reusable block)
+   * @todo this makes unserialization of displays hard - though that may not be a concern.
+   *
+   * @param BlockManager $blockManager
+   *
+   * @return DisplayInterface
+   *   The current DisplayInterface object.
+   */
+  public function setBlockManager(BlockManager $blockManager);
+
+  /**
+   * Returns the BlockManager contained in this display.
+   *
+   * @return BlockManager
+   */
+  public function getBlockManager();
 
   /**
    * Maps the contained block info to the provided layout.
@@ -71,7 +128,7 @@ public function getAllBlockInfo();
    *
    * @return array
    *   An array containing block configuration info, identical to that which
-   *   is returned by DisplayInterface::getAllBlockInfo().
+   *   is returned by DisplayInterface::getAllOuterBlockConfig().
    */
   public function mapBlocksToLayout(LayoutInterface $layout);
 
@@ -83,4 +140,18 @@ public function mapBlocksToLayout(LayoutInterface $layout);
    *   region types were assigned.
    */
   public function getAllRegionTypes();
+
+  /**
+   * Flushes all internally calculated and cached data from the display.
+   *
+   * Displays load and/or calculate, then attach a lot of data as local object
+   * properties: the layout plugin instance, their master display (if an heir),
+   * and potentially also block object instances. This method flushes all that
+   * locally cached data, which may be necessary if some of the raw data
+   * underlying some of those calculated properties changes (e.g., a new master
+   * is swapped in).
+   *
+   * @return void
+   */
+  public function flush();
 }
diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayStorageController.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayStorageController.php
new file mode 100644
index 0000000..8781a42
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayStorageController.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\layout\Config\UnboundDisplayStorageController.
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\block\Plugin\Type\BlockManager;
+use Drupal\layout\Config\DisplayInterface;
+
+/**
+ * Storage controller for Displays.
+ *
+ * @see \Drupal\layout\Config\BoundDisplayInterface
+ */
+class DisplayStorageController extends ConfigStorageController {
+  /**
+   * @param array $values
+   *   An array of values with which to create the new Display object.
+   *
+   * @return \Drupal\layout\Config\DisplayInterface
+   */
+  public function create(array $values) {
+    $display = parent::create($values);
+    if ($display instanceof HeirDisplayInterface && !empty($values['masterId'])) {
+      entity_load($values['masterType'], $values['masterId']);
+    }
+    // @todo ideally we should inject the BlockManager into displays here...but it's already hard to get the service into this storage controller.
+  }
+
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayBase.php b/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayBase.php
new file mode 100644
index 0000000..b8460c8
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayBase.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\layout\Config\HeirDisplayBase.
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\Component\Utility\NestedArray;
+
+/**
+ * Base class for Displays capable of receiving masters.
+ */
+abstract class HeirDisplayBase extends DisplayBase implements HeirDisplayInterface {
+  /**
+   * The string configuration key identifying this display's master, if any.
+   *
+   * @var string
+   */
+  public $masterId;
+
+  /**
+   * The entity type of the master display.
+   *
+   * Used to ensure we load the master display correctly via entity_load().
+   *
+   * @var string
+   */
+  public $masterType = 'display';
+
+  /**
+   * @var \Drupal\layout\Config\InheritableDisplayInterface
+   */
+  protected $master;
+
+  /**
+   * Contains inheritance-reconciled display data.
+   *
+   * Inheritance pulls down several properties from the master. This property
+   * contains all the fully reconciled information, keyed by the name of the
+   * object property that was merged.
+   *
+   * @var array
+   */
+  protected $reconciled = array();
+
+  /**
+   * Tracks whether or not master inheritance has been performed.
+   *
+   * @var bool
+   */
+  protected $inherited = FALSE;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMaster() {
+    if (!isset($this->master)) {
+      if (empty($this->masterId)) {
+        $this->master = FALSE;
+      }
+      else {
+        $master = entity_load($this->masterType, $this->masterId);
+        $this->master = $master instanceof InheritableDisplayInterface ? $master : FALSE;
+      }
+    }
+
+    return $this->master;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMaster(InheritableDisplayInterface $display) {
+    $this->flush();
+
+    $this->masterType = $display->entityType();
+    $this->masterId = $display->id();
+    $this->master = $display;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllOuterBlockConfig() {
+    $this->inherit();
+    return $this->reconciled['blockInfo'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllEmbeddedBlockConfigs() {
+    $this->inherit();
+    return $this->reconciled['embeddedBlockConfigs'];
+  }
+
+  /**
+   * Triggers inheritance from this display's master.
+   *
+   * Inheritance requires the reconciliation of multiple different properties.
+   * This method reconciles everything at once, which allows central control of
+   * inheritance state, rather than having to juggle it in each accessor method
+   * separately.
+   *
+   * @return void
+   */
+  protected function inherit() {
+    // Only calculate inherited properties if the state flag is not set.
+    if ($this->inherited) {
+      return;
+    }
+    $this->inherited = TRUE;
+
+    $local_infos = $this->blockInfo;
+    foreach ($local_infos as &$info) {
+      // Indicate that this block is originally declared in this display.
+      $info['owner'] = $this->id();
+    }
+
+    // Only try to inherit if there is a master.
+    if (!$this->getMaster()) {
+      // No master; merged block info will be identical to local block info.
+      $this->reconciled['blockInfo'] = $local_infos;
+      $this->reconciled['embeddedBlockConfigs'] = $this->embeddedBlockConfigs;
+    }
+    else {
+      // This display is an heir with a master, so pull everything down.
+      $master_infos = $this->getMaster()->getAllOuterBlockConfig();
+      $master_embedded_configs = $this->getMaster()->getAllEmbeddedBlockConfigs();
+
+      // @todo this needs to be thought through and made into a better pattern.
+      // Allow local blocks to supersede masters.
+      $this->reconciled['blockInfo'] = NestedArray::mergeDeep($master_infos, $local_infos);
+      $this->reconciled['embeddedBlockConfigs'] = NestedArray::mergeDeep($master_embedded_configs, $this->getAllEmbeddedBlockConfigs());
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function flush() {
+    unset($this->reconciled, $this->master);
+  }
+}
\ No newline at end of file
diff --git a/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayInterface.php
new file mode 100644
index 0000000..4c9d9f3
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/HeirDisplayInterface.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\layout\Config\HeirDisplayInterface.
+ */
+namespace Drupal\layout\Config;
+
+/**
+ * Interface describing a display that can inherit from another display.
+ *
+ * @see InheritableDisplayInterface
+ */
+interface HeirDisplayInterface extends DisplayInterface {
+
+  /**
+   * Sets the master display from which this display should inherit.
+   *
+   * @param InheritableDisplayInterface $display
+   *   The master display from which this display should inherit.
+   *
+   * @return HeirDisplayInterface
+   *   The current HeirDisplayInterface object.
+   */
+  public function setMaster(InheritableDisplayInterface $display);
+
+  /**
+   * Returns the master display from which this display inherits, if any.
+   *
+   * @return bool|\Drupal\layout\Config\InheritableDisplayInterface
+   *   This display's master, or FALSE if there is no master.
+   */
+  public function getMaster();
+}
\ No newline at end of file
diff --git a/core/modules/layout/lib/Drupal/layout/Config/InheritableDisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/InheritableDisplayInterface.php
new file mode 100644
index 0000000..750f17f
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/InheritableDisplayInterface.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\layout\Config\InheritableDisplayInterface.
+ */
+
+namespace Drupal\layout\Config;
+
+/**
+ * Interface describing a display from which another display can inherit.
+ *
+ * Display inheritance is a mechanism by which one display can inherit blocks
+ * defined in another. It is the primary mechanism by which site-wide block
+ * configuration is accomplished: a single parent, or master, display can define
+ * shared blocks, and then many "local" displays, each tied to a specific route,
+ * can each inherit the shared blocks from that master, but also add its own.
+ *
+ * @see HeirDisplayInterface
+ */
+interface InheritableDisplayInterface extends DisplayInterface {
+  // @todo get this to jive with the existing interface strategy.
+}
\ No newline at end of file
diff --git a/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayStorageController.php b/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayStorageController.php
new file mode 100644
index 0000000..c139a71
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayStorageController.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\layout\Config\UnboundDisplayStorageController.
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\layout\Plugin\Core\Entity\Display;
+use Drupal\Core\Config\Config;
+
+/**
+ * Storage controller for Unbound Displays.
+ *
+ * @see \Drupal\layout\Config\UnboundDisplayInterface
+ */
+class UnboundDisplayStorageController extends ConfigStorageController {
+  public function importCreate($name, Config $new_config, Config $old_config) {
+    // First, import the unbound display into active config
+    $unbound_display = $this->create($new_config->get());
+    $unbound_display->save();
+
+    // Now, create a corresponding bound display - if one doesn't exist already.
+    if (!entity_load('display', $name)) {
+      // @todo need finer-grained control than a single global default
+      // @todo how do we figure out whether we're doing frontend, admin, or...other?
+      $layout = drupal_container()->get('plugin.manager.layout')
+        ->createInstance(config('system.site')->get('default_layout'));
+      $bound_display = $unbound_display->generateDisplay($layout, $name);
+      $bound_display->save();
+    }
+
+    // @todo consider adding flexibility around which display type to create
+//    $controller = drupal_container()
+//      ->get('plugin.manager.entity')
+//      ->getStorageController('display');
+
+    // $controller->create();
+    return TRUE;
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageActions.php b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageActions.php
new file mode 100644
index 0000000..69cf145
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageActions.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\layout\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_actions",
+ *   subject = @Translation("Menu Actions"),
+ *   module = "layout",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageActions extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockBuild() {
+    return array(
+      menu_get_local_actions()
+    );
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageBreadcrumb.php b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageBreadcrumb.php
new file mode 100644
index 0000000..9aef4fc
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageBreadcrumb.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\layout\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_breadcrumb",
+ *   subject = @Translation("Breadcrumb"),
+ *   module = "layout",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageBreadcrumb extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockBuild() {
+    return array(
+      '#children' => theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb())),
+    );
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageMessages.php b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageMessages.php
new file mode 100644
index 0000000..43f62c6
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Block/PageMessages.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\layout\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_messages",
+ *   subject = @Translation("Status Messages"),
+ *   module = "layout",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageMessages extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockBuild() {
+    return array(
+      '#children' => theme('status_messages'),
+    );
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php
index adaf260..28d8567 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php
@@ -9,6 +9,9 @@
 
 use Drupal\layout\Config\DisplayBase;
 use Drupal\layout\Config\BoundDisplayInterface;
+use Drupal\layout\Config\HeirDisplayBase;
+use Drupal\layout\Config\HeirDisplayInterface;
+use Drupal\layout\Config\InheritableDisplayInterface;
 use Drupal\layout\Config\UnboundDisplayInterface;
 use Drupal\layout\Plugin\LayoutInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
@@ -31,7 +34,7 @@
  *   }
  * )
  */
-class Display extends DisplayBase implements BoundDisplayInterface {
+class Display extends HeirDisplayBase implements BoundDisplayInterface, InheritableDisplayInterface {
 
   /**
    * A two-level array expressing block ordering within regions.
@@ -70,8 +73,9 @@ class Display extends DisplayBase implements BoundDisplayInterface {
    */
   public $layoutSettings = array();
 
+
   /**
-   * Implements BoundDisplayInterface::getSortedBlocksByRegion().
+   * {@inheritdoc}
    *
    * @throws \Exception
    */
@@ -88,7 +92,7 @@ public function getSortedBlocksByRegion($region) {
   }
 
   /**
-   * Implements BoundDisplayInterface::getAllSortedBlocks().
+   * {@inheritdoc}
    */
   public function getAllSortedBlocks() {
     if ($this->blocksInRegions === NULL) {
@@ -124,7 +128,7 @@ protected function sortBlocks() {
   }
 
   /**
-   * Implements BoundDisplayInterface::remapToLayout().
+   * {@inheritdoc}
    */
   public function remapToLayout(LayoutInterface $layout) {
     $this->blockInfo = $this->mapBlocksToLayout($layout);
@@ -132,25 +136,21 @@ public function remapToLayout(LayoutInterface $layout) {
   }
 
   /**
-   * Set the contained layout plugin.
-   *
-   * @param string $plugin_id
-   *   The plugin id of the desired layout plugin.
+   * {@inheritdoc}
    */
   public function setLayout($plugin_id) {
+    $this->flush();
     // @todo verification?
     $this->layout = $plugin_id;
-    $this->layoutInstance = NULL;
-    $this->blocksInRegions = NULL;
   }
 
   /**
-   * Implements BoundDisplayInterface::generateUnboundDisplay().
+   * {@inheritdoc}
    *
    * @throws \Exception
    */
   public function generateUnboundDisplay($id, $entity_type = 'unbound_display') {
-    $block_info = $this->getAllBlockInfo();
+    $block_info = $this->getAllOuterBlockConfig();
     foreach ($block_info as &$info) {
       unset($info['region']);
     }
@@ -169,7 +169,7 @@ public function generateUnboundDisplay($id, $entity_type = 'unbound_display') {
   }
 
   /**
-   * Returns the instantiated layout object.
+   * {@inheritdoc}
    *
    * @throws \Exception
    */
@@ -185,4 +185,12 @@ public function getLayoutInstance() {
 
     return $this->layoutInstance;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function flush() {
+    parent::flush();
+    unset($this->layoutInstance, $this->blockInRegions);
+  }
 }
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php
index d2f4880..3b60cbb 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php
@@ -25,7 +25,7 @@
  *   label = @Translation("Unbound Display"),
  *   module = "layout",
  *   controllers = {
- *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController"
+ *     "storage" = "layout\Config\UnboundDisplayStorageController"
  *   },
  *   config_prefix = "display.unbound",
  *   entity_keys = {
@@ -37,11 +37,12 @@
 class UnboundDisplay extends DisplayBase implements UnboundDisplayInterface {
 
   /**
-   * Implements UnboundDisplayInterface::generateDisplay().
+   * {@inheritdoc}
    *
    * @throws \Exception
    */
   public function generateDisplay(LayoutInterface $layout, $id, $entity_type = 'display') {
+    // @todo might be better to decouple this from the UnboundDisplay class
     $values = array(
       'layout' => $layout->getPluginId(),
       'blockInfo' => $this->mapBlocksToLayout($layout),
@@ -56,4 +57,18 @@ public function generateDisplay(LayoutInterface $layout, $id, $entity_type = 'di
 
     return $entity;
   }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo this system is increasingly awkward - could it inherit from a master? how?
+   */
+  public function getAllOuterBlockConfig() {
+    return $this->blockInfo;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function flush() {}
 }
diff --git a/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php b/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php
index 07a77bf..ac0a77e 100644
--- a/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php
+++ b/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php
@@ -127,6 +127,6 @@ public function testBlockMapping() {
     $this->assertTrue($twocol_to_unbound instanceof UnboundDisplay, 'Unbinding the twocol display successfully created an UnboundDisplay object');
     // We can use Equal instead of Identical, because for this, array order and
     // integer vs. string data types do not matter.
-    $this->assertEqual($twocol_to_unbound->getAllBlockInfo(), $expected);
+    $this->assertEqual($twocol_to_unbound->getAllOuterBlockConfig(), $expected);
   }
 }
diff --git a/core/modules/layout/templates/block-ng.html.twig b/core/modules/layout/templates/block-ng.html.twig
new file mode 100644
index 0000000..2090f32
--- /dev/null
+++ b/core/modules/layout/templates/block-ng.html.twig
@@ -0,0 +1,24 @@
+{#
+
+Generic Block Template!
+
+what goes in header?
+
+#}
+
+{% if semantics %}
+  {# @todo our final goal for this is:
+  <{{ semantics }} {{ id }} {{ classes }} {{ aria }} {{ attributes }}>
+  #}
+  <{{ semantics }}{{ attributes }}>
+  {% if semantics != 'span' %}
+    <header>
+      {% if title %}{{ title }}{% endif %}
+    </header>
+  {% endif %}
+{% endif %}
+{{ content }}
+
+{% if semantics %}
+  </{{ semantics }}>
+{% endif %}
\ No newline at end of file
diff --git a/core/modules/layout/templates/group.html.twig b/core/modules/layout/templates/group.html.twig
new file mode 100644
index 0000000..7f7200e
--- /dev/null
+++ b/core/modules/layout/templates/group.html.twig
@@ -0,0 +1,8 @@
+{#
+
+Template for region groups, which are just thin containers for blocks.
+
+#}
+{% if semantics %}<{{ semantics }}{{ attributes }}>{% endif %}
+  {{ content }}
+{% if semantics %}</{{ semantics }}>{% endif %}
\ No newline at end of file
diff --git a/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuNavigation.php b/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuNavigation.php
new file mode 100644
index 0000000..9938dca
--- /dev/null
+++ b/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuNavigation.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu\Plugin\Block\MenuNavigation.
+ */
+
+namespace Drupal\menu\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Provides a navigation block for displaying menu links of a specified depth.
+ *
+ * @Plugin(
+ *   id = "menu_navigation",
+ *   admin_label = @Translation("Menu navigation"),
+ *   module = "menu"
+ * )
+ */
+class MenuNavigation extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settings() {
+    return array(
+      'menu' => 'main',
+      'level' => 0,
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, &$form_state) {
+    $form['menu'] = array(
+      '#type' => 'select',
+      '#title' => t('Source menu'),
+      '#default_value' => $this->configuration['menu'],
+      '#options' => menu_get_menus(),
+      '#required' => TRUE,
+    );
+    $form['level'] = array(
+      '#type' => 'select',
+      '#title' => t('Starting level'),
+      '#default_value' => $this->configuration['level'],
+      '#options' => drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 6, 7, 8)),
+      '#required' => TRUE,
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, &$form_state) {
+    $this->setConfig('menu', $form_state['values']['menu']);
+    $this->setConfig('level', $form_state['values']['level']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockBuild() {
+    // @todo BlockManager fails to merge default settings.
+    $this->configuration += $this->settings();
+
+    $menu_name = $this->configuration['menu'];
+    $level = $this->configuration['level'];
+    // @todo menu_nagivation_links should be migrated to a menu link service and
+    // that should be injected here.
+    $links = menu_navigation_links($menu_name, $level);
+    // Do not output this entire block if there are no visible/accessible links.
+    // Filter the links to remove those with #access set to FALSE.
+    array_filter($links, function($link) {
+      if (isset($link['#access']) && $link['#access'] === FALSE) {
+        return FALSE;
+      }
+      return TRUE;
+    });
+    if (empty($links)) {
+      return array();
+    }
+    $build = array(
+      '#theme' => 'links',
+      '#links' => $links,
+    );
+    if (!empty($this->configuration['id'])) {
+      $build['#attributes']['id'] = drupal_html_id($this->configuration['id']);
+    }
+    return $build;
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Block/ShortcutsBlock.php b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Block/ShortcutsBlock.php
index ff89f50..0e24aa5 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Block/ShortcutsBlock.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Block/ShortcutsBlock.php
@@ -17,6 +17,7 @@
  * @Plugin(
  *  id = "shortcuts",
  *  admin_label = @Translation("Shortcuts"),
+ *  has_native_access_logic = FALSE,
  *  module = "shortcut"
  * )
  */
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteLogo.php b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteLogo.php
new file mode 100644
index 0000000..2981fba
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteLogo.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\system\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_site_logo",
+ *   admin_label = @Translation("Site Logo"),
+ *   module = "system",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageSiteLogo extends BlockBase {
+
+  /**
+   * Overrides \Drupal\block\BlockBase::blockBuild().
+   */
+  public function blockBuild() {
+    $logo = theme_get_setting('logo');
+    if (!empty($logo)) {
+      $image = '<img src="' . $logo['url'] . '" alt="' . t('Home') . '" />';
+      return array(
+        '#children' => l($image, '', array('html' => TRUE, 'attributes' => array('rel' => 'home', 'id' => 'logo', 'title' => t('Home')))),
+      );
+    }
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteName.php b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteName.php
new file mode 100644
index 0000000..d29eda5
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteName.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Plugin\Block\PageSiteName
+ */
+
+namespace Drupal\system\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_site_name",
+ *   admin_label = @Translation("Site Name"),
+ *   module = "system",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageSiteName extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockBuild() {
+    $name = filter_xss_admin(config('system.site')->get('name'));
+    if ($name) {
+      return array(
+        '#children' => filter_xss_admin(config('system.site')->get('name')),
+      );
+    }
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteSlogan.php b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteSlogan.php
new file mode 100644
index 0000000..ed843c3
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/PageSiteSlogan.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\system\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * @Plugin(
+ *   id = "page_site_slogan",
+ *   admin_label = @Translation("Site Slogan"),
+ *   module = "system",
+ *   settings = {
+ *     "status" = TRUE,
+ *     "cache" = DRUPAL_NO_CACHE
+ *   }
+ * )
+ */
+class PageSiteSlogan extends BlockBase {
+
+  /**
+   * Overrides \Drupal\block\BlockBase::blockBuild().
+   */
+  public function blockBuild() {
+    $slogan = theme_get_setting('features.slogan');
+    if ($slogan) {
+      $slogan = config('system.site')->get('slogan');
+      if (!empty($slogan)) {
+        return array(
+          '#children' => filter_xss_admin($slogan),
+        );
+      }
+    }
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
index a370374..925da17 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
@@ -41,9 +41,14 @@ public function access() {
    * Implements \Drupal\block\BlockBase::blockBuild().
    */
   protected function blockBuild() {
-    return array(
-      '#children' => $this->help,
-    );
+    if (empty($this->help)) {
+      return array();
+    }
+    else {
+      return array(
+        '#children' => $this->help,
+      );
+    }
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
index db18651..b15f5c1 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
@@ -22,13 +22,28 @@
  */
 class SystemMainBlock extends BlockBase {
 
+  protected $controllerClosure;
+
   /**
-   * Implements \Drupal\block\BlockBase::blockBuild().
+   * {@inheritdoc}
    */
   protected function blockBuild() {
-    return array(
-      drupal_set_page_content()
-    );
+    // @todo this lets the old way work transparently while we do new stuff.
+    if ($ret = drupal_set_page_content()) {
+      return array($ret);
+    }
+
+    return is_callable($this->controllerClosure) ? call_user_func($this->controllerClosure) : '';
+  }
+
+  /**
+   * Sets the controller closure that returns the block content.
+   *
+   * @param \Closure $closure
+   *   The closure/callable that provides the block content.
+   */
+  public function setControllerClosure(\Closure $closure) {
+    $this->controllerClosure = $closure;
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
index 847249e..4d13964 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -24,12 +24,16 @@
 class SystemMenuBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::access().
+   * {@inheritdoc}
    */
   public function access() {
     // @todo The 'Tools' menu should be available to anonymous users.
     list($plugin, $derivative) = explode(':', $this->getPluginId());
-    return ($GLOBALS['user']->uid || in_array($derivative, array('menu-main', 'menu-tools', 'menu-footer')));
+    return ($GLOBALS['user']->uid || in_array($derivative, array(
+      'menu-main',
+      'menu-tools',
+      'menu-footer')
+    ));
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
index 3969710..ec1a9cf 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
@@ -17,18 +17,22 @@
  * @Plugin(
  *   id = "system_powered_by_block",
  *   admin_label = @Translation("Powered by Drupal"),
+ *   has_native_access_logic = FALSE,
  *   module = "system"
  * )
  */
 class SystemPoweredByBlock extends BlockBase {
 
   /**
-   * Implements \Drupal\block\BlockBase::blockBuild().
+   * {@inheritdoc}
    */
   protected function blockBuild() {
-    return array(
-      '#children' => theme('system_powered_by'),
-    );
+    $powered_by = theme('system_powered_by');
+    if ($powered_by) {
+      return array(
+        '#children' => $powered_by,
+      );
+    }
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Asset/AssetAssemblyTest.php b/core/modules/system/lib/Drupal/system/Tests/Asset/AssetAssemblyTest.php
new file mode 100644
index 0000000..9c89370
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Asset/AssetAssemblyTest.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Asset\AssetAssemblyTest.
+ */
+
+namespace Drupal\system\Tests\Asset;
+
+use Drupal\Core\Asset\AssetBag;
+use Drupal\Core\Asset\AssetLibrary;
+use Drupal\Core\Asset\AssetLibraryManager;
+use Drupal\Core\Asset\AssetLibraryReference;
+use Drupal\Core\Asset\JavascriptFileAsset;
+use Drupal\Core\Asset\JavascriptStringAsset;
+use Drupal\Core\Asset\JavascriptExternalAsset;
+use Drupal\Core\Asset\StylesheetFileAsset;
+use Drupal\Core\Asset\StylesheetStringAsset;
+use Drupal\Core\Asset\StylesheetExternalAsset;
+
+use Drupal\simpletest\UnitTestBase;
+
+/**
+ * Provides a base class for Ajax tests.
+ */
+class AssetAssemblyTest extends UnitTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Asset Assembly tests',
+      'description' => 'Tests to ensure assets declared via the various possible approaches come out with the correct properties, in the proper order.',
+      'group' => 'Asset',
+    );
+  }
+
+  public function createJQueryAssetLibrary() {
+    $library = new AssetLibrary(array(new JavascriptFileAsset('core/misc/jquery.js')));
+    return $library->setTitle('jQuery')
+      ->setVersion('1.8.2')
+      ->setWebsite('http://jquery.com');
+  }
+
+  /**
+   * Tests various simple single-bag asset assembly scenarios.
+   *
+   * Much of the real complexity of asset ordering in AssetBags comes from
+   * nesting them, but these tests are focused on the basic mechanics of
+   * assembly within a single bag.
+   */
+  public function testSingleBagAssetAssemblies() {
+    // Dead-simple bag - contains just one css and one js assets, both local files.
+    $bag = new AssetBag();
+
+    $css1 = new StylesheetFileAsset(DRUPAL_ROOT . '/core/misc/vertical-tabs.css');
+    $js1 = new JavascriptFileAsset(DRUPAL_ROOT . '/core/misc/ajax.js');
+
+    $bag->add($css1);
+    $bag->add($js1);
+
+    $this->assertTrue($bag->hasCss(), 'AssetBag correctly reports that it contains CSS assets.');
+    $this->assertTrue($bag->hasJs(), 'AssetBag correctly reports that it contains javascript assets.');
+
+    $this->assertIdentical(array($css1), $bag->getUnsortedCss());
+    $this->assertIdentical(array($js1), $bag->getUnsortedJs());
+
+    $css2 = new StylesheetFileAsset(DRUPAL_ROOT . 'core/misc/dropbutton/dropbutton.base.css');
+    $bag->add($css2);
+
+    $this->assertIdentical(array($css1, $css2), $bag->getCss());
+
+    $this->assertIdentical(array($css1, $js1, $css2), $bag->all());
+  }
+
+  public function testSortingAndDependencyResolution() {
+    $bag = new AssetBag();
+
+    $alm = new AssetLibraryManager();
+    $alm->set('jquery', $this->createJQueryAssetLibrary());
+    $dep = new AssetLibraryReference('jquery', $alm);
+
+    $css1 = new StylesheetFileAsset(DRUPAL_ROOT . '/core/misc/vertical-tabs.css');
+    $js1 = new JavascriptFileAsset(DRUPAL_ROOT . '/core/misc/ajax.js');
+    // $js1->addDependency($dep);
+
+    $bag->add($css1);
+    $bag->add($js1);
+
+    $this->assertEqual(array(new JavascriptFileAsset('core/misc/jquery.js'), $js1), $bag->getJs());
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Page/HtmlFragmentWebTest.php b/core/modules/system/lib/Drupal/system/Tests/Page/HtmlFragmentWebTest.php
new file mode 100644
index 0000000..13995d6
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Page/HtmlFragmentWebTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Page\HtmlFragmentWebTest.
+ */
+
+namespace Drupal\system\Tests\Page;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Page\HtmlFragment;
+use Drupal\Core\EventSubscriber\HtmlViewSubscriber;
+use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\HttpKernel;
+
+class HtmlFragmentWebTest extends WebTestBase {
+
+  public static $modules = array('html_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'HTML fragment response',
+      'description' => 'Tests that HtmlFragment data is properly rendered into html.tpl.php.',
+      'group' => 'Page',
+    );
+  }
+
+  /**
+   * Tests that a HtmlFragment object is rendered correctly by issuing an
+   * HTTP request against it.
+   */
+  public function testHtmlFragmentOutputByWeb() {
+    $this->drupalGet('html_test');
+
+    // Check that our basic body text is there.
+    $this->assertRaw('hello world');
+    // Check that we didn't get a page within a page, inception-style.
+    $this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
+  }
+
+  /**
+   * Tests that a HtmlFragment object is rendered correctly by mocking the
+   * environment.
+   */
+  public function testPartialResponseByUnit() {
+    $kernel = $this->container->get('http_kernel');
+    $request = Request::create('/foo');
+    $response = new HtmlFragment('hello world');
+    $subscriber = new HtmlViewSubscriber($this->container->get('module_handler'));
+    $event = new GetResponseForControllerResultEvent($kernel, $request, HttpKernel::MASTER_REQUEST, $response);
+    $subscriber->onHtmlFragmentResponse($event);
+    $this->assertTrue(preg_match('/hello world/', $event->getResponse()->getContent()), 'Expected raw output found within HTML response.');
+  }
+}
diff --git a/core/modules/system/tests/modules/html_test/html_test.info.yml b/core/modules/system/tests/modules/html_test/html_test.info.yml
new file mode 100644
index 0000000..2edf26b
--- /dev/null
+++ b/core/modules/system/tests/modules/html_test/html_test.info.yml
@@ -0,0 +1,6 @@
+name: 'HTML test'
+description: 'Support module for testing finalized HTML rendering.'
+package: Testing
+version: VERSION
+core: 8.x
+hidden: true
diff --git a/core/modules/system/tests/modules/html_test/html_test.module b/core/modules/system/tests/modules/html_test/html_test.module
new file mode 100644
index 0000000..ea3dfb5
--- /dev/null
+++ b/core/modules/system/tests/modules/html_test/html_test.module
@@ -0,0 +1,4 @@
+<?php
+/**
+ * Empty file; only the controller is needed.
+ */
diff --git a/core/modules/system/tests/modules/html_test/html_test.routing.yml b/core/modules/system/tests/modules/html_test/html_test.routing.yml
new file mode 100644
index 0000000..62b11f9
--- /dev/null
+++ b/core/modules/system/tests/modules/html_test/html_test.routing.yml
@@ -0,0 +1,6 @@
+html_test_1:
+  pattern: '/html_test'
+  defaults:
+    _controller: '\Drupal\html_test\TestController::testHtmlFragmentOutput'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/html_test/lib/Drupal/html_test/TestController.php b/core/modules/system/tests/modules/html_test/lib/Drupal/html_test/TestController.php
new file mode 100644
index 0000000..101568f
--- /dev/null
+++ b/core/modules/system/tests/modules/html_test/lib/Drupal/html_test/TestController.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * @file
+ * Contains Drupal\html_test\TestControllers.
+ */
+
+namespace Drupal\html_test;
+
+use Drupal\Core\Page\HtmlFragment;
+
+/**
+ * Controller for testing partial HTML responses.
+ */
+class TestController {
+  public function testHtmlFragmentOutput() {
+    return new HtmlFragment('<p>hello world</p>');
+  }
+}
diff --git a/core/modules/tour/lib/Drupal/tour/Plugin/Block/TourTips.php b/core/modules/tour/lib/Drupal/tour/Plugin/Block/TourTips.php
new file mode 100755
index 0000000..8e2374d
--- /dev/null
+++ b/core/modules/tour/lib/Drupal/tour/Plugin/Block/TourTips.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\tour\Plugin\Block\TourTips.
+ */
+
+namespace Drupal\tour\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Asset\AssetBag;
+use Drupal\Core\Asset\StylesheetFileAsset;
+use Drupal\Core\Asset\JavascriptFileAsset;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Provides a tour tips block.
+ *
+ * @Plugin(
+ *   id = "tour_tips",
+ *   admin_label = @Translation("Tour tips"),
+ *   has_native_access_logic = FALSE,
+ *   module = "tour"
+ * )
+ */
+class TourTips extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssets() {
+    $bag = new AssetBag();
+
+    // CSS Assets.
+    $bag->add(new StylesheetFileAsset(DRUPAL_ROOT . '/core/modules/tour/css/joyride-2.0.3.css'));
+    $bag->add(new StylesheetFileAsset(DRUPAL_ROOT . '/core/modules/tour/css/tour-rtl.css'));
+    $bag->add(new StylesheetFileAsset(DRUPAL_ROOT . '/core/modules/tour/css/tour.css'));
+    
+    // JS Assets.
+    $bag->add(new JavascriptFileAsset(DRUPAL_ROOT . '/core/modules/tour/js/jquery.joyride-2.0.3.js'));
+    $bag->add(new JavascriptFileAsset(DRUPAL_ROOT . '/core/modules/tour/js/tour.js'));
+
+    return $bag;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockBuild() {
+    if (!user_access('access tour')) {
+      return;
+    }
+
+    // @todo replace this with http://drupal.org/node/1918768 once it is committed.
+    $path = current_path();
+    $tour_items = array();
+    // Load all of the items and match on path.
+    $tours = entity_load_multiple('tour');
+
+    $path_alias = drupal_strtolower(drupal_container()->get('path.alias_manager')->getPathAlias($path));
+    foreach ($tours as $tour_id => $tour) {
+      // @todo Replace this with an entity query that does path matching when
+      // http://drupal.org/node/1918768 lands.
+      $pages = implode("\n", $tour->getPaths());
+      if (!drupal_match_path($path_alias, $pages) && (($path == $path_alias) || drupal_match_path($path, $pages))) {
+        unset($tours[$tour_id]);
+      }
+    }
+
+    if ($tours) {
+      return entity_view_multiple($tours, 'full');
+    }
+  }
+
+}
diff --git a/core/modules/tour/lib/Drupal/tour/TourRenderController.php b/core/modules/tour/lib/Drupal/tour/TourRenderController.php
index e1bf15d..db24b4e 100644
--- a/core/modules/tour/lib/Drupal/tour/TourRenderController.php
+++ b/core/modules/tour/lib/Drupal/tour/TourRenderController.php
@@ -66,10 +66,6 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
         );
       }
     }
-    // If at least one tour was built, attach the tour library.
-    if ($build) {
-      $build['#attached']['library'][] = array('tour', 'tour');
-    }
     return $build;
   }
 
diff --git a/core/modules/tour/tour.module b/core/modules/tour/tour.module
index 8d96cfd..2df7406 100644
--- a/core/modules/tour/tour.module
+++ b/core/modules/tour/tour.module
@@ -21,7 +21,7 @@ function tour_permission() {
 /**
  * Implements hook_library_info().
  */
-function tour_library_info() {
+/*function tour_library_info() {
   $path = drupal_get_path('module', 'tour');
 
   $libraries['tour'] = array(
@@ -66,7 +66,7 @@ function tour_library_info() {
   );
 
   return $libraries;
-}
+}*/
 
 /**
  * Implements hook_toolbar().
@@ -103,35 +103,6 @@ function tour_toolbar() {
 }
 
 /**
- * Implements hook_preprocess_HOOK() for page.tpl.php.
- */
-function tour_preprocess_page(&$variables) {
-  if (!user_access('access tour')) {
-    return;
-  }
-
-  // @todo replace this with http://drupal.org/node/1918768 once it is committed.
-  $path = current_path();
-  $tour_items = array();
-  // Load all of the items and match on path.
-  $tours = entity_load_multiple('tour');
-
-  $path_alias = drupal_strtolower(drupal_container()->get('path.alias_manager')->getPathAlias($path));
-  foreach ($tours as $tour_id => $tour) {
-    // @todo Replace this with an entity query that does path matching when
-    // http://drupal.org/node/1918768 lands.
-    $pages = implode("\n", $tour->getPaths());
-    if (!drupal_match_path($path_alias, $pages) && (($path == $path_alias) || drupal_match_path($path, $pages))) {
-      unset($tours[$tour_id]);
-    }
-  }
-
-  if ($tours) {
-    $variables['page']['help']['tour'] = entity_view_multiple($tours, 'full');
-  }
-}
-
-/**
  * Implements hook_tour_insert().
  */
 function tour_tour_insert($entity) {
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
index 41c2a43..6539dff 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserNewBlock.php
@@ -23,7 +23,7 @@
 class UserNewBlock extends BlockBase {
 
   /**
-   * Overrides \Drupal\block\BlockBase::settings().
+   * {@inheritdoc}
    */
   public function settings() {
     return array(
@@ -35,14 +35,14 @@ public function settings() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::access().
+   * {@inheritdoc}
    */
   public function access() {
     return user_access('access content');
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockForm().
+   * {@inheritdoc}
    */
   public function blockForm($form, &$form_state) {
     $form['user_block_whois_new_count'] = array(
@@ -55,14 +55,14 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
   public function blockSubmit($form, &$form_state) {
     $this->configuration['whois_new_count'] = $form_state['values']['user_block_whois_new_count'];
   }
 
   /**
-   * Implements \Drupal\block\BlockBase::blockBuild().
+   * {@inheritdoc}
    */
   protected function blockBuild() {
     // Retrieve a list of new users who have accessed the site successfully.
@@ -74,7 +74,9 @@ protected function blockBuild() {
     foreach ($items as $account) {
       $build['#items'][] = theme('username', array('account' => $account));
     }
-    return $build;
+    if (!empty($build['#items'])) {
+      return $build;
+    }
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
index 5b82a7b..bccba3c 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
@@ -18,6 +18,7 @@
  *   id = "views_block",
  *   admin_label = @Translation("Views Block"),
  *   module = "views",
+ *   has_native_access_logic = FALSE,
  *   derivative = "Drupal\views\Plugin\Derivative\ViewsBlock"
  * )
  */
diff --git a/core/profiles/standard/config/block.block.bartik.account_links.yml b/core/profiles/standard/config/block.block.bartik.account_links.yml
new file mode 100644
index 0000000..681f4d0
--- /dev/null
+++ b/core/profiles/standard/config/block.block.bartik.account_links.yml
@@ -0,0 +1,13 @@
+id: bartik.account_links
+label: 'Account links'
+region: header
+weight: '0'
+module: menu
+status: '1'
+plugin: menu_navigation
+settings:
+  menu: account
+  level: '0'
+  id: secondary-menu
+  subject: 'Menu Navigation'
+langcode: und
diff --git a/core/profiles/standard/config/block.block.bartik.main_menu.yml b/core/profiles/standard/config/block.block.bartik.main_menu.yml
new file mode 100644
index 0000000..33295a0
--- /dev/null
+++ b/core/profiles/standard/config/block.block.bartik.main_menu.yml
@@ -0,0 +1,13 @@
+id: bartik.main_menu
+label: 'Main menu'
+region: header
+weight: '0'
+module: menu
+status: '1'
+plugin: menu_navigation
+settings:
+  menu: main
+  level: '0'
+  id: main-menu
+  subject: 'Menu Navigation'
+langcode: und
diff --git a/core/profiles/standard/config/block.block.bartik.tour_tips.yml b/core/profiles/standard/config/block.block.bartik.tour_tips.yml
new file mode 100644
index 0000000..c543c55
--- /dev/null
+++ b/core/profiles/standard/config/block.block.bartik.tour_tips.yml
@@ -0,0 +1,22 @@
+id: bartik.tour_tips
+weight: ''
+status: '1'
+langcode: en
+region: help
+plugin: tour_tips
+settings:
+  label: 'Tour tips'
+  module: tour
+  label_display: '0'
+  cache: '-1'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types:
+      article: '0'
+      page: '0'
+  visibility__active_tab: edit-visibility-path
\ No newline at end of file
diff --git a/core/profiles/standard/config/block.block.seven.tour_tips.yml b/core/profiles/standard/config/block.block.seven.tour_tips.yml
new file mode 100644
index 0000000..851b588
--- /dev/null
+++ b/core/profiles/standard/config/block.block.seven.tour_tips.yml
@@ -0,0 +1,22 @@
+id: seven.tour_tips
+weight: ''
+status: '1'
+langcode: en
+region: help
+plugin: tour_tips
+settings:
+  label: 'Tour tips'
+  module: tour
+  label_display: '0'
+  cache: '-1'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types:
+      article: '0'
+      page: '0'
+  visibility__active_tab: edit-visibility-path
\ No newline at end of file
diff --git a/core/profiles/standard/config/display.bound.frontend.yml b/core/profiles/standard/config/display.bound.frontend.yml
new file mode 100644
index 0000000..a7cfac8
--- /dev/null
+++ b/core/profiles/standard/config/display.bound.frontend.yml
@@ -0,0 +1,211 @@
+id: frontend
+label: Frontend master display
+layout: static_layout:layout__core
+layoutSettings: { }
+blockInfo:
+# these have bartik in their namespace, but that's irrelevant to our use here -
+# we're just reusing them while we get everything together.
+  block.block.bartik.help:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '0'
+  block.block.bartik.content:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '0'
+    group: main-article
+  block.block.bartik.footer:
+    region: footer
+    region-type: footer
+    strategy: inline_block
+    weight: '0'
+  block.block.bartik.powered:
+    region: footer
+    region-type: footer
+    strategy: inline_block
+    weight: '10'
+    group: footer-container
+  block.block.bartik.search:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '0'
+    group: sidebar-first
+  block.block.bartik.login:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '-10'
+    group: sidebar-first
+  block.block.bartik.tools:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '-20'
+  block.block.bartik.main_menu:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '-10'
+  block.block.bartik.account_links:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '-10'
+  page_actions1:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '-15'
+    embedded: '1'
+  page_breadcrumb1:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '0'
+    embedded: '1'
+  page_messages1:
+    region: main
+    region-type: main
+    strategy: inline_block
+    weight: '0'
+    embedded: '1'
+  page_site_name1:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '2'
+    embedded: '1'
+    group: siteinfo
+  page_site_logo1:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '1'
+    embedded: '1'
+    group: siteinfo
+  page_site_slogan1:
+    region: header
+    region-type: header
+    strategy: inline_block
+    weight: '0'
+    embedded: '1'
+    group: siteinfo
+embeddedBlockConfigs:
+  page_actions1:
+    id: page_actions1
+    plugin: page_actions
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      id: secondary-menu
+      subject: 'Menu Navigation'
+      semantics: nav
+  page_breadcrumb1:
+    id: page_breadcrumb1
+    plugin: page_breadcrumb
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      subject: ''
+      semantics: nav
+      classes:
+        - l-s-full
+  page_messages1:
+    id: page_messages1
+    plugin: page_messages
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      subject: ''
+      semantics: div
+  page_site_logo1:
+    id: page_site_logo1
+    plugin: page_site_logo
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      subject: ''
+      semantics: span
+      classes:
+        - l-s-full
+        - l-m-1-6
+        - l-l-1-8
+        - l-xl-2-12
+        - l-xxl-2-16
+  page_site_name1:
+    id: page_site_name1
+    plugin: page_site_name
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      subject: ''
+      semantics: header
+      classes:
+        - l-s-full
+        - l-m-4-6
+        - l-m-omega
+        - l-l-2-8
+        - l-xl-4-12
+        - l-xxl-4-16
+  page_site_slogan1:
+    id: page_site_slogan1
+    plugin: page_site_slogan
+    label: ''
+    label_display: visible
+    module: block
+    status: '1'
+    settings:
+      subject: ''
+      semantics: span
+groups:
+  siteinfo:
+    region: header
+    weight: '-5'
+    semantics: div
+    classes:
+      - l-container
+      - l-clearfix
+  main-article:
+    region: main
+    weight: '-1'
+    semantics: article
+    classes:
+      - l-s-full
+      - l-m-4-6
+      - l-l-5-8
+      - l-xl-8-12
+      - l-xxl-10-16
+  sidebar-first:
+    region: main
+    weight: '0'
+    semantics: aside
+    classes:
+      - l-s-full
+      - l-m-2-6
+      - l-m-omega
+      - l-l-3-8
+      - l-l-omega
+      - l-xl-4-12
+      - l-xl-omega
+      - l-xxl-6-16
+      - l-xxl-omega
+  footer-container:
+    region: footer
+    weight: '-5'
+    semantics: div
+    classes:
+      - l-container
+      - l-clearfix
\ No newline at end of file
diff --git a/core/profiles/standard/standard.info.yml b/core/profiles/standard/standard.info.yml
index 2dfadbb..ef5b752 100644
--- a/core/profiles/standard/standard.info.yml
+++ b/core/profiles/standard/standard.info.yml
@@ -36,3 +36,4 @@ dependencies:
   - views
   - views_ui
   - tour
+  - booze_test
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 741f857..40335c1 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -23,6 +23,8 @@ function standard_install() {
 
   // Set front page to "node".
   config('system.site')->set('page.front', 'node')->save();
+  // Set default layout to Bartik's frontend layout.
+  config('system.site')->set('default_layout', 'static_layout:bartik__frontend');
 
   // Insert default pre-defined node types into the database. For a complete
   // list of available node type attributes, refer to the node type API
diff --git a/core/themes/bartik/bartik.classes.yml b/core/themes/bartik/bartik.classes.yml
new file mode 100644
index 0000000..ffcf11c
--- /dev/null
+++ b/core/themes/bartik/bartik.classes.yml
@@ -0,0 +1,280 @@
+# The groupings are arbitrary, so system should be flexible enough to accept any groupings.
+# Keys should be classes added, values are description
+# Following SMACSS here.
+layout-general:
+  name: 'General layout'
+  description: 'Classes relevant across multiple grids'
+  classes:
+    l-container: 'Container, max-width 1290px'
+
+layout-small:
+  name: 'Small grid'
+  description: '4 column grid, active until 499px'
+  classes:
+    l-s-full: 'Span full width'
+    l-s-alpha: 'First item in a row'
+    l-s-omega: 'Last item in a row'
+    l-s-1-4: 'Span one of four columns'
+    l-s-2-4: 'Span two of four columns'
+    l-s-3-4: 'Span three of four columns'
+
+layout-medium:
+  name: 'Medium grid'
+  description: '6 column grid, active at 500px'
+  classes:
+    l-m-full: 'Span full width'
+    l-m-alpha: 'First item in a row'
+    l-m-omega: 'Last item in a row'
+    l-m-1-6: 'Span 1 of 6 columns'
+    l-m-2-6: 'Span 2 of 6 columns'
+    l-m-3-6: 'Span 3 of 6 columns'
+    l-m-4-6: 'Span 4 of 6 columns'
+    l-m-5-6: 'Span 5 of 6 columns'
+    l-m-1-2: 'Span 1 of 2 columns'
+    l-m-1-3: 'Span 1 of 3 columns'
+    l-m-2-3: 'Span 2 of 3 columns'
+    l-m-1-4: 'Span 1 of 4 columns'
+    l-m-2-4: 'Span 2 of 4 columns'
+    l-m-3-4: 'Span 3 of 4 columns'
+    l-m-1-5: 'Span 1 of 5 columns'
+    l-m-2-5: 'Span 2 of 5 columns'
+    l-m-3-5: 'Span 3 of 5 columns'
+    l-m-4-5: 'Span 4 of 5 columns'
+
+layout-large:
+  name: 'Large grid'
+  description: '8 column grid, active at 700px'
+  classes:
+    l-l-full: 'Span full width'
+    l-l-alpha: 'First item in a row'
+    l-l-omega: 'Last item in a row'
+    l-l-1-8: 'Span 1 of 8 columns'
+    l-l-2-8: 'Span 2 of 8 columns'
+    l-l-3-8: 'Span 3 of 8 columns'
+    l-l-4-8: 'Span 4 of 8 columns'
+    l-l-5-8: 'Span 5 of 8 columns'
+    l-l-6-8: 'Span 6 of 8 columns'
+    l-l-7-8: 'Span 7 of 8 columns'
+    l-l-1-2: 'Span 1 of 2 columns'
+    l-l-1-3: 'Span 1 of 3 columns'
+    l-l-2-3: 'Span 2 of 3 columns'
+    l-l-1-4: 'Span 1 of 4 columns'
+    l-l-2-4: 'Span 2 of 4 columns'
+    l-l-3-4: 'Span 3 of 4 columns'
+    l-l-1-5: 'Span 1 of 5 columns'
+    l-l-2-5: 'Span 2 of 5 columns'
+    l-l-3-5: 'Span 3 of 5 columns'
+    l-l-4-5: 'Span 4 of 5 columns'
+    l-l-1-6: 'Span 1 of 6 columns'
+    l-l-2-6: 'Span 2 of 6 columns'
+    l-l-3-6: 'Span 3 of 6 columns'
+    l-l-4-6: 'Span 4 of 6 columns'
+    l-l-5-6: 'Span 5 of 6 columns'
+    l-l-1-7: 'Span 1 of 7 columns'
+    l-l-2-7: 'Span 2 of 7 columns'
+    l-l-3-7: 'Span 3 of 7 columns'
+    l-l-4-7: 'Span 4 of 7 columns'
+    l-l-5-7: 'Span 5 of 7 columns'
+    l-l-6-7: 'Span 6 of 7 columns'
+
+layout-extra-large:
+  name: 'Extra Large grid'
+  description: '12 column grid, active at 900px'
+  classes:
+    l-xl-full: 'Span full width'
+    l-xl-alpha: 'First item in a row'
+    l-xl-omega: 'Last item in a row'
+    l-xl-1-12: 'Span 1 of 12 columns'
+    l-xl-2-12: 'Span 2 of 12 columns'
+    l-xl-3-12: 'Span 3 of 12 columns'
+    l-xl-4-12: 'Span 4 of 12 columns'
+    l-xl-5-12: 'Span 5 of 12 columns'
+    l-xl-6-12: 'Span 6 of 12 columns'
+    l-xl-7-12: 'Span 7 of 12 columns'
+    l-xl-8-12: 'Span 8 of 12 columns'
+    l-xl-9-12: 'Span 9 of 12 columns'
+    l-xl-10-12: 'Span 10 of 12 columns'
+    l-xl-11-12: 'Span 11 of 12 columns'
+    l-xl-1-2: 'Span 1 of 2 columns'
+    l-xl-1-3: 'Span 1 of 3 columns'
+    l-xl-2-3: 'Span 2 of 3 columns'
+    l-xl-1-4: 'Span 1 of 4 columns'
+    l-xl-2-4: 'Span 2 of 4 columns'
+    l-xl-3-4: 'Span 3 of 4 columns'
+    l-xl-1-5: 'Span 1 of 5 columns'
+    l-xl-2-5: 'Span 2 of 5 columns'
+    l-xl-3-5: 'Span 3 of 5 columns'
+    l-xl-4-5: 'Span 4 of 5 columns'
+    l-xl-1-6: 'Span 1 of 6 columns'
+    l-xl-2-6: 'Span 2 of 6 columns'
+    l-xl-3-6: 'Span 3 of 6 columns'
+    l-xl-4-6: 'Span 4 of 6 columns'
+    l-xl-5-6: 'Span 5 of 6 columns'
+    l-xl-1-7: 'Span 1 of 7 columns'
+    l-xl-2-7: 'Span 2 of 7 columns'
+    l-xl-3-7: 'Span 3 of 7 columns'
+    l-xl-4-7: 'Span 4 of 7 columns'
+    l-xl-5-7: 'Span 5 of 7 columns'
+    l-xl-6-7: 'Span 6 of 7 columns'
+    l-xl-1-8: 'Span 1 of 8 columns'
+    l-xl-2-8: 'Span 2 of 8 columns'
+    l-xl-3-8: 'Span 3 of 8 columns'
+    l-xl-4-8: 'Span 4 of 8 columns'
+    l-xl-5-8: 'Span 5 of 8 columns'
+    l-xl-6-8: 'Span 6 of 8 columns'
+    l-xl-7-8: 'Span 7 of 8 columns'
+    l-xl-1-9: 'Span 1 of 9 columns'
+    l-xl-2-9: 'Span 2 of 9 columns'
+    l-xl-3-9: 'Span 3 of 9 columns'
+    l-xl-4-9: 'Span 4 of 9 columns'
+    l-xl-5-9: 'Span 5 of 9 columns'
+    l-xl-6-9: 'Span 6 of 9 columns'
+    l-xl-7-9: 'Span 7 of 9 columns'
+    l-xl-8-9: 'Span 8 of 9 columns'
+    l-xl-1-10: 'Span 1 of 10 columns'
+    l-xl-2-10: 'Span 2 of 10 columns'
+    l-xl-3-10: 'Span 3 of 10 columns'
+    l-xl-4-10: 'Span 4 of 10 columns'
+    l-xl-5-10: 'Span 5 of 10 columns'
+    l-xl-6-10: 'Span 6 of 10 columns'
+    l-xl-7-10: 'Span 7 of 10 columns'
+    l-xl-8-10: 'Span 8 of 10 columns'
+    l-xl-9-10: 'Span 9 of 10 columns'
+    l-xl-10-11: 'Span 10 of 11 columns'
+    l-xl-2-11: 'Span 2 of 11 columns'
+    l-xl-3-11: 'Span 3 of 11 columns'
+    l-xl-4-11: 'Span 4 of 11 columns'
+    l-xl-5-11: 'Span 5 of 11 columns'
+    l-xl-6-11: 'Span 6 of 11 columns'
+    l-xl-7-11: 'Span 7 of 11 columns'
+    l-xl-8-11: 'Span 8 of 11 columns'
+    l-xl-9-11: 'Span 9 of 11 columns'
+    l-xl-10-11: 'Span 10 of 11 columns'
+
+layout-extra-extra-large:
+  name: 'Extra Extra Large grid'
+  description: '16 column grid, active at 1100px'
+  classes:
+    l-xxl-full: 'Span full width'
+    l-xxl-alpha: 'First item in a row'
+    l-xxl-omega: 'Last item in a row'
+    l-xxl-1-16: 'Span 1 of 16 columns'
+    l-xxl-2-16: 'Span 2 of 16 columns'
+    l-xxl-3-16: 'Span 3 of 16 columns'
+    l-xxl-4-16: 'Span 4 of 16 columns'
+    l-xxl-5-16: 'Span 5 of 16 columns'
+    l-xxl-6-16: 'Span 6 of 16 columns'
+    l-xxl-7-16: 'Span 7 of 16 columns'
+    l-xxl-8-16: 'Span 8 of 16 columns'
+    l-xxl-9-16: 'Span 9 of 16 columns'
+    l-xxl-10-16: 'Span 10 of 16 columns'
+    l-xxl-11-16: 'Span 11 of 16 columns'
+    l-xxl-12-16: 'Span 12 of 16 columns'
+    l-xxl-13-16: 'Span 13 of 16 columns'
+    l-xxl-14-16: 'Span 14 of 16 columns'
+    l-xxl-15-16: 'Span 15 of 16 columns'
+    l-xxl-1-2: 'Span 1 of 2 columns'
+    l-xxl-1-3: 'Span 1 of 3 columns'
+    l-xxl-2-3: 'Span 2 of 3 columns'
+    l-xxl-1-4: 'Span 1 of 4 columns'
+    l-xxl-2-4: 'Span 2 of 4 columns'
+    l-xxl-3-4: 'Span 3 of 4 columns'
+    l-xxl-1-5: 'Span 1 of 5 columns'
+    l-xxl-2-5: 'Span 2 of 5 columns'
+    l-xxl-3-5: 'Span 3 of 5 columns'
+    l-xxl-4-5: 'Span 4 of 5 columns'
+    l-xxl-1-6: 'Span 1 of 6 columns'
+    l-xxl-2-6: 'Span 2 of 6 columns'
+    l-xxl-3-6: 'Span 3 of 6 columns'
+    l-xxl-4-6: 'Span 4 of 6 columns'
+    l-xxl-5-6: 'Span 5 of 6 columns'
+    l-xxl-1-7: 'Span 1 of 7 columns'
+    l-xxl-2-7: 'Span 2 of 7 columns'
+    l-xxl-3-7: 'Span 3 of 7 columns'
+    l-xxl-4-7: 'Span 4 of 7 columns'
+    l-xxl-5-7: 'Span 5 of 7 columns'
+    l-xxl-6-7: 'Span 6 of 7 columns'
+    l-xxl-1-8: 'Span 1 of 8 columns'
+    l-xxl-2-8: 'Span 2 of 8 columns'
+    l-xxl-3-8: 'Span 3 of 8 columns'
+    l-xxl-4-8: 'Span 4 of 8 columns'
+    l-xxl-5-8: 'Span 5 of 8 columns'
+    l-xxl-6-8: 'Span 6 of 8 columns'
+    l-xxl-7-8: 'Span 7 of 8 columns'
+    l-xxl-1-9: 'Span 1 of 9 columns'
+    l-xxl-2-9: 'Span 2 of 9 columns'
+    l-xxl-3-9: 'Span 3 of 9 columns'
+    l-xxl-4-9: 'Span 4 of 9 columns'
+    l-xxl-5-9: 'Span 5 of 9 columns'
+    l-xxl-6-9: 'Span 6 of 9 columns'
+    l-xxl-7-9: 'Span 7 of 9 columns'
+    l-xxl-8-9: 'Span 8 of 9 columns'
+    l-xxl-1-10: 'Span 1 of 10 columns'
+    l-xxl-2-10: 'Span 2 of 10 columns'
+    l-xxl-3-10: 'Span 3 of 10 columns'
+    l-xxl-4-10: 'Span 4 of 10 columns'
+    l-xxl-5-10: 'Span 5 of 10 columns'
+    l-xxl-6-10: 'Span 6 of 10 columns'
+    l-xxl-7-10: 'Span 7 of 10 columns'
+    l-xxl-8-10: 'Span 8 of 10 columns'
+    l-xxl-9-10: 'Span 9 of 10 columns'
+    l-xxl-10-11: 'Span 10 of 11 columns'
+    l-xxl-2-11: 'Span 2 of 11 columns'
+    l-xxl-3-11: 'Span 3 of 11 columns'
+    l-xxl-4-11: 'Span 4 of 11 columns'
+    l-xxl-5-11: 'Span 5 of 11 columns'
+    l-xxl-6-11: 'Span 6 of 11 columns'
+    l-xxl-7-11: 'Span 7 of 11 columns'
+    l-xxl-8-11: 'Span 8 of 11 columns'
+    l-xxl-9-11: 'Span 9 of 11 columns'
+    l-xxl-10-11: 'Span 10 of 11 columns'
+    l-xxl-1-12: 'Span 1 of 12 columns'
+    l-xxl-2-12: 'Span 2 of 12 columns'
+    l-xxl-3-12: 'Span 3 of 12 columns'
+    l-xxl-4-12: 'Span 4 of 12 columns'
+    l-xxl-5-12: 'Span 5 of 12 columns'
+    l-xxl-6-12: 'Span 6 of 12 columns'
+    l-xxl-7-12: 'Span 7 of 12 columns'
+    l-xxl-8-12: 'Span 8 of 12 columns'
+    l-xxl-9-12: 'Span 9 of 12 columns'
+    l-xxl-10-12: 'Span 10 of 12 columns'
+    l-xxl-11-12: 'Span 11 of 12 columns'
+    l-xxl-1-13: 'Span 1 of 13 columns'
+    l-xxl-2-13: 'Span 2 of 13 columns'
+    l-xxl-3-13: 'Span 3 of 13 columns'
+    l-xxl-4-13: 'Span 4 of 13 columns'
+    l-xxl-5-13: 'Span 5 of 13 columns'
+    l-xxl-6-13: 'Span 6 of 13 columns'
+    l-xxl-7-13: 'Span 7 of 13 columns'
+    l-xxl-8-13: 'Span 8 of 13 columns'
+    l-xxl-9-13: 'Span 9 of 13 columns'
+    l-xxl-10-13: 'Span 10 of 13 columns'
+    l-xxl-11-13: 'Span 11 of 13 columns'
+    l-xxl-12-13: 'Span 12 of 13 columns'
+    l-xxl-1-14: 'Span 1 of 14 columns'
+    l-xxl-2-14: 'Span 2 of 14 columns'
+    l-xxl-3-14: 'Span 3 of 14 columns'
+    l-xxl-4-14: 'Span 4 of 14 columns'
+    l-xxl-5-14: 'Span 5 of 14 columns'
+    l-xxl-6-14: 'Span 6 of 14 columns'
+    l-xxl-7-14: 'Span 7 of 14 columns'
+    l-xxl-8-14: 'Span 8 of 14 columns'
+    l-xxl-9-14: 'Span 9 of 14 columns'
+    l-xxl-10-14: 'Span 10 of 14 columns'
+    l-xxl-11-14: 'Span 11 of 14 columns'
+    l-xxl-12-14: 'Span 12 of 14 columns'
+    l-xxl-13-14: 'Span 13 of 14 columns'
+    l-xxl-1-15: 'Span 1 of 15 columns'
+    l-xxl-2-15: 'Span 2 of 15 columns'
+    l-xxl-3-15: 'Span 3 of 15 columns'
+    l-xxl-4-15: 'Span 4 of 15 columns'
+    l-xxl-5-15: 'Span 5 of 15 columns'
+    l-xxl-6-15: 'Span 6 of 15 columns'
+    l-xxl-7-15: 'Span 7 of 15 columns'
+    l-xxl-8-15: 'Span 8 of 15 columns'
+    l-xxl-9-15: 'Span 9 of 15 columns'
+    l-xxl-10-15: 'Span 10 of 15 columns'
+    l-xxl-11-15: 'Span 11 of 15 columns'
+    l-xxl-12-15: 'Span 12 of 15 columns'
+    l-xxl-13-15: 'Span 13 of 15 columns'
+    l-xxl-14-15: 'Span 14 of 15 columns'
\ No newline at end of file
diff --git a/core/themes/bartik/bartik.info.yml b/core/themes/bartik/bartik.info.yml
index 43e3e9c..f25a07c 100644
--- a/core/themes/bartik/bartik.info.yml
+++ b/core/themes/bartik/bartik.info.yml
@@ -7,8 +7,10 @@ core: 8.x
 stylesheets:
   all:
     - css/layout.css
+    - css/layout.grid.css
     - css/style.css
     - css/colors.css
+    - css/modules.css
   print:
     - css/print.css
 regions:
diff --git a/core/themes/bartik/css/layout.grid.css b/core/themes/bartik/css/layout.grid.css
new file mode 100644
index 0000000..cc0dab9
--- /dev/null
+++ b/core/themes/bartik/css/layout.grid.css
@@ -0,0 +1,1169 @@
+.l-container:after, main:after, body > header:after,
+body > footer:after {
+  content: "";
+  display: table;
+  clear: both;
+}
+
+[class*="l-s-"], [class*="l-m-"], [class*="l-l-"], [class*="l-xl-"], [class*="l-xxl-"] {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+.l-container:after, main:after, body > header:after,
+body > footer:after {
+  content: "";
+  display: table;
+  clear: both;
+}
+
+/* Small (4 Column) Grid */
+[class*="l-s-"] {
+  float: left;
+  clear: right;
+  margin-right: 5.26316%;
+}
+[dir="rtl"] [class*="l-s-"] {
+  float: right;
+  clear: left;
+}
+[dir="rtl"] [class*="l-s-"] {
+  margin-left: 5.26316%;
+}
+
+.l-s-full {
+  width: 100%;
+  float: left;
+  clear: both;
+}
+[dir="rtl"] .l-s-full {
+  float: right;
+}
+
+.l-s-alpha {
+  clear: both;
+}
+
+.l-s-omega {
+  float: right;
+  margin-right: 0;
+}
+[dir="rtl"] .l-s-omega {
+  float: left;
+  margin-left: 0;
+}
+
+.l-s-1-4 {
+  width: 21.05263%;
+}
+
+.l-s-2-4 {
+  width: 47.36842%;
+}
+
+.l-s-1-2 {
+  width: 44.44444%;
+}
+
+.l-s-3-4 {
+  width: 73.68421%;
+}
+
+.l-s-1-3 {
+  width: 28.57143%;
+}
+
+.l-s-2-3 {
+  width: 64.28571%;
+}
+
+/* Medium (6 Column) Grid */
+/* Begins at 500px */
+[class*="l-m-"] {
+  float: left;
+  clear: right;
+}
+[dir="rtl"] [class*="l-m-"] {
+  float: right;
+  clear: left;
+}
+@media (min-width: 31.25em) {
+  [class*="l-m-"] {
+    margin-right: 3.44828%;
+  }
+  [dir="rtl"] [class*="l-m-"] {
+    margin-left: 3.44828%;
+  }
+}
+
+@media (min-width: 31.25em) {
+  .l-m-full {
+    width: 100%;
+    float: left;
+    clear: both;
+  }
+  [dir="rtl"] .l-m-full {
+    float: right;
+  }
+
+  .l-m-alpha {
+    clear: both;
+  }
+
+  .l-m-omega {
+    float: right;
+    margin-right: 0;
+  }
+  [dir="rtl"] .l-m-omega {
+    float: left;
+    margin-left: 0;
+  }
+
+  .l-m-1-6 {
+    width: 13.7931%;
+  }
+
+  .l-m-2-6 {
+    width: 31.03448%;
+  }
+
+  .l-m-1-2 {
+    width: 44.44444%;
+  }
+
+  .l-m-3-6 {
+    width: 48.27586%;
+  }
+
+  .l-m-1-3 {
+    width: 28.57143%;
+  }
+
+  .l-m-2-3 {
+    width: 64.28571%;
+  }
+
+  .l-m-4-6 {
+    width: 65.51724%;
+  }
+
+  .l-m-1-4 {
+    width: 21.05263%;
+  }
+
+  .l-m-2-4 {
+    width: 47.36842%;
+  }
+
+  .l-m-3-4 {
+    width: 73.68421%;
+  }
+
+  .l-m-5-6 {
+    width: 82.75862%;
+  }
+
+  .l-m-1-5 {
+    width: 16.66667%;
+  }
+
+  .l-m-2-5 {
+    width: 37.5%;
+  }
+
+  .l-m-3-5 {
+    width: 58.33333%;
+  }
+
+  .l-m-4-5 {
+    width: 79.16667%;
+  }
+}
+/* Large (8 Column) Grid */
+/* Begins at 700px */
+[class*="l-l-"] {
+  float: left;
+  clear: right;
+}
+[dir="rtl"] [class*="l-l-"] {
+  float: right;
+  clear: left;
+}
+@media (min-width: 43.75em) {
+  [class*="l-l-"] {
+    margin-right: 2.5641%;
+  }
+  [dir="rtl"] [class*="l-l-"] {
+    margin-left: 2.5641%;
+  }
+}
+
+@media (min-width: 43.75em) {
+  .l-l-full {
+    width: 100%;
+    float: left;
+    clear: both;
+  }
+  [dir="rtl"] .l-l-full {
+    float: right;
+  }
+
+  .l-l-alpha {
+    clear: both;
+  }
+
+  .l-l-omega {
+    float: right;
+    margin-right: 0;
+  }
+  [dir="rtl"] .l-l-omega {
+    float: left;
+    margin-left: 0;
+  }
+
+  .l-l-1-8 {
+    width: 10.25641%;
+  }
+
+  .l-l-2-8 {
+    width: 23.07692%;
+  }
+
+  .l-l-1-2 {
+    width: 44.44444%;
+  }
+
+  .l-l-3-8 {
+    width: 35.89744%;
+  }
+
+  .l-l-1-3 {
+    width: 28.57143%;
+  }
+
+  .l-l-2-3 {
+    width: 64.28571%;
+  }
+
+  .l-l-4-8 {
+    width: 48.71795%;
+  }
+
+  .l-l-1-4 {
+    width: 21.05263%;
+  }
+
+  .l-l-2-4 {
+    width: 47.36842%;
+  }
+
+  .l-l-3-4 {
+    width: 73.68421%;
+  }
+
+  .l-l-5-8 {
+    width: 61.53846%;
+  }
+
+  .l-l-1-5 {
+    width: 16.66667%;
+  }
+
+  .l-l-2-5 {
+    width: 37.5%;
+  }
+
+  .l-l-3-5 {
+    width: 58.33333%;
+  }
+
+  .l-l-4-5 {
+    width: 79.16667%;
+  }
+
+  .l-l-6-8 {
+    width: 74.35897%;
+  }
+
+  .l-l-1-6 {
+    width: 13.7931%;
+  }
+
+  .l-l-2-6 {
+    width: 31.03448%;
+  }
+
+  .l-l-3-6 {
+    width: 48.27586%;
+  }
+
+  .l-l-4-6 {
+    width: 65.51724%;
+  }
+
+  .l-l-5-6 {
+    width: 82.75862%;
+  }
+
+  .l-l-7-8 {
+    width: 87.17949%;
+  }
+
+  .l-l-1-7 {
+    width: 11.76471%;
+  }
+
+  .l-l-2-7 {
+    width: 26.47059%;
+  }
+
+  .l-l-3-7 {
+    width: 41.17647%;
+  }
+
+  .l-l-4-7 {
+    width: 55.88235%;
+  }
+
+  .l-l-5-7 {
+    width: 70.58824%;
+  }
+
+  .l-l-6-7 {
+    width: 85.29412%;
+  }
+}
+/* Extra Large (12 Column) Grid */
+/* Begins at 900px */
+[class*="l-xl-"] {
+  float: left;
+  clear: right;
+}
+[dir="rtl"] [class*="l-xl-"] {
+  float: right;
+  clear: left;
+}
+@media (min-width: 56.25em) {
+  [class*="l-xl-"] {
+    margin-right: 2.12766%;
+  }
+  [dir="rtl"] [class*="l-xl-"] {
+    margin-left: 2.12766%;
+  }
+}
+
+@media (min-width: 56.25em) {
+  .l-xl-full {
+    width: 100%;
+    float: left;
+    clear: both;
+  }
+  [dir="rtl"] .l-xl-full {
+    float: right;
+  }
+
+  .l-xl-alpha {
+    clear: both;
+  }
+
+  .l-xl-omega {
+    float: right;
+    margin-right: 0;
+  }
+  [dir="rtl"] .l-xl-omega {
+    float: left;
+    margin-left: 0;
+  }
+
+  .l-xl-1-12 {
+    width: 6.38298%;
+  }
+
+  .l-xl-2-12 {
+    width: 14.89362%;
+  }
+
+  .l-xl-1-2 {
+    width: 42.85714%;
+  }
+
+  .l-xl-3-12 {
+    width: 23.40426%;
+  }
+
+  .l-xl-1-3 {
+    width: 27.27273%;
+  }
+
+  .l-xl-2-3 {
+    width: 63.63636%;
+  }
+
+  .l-xl-4-12 {
+    width: 31.91489%;
+  }
+
+  .l-xl-1-4 {
+    width: 20%;
+  }
+
+  .l-xl-2-4 {
+    width: 46.66667%;
+  }
+
+  .l-xl-3-4 {
+    width: 73.33333%;
+  }
+
+  .l-xl-5-12 {
+    width: 40.42553%;
+  }
+
+  .l-xl-1-5 {
+    width: 15.78947%;
+  }
+
+  .l-xl-2-5 {
+    width: 36.84211%;
+  }
+
+  .l-xl-3-5 {
+    width: 57.89474%;
+  }
+
+  .l-xl-4-5 {
+    width: 78.94737%;
+  }
+
+  .l-xl-6-12 {
+    width: 48.93617%;
+  }
+
+  .l-xl-1-6 {
+    width: 13.04348%;
+  }
+
+  .l-xl-2-6 {
+    width: 30.43478%;
+  }
+
+  .l-xl-3-6 {
+    width: 47.82609%;
+  }
+
+  .l-xl-4-6 {
+    width: 65.21739%;
+  }
+
+  .l-xl-5-6 {
+    width: 82.6087%;
+  }
+
+  .l-xl-7-12 {
+    width: 57.44681%;
+  }
+
+  .l-xl-1-7 {
+    width: 11.11111%;
+  }
+
+  .l-xl-2-7 {
+    width: 25.92593%;
+  }
+
+  .l-xl-3-7 {
+    width: 40.74074%;
+  }
+
+  .l-xl-4-7 {
+    width: 55.55556%;
+  }
+
+  .l-xl-5-7 {
+    width: 70.37037%;
+  }
+
+  .l-xl-6-7 {
+    width: 85.18519%;
+  }
+
+  .l-xl-8-12 {
+    width: 65.95745%;
+  }
+
+  .l-xl-1-8 {
+    width: 9.67742%;
+  }
+
+  .l-xl-2-8 {
+    width: 22.58065%;
+  }
+
+  .l-xl-3-8 {
+    width: 35.48387%;
+  }
+
+  .l-xl-4-8 {
+    width: 48.3871%;
+  }
+
+  .l-xl-5-8 {
+    width: 61.29032%;
+  }
+
+  .l-xl-6-8 {
+    width: 74.19355%;
+  }
+
+  .l-xl-7-8 {
+    width: 87.09677%;
+  }
+
+  .l-xl-9-12 {
+    width: 74.46809%;
+  }
+
+  .l-xl-1-9 {
+    width: 8.57143%;
+  }
+
+  .l-xl-2-9 {
+    width: 20%;
+  }
+
+  .l-xl-3-9 {
+    width: 31.42857%;
+  }
+
+  .l-xl-4-9 {
+    width: 42.85714%;
+  }
+
+  .l-xl-5-9 {
+    width: 54.28571%;
+  }
+
+  .l-xl-6-9 {
+    width: 65.71429%;
+  }
+
+  .l-xl-7-9 {
+    width: 77.14286%;
+  }
+
+  .l-xl-8-9 {
+    width: 88.57143%;
+  }
+
+  .l-xl-10-12 {
+    width: 82.97872%;
+  }
+
+  .l-xl-1-10 {
+    width: 7.69231%;
+  }
+
+  .l-xl-2-10 {
+    width: 17.94872%;
+  }
+
+  .l-xl-3-10 {
+    width: 28.20513%;
+  }
+
+  .l-xl-4-10 {
+    width: 38.46154%;
+  }
+
+  .l-xl-5-10 {
+    width: 48.71795%;
+  }
+
+  .l-xl-6-10 {
+    width: 58.97436%;
+  }
+
+  .l-xl-7-10 {
+    width: 69.23077%;
+  }
+
+  .l-xl-8-10 {
+    width: 79.48718%;
+  }
+
+  .l-xl-9-10 {
+    width: 89.74359%;
+  }
+
+  .l-xl-11-12 {
+    width: 91.48936%;
+  }
+
+  .l-xl-1-11 {
+    width: 6.97674%;
+  }
+
+  .l-xl-2-11 {
+    width: 16.27907%;
+  }
+
+  .l-xl-3-11 {
+    width: 25.5814%;
+  }
+
+  .l-xl-4-11 {
+    width: 34.88372%;
+  }
+
+  .l-xl-5-11 {
+    width: 44.18605%;
+  }
+
+  .l-xl-6-11 {
+    width: 53.48837%;
+  }
+
+  .l-xl-7-11 {
+    width: 62.7907%;
+  }
+
+  .l-xl-8-11 {
+    width: 72.09302%;
+  }
+
+  .l-xl-9-11 {
+    width: 81.39535%;
+  }
+
+  .l-xl-10-11 {
+    width: 90.69767%;
+  }
+}
+/* Extra Extra Large (16 Column) Grid */
+/* Begins at 1100px */
+[class*="l-xxl-"] {
+  float: left;
+  clear: right;
+}
+[dir="rtl"] [class*="l-xxl-"] {
+  float: right;
+  clear: left;
+}
+@media (min-width: 68.75em) {
+  [class*="l-xxl-"] {
+    margin-right: 1.5873%;
+  }
+  [dir="rtl"] [class*="l-xxl-"] {
+    margin-left: 1.5873%;
+  }
+}
+
+@media (min-width: 68.75em) {
+  .l-xxl-full {
+    width: 100%;
+    float: left;
+    clear: both;
+  }
+  [dir="rtl"] .l-xxl-full {
+    float: right;
+  }
+
+  .l-xxl-alpha {
+    clear: both;
+  }
+
+  .l-xxl-omega {
+    float: right;
+    margin-right: 0;
+  }
+  [dir="rtl"] .l-xxl-omega {
+    float: left;
+    margin-left: 0;
+  }
+
+  .l-xxl-1-16 {
+    width: 4.7619%;
+  }
+
+  .l-xxl-2-16 {
+    width: 11.11111%;
+  }
+
+  .l-xxl-1-2 {
+    width: 42.85714%;
+  }
+
+  .l-xxl-3-16 {
+    width: 17.46032%;
+  }
+
+  .l-xxl-1-3 {
+    width: 27.27273%;
+  }
+
+  .l-xxl-2-3 {
+    width: 63.63636%;
+  }
+
+  .l-xxl-4-16 {
+    width: 23.80952%;
+  }
+
+  .l-xxl-1-4 {
+    width: 20%;
+  }
+
+  .l-xxl-2-4 {
+    width: 46.66667%;
+  }
+
+  .l-xxl-3-4 {
+    width: 73.33333%;
+  }
+
+  .l-xxl-5-16 {
+    width: 30.15873%;
+  }
+
+  .l-xxl-1-5 {
+    width: 15.78947%;
+  }
+
+  .l-xxl-2-5 {
+    width: 36.84211%;
+  }
+
+  .l-xxl-3-5 {
+    width: 57.89474%;
+  }
+
+  .l-xxl-4-5 {
+    width: 78.94737%;
+  }
+
+  .l-xxl-6-16 {
+    width: 36.50794%;
+  }
+
+  .l-xxl-1-6 {
+    width: 13.04348%;
+  }
+
+  .l-xxl-2-6 {
+    width: 30.43478%;
+  }
+
+  .l-xxl-3-6 {
+    width: 47.82609%;
+  }
+
+  .l-xxl-4-6 {
+    width: 65.21739%;
+  }
+
+  .l-xxl-5-6 {
+    width: 82.6087%;
+  }
+
+  .l-xxl-7-16 {
+    width: 42.85714%;
+  }
+
+  .l-xxl-1-7 {
+    width: 11.11111%;
+  }
+
+  .l-xxl-2-7 {
+    width: 25.92593%;
+  }
+
+  .l-xxl-3-7 {
+    width: 40.74074%;
+  }
+
+  .l-xxl-4-7 {
+    width: 55.55556%;
+  }
+
+  .l-xxl-5-7 {
+    width: 70.37037%;
+  }
+
+  .l-xxl-6-7 {
+    width: 85.18519%;
+  }
+
+  .l-xxl-8-16 {
+    width: 49.20635%;
+  }
+
+  .l-xxl-1-8 {
+    width: 9.67742%;
+  }
+
+  .l-xxl-2-8 {
+    width: 22.58065%;
+  }
+
+  .l-xxl-3-8 {
+    width: 35.48387%;
+  }
+
+  .l-xxl-4-8 {
+    width: 48.3871%;
+  }
+
+  .l-xxl-5-8 {
+    width: 61.29032%;
+  }
+
+  .l-xxl-6-8 {
+    width: 74.19355%;
+  }
+
+  .l-xxl-7-8 {
+    width: 87.09677%;
+  }
+
+  .l-xxl-9-16 {
+    width: 55.55556%;
+  }
+
+  .l-xxl-1-9 {
+    width: 8.57143%;
+  }
+
+  .l-xxl-2-9 {
+    width: 20%;
+  }
+
+  .l-xxl-3-9 {
+    width: 31.42857%;
+  }
+
+  .l-xxl-4-9 {
+    width: 42.85714%;
+  }
+
+  .l-xxl-5-9 {
+    width: 54.28571%;
+  }
+
+  .l-xxl-6-9 {
+    width: 65.71429%;
+  }
+
+  .l-xxl-7-9 {
+    width: 77.14286%;
+  }
+
+  .l-xxl-8-9 {
+    width: 88.57143%;
+  }
+
+  .l-xxl-10-16 {
+    width: 61.90476%;
+  }
+
+  .l-xxl-1-10 {
+    width: 7.69231%;
+  }
+
+  .l-xxl-2-10 {
+    width: 17.94872%;
+  }
+
+  .l-xxl-3-10 {
+    width: 28.20513%;
+  }
+
+  .l-xxl-4-10 {
+    width: 38.46154%;
+  }
+
+  .l-xxl-5-10 {
+    width: 48.71795%;
+  }
+
+  .l-xxl-6-10 {
+    width: 58.97436%;
+  }
+
+  .l-xxl-7-10 {
+    width: 69.23077%;
+  }
+
+  .l-xxl-8-10 {
+    width: 79.48718%;
+  }
+
+  .l-xxl-9-10 {
+    width: 89.74359%;
+  }
+
+  .l-xxl-11-16 {
+    width: 68.25397%;
+  }
+
+  .l-xxl-1-11 {
+    width: 6.97674%;
+  }
+
+  .l-xxl-2-11 {
+    width: 16.27907%;
+  }
+
+  .l-xxl-3-11 {
+    width: 25.5814%;
+  }
+
+  .l-xxl-4-11 {
+    width: 34.88372%;
+  }
+
+  .l-xxl-5-11 {
+    width: 44.18605%;
+  }
+
+  .l-xxl-6-11 {
+    width: 53.48837%;
+  }
+
+  .l-xxl-7-11 {
+    width: 62.7907%;
+  }
+
+  .l-xxl-8-11 {
+    width: 72.09302%;
+  }
+
+  .l-xxl-9-11 {
+    width: 81.39535%;
+  }
+
+  .l-xxl-10-11 {
+    width: 90.69767%;
+  }
+
+  .l-xxl-12-16 {
+    width: 74.60317%;
+  }
+
+  .l-xxl-1-12 {
+    width: 6.38298%;
+  }
+
+  .l-xxl-2-12 {
+    width: 14.89362%;
+  }
+
+  .l-xxl-3-12 {
+    width: 23.40426%;
+  }
+
+  .l-xxl-4-12 {
+    width: 31.91489%;
+  }
+
+  .l-xxl-5-12 {
+    width: 40.42553%;
+  }
+
+  .l-xxl-6-12 {
+    width: 48.93617%;
+  }
+
+  .l-xxl-7-12 {
+    width: 57.44681%;
+  }
+
+  .l-xxl-8-12 {
+    width: 65.95745%;
+  }
+
+  .l-xxl-9-12 {
+    width: 74.46809%;
+  }
+
+  .l-xxl-10-12 {
+    width: 82.97872%;
+  }
+
+  .l-xxl-11-12 {
+    width: 91.48936%;
+  }
+
+  .l-xxl-13-16 {
+    width: 80.95238%;
+  }
+
+  .l-xxl-1-13 {
+    width: 5.88235%;
+  }
+
+  .l-xxl-2-13 {
+    width: 13.72549%;
+  }
+
+  .l-xxl-3-13 {
+    width: 21.56863%;
+  }
+
+  .l-xxl-4-13 {
+    width: 29.41176%;
+  }
+
+  .l-xxl-5-13 {
+    width: 37.2549%;
+  }
+
+  .l-xxl-6-13 {
+    width: 45.09804%;
+  }
+
+  .l-xxl-7-13 {
+    width: 52.94118%;
+  }
+
+  .l-xxl-8-13 {
+    width: 60.78431%;
+  }
+
+  .l-xxl-9-13 {
+    width: 68.62745%;
+  }
+
+  .l-xxl-10-13 {
+    width: 76.47059%;
+  }
+
+  .l-xxl-11-13 {
+    width: 84.31373%;
+  }
+
+  .l-xxl-12-13 {
+    width: 92.15686%;
+  }
+
+  .l-xxl-14-16 {
+    width: 87.30159%;
+  }
+
+  .l-xxl-1-14 {
+    width: 5.45455%;
+  }
+
+  .l-xxl-2-14 {
+    width: 12.72727%;
+  }
+
+  .l-xxl-3-14 {
+    width: 20%;
+  }
+
+  .l-xxl-4-14 {
+    width: 27.27273%;
+  }
+
+  .l-xxl-5-14 {
+    width: 34.54545%;
+  }
+
+  .l-xxl-6-14 {
+    width: 41.81818%;
+  }
+
+  .l-xxl-7-14 {
+    width: 49.09091%;
+  }
+
+  .l-xxl-8-14 {
+    width: 56.36364%;
+  }
+
+  .l-xxl-9-14 {
+    width: 63.63636%;
+  }
+
+  .l-xxl-10-14 {
+    width: 70.90909%;
+  }
+
+  .l-xxl-11-14 {
+    width: 78.18182%;
+  }
+
+  .l-xxl-12-14 {
+    width: 85.45455%;
+  }
+
+  .l-xxl-13-14 {
+    width: 92.72727%;
+  }
+
+  .l-xxl-15-16 {
+    width: 93.65079%;
+  }
+
+  .l-xxl-1-15 {
+    width: 5.08475%;
+  }
+
+  .l-xxl-2-15 {
+    width: 11.86441%;
+  }
+
+  .l-xxl-3-15 {
+    width: 18.64407%;
+  }
+
+  .l-xxl-4-15 {
+    width: 25.42373%;
+  }
+
+  .l-xxl-5-15 {
+    width: 32.20339%;
+  }
+
+  .l-xxl-6-15 {
+    width: 38.98305%;
+  }
+
+  .l-xxl-7-15 {
+    width: 45.76271%;
+  }
+
+  .l-xxl-8-15 {
+    width: 52.54237%;
+  }
+
+  .l-xxl-9-15 {
+    width: 59.32203%;
+  }
+
+  .l-xxl-10-15 {
+    width: 66.10169%;
+  }
+
+  .l-xxl-11-15 {
+    width: 72.88136%;
+  }
+
+  .l-xxl-12-15 {
+    width: 79.66102%;
+  }
+
+  .l-xxl-13-15 {
+    width: 86.44068%;
+  }
+
+  .l-xxl-14-15 {
+    width: 93.22034%;
+  }
+}
+.l-container, main {
+  max-width: 1290px;
+  padding: .25em .5em;
+  margin: 0 auto;
+}
diff --git a/core/themes/bartik/css/modules.css b/core/themes/bartik/css/modules.css
new file mode 100644
index 0000000..fb0124a
--- /dev/null
+++ b/core/themes/bartik/css/modules.css
@@ -0,0 +1,25 @@
+.colored-banner, body > header {
+  background: #48a9e4;
+  background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #0779bf), color-stop(100%, #48a9e4));
+  background: -webkit-linear-gradient(top, #0779bf, #48a9e4);
+  background: -moz-linear-gradient(top, #0779bf, #48a9e4);
+  background: -o-linear-gradient(top, #0779bf, #48a9e4);
+  background: linear-gradient(top, #0779bf, #48a9e4);
+}
+
+.colored-footer, body > footer {
+  background: #292929;
+  color: #c0c0c0;
+  color: rgba(255, 255, 255, 0.65);
+}
+.colored-footer a, body > footer a {
+  color: #fefefe;
+  color: rgba(255, 255, 255, 0.8);
+}
+.colored-footer a:hover, body > footer a:hover {
+  color: rgba(255, 255, 255, 0.95);
+}
+
+body > footer {
+  padding: 2em;
+}
diff --git a/core/themes/bartik/layouts/static/frontend/frontend.html.twig b/core/themes/bartik/layouts/static/frontend/frontend.html.twig
new file mode 100644
index 0000000..857a1d1
--- /dev/null
+++ b/core/themes/bartik/layouts/static/frontend/frontend.html.twig
@@ -0,0 +1,250 @@
+{#
+
+@file
+Bartik's primary frontend layout implementation.
+
+
+The doctype, html, head, and body tags are not in this template. Instead
+they can be found in the html.tpl.php template normally located in the
+core/modules/system directory.
+
+Available variables:
+
+General utility variables:
+- base_path: The base URL path of the Drupal installation. At the very
+  least, this will always default to /.
+- directory: The directory the template is located in, e.g. modules/system
+  or themes/bartik.
+- is_front: TRUE if the current page is the front page.
+- logged_in: TRUE if the user is registered and signed in.
+- is_admin: TRUE if the user has permission to access administration pages.
+
+Site identity:
+- front_page: The URL of the front page. Use this instead of base_path,
+  when linking to the front page. This includes the language domain or
+  prefix.
+- logo: The path to the logo image, as defined in theme configuration.
+- site_name: The name of the site, empty when display has been disabled
+  in theme settings.
+- site_slogan: The slogan of the site, empty when display has been disabled
+  in theme settings.
+- hide_site_name: TRUE if the site name has been toggled off on the theme
+  settings page. If hidden, the "element-invisible" class is added to make
+  the site name visually hidden, but still accessible.
+- hide_site_slogan: TRUE if the site slogan has been toggled off on the
+  theme settings page. If hidden, the "element-invisible" class is added to
+  make the site slogan visually hidden, but still accessible.
+
+Navigation:
+- main_menu (array): An array containing the Main menu links for the
+  site, if they have been configured.
+- secondary_menu (array): An array containing the Secondary menu links for
+  the site, if they have been configured.
+- breadcrumb: The breadcrumb trail for the current page.
+
+Page content (in order of occurrence in the default page.tpl.php):
+- title_prefix (array): An array containing additional output populated by
+  modules, intended to be displayed in front of the main title tag that
+  appears in the template.
+- title: The page title, for use in the actual HTML content.
+- title_suffix (array): An array containing additional output populated by
+  modules, intended to be displayed after the main title tag that appears in
+  the template.
+- messages: HTML for status and error messages. Should be displayed
+  prominently.
+- tabs (array): Tabs linking to any sub-pages beneath the current page
+  (e.g., the view and edit tabs when displaying a node).
+- action_links (array): Actions local to the page, such as 'Add menu' on
+  the menu administration interface.
+- feed_icons: A string of all feed icons for the current page.
+- node: The node entity, if there is an automatically-loaded node
+  associated with the page, and the node ID is the second argument
+  in the page's path (e.g. node/12345 and node/12345/revisions, but not
+  comment/reply/12345).
+
+Regions:
+- content.header: Items for the header region.
+- content.featured: Items for the featured region.
+- content.highlighted: Items for the highlighted content region.
+- content.help: Dynamic help text, mostly for admin pages.
+- content.content: The main content of the current page.
+- content.sidebar_first: Items for the first sidebar.
+- content.sidebar_second: Items for the second sidebar.
+- content.triptych_first: Items for the first triptych.
+- content.triptych_middle: Items for the middle triptych.
+- content.triptych_last: Items for the last triptych.
+- content.footer_firstcolumn: Items for the first footer column.
+- content.footer_secondcolumn: Items for the second footer column.
+- content.footer_thirdcolumn: Items for the third footer column.
+- content.footer_fourthcolumn: Items for the fourth footer column.
+- content.footer: Items for the footer region.
+
+@see template_preprocess()
+@see template_preprocess_content()
+@see template_process()
+@see bartik_process_page()
+@see html.tpl.php
+
+@ingroup themeable
+
+#}
+
+{# system is emitted before & above everything else #}
+{% if content.system %}{{ content.system }}{% endif %}
+
+<div id="page">
+  <header id="header" role="banner"><div class="section clearfix">
+    {# @todo remove/replace this hardcoding. #}
+    {% if secondary_nav %}
+      <nav id="secondary-menu" class="navigation" role="navigation">
+        {{ secondary_nav }}
+      </nav>
+    {% endif %}
+
+    {# @todo remove/replace this hardcoding. #}
+    {% if logo %}
+      <a href="{{ front_page }}" title="{{ 'Home'|t }}" rel="home" id="logo">
+        <img src="{{ logo }}" alt="{{ 'Home'|t }}" />
+      </a>
+    {% endif %}
+
+    {# @todo remove/replace aaaaall this hardcoding. #}
+    {% if site_name or site_slogan %}
+      <div id="name-and-slogan" {% if hide_site_name and hide_site_slogan %}class="element-invisible"{% endif %}>
+        {% if site_name %}
+          {% if title %}
+            <div id="site-name" {% if hide_site_name %}class="element-invisible"{% endif %}>
+              <strong>
+                <a href="{{ front_page }}" title="{{ 'Home'|t }}" rel="home"><span><{{ site_name }}></span></a>
+              </strong>
+            </div>
+          {% else %}
+            <h1 id="site-name" {% if hide_site_name %}class="element-invisible"{% endif %}>
+              <a href="{{ front_page }}" title="{{ 'Home'|t }}" rel="home"><span><{{ site_name }}></span></a>
+            </h1>
+          {% endif %}
+        {% endif %}
+
+        {% if site_slogan %}
+          <div id="site-slogan" {% if hide_site_slogan %}class="element-invisible"{% endif %}>
+            {{ site_slogan }}
+          </div>
+        {% endif %}
+
+      </div>
+    {% endif %}
+
+    {{ content.header }}
+
+    {# @todo remove/replace this hardcoding. #}
+    {% if primary_nav %}
+      <nav id="main-menu" class="navigation" role="navigation">
+        {{ primary_nav }}
+      </nav>
+    {% endif %}
+
+  </div></header>
+
+
+  {# @todo remove/replace this hardcoding. #}
+  {% if messages %}
+    <div id="messages"><div class="section clearfix">
+      {{ messages }}
+    </div></div>
+  {% endif %}
+
+
+  {% if content.featured %}
+    <aside id="featured"><div class="section clearfix">
+      {{ content.featured }}
+    </div></aside>
+  {% endif %}
+
+
+  <div id="main-wrapper" class="clearfix"><div id="main" class="clearfix">
+    {{ breadcrumb }} {# @todo remove/replace this hardcoding. #}
+    <main id="content" class="column" role="main"><section class="section">
+      {% if content.highlighted %}
+        <div id="highlighted">
+          {{ content.highlighted }}
+        </div>
+      {% endif %}
+
+      <a id="main-content"></a>
+
+      {# @todo remove/replace this hardcoding. #}
+      {{ title_prefix }}
+      {% if title %}
+        <h1 class="title" id="page-title">
+          {{ title }}
+        </h1>
+      {% endif %}
+      {{ title_suffix }}
+
+      {# @todo remove/replace this hardcoding. #}
+      {% if tabs %}
+        <nav class="tabs" role="navigation">
+          {{ tabs }}
+        </nav>
+      {% endif %}
+
+      {# @todo content.help should probably be a block, not a region #}
+      {{ content.help }}
+
+      {# @todo remove/replace this hardcoding. #}
+      {% if action_links %}
+        <ul class="action-links">
+          {{ action_links }}
+        </ul>
+      {% endif %}
+
+      {{ content.content }}
+
+      {# @todo remove/replace this hardcoding. #}
+      {{ feed_icons }}
+
+    </section></main>
+
+    {% if content.sidebar_first %}
+      <div id="sidebar-first" class="column sidebar"><aside class="section">
+        {{ content.sidebar_first }}
+      </aside></div>
+    {% endif %}
+
+    {% if content.sidebar_second %}
+      <div id="sidebar-first" class="column sidebar"><aside class="section">
+        {{ content.sidebar_first }}
+      </aside></div>
+    {% endif %}
+
+  </div></div>
+
+
+  {% if content.triptych_first or content.triptych_middle or content.triptych_last %}
+    <div id="triptych-wrapper"><aside id="triptych" class="clearfix">
+      {{ content.triptych_first }}
+      {{ content.triptych_middle }}
+      {{ content.triptych_last }}
+    </aside></div>
+  {% endif %}
+
+
+  <div id="footer-wrapper"><footer class="section" role="contentinfo">
+    {% if content.footer_firstcolumn or content.footer_secondcolumn
+       or content.footer_thirdcolumn or content.footer_fourthcolumn %}
+      <div id="footer-columns" class="clearfix">
+        {{ content.footer_firstcolumn }}
+        {{ content.footer_secondcolumn }}
+        {{ content.footer_thirdcolumn }}
+        {{ content.footer_fourthcolumn }}
+      </div>
+    {% endif %}
+
+    {% if content.footer %}
+      <div id="footer" role="contentinfo" class="clearfix">
+        {{ content.footer }}
+      </div>
+    {% endif %}
+  </footer></div>
+
+</div>
diff --git a/core/themes/bartik/layouts/static/frontend/frontend.yml b/core/themes/bartik/layouts/static/frontend/frontend.yml
new file mode 100644
index 0000000..c5fbacf
--- /dev/null
+++ b/core/themes/bartik/layouts/static/frontend/frontend.yml
@@ -0,0 +1,52 @@
+title: Bartik Frontend
+category: Frontend
+template: frontend
+regions:
+  system:
+    label: System
+    type: system
+  header:
+    label: Header
+    type: header
+  content:
+    label: Main Content
+    type: content
+  highlighted:
+    label: Highlighted
+    type: content
+  help:
+    label: Help
+    type: content
+  sidebar_first:
+    label: Sidebar first
+    type: aside
+  sidebar_second:
+    label: Sidebar second
+    type: aside
+  featured:
+    label: Featured
+    type: aside
+  triptych_first:
+    label: Triptych first
+    type: aside
+  triptych_second:
+    label: Triptych second
+    type: aside
+  triptych_last:
+    label: Triptych last
+    type: aside
+  footer:
+    label: Footer
+    type: footer
+  footer_firstcolumn:
+    label: Footer first column
+    type: footer
+  footer_secondcolumn:
+    label: Footer first column
+    type: footer
+  footer_thirdcolumn:
+    label: Footer first column
+    type: footer
+  footer_fourthcolumn:
+    label: Footer first column
+    type: footer
\ No newline at end of file
